2009-11-23 32 views
6

Tôi có một lớp COM CMyCOMServer triển khai IMyInterface trong một ứng dụng, cả với GUID chính xác. CMyCOMServer::QueryInterface sẽ trả về S_OK (và tự chuyển sang đúng loại) nếu IUnknown hoặc IMyInterface được yêu cầu, ngược lại nó trả về E_NOINTERFACE.CoCreateInstance trả lại E_NOINTERFACE mặc dù giao diện được tìm thấy

Trong một ứng dụng trên cùng một máy PC, tôi gọi:

HRESULT hr = ::CoCreateInstance(__uuidof(CMyCOMServer), 0, CLSCTX_SERVER, 
__uuidof(IMyInterface),(void **)&pInterface); 

Nó trả E_NOINTERFACE. Vì vậy, tôi cho rằng tôi đã làm điều gì sai và thêm điểm ngắt trên CMyCOMServer::QueryInterface. Tôi thấy rằng khi CoCreateInstance được gọi, QueryInterface được kích hoạt nhiều lần cho các giao diện khác nhau:

  • Thứ nhất, IUnknown được yêu cầu - không có vấn đề
  • Sau đó, một số giao diện như IMarshall vv được yêu cầu ... những không được hỗ trợ vì vậy E_NOINTERFACE được trả về
  • Cuối cùng, IMyInterface được yêu cầu. Tôi xác nhận QueryInterface trả S_OK và đặt (IMyInterface *)this như con trỏ giao diện, như mong đợi

Vì vậy, sự nhầm lẫn của tôi là lý do tại sao CoCreateInstance gọi là để lại cho tôi một con trỏ NULL và gửi lại mã của E_NOINTERFACE, khi ứng dụng máy chủ COM đang trở lại rõ giao diện tôi yêu cầu?

EDIT: ứng dụng khách của tôi gọi CoInitialize (NULL) khi khởi động, điều này không có sự khác biệt.

+1

Chỉ cần làm rõ: Máy chủ COM của bạn chạy trong một ứng dụng và ứng dụng khách trong ứng dụng khác? Bởi vì điều đó có nghĩa là họ sẽ ở trong các quá trình khác nhau, và điều đó có nghĩa là bạn _need_ marshalling, có thể tùy chỉnh. – MSalters

+0

Có. Hai ứng dụng riêng biệt trên 1 PC. Tôi không bao giờ phải lúng túng xung quanh với Marshalling trước đó, đó là lý do tại sao tôi bối rối. Tôi hầu như không nghe nói về nó trước đây và tôi đã thực hiện một số tiền hợp lý của sự phát triển COM. –

Trả lời

5

Nếu máy chủ COM của bạn đang chạy trong một quy trình khác hoặc một căn hộ khác trong cùng một quy trình, COM cần biết cách gói và truyền thông số khi bạn thực hiện cuộc gọi đến giao diện của mình. Quá trình này được gọi là "marshaling".

Nếu bạn xác định giao diện tùy chỉnh, bạn cần triển khai marshaling cho giao diện bằng cách sử dụng một trong các cách tiếp cận sau.

  • Chuẩn marshaling: có trình biên dịch tức về để tạo ra một proxy và còn sơ khai mà bạn phải đăng ký trên hệ thống. Đây có lẽ là tùy chọn tốt nhất vì bạn đã xác định giao diện của mình.
  • OLE Automation marshaling: bạn xác định một tự động tương thích giao diện tùy chỉnh và sử dụng marshaller mà đã là một phần của COM khuôn khổ
  • Tuỳ chỉnh marshaling: bạn thực hiện các phương pháp IMarshal

Khi bạn đang gỡ lỗi máy chủ COM của bạn, mặc dù bạn thấy rằng bạn đang quay trở lại giao diện tùy chỉnh của bạn trong cuộc gọi đến QueryInterface, nó không làm cho nó trên ranh giới quá trình vì COM không thể tìm ra cách sắp xếp ace, do đó khách hàng thấy E_NOINTERFACE.

CẬP NHẬT (dựa trên nhận xét của bạn)

Nếu đây là một ứng dụng máy chủ COM hiện tại sau đó có thể bạn đã có một proxy/bài. Bạn cần phải đăng ký trên cả máy khách và máy chủ. Nó có thể được rằng bạn đã thử nghiệm này trên một máy mới (s) và bạn chỉ đơn giản là quên đăng ký này? Để đăng ký bạn chỉ cần làm regsvr32 trên dll proxy/stub.

+0

