2009-08-05 5 views
18

je le code suivant:Impossible de jeter l'objet COM de type exception

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

Ce qui fonctionne très bien. Cependant, si je change le code à fileter:

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

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

Quand j'utilise le fil que je reçois l'exception:

Impossible de jeter l'objet COM de type 'System .__ ComObject' à l'interface de type 'IMyInterface' . Cette opération a échoué car l'appel QueryInterface sur le composant COM pour l'interface avec IID '{GUID}' a échoué en raison de l'erreur suivante: Aucune interface prise en charge

Mais l'interface doit-elle être prise en charge correctement? Quelqu'un a des idées sur ce qui se passe ici?

+0

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

Répondre

20

Cette exception désagréable et désagréable est due à un concept connu sous le nom de COM marshalling. L'essence du problème réside dans le fait que, pour consommer des objets COM à partir de n'importe quel thread, le thread doit avoir accès aux informations de type qui décrivent l'objet COM.

Dans votre scénario décrit, la raison pour laquelle il échoue sur le deuxième thread est parce que le deuxième thread n'a pas d'informations de type pour l'interface.

Vous pouvez essayer d'ajouter ce qui suit à votre code:

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

Fondamentalement, la Déclaration, au-dessus du cadre .NET COM chargé pour charger des informations de type en utilisant des techniques traditionnelles du Registre et recherchez la bibliothèque de type associé et aller De là.

Vous devez également limiter la création de l'objet COM à un seul thread (pour empêcher le tri des threads) afin de résoudre ce problème.

En résumé, cette erreur tourne autour des informations de type et de la gestion de threads. Assurez-vous que chaque thread qui souhaite accéder à l'objet COM dispose des informations pertinentes pour démélanger l'objet du thread source. PS: Ce problème est résolu dans .NET 4.0 en utilisant une technique appelée "Type Equivalence"

+0

Merci pour la réponse. Votre explination est logique et la recherche de la déconnexion ComImport sur le MSDN semble également logique. À votre santé. – Kyle

+0

C'est mon plaisir :) J'ai déjà rencontré ce problème et c'était un cauchemar d'essayer de résoudre, jusqu'à ce que l'ampoule s'éteigne et j'ai fini par consommer l'objet COM du thread qui l'a créé. –

+1

[+1] Merci beaucoup les gars! Pour moi, l'erreur était que [STAThread] manquait. Cette question et réponse m'a conduit à le trouver après avoir lu le problème de threading. – Marc

-1

Eh bien, pour commencer, vous faites un appel à un objet sans le verrouiller, cela causera automatiquement des problèmes. Votre code devrait ressembler davantage:

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

D'après ce que je comprends, l'erreur que vous avez énumérés peut parfois se produire lorsque la ressource ne peut pas être accessible, qui, avec une opération cross-fil comme celui-ci, serait le plus susceptible de se produire. Ne me citez pas dessus, je ne suis pas un expert COM.

Honnêtement, je ne pense pas que j'appellerais appeler cette méthode de cette façon, trop de risques à le faire. Avez-vous envisagé d'utiliser un ParameterizedThreadStart et de passer l'objet de cette façon? Vous auriez toujours besoin de verrouiller en toute sécurité vos objets pour les opérations de cross-thread, mais ce serait plus sûr.

En outre, vérifiez que votre classe "myInterface" peut toujours appeler la méthode "CallMethod()". Les interfaces n'ont pas d'implémentation, vous pouvez rencontrer des problèmes lorsque vous définissez "myInterface = iInterface".

+0

Aussi, j'ai vérifié, myInterface peut encore "CallMethod" une fois qu'il a été défini (myInterface = iInterface). – Kyle

+0

Il y a deux fausses informations dans cette réponse: ** 1. ** L'accès aux objets inter-threads ne cause pas * toujours * automatiquement des problèmes. Le verrouillage ne devrait pas être nécessaire avec des accès en lecture seule, par exemple. ** 2. ** Concernant le dernier paragraphe, vous ne pouvez pas faire circuler des interfaces en tant qu'objets, donc même si vous affectez un objet non nul à une variable avec un type d'interface (statique) et que le code compile, toutes ces méthodes peuvent être appelé. Pensez au type statique (interface) comme une sorte de façade pour un autre type d'implémentation. – stakx

3

J'ai reçu un conseil et cela m'a aidé!

Recherchez dans le thread principal (Program.cs) la ligne [STAThread] et remplacez-la par [MTAThread].

+0

Cela a fonctionné comme un charme. Pourriez-vous s'il vous plaît expliquer le changement? –

0

J'ai développé une application C# qui utilise 7-zip via les interfaces COM. J'ai couru dans cette drôle de situation où j'ai pu extraire des archives d'un thread de travail dans une instance, mais pas une autre, obtenant cette même exception.

J'ai trouvé que, tant que vous initialisez l'objet COM offensant dans le thread où il est utilisé, aucune exception n'est levée. Ma solution était de disposer les objets qui utilisaient les interfaces COM et de les réinitialiser en les passant entre les threads. Que vous pour la réponse, mais en utilisant ParameterizedThreadStart ne fonctionne pas non plus (Avec ou sans le verrou)

Questions connexes