九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
在VB 中調(diào)用動(dòng)態(tài)連接庫

作 為 一 種 簡(jiǎn) 單 易 用 的Windows 開 發(fā) 環(huán) 境,Visual Basic 從 一 推 出 就 受 到 了 廣 大 編 程 人 員 的 歡 迎。 它 使 程 序 員 不 必 再 直 接 面 對(duì) 紛 繁 復(fù) 雜 的Windows 消 息, 而 可 以 將 精 力 主 要 集 中 在 程 序 功 能 的 實(shí) 現(xiàn) 上, 大 大 提 高 了 編 程 效 率。 但 凡 事 有 利 必 有 弊。VB 中 高 度 的 封 裝 和 模 塊 化 減 輕 了 編 程 者 的 負(fù) 擔(dān), 同 時(shí) 也 使 開 發(fā) 人 員 失 去 了 許 多 訪 問 低 層API 函 數(shù) 和 直 接 與Windows 交 互 的 機(jī) 會(huì)。 因 此, 相 比 而 言,VB 應(yīng) 用 程 序 的 執(zhí) 行 效 率 和 功 能 比C/C++ 或Delphi 生 成 的 程 序 要 差。 為 了 解 決 這 個(gè) 問 題, 在 一 個(gè) 大 型 的VB 開 發(fā) 應(yīng) 用 中, 直 接 調(diào) 用Windows API 函 數(shù) 幾 乎 是 不 可 避 免 的; 同 時(shí), 還 有 可 能 需 要 程 序 員 自 己 用C/C++ 等 開 發(fā) 一 些 動(dòng) 態(tài) 連 接 庫, 用 于 在VB 中 調(diào) 用。 本 文 主 要 討 論 在32 位 開 發(fā) 環(huán) 境Visual Basic 5.0 中 直 接 調(diào) 用Windows 95 API 函 數(shù) 或 用 戶 生 成 的32 位 動(dòng) 態(tài) 連 接 庫 的 方 法 與 規(guī) 則。

---- Windows 動(dòng) 態(tài) 連 接 庫 是 包 含 數(shù) 據(jù) 和 函 數(shù) 的 模 塊, 可 以 被 其 它 可 執(zhí) 行 文 件(EXE、DLL、OCX 等) 調(diào) 用。 動(dòng) 態(tài) 連 接 庫 包 含 兩 種 函 數(shù): 輸 出(exported) 函 數(shù) 和 內(nèi) 部(internal) 函 數(shù)。 輸 出 函 數(shù) 可 以 被 其 它 模 塊 調(diào) 用, 而 內(nèi) 部 函 數(shù) 則 只 能 在 動(dòng) 態(tài) 連 接 庫 內(nèi) 部 使 用。 盡 管 動(dòng) 態(tài) 連 接 庫 也 能 輸 出 數(shù) 據(jù), 但 實(shí) 際 上 它 的 數(shù) 據(jù) 通 常 是 只 在 內(nèi) 部 使 用 的。 使 用 動(dòng) 態(tài) 連 接 庫 的 優(yōu) 點(diǎn) 是 顯 而 易 見 的。 將 應(yīng) 用 程 序 的 一 部 分 功 能 提 取 出 來 做 成 動(dòng) 態(tài) 連 接 庫, 不 但 減 小 了 主 應(yīng) 用 程 序 的 大 小, 提 高 了 程 序 運(yùn) 行 效 率, 還 使 它 更 加 易 于 升 級(jí)。 多 個(gè) 應(yīng) 用 程 序 共 享 一 個(gè) 動(dòng) 態(tài) 連 接 庫 還 能 有 效 地 節(jié) 省 系 統(tǒng) 資 源。 正 因 為 如 此, 在Windows 系 統(tǒng) 中, 動(dòng) 態(tài) 連 接 庫 得 到 了 大 量 的 使 用。

---- 一 般 來 說, 動(dòng) 態(tài) 連 接 庫 都 是 以DLL 為 擴(kuò) 展 名 的 文 件, 如Kernel32.dll 、commdlg.dll 等。 但 也 有 例 外, 如16 位Windows 的 核 心 部 件 之 一GDI.exe 其 實(shí) 也 是 一 個(gè) 動(dòng) 態(tài) 庫。 編 寫 動(dòng) 態(tài) 連 接 庫 的 工 具 很 多, 如Visual C++、Borland C++、Delphi 等, 具 體 方 法 可 以 參 見 相 關(guān) 文 檔。 下 面 只 以Visual C++ 5.0 為 例, 介 紹 一 下 開 發(fā) 應(yīng) 用 于Visual Basic 5.0 的 動(dòng) 態(tài) 連 接 庫 時(shí) 應(yīng) 注 意 的 問 題( 本 文 中 所 有 涉 及C/C++ 語 言 或 編 譯 環(huán) 境 的 地 方, 都 以VC5 為 例; 所 有 涉 及Visual Basic 的 地 方 都 以VB5 為 例)。

---- 作 為 一 種32 位Windows 應(yīng) 用 程 序 的 開 發(fā) 工 具,VB5 生 成 的exe 文 件 自 然 也 都 是32 位 的, 通 常 情 況 下 也 只 能 調(diào) 用32 位 的 動(dòng) 態(tài) 連 接 庫。 但 是, 并 不 是 所 有 的32 位 動(dòng) 態(tài) 庫 都 能 被VB 生 成 的exe 文 件 正 確 地 識(shí) 別。 一 般 來 說, 自 己 編 寫 用 于VB 應(yīng) 用 程 序 調(diào) 用 的 動(dòng) 態(tài) 連 接 庫 時(shí), 應(yīng) 注 意 以 下 幾 個(gè) 方 面 的 問 題:

---- 1、 生 成 動(dòng) 態(tài) 庫 時(shí) 要 使 用__stdcall 調(diào) 用 約 定, 而 不 能 使 用 缺 省 的__cdecl 調(diào) 用 約 定;__stdcall 約 定 通 常 用 于32 位API 函 數(shù) 的 調(diào) 用。

---- 2、 在VC5 中 的 定 義 文 件(.def) 中, 必 須 列 出 輸 出 函 數(shù) 的 函 數(shù) 名, 以 強(qiáng) 制VC5 系 統(tǒng) 將 輸 出 函 數(shù) 的 裝 飾 名(decorated name) 改 成 普 通 函 數(shù) 名; 所 謂 裝 飾 名 是VC 的 編 譯 器 在 編 譯 過 程 中 生 成 的 輸 出 函 數(shù) 名, 它 包 含 了 用 戶 定 義 的 函 數(shù) 名、 函 數(shù) 參 數(shù) 及 函 數(shù) 所 在 的 類 等 多 方 面 的 信 息。 由 于 在VC5 中 定 義 文 件 不 是 必 需 的, 因 此 工 程 不 包 含 定 義 文 件 時(shí)VC5 就 按 自 己 的 約 定 將 用 戶 定 義 的 輸 出 函 數(shù) 名 修 改 成 裝 飾 名 后 放 到 輸 出 函 數(shù) 列 表 中, 這 樣 的 輸 出 函 數(shù) 在VB 生 成 的 應(yīng) 用 程 序 中 是 不 能 正 確 調(diào) 用 的( 除 非 聲 明 時(shí) 使 用Alias 子 句)。 因 此 需 要 增 加 一 個(gè).def 文 件, 其 中 列 出 用 戶 需 要 的 函 數(shù) 名, 以 強(qiáng) 制VC5 不 按 裝 飾 名 進(jìn) 行 輸 出。