Như tôi đã nói, ứng dụng máy chủ không phải là mã mới. Nó đã được sử dụng trong một hệ thống trực tiếp - không có thay đổi đối với giao diện hoặc bất cứ thứ gì. Thay đổi bất cứ điều gì ở phía máy chủ không phải là một lựa chọn, tôi cần phải làm cho ứng dụng khách hàng mới của tôi làm việc với những gì ở đó vì các khách hàng khác bằng cách nào đó quản lý để làm như vậy. –

+0

Tôi nghĩ đây là câu trả lời hay nhất. nó chỉ ra chúng tôi DID có một proxy-stub DLL, tôi chỉ không nhận thức được nó. Sử dụng regsvr32 đã sửa nó. –

2

Đây có phải là vấn đề về mô hình luồng mà Raymond Chen wrote about không?

Sửa trả lời bình luận:.

Nếu mô hình luồng của bạn không phù hợp với mô hình luồng của đối tượng bạn đang tạo, sau đó COM đá marshalling trong Và nếu những thứ marshalling là không có , lỗi xuất hiện là E_NOINTERFACE, vì giao diện marshalling bị thiếu.

Đó là nhiều hơn về các mô hình luồng hơn về đầm lầy, thực sự.

+0

Có lẽ, nhưng tôi chưa bao giờ sử dụng Marshalling và như xa như tôi biết sau khi làm việc trên dự án này trong 3 năm, với hơn 100 COM EXE/DLL máy chủ COM. không có marshalling tùy chỉnh hoặc công cụ luồng ưa thích được thực hiện bất cứ nơi nào. Vì vậy, tôi bối rối tại sao nó phải là một vấn đề bây giờ. –

5

Điều này xảy ra vì hệ thống con COM cố gắng sắp xếp giao diện tùy chỉnh của bạn (IMyInterface) và đơn giản là không biết cách thực hiện điều đó. Điều đó xảy ra vì máy chủ là out-proc hoặc vì máy chủ nằm trong proc và luồng của ứng dụng người dùng gọi CoCreateInstance() đã gọi CoInitialize()/CoInitializeEx() không chính xác để "căn hộ đa luồng" được yêu cầu như đã đề cập trong bài viết user Thomas đề cập đến trong câu trả lời khác.

Nếu bạn chỉ cần một máy chủ trong proc bạn có thể ngăn chặn marshalling bằng cách đảm bảo rằng các chủ đề gọi CoCreateInstance() hoặc gọi CoInitialize() hoặc CoInitializeEx() với COINIT_APARTMENTTHREADED để thực thi "đơn luồng căn hộ".

Nếu bạn cần một máy chủ out-proc, bạn không thể xoay xở được.Trong trường hợp sau bạn có thể làm một trong các cách sau:

  • thực hiện IMarshal - thích hợp hơn
  • add proxy/khai nhất và đăng ký cho giao diện tùy chỉnh của bạn
  • (không chắc chắn nếu nó sẽ làm việc cho dùng ngoài trời proc, nhưng đó là đơn giản nhất) nếu giao diện của bạn có thể được marshalled với marshaller tự động chỉ đơn giản là bao gồm một typlib vào các nguồn lực của máy chủ COM của bạn và đăng ký rằng typelib trong registry.
+0

Tôi không biết điều đó có nghĩa là gì! Tôi nghi ngờ nếu tôi đã làm, vấn đề của tôi có thể được giải quyết. –

+1

Bạn đã đọc bài viết đó chưa? – sharptooth

+0

Có tôi hiện có. nó có vẻ liên quan nhưng không cho tôi bất kỳ ý tưởng gì để thay đổi. Các ứng dụng máy chủ đã được chạy trong nhiều năm và tôi chỉ ném cùng một ứng dụng khách hàng MFC mới để tương tác với nó. Tôi không thấy bất kỳ đề cập đến làm thế nào để 'trấn áp marshalling' trong bài viết đó. –

0

Các bình luận trước đó về E_NOINTERFACE trả lại vì marshalling giao diện là mất tích was very helpful, Tuy nhiên, cho chúng ta câu trả lời/sửa chữa là để buộc các ứng dụng chính (người gọi CoCreateInstance) là STA (căn hộ đơn luồng), và điều này đã được thực hiện bằng cách thiết lập một tùy chọn mối liên kết tiên tiến, ví dụ:

"CLR chủ đề thuộc tính" được thiết lập để "STA luồng thuộc tính"

hoặc trên dòng lệnh liên kết mà bạn do:

"/CLRTHREADATTRIBUTE:STA" 

Điều này ngăn cản sự kết hợp giữa MTA và STA, gây ra cuộc gọi qua chủ đề.

Hy vọng người khác thấy điều này hữu ích.

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