2011-12-19 3 views
9

Delphi 2010의 WebBrowser에서 JavaScript 오류 처리에 문제가 있습니다.오류 발생 후 TWebBrowser가 JavaScript를 계속 실행하도록하려면 어떻게합니까?

사용 가능한 자동 속성이있는 WebBrowser를 사용하고 있습니다. OK이지만 스크립트가 버그가있는 사이트에는 하나의 문제가 있습니다. 오류가 실행되지 않으면 스크립트의 일부처럼 보입니다. 일부 스크립트의 결과는 IE와 약간 다릅니다.

이 문제를 어떻게 해결할 수 있는지 알고 계십니까?

답변

12

IOleCommandTarget을 사용하고 IOleCommandTarget.Exec 메서드는 OLECMDID_SHOWSCRIPTERROR 명령을 사용할 수 있습니다.

다음 예제에서는 삽입 된 클래스를 사용 했으므로이 코드를 사용자의 유닛에 넣으면 폼의 웹 브라우저 또는이 유닛에서 동적으로 생성 된 웹 브라우저에서만이 동작이 발생합니다.

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

이 방법은 또한 모든 자바 스크립트 팝업을 억제합니다. – TipTop

+0

이런 식으로 동작하는 샘플 페이지가 있습니까? ['this'] (http://support.microsoft.com/kb/261003) 문서를 참조하십시오. 팝업이 표시되기 전에 오류가 발생하지 않았습니까? IMHO는 오류 만 표시하지 말아야합니다.하지만 ... – TLama

+0

@TipTop, 일반적으로 코드는 자바 스크립트 호출 팝업과는 아무런 관련이 없습니다. 코드에 문제가있는 경우 기본 반환 값은 S_OK가 아니어야하지만 OLECMDERR_E_NOTSUPPORTED라고 생각합니다. – stanleyxu2005

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

+0

코드를 검토하고 내 게시물을 다른 게시물과 비교하도록 명시하기 전에 내가하는 말을 알고 있는지 확인하십시오. 귀중한 것이 있습니다. * 어디에서 'vaOut' 값이 부울인지 발견 했습니까? 현재 실행 된 명령의 결과가 부울 (Boolean)이 될 것이며 True를 실행한다는 것을 어떻게 알 수 있습니까? 다음으로, 결과 값을 혼합하고 있습니다. 전에 말했던 것입니다. IOleCommandTarget :: QueryStatus에는 결과 값 OLECMDERR_E_NOTSUPPORTED가 없습니다. 다음으로 포인터에 대한 포인터에 대한 이벤트 핸들러를 테스트하는 이유는 무엇입니까? 'If ​​Assigned (OnNotifyScriptError) then OnNotifyScriptError (...) '만 테스트하십시오. – TLama

+0

... VCL이 어떻게 쓰여지는지보십시오, 당신이 얻을 수있는 최고의 소스입니다. 'IsEqualGUID'라는 줄은 전혀 얻지 못합니다. 내 개인적인 결론은, 만약 당신이 진지하게 가져 가면 더 조심스럽게 문서를 읽으려고 시도한다. (다른 비공식 문서에서 얻은 다음 그대로 둔다.) 누군가 내 게시물을 검토하고 나에게 자신의 의견을 말하면 좋겠지 만이 방법은 아닙니다. 자신의 코드를 검토하기 만하면 코멘트를 남겨두고 도움을 줄 수 있습니다. 이메일을 통해. – TLama

관련 문제