2010-04-06 8 views
2

Je fais un travail COM Interop avec Excel et autres logiciels Office Automation.COM Interop - Attendez Excel pour terminer l'opération

Un collègue m'a dit que je dois attendre ces serveurs d'automatisation pour être prêt après une commande pour eux.

Cependant, je ne vois pas le but de ce que ne pas bloquer tous les appels jusqu'à ce que le serveur d'automatisation complète la tâche donnée?

Par exemple, je normalement écrire:

 
Dim o as AutomationObject = AutomationServer.CreateObject(x, y, z) 
o.Property ' could throw COM exception!!???? 

Mon collègue dit que je dois dormir après cet appel parce que le serveur d'automatisation pourrait encore travailler sur la création et l'initialisation de l'objet.

 
Dim o as AutomationObject = AutomationServer.CreateObject(x, y, z) 
Threading.Sleep(5000) ' wait for AutomationServer to "become ready" 
o.Property ' could still throw COM exception!!???? 

Le problème que j'ai avec cela est que les appels AutomationServer devraient bloquer jusqu'à ce que le AutomationServer se termine ou se termine ce qu'il travaillait ou à tout le moins, il devrait être une boucle de vérifier si « o » est rien, mais cela n'a aucun sens car une fois que l'appel revient à sa fin!

Ma question est, est-il un avantage à dormir après un appel AutomationServer? Existe-t-il une méthode pour "attendre" jusqu'à la fin de l'AutomationServer (s'il ne bloque pas)?

Répondre

1

Une façon simple de résoudre ce problème est ci-dessous. Je devais l'interface avec Visual Studio récemment, et j'ai trouvé cela a bien fonctionné, si vous êtes prêt à échouer rapidement sur l'objet COM devient infiniment occupé. Voir si cela fonctionne pour vous:

delegate void COMWrapper(); 

    private void MakeRiskyCOMCall(COMWrapper doThis) 
    { 
     bool sendAgain = true; 
     int count = 0; 

     while (sendAgain) 
     { 
      try 
      { 
       doThis(); 
       sendAgain = false; 
      } 
      catch (COMException ex) 
      { 
       System.Threading.Thread.Sleep(50); 
       sendAgain = count > 100 ? false : true; 
       if (!sendAgain) 
       { 
        throw; 
       } 
      } 
      finally { count++; } 
     } 
    } 

Une fois que vous avez ce délégué et méthode portée, alors voici des exemples d'un appel de méthode et un accès à la propriété en utilisant la délégation anonyme.

// property access 
    vsDisplay display; 
    MakeRiskyCOMCall(delegate() { display = dte.DisplayMode; }); 
    if (display == null) 
     throw new Exception("VS Display not set");   

    //simple method call 
    MakeRiskyCOMCall(delegate() { dte.Solution.Close(true); }); 

Je délibérément caché l'COMException, car je ne voulais pas, mais si vous avez besoin juste définir une variable COMException dans la méthode MakeRiskyCOMCall qui est portée définie dans la méthode d'appel. Vous pouvez également vérifier le paramètre HResult spécifique qui indique l'attente d'un processus occupé et échouer plus rapidement pour les autres résultats HR. Cette solution est rapide et évite toutes les COM Interop salissant et inconvénient de c'est que ce n'est pas assez, mais il fonctionne et est plus facile à comprendre pour les mainteneurs de votre code (je pense).

1

Vous pouvez en effet une exception si l'accès à un serveur Automation out-proc qui est occupé. Dans le cas d'Office, cela peut se produire si vous avez une macro qui s'exécute lorsque vous ouvrez un document. Vous rencontrerez également des problèmes si vous vous connectez à une instance d'une application Office dans laquelle une boîte de dialogue est ouverte.

This article décrit comment vous pouvez éviter cela en mettant en place des gestionnaires d'erreurs IOleMessageFilter. L'article porte sur l'automatisation de Visual Studio, mais les principes et les techniques sont les mêmes pour l'automatisation d'autres serveurs d'automatisation hors proc comme Office.

Questions connexes