2009-11-23 8 views
6

Tengo una clase COM CMyCOMServer que implementa IMyInterface en una aplicación, ambas con GUID correctos. CMyCOMServer::QueryInterface devolverá S_OK (y se lanzará al tipo correcto) si se solicita IUnknown o IMyInterface, de lo contrario, devuelve E_NOINTERFACE.CoCreateInstance que devuelve E_NOINTERFACE aunque se encuentra la interfaz

En otra aplicación en el mismo ordenador, me llaman:

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

Devuelve E_NOINTERFACE. Así que asumí que estaba haciendo algo mal y agregué un punto de interrupción en CMyCOMServer::QueryInterface. He descubierto que cuando se llama CoCreateInstance, QueryInterface se dispara varias veces para diferentes interfaces:

  • En primer lugar, se solicita IUnknown - se solicitan ningún problema
  • Entonces, varias interfaces como IMarshall etc ... estos no son compatibles por lo que se devuelve E_NOINTERFACE
  • Finalmente, se solicita IMyInterface. Verifico QueryInterface devuelve S_OK y establece (IMyInterface *)this como el puntero de interfaz, como se esperaba

Así que mi confusión es la razón por la CoCreateInstance llamada me está dejando un puntero NULL y código de retorno de E_NOINTERFACE, cuando la aplicación de servidor COM está volviendo claramente la interfaz que pido?

EDITAR: mi aplicación cliente llama a CoInitialize (NULL) al inicio, esto no hace ninguna diferencia.

+1

Solo para aclarar: se ejecuta el servidor COM en una aplicación, y el cliente en aonother aplicación? Porque eso significa que se encontrarán en procesos diferentes, y eso a su vez significa que necesita una combinación, posiblemente personalizada. – MSalters

+0

Sí lo hacen. Dos aplicaciones separadas en 1 PC. Sin embargo, nunca tuve que meterme con Marshalling antes, es por eso que estoy confundido. Apenas lo había escuchado antes y he hecho una buena cantidad de desarrollo de COM. –

Respuesta

5

Si su servidor COM se ejecuta en un proceso diferente, o en un apartamento diferente en el mismo proceso, COM necesita saber cómo empacar y transmitir parámetros cuando realiza llamadas a su interfaz. Este proceso se llama "clasificación".

Si se define una interfaz personalizada, es necesario implementar el cálculo de referencias para ello usando uno de los siguientes enfoques.

  • estándar de cálculo de referencias: tienen el compilador MIDL para generar un proxy y talón de la cual usted debe registrarse en el sistema. Esta es probablemente la mejor opción ya que ya ha definido su interfaz.
  • automatización cálculo de referencias: se define una interfaz compatible encargo automatización y utiliza el contador de referencias que ya es parte de el marco COM
  • el cálculo personalizado: implementar los métodos de IMarshal

Cuando está depurando su servidor COM, aunque se ve que está devolviendo su interfaz personalizada en la llamada a QueryInterface, que no lo hace a través del límite proceso porque COM no puede encontrar la manera de calcular la referencia que interf as, de ahí que el cliente vea E_NOINTERFACE.

ACTUALIZACIÓN (basado en su comentario)

Si se trata de una aplicación de servidor COM existente, entonces es probable que ya tiene un proxy/trozo. Debe registrar esto tanto en el cliente como en el servidor. ¿Podría ser que estuvieras probando esto en una nueva máquina (s) y simplemente olvidaste registrar esto? Para registrarse simplemente regsvr32 en proxy/stub dll.

+0

Como dije, la aplicación de servidor no es un código nuevo. Ya se usa en un sistema en vivo, sin cambios en la interfaz ni nada. Cambiar cualquier cosa del lado del servidor no es una opción, necesito hacer que mi nueva aplicación cliente funcione con lo que hay allí porque otros clientes logran hacerlo de alguna manera. –

+0

Creo que esta es la mejor respuesta. resulta que TENEMOS una DLL proxy-stub, simplemente no estaba al tanto. El uso de regsvr32 lo solucionó. –

2

¿Podría ser este el problema del modelo de subprocesamiento que Raymond Chen wrote about?

Editar en respuesta al comentario:.

Si su modelo de subprocesos es incompatible con el modelo de subprocesamiento del objeto que está creando, entonces arranca de clasificación en COM y si la materia de clasificación no está allí , el error que aparece es E_NOINTERFACE, porque falta la interfaz de cálculo.

Se trata más bien de enhebrar modelos que de ordenar.

+0

Tal vez, pero nunca he utilizado alguna vez de clasificación y por lo que yo soy consciente después de haber trabajado en este proyecto durante 3 años, con más de 100 COM EXE/DLL de servidor. no se realizan operaciones de clasificación personalizadas o complicadas en ninguna parte. Así que estoy confundido por qué debería ser un problema ahora. –

5

Esto sucede porque el subsistema COM intenta coordinar su interfaz personalizada (IMyInterface) y simplemente no tiene idea de cómo hacerlo. Eso sucede ya sea porque el servidor está fuera de proceso o porque el servidor está en proceso y el hilo de la aplicación de consumidor que llama a CoCreateInstance() ha llamado CoInitialize()/CoInitializeEx() incorrectamente para que se solicite "apartamento multiproceso" como se menciona en el artículo user Thomas se refiere en la otra respuesta.

Si solo necesita un servidor en proceso, puede suprimir la clasificación asegurándose de que el hilo que llama a CoCreateInstance() llama a CoInitialize() o CoInitializeEx() con COINIT_APARTMENTTHREADED para imponer el "apartamento de subproceso único".

Si necesita un servidor fuera de proc, no puede moverse por las direcciones.En este último caso se podría hacer uno de los siguientes:

  • aplicar IMarshal - menos preferibles
  • add Proxy/talones y registrarlos para su interfaz personalizada
  • (no estoy seguro si va a trabajar tanto para exterior proc, pero es la más sencilla) si su interfaz puede ser movilizado y automatización marshaller simplemente incluir una typlib en los recursos de su servidor COM y registrar biblioteca de tipos que en el registro.
+0

¡No tengo idea de lo que eso significa! Sospecho que si lo hiciera, mi problema podría ser resuelto. –

+1

¿Has leído ese artículo? – sharptooth

+0

Sí, lo tengo ahora. parece relevante, pero no me da ninguna idea de qué cambiar. La aplicación de servidor se ha estado ejecutando durante años y acabo de lanzar una nueva aplicación cliente MFC para interactuar con ella. No vi ninguna mención de cómo 'suprimir el marshalling' en ese artículo. –

0

Los comentarios anteriores sobre E_NOINTERFACE devueltos porque interfaz de cálculo de referencias se faltaba era muy útil, sin embargo , para nosotros la respuesta/solución era forzar la aplicación principal (el que está llamando CoCreateInstance) para ser STA (solo apartamento roscado), y esto se consigue estableciendo la opción del vinculador avanzada, es decir:

"CLR Tema atributo" está ajustado en "STA enhebrar atributo"

o en la línea de comandos enlace do:

"/CLRTHREADATTRIBUTE:STA" 

Esto evita una mezcla de MTA y STA, lo que provoca una llamada entre subprocesos.

Esperanza alguien encuentra este útil.

Cuestiones relacionadas