---- 3、VC5 中 的 編 譯 選 項(xiàng)" 結(jié) 構(gòu) 成 員 對(duì) 齊 方 式(structure member alignment)" 應(yīng) 設(shè) 成4 字 節(jié), 其 原 因 將 在 后 文 詳 細(xì) 介 紹。

---- 4、 由 于 在C 中 整 型 變 量 是4 個(gè) 字 節(jié), 而VB 中 的 整 型 變 量 依 然 只 有2 個(gè) 字 節(jié), 因 此 在C 中 聲 明 的 整 型(int) 變 量 在VB 中 調(diào) 用 時(shí) 要 聲 明 為 長(zhǎng) 整 型(long), 而C 中 的 短 整 型(short) 在VB 中 則 要 聲 明 成 整 型(integer); 下 表 針 對(duì) 最 常 用 的 C 語 言 數(shù) 據(jù) 類 型 列 出 了 與 之 等 價(jià) 的 Visual Basic 類 型( 用 于 32 位 版 本 的 Windows)。

---- C 語 言 數(shù) 據(jù) 類 型 在Visual Basic 中 聲 明 為 調(diào) 用 時(shí) 使 用 的 表 達(dá) 式

---- ATOM ByVal variable As Integer 結(jié) 果 為Integer 類 型 的 表 達(dá) 式

---- BOOL ByVal variable As Long 結(jié) 果 為 Long 類 型 的 表 達(dá) 式

---- BYTE ByVal variable As Byte 結(jié) 果 為 Byte 類 型 的 表 達(dá) 式

---- CHAR ByVal variable As Byte 結(jié) 果 為 Byte 類 型 的 表 達(dá) 式

---- COLORREF ByVal variable As Long 結(jié) 果 為 Long 類 型 的 表 達(dá) 式

---- DWORD ByVal variable As Long 結(jié) 果 為 Long 類 型 的 表 達(dá) 式

---- HWND, HDC, HMENU ByVal variable As Long 結(jié) 果 為 Long 類 型 的 表 達(dá) 式 等Windows 句 柄

---- INT, UINT ByVal variable As Long 結(jié) 果 為 Long 類 型 的 表 達(dá) 式

---- LONG ByVal variable As Long 結(jié) 果 為 Long 類 型 的 表 達(dá) 式

---- LPARAM ByVal variable As Long 結(jié) 果 為 Long 類 型 的 表 達(dá) 式

---- LPDWORD variable As Long 結(jié) 果 為 Long 類 型 的 表 達(dá) 式

---- LPINT, LPUINT variable As Long 結(jié) 果 為 Long 類 型 的 表 達(dá) 式

---- LPRECT variable As type 自 定 義 類 型 的 任 意 變 量

---- LPSTR, LPCSTR ByVal variable As String 結(jié) 果 為 String 類 型 的 表 達(dá) 式

---- LPVOID variable As Any 任 何 變 量( 在 傳 遞 字 符 串 的 時(shí) 候 使 用ByVal)

---- LPWORD variable As Integer 結(jié) 果 為Integer 類 型 的 表 達(dá) 式

---- LRESULT ByVal variable As Long 結(jié) 果 為 Long 類 型 的 表 達(dá) 式

---- NULL As Any 或 ByVal Nothing 或

---- ByVal variable As Long ByVal 0& 或 VBNullString

---- SHORT ByVal variable As Integer 結(jié) 果 為Integer 類 型 的 表 達(dá) 式

---- VOID Sub procedure 不 可 用

---- WORD ByVal variable As Integer 結(jié) 果 為Integer 類 型 的 表 達(dá) 式

---- WPARAM ByVal variable As Long 結(jié) 果 為 Long 類 型 的 表 達(dá) 式

---- 5、VB 中 進(jìn) 行32 位 動(dòng) 態(tài) 庫 的 聲 明 時(shí), 函 數(shù) 名 是 大 小 寫 敏 感 的。 在 獲 得 了 需 要 的 動(dòng) 態(tài) 連 接 庫 之 后, 就 可 以 在VB 中 進(jìn) 行 調(diào) 用 了。 但 是, 由 于VB 不 能 驗(yàn) 證 應(yīng) 用 程 序 傳 遞 到 動(dòng) 態(tài) 連 接 庫 中 的 參 數(shù) 值 是 否 正 確, 因 此VB 程 序 中 大 量 的API 調(diào) 用 可 能 會(huì) 降 低 整 個(gè) 應(yīng) 用 程 序 的 穩(wěn) 定 性, 也 會(huì) 增 加 以 后 維 護(hù) 的 難 度。 所 以, 決 定 在VB 程 序 中 直 接 調(diào) 用API 函 數(shù) 時(shí) 要 慎 重, 但 適 當(dāng) 的 使 用API 調(diào) 用 確 實(shí) 能 夠 有 效 地 提 高VB 程 序 的 性 能。 這 之 間 的 平 衡 需 要 編 程 人 員 根 據(jù) 實(shí) 際 情 況 來 掌 握。 下 面 就 具 體 介 紹 一 下 在VB 中 調(diào) 用API 函 數(shù) 時(shí) 需 要 做 的 工 作。

---- 要 聲 明 一 個(gè)DLL 過 程, 首 先 需 要 在 代 碼 窗 口 的" 通 用(General)" 部 分 增 加 一 個(gè)Declare 語 句。 如 果 該 過 程 返 回 一 個(gè) 值, 應(yīng) 將 其 聲 明 為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]]...])]

---- 缺 省 情 況 下, 在 標(biāo) 準(zhǔn) 模 塊 中 聲 明 的DLL 過 程, 可 以 在 應(yīng) 用 程 序 的 任 何 地 方 調(diào) 用 它。 在 其 它 類 型 的 模 塊 中 定 義 的DLL 過 程 則 是 模 塊 私 有 的, 必 須 在 它 們 前 面 聲 明Private 關(guān) 鍵 字, 以 示 區(qū) 分。 下 面 分 別 介 紹 聲 明 語 句 的 各 個(gè) 組 成 部 分。

---- 1、 指 定 動(dòng) 態(tài) 庫:

---- Declare 語 句 中 的 Lib 子 句 用 來 告 訴 Visual Basic 如 何 找 到 包 含 過 程 的 .dll 文 件。 如 果 引 用 的 過 程 屬 于 Windows 核 心 庫(User32、Kernel32 或 GDI32), 則 可 以 不 包 含 文 件 擴(kuò) 展 名, 如:

---- Declare Function GetTickCount Lib "kernel32" Alias "GetTickCount" () As Long

---- 對(duì) 于 其 它 動(dòng) 態(tài) 連 接 庫, 可 以 在Lib 子 句 指 定 文 件 的 路 徑:

---- Declare Function lzCopy Lib "c:windowslzexpand.dll" _

---- (ByVal S As Integer, ByVal D As Integer) As Long

---- 如 果 未 指 定 libname 的 路 徑,Visual Basic 將 按 照 下 列 順 序 查 找 該 文 件:

---- ①.exe 文 件 所 在 的 目 錄

---- ② 當(dāng) 前 目 錄

---- ③Windows 系 統(tǒng) 目 錄

---- ④Windows 目 錄

---- ⑤Path 環(huán) 境 變 量 中 的 目 錄

---- 下 表 中 列 出 了 常 用 的 操 作 系 統(tǒng) 環(huán) 境 庫 文 件。

---- 動(dòng) 態(tài) 鏈 接 庫 描 述

---- Advapi32.dll 高 級(jí) API 服 務(wù), 支 持 大 量 的 API( 其 中 包 括 許 多 安 全 與 注 冊(cè) 方 面 的 調(diào) 用)

