从x64中的C#调用C 代码,所有参数都会偏移一个

calling a c++ code from C# in x64 all arguments shift by one

本文关键字:一个 参数 中的 x64 调用 代码      更新时间:2023-10-16

我的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但是,如果我以C 和X64的X64进行编译,或C#的任何CPU,则打印是:0

有任何建议?

编辑:问题是呼叫,因为在调试器中,我看到CPP接收0,或者在struct的情况下为null。

编辑2:使用DEF文件导出功能。如果我使用Extern" C"导出功能,它可以正常工作,但我不能导出CALS的功能,或者我不知道

如何

编辑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位之间的位置。

对于非常简单的情况,当实际上this不使用C 方法(并且不使用虚拟功能)时,您可以将IntPtr.Zero作为指针传递。通常,您将拥有一个extern C方法,该方法会创建C 对象" C 侧",然后将IntPtr(A void*)返回到C#,然后C#调用CC 方法传递此IntPtr

"脆性"点是C 编译器人员操作C 方法的名称(不在extern "C"块中的方法),因此您必须"手动"发现它们(例如,使用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);
    }
}