Используйте 32-битный COM-сервер из 64-битной программы .NET - PullRequest
5 голосов
/ 17 ноября 2010

У меня проблемы с COM Interop, ситуация следующая:

32-битный сервер COM Exe (который был запрограммирован на C ++) предлагает класс с некоторыми функциями-членами, которые работают с оборудованием сторонних производителей (это оборудование также связывает сервер COM Exe с 32-битным, так как производитель не поддержка 64-бит).

Я хочу использовать 32-разрядный сервер COM Exe в 64-разрядном приложении .NET (C #) ... Сначала я попытался добавить ссылку на сервер Exe в Visual Studio 2010, и он создал Interop- DLL. Эта Interop-DLL предоставила мне необходимые функции, одна из которых была объявлена ​​как:

int Initialize(ref string callingApplicationPath);

Исходное объявление в C ++ выглядит так:

LONG Class::Initialize(BSTR* callingApplicationPath)

... и вот так в IDL:

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

Однако, когда я хочу вызвать эту функцию из C # через Interop-DLL, она выдает исключение BadImageFormatException. Похоже, что Interop-DLL является 32-битной DLL (может быть, есть возможность генерировать 64-битную DLL?).

Моя следующая попытка состояла в том, чтобы создать экземпляр Exe-сервера с помощью этого кода:

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

Этот код, с другой стороны, вызывает исключение TargetInvocationException (более конкретно: 0x80020005 (DISP_E_TYPEMISMATCH)) в моей голове. К сожалению, я не смог выяснить, какой тип мне нужно передать в функцию из C # ... Я перепробовал все функции StringToXXX в классе Marshal, но, похоже, ничего не работает: , но я не вижу, что.

Любая помощь очень ценится!

С наилучшими пожеланиями

Christian

Ответы [ 3 ]

1 голос
/ 18 ноября 2010

Объявление IDL

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

не имеет смысла.Когда вы передаете BSTR в качестве параметра in, просто передайте его «по значению»:

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

, тогда вам не нужно будет делать ничего особенного в коде C # - просто передайте туда string исортировка будет выполняться автоматически.

Конечно, вам также придется изменить сигнатуру реализации метода.

1 голос
/ 17 ноября 2010

По умолчанию .NET-строки сортируются COM-взаимодействием в LPTSTR в C ++.Таким образом, вы должны явно маршалировать любой другой тип неуправляемой строки (включая BSTR) в строку .NET и из нее, используя атрибут MarshalAs.

0 голосов
/ 18 ноября 2010

Из-за общеязыковой среды выполнения, используемой в .net, есть только несколько случаев, когда нужно различать 32- и 64-битную версию с помощью управляемого кода.Однако это верно только для .net envoirement.Если вы пытаетесь получить доступ к неуправляемым ресурсам, битовый формат имеет значение, поскольку все адреса (экспортируемый интерфейс) довольно статичны и не скомпилированы для 64-битных.

Тем не менее, вы можете использовать довольно простую конструкцию для достижения вашей задачи;1003 * Создайте 32-разрядную оболочку .net и подключите ее через wcf к вашему 64-разрядному приложению.Я бы предложил создать оболочку c ++ в смешанном режиме для вашего com / неуправляемого сервера и поместить слой на основе wcf, написанный на «чистом» clr (c #, vb.net и т. Д.), В качестве точки соединения с вашим основным приложением.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...