2013-01-09 8 views
5

Sto cercando di ottenere l'evento Close del tipo .NET WebBrowser, che non sembra funzionare correttamente. (EDIT:. Questo evento viene emesso quando la chiamata window.close() è rilasciato in uno script in esecuzione nel browser)Eccezione generata quando WndProc è sovraccarico

Una soluzione che ho visto è quello di extend the WebBrowser class and override the WndProc method.

mio codice di estensione è la seguente:

type internal ExtendedBrowser() = class 
    inherit System.Windows.Forms.WebBrowser() 

    let WM_PARENTNOTIFY : int = 0x0210 
    let WM_DESTROY  : int = 0x0002 

    let closed : Event<unit> = new Event<unit>() 

    do() 

    [<System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")>] 
    override this.WndProc (msg : Message byref) = 
     match msg.Msg with 
     | wm when wm = WM_PARENTNOTIFY -> 
      if (not base.DesignMode) && (msg.WParam.ToInt32() = WM_DESTROY) 
      then closed.Trigger() 
      base.DefWndProc(ref msg) 
     | _ -> 
      base.WndProc(ref msg) 

    member this.Closed = closed.Publish 
end 

questo finisce per causare una generazione di un'eccezione quando un'istanza del tipo si accede:

Unhandled Exception: System.Reflection.TargetInvocationException: Unable to get the window handle for the 'ExtendedBrowser' control. Windowless ActiveX controls are not supported. ---> System.ComponentModel.Win32Exception: Error creating window handle. 
    at System.Windows.Forms.NativeWindow.CreateHandle(CreateParams cp) 
    at System.Windows.Forms.Control.CreateHandle() 
    at System.Windows.Forms.Control.get_Handle() 
    at System.Windows.Forms.WebBrowserBase.DoVerb(Int32 verb) 
    at System.Windows.Forms.WebBrowserBase.TransitionFromRunningToInPlaceActive() 

    --- End of inner exception stack trace --- 
    at System.Windows.Forms.WebBrowserBase.TransitionFromRunningToInPlaceActive() 

    at System.Windows.Forms.WebBrowserBase.TransitionUpTo(AXState state) 
    at System.Windows.Forms.WebBrowser.get_AxIWebBrowser2() 
    at System.Windows.Forms.WebBrowser.PerformNavigate2(Object& URL, Object& flag 
s, Object& targetFrameName, Object& postData, Object& headers) 
    at System.Windows.Forms.WebBrowser.Navigate(String urlString) 
    at [PRODUCT].Application.WebBrowser..ctor() in C:\[PATH]\WebBrowser.fs:line 107 
    at Program.Main.main(String[] args) in C:\[PATH]\Program.fs:line 79 
Press any key to continue . . . 

Attualmente si tratta di erroring su una chiamata a Navigate("about:blank") (il primo accesso dell'istanza dopo la sua costruzione). Posso commentare l'override WndProc e le cose funzionano bene (oltre a mancare l'evento close).

Qualcuno ha detto che si doveva put the security attribute on the WndProc override così l'ho fatto e non ho sistemato le cose.

Qualcuno ha detto che è possibile effettuare il disable the DEP, ma ho provato e non mi ha permesso di escludere l'EXE.

Un'istanza dell'estensione viene creata in un wrapper per il browser (chiamato anche WebBrowser) e un'istanza di questo viene creata nel mio main, che è in esecuzione in uno [STATO] (che sembra anche essere richiesto).

Qualcuno sa cosa potrebbe andare storto?

(Che cosa sono davvero dopo è un modo per ottenere la notifica della chiusura dell'evento, quindi se qualcuno conosce un percorso alternativo a quello sarei felice di sentirlo.)

risposta

0

Ho trovato un post in cui qualcun altro aveva avuto lo stesso problem overriding the WndProc method in F# e la soluzione lì funzionava per me; codice di lavoro è la seguente:

type ExtendedWebBrowser() = class 
    inherit System.Windows.Forms.WebBrowser() 

    let WM_PARENTNOTIFY : int = 0x0210 
    let WM_DESTROY  : int = 0x0002 

    let closed : Event<unit> = new Event<unit>() 

    do() 

    override this.WndProc (msg : Message byref) = 
     match msg.Msg with 
     | wm when wm = WM_PARENTNOTIFY -> 
      if (not base.DesignMode) && (msg.WParam.ToInt32() = WM_DESTROY) 
      then closed.Trigger() 
      base.DefWndProc(&msg) 
     | _ -> 
      base.WndProc(&msg) 

    member this.Closed = closed.Publish 
end 

Sembra che F # tratta ref un po 'diverso rispetto a C#: Facendo qualche lettura sulla Parameters and Arguments in F# - vedono la passaggio per riferimento sezione - sembra che le ref copie chiamata la sua argomento e utilizza quella copia come valore per la cella referenziale; quindi, quello che stavo passando era una cella di riferimento contenente una copia del contenuto di msg piuttosto che un riferimento all'originale. L'operatore address-of (&) ottiene l'indirizzo del valore, quindi è quello che era necessario per gli argomenti dei metodi e WndProc invece di includerli in ref s.

1

Se si vuole essere Quando il controllo WebBrowser viene chiuso, è possibile creare un'istanza della normale classe WebBrowser e aggiungere un gestore di eventi all'evento HandleDestroyed: viene attivato quando il modulo/controllo contenente l'istanza di WebBrowser viene chiusa.

Se ciò non funziona, puoi provare a trasmettere la proprietà Parent a Form e ad agganciare l'evento FormClosing; vedere qui per un esempio di entrambe le tecniche: HandleDestroyed event in userControl

+0

Purtroppo, il modulo padre non si chiuderà quando viene emesso questo evento - Sto cercando di acquisire una chiamata nel browser al metodo 'window.close()', dopo di che rimuoverò il browser istanza dal modulo. Cercherò e vedrò se c'è qualcos'altro in questa strada che potrebbe essere utile; grazie per il suggerimento! – paul

+0

Nessun problema. Si potrebbe anche provare l'approccio basato su 'Timer' suggerito qui: [window.close() congela il controllo WebBrowser di .NET 2.0 nell'applicazione Windows Form] (https://blogs.msdn.com/b/jpsanders/archive/2008/ 23/04/window-chiude-blocca-nET-2-0-browser web-controllo-in-finestre-form-Application.aspx? Redirected = true). È un post di follow-up per l'approccio basato su "estensione" a cui ti sei collegato nella tua domanda. –

+0

Ho trovato qual era il problema! (Vedi la mia risposta.) - Avevo visto quel post sull'approccio basato sul timer ma non mi era venuto in mente di usarlo dato che non sto usando .NET 2.0 e non stavo vivendo il congelamento. Grazie ancora per il tuo contributo! – paul