---- Comdlg32.dll 通 用 對(duì) 話 框 API 庫

---- Gdi32.dll 圖 形 設(shè) 備 接 口 API 庫

---- Kernel32.dll Windows 32 位 核 心 的 API 支 持

---- Lz32.dll 32 位 壓 縮 例 程

---- Mpr.dll 多 接 口 路 由 器 庫

---- Netapi32.dll 32 位 網(wǎng) 絡(luò) API 庫

---- Shell32.dll 32 位 Shell API 庫

---- User32.dll 用 戶 接 口 例 程 庫

---- Version.dll 版 本 庫

---- Winmm.dll Windows 多 媒 體 庫

---- Winspool.drv 后 臺(tái) 打 印 接 口, 包 含 后 臺(tái) 打 印 API 調(diào) 用。

---- 對(duì) 于Windows 的 系 統(tǒng)API 函 數(shù), 可 以 利 用VB 提 供 的 工 具API Viewer 查 找 某 一 函 數(shù) 及 其 相 關(guān) 數(shù) 據(jù) 結(jié) 構(gòu) 和 常 數(shù) 的 聲 明, 并 復(fù) 制 到 自 己 的 程 序 中。

---- 2、 使 用 別 名:

---- Declare 語 句 中 的Alias 子 句 是 一 個(gè) 可 選 的 部 分, 用 戶 可 以 通 過 它 所 標(biāo) 識(shí) 的 別 名 對(duì) 動(dòng) 態(tài) 庫 中 的 函 數(shù) 進(jìn) 行 引 用。 例 如, 在 下 面 的 語 句 中, 聲 明 了 一 個(gè) 在VB 中 名 為MyFunction 的 函 數(shù), 而 它 在 動(dòng) 態(tài) 庫Mydll.dll 中 最 初 的 名 字 是MyFunctionX。

---- Private Declare Function MyFunction Lib "Mydll.dll" _

---- Alias "MyFunctionX" ( ) As Long

---- 需 要 注 意 的 是,Alias 子 句 中 的 函 數(shù) 名 是 大 小 寫 敏 感 的, 也 就 是 說, 必 須 與 函 數(shù) 在 生 成 時(shí) 的 聲 明( 如 在C 源 文 件 中 的 聲 明) 一 致。 這 是 因 為32 位 動(dòng) 態(tài) 庫 與16 位 動(dòng) 態(tài) 庫 不 同, 其 中 的 函 數(shù) 名 是 區(qū) 分 大 小 寫 的。 同 樣 道 理, 如 果 沒 有 使 用Alias 子 句, 那 么 在Function( 或Sub) 后 的 函 數(shù) 名 也 是 區(qū) 分 大 小 寫 的。

---- 通 常 在 以 下 幾 種 情 況 時(shí) 需 要 使 用Alias 子 句:

---- A. 處 理 使 用 字 符 串 的 系 統(tǒng) Windows API 過 程

---- 如 果 調(diào) 用 的 系 統(tǒng) Windows API 過 程 要 使 用 字 符 串, 那 么 聲 明 語 句中 必 須 增 加 一 個(gè) Alias 子 句, 以 指 定 正 確 的 字 符 集。 包 含 字 符 串 的 系 統(tǒng) Windows API 函 數(shù) 實(shí) 際 有 兩 種 格 式:ANSI 和 Unicode( 關(guān) 于ANSI 和 Unicode 兩 種 字 符 集 的 區(qū) 別 將 在 后 面 詳 細(xì) 闡 述)。 因 此, 在 Windows 頭 文 件 中, 每 個(gè) 包 含 字 符 串 的 函 數(shù) 都 同 時(shí) 有 ANSI 版 本 和 Unicode 版 本。 例 如, 下 面 是 SetWindowText 函 數(shù) 的 兩 種 C 語 言 描 述。 可 以 看 到, 第 一 個(gè) 描 述 將 函 數(shù) 定 義 為 SetWindowTextA, 尾 部 的"A" 表 明 它 是 一 個(gè) ANSI 函 數(shù):

---- WINUSERAPI BOOL WINAPI SetWindowTextA(HWND hWnd, LPCSTR lpString);

---- 第 二 個(gè) 描 述 將 它 定 義 為 SetWindowTextW, 尾 部 的"W" 表 明 它 是 一 個(gè) Unicode 函 數(shù):

---- WINUSERAPI BOOL WINAPI SetWindowTextW(HWND hWnd, LPCWSTR lpString);

---- 因 為 兩 個(gè) 函 數(shù) 實(shí) 際 的 名 稱 都 不 是"SetWindowText", 要 引 用 正 確 的 函 數(shù) 就 必 須 增 加 一 個(gè) Alias 子 句:

Private Declare Function SetWindowText Lib "user32" _
Alias "SetWindowTextA" (ByVal hwnd As Long, ByVal _
lpString As String) As Long

---- 應(yīng) 當(dāng) 注 意, 對(duì) 于VB 中 使 用 的 系 統(tǒng)Windows API 函 數(shù), 應(yīng) 該 指 定 函 數(shù) 的 ANSI 版 本, 因 為 只 有 Windows NT 才 支 持 Unicode 版 本, 而 Windows 95 不 支 持 這 個(gè) 版 本。 僅 當(dāng) 應(yīng) 用 程 序 只 運(yùn) 行 在 Windows NT 平 臺(tái) 上 的 時(shí) 候 才 可 以 使 用 Unicode 版 本。

---- B. 函 數(shù) 名 是 不 標(biāo) 準(zhǔn) 的 名 稱

---- 有 時(shí), 個(gè) 別 的 DLL 過 程 的 名 稱 不 是 有 效 的 標(biāo) 識(shí) 符。 例 如, 它 可 能 包 含 了 非 法 的 字 符( 如 連 字 符), 或 者 名 稱 是 VB 的 關(guān) 鍵 字( 如 GetObject)。 在 這 種 情 況 下, 可 以 使 用 Alias 關(guān) 鍵 字。 例 如, 操 作 環(huán) 境 DLLs 中 的 某 些 過 程 名 以 下 劃 線 開 始。 盡 管 在 VB 標(biāo) 識(shí) 符 中 允 許 使 用 標(biāo) 識(shí) 符, 但 是 下 劃 線 不 能 作 為 標(biāo) 識(shí) 符 的 第 一 個(gè) 字 符。 為 了 使 用 這 種 過 程, 必 須 先 聲 明 一 個(gè) 名 稱 合 法 的 過 程, 然 后 用 Alias 子 句 引 用 過 程 的 真 實(shí) 名 稱:

Declare Function lopen Lib "kernel32" Alias "_lopen" _
(ByVal lpPathName As String, ByVal iReadWrite _
As Long) As Long

---- 在 上 例 中,lopen 是 VB 中 使 用 的 過 程 名 稱。 而 _lopen 則 是 動(dòng) 態(tài) 連 接 庫 中 可 以 識(shí) 別 的 名 稱。

---- C. 使 用 序 號(hào) 標(biāo) 識(shí) DLL 過 程

