【问题标题】:Exception thrown when WndProc is overloadedWndProc 重载时抛出异常
【发布时间】:2012-12-24 00:37:51
【问题描述】:

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

我见过的一个解决方案是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] 中运行(这似乎也是必填)。

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

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

【问题讨论】:

    标签: .net winforms exception f# wndproc


    【解决方案1】:

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

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

    【讨论】:

    • 遗憾的是,发出此事件时父表单不会关闭——我希望在浏览器中捕获对 window.close() 方法的调用,之后我将删除表单中的浏览器实例。我会搜索一下,看看这条路上是否还有其他可能有用的东西;谢谢你的建议!
    • 没问题。您也可以尝试此处建议的基于Timer 的方法:window.close() freezes .NET 2.0 WebBrowser Control in Windows Form application。这是您在问题中链接到的基于“扩展”的方法的后续帖子。
    • 我发现了问题所在! (见我的回答。)——我看过那篇关于基于计时器的方法的帖子,但我没有想到要使用它,因为我没有使用 .NET 2.0 并且没有遇到冻结。再次感谢您的意见!
    【解决方案2】:

    我发现了一个帖子,其他人也有相同的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 内容的副本,而不是对原始内容的引用。地址运算符 (&amp;) 获取值的地址,因此这是 DefWndProcWndProc 方法的参数所需要的,而不是将它们包装在 refs 中。

    【讨论】:

      猜你喜欢
      • 2013-05-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-24
      • 1970-01-01
      • 1970-01-01
      • 2019-12-27
      相关资源
      最近更新 更多