在 VB.NET 中初始化 ExtendedWebBrowser,从 C# 到 VB.Net 的解析问题

Initialize ExtendedWebBrowser in VB.NET, problem parsing from C# to VB.Net

根据之前的回答 open link in new tab WebBrowser control

感谢 Mauricio Rojas 用 C# 发布了一个很好的例子:
Extended WebBrowser Control for C#.

我正在尝试将为 C# 提供的代码转换为 VB.NET,但我遇到了问题:
我不明白为什么,当我尝试在 WebBrowserExtendedEvents Class 中实现 DWebBrowserEvents2 接口时,Visual Studio 给我一个错误:

Class WebBrowserExtendedEvents must implements Sub NewWindow2(ByRef pDisp As Object, ByRef cancel As Boolean) for the Interface DWebBrowserEvents2

在我看来,我已经在 Class 和界面中正确地实现了该方法。

Note: I though about removing parts of code not related to the question, as jmcilhinney suggested, but since I didn't find, in the Web, clear examples of ExtendedWebBrowser for VB.Net, I decided to leave the full code, for the benefit of others.

此处完整代码翻译为VB.Net

'First define a new EventArgs class to contain the newly exposed data
Public Class NewWindow2EventArgs
    Inherits CancelEventArgs

    Private _ppDisp As Object
    Public Property PPDisp As Object
        Get
            Return _ppDisp
        End Get
        Set(value As Object)
            _ppDisp = value
        End Set
    End Property

    Public Sub New(ByRef ppDisp As Object, ByRef cancel As Boolean)
        MyBase.New()
        Me.ppDisp = Me.ppDisp
        Me.Cancel = cancel
    End Sub
End Class

Public Class DocumentCompleteEventArgs
    Inherits EventArgs

    Private _ppDisp As Object
    Public Property PPDisp As Object
        Get
            Return _ppDisp
        End Get
        Set(value As Object)
            _ppDisp = value
        End Set
    End Property

    Private _url As Object
    Public Property Url As Object
        Get
            Return _url
        End Get
        Set(value As Object)
            _url = value
        End Set
    End Property

    Public Sub New(ByVal ppDisp As Object, ByVal url As Object)
        MyBase.New()
        Me.ppDisp = Me.ppDisp
        Me.url = Me.url
    End Sub
End Class

Public Class CommandStateChangeEventArgs
    Inherits EventArgs

    Private _command As Long
    Public Property Command As Long
        Get
            Return _command
        End Get
        Set(value As Long)
            _command = value
        End Set
    End Property

    Private _enable As Boolean
    Public Property Enable As Boolean
        Get
            Return _enable
        End Get
        Set(value As Boolean)
            _enable = value
        End Set
    End Property

    Public Sub New(ByVal command As Long, ByRef enable As Boolean)
        MyBase.New()
        Me.command = Me.command
        Me.enable = Me.enable
    End Sub

End Class