---- 除 了 使 用 名 稱 之 外, 還 可 以 使 用 序 號(hào) 來 標(biāo) 識(shí) DLL 過 程。 某 些 動(dòng) 態(tài) 連 接 庫 中 不 包 含 過 程 的 名 稱, 在 聲 明 它 們 包 含 的 過 程 時(shí) 必 須 使 用 序 號(hào)。 同 使 用 名 稱 標(biāo) 識(shí) 的DLL 過 程 相 比, 如 果 使 用 序 號(hào), 在 最 終 的 應(yīng) 用 程 序 中 消 耗 的 內(nèi) 存 將 比 較 少, 而 且 速 度 會(huì) 快 些。 但 是, 一 個(gè) 具 體 的API 的 序 號(hào) 在 不 同 的 操 作 系 統(tǒng) 中 可 能 是 不 同 的。 例 如 GetWindowsDirectory 在 Win95 下 的 序 號(hào) 為 432, 而 在 Windows NT 4.0 下 為 338。 總 而 言 之, 如 果 希 望 應(yīng) 用 程 序 能 夠 在 不 同 的 操 作 系 統(tǒng) 下 運(yùn) 行, 那 么 最 好 不 要 使 用 序 號(hào) 來 標(biāo) 識(shí) API 過 程。 如 果 過 程 不 屬 于API, 或 者 應(yīng) 用 程 序 使 用 的 范 圍 很 有 限, 那 么 使 用 序 號(hào) 還 是 有 好 處 的。

