GCHandle,AppDomains托管代码和第三方dll

时间:2013-08-22 11:50:55

标签: c#-4.0 dll biztalk unmanaged appdomain

我看过很多关于异常的帖子“无法通过AppDomains传递GCHandle”,但我仍然没有得到它....

我正在使用由DLL驱动的RFID阅读器。我没有此DLL的源代码,只有一个示例来说明如何使用它。

该示例效果很好,但我必须在另一个项目中复制一些代码,以将读取器添加到中间件Microsoft Biztalk。

问题是Microsoft Biztalk的进程在另一个AppDomain中运行。阅读器在读取标签时处理事件。但是当我在Microsoft Biztalk下运行时,我遇到了这个令人烦恼的异常。

我看不出任何有关如何使其发挥作用的解决方案......

以下是一些可能有趣的代码:

// Let's connecting the result handlers.
// The reader calls a command-specific result handler if a command is done and the answer is ready to send.
// So let's tell the reader which functions should be called if a result is ready to send.

// result handler for reading EPCs synchronous
Reader.KSRWSetResultHandlerSyncGetEPCs(ResultHandlerSyncGetEPCs);

[...]

var readerErrorCode = Reader.KSRWSyncGetEPCs();
if (readerErrorCode == tKSRWReaderErrorCode.KSRW_REC_NoError)
{
    // No error occurs while sending the command to the reader. Let's wait until the result handler was called.
    if (ResultHandlerEvent.WaitOne(TimeSpan.FromSeconds(10)))
    {
        // The reader's work is done and the result handler was called. Let's check the result flag to make sure everything is ok.
        if (_readerResultFlag == tKSRWResultFlag.KSRW_RF_NoError)
        {
             // The command was successfully processed by the reader.
             // We'll display the result in the result handler.
        }
        else
        {
            // The command can't be proccessed by the reader. To know why check the result flag.
            logger.error("Command \"KSRWSyncGetEPCs\" returns with error {0}", _readerResultFlag);
        }
    }
    else
    {
        // We're getting no answer from the reader within 10 seconds.
        logger.error("Command \"KSRWSyncGetEPCs\" timed out");
    }
}

[...]

private static void ResultHandlerSyncGetEPCs(object sender, tKSRWResultFlag resultFlag, tKSRWExtendedResultFlag extendedResultFlag, tKSRWEPCListEntry[] epcList)
{
    if (Reader == sender)
    {
        // Let's store the result flag in a global variable to get access from everywhere.
        _readerResultFlag = resultFlag;

        // Display all available epcs in the antenna field.
        Console.ForegroundColor = ConsoleColor.White;
        foreach (var resultListEntry in epcList)
        {
            handleTagEvent(resultListEntry);
        }

        // Let's set the event so that the calling process knows the command was processed by reader and the result is ready to get processed.
        ResultHandlerEvent.Set();
    }
}

1 个答案:

答案 0 :(得分:1)

您遇到gcroot<> helper class的问题。它被用在DLL中没有人能看到的代码中。它经常被设计用于与托管代码交互的C ++代码使用,gcroot&lt;&gt;存储对托管对象的引用。该类使用GCHandle类型添加引用。 GCHandle.ToIntPtr()方法返回C ++代码可以存储的指针。失败的操作是GCHandle.FromIntPtr(),由C ++代码用于恢复对象的引用。

获得此例外有两种基本解释:

  1. 它可以准确。当您从一个AppDomain初始化DLL中的代码并在另一个AppDomain中使用它时,会发生这种情况。从片段中不清楚Reader类对象的初始化,因此存在非零概率,这就是解释。请务必将其与使用Reader类的代码保持一致。

  2. 它可能是由另一个错误引起的,存在于DLL内部的C ++代码中。非托管代码经常遇到指针错误,这种错误可能会意外覆盖内存。如果在存储gcroot&lt;&gt;的字段中发生这种情况对象然后一段时间没有出错。直到代码再次尝试恢复对象引用。此时,CLR注意到损坏的指针值不再与实际对象句柄匹配,并生成此异常。这肯定是一个难以解决的问题,因为这种情况发生在你无法修复的代码中,并且显示在其上工作的程序员非常困难,这样的内存损坏问题永远不会很好。

  3. 首先追逐子弹#1。 Biztalk在单独的AppDomain中运行您的C#代码有不错的赔率。并且在创建AppDomain之前或期间,DLL过早加载。你可以用SysInternals的ProcMon看到的东西。通过编写一个创建AppDomain并运行测试代码的小测试程序来创建一个repro。如果再次发生崩溃,那么你将有一个非常好的方法来向RFID供应商展示这个问题,并希望他们能够使用它并进行修复。

    与RFID阅读器供应商建立良好的合作关系以获得解决方案将非常重要。这绝不是一个问题,总是在其他地方购物的好理由。

相关问题