gpt4 book ai didi

c# - 在 x64 中从 C# 调用 C++ 代码,所有参数都移动 1

转载 作者:太空狗 更新时间:2023-10-29 23:13:00 25 4
gpt4 key购买 nike

我的 C++ dll:

int test2::CallMe(int y) {
return y;
}

C#代码:

[DllImport("test2.dll",CharSet = CharSet.Anci)]
private static extern int CallMe(int y);

Console.WriteLine(CallMe(7));

如果 dll 和测试程序是在 x86 中编译的,我会得到一个打印:7但是如果我在 X64 上为 C++ 和 X64 或任何 CPU 为 C# 编译它们,打印是:0

有什么建议吗?

编辑:问题出在调用上,因为在调试器中我看到 CPP 接收到 0 ,或者在结构的情况下接收到 null。

编辑 2:使用 def 文件导出函数。如果我使用 extern "C"导出一个函数,它工作正常,但我不能导出一个 calss 函数,或者我不知道如何导出

编辑 3:显然参数实际上不是零,只有最后一个参数是零,所有参数都被移位,第二个参数设置为第一个等等

最佳答案

不完全/完全/透明地支持从 C# 调用 C++ 函数。您可以尝试在 DllImport 中使用 CallingConvention = CallingConvention.ThisCall,但这不是一门精确的科学。假设它应该适用于简单的情况......

[DllImport("test2.dll", CallingConvention = CallingConvention.ThisCall)]
private static extern int CallMe(IntPtr obj, int y);

其中 obj 是对 C++ 对象的引用(在 C++ 中称为 this)。 32 位和 64 位之间的差异是因为放置 this 指针的位置在 32 位和 64 位之间发生变化。

对于非常简单的情况,当 C++ 方法实际上没有使用 this(并且它不使用虚函数)时,您可以传递 IntPtr.Zero 作为指针。通常,您会有一个 extern C 方法创建 C++ 对象“C++ 端”并返回一个 IntPtr(一个 void*)给 C#,然后 C# 调用传递此 IntPtr 的 C++ 方法。

“脆弱”的一点是 C++ 编译器会破坏 C++ 方法的名称(不在 extern "C" block 中的方法),因此您必须“手动”发现它们(例如使用 DUMPBIN/exports)...为了让事情“更简单”,错位的名称在 32 位和 64 位之间变化:-)

一个例子:

C++ 端:

class Store
{
private:
int value;

public:
__declspec(dllexport) void Put(int value)
{
this->value = value;
}

__declspec(dllexport) int Get()
{
return this->value;
}

__declspec(dllexport) void Increment()
{
this->value++;
}
};

extern "C"
{
__declspec(dllexport) int PlusOne(int x)
{
return x + 1;
}

__declspec(dllexport) Store* NewStore()
{
return new Store;
}

__declspec(dllexport) void DeleteStore(Store* store)
{
delete store;
}
}

class Program
{
[DllImport("CplusPlusSide.dll", CallingConvention = CallingConvention.Cdecl)]
extern static int PlusOne(int x);

[DllImport("CplusPlusSide.dll", CallingConvention = CallingConvention.Cdecl)]
extern static IntPtr NewStore();

[DllImport("CplusPlusSide.dll", CallingConvention = CallingConvention.Cdecl)]
extern static void DeleteStore(IntPtr store);

// EntryPoint generated with DUMPBIN /exports dllname.dll
[DllImport("CplusPlusSide.dll", CallingConvention = CallingConvention.ThisCall, EntryPoint = "?Put@Store@@QAEXH@Z")]
extern static void Put32(IntPtr store, int value);

// EntryPoint generated with DUMPBIN /exports dllname.dll
[DllImport("CplusPlusSide.dll", CallingConvention = CallingConvention.ThisCall, EntryPoint = "?Get@Store@@QAEHXZ")]
extern static int Get32(IntPtr store);

// EntryPoint generated with DUMPBIN /exports dllname.dll
[DllImport("CplusPlusSide.dll", CallingConvention = CallingConvention.ThisCall, EntryPoint = "?Increment@Store@@QAEXXZ")]
extern static void Increment32(IntPtr store);

// EntryPoint generated with DUMPBIN /exports dllname.dll
[DllImport("CplusPlusSide.dll", CallingConvention = CallingConvention.ThisCall, EntryPoint = "?Put@Store@@QEAAXH@Z")]
extern static void Put64(IntPtr store, int value);

// EntryPoint generated with DUMPBIN /exports dllname.dll
[DllImport("CplusPlusSide.dll", CallingConvention = CallingConvention.ThisCall, EntryPoint = "?Get@Store@@QEAAHXZ")]
extern static int Get64(IntPtr store);

// EntryPoint generated with DUMPBIN /exports dllname.dll
[DllImport("CplusPlusSide.dll", CallingConvention = CallingConvention.ThisCall, EntryPoint = "?Increment@Store@@QEAAXXZ")]
extern static void Increment64(IntPtr store);

static void Main(string[] args)
{
int x = PlusOne(1);
Console.WriteLine(x);

IntPtr store = NewStore();

int ret;

if (IntPtr.Size == 8)
{
Put64(store, 5);
Increment64(store);
ret = Get64(store);
}
else
{
Put32(store, 5);
Increment32(store);
ret = Get32(store);
}

Console.WriteLine(ret);

DeleteStore(store);
}
}

关于c# - 在 x64 中从 C# 调用 C++ 代码,所有参数都移动 1,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42483796/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com