stdcall调用约定并在C#中使用pinvoke

Jen*_*nix 1 c# c++ pinvoke calling-convention stdcall

我创建了一个DLL文件,其中包含两个空函数.

extern "C" __declspec(dllexport) void __stdcall myFunc1() {
    // just empty function
}

extern "C" __declspec(dllexport) void __cdecl myFunc2() {
    // just empty function
}
Run Code Online (Sandbox Code Playgroud)

在C#中,我可以使用DLLImport如下属性调用函数.

[DllImport("myDLL", CallingConvention=CallingConvention.StdCall)]
private extern static void myFunc1();

[DllImport("myDLL", CallingConvention=CallingConvention.Cdecl)]
private extern static void myFunc2();
Run Code Online (Sandbox Code Playgroud)

所以我再次尝试使用LoadLibrary()kernel32.dll而不是DllImport属性.

[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate void MyFunc1();

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void MyFunc2();
Run Code Online (Sandbox Code Playgroud)

但是,当我调用MyFunc1()工作时MyFunc1()时会发生运行时错误.

所以我__stdcall__cdeclC++ 替换,重新编译DLL,然后在C#中再次调用MyFunc1().

并且......它奏效了.

为什么地球上没有__stdcall呼叫约会在C#中用pinvoke工作?

Dav*_*nan 7

这里发生的是当您从C++代码切换__cdecl__stdcallC++代码时,编译器会修饰导出函数的名称.而不是将myFunc1其导出为myFunc1@0或可能_myFunc1@0.同样,名字是装饰的.你可以使用dumpbinDependency Viewer 来检查是这样的.

当你调用时GetProcAddress,它找不到一个名为的函数myFunc1,所以返回NULL.您不检查返回值,因此无论如何都要继续.当您尝试调用该函数时,将引发运行时错误.

我不得不猜测大部分内容,因为你没有显示完整的代码.另一个重要的教训是在调用Win32函数时检查错误.

  • 需要使用def文件导出 (3认同)
  • 声明一个重载,接受`IntPtr`作为第二个参数,并将序数值传递给该参数. (2认同)
  • 如果导出变量,则使用`GetProcAddress`导入它 (2认同)
  • 记录:*如果函数成功,返回值是导出函数或变量的地址.* (2认同)