2013-08-22 14 views
5

ho guardando molte discussioni circa l'eccezione "non può passare un GCHandle attraverso AppDomain" ma io ancora non capisco ....GCHandle, AppDomain codice gestito e 3 ° dll parti

sto lavorando con un lettore RFID guidato da una DLL. Non ho codice sorgente per questa DLL ma solo un esempio per mostrare come usarlo.

L'esempio funziona benissimo ma devo copiare del codice in un altro progetto per aggiungere il lettore al middleware Microsoft Biztalk.

Il problema è che il processo di Microsoft Biztalk funziona in un altro AppDomain. Il lettore gestisce gli eventi quando viene letto un tag. Ma quando lo eseguo sotto Microsoft Biztalk ho ottenuto questa fastidiosa eccezione.

Non riesco a vedere alcuna soluzione su come farlo funzionare ...

Ecco alcuni codice che potrebbe essere interessante:

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

risposta

1

Si stanno avendo un problema con il gcroot<> helper class. È usato nel codice che nessuno può vedere, all'interno di quella DLL. Viene spesso utilizzato dal codice C++ progettato per l'interoperabilità con il codice gestito, gcroot <> memorizza un riferimento a un oggetto gestito. La classe usa il tipo GCHandle per aggiungere il riferimento. Il metodo GCHandle.ToIntPtr() restituisce un puntatore che il codice C++ può memorizzare. L'operazione che non riesce è GCHandle.FromIntPtr(), utilizzata dal codice C++ per recuperare il riferimento all'oggetto.

Ci sono due spiegazioni di base per ottenere questa eccezione:

  1. Può essere precisi. Che avverrà quando hai inizializzato il codice nella DLL da un AppDomain e lo usi in un altro. Non è chiaro dallo snippet in cui l'oggetto della classe Reader viene inizializzato così ci sono delle probabilità non-zero che questa è la spiegazione. Assicurati di tenerlo vicino al codice che utilizza la classe Reader.

  2. Può essere causato da un altro bug, presente nel codice C++ all'interno della DLL. Il codice non gestito soffre spesso di bug puntatori, il tipo di bug che può accidentalmente sovrascrivere la memoria. Se ciò accade con il campo in cui è memorizzato l'oggetto gcroot <>, nulla può andare storto per un po 'di tempo. Fino a quando il codice tenta di ripristinare nuovamente il riferimento all'oggetto. A quel punto, CLR rileva che il valore del puntatore danneggiato non corrisponde più a un handle di oggetto effettivo e genera questa eccezione. Questo è sicuramente il difficile tipo di bug da risolvere poiché ciò accade nel codice che non è possibile correggere e mostrare il programmatore che ha funzionato su di esso una repro per il bug è molto difficile, problemi di corruzione della memoria che non si ripropongono mai bene.

Primo pallino # 1. Esistono probabilità decenti che Biztalk esegua il codice C# in un AppDomain separato. E che la DLL venga caricata troppo presto, prima o durante la creazione di AppDomain. Qualcosa che puoi vedere con ProcMon di SysInternals. Crea una riproduzione di ciò scrivendo un piccolo programma di test che crea un AppDomain ed esegue il codice di test. Se questo riproduce il crash, avrai un ottimo modo per dimostrare il problema al fornitore RFID e alcuni sperano che lo usino e lavorino su una correzione.

Avere un buon rapporto di lavoro con il fornitore di lettori RFID per ottenere una risoluzione sarà molto importante. Non è mai un problema, è sempre una buona ragione per andare a fare shopping altrove.

+0

Innanzitutto grazie per la risposta.In realtà, riesco a instanziare un oggetto dalla DLL e usarlo. Come puoi vedere nel codice qui sopra, collego un metodo (ResultHandlerSyncGetEPCs) all'evento che il lettore invia quando legge i tag. Il codice sorgente si blocca sulla linea che è in attesa di un evento ... Non attende almeno 10 secondi per un timeout, lancia immediatamente l'eccezione "impossibile passare GCHandle ...". – hurtauda

+0

E posso vedere che il lettore è ben collegato e può ricevere il metodo 'Reader.KSRWSyncGetEPCs();' perché sta leggendo i tag sull'antenna in questo momento. – hurtauda

+0

Ho dato una raccomandazione specifica per diagnosticare la fonte del problema. Se non si desidera eseguire questa operazione, contattare direttamente il fornitore per ricevere assistenza. –

Problemi correlati