2013-01-09 17 views
5

Próbuję uzyskać w zdarzeniu Zamknij typu .NET WebBrowser, który wydaje się nie działa po wyjęciu z pudełka. (EDIT:. To zdarzenie jest emitowany, gdy połączenie window.close() wydawana jest w skrypcie uruchomionym w przeglądarce)Wyjątek zgłaszany, gdy WndProc jest przeciążony

Jedno rozwiązanie widziałem jest extend the WebBrowser class and override the WndProc method.

Mój kod rozszerzenie jest w następujący sposób:

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 

To kończy się przyczyną wyjątek jest generowany, gdy instancja typu jest dostępny:

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 . . . 

Obecnie to erroring na wezwanie do Navigate("about:blank") (pierwszy dostęp do instancji po jej budowie). Mogę skomentować zastąpienie WndProc i wszystko działa dobrze (oprócz tego, że brakuje zdarzenia zamknięcia).

Ktoś powiedział, że musiałeś put the security attribute on the WndProc override, więc zrobiłem to i to nie naprawiło.

Ktoś inny powiedział, że możesz disable the DEP, ale próbowałem i nie pozwolił mi zwolnić EXE.

Instancja rozszerzenia jest tworzona w opakowaniu przeglądarki (zwanym również WebBrowser), a wystąpienie tego jest tworzone w moim main, które jest uruchamiane w [STAThread] (które również wydaje się być wymagane).

Czy ktoś wie, co może być nie tak?

(Co ja jestem po to sposób, aby dostać powiadomienie o ścisłej zdarzenia, więc jeśli ktoś wie alternatywną drogę do że byłbym szczęśliwy, aby go usłyszeć.)

Odpowiedz

0

Znalazłem stanowisko, w którym ktoś inny miał to samo problem overriding the WndProc method in F#, a rozwiązanie tam pracowało dla mnie; Kod działa następująco:

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 

Wydaje się, że F # traktuje ref nieco inaczej niż C#: Wykonanie pewnych odczyt na Parameters and Arguments in F# - patrz przez referencję sekcji - wydaje się, że ref kopie wywołać jej argument i używa tej kopii jako wartości dla komórki referencyjnej; tak więc przechodziłem przez komórkę referencyjną zawierającą kopię zawartości msg zamiast odniesienia do oryginału. Adres operatora (&) otrzymuje adres wartości, więc to właśnie było potrzebne dla argumentów metodami DefWndProc i WndProc, zamiast owijać je w ref s.

1

Jeśli chcesz być powiadomiony, gdy kontrola WebBrowser jest zamknięta, możesz utworzyć instancję normalnej klasy WebBrowser i dodać procedurę obsługi zdarzeń do zdarzenia HandleDestroyed - jest uruchamiana, gdy formularz/formant zawierający instancję WebBrowser zostanie zamknięty.

Jeśli to nie zadziała, możesz spróbować rzucić właściwość Parent do Form i podłączyć wydarzenie FormClosing; zobacz tutaj przykład obu technik: HandleDestroyed event in userControl

+0

Niestety, formularz macierzysty nie będzie zamykany, gdy wydarzenie zostanie wyemitowane - Szukam przechwycenia wywołania w przeglądarce do metody 'window.close()', po czym usunę przeglądarkę wystąpienie z formularza. Przeszukuję i zobaczę, czy jest coś jeszcze, co może być użyteczne; dzieki za sugestie! – paul

+0

Bez problemu. Możesz również wypróbować sugerowane tutaj podejście oparte na "Czasomierzu": [window.close() zawiesza .NET 2.0 Kontrola WebBrowser w aplikacji Windows Form] (https://blogs.msdn.com/b/jpsanders/archive/2008/ 04/23/window-close-freezes-net-2-0-webbrowser-control-in-windows-form-application.aspx? Przekierowany = true). Jest to wpis uzupełniający do podejścia opartego na "rozszerzeniu", do którego linkujesz w swoim pytaniu. –

+0

Znalazłem problem! (Zobacz moją odpowiedź.) - Widziałem ten post na temat podejścia opartego na czasomierzu, ale nie przyszło mi do głowy, aby go użyć, ponieważ nie używam .NET 2.0 i nie odczuwałem zamrożenia. Jeszcze raz dziękuję za Twój wkład! – paul

Powiązane problemy