我为c ++ dll创建了一个c#包装器,我没有c ++ dll的源代码。现在c ++有一个委托函数,我在c#wrapper中创建了委托函数,并为它提供了必要的参数。 面临的问题是每当委托函数完成时,我都会收到内存不足异常,并且我还发现委托使用了一个新线程。我将演示下面的代码:
1)C#wrapper
public struct WISCN_RUN_OPTS
{
public uint Version;
public WISCN_CALLBACK_CODELINE_DONE CodelineDoneCallback;
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public delegate bool WISCN_CALLBACK_CODELINE_DONE(
uint doc_index,
uint user_data,
uint codelines_count,
WISCN_CODELINE[] codelines,ref
WISCN_CODELINE_DOC_CTRL p_doc_ctrl);
[DllImport(@"wiscn.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
public static extern WISCN_ERROR WiScn_Run(_WISCN_HINST_STRUCT hinst, uint num_of_docs, ref uint p_docs_done, ref WISCN_RUN_OPTS p_opts);
2)C#windows应用程序
private void ButtonProcessDocsWithOcr_Click(object sender, EventArgs e)
{
var run_opts = new DllLoad.WISCN_RUN_OPTS
{
Version = DefineConstants.WISCN_STRUCT_VERSION_RUN_OPTS
CodelineDoneCallback = DocDoneCallback;
};
//The callback delegate is called when this method is triggered
WiScn_Run(hinst, 0, ref docNum, ref run_opts);
}
bool DocDoneCallback(uint doc_index, uint user_data,
uint codelines_count,
WISCN_CODELINE[] codelines,ref
WISCN_CODELINE_DOC_CTRL p_doc_ctrl)
{
return false;
}//After this line i receive the out of memory exception
// when it tries to resume ButtonProcessDocsWithOcr_Click event.
3)C ++包装器头文件
typedef struct
{
DWORD Version;
WISCN_CALLBACK_CODELINE_DONE CodelineDoneCallback;
}
WISCN_RUN_OPTS;
typedef BOOL (*WISCN_CALLBACK_CODELINE_DONE)(DWORD doc_index,
DWORD user_data, DWORD codelines_count, const WISCN_CODELINE codelines[],
WISCN_CODELINE_DOC_CTRL *p_doc_ctrl);
typedef WISCN_ERROR (WISCN_API *WISCN_RUN)(WISCN_HINST hinst, DWORD num_of_docs, LPDWORD p_docs_done, const WISCN_RUN_OPTS *p_opts);
WISCN_ERROR WISCN_API WiScn_Run(WISCN_HINST hinst, DWORD num_of_docs, LPDWORD p_docs_done, const WISCN_RUN_OPTS *p_opts);
4)c ++样本
BOOL DocDoneCallback(DWORD doc_index, DWORD user_data,
DWORD codelines_count, const WISCN_CODELINE codelines[],
WISCN_CODELINE_DOC_CTRL *p_doc_ctrl)
{
return FALSE;
}
void main()
{
WISCN_RUN _WiScn_Run;
WISCN_RUN_OPTS run_opts;
_WiScn_Run = (WISCN_RUN)GetProcAddress(hmod, "WiScn_Run");
run_opts.Version = WISCN_STRUCT_VERSION_RUN_OPTS;
run_opts.DocDoneCallback = DocDoneCallback;
_WiScn_Run(hinst, 0, NULL, &run_opts);
}
答案 0 :(得分:1)
您提到过非托管代码创建了一个新线程。在我看来,在非托管线程的上下文中调用回调似乎是合理的。通过致电GetCurrentThreadId
检查一下。
[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();
在致电WiScn_Run
然后在DocDoneCallback
之前拨打此电话。我假设您将发现您的回调在不同的线程中运行。
如果我对这种预感是对的,那么你永远不能用C#调用该库。您需要做的是将C ++代码包装在混合模式C ++ / CLI包装器中,以便您可以在非托管代码中实现回调函数。