---- 要 使 用 序 號(hào) 來 聲 明 DLL 過 程,Alias 子 句 中 的 字 符 串 需 要 包 含 過 程 的 序 號(hào), 并 在 序 號(hào) 的 前 面 加 一 個(gè) 數(shù) 字 標(biāo) 記 字 符 (#)。 例 如,Windows kernel 中 的 GetWindowsDirectory 函 數(shù) 的 序 號(hào) 為 432; 可 以 用 下 面 的 語 句 來 聲 明 該 DLL 過 程:

Declare Function GetWindowsDirectory Lib "kernel32" _
Alias "#432" (ByVal lpBuffer As String, _
ByVal nSize As Long) As Long

---- 在 這 里, 可 以 使 用 任 意 的 合 法 名 稱 作 為 過 程 的 名 稱,VB 將 用 序 號(hào) 在 DLL 中 尋 找 過 程。

---- 為 了 得 到 要 聲 明 的 過 程 的 序 號(hào), 可 以 使 用 Dumpbin.exe 等 實(shí) 用 工 具(Dumpbin.exe 是 Microsoft Visual C++ 提 供 的 一 個(gè) 實(shí) 用 工 具, 它 的 使 用 說 明 可 以 參 見VC 的 文 檔)。 利 用 Dumpbin, 可 以 提 取 出 .dll 文 件 中 的 各 種 信 息, 例 如 DLL 中 的 函 數(shù) 列 表, 它 們 的 序 號(hào) 以 及 與 代 碼 有 關(guān) 的 其 它 信 息。

---- 3、 使 用 值 或 引 用 傳 遞

---- 在 缺 省 的 情 況 下,VB 以 引 用 方 式 傳 遞 所 有 參 數(shù)(ByRef)。 這 意 味 著 并 沒 有 傳 遞 實(shí) 際 的 參 數(shù) 值,VB 只 傳 遞 了 數(shù) 據(jù) 的 32 位 地 址。 另 外 有 許 多 DLL 過 程 要 求 參 數(shù) 以 值 方 式 傳 遞(ByVal)。 這 意 味 著 它 們 需 要 實(shí) 際 的 數(shù) 據(jù), 而 不 是 數(shù) 據(jù) 的 內(nèi) 存 地 址。 如 果 過 程 需 要 一 個(gè) 傳 值 參 數(shù), 而 傳 遞 給 它 的 參 數(shù) 是 一 個(gè) 指 針, 那 么 由 于 得 到 了 錯(cuò) 誤 的 數(shù) 據(jù), 該 過 程 將 不 能 正 確 地 工 作。

---- 要 使 參 數(shù) 以 使 用 值 方 式 傳 遞, 在 Declare 語 句 中 需 要 在 參 數(shù) 聲 明 的 前 面 加 上 ByVal 關(guān) 鍵 字。 例 如InvertRect 過 程 要 求 第 一 個(gè) 參 數(shù) 用 傳 值 方 式 傳 遞, 而 第 二 個(gè) 用 引 用 方 式 傳 遞:

Declare Function InvertRect Lib "user32" Alias _
"InvertRectA" (ByVal hdc As Long, lpRect As RECT) As Long

---- 動(dòng) 態(tài) 連 接 庫 的 參 數(shù) 傳 遞 是 一 個(gè) 復(fù) 雜 的 問 題, 也 是VB 中 調(diào) 用 動(dòng) 態(tài) 連 接 庫 時(shí) 最 容 易 出 現(xiàn) 錯(cuò) 誤 的 地 方。 參 數(shù) 類 型 或 傳 遞 方 式 的 聲 明 錯(cuò) 誤 都 可 能 導(dǎo) 致 應(yīng) 用 程 序 出 現(xiàn)GPF( 通 用 保 護(hù) 錯(cuò) 誤), 甚 至 使 操 作 系 統(tǒng) 崩 潰, 因 此 我 們 將 在 后 面 專 門 詳 細(xì) 地 討 論 這 個(gè) 問 題。

---- 4、 靈 活 的 參 數(shù) 類 型

---- 某 些 DLL 過 程 的 同 一 個(gè) 參 數(shù) 能 夠 接 受 多 種 數(shù) 據(jù) 類 型。 如 果 需 要 傳 遞 多 種 類 型 的 數(shù) 據(jù), 可 以 將 參 數(shù) 聲 明 為 As Any, 從 而 取 消 類 型 限 制。 例 如, 下 面 的 聲 明 中 的 第 三 個(gè) 參 數(shù) (lppt As Any) 既 可 以 傳 遞 一 個(gè) POINT 結(jié) 構(gòu) 的 數(shù) 組, 也 可 以 傳 遞 一 個(gè) RECT 結(jié) 構(gòu):

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 子 句 提 供 了 一 定 的 靈 活 性, 但 是, 由 于 它 不 進(jìn) 行 任 何 的 類 型 檢 查, 風(fēng) 險(xiǎn) 也 隨 之 增 加。 因 此 在 使 用 As Any 子 句 時(shí), 必 須 仔 細(xì) 檢 查 所 有 參 數(shù) 的 類 型。

---- 正 確 的 函 數(shù) 聲 明 是 在VB 中 調(diào) 用 動(dòng) 態(tài) 連 接 庫 的 前 提, 但 要 想 在VB 中 用 對(duì)、 用 好 動(dòng) 態(tài) 庫 中 的 函 數(shù), 僅 僅 有 聲 明 還 是 遠(yuǎn) 遠(yuǎn) 不 夠 的。 前 面 已 經(jīng) 說 過, 由 于VB 不 能 驗(yàn) 證 應(yīng) 用 程 序 傳 遞 到 動(dòng) 態(tài) 連 接 庫 中 的 參 數(shù) 值 是 否 正 確, 因 此 就 要 求 程 序 員 應(yīng) 對(duì) 參 數(shù) 類 型 有 非 常 詳 細(xì) 的 了 解, 否 則 很 容 易 引 起 應(yīng) 用 程 序 發(fā) 生 通 用 保 護(hù) 錯(cuò) 或 導(dǎo) 致 潛 在 的Bug, 降 低 軟 件 的 可 靠 性。 下 面 將 參 數(shù) 類 型 分 為 簡(jiǎn) 單 數(shù) 據(jù) 類 型、 字 符 串、 和 用 戶 自 定 義 類 型 三 種 分 別 進(jìn) 行 討 論。

---- 1、 簡(jiǎn) 單 數(shù) 據(jù) 類 型:

---- 簡(jiǎn) 單 數(shù) 據(jù) 類 型 是 指Numeric 數(shù) 據(jù) 類 型( 包 括Integer、Long、Single、Double、Currency 類 型)、Byte 數(shù) 據(jù) 類 型 和Boolean 數(shù) 據(jù) 類 型。 它 們 的 共 同 的 特 點(diǎn) 是 結(jié) 構(gòu) 簡(jiǎn) 單, 操 作 系 統(tǒng) 在 處 理 時(shí) 不 必 進(jìn) 行 特 殊 的 轉(zhuǎn) 換。

---- 簡(jiǎn) 單 數(shù) 據(jù) 類 型 參 數(shù) 的 傳 遞 比 較 簡(jiǎn) 單。 我 們 知 道, 在VB 中 傳 遞 參 數(shù) 的 方 式 有 兩 種: 傳 值(Byval) 和 傳 址(ByRef), 缺 省 的 方 式 是 傳 址。 所 謂 傳 值, 就 是 對(duì) 一 個(gè) 變 量 的 具 體 值 進(jìn) 行 傳 遞; 而 傳 址 則 是 傳 遞 變 量 的 地 址。 例 如, 在VB 程 序 中 需 要 將 一 個(gè) 整 型 變 量m=10 的 值 傳 進(jìn) 動(dòng) 態(tài) 庫, 如 果 用 傳 值 方 式, 那 么 傳 進(jìn) 動(dòng) 態(tài) 庫 的 值 就 是10, 而 在 傳 址 方 式 下, 傳 入 的 則 是 變 量 m 的 地 址, 相 當(dāng) 于C/C++ 中 &m 的 值。 需 要 注 意 的 是, 以 傳 值 方 式 傳 進(jìn) 動(dòng) 態(tài) 連 接 庫 的 變 量, 其 值 在 動(dòng) 態(tài) 庫 中 是 不 能 被 改 變 的; 如 果 需 要 在 動(dòng) 態(tài) 連 接 庫 中 修 改 傳 入 參 數(shù) 的 值, 則 必 須 使 用 傳 址 方 式。 一 般 來 說, 在VB 和 動(dòng) 態(tài) 連 接 庫 之 間 傳 遞 單 個(gè) 的 簡(jiǎn) 單 數(shù) 據(jù) 類 型, 只 要 注 意 了 以 上 幾 個(gè) 方 面 就 可 以 了。 當(dāng) 需 要 將 一 個(gè) 簡(jiǎn) 單 數(shù) 據(jù) 類 型 的 整 個(gè) 數(shù) 組 傳 進(jìn) 動(dòng) 態(tài) 庫 時(shí), 必 須 將 相 應(yīng) 參 數(shù) 聲 明 為 傳 址 方 式, 然 后 把 數(shù) 組 的 第 一 個(gè) 元 素 作 為 參 數(shù) 傳 入, 這 樣 在 動(dòng) 態(tài) 連 接 庫 中 就 得 到 了 數(shù) 組 的 首 地 址, 從 而 可 以 對(duì) 整 個(gè) 數(shù) 組 進(jìn) 行 訪 問。 例 如, 聲 明 了 一 個(gè) 名 為ReadArray 的DLL 過 程, 要 求 傳 入 一 個(gè) 整 型 數(shù) 組aArray:

Declare Function ReadArray Lib "mydll.dll" _
(aArray As Integer) As Integer
在 調(diào) 用 時(shí) 可 以 采 用 如 下 方 式:
Dim ret,I(5) as Integer
… …
ret = ReadArray(I(0)) ‘ 將 整 個(gè) 數(shù) 組 傳 入 動(dòng) 態(tài) 連 接 庫

---- 2、 字 符 串 參 數(shù) 的 傳 遞:

---- 與 簡(jiǎn) 單 數(shù) 據(jù) 類 型 相 比, 字 符 串 類 型(String、String * n) 的 參 數(shù) 傳 遞 要 復(fù) 雜 得 多,這 主 要 是Windows 95 API 和VB 使 用 的 字 符 串 類 型 不 同 的 緣 故。VB 使 用 被 稱 為 BSTR 的 String 數(shù) 據(jù) 類 型, 它 是 由 自 動(dòng) 化( 以 前 被 稱 為 OLE Automation) 定 義 的 數(shù) 據(jù) 類 型。 一 個(gè) BSTR 由 頭 部 和 字 符 串 組 成, 頭 部 包 含 了 字 符 串 的 長(zhǎng) 度 信 息, 字 符 串 中 可 以 包 含 嵌 入 的 null 值。 大 部 分 的 BSTR 是 Unicode 的, 即 每 個(gè) 字 符 需 要 兩 個(gè) 字 節(jié)。BSTR 通 常 以 兩 字 節(jié) 的 兩 個(gè) null 字 符 結(jié) 束。 下 圖 表 示 了 一 個(gè)BSTR 類 型 的 字 符 串。

( 前 綴) a T e s t {content}
頭 部 BSTR指向數(shù)據(jù)的第一個(gè)字節(jié)

---- 另 一 方 面, 大 部 分 的DLL 過 程( 包 括 Windows 95 API 中 的 所 有 過 程) 使 用 LPSTR 類 型 字 符 串, 這 是 指 向 標(biāo) 準(zhǔn) 的 以 null 結(jié) 束 的 C 語 言 字 符 串 的 指 針, 它 也 被 稱 為 ASCIIZ 字 符 串。LPSTR 沒 有 前 綴。 下 圖 顯 示 了 一 個(gè) 指 向 ASCIIZ 字 符 串 的 LPSTR。

---- a T e s t {content}

---- LPSTR 指 向 一 個(gè) 以null 結(jié) 尾 的 字 符 串 數(shù) 據(jù) 的 第 一 個(gè) 字 節(jié)

---- 如 果 DLL 過 程 需 要 一 個(gè) LPSTR( 指 向 以 null 結(jié) 束 的 字 符 串 的 指 針) 作 為 參 數(shù), 可 以 在VB 中 將 一 個(gè) 字 符 串 以 傳 值 的 方 式 傳 遞 給 它。 因 為 指 向 BSTR 的 指 針 實(shí) 際 指 向 以 null 值 結(jié) 束 的 字 符 串 的 第 一 個(gè) 數(shù) 據(jù) 字 節(jié), 所 以 對(duì) 于 DLL 過 程 來 說, 它 就 是 一 個(gè) LPSTR。 這 樣 傳 入 動(dòng) 態(tài) 連 接 庫 的 字 符 串,DLL 過 程 也 可 以 對(duì) 它 進(jìn) 行 修 改, 盡 管 它 是 以 傳 值 方 式 傳 入 的。 只 有 當(dāng)DLL 過 程 需 要 一 個(gè) 指 向LPSTR 的 指 針 時(shí), 才 以 傳 址 的 方 式 傳 入 字 符 串, 這 時(shí)DLL 過 程 得 到 的 是 一 個(gè) 指 向 字 符 串 指 針 的 指 針( 相 當(dāng) 于C/C++ 中 的char * *), 而 不 是 通 常 所 用 的 字 符 串 的 首 地 址( 相 當(dāng) 于C/C++ 中 的char *)。

---- 當(dāng) 需 要 把 一 個(gè) 字 符 串 數(shù) 組 整 個(gè) 傳 入 動(dòng) 態(tài) 連 接 庫 時(shí), 情 況 就 變 得 復(fù) 雜 多 了, 用 傳 遞 簡(jiǎn) 單 數(shù) 據(jù) 類 型 數(shù) 組 的 方 式 來 傳 遞 字 符 串 數(shù) 組 是 行 不 通 的。 當(dāng) 我 們 以 傳 值 的 方 式 將 一 個(gè) 字 符 串 數(shù) 組 的 第 一 個(gè) 元 素 傳 進(jìn) 動(dòng) 態(tài) 連 接 庫 時(shí),DLL 過 程 得 到 的 實(shí) 際 上 是 該 元 素 壓 入 堆 棧 段 后 的 地 址, 而 不 是 數(shù) 據(jù) 段 中 整 個(gè) 數(shù) 組 的 首 地 址。 也 就 是 說, 這 時(shí)DLL 過 程 只 能 得 到 數(shù) 組 的 第 一 個(gè) 元 素, 而 無 法 訪 問 整 個(gè) 數(shù) 組。 而 以 傳 址 方 式 傳 入 第 一 個(gè) 元 素 時(shí),DLL 過 程 只 能 得 到 指 向 該 元 素 在 堆 棧 段 中 地 址 的 指 針, 同 樣 無 法 訪 問 整 個(gè) 數(shù) 組。 這 不 能 不 說 是VB 的 一 個(gè) 不 足。 因 此, 在 程 序 設(shè) 計(jì) 中, 如 果 確 實(shí) 需 要 將 整 個(gè) 字 符 串 數(shù) 組 傳 入 動(dòng) 態(tài) 庫, 就 必 須 采 取 其 它 方 法。

---- 我 們 知 道, 在VB 中, 有 一 種Byte 數(shù) 據(jù) 類 型。 每 個(gè)Byte 型 變 量 占 一 個(gè) 字 節(jié), 不 含 符 號(hào) 位, 因 此 所 能 表 示 的 范 圍 為0 到255。 這 種 數(shù) 據(jù) 類 型 是 專 門 用 于 存 放 二 進(jìn) 制 數(shù) 據(jù) 的。 為 了 將 整 個(gè) 字 符 串 數(shù) 組 傳 進(jìn) 動(dòng) 態(tài) 庫, 可 以 用 字 節(jié) 數(shù) 組 來 保 存 字 符 串。 由 于Byte 是 一 種 簡(jiǎn) 單 數(shù) 據(jù) 類 型, 因 此 字 節(jié) 數(shù) 組 的 傳 遞 是 非 常 簡(jiǎn) 單 的。 首 先, 需 要 把 一 個(gè) 字 符 串 正 確 地 轉(zhuǎn) 變 成 一 個(gè) 字 節(jié) 數(shù) 組。 這 要 涉 及 一 些 字 符 集 的 知 識(shí)。Windows 95 和VB 使 用 不 同 的 字 符 集,Windows 95 API 使 用 的 是ANSI 或DBCS 字 符 集, 而VB 使 用 的 則 是Unicode 字 符 集。 所 謂ANSI 字 符 集, 是 指 每 個(gè) 字 符 都 用 一 個(gè) 字 節(jié) 表 示, 因 此 最 多 只 能 有28=256 個(gè) 不 同 的 字 符, 這 對(duì) 于 英 語 來 說 已 經(jīng) 足 夠 了, 但 不 能 完 全 支 持 其 它 語 言。DBCS 字 符 集 支 持 很 多 不 同 的 東 亞 語 言, 如 漢 語、 日 語 和 朝 鮮 語, 它 使 用 數(shù) 字 0-255 表 示 ASCII 字 符, 其 它 大 于255 或 小 于0 的 數(shù) 字 表 明 該 字 符 屬 于 非 拉 丁 字 符 集; 在 DBCS 中,ASCII 字 符 的 長(zhǎng) 度 是 一 個(gè) 字 節(jié), 而 漢 語、 日 語 和 其 它 東 亞 字 符 的 長(zhǎng) 度 是 2 個(gè) 字 節(jié)。 而Unicode 字 符 集 則 完 全 用 兩 個(gè) 字 節(jié) 表 示 一 個(gè) 字 符, 因 此 最 多 可 以 表 示216=65536 個(gè) 不 同 字 符。 也 就 是 說,ANSI 字 符 集 中 所 有 的 字 符 都 只 占 一 個(gè) 字 節(jié),DBCS 字 符 集 中ASCII 字 符 占 一 個(gè) 字 節(jié), 漢 字 占 兩 個(gè) 字 節(jié),Unicode 字 符 集 中 每 個(gè) 字 符 都 占 兩 個(gè) 字 節(jié)。 由 于VB 與Windows API 使 用 的 字 符 集 不 同, 因 此 在 進(jìn) 行 字 符 串 到 字 節(jié) 數(shù) 組 的 轉(zhuǎn) 換 時(shí), 當(dāng) 用Asc 函 數(shù) 取 得 一 個(gè) 字 符 的 字 節(jié) 碼 后, 需 要 判 斷 它 是 否 是 一 個(gè)ASCII 字 符; 如 果 是ASCII 字 符, 則 在 轉(zhuǎn) 換 后 的 字 節(jié) 數(shù) 組 中 就 只 占 一 個(gè) 字 節(jié), 否 則 要 占 兩 個(gè) 字 節(jié)。 如 下 流 程 圖 表 示 了 轉(zhuǎn) 換 一 個(gè) 字 符 串 的 過 程。

---- 下 面 給 出 了 轉(zhuǎn) 換 函 數(shù):GetCharByte 得 到 一 個(gè) 字 符 的 高 字 節(jié) 或 低 字 節(jié), 它 的 第 一 個(gè) 參 數(shù) 是 一 個(gè) 字 符 的ASCII 碼, 第 二 個(gè) 參 數(shù) 是 標(biāo) 志 取 高 字 節(jié) 還 是 低 字 節(jié);StrToByte 按DBCS 或ANSI 格 式 將 一 個(gè) 字 符 串 轉(zhuǎn) 換 成 一 個(gè) 字 節(jié) 數(shù) 組, 第 一 個(gè) 參 數(shù) 是 待 轉(zhuǎn) 換 的 字 符 串, 第 二 個(gè) 參 數(shù) 是 轉(zhuǎn) 換 后 的 一 個(gè) 定 長(zhǎng) 字 節(jié) 數(shù) 組, 若 該 數(shù) 組 長(zhǎng) 度 不 足 以 存 放 整 個(gè) 字 符 串, 則 截 去 超 長(zhǎng) 的 部 分;ChangeStrAryToByte 利 用 前 兩 個(gè) 函 數(shù) 將 字 符 串 數(shù) 組 轉(zhuǎn) 換 成 字 節(jié) 數(shù) 組, 第 一 個(gè) 參 數(shù) 是 定 長(zhǎng) 的 字 符 串 數(shù) 組, 其 中 每 個(gè) 元 素 都 是 一 個(gè) 字 符 串( 各 個(gè) 元 素 包 含 的 字 符 數(shù) 可 以 不 同), 第 二 個(gè) 參 數(shù) 是 一 個(gè) 變 長(zhǎng) 的 字 節(jié) 數(shù) 組, 保 存 轉(zhuǎn) 換 后 的 結(jié) 果。

---- Function GetCharByte(ByVal OneChar As Integer, ByVal IsHighByte As Boolean) As Byte ‘ 該 函 數(shù) 獲 得 一 個(gè) 字 符 的 高 字 節(jié) 或 低 字 節(jié)

If IsHighByte Then
If OneChar >= 0 Then
GetCharByte = CByte(OneChar 256)
‘右移8位,得到高字節(jié)
Else
GetCharByte = CByte((OneChar
And &H7FFF) 256) Or &H80
End If
Exit Function
Else
GetCharByte = CByte(OneChar And &HFF)
‘屏蔽掉高字節(jié),得到低字節(jié)
Exit Function
End If
End Function

Sub StrToByte(StrToChange As String, ByteArray() As Byte)
‘該函數(shù)將一個(gè)字符串轉(zhuǎn)換成字節(jié)數(shù)組
Dim LowBound, UpBound As Integer
Dim i, count, length As Integer
Dim OneChar As Integer

count = 0
length = Len(StrToChange)
LowBound = LBound(ByteArray)
UpBound = UBound(ByteArray)

For i = LowBound To UpBound
ByteArray(i) = 0 ‘初始化字節(jié)數(shù)組
Next

For i = LowBound To UpBound
count = count + 1
If count <= length Then
OneChar = Asc(Mid(StrToChange, count, 1))

If (OneChar > 255) Or (OneChar < 0) Then
‘該字符是非ASCII字符
ByteArray(i) = GetCharByte(OneChar, True) ‘得到高字節(jié)
i = i + 1
If i <= UpBound Then ByteArray(i)
= GetCharByte(OneChar, False)
‘得到低字節(jié)
Else
‘該字符是ASCII字符
ByteArray(i) = OneChar
End If
Else
Exit For
End If
Next
End Sub

Sub ChangeStrAryToByte(StrAry()
As String, ByteAry() As Byte)
‘將字符串?dāng)?shù)組轉(zhuǎn)換成字節(jié)數(shù)組
Dim LowBound, UpBound As Integer
Dim i, count, StartPos, MaxLen As Integer
Dim TmpByte() As Byte

