【问题标题】:How should a delegate be returned for unmanaged code when called from a callback?从回调中调用时,应如何为非托管代码返回委托?
【发布时间】:2011-02-04 00:36:47
【问题描述】:

我有一种情况,我正在单步执行非/托管代码,我认为我的方法导致我得到“FatalExecutionEngineError”。具体来说,我有一个 C# 回调(“X”),它将另一个回调(“Y”)返回到 C#,其中 X 和 Y 都由非托管 C++ 代码(由 C# 调用)调用。从回调 Y 返回时抛出错误。


Dll 导入语句:

[DllImport ("SearchDLL.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern unsafe bool Dll_Search_Text (..., delegate_add_result Fn);

非托管 C 代码:

extern "C" {
__declspec(dllexport) bool Dll_Search_Text (..., bool (*Add_Result (int, int)) (int, int, int)) {
    bool (*Add_Result_Word) (int, int, int);
    bool Add_Word_Ret;

    ...    
    Add_Result_Word = Add_Result ([int param], [int param]);
    if (0 == Add_Result_Word) return false;
    ...

        for (Itr=Set->begin (); Itr != Set->end (); Itr++) {
            ...
            Add_Word_Ret = Add_Result_Word ([int param], [int param], [int param]);   
            }
        }

    return true;
    }
}

委托定义:

public delegate bool delegate_add_result_word (int A, int B, int C);
public delegate delegate_add_result_word delegate_add_result (int D, int E);

错误信息:

"Managed Debugging Assistant 'FatalExecutionEngineError' has detected a
problem in 'C:\Neuric\bin\Search.exe'. Additional Information: The 
runtime has encountered a fatal error. The address of the error was
at 0x6ea2ceca, on thread 0x744. The error code is 0xc0000005. This 
error may be a bug in the CLR or in the unsafe or non-verifiable 
portions of user code. Common sources of this bug include user marshaling
errors for COM-interop or PInvoke, which may corrupt the stack."

代码有时可以工作(在我添加嵌套回调之前工作得很好),但在其余时间抛出此异常。

【问题讨论】:

  • 您如何将 .NET 委托转换为 C 函数指针,您如何处理函数指针/委托以支持转换?
  • x86 或 x64 的架构是什么?

标签: c# c++ delegates unmanaged dllimport


【解决方案1】:

代表通常使用 fastcall。但是 c 风格的函数指针使用 cdecl。使用 UnamangedFuntionPointer-attribute 标记您的委托。

【讨论】:

  • 哈哈!我知道它是这样的,但我不确定如何标记它。谢谢你!现在可以了。 ^__^
  • @Amanduh,别忘了给答案投票,并将最佳答案标记为答案。
  • @Eamon Nerbonne,哦,谢谢。这只是我第二次提问。
【解决方案2】:

我不确定究竟你在做什么,但我能想到两个原因。我假设您已将委托转换为函数指针。那么……

  • 您必须确保委托对象没有被垃圾回收。 GC 看不到您的函数指针,因此它会立即清理委托。命名空间 msclr 中有一些句柄句柄容器,但如果您正在处理复杂的场景,您可能需要手动分配 GCHandle。当然,您可能已经这样做了;-)。
  • 您必须进一步确保对 GC 控制的对象的引用在您访问它时不会移动。 pin_ptr 是在本地执行此操作的一种方法,但您听起来像是以一种复杂的方式传递东西,所以这可能意味着您需要手动固定对象,使用 GCHandle.Alloc(..., GCHandleType.Pinned)

【讨论】:

  • 我一直担心这种情况(但同样,不确定解决方法到底是什么),但使用你给我的信息我能够找到这个:social.msdn.microsoft.com/Forums/en-US/clr/thread/… 似乎代表不会四处走动,但我仍然必须想办法“延长代表的生命”。我应该能够在我的托管类中添加对委托的引用,不是吗?
  • 感谢您的链接!事实上,你的托管类中的引用应该没问题,只要类本身是某处的引用,即;-)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-09-18
  • 2012-07-03
  • 2013-08-24
  • 1970-01-01
  • 2015-02-24
  • 1970-01-01
  • 2020-08-26
相关资源
最近更新 更多