如何讓VB調用外部的DLL

來源:互聯網
上載者:User
collected by barenxWindows動態串連庫是包含資料和函數的模組,可以被其它可執行檔(EXE、DLL、OCX 等)調用。動態串連庫包含兩種函數:輸出(exported)函數和內部(internal)函數。輸出函數可以被其它模組調用,而內建函式則只能在動態串連庫內部使用。儘管動態串連庫也能輸出 資料,但實際上它的資料通常是只在內部使用的。使用動態串連庫的優點是顯而易見的。將應用程式的一部分功能提取出來做成動態串連庫,不但減小了主應用程式的大小,提高了程式 運行效率,還使它更加易於升級。多個應用程式共用一個動態串連庫還能有效地節省系統資源。正因為如此,在Windows系統中,動態串連庫得到了大量的使用。   一般來說,動態串連庫都是以DLL為副檔名的檔案,如Kernel32.dll、commdlg.dll等。但也有例外,如16位Windows的核心組件之一GDI.exe其實也是一個動態庫。編寫動態串連庫的工具很多,如VisualC++、BorlandC++、Delphi等,具體方法可以參見相關文檔。下面只以Visual C++6.0為例,介紹一下開發應用於VisualBasic6.0的動態串連庫時應注意的問題(本文中所有涉及C/C++語言或編譯環境的地方,都以VC為例;所有涉及Visual Basic的地方都以VB 為例)。  作為一種32位Windows應用程式的開發工具,VB產生的exe檔案自然也都是32位的,通常情況下也只能調用32位的動態串連庫。但是,並不是所有的32位動態庫都能被VB產生的exe 檔案正確地識別。一般來說,自己編寫用於VB應用程式調用的動態串連庫時,應注意以下幾個方面的問題:  1、產生動態庫時要使用__stdcall呼叫慣例,而不能使用預設的__cdecl呼叫慣例;__stdcall 約定通常用於32位API函數的調用。  2、在VC中的定義檔案(.def)中,必須列出輸出函數的函數名,以強制VC系統將輸出函數的裝飾名(decoratedname)改成普通函數名;所謂裝飾名是VC的編譯器在編譯過程中產生的輸出函數名,它包含了使用者定義的函數名、函數參數及函數所在的類等多方面的資訊。由於在VC中定義檔案不是必需的,因此工程不包含定義檔案時VC就按自己的約定將使用者定義的輸出函數名修改成裝飾名後放到輸出函數列表中,這樣的輸出函數在VB產生的應用程式中是不能正確調用的(除非聲明時使用Alias子句)。因此需要增加一個.def檔案,其中列出使用者需要的函數名,以強制VC不按裝飾名進行輸出。  3、VC中的編譯選項"結構成員對齊(structure member alignment)" 應設成4位元組,其原因將在後文詳細介紹。  4、由於在C中整型變數是4個位元組,而VB中的整型變數依然只有2個位元組,因此在C中聲 明的整型(int)變數在VB中調用時要聲明為長整型(long),而C中的短整型(short)在VB中則 要聲明成整型(integer);下錶針對最常用的C語言資料類型列出了與之等價的Visual Basic 類型(用於32位版本的Windows)。C語言資料類型在VisualBasic中聲明為調用時使用的運算式   ATOM ByVal variable As Integer 結果為Integer 類型的運算式    BOOL ByVal variable As Long 結果為 Long 類型的運算式    BYTE ByVal variable As Byte 結果為 Byte 類型的運算式    CHAR ByVal variable As Byte 結果為 Byte 類型的運算式    COLORREF ByVal variable As Long 結果為 Long 類型的運算式    DWORD ByVal variable As Long 結果為 Long 類型的運算式    HWND, HDC, HMENU ByVal variable As Long 結果為 Long 類型的運算式等Windows 控制代碼    INT, UINT ByVal variable As Long 結果為 Long 類型的運算式    LONG ByVal variable As Long 結果為 Long 類型的運算式    LPARAM ByVal variable As Long 結果為 Long 類型的運算式    LPDWORD variable As Long 結果為 Long 類型的運算式    LPINT, LPUINT variable As Long 結果為 Long 類型的運算式    LPRECT variable As type 自訂類型的任意變數    LPSTR, LPCSTR ByVal variable As String 結果為 String 類型的運算式    LPVOID variable As Any 任何變數(在傳遞字串的時候使用ByVal)    LPWORD variable As Integer 結果為Integer 類型的運算式    LRESULT ByVal variable As Long 結果為 Long 類型的運算式    NULL As Any 或 ByVal Nothing 或    ByVal variable As Long ByVal 0& 或 VBNullString    SHORT ByVal variable As Integer 結果為Integer 類型的運算式    VOID Sub procedure 不可用    WORD ByVal variable As Integer 結果為Integer 類型的運算式    WPARAM ByVal variable As Long 結果為 Long 類型的運算式   5、VB中進行32位動態庫的聲明時,函數名是大小寫敏感的。在獲得了需要的動態串連 庫之後,就可以在VB中進行調用了。但是,由於VB不能驗證應用程式傳遞到動態串連庫中的參 數值是否正確,因此VB程式中大量的API調用可能會降低整個應用程式的穩定性,也會增加以 後維護的難度。所以,決定在VB程式中直接調用API函數時要謹慎,但適當的使用API調用確實 能夠有效地提高VB程式的效能。這之間的平衡需要編程人員根據實際情況來掌握。下面就具體介紹一下在VB中調用API函數時需要做的工作。  要聲明一個DLL過程,首先需要在代碼視窗的"通用(General)"部分增加一個Declare語句。如果該過程返回一個值,應將其聲明為Function:   Declare Function publicname Lib "libname" [Alias "alias"] [([[ByVal] variable [As type] [,[ByVal] variable [As type]]...])] As Type    如果過程沒有傳回值,可將其聲明為Sub:    Declare Sub publicname Lib "libname" [Alias "alias"] [([[ByVal] variable [As type] [,[ByVal] variable [As type]]...])]   預設情況下,在標準模組中聲明的DLL過程,可以在應用程式的任何地方調用它。在其它類型的模組中定義的DLL過程則是模組私人的,必須在它們前面聲明Private關鍵字,以示區分。下面分別介紹聲明語句的各個組成部分。   ( 一) 、指定動態庫:  Declare語句中的Lib子句用來告訴Visual Basic如何找到包含過程的.dll檔案。 如果引用的過程屬於Windows核心庫(User32、Kernel32或GDI32),則可以不包含副檔名,如:   Declare Function GetTickCount Lib "kernel32" Alias "GetTickCount" () As Long    對於其它動態串連庫,可以在Lib子句指定檔案的路徑:    Declare Function lzCopy Lib "c:/windows/lzexpand.dll" _    (ByVal S As Integer, ByVal D As Integer) As Long 如果未指定libname的路徑,Visual Basic將按照下列順序尋找該檔案:  ①.exe檔案所在的目錄  ②目前的目錄  ③Windows系統目錄  ④Windows目錄  ⑤Path環境變數中的目錄  下表中列出了常用的作業系統環境庫檔案。  動態連結程式庫描述  Advapi32.dll進階API服務,支援大量的API(其中包括許多安全與註冊方面的調用)   Comdlg32.dll通用對話方塊API庫  Gdi32.dll圖形裝置介面API庫  Kernel32.dllWindows32位核心的API支援  Lz32.dll32位壓縮常式  Mpr.dll多介面路由器庫  Netapi32.dll32位網路API庫  Shell32.dll32位ShellAPI庫  User32.dll使用者介面常式庫  Version.dll版本庫  Winmm.dllWindows多媒體庫  Winspool.drv後台列印介面,包含後台列印API調用。  對於Windows的系統API函數,可以利用VB提供的工具API Viewer尋找某一函數及其相 關資料結構和常數的聲明,並複製到自己的程式中。 ( 二) 、使用別名: A. 函數名是標準的名稱  Declare語句中的Alias子句是一個可選的部分,使用者可以通過它所標識的別名對動態 庫中的函數進行引用。例如,在下面的語句中,聲明了一個在VB中名為MyFunction的函數,而它在動態庫Mydll.dll中最初的名字是MyFunctionX。   Private Declare Function MyFunction Lib "Mydll.dll" _    Alias "MyFunctionX" ( ) As Long   需要注意的是,Alias子句中的函數名是大小寫敏感的,也就是說,必須與函數在產生時的聲明(如在C源檔案中的聲明)一致。這是因為32位動態庫與16位動態庫不同,其中的函數名是區分大小寫。同樣道理,如果沒有使用Alias子句,那麼在Function(或Sub)後的函數名也是區分大小寫。  通常在以下幾種情況時需要使用Alias子句:A.處理使用字串的系統Windows API過程  如果調用的系統Windows API過程要使用字串,那麼聲明語句中必須增加一個Alias 子句,以指定正確的字元集。包含字串的系統Windows API函數實際有兩種格式:ANSI和Unicode( 關於ANSI和Unicode兩種字元集的區別將在後面詳細闡述)。因此,在Windows標頭檔中,每個包含字串的函數都同時有ANSI版本和Unicode版本。例如,下面是SetWindowText函數 的兩種C語言描述。可以看到,第一個描述將函數定義為SetWindowTextA,尾部的"A" 表明它是一個ANSI函數:   WINUSERAPI BOOL WINAPI SetWindowTextA(HWND hWnd, LPCSTR lpString);   第二個描述將它定義為 SetWindowTextW, 尾部的"W" 表明它是一個 Unicode 函數:    WINUSERAPI BOOL WINAPI SetWindowTextW(HWND hWnd, LPCWSTR lpString);   因為兩個函數實際的名稱都不是"SetWindowText",要引用正確的函數就必 須增加一個Alias子句:Private Declare Function SetWindowText Lib "user32" _Alias "SetWindowTextA" (ByVal hwnd As Long, ByVal _lpString As String) As Long   應當注意,對於VB中使用的系統WindowsAPI函數,應該指定函數的ANSI版本,因為只 有WindowsNT才支援Unicode版本,而Windows95不支援這個版本。僅當應用程式只運行 在WindowsNT平台上的時候才可以使用Unicode版本。   B. 函數名是不標準的名稱  有時,個別的DLL過程的名稱不是有效標識符。例如,它可能包含了非法的字元(如連 字元),或者名稱是VB的關鍵字(如GetObject)。在這種情況下,可以使用Alias關鍵字。例 如,作業環境DLLs中的某些過程名以底線開始。儘管在VB標識符中允許使用標識符,但是底線不能作為標識符的第一個字元。為了使用這種過程,必須先聲明一個名稱合法的過程, 然後用Alias子句引用過程的真實名稱:Declare Function lopen Lib "kernel32" Alias "_lopen" _(ByVal lpPathName As String, ByVal iReadWrite _As Long) As Long   在上例中,lopen是VB中使用的過程名稱。而_lopen則是動態串連庫中可以識別的名 稱。    C. 使用序號標識DLL 過程  除了使用名稱之外,還可以使用序號來標識DLL過程。某些動態串連庫中不包含過程的名稱,在聲明它們包含的過程時必須使用序號。同使用名稱標識的DLL過程相比,如果使用序號,在最終的應用程式中消耗的記憶體將比較少,而且速度會快些。但是,一個具體的API的序號 在不同的作業系統中可能是不同的。例如GetWindowsDirectory在Win95下的序號為432,而在WindowsNT4.0下為338。總而言之,如果希望應用程式能夠在不同的作業系統下運行,那麼最好不要使用序號來標識API過程。如果過程不屬於API,或者應用程式使用的範圍很有 限,那麼使用序號還是有好處的。  要使用序號來聲明DLL過程,Alias子句中的字串需要包含過程的序號,並在序號的 前面加一個數字標記字元(#)。例如,Windowskernel中的GetWindowsDirectory函數的序 號為432;可以用下面的語句來聲明該DLL過程:Declare Function GetWindowsDirectory Lib "kernel32" _Alias "#432" (ByVal lpBuffer As String, _ByVal nSize As Long) As Long   在這裡,可以使用任意的合法名稱作為過程的名稱,VB將用序號在DLL中尋找過程。  為了得到要聲明的過程的序號,可以使用Dumpbin.exe等工具 + 生產力(Dumpbin.exe是Microsoft VisualC++提供的一個工具 + 生產力,它的使用說明可以參見VC的文檔)。利用Dumpbin,可以提取出.dll檔案中的各種資訊,例如DLL中的函數列表,它們的序號以及與代碼有關的其它資訊。   ( 三) 、使用值或引用傳遞  在預設的情況下,VB以引用方式傳遞所有參數(ByRef)。這意味著並沒有傳遞實際的參 數值,VB只傳遞了資料的32位地址。另外有許多DLL過程要求參數以值方式傳遞(ByVal)。這意味著它們需要實際的資料,而不是資料的記憶體位址。如果過程需要一個傳值參數,而傳遞給它的參數是一個指標,那麼由於得到了錯誤的資料,該過程將不能正確地工作。要使參數以使用值方式傳遞,在Declare語句中需要在參數聲明的前面加上ByVal關鍵字。例如InvertRect過程要求第一個參數用傳值方式傳遞,而第二個用引用方式傳遞:Declare Function InvertRect Lib "user32" Alias _"InvertRectA" (ByVal hdc As Long, lpRect As RECT) As Long   動態串連庫的參數傳遞是一個複雜的問題,也是VB中調用動態串連庫時最容易出現錯誤的地方。參數類型或傳遞方式的聲明錯誤都可能導致應用程式出現GPF(通用保護錯誤),甚至使作業系統崩潰,因此我們將在後面專門詳細地討論這個問題。   ( 四) 、靈活的參數類型  某些DLL過程的同一個參數能夠接受多種資料類型。如果需要傳遞多種類型的資料,可以將參數聲明為AsAny,從而取消類型限制。例如,下面的聲明中的第三個參數(lpptAsAny) 既可以傳遞一個POINT結構的數組,也可以傳遞一個RECT結構:Declare Function MapWindowPoints Lib "user32" Alias _"MapWindowPoints" (ByVal hwndFrom As Long, _ByVal hwndTo As Long, lppt As Any, _ByVal cPoints As Long) As Long  As Any子句提供了一定的靈活性,但是,由於它不進行任何的類型檢查,風險也隨之增加。因此在使用AsAny子句時,必須仔細檢查所有參數的類型。正確的函式宣告是在VB中調用動態串連庫的前提,但要想在VB中用對、用好動態庫中的 函數,僅僅有聲明還是遠遠不夠的。前面已經說過,由於VB不能驗證應用程式傳遞到動態串連 庫中的參數值是否正確,因此就要求程式員應對參數類型有非常詳細的瞭解,否則很容易引起應用程式發生通用保護錯或導致潛在的Bug,降低軟體的可靠性。下面將參數類型分為單一資料型別、字串、和使用者自訂類型三種分別進行討論。    (1) 、單一資料型別:  單一資料型別是指Numeric資料類型(包括Integer、Long、Single、Double、Currency類型)、Byte資料類型和Boolean資料類型。它們的共同的特點是結構簡單,作業系統在處理時不必進行特殊的轉換。  單一資料型別參數的傳遞比較簡單。我們知道,在VB中傳遞參數的方式有兩種:傳值(Byval) 和傳址(ByRef),預設的方式是傳址。所謂傳值,就是對一個變數的具體值進行傳遞;而傳址則 是傳遞變數的地址。例如,在VB程式中需要將一個整型變數m=10的值傳進動態庫,如果用傳值 方式,那麼傳進動態庫的值就是10,而在傳址方式下,傳入的則是變數m的地址,相當於C/C++ 中&m的值。需要注意的是,以傳值方式傳進動態串連庫的變數,其值在動態庫中是不能 被改變的;如果需要在動態串連庫中修改傳入參數的值,則必須使用傳址方式。一般來說,在VB 和動態串連庫之間傳遞單個的單一資料型別,只要注意了以上幾個方面就可以了。當需要將 一個單一資料型別的整個數組傳進動態庫時,必須將相應參數聲明為傳址方式,然後把數組 的第一個元素作為參數傳入,這樣在動態串連庫中就得到了數組的首地址,從而可以對整個數組進行訪問。例如,聲明了一個名為ReadArray的DLL過程,要求傳入一個整型數組aArray:Declare Function ReadArray Lib "mydll.dll" _(aArray As Integer) As Integer 在調用時可以採用如下方式:Dim ret,I(5) as Integer… …ret = ReadArray(I(0)) ' 將整個數組傳入動態串連庫 (2) 、字串參數的傳遞:  與單一資料型別相比,字串類型(String、String*n)的參數傳遞要複雜得多,這主要是Windows 95 API和VB使用的字串類型不同的緣故。VB使用被稱為BSTR的String資料類型,它是由自動化(以前被稱為OLE Automation)定義的資料類型。一個BSTR由頭部和字串組成,頭部包含了字串的長度資訊,字串中可以包含嵌入的null值。大部分的BSTR是 Unicode的,即每個字元需要兩個位元組。BSTR通常以兩位元組的兩個null字元結束。表示 了一個BSTR類型的字串。  (首碼)aTest/0  頭部BSTR指向資料的第一個位元組  另一方面,大部分的DLL過程(包括Windows 95 API中的所有過程)使用LPSTR類型字串,這是指向標準的以null結束的C語言字串的指標,它也被稱為ASCIIZ字串。LPSTR 沒有首碼。顯示了一個指向ASCIIZ字串的LPSTR。  aTest/0  LPSTR指向一個以null結尾的字串資料的第一個位元組  如果DLL過程需要一個LPSTR(指向以null結束的字串的指標)作為參數,可以在VB 中將一個字串以傳值的方式傳遞給它。因為指向BSTR的指標實際指向以null值結束的字串的第一個資料位元組,所以對於DLL過程來說,它就是一個LPSTR。這樣傳入動態串連庫的字串,DLL過程也可以對它進行修改,儘管它是以傳值方式傳入的。只有當DLL過程需要一個指向LPSTR的指標時,才以傳址的方式傳入字串,這時DLL過程得到的是一個指向字串指標的指標(相當於C/C++中的char**),而不是通常所用的字串的首地址(相當於C/C++中的char*)。  當需要把一個字串數組整個傳入動態串連庫時,情況就變得複雜多了,用傳遞單一資料型別數組的方式來傳遞字串數組是行不通的。當我們以傳值的方式將一個字串數組的第一個元素傳進動態串連庫時,DLL過程得到的實際上是該元素壓入堆棧段後的地址,而不是資料區段中整個數組的首地址。也就是說,這時DLL過程只能得到數組的第一個元素,而無法訪問整個數組。而以傳址方式傳入第一個元素時,DLL過程只能得到指向該元素在堆棧段中地址的指標,同樣無法訪問整個數組。這不能不說是VB的一個不足。因此,在程式設計中,如果確實需要將整個字串數組傳入動態庫,就必須採取其它方法。  我們知道,在VB中,有一種Byte資料類型。每個Byte型變數佔一個位元組,不含符號位,因 此所能表示的範圍為0到255。這種資料類型是專門用於存放位元據的。為了將整個字元 串數組傳進動態庫,可以用位元組數組來儲存字串。由於Byte是一種單一資料型別,因此位元組 數組的傳遞是非常簡單的。首先,需要把一個字串正確地轉變成一個位元組數組。這要涉及一 些字元集的知識。Windows 95和VB使用不同的字元集,Windows 95 API使用的是ANSI或DBCS 字元集,而VB使用的則是Unicode字元集。所謂ANSI字元集,是指每個字元都用一個位元組表示, 因此最多隻能有28=256個不同的字元,這對於英語來說已經足夠了,但不能完全支援其它語 言。DBCS字元集支援很多不同的東亞語言,如漢語、日語和朝鮮語,它使用數字0-255表示ASCII 字元,其它大於255或小於0的數字表明該字元屬於非拉丁字元集;在DBCS中,ASCII字元的長 度是一個位元組,而漢語、日語和其它東亞字元的長度是2個位元組。而Unicode字元集則完全用 兩個位元組表示一個字元,因此最多可以表示216=65536個不同字元。也就是說,ANSI字元集中 所有的字元都只佔一個位元組,DBCS字元集中ASCII字元佔一個位元組,漢字佔兩個位元組,Unicode 字元集中每個字元都佔兩個位元組。由於VB與WindowsAPI使用的字元集不同,因此在進行字元 串到位元組數組的轉換時,當用Asc函數取得一個字元的位元組碼後,需要判斷它是否是一個ASCII 字元;如果是ASCII字元,則在轉換後的位元組數組中就只佔一個位元組,否則要佔兩個位元組。  下面給出了轉換函式:GetChar Byte得到一個字元的高位元組或低位元組,它的第一個參數 是一個字元的ASCII碼,第二個參數是標誌取高位元組還是低位元組;StrToByte按DBCS或ANSI格 式將一個字串轉換成一個位元組數組,第一個參數是待轉換的字串,第二個參數是轉換後的一個定長位元組數組,若該數組長度不足以存放整個字串,則截去超長的部分;ChangeStrAryToByte 利用前兩個函數將字串數群組轉換成位元組數組,第一個參數是定長的字串數組,其中每個元素都是一個字串(各個元素包含的字元數可以不同),第二個參數是一個變長的位元組數組, 儲存轉換後的結果。  當轉換完成以後,查看位元組數組ResultAry,其中包含了21個元素,依次是:178,226,202,212,49,0,178,226,202,212,50,50,50,0,178,226,202,212,51,51,0。其中,[178,226]是"測"的位元組碼,[202,112]是"試"的位元組碼,49,50,51 分別為字元1、2、3的ASCII碼。可見,經過轉換後,字串數組中的各個元素按順序放在了位元組數組中,相互間以終止符0分隔。  這樣,字串數組就全部轉換成了位元組數組,然後只要將位元組數組的第一個元素以傳址的方式傳入動態串連庫,DLL過程就可以正確地訪問數組中的所有字串了。但是,使用這種方法,當DLL過程處理結束返回VB時,VB得到的仍然是位元組數組。如果需要在VB中再次得到該位元組數組表示的字串,還要把整個位元組數組重新以0為分割符分成多個子數組(每個子數組都對應原來字串數組中的一個元素),然後使用VB函數StrConv將每個子數群組轉換成字串(轉換時第二個參數選vbUnicode),就可以顯示或進行其它操作了。例如,其中一個子數組的名字是SubAry,則函數StrConv(SubAry,vbUnicode)就返回了它所對應的字串。  總之,VB應用程式和動態庫間字串參數的傳遞是一個比較複雜的過程,使用時要非常謹慎。同時應儘可能避免傳遞字串數群組類型的參數,因為這很容易引起下標越界、堆疊溢位等嚴重錯誤。 (3) 、使用者自訂類型(User-defined Type )參數的傳遞  使用者自訂類型在VB中是一種重要的資料類型,它為編程者提供了很大的靈活性,使開發人員可以根據需要構造自己的資料結構。它相當於C/C++中的結構類型(structure)。在VB中,允許程式員以傳址的方式將自訂資料類型參數傳入動態庫,DLL過程也可以將修改後的參數返回VB程式。但是,在VB中仍然不支援以傳值的方式傳遞使用者自訂型別參數。  傳遞使用者自訂型別參數時,必須確保VB中的資料類型的成員與動態庫中的結構成員是一一對應的,所佔空間也必須嚴格一致。這裡所說的一一對應,不僅是指VB 中的所有結構成員在動態庫的結構中都必須有對應的元素,而且它們在資料結構中定義的順序也必須嚴格一致,這是VB中使用的"資料結構成員對齊"決定的。在VB 中,資料結構使用雙字對齊(4-byte alignment),因此,在使用者自己產生用於VB 調用的動態串連庫時,也必須把編譯選項"structure member alignment" 設為4位元組(如前文所述)。  所謂結構成員對齊是指一個資料結構內部,其成員的相片順序。譬如,在VB中,其對齊是4位元組,這就好象在一個資料結構內部分成了很多個4位元組大小的小單元,如果相鄰 兩個或多個資料成員的大小可以放在一個單元中,那麼就放在一起;否則這些小單元中可能 會出現未用的空位元組。我們來看下面一個資料類型:Type TestTypem1 as Integerm2 as Bytem3 as LongEnd Type   它的三個成員的大小加起來是2+1+4=7。但是,由於m1和m2的位元組總長度是3,小於4,它 們就存放於一個單元中;但該單元剩下的一個位元組不足以放下一個Long型的成員m3,於是m3 就被放在下一個單元中,它們之間就有了一個未用的空位元組;因此,整個結構所佔實際長度是8 位元組。同理,如果將m3和m2的位置交換一下,它所佔的尺寸就變成了9位元組。可見,成員在結構 中的聲明順序也是非常重要的。  通常,當一個使用者自訂類型中不包含字串時,向動態串連庫中傳遞該類型的參數是沒有什麼問題的。如果只傳遞一個自訂類型變數,則既可以傳遞該變數名,也可以傳遞該變 量 的第一個成員,它們的效果是一樣的,都是將該變數的地址傳進了動態庫;同樣,如果要傳遞一個自訂類型的數組,則既可以傳遞該數組的第一個元素,也可以傳 遞第一個元素的第一個成員。但是,如果使用者自訂類型中包含字串類型時,又該如何與動態串連庫傳遞參數呢?答案是令人遺憾的:在VB中,你無法將一個包含字串成員的使用者自訂類型變數或數 組 安全、正確地傳入動態庫中。如果你這樣做了,即使某次僥倖得到了正確的結果,在其背後也隱藏著許多致命的危險。因此,如果一定要在使用者自訂類型中包含字 符串變數,並且該類型的變數又要作為參數傳入動態庫時,你最好修改類型定義,把其中的字串成員用相應的位元組數群組類型替換掉(轉換方法可參見前文),這樣 就可以在VB 和動態庫間傳遞這種類型的參數了。  另外,在VB 中還可以把一個函數的指標傳遞到動態庫中,方法也並不複雜。但筆者強烈建議最好不要這麼做,因為這樣一來VB 應用程式就幾乎完全喪失了它所應有的安全性。如果 確實需要傳遞函數指標的話,那麼還是編一個C/C++ 的程式來完成這項工作吧。總之,在VB中調用DLL過程是一個比較複雜的問題,編程人員必須很好地把握,才能達到既提高了程式效率,開拓了程式功能,又不降低程式安全性的目的。另外需要特別指出的一點是,在本文中提到的所有動態串連庫,都是指沒有使用自動化(OLE Automation)技術的動態庫,Windows API和大多數使用者自編的動態串連庫都是這種類型的。對於使用了OLE Automation技術的動態串連庫,其參數傳遞的方式有所不同,讀者可以參閱有關OLE 技術的書籍,在此不再涉及。

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.