2

我这样做是为了从 C 代码中调用非托管函数。pCallback 是一个函数指针,因此托管端是一个委托。

[DllImport("MyDLL.dll")]

public static extern Result SetCallback(
            IntPtr handle,
            Delegate pCallback,
            CallbackType Type);

现在我正在设置

    public delegate void pfnCallback(uint PromptID, ttsEventType evt, IntPtr lData);

    public Form1()
    {
        pfnCallback cb = new pfnCallback(cback);
        (...)
        Wrapper.SetCallback(handle, cb, IntPtr.Zero, CallBackType.DEFAULT);
        (...)
        }

它给了我一个错误说“......当将委托传递给非托管代码时,它们必须保持活动......”

谁能帮我 ?

问候

4

4 回答 4

3

据我了解该消息,您应该这样做:

public delegate void pfnCallback(uint PromptID, ttsEventType evt, IntPtr lData);

public pfnCallback cb = new pfnCallback(cback);

public Form1()
{
    (...)
    Wrapper.SetCallback(handle, cb, IntPtr.Zero, CallBackType.DEFAULT);
    (...)
}
于 2010-02-17T12:34:27.777 回答
3

我相信您需要扩展 cb 的范围以确保该变量将继续存在并在非托管代码可能想要调用它时引用回调函数。非托管代码不参与 .NET 引用跟踪,因此如果您不强制在 .NET 代码中保留对回调的引用,它将被框架释放,并且非托管代码将无法在之后正确调用它那。

于 2010-02-17T12:36:12.687 回答
2

您将委托类型声明与委托实例混淆了。是的,您公开了您的代表声明,这是错误的。只有 Form1 类使用它,它应该是私有的。在这里重要的是委托的实例,即您使用 new 语句创建的实例。

现在,您将实例存储在 Form1 构造函数的局部变量中。这会使实例的引用保持几微秒。一旦构造函数完成,该引用就消失了,垃圾收集器可以在之后的任何时候收集委托实例。它看不到非托管代码保留对它的引用,收集器只能发现托管代码持有的引用。

当非托管代码在收集的委托实例上调用回调时,没有什么好事发生,您会听到响亮的咔嚓声。您必须更改代码,以便对实例进行托管引用。一种简单的方法是向 Form1 类添加一个私有成员来存储实例。

即使这样可能还不够好,Form1 对象也将在将来的某个时候被垃圾收集。它也收集委托对象。您还必须确保非托管代码在此之后不能使用回调。鉴于类的名称(Form1),在这种特定情况下不太可能发生。但是进行防御性代码并进行调用以重置表单的 FormClosing 事件处理程序中的回调。

于 2010-02-17T14:12:01.393 回答
0

cb全局尝试回调变量

于 2010-02-17T12:38:43.990 回答