2011-12-19 71 views
9

我在使用Delphi 2010的WebBrowser中的javascript錯誤處理方面遇到了一些麻煩。如何讓TWebBrowser在發生錯誤後繼續運行JavaScript?

我使用WebBrowser並啓用了無聲屬性。似乎沒問題,但在有錯誤腳本的網站上有一個問題:在錯誤未執行後,它好像是腳本的一部分。某些腳本的結果與IE略有不同。

你有什麼想法如何解決這個問題?

回答

12

您可以使用IOleCommandTarget並在其IOleCommandTarget.Exec方法中捕獲OLECMDID_SHOWSCRIPTERROR命令。

在以下示例中,我使用了插入類,因此如果將此代碼放入單元中,則只有表單上的那些Web瀏覽器或動態創建的那些Web瀏覽器纔會出現此行爲。

uses 
    SHDocVw, ActiveX; 

type 
    TWebBrowser = class(SHDocVw.TWebBrowser, IOleCommandTarget) 
    private 
    function QueryStatus(CmdGroup: PGUID; cCmds: Cardinal; prgCmds: POleCmd; 
     CmdText: POleCmdText): HRESULT; stdcall; 
    function Exec(CmdGroup: PGUID; nCmdID, nCmdexecopt: DWORD; 
     const vaIn: OleVariant; var vaOut: OleVariant): HRESULT; stdcall; 
    end; 

implementation 

function TWebBrowser.QueryStatus(CmdGroup: PGUID; cCmds: Cardinal; 
    prgCmds: POleCmd; CmdText: POleCmdText): HRESULT; stdcall; 
begin 
    Result := S_OK; 
end; 

function TWebBrowser.Exec(CmdGroup: PGUID; nCmdID, nCmdexecopt: DWORD; 
    const vaIn: OleVariant; var vaOut: OleVariant): HRESULT; stdcall; 
begin 
    // presume that all commands can be executed; for list of available commands 
    // see SHDocVw.pas unit, using this event you can suppress or create custom 
    // events for more than just script error dialogs, there are commands like 
    // undo, redo, refresh, open, save, print etc. etc. 
    // be careful, because not all command results are meaningful, like the one 
    // with script error message boxes, I would expect that if you return S_OK, 
    // the error dialog will be displayed, but it's vice-versa 
    Result := S_OK; 

    // there's a script error in the currently executed script, so 
    if nCmdID = OLECMDID_SHOWSCRIPTERROR then 
    begin 
    // if you return S_FALSE, the script error dialog is shown 
    Result := S_FALSE; 
    // if you return S_OK, the script error dialog is suppressed 
    Result := S_OK; 
    end; 
end; 
+0

該方法還抑制所有JavaScript彈出窗口。 – TipTop 2012-04-24 11:47:49

+0

