2010-11-17 9 views
5

Mam pewne problemy z modelu COM, sytuacja przedstawia się następująco:Zastosowanie 32bit COM Server z programem 64-NET

32-Bit COM Exe Server (który został zaprogramowany w języku C++) oferuje klasę z niektórymi funkcjami członkowskimi, które dotyczą sprzętu innego producenta (sprzęt ten wiąże również serwer COM exe z 32-bitowym, ponieważ producent nie obsługuje wersji 64-bitowej).

Chcę używać 32-bitowego COM Exe Server w 64-bitowej aplikacji .NET (C#) ... Najpierw próbowałem dodać odwołanie do serwera Exe w Visual Studio 2010 i utworzyłem Interop -DLL. Ten Interop DLL-dostarczyła mi niezbędne funkcje, jedną z nich jest zadeklarowana jako:

int Initialize(ref string callingApplicationPath); 

oryginalnej deklaracji w C++ wygląda następująco:

LONG Class::Initialize(BSTR* callingApplicationPath) 

... i tak w IDL:

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

jednak, gdy chcę wywołać tę funkcję z C# za pośrednictwem Interop-DLL, to rzuca BadImageFormatException. Wygląda na to, że Interop-DLL jest 32-bitową biblioteką DLL (może istnieje możliwość wygenerowania 64-bitowej biblioteki DLL?).

Moja następna próba była instancji serwera Exe z tym kodem:

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); 

Kod ten, z drugiej strony, rzuca TargetInvocationException (dokładniej: 0x80020005 (DISP_E_TYPEMISMATCH)) w mojej głowie. Niestety nie byłem w stanie dowiedzieć się, jaki typ muszę przekazać do funkcji z C# ... Próbowałem wszystkich funkcji StringToXXX w klasie Marshal, ale nic nie działa:/Chyba brakuje mi czegoś prostego tutaj , ale nie widzę co.

Każda pomoc jest bardzo doceniana!

Pozdrawiam

Christian

+0

Czy próbowałeś uruchomić Monitor procesu i sprawdzić, co się dzieje, gdy instancja jest wykonywana? Może nie znajduje się w niektórych wpisach do rejestru lub jakiś proces ma niewystarczające uprawnienia? Process Monitor migt pomaga w tym. – sharptooth

+0

@sharptooth: Sama instancja działa dobrze i mogę z powodzeniem wywołać metodę Dummy, która nie przyjmuje argumentów i zwraca int. Problem polega tylko na "System.String -> BSTR * konwersji – Christian

+0

Widzę. Jaki jest sens przekazania BSTR * jako parametru "in"? Dlaczego nie tylko BSTR? – sharptooth

Odpowiedz

1

Deklaracja IDL

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

nie ma sensu. Po przejechaniu BSTR w postaci in parametr tylko przekazać go „wartością”:

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

wtedy nie trzeba robić nic specjalnego w kod C# - wystarczy przejść string tam i przetaczanie zostanie wykonana automatycznie.

Oczywiście trzeba będzie również zmienić podpis implementacji metody.

1

Domyślnie ciągi .NET są zgromadzona w modelu COM do LPTSTR w C++. W związku z tym należy jawnie przekazać dowolny inny typ niezarządzanego ciągu (w tym BSTR) do iz ciągu .NET za pomocą atrybutu MarshalAs.
Spróbuj

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

Dzięki za odpowiedź! Ale w jaki sposób powinienem wprowadzić ten kod do mojego programu C#? W ostatnim przykładzie kodu w moim pytaniu nie deklaruję żadnych sygnatur funkcji, ale zamiast tego używam InvokeMember. Pierwsza linijka kodu w moim pytaniu została zaczerpnięta z automatycznie wygenerowanego Interop.DLL. – Christian

+0

Zmieniłbym automatycznie wygenerowany Interop.DLL ręcznie. – weismat

+0

Sprawdziłem wygenerowaną Interop-DLL z .NET Reflector i dowiedziałem się, że używa ona podpisu, który podałeś. Jednak wywołując serwer COM exe za pośrednictwem tej biblioteki DLL, wywołuję to w procesie i to się nie powiedzie, ponieważ moja aplikacja C# jest 64-bitowa, a Interop-DLL + serwer COM exe są 32-bitowe. Dlatego próbowałem wywoływać funkcje poza procesem za pośrednictwem InvokeMember, niestety bez powodzenia:/ – Christian

0

Ze względu na wspólne środowisko uruchomieniowe języka używane w .NET istnieje tylko kilka przypadków, w których należy rozróżniać 32- i 64-bitowe kody zarządzane. Jednak dotyczy to wyłącznie środowiska .net.Jeśli próbujesz uzyskać dostęp do zasobów niezarządzanych, format bitowy ma znaczenie, ponieważ wszystkie adresy (wyeksportowany interfejs) są dość statyczne i nie są skompilowane dla 64-bitów.

Nadal można użyć dość prostej konstrukcji, aby osiągnąć swoje zadanie;
Utwórz 32-bitowe opakowanie .net i podłącz je przez wcf do aplikacji 64-bitowej. Sugerowałbym stworzenie pakietu C++ w trybie mieszanym do twojego serwera com/niezarządzanego i umieszczenie warstwy opartej na wcf napisanej w "czystym" klr (C#, vb.net, itp.) Jako punktu połączenia z główną aplikacją.

+0

Dziękuję za odpowiedź ... ale bardzo chciałbym, aby liczba warstw była jak najniższa. A dzięki pomocy Sharptooth udało mi się przezwyciężyć mój początkowy problem :) – Christian

+0

nevermind. nie wiedziałem, że masz dostęp do niezarządzanej części kodu, ponieważ powiedziałeś coś o sprzęcie innej firmy;) – Jaster

Powiązane problemy