Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/294.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
将数据类型从C#封送到C++; 我目前正在使用一个非托管C++库中的一些业务逻辑来处理一个C(.net框架4.7.2)应用程序。我尝试从C到C++之间来回传递数据(互操作)。我可能不使用C++/CLI,我的项目中不允许使用公共语言运行时_C#_C++_Marshalling - Fatal编程技术网

将数据类型从C#封送到C++; 我目前正在使用一个非托管C++库中的一些业务逻辑来处理一个C(.net框架4.7.2)应用程序。我尝试从C到C++之间来回传递数据(互操作)。我可能不使用C++/CLI,我的项目中不允许使用公共语言运行时

将数据类型从C#封送到C++; 我目前正在使用一个非托管C++库中的一些业务逻辑来处理一个C(.net框架4.7.2)应用程序。我尝试从C到C++之间来回传递数据(互操作)。我可能不使用C++/CLI,我的项目中不允许使用公共语言运行时,c#,c++,marshalling,C#,C++,Marshalling,它对int很好。不幸的是,当我尝试发送另一个数据类型时,我得到了一个转换错误,例如float 4.2f变为1,字符串“fourtytwo”变为-1529101360 我的C#代码如下所示: // works fine, creates an instance of TestClass var test = TestProxy.Wrapper_Create("test"); // int, works fine, a = 42 var a = TestProxy.TryInt(test

它对int很好。不幸的是,当我尝试发送另一个数据类型时,我得到了一个转换错误,例如float 4.2f变为1,字符串“fourtytwo”变为-1529101360

我的C#代码如下所示:

// works fine, creates an instance of TestClass    
var test = TestProxy.Wrapper_Create("test"); 

// int, works fine, a = 42
var a = TestProxy.TryInt(test, 42);

// float, problem, b = 1
var b = TestProxy.TryFloat(test, 4.2f);

