2013-01-09 102 views
5

我試圖得到.NET WebBrowser類型的Close事件,它似乎並不能用於開箱即用。 (編輯:window.close()調用在瀏覽器中運行的腳本發出發出此事件)WndProc超載時拋出的異常

一個解決方案,我看到的是給extend the WebBrowser class and override the WndProc method

我的擴展代碼如下:

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 

這最終導致被拋出一個異常時,該類型的實例訪問:

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

目前它的示數到通話Navigate("about:blank")(實例第一次訪問後)。我可以註釋掉WndProc覆蓋和事情工作正常(除了錯過關閉事件)。

有人說你必須要put the security attribute on the WndProc override,所以我這樣做,它並沒有解決問題。

別人說你可以disable the DEP,但我試過了,它並沒有讓我免除EXE。

在瀏覽器(也稱爲WebBrowser)的包裝中創建擴展的一個實例,並在我的main中創建了一個實例,該實例在[STAThread]中運行(似乎也是必需的)。

有誰知道會出現什麼問題?

(什麼我真的是後的方式來獲得接近事件的通知,因此,如果有人知道到備用路由我很高興聽到這個消息。)

回答

0

我發現一個職位,其他人有相同的problem overriding the WndProc method in F#,並在那裏的解決方案爲我工作;工作的代碼如下:

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 

看來,F#對待ref一點不同於C#:在對Parameters and Arguments in F#一些閱讀 - 看到引用傳遞部分 - 它似乎ref調用將其參數並將該副本用作參考單元格的值;所以,我通過的是一個參考單元格,其中包含msg內容的副本,而不是對原始內容的引用。地址 - 運算符(&)獲取值的地址,所以這就是DefWndProcWndProc方法的參數所需的內容,而不是將它們包裝在ref中。

1

如果你想成爲在WebBrowser控件關閉時通知您,您可能可以創建正常WebBrowser類的實例,並向HandleDestroyed事件添加事件處理程序 - 當包含WebBrowser實例的表單/控件關閉時,它會被觸發。

如果這不起作用,您可以嘗試將Parent屬性投射到Form並掛鉤FormClosing事件;看到這裏的兩個技術的例子:HandleDestroyed event in userControl

+0

不幸的是,當這個事件發出時父窗體不會關閉 - 我正在瀏覽器中捕獲一個調用window.close()方法,之後我將刪除瀏覽器從窗體中的實例。我會搜索並查看這條街上是否還有其他可能有用的東西;感謝您的建議! – paul

+0

沒問題。你也可以嘗試這裏建議的基於Timer的方法:[window.close()凍結Windows窗體應用程序中的.NET 2.0 WebBrowser控件](https://blogs.msdn.com/b/jpsanders/archive/2008/ 4月23日/窗口密凍結淨2-0-web瀏覽器 - 控制 - 在 - 窗口形狀application.aspx?重定向=真)。這是您在問題中鏈接到的「擴展」方法的後續文章。 –

+0

我發現問題是什麼! (請參閱我的答案。) - 我已經看過那篇關於基於計時器的方法的文章,但由於我沒有使用.NET 2.0並沒有遇到凍結,所以我沒有想過使用它。再次感謝您的輸入! – paul