Esotérica JScript problema de alojamiento: ¿dónde está el código de error cuando IDispatch :: Invoke vuelve SCRIPT_E_PROPAGATE?

StackOverflow https://stackoverflow.com/questions/3145992

Pregunta

Nuestros anfitriones de aplicación del motor y expone JScript de Windows Scripting Host varios objetos de dominio que se puede llamar desde el código de secuencia de comandos.

Uno de los objetos de dominio es un componente COM que implementa IDispatch (en realidad, IDispatchEx) y que tiene un método que toma una función de script como un parámetro de devolución de llamada (IDispatch * como parámetro). Este componente COM es llamado por la escritura, hace algunas cosas, y luego llama de nuevo en la escritura a través de ese parámetro IDispatch suministrado antes de volver a llamar a la secuencia de comandos.

Si el script de devolución de llamada pasa a lanzar una excepción (por ejemplo, hace una llamada a otro componente COM que devuelve algo distinto de S OK), entonces la llamada a IDispatch :: Invoke en el guión de devolución de llamada volverá SCRIPT_E_PROPAGATE vez del HRESULT desde el otro componente COM; No se esperaba el HRESULT del otro objeto COM. Si regreso que HRESULT (SCRIPT_E_PROPAGATE) al llamador del primer componente COM (por ejemplo, para llamar a la secuencia de comandos), entonces el motor de scripts lanza correctamente un error con el HRESULT esperado desde el otro objeto COM.

Sin embargo, el error real está por ningún lado. No es devuelto desde la llamada Invoke (el valor de retorno es SCRIPT_E_PROPAGATE). No es devuelto a través de la EXCEPINFO suministra a Invoke (la estructura permanece vacío). Y, que no está disponible a través de GetErrorInfo (se devuelve la llamada 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)

Me había realmente como para poner mis manos en dicho error, ya que sería útil para almacenar en caché y volver el mismo error en llamadas posteriores (obtener al error a menudo implica una operación costosa que se define por la secuencia de comandos de función pasada como parámetro, pero sí sé cómo almacenar en caché el error). ¿Hay una manera para que un componente COM con guión llegar a una excepción lanzada durante una devolución de llamada en un guión funciones suministrado ???

¿Fue útil?

Solución

Wow, esto fue seriamente poco documentadas.

La respuesta es:

En el componente COM hacer una devolución de llamada en el guión ...

  1. QI para conseguir un IDispatchEx puntero de la función de script para ser llamado.
  2. Construir un objeto que implementa tanto IServiceProvider y ICanHandleException ; p.ej. CScriptErrorCapturer .
    • IServiceProvider :: QueryService puede volver E_NOINTERFACE
    • Si la función de devolución de llamada escritura lanza, pero no la atrapa, una excepción cuando InvokEx'd (ver más abajo), a continuación, ICanHandleException :: CanHandleException recibirá EXCEPINFO y la variante * (mirada en MSDN para documentación ).
    • La variante contendrá el objeto lanzado, lo que podría ser un Error objeto.
    • Trate de obtener el "número" y propiedades "mensaje" del IDispatch en este Error objeto, donde "número" representa el error de script (HRESULT).
    • Estos valores se puede / debe utilizarse para actualizar el EXCEPINFO scode y (opcionalmente) bstrDescription con el fin de propagar el error hasta la secuencia de comandos que llama. Si no actualiza el scode , a continuación, a continuación, el motor generará un "excepción lanzada, pero no se detecta" (0x800A139E), que es lo que el EXCEPINFO contiene antes de modificarlo.
    • No estoy seguro si pfnDeferredFillIn debe ser limpiado, pero funciona sin hacer esto.
    • En mi código, capturo el error aquí en mi CScriptErrorCapturer.
    • Vuelta S OK. Volviendo E_FAIL aquí, se cancelará toda la carrera de la escritura, y no permitir que la excepción a ser echada hacia atrás hasta el guión original de la llamada.
  3. Llamada IDispatchEx :: InvokeEx y pasan su CScriptErrorCapturer como parámetro IServiceProvider.
  4. Al regresar de InvokeEx, consulta su CScriptErrorCapturer para ver si se capturó un error. De acuerdo con código en el GoogleWebKit , a veces InvokeEx puede devolver S_OK, incluso si se produce un error.
  5. No toque el valor de retorno de InvokeEx, sobre todo si es SCRIPT_E_PROPAGATE (0x80020102)

Nota: este enlace contiene algunos de los indocumentado JScript HRESULTS descrito anteriormente.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top