2011-12-19 20 views
9

Mam pewne problemy z obsługą błędów JavaScript w WebBrowser na Delphi 2010.Jak sprawić, aby TWebBrowser nadal obsługiwał JavaScript po błędzie?

Używam przeglądarki WebBrowser z włączoną cichą usługą. Wydaje się OK, ale jest jeden problem na stronach z błędnymi skryptami: wygląda na to, że jest częścią skryptu po tym, jak błąd nie zostanie wykonany. Wyniki niektórych skryptów nieco różnią się od IE.

Czy masz pojęcie, w jaki sposób można rozwiązać ten problem?

Odpowiedz

12

Można użyć metody IOleCommandTarget, aw jej metodzie IOleCommandTarget.Exec można przechwycić polecenie OLECMDID_SHOWSCRIPTERROR.

W poniższym przykładzie użyłem klasy pośredniej, więc jeśli umieścisz ten kod w swoim urządzeniu, tylko te przeglądarki internetowe w formularzu lub te utworzone w tej jednostce dynamicznie uzyskają to zachowanie.

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

Ta metoda również blokuje wszystkie wyskakujące okienka javascript. – TipTop

+0

Czy masz przykładową stronę, która zachowuje się w ten sposób? Zobacz artykuł ['this'] (http://support.microsoft.com/kb/261003). Czy na pewno nie ma błędu, zanim pojawi się wyskakujące okienko? IMHO powinno tłumić tylko błędy, ale mogę spojrzeć ... – TLama

+0

@ TipTop, ogólnie rzecz biorąc, kod nie ma nic wspólnego z wyskakującymi wyskakującymi skryptami JavaScript. Jeśli masz problem z kodem, myślę, że domyślną wartością zwracaną nie powinno być S_OK, ale OLECMDERR_E_NOTSUPPORTED. – stanleyxu2005

4

Oto moja rekomendacja wdrożenia.

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;" Przynajmniej jest to cenna wskazówka. Często czytam msdn, zgadzam się z tobą, że te zwracane wartości * powinny * być S_OK. Ale zgodnie z moim doświadczeniem w prawdziwej aplikacji, muszę ustawić je na OLECMDERR_E_NOTSUPPORTED, w przeciwnym razie zachowuje się nieoczekiwanie. – stanleyxu2005

+0

Zapoznaj się z kodem i upewnij się, że wiesz, co mówisz, zanim przejdziesz do * porównania mojego postu z innym, mam coś wartościowego. * Gdzie znalazłeś wartość 'vaOut'? Skąd wiadomo, że wynik aktualnie wykonanej komendy będzie wartością logiczną i będzie oznaczać True do wykonania? Następnie miksujesz wartości wyników, jak już ci mówiłem, 'IOleCommandTarget :: QueryStatus' nie ma wartości wyniku' OLECMDERR_E_NOTSUPPORTED' ... Następnie, dlaczego testujesz obsługę zdarzeń dla wskaźnika do wskaźnika? Po prostu przetestuj 'if Assigned (OnNotifyScriptError) następnie OnNotifyScriptError (...)' – TLama

+0

... zobacz, jak VCL jest napisane, to najlepsze źródło, jakie możesz uzyskać. Linia z 'IsEqualGUID' w ogóle się nie dostaję. Mój osobisty wniosek, jeśli zrobiłeś to poważnie, spróbuj dokładniej przeczytać dokumentację (jeśli masz ją z innej, nieoficjalnej dokumentacji, zostaw ją). Cieszę się, że ktoś przejrzy mój post i powie mi swoją opinię, ale nie w ten sposób. Jeśli potrzebujesz tylko przeglądu własnego kodu, możesz zostawić komentarz i mogę Ci w tym pomóc, np. przez e-mail. – TLama

Powiązane problemy