我正在尝试从用 C 编写的第三方 DLL 执行一些方法(在这种特殊情况下,rdOnAllDone),并查看头文件,我发现了这个:
#ifndef TDECLSDONE
#ifdef STDCALL
#define CCON __stdcall
#else
#define CCON __cdecl
#endif
#define TDECLSDONE
#endif
#define DLLIMP __declspec (dllimport)
DLLIMP int CCON rdOnAllDone (void(CCON *)(int));
在寻找调用此方法的方法后,我做了这个:
[DllImport("sb6lib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int rdOnAllDone(Delegate d);
public delegate void rdOnAllDoneCallbackDelegate();
private static void rdOnAllDoneCallback()
{
Console.WriteLine("rdOnAllDoneCallback invoked");
}
该方法被正确调用,只是我无法获取 int 参数。所以我尝试像这样添加输入参数 int
[DllImport("sb6lib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int rdOnAllDone(Delegate d);
public delegate void rdOnAllDoneCallbackDelegate(int number);
private static void rdOnAllDoneCallback(int number)
{
Console.WriteLine("rdOnAllDoneCallback invoked " + number);
}
但现在委托(delegate)被调用了两次,它使程序崩溃并出现以下错误“vshosts32.exe 已停止工作”
调用此 DLL 方法的正确方法是什么?
编辑:忘记添加 Main 方法:
public static void Main()
{
rdOnAllDoneCallbackDelegate del3 = new rdOnAllDoneCallbackDelegate(rdOnAllDoneCallback);
rdOnAllDone(del3);
while (true)
{
Thread.Sleep(1000);
}
}
最佳答案
要使这项工作正常进行,您需要做三件事:
- 您需要告诉 pinvoke 编码器有关实际 委托(delegate)类型的信息,使用 Delegate 还不够好。这将创建错误的 thunk,无法正确整理参数。这就是您看到的情况。
- 如果调用约定不是具有 [UnmanagedFunctionPointer] 属性的 __stdcall,则需要将调用约定告诉编码器。弄错这个错误会导致堆栈不平衡,并很有可能发生严重崩溃。
- 您需要存储对委托(delegate)对象的引用,这样垃圾收集器就不会收集它。它看不到 native 代码持有的引用。错误的处理会导致 native 代码在下一次垃圾回收后发生硬崩溃。
所以这应该能更好地工作,根据需要进行调整:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void rdOnAllDoneCallbackDelegate(int parameter);
[DllImport("sb6lib.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int rdOnAllDone(rdOnAllDoneCallbackDelegate d);
class Foo {
private static rdOnAllDoneCallbackDelegate callback; // Keeps it referenced
public static void SetupCallback() {
callback = new rdOnAllDoneCallbackDelegate(rdOnAllDoneCallback);
rdOnAllDone(callback);
}
private static void rdOnAllDoneCallback(int parameter) {
Console.WriteLine("rdOnAllDoneCallback invoked, parameter={0}", parameter);
}
}
关于c# - 从 C# 调用 C DLL 方法的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8657805/