你有任何樣本頁面的行爲是這樣嗎?請參閱['this'](http://support.microsoft.com/kb/261003)文章。在彈出窗口顯示之前,你確定沒有錯誤嗎?恕我直言,它應該只壓制錯誤,但我可以看看... – TLama 2012-04-24 11:52:43

+0

@TipTop,一般來說,代碼與JavaScript調用彈出窗口無關。如果您確實遇到了代碼問題,我認爲默認返回值不應該是S_OK,而應該是OLECMDERR_E_NOTSUPPORTED。 – stanleyxu2005 2012-05-21 14:45:09

4

這是我的實施建議。

uses 
    SHDocVw, ActiveX; 

type 
    TWebBrowser = class(SHDocVw.TWebBrowser, IOleCommandTarget) 
    private 
    function QueryStatus(CmdGroup: PGUID; cCmds: Cardinal; prgCmds: POleCmd; 
     CmdText: POleCmdText): HRESULT; stdcall; 
    function Exec(CmdGroup: PGUID; nCmdID, nCmdexecopt: DWORD; 
     const vaIn: OleVariant; var vaOut: OleVariant): HRESULT; stdcall; 
    end; 

implementation 

function TWebBrowser.QueryStatus(CmdGroup: PGUID; cCmds: Cardinal; 
    prgCmds: POleCmd; CmdText: POleCmdText): HRESULT; stdcall; 
begin 
    // MSDN notes that a command target must implement this function; E_NOTIMPL is not a 
    // valid return value. Be careful to return S_OK, because we notice that context menu 
    // of Web page "Add to Favorites..." becomes disabled. Another MSDN document shows an 
    // example with default return value OLECMDERR_E_NOTSUPPORTED. 
    // http://msdn.microsoft.com/en-us/library/bb165923(v=vs.80).aspx 
    Result := OLECMDERR_E_NOTSUPPORTED; 
end; 

function TWebBrowser.Exec(CmdGroup: PGUID; nCmdID, nCmdexecopt: DWORD; 
    const vaIn: OleVariant; var vaOut: OleVariant): HRESULT; stdcall; 
var 
    ShowDialog, InterpretScript: Boolean; 
begin 
    if CmdGroup = nil then 
    begin 
    Result := OLECMDERR_E_UNKNOWNGROUP; 
    Exit; 
    end; 

    // MSDN notes that a command target must implement this function; E_NOTIMPL is not a 
    // valid return value. Be careful to return S_OK, because we notice some unhandled 
    // commands behave unexpected with S_OK. We assumed that a return value 
    // OLECMDERR_E_NOTSUPPORTED means to use the default behavior. 
    Result := OLECMDERR_E_NOTSUPPORTED; 

    if IsEqualGUID(CmdGroup^, CGID_DocHostCommandHandler) then 
    begin 
    // there's a script error in the currently executed script, so 
    if nCmdID = OLECMDID_SHOWSCRIPTERROR then 
    begin 
     ShowDialog := True; 
     InterpretScript := False; 

     // Implements an event if you want, so that your application is able to choose the way of handling script errors at runtime. 
     if Assigned(OnNotifyScriptError) then 
     OnNotifyScriptError(Self, ShowDialog, InterpretScript); 

     if ShowDialog then 
     Result := S_FALSE 
     else 
     Result := S_OK; 
     vaOut := InterpretScript; // Without setting the variable to true, further script execution will be cancelled. 
    end; 
    end; 
end; 
+0

「vaOut:= InterpretScript;」至少這是一個有價值的提示。我多次閱讀msdn,我同意你的看法,這些返回值*應該*爲S_OK。但根據我在實際應用中的經驗,我必須將它們設置爲OLECMDERR_E_NOTSUPPORTED,否則它的行爲會出乎意料。 – stanleyxu2005 2012-05-21 15:49:34

+0

請檢查你的代碼,並確保你知道你說什麼之前,你展現*比較我的文章與另一個,我有一些有價值的。*你在哪裏發現'vaOut'值是布爾值?你怎麼知道當前執行的命令的結果是布爾值,並且意味着要執行?接下來,你混合了結果值,我以前告訴過你,IOleCommandTarget :: QueryStatus沒有OLECMDERR_E_NOTSUPPORTED結果值...接下來,你爲什麼要測試指向指針的事件處理程序?只要測試'如果分配(OnNotifyScriptError)然後OnNotifyScriptError(...)' – TLama 2012-05-21 19:11:52

+0

...看看如何編寫VCL,這是你可以得到的最好的來源。帶有'IsEqualGUID'的行我根本沒有得到。我個人的結論是,如果你認真對待這個問題,那麼應該仔細閱讀文檔(如果你從另一個非官方的文檔中得到它,那麼就離開它)。我很高興如果有人審查我的帖子,並告訴我自己的意見,但不是這樣。如果您只需要查看自己的代碼,那麼您可以給我留言,我可以幫助您解決問題,例如通過電子郵件。 – TLama 2012-05-21 19:29:19

相關問題