2013-08-22 17 views
5

ja patrząc na wielu wątków o wyjątku „nie może przejść GCHandle całej AppDomains”, ale ja nadal nie rozumiem ....GCHandle, AppDomains kodu zarządzanego i 3rd party dll

pracuję z czytnik RFID obsługiwany przez bibliotekę DLL. Nie mam kodu źródłowego dla tej biblioteki DLL, ale tylko próbkę, aby pokazać, jak z niego korzystać.

Próbka działa świetnie, ale muszę skopiować kod w innym projekcie, aby dodać czytnik do oprogramowania pośredniego Microsoft Biztalk.

Problem polega na tym, że proces Microsoft Biztalk działa w innym AppDomain. Czytnik obsługuje zdarzenia po odczytaniu znacznika. Ale kiedy uruchomiłem go pod Microsoft Biztalk, dostałem ten denerwujący wyjątek.

Nie widzę żadnego rozwiązania, w jaki sposób, aby to działało ...

Oto kod, który może być interesujący:

// 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(); 
    } 
} 

Odpowiedz

1

Masz problem z gcroot<> helper class. Jest używany w kodzie, którego nikt nie widzi, wewnątrz tej biblioteki DLL. Jest często używany przez kod C++, który został zaprojektowany do współdziałania z kodem zarządzanym, gcroot <> przechowuje odniesienie do zarządzanego obiektu. Klasa używa typu GCHandle, aby dodać odniesienie. Metoda GCHandle.ToIntPtr() zwraca wskaźnik, który może przechowywać kod C++. Operacją, która nie powiedzie się, jest GCHandle.FromIntPtr(), używana przez kod C++ do odzyskiwania odwołania do obiektu.

Istnieją dwa podstawowe wyjaśnienia otrzymuję ten wyjątek:

  1. może być dokładne. Co się stanie, gdy zainicjujesz kod w bibliotece DLL z jednego AppDomain i użyjesz go w innym. Nie wynika to z fragmentu, w którym obiekt klasy Reader zostaje zainicjalizowany, więc istnieje niezerowa szansa, że ​​jest to wyjaśnienie. Upewnij się, że jest blisko kodu korzystającego z klasy Reader.

  2. Może to być spowodowane przezbłąd, obecny w kodzie C++ wewnątrz biblioteki DLL. Kod niezarządzany często cierpi na błędy wskaźnika, rodzaj błędu, który może przypadkowo nadpisać pamięć. Jeśli tak się stanie z polem przechowującym obiekt gcroot <>, to przez jakiś czas nic się nie dzieje. Dopóki kod nie spróbuje ponownie odzyskać odwołania do obiektu. W tym momencie CLR zauważa, że ​​uszkodzona wartość wskaźnika nie pasuje do rzeczywistego uchwytu obiektu i generuje ten wyjątek. Jest to z pewnością trudny do rozwiązania problem, ponieważ dzieje się to w kodzie, którego nie da się naprawić, i pokazując programistę, który nad nim pracował, jest bardzo trudny do zlikwidowania, takie problemy z uszkodzeniem pamięci nigdy nie powodują błędów.

Najpierw wykonaj pocisk # 1. Istnieją przyzwoite szanse, że Biztalk uruchomi twój kod C# w oddzielnym AppDomain. I że biblioteka DLL zostanie wczytana zbyt wcześnie, przed lub podczas tworzenia aplikacji AppDomain. Coś, co można zobaczyć za pomocą ProcMon SysInternals. Utwórz repro tego, pisząc mały program testowy, który tworzy AppDomain i uruchamia kod testowy. Jeśli powiela to awarię, będziesz miał bardzo dobry sposób, aby zademonstrować problem dostawcy RFID, a niektórzy mają nadzieję, że go wykorzystają i popracują nad poprawką.

Posiadanie dobrych relacji roboczych z dostawcą czytnika RFID w celu uzyskania rozwiązania będzie bardzo ważne. To nigdy nie stanowi problemu, zawsze jest dobry powód, by robić zakupy gdzie indziej.

+0

Najpierw dziękuję za odpowiedź.Właściwie udało mi się wprowadzić obiekt z biblioteki DLL i użyć go. Jak widać w powyższym kodzie, podłączam metodę (ResultHandlerSyncGetEPCs) do zdarzenia wysyłanego przez czytnik, gdy czyta znaczniki. Awaria kodu źródłowego w linii czekającej na zdarzenie ... Nie czeka na co najmniej 10 sekund na przekroczenie limitu czasu, natychmiast rzuca "nie można przekazać GCHandle ..." wyjątku. – hurtauda

+0

I widzę, że czytnik jest dobrze podłączony i może odbierać metodę "Reader.KSRWSyncGetEPCs();" , ponieważ czyta znaczniki na antenie w tym momencie. – hurtauda

+0

Podałem konkretną rekomendację, aby zdiagnozować źródło problemu. Jeśli nie chcesz tego robić, skontaktuj się bezpośrednio ze sprzedawcą w celu uzyskania wsparcia. –

Powiązane problemy