'Extend the WebBrowser control
Public Class ExtendedWebBrowser
    Inherits WebBrowser

    Private cookie As AxHost.ConnectionPointCookie

    Private Shadows events As WebBrowserExtendedEvents

    'This method will be called to give you a chance to create your own event sink
    Protected Overrides Sub CreateSink()
        'MAKE SURE TO CALL THE BASE or the normal events won't fire
        MyBase.CreateSink()
        Me.events = New WebBrowserExtendedEvents(Me)
        Me.cookie = New AxHost.ConnectionPointCookie(Me.ActiveXInstance, Me.events, GetType(DWebBrowserEvents2))
    End Sub

    Public ReadOnly Property Application As Object
        Get
            Dim axWebBrowser As IWebBrowser2 = CType(Me.ActiveXInstance, IWebBrowser2)
            If (Not (axWebBrowser) Is Nothing) Then
                Return axWebBrowser.Application
            Else
                Return Nothing
            End If

        End Get
    End Property

    Protected Overrides Sub DetachSink()
        If (Not (Me.cookie) Is Nothing) Then
            Me.cookie.Disconnect()
            Me.cookie = Nothing
        End If

        MyBase.DetachSink()
    End Sub

    'This new event will fire for the NewWindow2
    Public Event NewWindow2 As EventHandler(Of NewWindow2EventArgs)

    Protected Sub OnNewWindow2(ByRef ppDisp As Object, ByRef cancel As Boolean)
        'Dim h As EventHandler(Of NewWindow2EventArgs) = NewWindow2

        Dim args As NewWindow2EventArgs = New NewWindow2EventArgs(ppDisp, cancel)
        If Not IsNothing(NewWindow2Event) Then
            RaiseEvent NewWindow2(Me, args)
        End If

        'Pass the cancellation chosen back out to the events
        'Pass the ppDisp chosen back out to the events
        cancel = args.Cancel
        ppDisp = args.PPDisp
    End Sub

    'This new event will fire for the DocumentComplete
    Public Event DocumentComplete As EventHandler(Of DocumentCompleteEventArgs)

    Protected Sub OnDocumentComplete(ByVal ppDisp As Object, ByVal url As Object)
        'Dim h As EventHandler(Of DocumentCompleteEventArgs) = DocumentComplete
        Dim args As DocumentCompleteEventArgs = New DocumentCompleteEventArgs(ppDisp, url)
        If Not IsNothing(DocumentCompleteEvent) Then
            RaiseEvent DocumentComplete(Me, args)
        End If

        'Pass the ppDisp chosen back out to the events
        ppDisp = args.PPDisp
        'I think url is readonly
    End Sub

    'This new event will fire for the CommandStateChange
    Public Event CommandStateChange As EventHandler(Of CommandStateChangeEventArgs)

    Protected Sub OnCommandStateChange(ByVal command As Long, ByRef enable As Boolean)
        'Dim h As EventHandler(Of CommandStateChangeEventArgs) = CommandStateChange
        Dim args As CommandStateChangeEventArgs = New CommandStateChangeEventArgs(command, enable)
        If Not IsNothing(CommandStateChangeEvent) Then
            RaiseEvent CommandStateChange(Me, args)
        End If

    End Sub

    'This class will capture events from the WebBrowser
    Public Class WebBrowserExtendedEvents
        Inherits System.Runtime.InteropServices.StandardOleMarshalObject

        '******************* HERE THE ERROR ********************
        Implements DWebBrowserEvents2
        '*******************************************************

        Private _Browser As ExtendedWebBrowser

        Public Sub New(ByVal browser As ExtendedWebBrowser)
            MyBase.New()
            Me._Browser = browser
        End Sub

        'Implement whichever events you wish
        Public Sub NewWindow2(ByRef pDisp As Object, ByRef cancel As Boolean)
            Me._Browser.OnNewWindow2(pDisp, cancel)
        End Sub

        'Implement whichever events you wish
        Public Sub DocumentComplete(ByVal pDisp As Object, ByRef url As Object)
            Me._Browser.OnDocumentComplete(pDisp, url)
        End Sub

        'Implement whichever events you wish
        Public Sub CommandStateChange(ByVal command As Long, ByVal enable As Boolean)
            Me._Browser.OnCommandStateChange(command, enable)
        End Sub

    End Class

    <ComImport(), _
     Guid("34A715A0-6587-11D0-924A-0020AFC7AC4D"), _
     InterfaceType(ComInterfaceType.InterfaceIsIDispatch), _
     TypeLibType(TypeLibTypeFlags.FHidden)> _
    Public Interface DWebBrowserEvents2

        <DispId(105)> _
        Sub CommandStateChange(ByVal command As Long, ByVal enable As Boolean)

        <DispId(259)> _
        Sub DocumentComplete(ByVal pDisp As Object, ByRef URL As Object)

        <DispId(251)> _
        Sub NewWindow2(ByRef pDisp As Object, ByRef cancel As Boolean)

    End Interface

    <ComImport(), _
     Guid("D30C1661-CDAF-11d0-8A3E-00C04FC9E26E"), _
     TypeLibType((TypeLibTypeFlags.FOleAutomation _
                Or (TypeLibTypeFlags.FDual Or TypeLibTypeFlags.FHidden)))> _
    Public Interface IWebBrowser2

        <DispId(100)> _
        Sub GoBack()

        <DispId(101)> _
        Sub GoForward()

        <DispId(102)> _
        Sub GoHome()

        <DispId(103)> _
        Sub GoSearch()

        <DispId(104)> _
        Sub Navigate(ByVal Url As String, ByRef flags As Object, ByRef targetFrameName As Object, ByRef postData As Object, ByRef headers As Object)

        <DispId(-550)> _
        Sub Refresh()

        <DispId(105)> _
        Sub Refresh2(ByRef level As Object)

        <DispId(106)> _
        Sub [Stop]()

        <DispId(200)> _
        ReadOnly Property Application As Object

        <DispId(201)> _
        ReadOnly Property Parent As Object

        <DispId(202)> _
        ReadOnly Property Container As Object

        <DispId(203)> _
        ReadOnly Property Document As Object

        <DispId(204)> _
        ReadOnly Property TopLevelContainer As Boolean

        <DispId(205)> _
        ReadOnly Property Type As String

        <DispId(206)> _
        Property Left As Integer

        <DispId(207)> _
        Property Top As Integer

        <DispId(208)> _
        Property Width As Integer

        <DispId(209)> _
        Property Height As Integer

        <DispId(210)> _
        ReadOnly Property LocationName As String

        <DispId(211)> _
        ReadOnly Property LocationURL As String

        <DispId(212)> _
        ReadOnly Property Busy As Boolean

        <DispId(300)> _
        Sub Quit()

        <DispId(301)> _
        Sub ClientToWindow(ByRef pcx As Integer, ByRef pcy As Integer)

        <DispId(302)> _
        Sub PutProperty(ByVal _property As String, ByVal vtValue As Object)

        <DispId(303)> _
        Function GetProperty(ByVal _property As String) As Object

        <DispId(0)> _
        ReadOnly Property Name As String

        <DispId(-515)> _
        ReadOnly Property HWND As Integer

        <DispId(400)> _
        ReadOnly Property FullName As String

        <DispId(401)> _
        ReadOnly Property Path As String

        <DispId(402)> _
        Property Visible As Boolean

        <DispId(403)> _
        Property StatusBar As Boolean

        <DispId(404)> _
        Property StatusText As String

        <DispId(405)> _
        Property ToolBar As Integer

        <DispId(406)> _
        Property MenuBar As Boolean

        <DispId(407)> _
        Property FullScreen As Boolean

        <DispId(500)> _
        Sub Navigate2(ByRef URL As Object, ByRef flags As Object, ByRef targetFrameName As Object, ByRef postData As Object, ByRef headers As Object)

        <DispId(503)> _
        Sub ShowBrowserBar(ByRef pvaClsid As Object, ByRef pvarShow As Object, ByRef pvarSize As Object)

        <DispId(-525)> _
        ReadOnly Property ReadyState As WebBrowserReadyState

        <DispId(550)> _
        Property Offline As Boolean

        <DispId(551)> _
        Property Silent As Boolean

        <DispId(552)> _
        Property RegisterAsBrowser As Boolean

        <DispId(553)> _
        Property RegisterAsDropTarget As Boolean

        <DispId(554)> _
        Property TheaterMode As Boolean

        <DispId(555)> _
        Property AddressBar As Boolean

        <DispId(556)> _
        Property Resizable As Boolean
    End Interface
