其它技術
求取變數在記憶體中的位置,這是 Visual Basic 內建函數,但是微軟不建議使用
函數名 | 引數 | 說明 |
VarPtr | Any | 求取任一變數在記憶體中的位置,使用者自訂型態也用這個 |
StrPtr | String | 求取字串在記憶體中的位置 |
ObjPtr | UnKnown | 求取任一物件在記憶體中的位置 |
MSChart 物件結構圖:為配合使用 MSChart 物件,不得不自行繪製其結構圖,畫這張圖就花了一天,被老闆譏為浪費時間,希望各位網友不要再白花時間了
最佳化
尋找字串變數在字串中的位置:
尋找字串變數在字串中的位置時,若字串可能不分大小寫,可以用字串比較或全部轉成小寫後尋找,全部轉成小寫後再尋找可節省 30 % 的時間
tLoc = InStr(1, OldStr, FindStr, vbTextCompare)
tLoc = InStr(LCase(OldStr), LCase(FindStr)) ' 較快取得中英混合字串長度 (中文字串當成 2)
經常用來取的中英混合字串長度的方式有兩種:
- tLen = lstrlen(myString) ' Windows API
- tLen = LenB(StrConv(myString, vbFromUnicode))
其速度比為
字串長度 | <256 | >256 |
---|---|---|
法 1 | 80% | 120% |
法 2 | 100% | 100% |
當字串長度小於 256 個字元時,使用 Windows API 較快,當字串長度大於 256 個字元時,使用 Visual Basic 函數較快,而使用哪種方式求取字串長度視使用狀況而定
字串測試報告
對於字串到底在記憶體中是如何的存在呢?在引數傳遞中又是如何傳遞呢?很多人大概跟我一樣好奇,首先先以 myStrPtr 這個函數模擬對於 StrPtr 這個函數的動作:
Public Function myStrPtr(lpString As Variant) As Long ReDim tBytes(1 To 16) As Byte Dim tLong As Long CopyMemory tBytes(1), lpString, 16 CopyMemory tLong, tBytes(9), 4 CopyMemory myStrPtr, ByVal tLong, 4 End Function |
不管是 String 或是 Variant 的字串型態,先強迫轉換為可取得 Pointer 內容的 Variant 資料型態,透過第 9 ~ 12 位元的指標指向原 String 的指標位置,再將指標位置的內容轉換為 String 的指標
那麼在這個記憶體位置內的內容又是如何表示的呢?在 Visual Basic 的相關技術文件均記載著是以 UniCode 的型式存在,我們來看看範例 "Basic 培基語言" 在記憶體內的 16 進位值:
42 0 61 0 73 0 69 0 63 0 20 0 F9 57 FA 57 9E 8A 0 8A
以上 42 0 就是 "B" 的 UniCode 值, F9 57 就是 "培" 的 UniCode 值
對於 Visual Basic 中的字串傳遞大概沒問題了,那麼對於呼叫 Windows API 又是如何運作的呢?我們以三種宣告引數方式及兩種傳遞引數方式測試:
Dim tStr As String : tStr = "Basic 培基語言"
引數宣告 | 傳址呼叫 (ByRef) | 傳值呼叫 (ByVal) |
lpString As Any | 指向 ANSI 字串的指標 | ANSI 字串的指標 |
lpString As String | 指向 ANSI 字串的指標 | ANSI 字串的指標 |
ByVal lpString As String | ANSI 字串的指標 | ANSI 字串的指標 |
什麼是 ANSI 字串呢?一般我們存在檔案中的格式就是所謂的 ANSI 字串,我們來看看範例 "Basic 培基語言" 在記憶體內的 16 進位值:
42 61 73 69 63 20 B0 F6 B0 F2 BB 79 A8 A5
以上 42 就是 "B" 的 ANSI 值, B0 F6 就是 "培" 的 ANSI 值 (= Asc("培"))
由以上總結,在傳值呼叫中, Visual Basic 會將 tStr 內容由 UniCode 碼轉換為 ANSI 碼,並將指向這個位置的指標傳遞給 DLL ,而傳址呼叫會將指向字串的指標位置傳給 DLL ,若要取得 tStr 的 ANSI 的位元陣列可用三種方式:
Dim tBytes() As Byte tBytes = StrConv(tStr, vbFromUnicode) |
Declare Sub CopyMemory Lib "kernel32" Alias
"RtlMoveMemory" (hpvDest As Any, lpString As
Any, ByVal cbCopy As Long) ReDim tBytes(1 To 14) As Byte |
Declare Sub CopyMemory Lib "kernel32" Alias
"RtlMoveMemory" (hpvDest As Any, lpString As
Any, ByVal cbCopy As Long) ReDim tBytes(1 To 14) As Byte |
由上大改可以概知 Visual Basic 在傳遞字串的轉移方式,另外對於使用者自訂型態中的字串來說,傳遞的是指向 ANSI 字串的指標,也就是說 Visual Basic 在傳遞使用者自訂型態前還是會自動做轉換處理
註:宣告引數為 lpString As String 在傳遞上並不穩定,下面兩種方式居然得到兩種不同內容,在使用上請自行注意:
Declare Sub CopyMemoryStr Lib "kernel32"
Alias "RtlMoveMemory" (hpvDest As Any, lpString
As String, ByVal cbCopy As Long) ReDim tBytes(1 To 14)
As Byte CopyMemoryStr tBytes(1), tStr, 14 ' 傳遞內容與宣告成為 lpString As Any 相同 ' 只是在下面加一個 CopyMemoryStr tlng, tStr, 4
敘述,卻完全不知道在傳什麼,傳遞內容完全不同 |
轉載 MSDN 文章
以下資訊版權屬 Microsoft 所有,文章是 MSDN 裡的,我只是抓回來自己參考並提供網友參考
經運用本文內容後,完成的螢幕保護程式並支援 Windows 內建密碼保護功能