如何調用外部DLL內的方法與資源

如何調用外部DLL內的方法與資源

一般來說調用DLL可以透過參考的方式來達到目的。但在某些情況下,需要臨時參考某個DLL檔時,或是想把DLL包入資源檔中,就可以透過 Reflection 來將程式庫載入。

 

範例:

引用外部 DLL 檔案,調用方法與資源檔。

 

動作:

1. 按下按鍵(Button1),從 Utility.DLL 中調用方法 GetNicIPAddrNumber 取回目前電腦所使用的 IP (數值)並填入文字方塊(TEXTBOX1)內。

2. 調用 Utility.DLL 中的資源,將圖示檔(OnLineIcon)取出後,置換目前視窗所使用的圖示。

 

原始碼:



   Dim asmUtility As System.Reflection.Assembly = System.Reflection.Assembly.LoadFile("C:\TEST\Utility.dll")

   For Each tmpType As Type In asmUtility.GetTypes
       Select Case tmpType.Name
          Case "IPTools"
               Me.TEXTBOX1.Text = tmpType.InvokeMember(Nothing, Reflection.BindingFlags.DeclaredOnly Or Reflection.BindingFlags.Public Or Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance Or Reflection.BindingFlags.CreateInstance, Nothing, Nothing, Nothing).GetNicIPAddrNumber
          Case "Resources"
               Me.Icon = tmpType.InvokeMember("OnLineIcon", Reflection.BindingFlags.GetProperty, Nothing, Nothing, Nothing)
       End Select
   Next

End Sub


Binding Flags 列舉型別

Default 指定無繫結旗標。
IgnoreCase 指定繫結時不考慮成員名稱的大小寫。
DeclaredOnly 指定只考慮在所提供型別階層層級宣告的成員。不考慮繼承成員。
Instance 指定執行個體成員將包含在搜尋中。
Static 指定靜態成員將包含在搜尋中。
Public 指定搜尋中要包含公用 (Public) 成員。
Non Public 指定在搜尋中包含非公用成員。
FlattenHierarchy 指定應傳回在階層之上的 Public 成員和受保護的靜態 (Static) 成員。不會傳回繼承類別中的私用靜態成員。靜態成員包括欄位、方法、事件和屬性。巢狀型別 (Nested Type) 不會傳回。
InvokeMethod 指定要叫用方法。這不能是建構函式或型別初始設定式。
CreateInstance 指定反映應該建立指定型別的執行個體。呼叫符合指定引數的建構函式。所提供的成員名稱會忽略。如果沒有指定查詢的類型,則會套用 (Instance | Public)。不可能呼叫型別初始設定式。
GetField 指定所指定欄位的值應傳回。
SetField 指定應設定所指定欄位的值。
GetProperty 指定所指定屬性的值應傳回。
SetProperty 指定應設定所指定屬性的值。對於 COM 屬性來說,指定這個繫結旗標等同於指定 PutDispProperty 和 PutRefDispProperty。
PutDispProperty 指定要叫用 COM 物件上的 PROPPUT 成員。PROPPUT 會指定使用一個值的屬性設定功能。如果屬性同時具有 PROPPUT 和 PROPPUTREF,而且必須區分呼叫哪一個,則使用 PutDispProperty。
PutRefDispProperty 指定應該要叫用 COM 物件上的 PROPPUTREF 成員。PROPPUTREF 會指定要使用參考而非數值的屬性設定函式。如果屬性同時具有 PROPPUT 和 PROPPUTREF,而且必須區分呼叫哪一個,則使用 PutRefDispProperty。
ExactBinding 指定所提供引數型別必須確實符合對應的型式參數型別。如果呼叫端提供非 Null 的 Binder 物件,則反映會擲回例外狀況,因為那表示呼叫端正在提供會選擇適當方法的 BindToXXX 實作。
SuppressChangeType 尚未實作。
OptionalParamBinding 傳回成員集,其參數計數會符合所提供引數的數目。這個繫結旗標用於具有預設值參數的方法和具有變數引數 Varargs 的方法。這個旗標應該只與 Type.InvokeMember 使用。
IgnoreReturn 用於 COM Interop 以指定成員的傳回值可忽略。




UTILITY.DLL 原始碼


    ''' <summary>
    ''' 取回網路卡 IP 位址(數值模式)
    ''' </summary>
    ''' <param name="intIndex">編號。預設為第一組 IP 位址</param>
    Public Shared Function GetNicIPAddrNumber(Optional ByVal intIndex As Integer = 0) As Long
        Dim strAddr As String = GetNicIPAddr(intIndex)
        Return IP2DEC(strAddr)
    End Function

    ''' <summary>
    ''' 取回網路卡 IP 位址
    ''' </summary>
    ''' <param name="intIndex">編號。預設為第一組 IP 位址</param>
    Public Shared Function GetNicIPAddr(Optional ByVal intIndex As Integer = -1) As String
        Dim strHostName As String = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties.HostName
        Dim tmpString As String = ""

        If intIndex > -1 Then
            tmpString = System.Net.Dns.GetHostEntry(strHostName).AddressList(intIndex).ToString
        Else
            For Each tmpIPaddr As Net.IPAddress In System.Net.Dns.GetHostEntry(strHostName).AddressList
                If Not tmpIPaddr.IsIPv6LinkLocal Then
                    tmpString = tmpIPaddr.ToString
                    Exit For
                End If
            Next
        End If

        If tmpString.Trim = "" Then
            Return ""
        Else
            Return CInt(tmpString.Split(".")(0)).ToString("000") & "." & CInt(tmpString.Split(".")(1)).ToString("000") & "." & CInt(tmpString.Split(".")(2)).ToString("000") & "." & CInt(tmpString.Split(".")(3)).ToString("000")
        End If
    End Function

    ''' <summary>
    ''' 將 IP 位址 (nnn.nnn.nnn.nnn) 轉換為 IP 數值
    ''' </summary>
    ''' <param name="IPAddress">文字格式的 IP 位址</param>
    ''' <returns>數值型態的 IP 位址</returns>
    Public Shared Function IP2DEC(ByVal IPAddress As String) As Long
        Dim strIPs() As String
        Dim lngReturn As Long = 0
        strIPs = Split(IPAddress, ".")
        If UBound(strIPs) <> 3 Then Return 0

        For i As Integer = 0 To UBound(strIPs)
            If (CLng(strIPs(i)) < 0) Or (CLng(strIPs(i)) > 255) Then Return 0
        Next

        lngReturn = (CLng(strIPs(0)) * (256 ^ 3)) + (CLng(strIPs(1)) * (256 ^ 2)) + (CLng(strIPs(2)) * 256) + (CLng(strIPs(3)))

        Return lngReturn
    End Function
End Class



參考 COM 元件範例:

使用 Windows Media Player 的 COM 元件Interop.WMPLib.dll,將此元件加入到資源檔中,再來透過資源檔來調用其功能。


Dim objWMP as Object
asmWMP = System.Reflection.Assembly.Load(My.Resources.Interop_WMPLib)
objWMP = System.Activator.CreateInstance(asmWMP.GetType("WMPLib.WindowsMediaPlayerClass"))

播放檔案
objWMP.URL = “要播放的檔案”
objWMP.settings.autoStart = False
objWMP.settings.playCount = 1
objWMP.controls.play()


停止播放
objWMP.controls.stop()




看吧,一切就是這麼簡單。


程式是運氣與直覺堆砌而成的奇蹟。
若不具備這兩者,不可能以這樣的工時實現這樣的規格。
修改規格是對奇蹟吐槽的褻瀆行為。
而追加修改則是相信奇蹟還會重現的魯莽行動。