End Class

VB.Net要求在实现相应接口成员的成员上加一个Implements keyword

您的 WebBrowserExtendedEvents class 定义了实现,但其成员缺少 Implements 关键字,仅此而已。例如:

Public Sub NewWindow2(ByRef pDisp As Object, ByRef cancel As Boolean)
    Me._Browser.OnNewWindow2(pDisp, cancel)
End Sub

需要修改的地方(不能写成两行,所以留在这里一行):

Public Sub NewWindow2(ByRef pDisp As Object, ByRef cancel As Boolean) Implements DWebBrowserEvents2.NewWindow2
    Me._Browser.OnNewWindow2(pDisp, cancel)
End Sub

我还建议保留您在 C# 示例代码中找到的 MarshalAs 属性。
例如,在 DWebBrowserEvents2 接口定义中,更改:

<ComImport(), Guid("34A715A0-6587-11D0-924A-0020AFC7AC4D"), [...]
Public Interface DWebBrowserEvents2
    '[...]
    <DispId(251)> _
    Sub NewWindow2(ByRef pDisp As Object, ByRef cancel As Boolean)
End Interface

在:

<ComImport(), Guid("34A715A0-6587-11D0-924A-0020AFC7AC4D"), [...]
Public Interface DWebBrowserEvents2
    '[...]
    <DispId(251)>
    Sub NewWindow2(<MarshalAs(UnmanagedType.IDispatch)> ByRef pDisp As Object, ByRef cancel As Boolean)
End Interface

▶ 请注意,当您收到 通知时,class 必须实施...,您可以 select 带下划线的成员和按 ALT+ENTER 让 Visual Studio 为您实现界面。