2009-10-12 5 views
0

J'ai un client COM VB6 qui effectue des appels vers un serveur ATL/COM STA inprocess. L'une des méthodes serveur, X, peut prendre un certain temps pour terminer, je dois donc pouvoir l'annuler. Ce que j'ai essayé était d'exécuter le code de la méthode dans un nouveau thread et d'inclure une autre méthode, Y, qui fait WaitForSinleObject. Ainsi, le client appelle d'abord X puis va dans une boucle appelant VB6 DoEvents et ensuite Y jusqu'à ce que Y indique que X a fini. Cela fonctionne bien, cependant, la mouche dans l'onguent est que le thread X déclenche également des événements au client via l'interface IConnectionPoint. Les événements passent bien, mais les appels GUI ne fonctionnent pas car, autant que je peux glaner, l'interface graphique ne peut fonctionner que sur un thread, c'est-à-dire le thread principal.L'interface graphique VB6 ne fonctionne pas dans un environnement COM multithread

Existe-t-il un moyen évident d'utiliser mon code existant? Alternativement, s'il vous plaît pouvez-vous suggérer d'autres façons que je pourrais accomplir cela.

Merci d'avance.

Répondre

1

Vous devez toujours marshaler vos appels de point de connexion. Lorsque vous ne faites pas cela, vous pouvez appeler le code VB, mais il échoue de façon aléatoire (objets non-marshaled), ou ne fonctionne tout simplement pas (GUI).

Pour utiliser le marshaling, vous devez implémenter plusieurs interfaces (voir ci-dessous).

L'autre possibilité consiste à convertir les appels asynchrones en VB en appels «fetch» ​​synchrones.

donc votre code passe de (en code C Pseudo ...):

while(!wait(X)) 
{ 
    doevents(); 
} 

à:

while(!wait(X)) 
{ 
    doevents(); 
    fetch_async_data(); 
} 

1) Ajouter un placier à votre classe en l'ajoutant à la table COM_AGGRGATE:

CComPtr<IUnknown> m_pUnkMarshaler; 

BEGIN_COM_MAP(..) 
    ... 
    COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal, m_pUnkMarshaler.p) 
END_COM_MAP() 

2) Créer le mar Shaller à FinalConstruct()

FinalConstruct() 
{ 
    HRESULT rval = CoCreateFreeThreadedMarshaler(GetControllingUnknown(), &m_pUnkMarshaler.p); 
    ... 
} 

FinalRelease() 
{ ...; m_pUnkMarshaler = 0; } 

3) Déduire votre point de connexion de IConnectionPointImplMT et verrouiller les appels internes lorsque vous pouvez tirer plus d'un à la fois.

4) N'attendez pas indéfiniment dans les méthodes de votre objet, car vous pouvez courir dans des blocages.

5) Répétez l'opération pour chaque objet exposé et chaque point de connexion.

(Cela devrait fonctionner, mais je n'ai pas essayé depuis longtemps ...)

+0

Merci beaucoup, je l'ai trié. J'ai cherché IConnectionPointImplMT et trouvé ce lien support.microsoft.com/kb/280512/EN-US/. Le code fourni a bien fonctionné après avoir changé 2 lignes (devrait être: m_vec.GetUnknown à la ligne 148 et m_vec.GetCookie à la ligne 196). Je ne comprends pas pourquoi j'ai besoin d'ajouter un marshaller - aucune mention de cela dans le lien? – Humbleton

+0

Le marshaller est nécessaire lorsque vous souhaitez communiquer avec votre objet dans le thread vb6. Si ce n'est pas nécessaire, ... – Christopher

Questions connexes