LowBound = LBound(StrAry)
UpBound = UBound(StrAry)
count = 0
ReDim ByteAry(0)

For i = LowBound To UpBound
MaxLen = LenB(StrAry(i))
ReDim TmpByte(MaxLen + 1)
ReDim Preserve ByteAry(count + MaxLen + 1)
Call StrToByte(StrAry(i), TmpByte) ‘轉(zhuǎn)換一個(gè)字符串
StartPos = count
Do
ByteAry(count) = TmpByte(count - StartPos)
count = count + 1
If ByteAry(count - 1) = 0 Then Exit Do
Loop ‘將每一個(gè)字符串對(duì)應(yīng)
的字節(jié)數(shù)組按順序填入結(jié)果數(shù)組中
ReDim Preserve ByteAry(count - 1)
Next i
End Sub

---- 下 面 看 一 個(gè) 轉(zhuǎn) 換 的 例 子:

Dim ResultAry() as Byte
Dim SomeStr(2) as String
SomeStr(0) = " 測(cè) 試1"
SomeStr(1) = " 測(cè) 試222"
SomeStr(2) = " 測(cè) 試33"
Call ChangeStrAryToByte
(SomeStr,ResultAry) ‘ 轉(zhuǎn) 換 字 符 串 數(shù) 組

---- 當(dāng) 轉(zhuǎn) 換 完 成 以 后, 查 看 字 節(jié) 數(shù) 組ResultAry, 其 中 包 含 了21 個(gè) 元 素, 依 次 是:178,226,202,212,49,0,178,226,202,212,50,50,50,0,178,226,202,212,51,51,0。 其 中,[178,226] 是" 測(cè)" 的 字 節(jié) 碼,[202,112] 是" 試" 的 字 節(jié) 碼,49,50,51 分 別 為 字 符1、2、3 的ASCII 碼。 可 見, 經(jīng) 過 轉(zhuǎn) 換 后, 字 符 串 數(shù) 組 中 的 各 個(gè) 元 素 按 順 序 放 在 了 字 節(jié) 數(shù) 組 中, 相 互 間 以 終 止 符0 分 隔。

