2010-11-17 31 views
5

Tôi đang gặp sự cố với COM Interop, tình hình như sau:Sử dụng Máy chủ COM 32 bit từ Chương trình .NET 64bit

Máy chủ 32 bit COM Exe (được lập trình trong C++) cung cấp một lớp với một số chức năng thành viên đối phó với phần cứng của bên thứ 3 (Phần cứng này cũng liên kết máy chủ COM Exe với 32-Bit, vì nhà sản xuất không hỗ trợ 64-Bit).

Tôi muốn sử dụng máy chủ API 32 bit COM trong ứng dụng .NET 64 bit (C#) ... Lúc đầu, tôi đã cố gắng thêm tham chiếu đến Máy chủ Exe trong Visual Studio 2010 và nó tạo ra một Interop -DLL. Đây Interop-DLL cung cấp cho tôi với các chức năng cần thiết, một trong số họ được khai báo là:

int Initialize(ref string callingApplicationPath); 

Việc kê khai ban đầu trong C++ trông như thế này:

LONG Class::Initialize(BSTR* callingApplicationPath) 

... và như thế này trong IDL:

[id(1)] LONG Initialize([in] BSTR* callingApplicationPath); 

Tuy nhiên, khi tôi muốn gọi hàm này từ C# qua Interop-DLL, nó sẽ phát ra BadImageFormatException. Dường như Interop-DLL là một DLL 32-Bit (Có thể có khả năng tạo ra một 64-Bit-DLL?).

nỗ lực tiếp theo của tôi là để nhanh chóng Server Exe với mã này:

Type type = Type.GetTypeFromProgID("OurCompany.Class"); 
Object o = Activator.CreateInstance(type); 
Object[] args = { Marshal.StringToBSTR(str) }; 
Object result = type.InvokeMember("Initialize", BindingFlags.InvokeMethod, null, o, args); 

Mã này, mặt khác, ném một TargetInvocationException (Cụ thể hơn: 0x80020005 (DISP_E_TYPEMISMATCH)) tại đầu tôi. Thật không may tôi đã không thể tìm ra loại tôi phải vượt qua trong các chức năng từ C# ... Tôi đã thử tất cả các StringToXXX-chức năng trong Marshal-class nhưng không có gì có vẻ làm việc:/Tôi đoán tôi thiếu một cái gì đó đơn giản ở đây nhưng tôi không thấy gì.

Bất kỳ trợ giúp nào được đánh giá cao!

Trân trọng

Christian

+0

Bạn đã cố gắng kích hoạt Trình theo dõi quy trình và xem điều gì đang xảy ra khi quá trình tạo xong chưa? Có lẽ nó không tìm thấy một số mục đăng ký, hoặc một số quá trình có đủ quyền? Quy trình giám sát di chuyển trợ giúp với điều đó. – sharptooth

+0

@sharptooth: Bản thân nó cũng hoạt động tốt và tôi có thể gọi thành công một phương thức giả mà không có đối số và trả về một int. Vấn đề là "chỉ" chuyển đổi System.String -> BSTR * – Christian

+0

Tôi hiểu. Điểm BSTR * là gì khi tham số "trong"? Tại sao không chỉ BSTR? – sharptooth

Trả lời

1

Việc kê khai IDL

[id(1)] LONG Initialize([in] BSTR* str);  

làm cho không có ý nghĩa. Khi bạn vượt qua một BSTR như một in tham số chỉ cần vượt qua nó "bởi giá trị":

[id(1)] LONG Initialize([in] BSTR str); 

sau đó bạn sẽ không cần phải làm bất cứ điều gì đặc biệt trong mã C# - chỉ cần vượt qua string đó và marshalling sẽ được thực hiện tự động.

Tất nhiên bạn cũng sẽ phải thay đổi chữ ký triển khai phương thức.

1

Theo mặc định, dây NET được sắp sếp bởi COM Interop để LPTSTR trong C++. Vì vậy, bạn phải sắp xếp một cách rõ ràng bất kỳ loại chuỗi không quản lý nào khác (kể cả BSTR) đến và từ một chuỗi .NET bằng cách sử dụng thuộc tính MarshalAs.
Hãy thử

int Initialize([MarshalAs(UnmanagedType.BStr)] ref string callingApplicationPath); 
+0

Cảm ơn câu trả lời của bạn! Nhưng làm thế nào tôi sẽ kết hợp mã này vào chương trình C# của tôi? Trong mẫu mã cuối cùng trong câu hỏi của tôi, tôi không khai báo bất kỳ chữ ký chức năng nào, nhưng thay vì sử dụng InvokeMember. Dòng mã đầu tiên trong câu hỏi của tôi được lấy từ Interop.DLL được tạo tự động. – Christian

+0

Tôi sẽ tự động thay đổi Interop.DLL được tạo tự động. – weismat

+0

Tôi đã kiểm tra Interop-DLL được tạo bằng .NET Reflector và phát hiện ra rằng nó sử dụng chữ ký bạn đã cung cấp. Tuy nhiên, bằng cách gọi COM Exe Server thông qua DLL này, tôi gọi nó là trong quá trình và thất bại vì C# App của tôi là 64-Bit và Interop-DLL + COM Exe Server đều là 32-Bit. Đó là lý do tại sao tôi đã cố gắng gọi các chức năng out-of-process thông qua InvokeMember, thật không may mà không thành công:/ – Christian

0

Do thời gian chạy ngôn ngữ chung được sử dụng bởi .net chỉ có một vài trường hợp bạn phải phân biệt giữa 32 và 64 bit bằng mã được quản lý. Tuy nhiên điều này chỉ đúng đối với envoirement .net.Nếu bạn cố gắng truy cập tài nguyên không được quản lý, định dạng bit quan trọng, vì tất cả các địa chỉ (giao diện xuất) khá tĩnh và không được biên dịch cho 64 bit.

Tuy nhiên, bạn có thể sử dụng một cấu trúc khá đơn giản để đạt được nhiệm vụ của mình;
Tạo một gói 32 bit .net và conenct nó qua wcf vào ứng dụng 64 bit của bạn. Tôi muốn đề nghị tạo một chế độ hỗn hợp C++ wrapper cho máy chủ com/unmanaged của bạn và đặt một lớp dựa trên wcf được viết bằng "tinh khiết" clr (C#, vb.net, vv) làm điểm conenction cho ứng dụng chính của bạn.

+0

Cảm ơn câu trả lời của bạn, quá ... nhưng tôi rất muốn giữ số lượng các lớp càng thấp càng tốt. Và nhờ sự giúp đỡ của sharptooth, tôi đã vượt qua được vấn đề ban đầu của mình :) – Christian

+0

nevermind. không biết bạn có quyền truy cập vào phần mã không được quản lý, vì bạn đã nói gì đó về phần cứng của bên thứ 3;) – Jaster

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