5

我正在尝试处理 .NET WebBrowser 类型的 Close 事件,这似乎无法开箱即用。(编辑:window.close()在浏览器中运行的脚本中发出调用时会发出此事件。)

我见过的一种解决方案是扩展WebBrowser和方法overrideWndProc

我的扩展代码如下:

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覆盖并且一切正常(除了错过关闭事件)。

有人说您必须将安全属性放在WndProc覆盖上,所以我这样做了,但它并没有解决问题。

有人说你可以禁用 DEP,但我试过了,它并没有让我免除 EXE。

在浏览器(也称为 WebBrowser)的包装器中创建了一个扩展实例,并在 my 中创建了一个实例,该实例main在 [STAThread] 中运行(这似乎也是必需的)。

有谁知道可能出了什么问题?

(我真正追求的是一种获取关闭事件通知的方法,所以如果有人知道替代路线,我会很高兴听到它。)

4

2 回答 2

1

如果您想在WebBrowser控件关闭时收到通知,您可以创建普通WebBrowser类的实例并向事件添加事件处理程序——它在包含您的实例的表单/控件关闭HandleDestroyed时触发。WebBrowser

如果这不起作用,您可以尝试将Parent属性转换为Form并挂钩FormClosing事件;有关这两种技术的示例,请参见此处:HandleDestroyed event in userControl

于 2013-01-09T22:01:32.800 回答
1

我发现了一个帖子,其他人在覆盖 F# 中的 WndProc 方法时遇到了同样的问题,那里的解决方案对我有用;工作代码如下:

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# 有点不同:Doing some reading on Parameters and Arguments in F# -- 请参阅Passing by Reference部分 -- 似乎ref调用复制了它的参数并将该副本用作引用单元格的值;所以,我传递的是一个包含内容副本的参考单元格,msg而不是对原始内容的引用。address-of 运算符 ( ) 获取值的地址,因此这就是and方法&的参数所需要的,而不是将它们包装在s 中。DefWndProcWndProcref

于 2013-01-11T17:08:56.313 回答