【问题标题】:How to use a dll written for VB.Net in C#如何在 C# 中使用为 VB.Net 编写的 dll
【发布时间】:2011-11-22 10:20:52
【问题描述】:

我有问题要问。

我有一个用于在 USB 上读写数据的 dll 文件。 要在 VB.Net 中使用 dll,需要集成一个 .vb 文件,该文件与 该 dll 文件以使用其功能、属性等。

我需要在 C# 项目中使用这个 dll。这可能吗? 如果是,我该如何实现?

表单类中的代码:

Public Class frmUSB
    ' vendor and product IDs
    Private Const VendorID As Integer = &H1234    'Replace with your device's
    Private Const ProductID As Integer = &H1234      'product and vendor IDs

    ' read and write buffers
    Private Const BufferInSize As Integer = 1 'Size of the data buffer coming IN to the PC
    Private Const BufferOutSize As Integer = 1    'Size of the data buffer going OUT from the PC
    Dim BufferIn(BufferInSize) As Byte          'Received data will be stored here - the first byte in the array is unused
    Dim BufferOut(BufferOutSize) As Byte    'Transmitted data is stored here - the first item in the array must be 0

    ' ****************************************************************
    ' when the form loads, connect to the HID controller - pass
    ' the form window handle so that you can receive notification
    ' events...
    '*****************************************************************
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' do not remove!
        ConnectToHID(Me)
    End Sub

    '*****************************************************************
    ' disconnect from the HID controller...
    '*****************************************************************
    Private Sub Form1_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
        DisconnectFromHID()
    End Sub

    '*****************************************************************
    ' a HID device has been plugged in...
    '*****************************************************************
    Public Sub OnPlugged(ByVal pHandle As Integer)
        If hidGetVendorID(pHandle) = VendorID And hidGetProductID(pHandle) = ProductID Then
            ' ** YOUR CODE HERE **
        End If
    End Sub

    '*****************************************************************
    ' a HID device has been unplugged...
    '*****************************************************************
    Public Sub OnUnplugged(ByVal pHandle As Integer)
        If hidGetVendorID(pHandle) = VendorID And hidGetProductID(pHandle) = ProductID Then
            hidSetReadNotify(hidGetHandle(VendorID, ProductID), False)
            ' ** YOUR CODE HERE **
        End If
    End Sub

    '*****************************************************************
    ' controller changed notification - called
    ' after ALL HID devices are plugged or unplugged
    '*****************************************************************
    Public Sub OnChanged()
        ' get the handle of the device we are interested in, then set
        ' its read notify flag to true - this ensures you get a read
        ' notification message when there is some data to read...
        Dim pHandle As Integer
        pHandle = hidGetHandle(VendorID, ProductID)
        hidSetReadNotify(hidGetHandle(VendorID, ProductID), True)
    End Sub

    '*****************************************************************
    ' on read event...
    '*****************************************************************
    Public Sub OnRead(ByVal pHandle As Integer)
        ' read the data (don't forget, pass the whole array)...
        If hidRead(pHandle, BufferIn(0)) Then

            TextBox1.Text = Str(BufferIn(1))
            ' ** YOUR CODE HERE **
            ' first byte is the report ID, e.g. BufferIn(0)
            ' the other bytes are the data from the microcontroller...
        End If
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        BufferOut(1) = Val(TextBox2.Text)
        hidWriteEx(VendorID, ProductID, BufferOut(0))

    End Sub
End Class

我可以使用什么将我的表单实例发送到 HIDDLLInterface (相当于 Me 关键字)?

接口类代码如下:

进口系统 导入 System.Threading 导入 System.Runtime.InteropServices

