【程式四】: 
  
'看看我們的東西被拷貝到哪兒去了  
Sub TestCopyMemory() 
 Dim i As Long, k As Long 
 k = 5 
 i = VarPtr(k) 
 NOTE4: CopyMemory i, 40000, 4 
 Debug.Print k 
 Debug.Print i 
 i = VarPtr(k) 
 NOTE5: CopyMemory ByVal i, 40000, 4 
 Debug.Print k 
End Sub  
  
  程式輸出: 
  
5 
40000 
40000  
  
由於NOTE4處使用缺省的ByVal,傳遞的是i的位址(也就是指向i的指標),所以常量40000拷貝到了變數i堙A因此i的值成了40000,而k的值卻沒有變化。 
 
  
但是,在NOTE4前有:i=VarPtr(k),本意是要把i本身做為一個指標來使用。 
 
  
這時,我們必須如NOTE5那樣用ByVal來傳遞指標i,由於i是指向變數k的指標,所以最後常量40000被拷貝了變數k堙C 
  
  希望你已經理解了這種區別,在後面問題的討論中,我還會再談到它。 
 
  
 
  
 4、AddressOf 
  
  它用來得到一個指向VB函數入口位址的指標,不過這個指標只能傳遞給API使用,以使得API能回調VB函數。 
  
  本文不準備詳細討論函數指標,關於它的使用請參考VB文檔。 
  
  5、拿來主義 
  
  實際上,有了CopyMemory,VarPtr,AddressOf這三把斧頭,我們已經可以將C堸禰貌澈標操作拿過來了。 
  
  如下面的C程式包括了大部分基本的指標指標操作: 
  
struct POINT{ 
 int x; int y; 
}; 
  
int Compare(void* elem1, void* elem2){} 
  
void PtrDemo(){ 
 //指針聲明: 
 char c = 'X'; //聲明一個char型變數 
 char* pc; long* pl; //聲明普通指針 
 POINT* pPt; //聲明結構指標 
 void* pv; //聲明無類型指針 
 int (*pfnCastToInt)(void *, void*);//聲明函數指標:  
 //指針賦值: 
 pc = &c; //將變數c的位址值賦給指針pc 
 pfnCompare = Compare; //函數指標賦值。 
 //指針取值: 
 c = *pc; //將指標pc所指處的記憶體值賦給變數c 
 //用指針賦值: 
 *pc = 'Y' //將'Y'賦給指標pc所指記憶體變數堙C 
 //指標移動: 
 pc++; pl--;  
}  
  
  這些對指針操作在VB堻ㄕ陬它P的東西,前面討論ByVal和ByRef時曾說過傳指針和傳地址是一回事, 
 
  
實際上當我們在VB堨巹坌椌ByRef聲明函數參數時,我們已經就聲明了指標。 
  
  如一個C聲明的函數:long Func(char* pc) 
  
  其對應的VB聲明是:Function Func(pc As Byte) As Long 
  
  這時參數pc使用缺省的ByRef傳位址方式來傳遞,這和C堨峆針來傳遞參數是一樣。 
  
  那麼怎麼才能象C堥獐邥確地聲明一個指標呢? 
  
  很簡單,如前所說,用一個32位元長整數來表達指標就行。在VB奡N是用Long型來明確地聲明指標,我們不用區分是普通指標、 
 
  
無類型指標還是函數指標,通通都可用Long來聲明。而給一個指標賦值,就是賦給它用VarPar得到的另一個變數的位址。具體見程式五。 
  
  【程式五】:同C一樣,各種指針。 
  
Type POINT 
 X As Integer 
 Y As Integer 
End Type 
  
Public Function Compare(elem1 As Long, elem2 As Long) As Long 
' 
End Function 
  
Function FnPtrToLong(ByVal lngFnPtr As Long) As Long 
 FnPtrToLong = lngFnPtr 
End Function 
  
Sub PtrDemo() 
 Dim l As Long, c As Byte, ca() As Byte, Pt As POINT 
 Dim pl As Long, pc As Long, pv As Long, pPt As Long, pfnCompare As Long 
 c = AscB("X") 
 pl = VarPtr(l) '對應C堛long、int型指針 
 pc = VarPtr(c) '對應char、short型指針 
 pPt = VarPtr(Pt) '結構指標 
 pv = VarPtr(ca(0)) '位元組陣列指標,可對應任何類型,也就是void* 
 pfnCompare = FnPtrToLong(AddressOf Compare) '函數指標 
 CopyMemory c, ByVal pc, LenB(c) '用指針取值 
 CopyMemory ByVal pc, AscB("Y"), LenB(c) '用指針賦值 
 pc = pc + LenB(c) : pl = pl - LenB(l) '指標移動 
End Sub 
  
  
  我們看到,由於VB不直接支持指標操作,在VB堨峆標取值和用指標賦值都必須用CopyMemory這個API, 
 
  
而調用API的代價是比較高的,這就決定了我們在VB堥洏峆標不能象在C堥獐辿菪悕M頻繁,我們必須要考慮指標操作的代價, 
 
  
在後面的"指標應用"我們會再變談這個問題。 
  
  程式五中關於函數指標的問題請參考VB文檔,無類型指標void*會在下面"關於Any的問題"婸﹛C 
  
  程式五基本上已經包括了我們能在VB媔i行的所有指標操作,僅此而已。 
  
  下面有一個小測試題,如果現在你就弄懂了上面程咬金的三板斧,你就應該能做得出來。 
  
  上面提到過,VB.NET中沒有VarPtr,我們可以用聲明API的方式來引入MSVBVM60.DLL中的VarPtr。 
 
  
現在的問題如果不用VB的運行時DLL檔,你能不能自己實現一個ObjPtr。答案在下一節後給出。 
  |