2009-08-05 20 views
18

Tôi có đoạn mã sau:Không thể đúc tượng COM kiểu ngoại lệ

public void Test(IMyInterface iInterface) 
{ 
    iInterface.CallMethod (); 
} 

nào hoạt động tốt. Tuy nhiên, nếu tôi thay đổi mã để được luồng:

private IMyInterface myInterface; 
public void Test(IMyInterface iInterface) 
{ 
    myInterface = iInterface; 
    new Thread (new ThreadStart (CallInterfaceMethod)).Start (); 
} 

public void CallInterfaceMethod () 
{ 
    myInterface.CallMethod () 
} 

Khi tôi sử dụng các chủ đề tôi nhận được ngoại lệ:

Không thể đúc tượng COM của loại 'Hệ thống .__ ComObject' giao diện gõ 'IMyInterface' . Thao tác này không thành công do cuộc gọi QueryInterface trên thành phần COM cho giao diện với IID '{GUID}' không thành công do lỗi sau: Không có giao diện nào được hỗ trợ

Nhưng giao diện nên được hỗ trợ tốt? Bất cứ ai có bất kỳ suy nghĩ về những gì đang xảy ra ở đây?

+0

http://blogs.msdn.com/b/oldnewthing/archive/2004/12/13/281910.aspx – EricLaw

Trả lời

20

Ngoại lệ khó chịu, khó chịu này phát sinh do một khái niệm được gọi là COM marshalling. Bản chất của vấn đề nằm trong thực tế là để tiêu thụ các đối tượng COM từ bất kỳ chủ đề nào, luồng phải có quyền truy cập vào thông tin kiểu mô tả đối tượng COM.

Trong trường hợp của bạn được mô tả, lý do không thành công trong chuỗi thứ hai là do luồng thứ hai không có thông tin kiểu cho giao diện.

Bạn có thể thử thêm dòng sau vào code của bạn:

[ComImport] 
[Guid("23EB4AF8-BE9C-4b49-B3A4-24F4FF657B27")] 
public interface IMyInterface 
{ 
    void CallMethod(); 
} 

Về cơ bản tuyên bố trên chỉ thị COM NET framework nạp để tải loại thông tin sử dụng kỹ thuật truyền thống từ registry và xác định vị trí thư viện kiểu gắn liền và đi từ đó.

Bạn cũng nên hạn chế việc tạo đối tượng COM thành một chuỗi duy nhất (để ngăn chặn việc sắp xếp chuỗi) để giúp giải quyết vấn đề này.

Để tóm tắt, lỗi này xoay quanh thông tin loại và sắp xếp chủ đề. Hãy chắc chắn rằng mỗi thread muốn truy cập đối tượng COM có thông tin liên quan để unmarshal đối tượng từ thread nguồn.

PS: Sự cố này được giải quyết trong .NET 4.0 sử dụng kỹ thuật được gọi là "Loại Tương đương"

+0

Cảm ơn bạn đã trả lời. Sự bùng nổ của bạn có ý nghĩa và tìm kiếm sự giải mã ComImport trên MSDN dường như cũng có ý nghĩa. Chúc mừng. – Kyle

+0

Đó là niềm vui của tôi :) Tôi đã chạy vào vấn đề này trước và đó là một cơn ác mộng để thử và giải quyết, cho đến khi bóng đèn tắt và tôi đã kết thúc tiêu thụ đối tượng COM từ chủ đề tạo ra nó. –

+1

[+1] Cảm ơn rất nhiều bạn! Đối với tôi, lỗi là [STAThread] bị thiếu. Câu hỏi và câu trả lời này đã dẫn tôi đến tìm nó sau khi đọc vấn đề luồng. – Marc

-1

Vâng, đối với một, bạn đang thực hiện cuộc gọi cross-thread đến một đối tượng mà không khóa nó, điều này tự động sẽ gây ra một số vấn đề. Mã của bạn sẽ trông như thế hơn:

private IMyInterface myInterface; 
private static readonly object _myObjectLock = new object(); 

public void Test(IMyInterface iInterface) 
{ 
    myInterface = iInterface; 
    new Thread (new ThreadStart (CallInterfaceMethod)).Start (); 
} 

public void CallInterfaceMethod () 
{ 
    lock(_myObjectLock) 
    { 
     myInterface.CallMethod (); 
    } 
} 

Từ những gì tôi hiểu, lỗi mà bạn liệt kê đôi khi có thể xảy ra khi tài nguyên không thể truy cập, trong đó, với một hoạt động cross-đề như thế này, sẽ rất có thể xảy ra. Đừng báo cho tôi về nó mặc dù, tôi không có chuyên gia COM.

Thật sự, tôi không nghĩ rằng tôi sẽ tiếp cận gọi phương pháp này theo cách này, quá nhiều rủi ro khi làm như vậy. Bạn đã xem xét sử dụng một số ParameterizedThreadStart và truyền đối tượng qua cách đó chưa? Bạn vẫn cần phải khóa các đối tượng của mình một cách an toàn cho các hoạt động chéo, nhưng nó sẽ an toàn hơn.

Ngoài ra, hãy kiểm tra để đảm bảo rằng lớp "myInterface" của bạn vẫn có thể gọi phương thức "CallMethod()". Giao diện không có triển khai, bạn có thể gặp sự cố khi đặt "myInterface = iInterface".

+0

Hơn bạn cho câu trả lời, nhưng sử dụng ParameterizedThreadStart không hoạt động (Có hoặc không có khóa). Ngoài ra tôi đã kiểm tra, myInterface vẫn có thể "CallMethod" một khi nó đã được thiết lập (myInterface = iInterface). – Kyle

+0

Có hai bit thông tin sai lạc trong câu trả lời này: ** 1. ** Truy cập đối tượng chéo không * luôn luôn * tự động gây ra sự cố. Chẳng hạn, việc khóa không nên cần thiết với các truy cập chỉ đọc. ** 2. ** Về đoạn cuối, bạn không thể truyền xung quanh giao diện dưới dạng đối tượng, vì vậy ngay cả khi bạn gán một đối tượng không null cho một biến với kiểu giao diện (tĩnh) và mã biên dịch thì tất cả các phương thức này có thể được gọi là. Hãy suy nghĩ về kiểu tĩnh (giao diện) như một loại mặt tiền cho một kiểu triển khai khác. – stakx

3

Tôi nhận được lời khuyên và nó đã giúp tôi!

Tìm trong chuỗi chính (Program.cs) dòng [STAThread] và thay đổi thành [MTAThread].

+0

Nó hoạt động như một sự quyến rũ. Bạn có thể giải thích sự thay đổi không? –

0

Tôi đã phát triển một ứng dụng C# sử dụng 7-zip thông qua giao diện COM. Tôi chạy vào điều buồn cười này, nơi tôi đã có thể trích xuất lưu trữ từ một chuỗi công nhân trong một trường hợp, nhưng không phải khác, nhận được ngoại lệ này.

Tôi thấy rằng, miễn là bạn khởi tạo đối tượng COM vi phạm trong chuỗi nơi nó được sử dụng không có ngoại lệ được ném. Giải pháp của tôi là xử lý các đối tượng sử dụng giao diện COM và khởi tạo lại chúng khi truyền chúng giữa các luồng.

Các vấn đề liên quan