none
[VB2005] 如何動態 載入和卸載 dll RRS feed

  • 問題

  • 請教各位大大

    我目前使用到一個Dll

    宣告為

    Public Declare Function AD_GetData Lib "AD8528.dll" Alias "_AD_GetData@16" (ByRef high As Integer, ByRef low As Integer, ByVal buffer() As Byte, ByRef size As Integer) As Integer

    我在System.Windows.Forms.timer中 持續去呼叫它

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick

            Dim high As Integer
            Dim low As Integer
            Dim length As Integer
            Dim databyte(127) As Byte
            Dim RxData As Integer
            RxData = AD_GetData(high, low, length, databyte)      
        End Sub

    但視窗光移動都變得很慢  時間一長就當掉了

    請問若把呼叫方式改為動態載入跟卸載這dll 會變比較好嗎? 還是這dll本身就有的問題?

    若是改為動態方式可能可以解決  請問這應該怎麼做

    或是可以推薦那裡有資料可以參考嗎

     

    謝謝

     

    2010年3月25日 上午 06:02

解答

  • 對於Function DLL VBNET 沒辦法,也許幾代後在 VBNET 裡面加入 pointer 完整功能還有可能。

    其他 DLL 到是可以動態載入,例如 COM DLL 的延後連結、.Net Managed DLL 的動態載入。

    若 dll 本身有問題,我都是丟給原廠去處理,若有未釋放的記憶體,在 VBNET 可以定時呼叫 GC.Collect ,因為大多數未釋放的記憶體只是 .Net 還沒去釋放,而非 dll 的問題,若是 dll 有問題,換啥語言都有問題,而記憶體是跟程序的,釋放 dll 只會變成無主破碎的記憶體,到時要靠程式終結才能釋放。

    所以你一開始應該就走偏了。


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    提問時,錯誤情境描述與錯誤訊息很重要,情境描述包含你做了什麼,預期的結果與實際發生的結果。一個最爛的問法範例:「我的電腦電腦怎麼不能開機?」誰知道你家是不是沒電還是你根本找不到電源鈕。
    • 已標示為解答 Vic-Su 2010年4月1日 上午 03:49
    2010年3月29日 下午 02:52
  • 我的習慣會在 Do Loop 迴圈內,先睡再收,因為要等硬體判讀收到你的命令開始準備回應跟資料回傳的時間,睡的話看你的資料量,1 ms 的話,你用 AccessPort 看,大概也等同 1 bytes 1 bytes 收了。

    我自己一睡就會睡 10 ~ 30 ms ,至於 100 ms 下實在沒啥意義,因為硬體自己也有反應時間,除非你的通訊協定可以很輕易判別結束字元,或者是 485 的第 3 byte 是資料長度,你可以確認結束,否則一般都會等到 TimeOut 才視為接收完畢,所以這樣 1ms 以下意義就不大了,而且你把時間也同時顯示出來看看,你會發覺時差會亂跳...

    畫面 lag 牽扯兩部分:

    1. 不要用主執行緒抓資料,而是開新執行緒,畫面就不會受影響。

    2. 畫面更新時,要先通知 Form 不要立即更新,比如說 BeginUpdate / SuspendLayout


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    提問時,錯誤情境描述與錯誤訊息很重要,情境描述包含你做了什麼,預期的結果與實際發生的結果。一個最爛的問法範例:「我的電腦電腦怎麼不能開機?」誰知道你家是不是沒電還是你根本找不到電源鈕。
    • 已標示為解答 Vic-Su 2010年4月2日 上午 10:59
    2010年4月1日 下午 03:23

