从c#调用c ++委托内存异常

时间:2014-01-10 22:40:02

标签: c# c++ memory delegates

我为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);
}

1 个答案:

答案 0 :(得分:1)

您提到过非托管代码创建了一个新线程。在我看来,在非托管线程的上下文中调用回调似乎是合理的。通过致电GetCurrentThreadId检查一下。

[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();

在致电WiScn_Run然后在DocDoneCallback之前拨打此电话。我假设您将发现您的回调在不同的线程中运行。

如果我对这种预感是对的,那么你永远不能用C#调用该库。您需要做的是将C ++代码包装在混合模式C ++ / CLI包装器中,以便您可以在非托管代码中实现回调函数。