Проблема эзотерического хостинга JScript: где находится код ошибки, когда IDispatch :: Invoke возвращает SCRIPT_E_PROPAGATE? - PullRequest
2 голосов
/ 30 июня 2010

Наше приложение содержит движок JScript Windows Scripting Host и предоставляет несколько объектов домена, которые можно вызывать из кода скрипта.

Один из объектов домена - это COM-компонент, который реализует IDispatch (фактически IDispatchEx) и имеет метод, который принимает функцию сценария в качестве параметра обратного вызова (IDispatch * в качестве параметра). Этот COM-компонент вызывается сценарием, выполняет некоторые действия и затем вызывает обратно в сценарий с помощью предоставленного параметра IDispatch, прежде чем вернуться к вызывающему сценарию.

Если сценарий обратного вызова выдает исключение (например, делает вызов другому компоненту COM, который возвращает что-то отличное от S_OK), то вызов IDispatch :: Invoke в сценарии обратного вызова вместо этого возвращает SCRIPT_E_PROPAGATE HRESULT от другого компонента COM; не ожидаемый HRESULT от другого COM-объекта. Если я возвращаю этот HRESULT (SCRIPT_E_PROPAGATE) обратно вызывающей стороне первого COM-компонента (например, вызывающему сценарию), то обработчик сценариев корректно выдает ошибку с ожидаемым HRESULT из другого COM-объекта.

Однако, АКТУАЛЬНАЯ ОШИБКА нигде не найдена. Он не возвращается из вызова Invoke (возвращаемое значение - SCRIPT_E_PROPAGATE). Он не возвращается через EXCEPINFO, предоставленный Invoke (структура остается пустой). И, это не доступно через 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 Ответ

2 голосов
/ 02 июля 2010

Ничего себе, это было серьезно недокументировано.

Ответ таков:

В компоненте COM выполняется обратный вызов в сценарий ...

  1. QI toполучить указатель IDispatchEx на вызываемую функцию скрипта.
  2. Создание объекта, реализующего оба IServiceProvider & ICanHandleException ;например, CScriptErrorCapturer .
    • IServiceProvider :: QueryService может возвращать E_NOINTERFACE
    • Если функция обратного вызова сценария выдает, но не перехватывает, исключение, когда InvokEx'd (см. Ниже), затем ICanHandleException :: CanHandleException получит EXCEPINFO и VARIANT * (посмотрите в MSDN документацию ).
    • Вариант будет содержать брошенный объект, который может быть Ошибка объект.
    • Попробуйте получить свойства "number" и "message" из IDispatch для этого Error object, где "number" представляет фактическую ошибку сценария (HRESULT).
    • Эти значения могут / должны использоваться для обновления EXCEPINFO scode и (необязательно) bstrDescription для распространения ошибки до вызывающего сценария.Если вы не обновите scode , то движок сгенерирует «Исключение выброшено, но не перехвачено» (0x800A139E), которое содержится в EXCEPINFO перед его изменением.
    • Неконечно, если pfnDeferredFillIn должен быть очищен, но он работает без этого.
    • В моем коде я фиксирую ошибку здесь, в моем CScriptErrorCapturer.
    • Return S_OK.Возвращение E_FAIL здесь прервет весь запуск сценария и не позволит перебросить исключение обратно в исходный вызывающий сценарий.
  3. Вызовите IDispatchEx :: InvokeEx и передайте CScriptErrorCapturer в качестве IServiceProviderпараметр.
  4. По возвращении из InvokeEx, запросите ваш CScriptErrorCapturer, чтобы увидеть, если он обнаружил ошибку.Согласно коду в GoogleWebKit , иногда InvokeEx может возвращать S_OK, даже если выдается ошибка.
  5. Не трогайте возвращаемое значение из InvokeEx, особенно если это SCRIPT_E_PROPAGATE (0x80020102)

Примечание: эта ссылка содержит некоторые недокументированные JScript HRESULTS, описанные выше.

...