【问题标题】:stdcall calling convention and using pinvoke in C#stdcall 调用约定和在 C# 中使用 pinvoke
【发布时间】:2015-09-06 19:31:26
【问题描述】:

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

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

extern "C" __declspec(dllexport) void __cdecl myFunc2() {
    // just empty function
}

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

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

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

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

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

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void MyFunc2();

但是,当我调用 MyFunc1() MyFunc2() 工作的地方时会发生运行时错误。

所以我在 C++ 中将 __stdcall 替换为 __cdecl,重新编译 DLL,然后在 C# 中再次调用 MyFunc1()。

而且.. 它奏效了。

到底为什么 __stdcall 调用约定不能与 C# 中的 pinvoke 一起使用?

【问题讨论】:

  • DllImport P/Invoke。你到底想做什么? :D UnmanagedFunctionPointer 将托管委托编组为非托管函数指针(顾名思义) - 它与调用 DLL 中的非托管函数无关。好吧,不是“什么都没有”——显然,你有一个可以从非托管方传递或接收的委托,但这不是你在这里想要做的。
  • 另外,根据UnmanagedFunctionPointerif you do not specify a field name, UnmanagedFunctionPointerAttribute is ignored. 的文档,我没有看到您指定任何名称。
  • 是的,你是对的。这次我使用的是“kernel32.dll”的LoadLibrary()、FreeLibrary() 和GetProcAddress()。我没有发布其余代码,因为我认为这对于这里的专家来说只是基本的东西。
  • 很抱歉问了这么一个基本的问题,但是UnmanagedFunctionPointer中的函数名怎么指定??我只是使用 Marshal.GetDelegateForFunctionPointer 获取指针,并在那里指定了名称。
  • GetDelegateForFunctionPointer 需要第二个参数的类型。通过typeof(MyFunc1) ;-)

标签: c# c++ pinvoke calling-convention stdcall


【解决方案1】:

这里发生的情况是,当您在 C++ 代码中从 __cdecl 切换到 __stdcall 时,编译器会修饰函数导出的名称。它不是myFunc1,而是导出为myFunc1@0_myFunc1@0。尽管如此,名字都被装饰了。您可以使用 dumpbin 或 Dependency Viewer 检查是否如此。

当您调用GetProcAddress 时,它找不到名为myFunc1 的函数,因此返回NULL。你不检查返回值,所以不管怎样都继续。当您尝试调用该函数时,会引发运行时错误。

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

【讨论】:

  • 需要使用def文件导出
  • 依赖查看器不同。它可以做得更多。它是视觉的。但是,dumpbin 很好地列出了导出。
  • 声明一个接受IntPtr作为第二个参数的重载并将序数值传递给该参数。
  • 如果变量被导出然后你用GetProcAddress导入它
  • 记载:如果函数成功,返回值为导出函数或变量的地址。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-19
  • 2012-05-23
  • 1970-01-01
  • 2018-02-12
  • 1970-01-01
  • 2011-07-04
相关资源
最近更新 更多