再谈在VB中调用VC++开发的DLL

再谈在VB中调用VC++开发的DLL 
作者:未知 来源:月光软件站 
  近日开发一个程序,用到动态链接库,在VB中调用时遇到了一些问题。我查了一些资料,也看了一下CSDN上的文章,感觉这些文章对在VB中调用VC++开发的DLL这一问题阐述得不够详细。因此在我的问题得到解决之余,特为初接触DLL的朋友们写下这篇文章。 

本文中关于调用约 定的解决方法,也适用于解决其它编程语言之间DLL调用的兼容问题。 


  ①关于DLL的创建与调用 

  使用VC++的向导即可。具体操作如下:打开菜单“File\New”→选择“Projects\Win32 Dynamic-Link Library”→选择“A simple DLL project”即可。这时系统会自动生成3个文件:*.cpp,stdafx.cpp,stdafx.h。 

  之后将入口函数DLLMain()补充完整,再添加自定义函数代码。如果你自定义函数很多,可以将这些函数的声明部分统一写入一个文件中。再在.cpp文件首部用“# include”语句引入这个头文件。注意函数声明前要加上“__declspec(dllexport)”。 

  (如果你建DLL时选择的是第三种类型(加入示例代码),则在函数声明及定义前都要加上系统定义的宏“*_API”。) 

  在VB中用如下语句声明:“Declare Function 函数名 Lib "完整路径\文件名.dll" [Alias "函数别名"] (ByVal 变量1 As 类型1,ByVal 变量2 As 类型2,…) As 类型3”,与调用API函数类似。 

  注意:若在窗体代码的“通用”部分使用,“Declare”前要加“Private”;若在Moudle中使用,“Declare”前要加“Public”。若将DLL文件放在“\Windows\System”或“\WinNT\System32” 目录下,“Lib”后只写出DLL主文件名即可。 

具体的实例代码见④(修正后的,可直接运行)。  


  ②关于入口点 

  如上编写Cipher.dll,运行,出现错误信息“找不到DLL入口点(Error 53)”。出现这一错误的原因是C++编译器在编译时对函数名Encrypt作了修改。打开快速查看程序(D:\WINNT\System32\Viewers\QuikView.exe),将Cipher.dll拖入查看窗口,找到字段“?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”的替换值做更改即可。) 

进行了③的更改后,程序又找不到入口点了。再用QuikVie w查看,发现函数名变为“_Encrypt@8”。还有解决方法。在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,DWORD 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:\WINNT\System32”目录。 

在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

相关文章

Format[$] ( expr [ , fmt ] ) format 返回变体型 format$ 强...
VB6或者ASP 格式化时间为 MM/dd/yyyy 格式,竟然没有好的办...
在项目中添加如下代码:新建窗口来显示异常信息。 Namespace...
转了这一篇文章,原来一直想用C#做k3的插件开发,vb没有C#用...
Sub 分列() ‘以空格为分隔符,连续空格只算1个。对所选...
  窗体代码 1 Private Sub Text1_OLEDragDrop(Data As Dat...