2010-06-30 21 views
2

Notre application héberge le moteur JScript de Windows Scripting Host et expose plusieurs objets de domaine pouvant être appelés à partir du code de script.Esotérique JScript problème d'hébergement: où est le code d'erreur lorsque IDispatch :: Invoke retourne SCRIPT_E_PROPAGATE?

Un des objets de domaine est un composant COM qui implémente IDispatch (en fait, IDispatchEx) et qui a une méthode qui prend une fonction de script en tant que paramètre callback (un IDispatch * en tant que paramètre). Ce composant COM est appelé par script, fait certaines choses, puis rappelle en script via le paramètre IDispatch fourni avant de retourner au script appelant.

Si le script de rappel arrive à déclencher une exception (par exemple, appelle un autre composant COM qui renvoie autre chose que S_OK), l'appel à IDispatch :: Invoke sur le script de rappel retournera SCRIPT_E_PROPAGATE au lieu du HRESULT de l'autre composant COM; pas le HRESULT attendu de l'autre objet COM. Si je renvoie cette HRESULT (SCRIPT_E_PROPAGATE) à l'appelant du premier composant COM (par exemple, au script appelant), puis le moteur de script renvoie correctement une erreur avec le HRESULT attendu de l'autre objet COM.

Toutefois, l'erreur ACTUAL ERROR est introuvable. Il n'est pas renvoyé à partir de l'appel Invoke (la valeur de retour est SCRIPT_E_PROPAGATE). Il n'est pas renvoyé via EXCEPINFO fourni à Invoke (la structure reste vide). AND, il n'est pas disponible via GetErrorInfo (l'appel renvoie S_FALSE)!

Script 
    Defines ScriptCallback = function() { return ComComponentB.doSomething(); } 
    Invokes ComComponentA.execute(ScriptCallback) 
     Invokes ScriptCallback() 
      Invokes ComComponentB.doSomething() 
       Returns E_FAIL (or some other HRESULT) 
      Throws returned HRESULT 
     Receives SCRIPT_E_PROPAGATE <--- WHERE IS THE ACTUAL ERROR? 
     Returns SCRIPT_E_PROPAGATE 
    Throws E_FAIL (or whatever HRESULT was returned from ComComponentB) 

Je serais vraiment aiment mettre la main sur cette erreur, car il serait utile de mettre en cache et retourner la même erreur sur les appels suivants (se rendre à l'erreur implique souvent une opération coûteuse qui est défini par la fonction de script passée en paramètre, mais je sais comment mettre en cache l'erreur). Existe-t-il un moyen pour un composant COM scripté d'obtenir une exception levée lors d'un rappel dans une fonction de script fournie?

Répondre

2

Wow, c'était sérieusement sous-documenté.

La réponse est:

Dans le composant COM faisant un rappel dans le script ...

  1. QI pour obtenir un pointeur IDispatchEx sur la fonction de script à appeler.
  2. Construire un objet à la fois la mise en œuvre IServiceProvider & ICanHandleException; par exemple. CScriptErrorCapturer.
    • IServiceProvider :: QueryService peut retourner E_NOINTERFACE
    • Si la fonction de rappel de script lance, mais ne une exception lorsque InvokEx'd (voir ci-dessous) pas attraper, puis ICanHandleException :: CanHandleException recevra une EXCEPINFO et VARIANT * (recherchez MSDN pour documentation).
    • La variante contiendra l'objet renvoyé, qui peut être un objet Error.
    • Essayez d'obtenir les propriétés "number" et "message" de l'IDispatch sur cet objet Error, où "number" représente l'erreur de script réelle (HRESULT).
    • Ces valeurs peuvent/doivent être utilisées pour mettre à jour EXCEPINFO scode et (optionnellement) bstrDescription afin de propager l'erreur jusqu'au script appelant. Si vous ne mettez pas à jour le scode, alors le moteur lancera une "Exception lancée mais non interceptée" (0x800A139E), qui est ce que contient l'EXCEPINFO avant de le modifier.
    • Vous ne savez pas si pfnDeferredFillIn doit être effacé, mais cela fonctionne sans cela.
    • Dans mon code, je capture l'erreur ici dans mon CScriptErrorCapturer.
    • Retour S_OK. Si vous renvoyez E_FAIL, l'exécution du script sera annulée et l'exception ne sera pas renvoyée au script appelant d'origine.
  3. Appelez IDispatchEx :: InvokeEx et transmettez votre CScriptErrorCapturer en tant que paramètre IServiceProvider.
  4. À votre retour d'InvokeEx, interrogez votre CScriptErrorCapturer pour voir s'il a détecté une erreur. Selon code in the GoogleWebKit, parfois InvokeEx peut renvoyer S_OK, même si une erreur est renvoyée.
  5. Ne touchez pas la valeur de retour de InvokeEx, surtout si elle est SCRIPT_E_PROPAGATE (0x80020102)

Note: this link contient une partie des sans papier JScript HRESULTS décrit ci-dessus.