所有回覆

  • PS : high , low , length, databyte 是會回傳值回來的
    2010年3月25日 上午 08:34
  • 各位大大  我從網路上使用了以下的方式

    引用的函數若是以下這種參數不需回傳的 就沒問題 

    Public Declare Function AD_Open Lib "AD8528.dll" Alias "#7" (ByVal port As Integer) As Integer

    但是若像byref 有值會回傳的型式  就沒辦法  請問能告訴我問題在那裡嗎? 以下是代碼

     

        Public Declare Function GetStdHandle Lib "kernel32" (ByVal nStdHandle As Integer) As Integer
    
        Private Declare Auto Function LoadLibrary Lib "kernel32" (ByVal LibFilePath As String) As Integer
    
        Private Declare Function GetProcAddress Lib "kernel32" (ByVal ModuleHandle As Integer, ByVal ProcName As String) As Integer
    
        Public Delegate Function MyMax(ByRef high As Integer, ByRef low As Integer) As Integer
    
        Private Declare Function FreeLibrary Lib "kernel32" (ByVal ModuleHandle As Integer) As Integer
        Private hLib As IntPtr
    
        Public Sub LoadMyDLL(ByVal DLLPath As [String])
    
            hLib = LoadLibrary(DLLPath)
    
        End Sub
    
    
        Public Function Invoke(ByVal pAPIName As String, ByVal ptype As Type) As [Delegate]
    
            Dim api As IntPtr = GetProcAddress(hLib, pAPIName)
    
            Return DirectCast(Marshal.GetDelegateForFunctionPointer(api, ptype), [Delegate])
    
        End Function
    
    
    
        Public Sub go()
    
            Dim ret As Integer
            Dim a As Integer = 0
            Dim b As Integer = 0
            Call LoadMyDLL("D:\Visual Basic\AD8528_Test\AD8528_Test\bin\Debug\AD8528.dll")
    
            Dim s As MyMax = Invoke("_AD_GetMacAddress@8", GetType(MyMax))
    
            ret = s(a, b)
            Console.WriteLine(ret)
            Console.WriteLine(a)
            Console.WriteLine(b)
            Console.ReadLine()
    
            FreeLibrary(hLib)
    
    
        End Sub
    
        Sub main()
    
            Call go()
    
        End Sub
    

    2010年3月25日 上午 11:08
  • VB6/VBNET 不支援指標,所以用 LoadLibrary 最多只能做到一個引數,超過一個以上的不行。

    你可以先問廠商看看,類比轉數位多半是走 485 ,直接自己寫也不會有這樣問題。


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    提問時,錯誤情境描述與錯誤訊息很重要,情境描述包含你做了什麼,預期的結果與實際發生的結果。一個最爛的問法範例:「我的電腦電腦怎麼不能開機?」誰知道你家是不是沒電還是你根本找不到電源鈕。
    2010年3月25日 下午 03:03
  • 應該和動態載入跟卸載這dll, 而是在.NET平台與Windows平台做資料轉換產生的影響(ByRef)會由Windows平台傳回結果, ByVal不會
    2010年3月26日 上午 03:10
  • 我測試了一下他其他的函數  結果也有同樣的問題

    有幾個Byval的也一樣 之前沒測到這幾個函數 譬如

    Public Declare Function AD_SendData Lib "AD8528.dll" Alias "_AD_SendData@16" (ByVal IEEE1 As Integer, ByVal IEEE2 As Integer, ByVal buffer() As Char, ByVal size As Integer) As Integer

    這dll目的其實只是一般的RS232的程式

    我如果不用他自己寫這段程式就沒問題  所以應該跟硬體無關

    我測試了一下  我下一命令給dll 等待他回應有時居然會到將近500ms

    目前跟廠商要他的原始碼中 謝謝兩位前輩指導

     

     

    2010年3月29日 上午 12:32
  • VB6/VBNET 不支援指標,所以用 LoadLibrary 最多只能做到一個引數,超過一個以上的不行。

    你可以先問廠商看看,類比轉數位多半是走 485 ,直接自己寫也不會有這樣問題。


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    提問時,錯誤情境描述與錯誤訊息很重要,情境描述包含你做了什麼,預期的結果與實際發生的結果。一個最爛的問法範例:「我的電腦電腦怎麼不能開機?」誰知道你家是不是沒電還是你根本找不到電源鈕。


    心大  另外請教一下

    那在VB.Net中有別種指令可以做得到嗎?

    2010年3月29日 上午 12:33
  • 問哪個?LoadLibrary ? 485 ?


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    提問時,錯誤情境描述與錯誤訊息很重要,情境描述包含你做了什麼,預期的結果與實際發生的結果。一個最爛的問法範例:「我的電腦電腦怎麼不能開機?」誰知道你家是不是沒電還是你根本找不到電源鈕。
    2010年3月29日 下午 12:20
  • 除了LoadLibrary 以外 還有其他方式可以做得到超過一個以上引數的動態載入跟卸載嗎?
    2010年3月29日 下午 01:55
  • 對於Function DLL VBNET 沒辦法,也許幾代後在 VBNET 裡面加入 pointer 完整功能還有可能。

    其他 DLL 到是可以動態載入,例如 COM DLL 的延後連結、.Net Managed DLL 的動態載入。

    若 dll 本身有問題,我都是丟給原廠去處理,若有未釋放的記憶體,在 VBNET 可以定時呼叫 GC.Collect ,因為大多數未釋放的記憶體只是 .Net 還沒去釋放,而非 dll 的問題,若是 dll 有問題,換啥語言都有問題,而記憶體是跟程序的,釋放 dll 只會變成無主破碎的記憶體,到時要靠程式終結才能釋放。

    所以你一開始應該就走偏了。


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    提問時,錯誤情境描述與錯誤訊息很重要,情境描述包含你做了什麼,預期的結果與實際發生的結果。一個最爛的問法範例:「我的電腦電腦怎麼不能開機?」誰知道你家是不是沒電還是你根本找不到電源鈕。
    • 已標示為解答 Vic-Su 2010年4月1日 上午 03:49
    2010年3月29日 下午 02:52
  • 廠商會給你的,應該是通訊協定,而非原始碼,會給你 dll 就是不想給你原始碼。

    通訊協定可以裝 AccessPort 去撈,從 AccessPort 也可以看出為啥要 500ms ,若是中間有一些有燈號的設備,也可以看燈號來辨識。

    我是碰過很多 COM Port 寫得亂七八糟的程式,會變成資料是 1 byte 1 byte 的收,那時間就會比較久,CPU Loading 也會比較重。


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    提問時,錯誤情境描述與錯誤訊息很重要,情境描述包含你做了什麼,預期的結果與實際發生的結果。一個最爛的問法範例:「我的電腦電腦怎麼不能開機?」誰知道你家是不是沒電還是你根本找不到電源鈕。
    2010年3月29日 下午 02:56
  • 心大 您說的沒錯

    我這兩天花點時間去找廠商要到他的程式碼

    他在通訊的部分的確是一個byte一個byte去收 這是問題一

    問題二是 傳送命令的部分他也是一個byte一個byte傳送過去 而且每傳送一個byte之間sleep(1)

    畫面lag原因 我目前還在try 所以我寫了以下的程式

     

    Public RecieveData, RecieveMac As String
    Public RequestCMD As Boolean

    Sub Serial_RxData(ByRef lendata As Byte, ByRef databyte() As Byte, ByRef rssi As Integer, ByRef high As String, ByRef low As String, ByRef data As String) Dim Tick As UInteger Dim Rxdata As String Dim pos As Integer RequestCMD = True '============= Read Data =============== RecieveData = "" myRS232.Write("ATRXDATA" + Chr(13) + Chr(10)) Tick = GetTickCount() Do Rxdata = myRS232.ReadExisting() RecieveData = RecieveData + Rxdata If (GetTickCount() - Tick) >= 100 Then myRS232.DiscardInBuffer() RequestCMD = False Exit Sub End If System.Windows.Forms.Application.DoEvents() System.Threading.Thread.Sleep(1) Loop Until InStr(1, RecieveData, Chr(13) + Chr(10) + _
     "OK" + Chr(13) + Chr(10)) > 0 Or _
     RecieveData = "FAIL ER05" + Chr(13) + _
     Chr(10) If (Mid(RecieveData, 1, 4) = "FAIL") Or _
     ((Mid(RecieveData, 1, 7) = "ERXDATA") _
    And (Len(RecieveData) <> 60)) Then myRS232.DiscardInBuffer() RequestCMD = False Exit Sub End If '============= Read Mac Address =============== RecieveMac = "" myRS232.Write("ATDUMP 4" + Chr(13) + Chr(10)) Tick = GetTickCount() Do Rxdata = myRS232.ReadExisting() RecieveMac = RecieveMac + Rxdata If (GetTickCount() - Tick) >= 100 Then myRS232.DiscardInBuffer() RequestCMD = False Exit Sub End If System.Windows.Forms.Application.DoEvents() System.Threading.Thread.Sleep(1) Loop Until InStr(1, RecieveMac, "END" + Chr(13) + Chr(10)) > 0 If Len(RecieveMac) = 131 And Len(RecieveData) = 60 Then pos = InStr(1, RecieveMac, "IEEE Addr:") + 1 pos = InStr(pos, RecieveMac, "IEEE Addr:") + 10 high = Mid(RecieveMac, pos, 8) low = Mid(RecieveMac, pos + 8, 8) rssi = Convert.ToInt32(Mid(RecieveData, 20, 2), 16) lendata = Val(Mid(RecieveData, 17, 2)) databyte = StrToByteArray(Mid(RecieveData, 23, lendata)) data = (Mid(RecieveData, 23, lendata)) Else myRS232.DiscardInBuffer() End If RequestCMD = False End Sub

    我使用timer循環呼叫這sub來呼叫這程式  寫的不好請不要見笑 希望大大能指出寫的不好的地方 謝謝 ^^a

    當timer.interval 設定100ms或以上時也不會有問題 但如果設定在100ms 以下時 就會產生畫面lag的問題

    因為這程式共有兩個command 我各別連續去下時 比較沒有問題(也是會有,比較不明顯)但一起時 一整個不行

    我想可能是硬體回覆本身就在loop等待中 所以我才用了RequestCMD來判斷是否正在執行,如下

    If RequestCMD = False Then Serial_RxData(length, databyte, rssi, high, low, datastring)

    不知道這樣的寫法 好不好 希望請大大們指導一下

     

    謝謝~~

     

     

    • 已編輯 Vic-Su 2010年4月1日 上午 12:50 畫面編輯清楚些
    2010年4月1日 上午 12:48
  • 我的習慣會在 Do Loop 迴圈內,先睡再收,因為要等硬體判讀收到你的命令開始準備回應跟資料回傳的時間,睡的話看你的資料量,1 ms 的話,你用 AccessPort 看,大概也等同 1 bytes 1 bytes 收了。

    我自己一睡就會睡 10 ~ 30 ms ,至於 100 ms 下實在沒啥意義,因為硬體自己也有反應時間,除非你的通訊協定可以很輕易判別結束字元,或者是 485 的第 3 byte 是資料長度,你可以確認結束,否則一般都會等到 TimeOut 才視為接收完畢,所以這樣 1ms 以下意義就不大了,而且你把時間也同時顯示出來看看,你會發覺時差會亂跳...

    畫面 lag 牽扯兩部分:

    1. 不要用主執行緒抓資料,而是開新執行緒,畫面就不會受影響。

    2. 畫面更新時,要先通知 Form 不要立即更新,比如說 BeginUpdate / SuspendLayout


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    提問時,錯誤情境描述與錯誤訊息很重要,情境描述包含你做了什麼,預期的結果與實際發生的結果。一個最爛的問法範例:「我的電腦電腦怎麼不能開機?」誰知道你家是不是沒電還是你根本找不到電源鈕。
    • 已標示為解答 Vic-Su 2010年4月2日 上午 10:59
    2010年4月1日 下午 03:23
  • 心大

    真的很感謝你的幫忙跟指導

    多執行緒的方式我沒用過 不過我想這是我問題所在

    謝謝各位的指點與幫忙

    2010年4月2日 上午 10:59
  • 我覺得這個算簡單的了:

    http://tlcheng.spaces.live.com/blog/cns!145419920BFD55A7!1440.entry


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    提問時,錯誤情境描述與錯誤訊息很重要,情境描述包含你做了什麼,預期的結果與實際發生的結果。一個最爛的問法範例:「我的電腦電腦怎麼不能開機?」誰知道你家是不是沒電還是你根本找不到電源鈕。
    2010年4月2日 下午 01:09
  • 您好

    感謝你的幫忙

    我對於多執行緒有些疑問 

    1.能強制停止所開啟的執行緒嗎

    2.所開啟的執行緒可以傳回值嗎

     

    我有心大您另外回覆別人的問題中看到用thread的方式 

    以下是我修改後的連續讀取dll的程式

    Imports System.Threading

    Dim mythread = New System.Threading.Thread(AddressOf myProccess)

    mythread.Start()

    Sub myProccess()

            Dim hi As Integer
            Dim lo As Integer
            Dim leng As Integer
            Dim data(127) As Byte
            Dim rssi As Integer
            Dim i As Long


            Do
                Tick = GetTickCount()

                If i = 10000000 Then i = 0

                If i Mod 5 = 0 Then
                    System.Windows.Forms.Application.DoEvents()
                    GC.Collect()
                End If

                RecieveStatus = AD_GetData(hi, lo, data, leng, rssi)

                System.Threading.Thread.Sleep(30)

                i = i + 1
            
            Loop

        End Sub

    可是我不大清楚如何強制關掉此執行緒 和如何從此執行緒傳值回去

    或是這樣根本就是不度的寫法

    期盼大大的指導

    謝謝~~

     

     

    2010年4月7日 上午 10:13
  • 1. [終結執行緒 ]

    2. [.NET Framework 開發人員手冊 建立執行緒並在啟動時間傳遞資料 ]

    3.[.NET Framework 開發人員手冊 Managed 執行緒 ]


    MSDN 文件庫很重要
    回應幫助你的人是一種禮貌, 良好的禮貌有助於激發大家對你問題回應的熱情
    進步的人會找尋自己程式中的缺點,半桶水則把自己程式的錯誤推到不相干事物的身上
    2010年4月7日 上午 11:46
    版主
  • 1. 有人回了

    2. 不要把執行緒當函數... 執行緒基本上是執行後不理,如果不會控制流程,寫成一個小類別,結束時觸發事件,透過事件來回收結果。


    論壇是網友平等互助 保證解答請至 微軟技術支援服務
    提問時,錯誤情境描述與錯誤訊息很重要,情境描述包含你做了什麼,預期的結果與實際發生的結果。一個最爛的問法範例:「我的電腦電腦怎麼不能開機?」誰知道你家是不是沒電還是你根本找不到電源鈕。
    2010年4月7日 下午 02:55
  • 謝謝大大提供的資料

    之前搞錯了  所以造成不能使用Abort

    感謝

    ^^

    2010年4月9日 上午 06:48
  • 了解

    觀念錯誤謝謝大大指正~~~

    2010年4月9日 上午 06:49