2013-08-22 84 views
5

Tôi đã nhìn vào nhiều chủ đề về ngoại lệ "không thể vượt qua một GCHandle trên AppDomains" nhưng tôi vẫn không nhận được nó ....GCHandle, AppDomains quản lý mã và 3 dll bên

Tôi đang làm việc với một đầu đọc RFID được điều khiển bởi một DLL. Tôi không có mã nguồn cho DLL này nhưng chỉ có một mẫu để hiển thị cách sử dụng nó.

Mẫu hoạt động tốt nhưng tôi phải sao chép một số mã trong một dự án khác để thêm người đọc vào phần mềm trung gian Microsoft Biztalk.

Vấn đề là quá trình Microsoft Biztalk hoạt động trong một AppDomain khác. Trình đọc xử lý các sự kiện khi một thẻ được đọc. Nhưng khi tôi chạy nó dưới Microsoft Biztalk tôi đã nhận được ngoại lệ này gây phiền nhiễu.

Tôi không thể nhìn thấy bất kỳ giải pháp làm thế nào để làm cho nó hoạt ...

Dưới đây là một số mã có thể là thú vị:

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

Trả lời

1

Bạn đang gặp vấn đề với các gcroot<> helper class. Nó được sử dụng trong mã mà không ai có thể nhìn thấy, bên trong DLL đó. Nó thường được sử dụng bởi mã C++ được thiết kế để interop với mã được quản lý, gcroot <> lưu trữ một tham chiếu đến một đối tượng được quản lý. Lớp này sử dụng loại GCHandle để thêm tham chiếu. Phương thức GCHandle.ToIntPtr() trả về một con trỏ mà mã C++ có thể lưu trữ. Thao tác thất bại là GCHandle.FromIntPtr(), được sử dụng bởi mã C++ để khôi phục tham chiếu đến đối tượng.

Có hai cách giải thích cơ bản để có được ngoại lệ này:

  1. Nó có thể là chính xác. Điều này sẽ xảy ra khi bạn khởi tạo mã trong DLL từ một AppDomain và sử dụng nó trong một tên miền khác. Nó không phải là rõ ràng từ đoạn mà đối tượng lớp Reader được khởi tạo để có tỷ lệ cược khác không phải là giải thích. Hãy chắc chắn giữ nó gần với mã sử dụng lớp Reader.

  2. Nó có thể được gây ra bởi lỗi khác, hiện diện trong mã C++ bên trong DLL. Mã không được quản lý thường bị lỗi con trỏ, loại lỗi có thể vô tình ghi đè lên bộ nhớ. Nếu điều đó xảy ra với trường lưu trữ gcroot <> đối tượng thì không có gì xảy ra trong một thời gian. Cho đến khi mã cố gắng khôi phục lại tham chiếu đối tượng một lần nữa. Tại thời điểm đó CLR nhận thấy rằng giá trị con trỏ bị hỏng không còn khớp với một đối tượng xử lý thực tế và tạo ra ngoại lệ này. Điều này chắc chắn là loại lỗi khó giải quyết vì điều này xảy ra trong mã bạn không thể sửa chữa và hiển thị lập trình viên làm việc trên nó một repro cho lỗi này là rất khó, các vấn đề tham nhũng bộ nhớ như vậy không bao giờ repro tốt.

Đuổi đạn đầu tiên # 1 trước. Có tỷ lệ cược khá là Biztalk chạy mã C# của bạn trong một AppDomain riêng biệt. Và rằng DLL được tải quá sớm, trước hoặc trong khi AppDomain được tạo ra. Một cái gì đó bạn có thể nhìn thấy với SysInternals 'ProcMon. Tạo một repro này bằng cách viết một chương trình thử nghiệm nhỏ tạo ra một AppDomain và chạy mã kiểm thử. Nếu đó tái tạo vụ tai nạn thì bạn sẽ có một cách rất tốt để chứng minh vấn đề cho nhà cung cấp RFID và một số hy vọng rằng họ sẽ sử dụng nó và làm việc trên một sửa chữa.

Có mối quan hệ làm việc tốt với nhà cung cấp đầu đọc RFID để đạt được giải pháp sẽ rất quan trọng. Đó không bao giờ không phải là một vấn đề, luôn luôn là một lý do tốt để đi mua sắm ở nơi khác.

+0

Đầu tiên cảm ơn bạn đã trả lời.Trên thực tế, tôi thành công trong instanciating một đối tượng từ dll và sử dụng nó. Như bạn có thể thấy trong đoạn mã trên, tôi cắm một phương thức (ResultHandlerSyncGetEPCs) vào sự kiện mà người đọc gửi khi đọc thẻ. Sự cố mã nguồn tại dòng đang đợi một sự kiện đến ... Nó không chờ đợi ít nhất 10 giây cho một thời gian chờ, nó ném "không thể vượt qua GCHandle ..." ngoại lệ ngay lập tức. – hurtauda

+0

Và tôi có thể thấy rằng đầu đọc được kết nối tốt và có thể nhận phương thức 'Reader.KSRWSyncGetEPCs(); ' vì nó đang đọc thẻ trên ăng ten tại thời điểm này. – hurtauda

+0

Tôi đã đưa ra một đề xuất cụ thể để chẩn đoán nguồn gốc của vấn đề. Nếu bạn không muốn theo đuổi điều này thì hãy liên hệ trực tiếp với nhà cung cấp để được hỗ trợ. –