再談在VB中呼叫VC++開發的DLL (轉)

amyz發表於2007-08-15
再談在VB中呼叫VC++開發的DLL (轉)[@more@]

  近日開發一個,用到動態連結庫,在VB中時遇到了一些問題。我查了一些資料,也看了一下CSDN上的文章,感覺這些文章對在VB中呼叫VC++開發的DLL這一問題闡述得不夠詳細。因此在我的問題得到解決之餘,特為初接觸DLL的朋友們寫下這篇文章。:namespace prefix = o ns = "urn:schemas--com::office" />

本文中關於呼叫約定的解決方法,也適用於解決其它語言之間DLL呼叫的相容問題。

  ①關於DLL的建立與呼叫

  使用VC++的嚮導即可。具體操作如下:開啟選單“FileNew”→選擇“Projects Dynamic-Link Library”→選擇“A simple DLL project”即可。這時會自動生成3個:*.cpp,stdafx.cpp,stdafx.h。

  之後將入口DLLMain()補充完整,再新增你自定義的函式的程式碼。如果你自定義的函式很多,可以將這些函式的宣告部分統一寫入一個標頭檔案中。再在.cpp檔案首部用“#include”語句引入這個標頭檔案。注意函式宣告前要加上“__declspec(dllexport)”。

  (如果你建DLL時選擇的是第三種型別(加入示例程式碼),則在函式宣告及定義前都要加上系統定義的宏“*_”。)

  在VB中用如下語句宣告:“Declare Function 函式名 Lib "完整路徑檔名.dll" [Alias "函式別名"] (ByVal 變數1 As 型別1, ByVal 變數2 As 型別2,…) As 型別3”,與呼叫API函式類似。

  注意:若在窗體程式碼的“通用”部分使用,“Declare”前要加“Private”;若在Moudle中使用,“Declare”前要加“Public”。若將DLL檔案放在“System”或“WinNTSystem32”目錄下,“Lib”後只寫出DLL主檔名即可。

具體的例項程式碼見④(修正後的,可直接執行)。 

  ②關於入口點

  如上編寫Cipher.dll,執行,出現錯誤資訊“找不到DLL入口點(Error 53)”。出現這一錯誤的原因是C++在編譯時對函式名Encrypt作了修改。開啟檢視程式(D:WINNTSystem32ViewersQuikView.exe),將Cipher.dll拖入檢視視窗,找到欄位to:“?Encrypt@@YAHHH@Z">“?Encrypt@@YAHHH@Z”,發現函式名被加了一串字元。

  解決方法有二。第一,直接在VB宣告中將“?Encrypt@@Y AHHH@Z”作為別名放在“Alias”後即可;第二,在Cipher.dll程式碼中在語句“__declspec(dllexport) int __stdcall Encrypt(int p, int k); ”前加上“extern "C" ”,編譯後,用QuikView檢視,函式名變為“_Encrypt”,之後再在VB宣告中做相應調整即可。

  (對於使用宏的DLL,在“#define”語句中,對宏“Cipher_API”的替換值做更改即可。)

進行了③的更改後,程式又找不到入口點了。再用QuikView檢視,發現函式名變為”。還有解決方法。在Cipher.dll工程中新增一個文字檔案,命名為“Cipher.def”,新增程式碼如④。編譯後再用QuikView檢視,函式名變回“Encrypt”,在VB中呼叫,執行正常。

  ③關於呼叫約定

  採用②中第二種解決方法,執行,出現錯誤資訊“DLL呼叫約定錯誤(Error 49)”。原因是呼叫約定共有4種方式:__fastcall、__pascal、__stdcall、__cdecl,VC++預設呼叫方式為__cdecl,而VB預設呼叫方式則為__stdcall。解決方法是,更改程式碼如下(限定呼叫方式):

  extern “C” __declspec(dllexport) int __stdcall Encrypt(int p, int k);

  …………

  int __stdcall Encrypt(int p, int k)

  {

    int c = p+k;

    return c;

  }

  

Cipher.dll

 Cipher.cpp

  //引入預編譯標頭檔案

  #include “stdafx.h”

  //宣告我的函式

extern “C” __declspec(dllexport) int __stdcall Encrypt( int p, int k );

  //DLL入口函式

 BOOL APIENTRY DllMain( HANDLE  hModule,

    D  ul_reason_for_call,

 LPVOID  lpReserved

 )

  {

 switch( ul_reason_for_call )

    {

  case  DLL_PROCESS_ATTACH:

  case  DLL_THREAD_ATTACH:

  case  DLL_THREAD_DETACH:

  case  DLL_PROCESS_DETACH:

    break;

    }

  return TRUE;

  }

  //我的函式

  int __stdcall Encrypt ( int p, int k )

  {

  int c = p + k ;

    return c ;

  }

 Cipher.def

  LIBRARY Cipher

  EXPORTS Encrypt

編譯後,將Cipher.dll複製到“D:WINNTSystem32”目錄。

VB中呼叫:

  Option Explicit

Private Declare Function Encrypt Lib “Cipher” _

(ByVal p As Long, ByVal k As Long) As Long

   Private Sub Form_Load()

  Dim c As Long

  c = Encrypt(24, 8)

  Text1.Text = c

  End Sub

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752019/viewspace-957727/,如需轉載,請註明出處,否則將追究法律責任。

相關文章