将 C++ 函数与委托(delegate)一起使用后,C# 应用程序在退出时崩溃

标签 c# c++ delegates dllimport

我的 C# 应用程序需要与用 C++ 编写的 DLL 对话。我没有此 DLL 的代码,但我有使用该 DLL 并可以运行的演示应用程序(也在 C++ 中)的代码。

这是来自 C++ 演示应用程序的有趣代码。它有两个函数,其中一个函数接受 4 个委托(delegate)的回调集。

typedef BOOL (CBAPI* OPENSCANNERSDK)(HWND hwnd, TCallBackSet* callbackSet, wchar_t* configPath);
typedef void (CBAPI* CLOSESCANNERSDK)();

typedef struct              TCallBackSet
{
    TOnScannerStatusEvent   scannerStatusEvent;
    TOnScannerNotifyEvent   scannerNotifyEvent;
    TOnRFIDStatusEvent      rfidStatusEvent;
    TOnRFIDNotifyEvent      rfidNotifyEvent;
} TCallBackSet;

typedef void        (cdecl* TOnScannerStatusEvent   )   (int scannerStatus);
typedef void        (cdecl* TOnScannerNotifyEvent)      (int scannerNotify, int lParam);
typedef void        (cdecl* TOnRFIDStatusEvent      )   (int rfidStatus);
typedef void        (cdecl* TOnRFIDNotifyEvent      )   (int rfidnotify);

所以,我必须调用 OpenScannerSDK,传递一个带有指向某些函数的指针的回调集,做一些事情,最后调用 CloseScannerSDK。

我已经在我的 C# 应用程序中这样声明了:

[DllImport(DllName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "_OpenScannerSDK")]
extern public static bool OpenScannerSDK(IntPtr hwnd, TCallBackSet callbackSet, 
  [MarshalAs(UnmanagedType.LPWStr)]string configPath);

[DllImport(DllName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "_CloseScannerSDK")]
extern public static void CloseScannerSDK();

[StructLayout(LayoutKind.Sequential)]
public class TCallBackSet
{
    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void TOnScannerStatusEvent(int scannerStatus);

    [MarshalAs(UnmanagedType.FunctionPtr)]
    public TOnScannerStatusEvent ScannerStatusEvent;

    (I have removed the other 3 callbacks for brevity)
}

最后我像这样使用这个库:

var callback = new TCallBackSet() { ... set the delegates ... }
OpenScannerSDK(IntPtr.Zero, callback, ".");
... do other stuff...
CloseScannerSDK();

所有这一切似乎都有效 - OpenScannerSDK 和 CloseScannerSDK 以及我在它们之间使用的所有其他工具都可以正常工作。问题是,一旦应用程序试图退出,我就会在 KERNELBASE.dll 中得到一个 APPCRASH。我在崩溃报告文件中没有看到任何相关信息。我注意到,如果我不调用 OpenScannerSDK,而只是调用与委托(delegate)无关的 DLL 的其他一些函数,则 APPCRASH 不会发生。

我也为委托(delegate)尝试了 GC.KeepAlive,但没有效果。

最佳答案

几年前,我在将其他 C DLL 移植到 C# 时遇到了类似的问题。

C# 中的函数指针表示为委托(delegate)。在内部,委托(delegate)是类实例,它们由 GC 以与收集其他对象相同的方式收集。

可能在您的 DLL 中有一些方法可以“停止”API,使其停止调用 C++ 函数指针。您必须在关闭应用程序之前调用它。

可能您的应用程序收集委托(delegate)对象,当 C++ DLL 尝试从非托管代码调用时,发现无效的对象引用。

在 C# 中将这些委托(delegate)的引用保存在私有(private)字段中很有趣,以避免在应用程序运行时收集它们。此问题的症状是应用程序间歇性崩溃。

希望这对您有所帮助。

关于将 C++ 函数与委托(delegate)一起使用后,C# 应用程序在退出时崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24740804/

相关文章:

c# - 带有 params 关键字的委托(delegate)会匹配任何方法吗?

c# - 在 Xamarin 移动应用程序中显示存储在 Azure 存储中的 Blob/照片

c# - C# 中的 wglCreateContext 失败但托管 C++ 中没有

c++ - Linux/Windows 的 sleep 时间

ios - awakeFromNib 的好处?

c# - 为什么不用 .NET 风格的委托(delegate)而不是 Java 中的闭包?

c# - 从 C++ 到 C# 重写串口通信

c# - Linq 查询字典,其中列表中的值

c++ - 将大数字类型转换为较小类型

c++ - 如何从文本文件中取出标记并将其放入二维矩阵中?