2010-11-17 17 views
5

Estoy teniendo algunos problemas con la interoperabilidad COM, la situación es la siguiente:uso de 32 bits de servidor COM desde un programa de 64 bits .NET

COM de 32 bits servidor EXE (que fue programado en C++) ofrece una clase con algunas funciones de miembros que se ocupan de hardware de terceros (este hardware también vincula el servidor EXE de COM a 32 bits, ya que el fabricante no es compatible con 64 bits).

Quiero usar el servidor COM Exe de 32 bits en una aplicación .NET (C#) de 64 bits ... Al principio traté de agregar una referencia al servidor Exe en Visual Studio 2010 y creé una interoperabilidad. -DLL. Esta interoperabilidad DLL-me proporcionó las funciones necesarias, estando uno de ellos declarados como:

int Initialize(ref string callingApplicationPath); 

La primera declaración en C++ es el siguiente:

LONG Class::Initialize(BSTR* callingApplicationPath) 

... y así en IDL:

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

Sin embargo, cuando quiero llamar a esta función desde C# a través de la interoperabilidad-DLL, que arroja un BadImageFormatException. Parece que la DLL de Interoperación es una DLL de 32 bits (¿Tal vez hay una posibilidad de generar una DLL de 64 bits?).

Mi siguiente intento fue crear una instancia del servidor EXE con este código:

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

Este código, por otro lado, lanza un TargetInvocationException (Más específicamente: 0x80020005 (DISP_E_TYPEMISMATCH)) a la cabeza. Desafortunadamente, no pude averiguar qué tipo tengo que pasar a la función desde C# ... Probé todas las funciones de StringToXXX en la clase Marshal, pero nada parece funcionar:/Supongo que me está perdiendo algo simple aquí , pero no veo qué.

¡Cualquier ayuda es muy apreciada!

Saludos

Cristiano

+0

¿Ha intentado iniciar Process Monitor y observar qué ocurre cuando se realiza la creación de instancias? Tal vez no encuentre algunas entradas de registro, o algún proceso tiene derechos insuficientes? Process Monitor migt ayuda con eso. – sharptooth

+0

@sharptooth: la instanciación en sí funciona bien y puedo invocar con éxito un método ficticio que no toma argumentos y devuelve un int. El problema es "solo" el System.String -> BSTR * conversion – Christian

+0

Veo. ¿De qué sirve pasar BSTR * como un parámetro "in"? ¿Por qué no solo BSTR? – sharptooth

Respuesta

1

La declaración IDL

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

no tiene sentido. Cuando se pasa una BSTR como un parámetro in simplemente pasarlo "por valor":

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

entonces usted no tendrá que hacer nada especial en código C# - sólo tiene que pasar string allí y de clasificación se realiza de forma automática.

Por supuesto, también deberá cambiar la firma de implementación del método.

1

Por defecto, las cadenas de .NET son formateados por la interoperabilidad COM a LPTSTR en C++. Por lo tanto, debe ordenar explícitamente cualquier otro tipo de cadena no gestionada (incluido BSTR) hacia y desde una cadena .NET utilizando el atributo MarshalAs.
Trate

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

Gracias por su respuesta! ¿Pero cómo incorporaría este código en mi programa C#? En la última muestra de código en mi pregunta, no declaro ninguna firma de función, sino que uso InvokeMember. La primera línea de código en mi pregunta fue tomada del Interop.DLL generado automáticamente. – Christian

+0

Cambiaría el Interop.DLL generado automáticamente de forma manual. – weismat

+0

Comprobé el Interop-DLL generado con .NET Reflector y descubrí que usa la firma que me proporcionó. Sin embargo, al llamar al COM Exe Server a través de este archivo DLL, lo estoy llamando en proceso y eso falla porque mi aplicación C# es de 64 bits y el Interop-DLL + el servidor COM Exe son ambos de 32 bits. Es por eso que traté de llamar a las funciones fuera de proceso a través de InvokeMember, desafortunadamente sin éxito:/ – Christian

0

Debido al tiempo de ejecución de idioma común utilizado por .net, solo hay unos pocos casos en los que debe distinguir entre 32 y 64 bits mediante código administrado. Sin embargo, esto solo es cierto para el enredo de .net.Si intenta acceder a los recursos no administrados, importa el formato del bit, ya que todas las direcciones (interfaz exportada) son bastante estáticas y no compiladas para 64 bits.

Todavía podría utilizar un constructo bastante simple para lograr su tarea;
Crea un contenedor .net de 32 bits y conéctalo a través de wcf a tu aplicación de 64 bits. Sugiero crear un contenedor C++ de modo mixto para su servidor com/unmanaged y colocar una capa basada en wcf escrita en clr "puro" (C#, vb.net, etc.) como el punto de conexión a su aplicación principal.

+0

Gracias por su respuesta, también ... pero me gustaría mantener el número de capas lo más bajo posible. Y debido a la ayuda de sharptooth, logré superar mi problema inicial :) – Christian

+0

nevermind. tampoco sabía que tenía acceso a la parte del código no administrado, ya que dijo algo acerca del hardware de terceros;) – Jaster

Cuestiones relacionadas