Esoteric JScript托管问题:当IDispatch :: Invoke返回SCRIPT_E_PROPAGATE时,错误代码在哪里?

时间:2010-06-30 01:54:23

标签: c++ com javascript wsh idispatch

我们的应用程序托管Windows Scripting Host JScript引擎,并公开可以从脚本代码调用的多个域对象。

其中一个域对象是实现IDispatch(实际上是IDispatchEx)的COM组件,它有一个将脚本函数作为回调参数(IDispatch *作为参数)的方法。这个COM组件由脚本调用,做一些事情,然后在返回调用脚本之前通过提供的IDispatch参数调回脚本。

如果回调脚本碰巧抛出异常(例如,调用另一个返回S_OK以外的东西的COM组件),那么对回调脚本上的IDispatch :: Invoke的调用将返回SCRIPT_E_PROPAGATE而不是来自其他COM组件的HRESULT;不是来自其他COM对象的预期HRESULT。如果我将HRESULT(SCRIPT_E_PROPAGATE)返回给第一个COM组件的调用者(例如,返回到调用脚本),那么脚本引擎会正确地从另一个COM对象中抛出一个带有预期HRESULT的错误。

然而, ACTUAL ERROR 无处可寻。它不是从Invoke调用返回的(返回值是SCRIPT_E_PROPAGATE)。它不是通过提供给Invoke的EXCEPINFO返回的(结构保持为空)。 AND,它不能通过GetErrorInfo获得(调用返回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)

真的喜欢抓住这个错误,因为缓存它并在后续调用中返回相同的错误会很有用(获取错误通常会导致昂贵的操作,由作为参数传递的脚本函数定义,但我知道如何缓存错误)。有没有办法使脚本化的COM组件在回调到提供的脚本函数期间抛出异常???

1 个答案:

答案 0 :(得分:2)

哇,这是严重缺乏证据的。

答案是:

在COM组件中进行回调...

  1. 要在要调用的脚本函数上获取 IDispatchEx 指针。
  2. 构造一个实现 IServiceProvider 和&amp;的对象。 ICanHandleException ;例如 CScriptErrorCapturer
    • IServiceProvider :: QueryService 可以返回E_NOINTERFACE
    • 如果脚本回调函数抛出但没有捕获,则在InvokEx'd(见下文)时出现异常,那么 ICanHandleException :: CanHandleException 将获得EXCEPINFO和VARIANT *(在MSDN上查找documentation)。
    • 该变体将包含抛出的对象,该对象可能是错误对象。
    • 尝试从此错误对象上的IDispatch获取“数字”和“消息”属性,其中“数字”表示实际的脚本错误(HRESULT)。
    • 这些值可以/应该用于更新EXCEPINFO scode 和(可选) bstrDescription ,以便将错误传播到调用脚本。如果你没有更新 scode ,那么引擎将抛出一个“异常抛出但未被捕获”(0x800A139E),这是EXCEPINFO在修改之前所包含的内容。
    • 不确定是否应该清除 pfnDeferredFillIn ,但它不会这样做。
    • 在我的代码中,我在CScriptErrorCapturer中捕获了错误。
    • 返回S_OK。在这里返回E_FAIL将中止整个脚本运行,并且不允许将异常抛回到原始调用脚本。
  3. 调用IDispatchEx :: InvokeEx并将您的CScriptErrorCapturer作为IServiceProvider参数传递。
  4. 从InvokeEx返回后,查询您的CScriptErrorCapturer以查看它是否发生错误。根据{{​​3}},有时InvokeEx可能会返回S_OK,即使引发了错误。
  5. 不要触摸InvokeEx的返回值,特别是如果它是SCRIPT_E_PROPAGATE(0x80020102)
  6. 注意:code in the GoogleWebKit包含一些上述未记录的JScript HRESULTS。