// string, problem, c = -159101360
var c = TestProxy.TryString(test, "fourtytwo");
public static class TestProxy
    {
        private const string coreDLL = "test.core.dll";

        [DllImport(coreDLL, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr Wrapper_Create(string name);

        [DllImport(coreDLL, EntryPoint = "?TryInt@TestClass@@XXX@X", CallingConvention = CallingConvention.ThisCall)]
        public static extern int TryInt(IntPtr instance, int n);

        [DllImport(coreDLL, EntryPoint = "?TryFloat@TestClass@@XXX@X", CallingConvention = CallingConvention.ThisCall)]
        public static extern int TryFloat(IntPtr instance, float n);

        [DllImport(coreDLL, EntryPoint = "?TryString@TestClass@@XXX@X", CallingConvention = CallingConvention.ThisCall)]
        public static extern int TryString(IntPtr instance, string n);

    }
HRESULT TryString( TestClass *instance, BSTR i, BSTR *o )
< P>我调用C(本地)(非托管)C++代码的C互操作代理类看起来是这样的:

// works fine, creates an instance of TestClass    
var test = TestProxy.Wrapper_Create("test"); 

// int, works fine, a = 42
var a = TestProxy.TryInt(test, 42);

// float, problem, b = 1
var b = TestProxy.TryFloat(test, 4.2f);

// string, problem, c = -159101360
var c = TestProxy.TryString(test, "fourtytwo");
public static class TestProxy
    {
        private const string coreDLL = "test.core.dll";

        [DllImport(coreDLL, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr Wrapper_Create(string name);

        [DllImport(coreDLL, EntryPoint = "?TryInt@TestClass@@XXX@X", CallingConvention = CallingConvention.ThisCall)]
        public static extern int TryInt(IntPtr instance, int n);

        [DllImport(coreDLL, EntryPoint = "?TryFloat@TestClass@@XXX@X", CallingConvention = CallingConvention.ThisCall)]
        public static extern int TryFloat(IntPtr instance, float n);

        [DllImport(coreDLL, EntryPoint = "?TryString@TestClass@@XXX@X", CallingConvention = CallingConvention.ThisCall)]
        public static extern int TryString(IntPtr instance, string n);

    }
HRESULT TryString( TestClass *instance, BSTR i, BSTR *o )
<我的本地(非托管)C++看起来是这样的: 头文件:

#ifdef TESTCORE_EXPORTS
#define TESTCORE_API __declspec(dllexport)
#endif

#pragma once

extern "C"
{
    class TESTCORE_API TestClass
    {
    private:
        char* name;
    public:
        TestClass(char*);
        int TryInt(int);
        float TryFloat(float);
        char* TryString(char*);
    };

    TESTCORE_API TestClass* Wrapper_Create(char* name);
}
实现文件:

#include "stdafx.h"

#include "TESTCore.h"

TestClass::TestClass(char* n) 
{
    name = n;
}

int TestClass::TryInt(int n) 
{
    return n; // works fine
}

float TestClass::TryFloat(float n)
{
    return n; // something goes wrong here
}

char* TestClass::TryString(char* n)
{
    return n; // something goes wrong here
}

extern "C"
{
    TESTCORE_API TestClass * Wrapper_Create(char* name)
    {
        return new TestClass(name);
    }

    TESTCORE_API int TryInt(TestClass * instance, int n) 
    {
        if (instance != NULL) 
        {
            return instance->TryInt(n);
        }
    }

    TESTCORE_API float TryFloat(TestClass * instance, float n) 
    {
        if (instance != NULL) 
        {
            return instance->TryFloat(n);
        }
    }

    TESTCORE_API char* TryString(TestClass * instance, char* n) 
    {
        if (instance != NULL)
        {
            return instance->TryString(n); 
        }
    }
}
你知道如何正确地将浮点、字符串从C→C++返回到?


谢谢大家!

C++没有标准的ABI。在DLL上使用C++类是个好主意,即使在两边都有相同的语言。

有更好的办法

< > > >用全局函数、CDECL或STDCLAK替换您的<代码>代码> C++ /Cord>类方法(但注意C++和C++有不同的缺省值,如果您不做任何处理,C++将使用CDECL,C将导入STDCALL)。您可以在第一个参数中传递类的“this”指针,即C#中的IntPtr,就像您现在所做的一样。另外,如果您要编写
extern“C”
或使用模块定义文件,它们将具有人类可读的名称

  • 如果需要对象,请使用COM。声明一个继承IUnknown的接口,用C++实现(通常使用ATL),导出一个全局函数来创建该对象的实例(ATL中的2行,<代码> CCOMObj::CreateInstance < /代码>,后面是代码> AddiFF < /C>)。无需注册、键入库,只需实现IUnknown(但如果希望从多个线程使用它们)

  • 更新:字符串确实更难。将
    [marshallas(UnmanagedType.LPTStr)]
    应用于参数。将
    [返回:marshallas(UnmanagedType.LPTStr)]
    应用于函数。在DllImport中指定
    PreserveSig=true
    。最后,修改C++代码返回一个字符串的副本,即调用<代码> StrLon < /C> >代码> COTASKMeMeloLC/<代码(不要忘记<代码> 0”<代码>,然后<代码> StrcPy < /Cord> 处理字符串的更简单方法如下:

    // works fine, creates an instance of TestClass    
    var test = TestProxy.Wrapper_Create("test"); 
    
    // int, works fine, a = 42
    var a = TestProxy.TryInt(test, 42);
    
    // float, problem, b = 1
    var b = TestProxy.TryFloat(test, 4.2f);
    
    // string, problem, c = -159101360
    var c = TestProxy.TryString(test, "fourtytwo");
    
    public static class TestProxy
        {
            private const string coreDLL = "test.core.dll";
    
            [DllImport(coreDLL, CallingConvention = CallingConvention.Cdecl)]
            public static extern IntPtr Wrapper_Create(string name);
    
            [DllImport(coreDLL, EntryPoint = "?TryInt@TestClass@@XXX@X", CallingConvention = CallingConvention.ThisCall)]
            public static extern int TryInt(IntPtr instance, int n);
    
            [DllImport(coreDLL, EntryPoint = "?TryFloat@TestClass@@XXX@X", CallingConvention = CallingConvention.ThisCall)]
            public static extern int TryFloat(IntPtr instance, float n);
    
            [DllImport(coreDLL, EntryPoint = "?TryString@TestClass@@XXX@X", CallingConvention = CallingConvention.ThisCall)]
            public static extern int TryString(IntPtr instance, string n);
    
        }
    
    HRESULT TryString( TestClass *instance, BSTR i, BSTR *o )
    

    <>至少有<代码> CCOMBSTR 和 BSTRUTT < /COD>内置类来处理内存管理。< /P>我刚才尝试了String的属性[MARSARLAS(unMaundType,LPTSTR)]和[MarshalAs(unMaundType,R4)],但是它似乎不能正常工作。尝试用STDCALL替换这个调用,并相应地修改C++代码。代码>\uuu stdcall由WinAPI和COM使用,稍微标准一些。感谢您的回复,非常正确。另外,在我的C#TestProxy类中,我需要正确的返回类型,例如float。不过,我仍在为绳子而挣扎。不幸的是,我无法以某种方式将char*转换为string。