---- 這 樣, 字 符 串 數(shù) 組 就 全 部 轉(zhuǎn) 換 成 了 字 節(jié) 數(shù) 組, 然 后 只 要 將 字 節(jié) 數(shù) 組 的 第 一 個(gè) 元 素 以 傳 址 的 方 式 傳 入 動(dòng) 態(tài) 連 接 庫,DLL 過 程 就 可 以 正 確 地 訪 問 數(shù) 組 中 的 所 有 字 符 串 了。 但 是, 使 用 這 種 方 法, 當(dāng)DLL 過 程 處 理 結(jié) 束 返 回VB 時(shí),VB 得 到 的 仍 然 是 字 節(jié) 數(shù) 組。 如 果 需 要 在VB 中 再 次 得 到 該 字 節(jié) 數(shù) 組 表 示 的 字 符 串, 還 要 把 整 個(gè) 字 節(jié) 數(shù) 組 重 新 以0 為 分 割 符 分 成 多 個(gè) 子 數(shù) 組( 每 個(gè) 子 數(shù) 組 都 對(duì) 應(yīng) 原 來 字 符 串 數(shù) 組 中 的 一 個(gè) 元 素), 然 后 使 用VB 函 數(shù)StrConv 將 每 個(gè) 子 數(shù) 組 轉(zhuǎn) 換 成 字 符 串( 轉(zhuǎn) 換 時(shí) 第 二 個(gè) 參 數(shù) 選vbUnicode), 就 可 以 顯 示 或 進(jìn) 行 其 它 操 作 了。 例 如, 其 中 一 個(gè) 子 數(shù) 組 的 名 字 是SubAry, 則 函 數(shù)StrConv(SubAry,vbUnicode) 就 返 回 了 它 所 對(duì) 應(yīng) 的 字 符 串。

---- 總 之,VB 應(yīng) 用 程 序 和 動(dòng) 態(tài) 庫 間 字 符 串 參 數(shù) 的 傳 遞 是 一 個(gè) 比 較 復(fù) 雜 的 過 程, 使 用 時(shí) 要 非 常 謹(jǐn) 慎。 同 時(shí) 應(yīng) 盡 可 能 避 免 傳 遞 字 符 串 數(shù) 組 類 型 的 參 數(shù), 因 為 這 很 容 易 引 起 下 標(biāo) 越 界、 堆 棧 溢 出 等 嚴(yán) 重 錯(cuò) 誤。

---- 3、 用 戶 自 定 義 類 型(User-defined Type) 參 數(shù) 的 傳 遞

---- 用 戶 自 定 義 類 型 在VB 中 是 一 種 重 要 的 數(shù) 據(jù) 類 型, 它 為 編 程 者 提 供 了 很 大 的 靈 活 性, 使 開 發(fā) 人 員 可 以 根 據(jù) 需 要 構(gòu) 造 自 己 的 數(shù) 據(jù) 結(jié) 構(gòu)。 它 相 當(dāng) 于C/C++ 中 的 結(jié) 構(gòu) 類 型(structure)。 在VB 中, 允 許 程 序 員 以 傳 址 的 方 式 將 自 定 義 數(shù) 據(jù) 類 型 參 數(shù) 傳 入 動(dòng) 態(tài) 庫,DLL 過 程 也 可 以 將 修 改 后 的 參 數(shù) 返 回VB 程 序。 但 是, 在VB 中 仍 然 不 支 持 以 傳 值 的 方 式 傳 遞 用 戶 自 定 義 類 型 參 數(shù)。

