C# C应用程序在使用C+后退出时崩溃+;与代表一起工作 我的C语言应用程序需要和C++编写的DLL对话。我没有这个DLL的代码,但是我有一个演示应用程序的代码(同样是C++),它使用这个DLL并工作 这是C++演示应用程序的有趣代码。它有两个函数,其中一个接受由4个委托组成的回调集 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);

C# C应用程序在使用C+后退出时崩溃+;与代表一起工作 我的C语言应用程序需要和C++编写的DLL对话。我没有这个DLL的代码,但是我有一个演示应用程序的代码(同样是C++),它使用这个DLL并工作 这是C++演示应用程序的有趣代码。它有两个函数,其中一个接受由4个委托组成的回调集 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);,c#,c++,delegates,dllimport,C#,C++,Delegates,Dllimport,所以,我必须调用OpenScannerSDK,传递一个带有指向某些函数的指针的回调集,做一些事情,最后调用CloseScannerSDK 我在我的C#应用程序中这样声明: [DllImport(DllName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "_OpenScannerSDK")] extern public static bool OpenScannerSDK(IntPtr hwnd, TCallBackSet

所以,我必须调用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,而只是调用DLL中与委托无关的一些其他函数,APPCRASH就不会发生


我还为代理尝试了GC.KeepAlive,没有效果

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

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

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

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

有趣的是,将这些委托的C#引用保存在私有字段中,以避免在应用程序运行时收集它们。这个问题的症结在于应用程序会间歇性崩溃


希望这能有所帮助。

进一步测试后,我发现实际上OpenScannerSDK总是返回True,这让我相信它工作正常,但情况可能并非如此。我做了几个测试,包括传递一个没有任何成员的TCallBackSet结构,OpenScannerSDK仍然返回True


所以问题似乎出在TCallBackSet和这些代理上。有点不对劲。我试着传递回拨键w和w/o ref,没有区别。C++中的INTEN INT与C语言中的int不一样,因此改变函数签名来使用短而不是int。这些都没有任何区别。p> 对于任何感兴趣的人,这里是最终的工作解决方案

首先,CallBackSet的定义如下:

[StructLayout(LayoutKind.Sequential)]
public class CallBackSet
{
    public IntPtr ScannerStatusEvent;
    public IntPtr ScannerNotifyEvent;
    public IntPtr RfidStatusEvent;
    public IntPtr RfidNotifyEvent;
}
然后:

OnScannerStatusEvent onScannerStatus = (ScannerStatus status) => {...};
OnScannerNotifyEvent onScannerNotify = (ScannerNotify notify, short lparam) => {...};
OnRfidStatusEvent onRfidStatus = (RfidStatus status) => {...};
OnRfidNotifyEvent onRfidNotify = (RfidNotify notify) => {...};

GCHandle.Alloc(onScannerStatus);
GCHandle.Alloc(onScannerNotify);
GCHandle.Alloc(onRfidStatus);
GCHandle.Alloc(onRfidNotify);

callbackSet = new CallBackSet()
{
    RfidNotifyEvent = Marshal.GetFunctionPointerForDelegate(onRfidNotify),
    RfidStatusEvent = Marshal.GetFunctionPointerForDelegate(onRfidStatus),
    ScannerNotifyEvent = Marshal.GetFunctionPointerForDelegate(onScannerNotify),
    ScannerStatusEvent = Marshal.GetFunctionPointerForDelegate(onScannerStatus)
};

callbackPtr = Marshal.AllocHGlobal(Marshal.SizeOf(callbackSet));
Marshal.StructureToPtr(callbackSet, callbackPtr, false);

OpenScannerSDK(IntPtr.Zero, callbackPtr, ".");

C++ API是否复制了 TcLaBeSETSE//>,或者存储了一个指针,您没有通过C++的DLL代码,所以我不知道它的内部工作。这也是我的想法,CeleSnEnnRSDK函数应该是这样做的,释放您通过OpenScNeNSDK传递的回调指针。问题是CloseScannerSDK执行正确,然后在我的应用程序尝试退出时发生崩溃。我也知道,在C++库中可能有一个代码错误(没有正确地释放指针),但是使用库的C++演示应用程序工作。但是,在使用DLL时,它使用LoadLibrary和FreeLibrary。也许如果我也这样做,在应用程序退出之前释放库,这将解决问题。