2009-08-05 32 views
18

tengo el siguiente código:No se puede convertir objeto COM del tipo de excepción

public void Test(IMyInterface iInterface) 
{ 
    iInterface.CallMethod (); 
} 

que funciona muy bien. Sin embargo, si se cambia el código para ser roscado:

private IMyInterface myInterface; 
public void Test(IMyInterface iInterface) 
{ 
    myInterface = iInterface; 
    new Thread (new ThreadStart (CallInterfaceMethod)).Start (); 
} 

public void CallInterfaceMethod () 
{ 
    myInterface.CallMethod () 
} 

Cuando utilizo el hilo que recibe la excepción:

No se puede convertir objeto COM del tipo 'System .__ ComObject' a la interfaz tipo 'IMyInterface' . Esta operación falló porque la llamada a QueryInterface en el componente COM para la interfaz con IID '{GUID}' falló debido al siguiente error: No se admitió dicha interfaz

¿Pero la interfaz debería ser compatible? Alguien tiene alguna idea sobre lo que está pasando aquí?

+0

http://blogs.msdn.com/b/oldnewthing/archive/2004/12/13/281910.aspx – EricLaw

Respuesta

20

Esta desagradable y repugnante excepción se debe a un concepto conocido como COM marisqueo. La esencia del problema radica en el hecho de que para consumir objetos COM de cualquier subproceso, el subproceso debe tener acceso a la información de tipo que describe el objeto COM.

En su escenario descrito, la razón por la que falla en el segundo subproceso es porque el segundo subproceso no tiene información de tipo para la interfaz.

Usted podría intentar agregar lo siguiente a su código:

[ComImport] 
[Guid("23EB4AF8-BE9C-4b49-B3A4-24F4FF657B27")] 
public interface IMyInterface 
{ 
    void CallMethod(); 
} 

Básicamente la declaración anterior indica al COM NET Framework carga para cargar la información de tipo con las técnicas tradicionales del Registro y busque la biblioteca de tipo asociado e ir desde allí.

También debe restringir la creación del objeto COM a un único hilo (para evitar la clasificación de hilos) para ayudar a resolver este problema.

Para resumir, este error gira en torno a la información de tipo y clasificación de subprocesos. Asegúrese de que cada subproceso que desea acceder al objeto COM tenga la información relevante para desasignar el objeto del subproceso de origen.

PD: Este problema está resuelto en .NET 4.0 usando una técnica llamada "Equivalencia de tipo"

+0

Gracias por la respuesta. Su explicación tiene sentido y buscar la declinación de ComImport en MSDN también parece tener sentido. Aclamaciones. – Kyle

+0

Es un placer :) Me he encontrado con este problema antes y fue una pesadilla intentarlo y resolverlo, hasta que se apagó la bombilla y terminé consumiendo el objeto COM del hilo que lo creó. –

+1

[+1] Muchas gracias muchachos! Para mí, el error fue que [STAThread] faltaba. Esta pregunta y respuesta me llevaron a encontrarlo después de leer el problema de enhebrado. – Marc

-1

Bueno, para empezar, está haciendo una llamada entre hilos a un objeto sin bloquearlo, esto automáticamente causará algunos problemas. El código debería ser más como:

private IMyInterface myInterface; 
private static readonly object _myObjectLock = new object(); 

public void Test(IMyInterface iInterface) 
{ 
    myInterface = iInterface; 
    new Thread (new ThreadStart (CallInterfaceMethod)).Start (); 
} 

public void CallInterfaceMethod () 
{ 
    lock(_myObjectLock) 
    { 
     myInterface.CallMethod (); 
    } 
} 

Por lo que entiendo, el error que se menciona a veces puede ocurrir cuando no se puede acceder al recurso, que, con una operación de hilo cruzado de esta manera, lo más probable ocurrir. Aunque no me cites, no soy un experto en COM.

A decir verdad, no creo que me acerque a llamar a este método de esta manera, demasiados riesgos al hacerlo. ¿Ha considerado usar un ParameterizedThreadStart y pasar el objeto por ese camino? Todavía necesitaría bloquear con seguridad sus objetos para las operaciones de cruce de hilos, pero sería más seguro.

Además, verifique que su clase "myInterface" aún pueda llamar al método "CallMethod()". Las interfaces no tienen implementación, es posible que tenga problemas al establecer "myInterface = iInterface".

+0

Gracias por la respuesta, pero el uso de ParameterizedThreadStart tampoco funciona (con o sin el bloqueo). También he comprobado, myInterface todavía puede "CallMethod" una vez que se ha establecido (myInterface = iInterface). – Kyle

+0

Hay dos bits de información errónea en esta respuesta: ** 1. ** El acceso a objetos entre subprocesos no * siempre * automáticamente causa problemas. El bloqueo no debería ser necesario con accesos de solo lectura, por ejemplo. ** 2. ** Con respecto al último párrafo, no puede pasar interfaces como objetos, por lo que incluso si asigna un objeto no nulo a una variable con un tipo de interfaz (estática) y el código se compila, entonces todos estos métodos pueden ser llamado. Piense en el tipo estático (interfaz) como algún tipo de fachada para otro tipo de implementación. – stakx

3

¡Obtuve un consejo y me ayudó!

Busque en el hilo principal (Program.cs) la línea [STAThread] y cámbielo a [MTAThread].

+0

Funcionó como un amuleto. ¿Puede explicar el cambio? –

0

He estado desarrollando una aplicación C# que utiliza 7-zip a través de las interfaces COM. Me encontré con esta cosa graciosa donde pude extraer archivos de un hilo de trabajo en una instancia, pero no en otra, obteniendo la misma excepción.

Descubrí que, siempre que inicialice el objeto COM ofensivo en la secuencia donde se utiliza, no se produce ninguna excepción. Mi solución fue eliminar los objetos que utilizaban las interfaces COM y reiniciarlos al pasarlos entre hilos.

Cuestiones relacionadas