---- 傳 遞 用 戶 自 定 義 類 型 參 數(shù) 時(shí), 必 須 確 保VB 中 的 數(shù) 據(jù) 類 型 的 成 員 與 動(dòng) 態(tài) 庫 中 的 結(jié) 構(gòu) 成 員 是 一 一 對(duì) 應(yīng) 的, 所 占 空 間 也 必 須 嚴(yán) 格 一 致。 這 里 所 說 的 一 一 對(duì) 應(yīng), 不 僅 是 指VB 中 的 所 有 結(jié) 構(gòu) 成 員 在 動(dòng) 態(tài) 庫 的 結(jié) 構(gòu) 中 都 必 須 有 對(duì) 應(yīng) 的 元 素, 而 且 它 們 在 數(shù) 據(jù) 結(jié) 構(gòu) 中 定 義 的 順 序 也 必 須 嚴(yán) 格 一 致, 這 是VB 中 使 用 的" 數(shù) 據(jù) 結(jié) 構(gòu) 成 員 對(duì) 齊 方 式" 決 定 的。 在VB 中, 數(shù) 據(jù) 結(jié) 構(gòu) 使 用 雙 字 對(duì) 齊 方 式(4-byte alignment), 因 此, 在 用 戶 自 己 生 成 用 于VB 調(diào) 用 的 動(dòng) 態(tài) 連 接 庫 時(shí), 也 必 須 把 編 譯 選 項(xiàng)"structure member alignment" 設(shè) 為4 字 節(jié)( 如 前 文 所 述)。

---- 所 謂 結(jié) 構(gòu) 成 員 對(duì) 齊 方 式 是 指 一 個(gè) 數(shù) 據(jù) 結(jié) 構(gòu) 內(nèi) 部, 其 成 員 的 排 列 方 式。 譬 如, 在VB 中, 其 對(duì) 齊 方 式 是4 字 節(jié), 這 就 好 象 在 一 個(gè) 數(shù) 據(jù) 結(jié) 構(gòu) 內(nèi) 部 分 成 了 很 多 個(gè)4 字 節(jié) 大 小 的 小 單 元, 如 果 相 鄰 兩 個(gè) 或 多 個(gè) 數(shù) 據(jù) 成 員 的 大 小 可 以 放 在 一 個(gè) 單 元 中, 那 么 就 放 在 一 起; 否 則 這 些 小 單 元 中 可 能 會(huì) 出 現(xiàn) 未 用 的 空 字 節(jié)。 我 們 來 看 下 面 一 個(gè) 數(shù) 據(jù) 類 型:

Type TestType
m1 as Integer
m2 as Byte
m3 as Long
End Type

---- 它 的 三 個(gè) 成 員 的 大 小 加 起 來 是2+1+4=7。 但 是, 由 于m1 和m2 的 字 節(jié) 總 長(zhǎng) 度 是3, 小 于4, 它 們 就 存 放 于 一 個(gè) 單 元 中; 但 該 單 元 剩 下 的 一 個(gè) 字 節(jié) 不 足 以 放 下 一 個(gè)Long 型 的 成 員m3, 于 是m3 就 被 放 在 下 一 個(gè) 單 元 中, 它 們 之 間 就 有 了 一 個(gè) 未 用 的 空 字 節(jié); 因 此, 整 個(gè) 結(jié) 構(gòu) 所 占 實(shí) 際 長(zhǎng) 度 是8 字 節(jié)。 同 理, 如 果 將m3 和m2 的 位 置 交 換 一 下, 它 所 占 的 尺 寸 就 變 成 了9 字 節(jié)。 可 見, 成 員 在 結(jié) 構(gòu) 中 的 聲 明 順 序 也 是 非 常 重 要 的。

---- 通 常, 當(dāng) 一 個(gè) 用 戶 自 定 義 類 型 中 不 包 含 字 符 串 時(shí), 向 動(dòng) 態(tài) 連 接 庫 中 傳 遞 該 類 型 的 參 數(shù) 是 沒 有 什 么 問 題 的。 如 果 只 傳 遞 一 個(gè) 自 定 義 類 型 變 量, 則 既 可 以 傳 遞 該 變 量 名, 也 可 以 傳 遞 該 變 量 的 第 一 個(gè) 成 員, 它 們 的 效 果 是 一 樣 的, 都 是 將 該 變 量 的 地 址 傳 進(jìn) 了 動(dòng) 態(tài) 庫; 同 樣, 如 果 要 傳 遞 一 個(gè) 自 定 義 類 型 的 數(shù) 組, 則 既 可 以 傳 遞 該 數(shù) 組 的 第 一 個(gè) 元 素, 也 可 以 傳 遞 第 一 個(gè) 元 素 的 第 一 個(gè) 成 員。 但 是, 如 果 用 戶 自 定 義 類 型 中 包 含 字 符 串 類 型 時(shí), 又 該 如 何 與 動(dòng) 態(tài) 連 接 庫 傳 遞 參 數(shù) 呢 ? 答 案 是 令 人 遺 憾 的: 在VB 中, 你 無 法 將 一 個(gè) 包 含 字 符 串 成 員 的 用 戶 自 定 義 類 型 變 量 或 數(shù) 組 安 全、 正 確 地 傳 入 動(dòng) 態(tài) 庫 中。 如 果 你 這 樣 做 了, 即 使 某 次 僥 幸 得 到 了 正 確 的 結(jié) 果, 在 其 背 后 也 隱 藏 著 許 多 致 命 的 危 險(xiǎn)。 因 此, 如 果 一 定 要 在 用 戶 自 定 義 類 型 中 包 含 字 符 串 變 量, 并 且 該 類 型 的 變 量 又 要 作 為 參 數(shù) 傳 入 動(dòng) 態(tài) 庫 時(shí), 你 最 好 修 改 類 型 定 義, 把 其 中 的 字 符 串 成 員 用 相 應(yīng) 的 字 節(jié) 數(shù) 組 類 型 替 換 掉( 轉(zhuǎn) 換 方 法 可 參 見 前 文), 這 樣 就 可 以 在VB 和 動(dòng) 態(tài) 庫 間 傳 遞 這 種 類 型 的 參 數(shù) 了。

---- 另 外, 在VB 中 還 可 以 把 一 個(gè) 函 數(shù) 的 指 針 傳 遞 到 動(dòng) 態(tài) 庫 中, 方 法 也 并 不 復(fù) 雜。 但 筆 者 強(qiáng) 烈 建 議 最 好 不 要 這 么 做, 因 為 這 樣 一 來VB 應(yīng) 用 程 序 就 幾 乎 完 全 喪 失 了 它 所 應(yīng) 有 的 安 全 性。 如 果 確 實(shí) 需 要 傳 遞 函 數(shù) 指 針 的 話, 那 么 還 是 編 一 個(gè)C/C++ 的 程 序 來 完 成 這 項(xiàng) 工 作 吧。

---- 總 之, 在VB 中 調(diào) 用DLL 過 程 是 一 個(gè) 比 較 復(fù) 雜 的 問 題, 編 程 人 員 必 須 很 好 地 把 握, 才 能 達(dá) 到 既 提 高 了 程 序 效 率, 開 拓 了 程 序 功 能, 又 不 降 低 程 序 安 全 性 的 目 的。 另 外 需 要 特 別 指 出 的 一 點(diǎn) 是, 在 本 文 中 提 到 的 所 有 動(dòng) 態(tài) 連 接 庫, 都 是 指 沒 有 使 用 自 動(dòng) 化(OLE Automation) 技 術(shù) 的 動(dòng) 態(tài) 庫,Windows API 和 大 多 數(shù) 用 戶 自 編 的 動(dòng) 態(tài) 連 接 庫 都 是 這 種 類 型 的。 對(duì) 于 使 用 了OLE Automation 技 術(shù) 的 動(dòng) 態(tài) 連 接 庫, 其 參 數(shù) 傳 遞 的 方 式 有 所 不 同, 讀 者 可 以 參 閱 有 關(guān)OLE 技 術(shù) 的 書 籍, 在 此 不 再 涉 及。

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
在VB中使用API函數(shù)詳解
VB編外掛的一些基礎(chǔ)知識(shí)
什么是API
C語言的DLL怎么給VB返回String(char*)呢
vc vb dll 參數(shù)傳遞
c-vb Type
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服