首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >将托管回调传递给DllImport (ed)函数

将托管回调传递给DllImport (ed)函数
EN

Stack Overflow用户
提问于 2011-06-24 13:48:09
回答 2查看 974关注 0票数 2

我有一段代码,在非托管函数调用的垃圾收集委托方面抛出了异常。这是代码:

代码语言:javascript
运行
复制
// Setup Callback functions
errorCode = gsapi_set_stdio(ghostScriptPtr, new StdioMessageEventHandler(RaiseStdInCallbackMessageEvent), new StdioMessageEventHandler(RaiseStdOutCallbackMessageEvent), new StdioMessageEventHandler(RaiseStdErrCallbackMessageEvent));

if (errorCode >= 0)
{
    try
    {
        //GC.SuppressFinalize(this);
        // Init the GhostScript interpreter
        errorCode = gsapi_init_with_args(ghostScriptPtr, commandParameters.Length, commandParameters);

        // Stop the Ghostscript interpreter
        gsapi_exit(ghostScriptPtr);
    }
    finally
    {
        // Release the Ghostscript instance handle
        gsapi_delete_instance(ghostScriptPtr);
    }
}

传递给函数的_Raise.变量在被函数调用之前正在被释放。

我不知道自己发生了什么,但我将回调更改为变量:

代码语言:javascript
运行
复制
var _RaiseStdInCallbackMessageEventHandler = new StdioMessageEventHandler(RaiseStdInCallbackMessageEvent);
var _RaiseStdOutCallbackMessageEventHandler = new StdioMessageEventHandler(RaiseStdOutCallbackMessageEvent);
var _RaiseStdErrCallbackMessageEventHandler = new StdioMessageEventHandler(RaiseStdErrCallbackMessageEvent);
// Setup Callback functions
errorCode = gsapi_set_stdio(ghostScriptPtr, _RaiseStdInCallbackMessageEventHandler, _RaiseStdOutCallbackMessageEventHandler, _RaiseStdErrCallbackMessageEventHandler);

最后阻止:

代码语言:javascript
运行
复制
    finally
    {
        // Release the Ghostscript instance handle
        gsapi_delete_instance(ghostScriptPtr);
        _RaiseStdInCallbackMessageEventHandler = _RaiseStdOutCallbackMessageEventHandler = _RaiseStdErrCallbackMessageEventHandler = null;
    }

它解决了这个问题。为什么?我不知道。也许只是个巧合。我有一种直觉,认为在最终块中使用变量会导致变量的对象没有提前处理(因为它在最终块中使用)。这是真的吗?无论如何,提供带有托管回调的dllimported函数是一种正确的方法吗?

谢谢你,帕维尔

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-06-24 16:47:27

是的,你这样做是正确的。不完全是。垃圾收集器无法知道本机代码对委托的引用。它被掩埋在由Marshal.GetFunctionPointerForDelegate()生成的一次雷击中,这是GC无法触及的。因此,您必须有另一个对委托的引用,一个GC可以看到的引用。

通过使用局部变量,GC还可以遍历堆栈和CPU寄存器,并可以看到委托引用。但是,当您在没有调试器的情况下以发行模式运行代码时,这会出错。通过附加调试器,抖动报告局部变量的生存期,直到方法结束为止。这样调试就容易多了。如果没有调试器,它将不再这样做。即使在最后块中将变量设置为null时,抖动优化器也会删除该赋值。在发布版本中启用了优化器。

最好的方法是将委托引用存储在类的一个字段中。并确保类对象的生存期足以超过回调。其次,最好在局部变量上使用GC.KeepAlive()。

票数 4
EN

Stack Overflow用户

发布于 2011-06-24 15:54:58

您的文章并不包含理解所发生的事情所需的所有信息:非托管函数原型、PInvoke声明。无论如何,查看问题标题,我发现您需要使用Marshal.GetFunctionPointerForDelegate方法--这是将托管回调传递给非托管代码的方法。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6468727

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档