Module HIDDLLInterface
    ' this is the interface to the HID controller DLL - you should not
    ' normally need to change anything in this file.
    '
    ' WinProc() calls your main form 'event' procedures - these are currently
    ' set to..
    '
    ' MainForm.OnPlugged(ByVal pHandle as long)
    ' MainForm.OnUnplugged(ByVal pHandle as long)
    ' MainForm.OnChanged()
    ' MainForm.OnRead(ByVal pHandle as long)


    ' HID interface API declarations...
    Declare Function hidConnect Lib "mcHID.dll" Alias "Connect" (ByVal pHostWin As Integer) As Boolean
    Declare Function hidDisconnect Lib "mcHID.dll" Alias "Disconnect" () As Boolean
    Declare Function hidGetItem Lib "mcHID.dll" Alias "GetItem" (ByVal pIndex As Integer) As Integer
    Declare Function hidGetItemCount Lib "mcHID.dll" Alias "GetItemCount" () As Integer
    Declare Function hidRead Lib "mcHID.dll" Alias "Read" (ByVal pHandle As Integer, ByRef pData As Byte) As Boolean
    Declare Function hidWrite Lib "mcHID.dll" Alias "Write" (ByVal pHandle As Integer, ByRef pData As Byte) As Boolean
    Declare Function hidReadEx Lib "mcHID.dll" Alias "ReadEx" (ByVal pVendorID As Integer, ByVal pProductID As Integer, ByRef pData As Byte) As Boolean
    Declare Function hidWriteEx Lib "mcHID.dll" Alias "WriteEx" (ByVal pVendorID As Integer, ByVal pProductID As Integer, ByRef pData As Byte) As Boolean
    Declare Function hidGetHandle Lib "mcHID.dll" Alias "GetHandle" (ByVal pVendoID As Integer, ByVal pProductID As Integer) As Integer
    Declare Function hidGetVendorID Lib "mcHID.dll" Alias "GetVendorID" (ByVal pHandle As Integer) As Integer
    Declare Function hidGetProductID Lib "mcHID.dll" Alias "GetProductID" (ByVal pHandle As Integer) As Integer
    Declare Function hidGetVersion Lib "mcHID.dll" Alias "GetVersion" (ByVal pHandle As Integer) As Integer
    Declare Function hidGetVendorName Lib "mcHID.dll" Alias "GetVendorName" (ByVal pHandle As Integer, ByVal pText As String, ByVal pLen As Integer) As Integer
    Declare Function hidGetProductName Lib "mcHID.dll" Alias "GetProductName" (ByVal pHandle As Integer, ByVal pText As String, ByVal pLen As Integer) As Integer
    Declare Function hidGetSerialNumber Lib "mcHID.dll" Alias "GetSerialNumber" (ByVal pHandle As Integer, ByVal pText As String, ByVal pLen As Integer) As Integer
    Declare Function hidGetInputReportLength Lib "mcHID.dll" Alias "GetInputReportLength" (ByVal pHandle As Integer) As Integer
    Declare Function hidGetOutputReportLength Lib "mcHID.dll" Alias "GetOutputReportLength" (ByVal pHandle As Integer) As Integer
    Declare Sub hidSetReadNotify Lib "mcHID.dll" Alias "SetReadNotify" (ByVal pHandle As Integer, ByVal pValue As Boolean)
    Declare Function hidIsReadNotifyEnabled Lib "mcHID.dll" Alias "IsReadNotifyEnabled" (ByVal pHandle As Integer) As Boolean
    Declare Function hidIsAvailable Lib "mcHID.dll" Alias "IsAvailable" (ByVal pVendorID As Integer, ByVal pProductID As Integer) As Boolean

    ' windows API declarations - used to set up messaging...

    Public Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Integer, ByVal hwnd As Integer, ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
    Public Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _
                                          (ByVal hwnd As Integer, ByVal nIndex As Integer, ByVal dwNewLong As Integer) As Integer

    Delegate Function SubClassProcDelegate(ByVal hwnd As Integer, ByVal msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
    Public Declare Function DelegateSetWindowLong Lib "USER32.DLL" Alias "SetWindowLongA" _
                                           (ByVal hwnd As Integer, ByVal attr As Integer, ByVal lval As SubClassProcDelegate) As Integer


    ' windows API Constants
    Public Const WM_APP As Integer = 32768
    Public Const GWL_WNDPROC As Short = -4

    ' HID message constants
    Private Const WM_HID_EVENT As Decimal = WM_APP + 200
    Private Const NOTIFY_PLUGGED As Short = 1
    Private Const NOTIFY_UNPLUGGED As Short = 2
    Private Const NOTIFY_CHANGED As Short = 3
    Private Const NOTIFY_READ As Short = 4

    ' local variables
    Private FPrevWinProc As Integer ' Handle to previous window procedure
    Private FWinHandle As Integer ' Handle to message window
    Private Ref_WinProc As New SubClassProcDelegate(AddressOf WinProc)
    Private HostForm As Object

    ' Set up a windows hook to receive notification
    ' messages from the HID controller DLL - then connect
    ' to the controller
    Public Function ConnectToHID(ByRef targetForm As Form) As Boolean
        Dim pHostWin As Integer = targetForm.Handle.ToInt32
        FWinHandle = pHostWin
        pHostWin = hidConnect(FWinHandle)
        FPrevWinProc = DelegateSetWindowLong(FWinHandle, GWL_WNDPROC, Ref_WinProc)
        HostForm = targetForm
    End Function

    ' Unhook from the HID controller and disconnect...
    Public Function DisconnectFromHID() As Boolean
        DisconnectFromHID = hidDisconnect
        SetWindowLong(FWinHandle, GWL_WNDPROC, FPrevWinProc)
    End Function


    ' This is the procedure that intercepts the HID controller messages...

    Private Function WinProc(ByVal pHWnd As Integer, ByVal pMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
        If pMsg = WM_HID_EVENT Then
            Select Case wParam

                ' HID device has been plugged message...
                Case Is = NOTIFY_PLUGGED
                    HostForm.OnPlugged(lParam)

                    ' HID device has been unplugged
                Case Is = NOTIFY_UNPLUGGED
                    HostForm.OnUnplugged(lParam)

                    ' controller has changed...
                Case Is = NOTIFY_CHANGED
                    HostForm.OnChanged()

                    ' read event...
                Case Is = NOTIFY_READ
                    HostForm.OnRead(lParam)
            End Select

        End If

        ' next...
        WinProc = CallWindowProc(FPrevWinProc, pHWnd, pMsg, wParam, lParam)

    End Function
End Module

【问题讨论】:

  • 添加参考没有帮助?

标签: c# vb.net dll


【解决方案1】:

假设 VB.NET 代码是 CLS compliant,您可以简单地将它的引用添加到您的 C# 项目中。

此时,DLL 中的命名空间和所有公共成员将可用于您的 C# 代码。

【讨论】:

  • @Hi,我猜它不符合 CLS,因为我无法将 .dll 文件添加到我的项目中作为参考。
  • @Un_NatMenDim - 你遇到了什么错误?您是否将 dll 标记为符合 CLS?
  • 我不知道如何将 dll 标记为符合 CLS。我只是自己的dll文件,不知道里面是什么。
  • @Un_NatMenDim - VB.NET 包装器您的代码,对吗?这是您需要添加的参考。我发布的链接包含您需要的所有详细信息。
  • 先生,我看不到您添加的链接?
【解决方案2】:

您的设计中存在耦合问题。为了解决这个问题,我建议如下:

  • HIDDLLInterface 转换为在构造函数中采用IntPtr 的类。在构造函数中,调用hidConnect
  • 使类实现IDisposable。 VB IDE 提供了一个不错的默认实现。因为您正在处理 非托管 资源,所以您可能还应该取消注释它添加的终结器。
  • 不是从 dll 接口调用表单方法,而是在相应消息进入时引发事件。
  • 检查您的 PInvoke 签名。如果参数名称中包含“句柄”,或者在本机 dll 中声明为 HWNDHsomething,则应使用 IntPtr 而不是 Integer 以更接近地匹配参数的含义。李>
  • 您也可以考虑在新类上提供额外的方法,并完全封装类中的所有“Declare”函数,但这超出了本问题的范围。

之后,该类应如下所示:

Public Class HIDController
    Implements IDisposable

#Region "Constructor"
    Public Sub New(handle As IntPtr)
        If Not hidConnect(handle) Then
            'consider a custom exception type here.  You may also get
            'more info about the failure from GetLastError.
            Throw New Exception("Connection failed")
        End If
        _handle = handle
        _prevWinProc = DelegateSetWindowLong(handle, GWL_WNDPROC, AddressOf Me.WinProc)
    End Sub
#End Region
#Region "IDisposable Support"
    Private disposedValue As Boolean 
    Protected Overridable Sub Dispose(disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                ' TODO: dispose managed state (managed objects).
            End If

            ' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
            DisconnectFromHID()
        End If
        Me.disposedValue = True
    End Sub

    Protected Overrides Sub Finalize()
        Dispose(False)
        MyBase.Finalize()
    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region

    Private _handle As IntPtr
    Private ReadOnly _prevWinProc As IntPtr

    'on one hand, you are not supposed to throw from Dispose/Finalize, but
    'on the other hand, I don't know what you would do instead to signal failure.
    Private Sub DisconnectFromHID()
        'do not disconnect if you did not connect
        If _handle = IntPtr.Zero Then Exit Sub

        If Not hidDisconnect() Then
            'see above about custom exception type
            Throw New Exception("Disconnect failed")
        End If
        SetWindowLong(_handle, GWL_WNDPROC, _prevWinProc)
        _handle = IntPtr.Zero
    End Sub

    Private Function WinProc(ByVal pHWnd As IntPtr, ByVal pMsg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
        If pMsg = WM_HID_EVENT Then
            Select Case wParam.ToInt32()
                Case NOTIFY_PLUGGED
                    OnPlugged(lParam)
                Case NOTIFY_UNPLUGGED
                    OnUnplugged(lParam)
                Case NOTIFY_CHANGED
                    OnChanged()
                Case NOTIFY_READ
                    OnRead(lParam)
            End Select
        End If

        WinProc = CallWindowProc(FPrevWinProc, pHWnd, pMsg, wParam, lParam)
    End Function

#Region "USB events"
    Private Sub OnPlugged(lParam As IntPtr)
        RaiseEvent Plugged(Me, New ParamEventArgs(lParam))
    End Sub
    Public Event Plugged As EventHandler(Of ParamEventArgs)

    Private Sub OnUnplugged(lParam As IntPtr)
        RaiseEvent Unplugged(Me, New ParamEventArgs(lParam))
    End Sub
    Public Event Unplugged As EventHandler(Of ParamEventArgs)

    Private Sub OnChanged()
        RaiseEvent Changed(Me, EventArgs.Empty)
    End Sub
    Public Event Changed As EventHandler

    Private Sub OnRead(lParam As IntPtr)
        RaiseEvent Read(Me, New ParamEventArgs(lParam))
    End Sub
    Public Event Read As EventHandler(Of ParamEventArgs)
#End Region

    'other constants and declarations I did not copy.

End Class

Public Class ParamEventArgs
    Inherits EventArgs

    Public Sub New(param As IntPtr)
        _param = param
    End Sub

    Private _param As IntPtr
    Public ReadOnly Property Param() As IntPtr
        Get
            Return _param
        End Get
    End Property

End Class

从那里,您可以更改表单以在 Load/Close 事件中创建和处置此类的实例并挂钩处理程序。您必须更改表单方法以匹配事件签名,但这应该很简单。

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    _controller = new HIDController(Me.Handle)
    AddHandler _controller.Plugged, AddressOf Me.OnPlugged
    'similarly for other events
End Sub

Private Sub Form1_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
    If _controller IsNot Nothing Then _controller.Dispose()
End Sub

现在这个类应该很容易从 C# dll 中使用。只需将HIDController 编译为 VB.NET 中的程序集,然后从 C# 项目中引用该 dll(并导入任何需要的命名空间)。不要忘记复制本机 dll; C# 编译器只会自动复制 VB dll。任何可以提供窗口句柄的类现在都可以创建HIDController 并处理其事件,而控制器不知道哪个类托管它。

PS:我建议在 VB 中编码时打开 Option Strict。此外,您可能需要查看 DllImport 以将本机库中的函数导入 .NET 项目,因为这是大多数示例的方式,并且可以更轻松地在 VB 和 C# 之间进行复制。

【讨论】:

    【解决方案3】:

    在 VB 项目中引用 C# dll(或者直接将 dll 放到 /bin 文件夹中)

    如您所知,您需要将表单类中的 VB.NET 代码改编为 C#。

    回答您的问题,而不是来自 VB.NET 表单代码隐藏的调用:

    iConnectToHID(Me)
    

    你会使用

    iConnectToHID(this);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多