姐妹们你们睡过老外么:vb调用C++写的DLL

来源:百度文库 编辑:中财网 时间:2024/05/05 10:01:05
首先必须了解此函数在C中的原型,包括参数类型和传递方式。 

C   DLL   原型                   VB声明                                   VB调用 
  
int   a                             ByVal   a   as   long                 Call   func(…,a,…) 
long   a                           ByRef   a   as   long                 Call   func(…,byval   a,…) 
int   *pa                         ByRef   pa   as   long               Call   func(…,pa,…) 
long   *pa                       ByVal   pa   as   long               Call   func(…,varptr(pa),…)       *(1) 
char   *pstr                   ByVal   pstr   as   string       Call   func(…,pstr,…)                   *(2) 
wchar   *pstr                 ByRef   pstr   as   string       Call   func(…,byval   pstr,…) 
struct   tagX   *p           ByRef   p   as   tagX                 Call   func(…,ptag,…)                   *(3)   
HANDLE   h                       ByVal   h   as   long                 Call   func(…,h,…)                         *(4)   

注意       

1)不推荐使用此方式 

2)如果DLL要求一个字符串缓冲区,一定要在调用前初始化字串,即dim   t   as   string   *   50 

3)用户定义子类型必须用ByRef方式传递,   

4)任何内核对象的句柄(process,   thread,   module,   file,   filemapping,   semaphore等)和大多数GDI对象的句柄都能用此方式传递。 



近日开发一个程序,用到动态链接库,在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”的替换值做更改即可。) 

进行了③的更改后,程序又找不到入口点了。再用QuikView查看,发现函数名变为“_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 

  

  
  

对该文的评论   人气:1077     
            gengdong   (2004-4-26   21:25:05)     

二,在Cipher.dll代码中在语句“__declspec(dllexport)   int   __stdcall   Encrypt(int   p,   int   k);   ”前加上“extern   "C "   ”,编译后,用QuikView查看,函数名变为“_Encrypt”,之后再在VB声明中做相应调整即可。   //这里是不是错了,按我的笔记里和作者的意思,这里应该是__declspec(dllexport)   int   __cdecl   Encrypt(int   p,   int   k);   
  
            WindsonZhL   (2004-2-25   11:56:56)     

__stdcall   又叫“回调函数”,MFC   有宏:   #define   CALLBACK   __stdcall   #define   WINAPI   __stdcall   #define   WINAPIV   __cdecl   #define   APIENTRY   WINAPI   #define   APIPRIVATE   __stdcall   
  
            WindsonZhL   (2004-2-24   15:55:15)     

补充说明:   ①使用了   def   文件,就可以不加   extern   "C "   了;   ②QuikView.exe   是   Win2000   Server   系统自带的程序,装有其它系统的用户可用   VC   的   Depends   工具察看;   ③http://www.onlinedown.net/soft/4975.htm   可下载   Quick   View   Plus   ,开发商   stellent,最新版本   v8.0      在vb中使用vc编译的dll实例 
    
关键字           在VB中使用VC编译的dll   
    


18:07   2003-12-3 
今天,仿照着书,我使用vc编了一个动态链接库(dll)--a.dll,然后将它复制到windows/system/目录下面,之后建立了一个vb程序,并在程序中声明了a.dll中的函数add(),实现两个整形数的加法运算。 
实现过程如下: 
一、建立dll 
打开vc,创建一个基于API的DLL. 

----   1.在FILE-   > NEW-   > PROJECTS中选择 "WIN32   Dynamic-Link   Library "在Project   Name中输入   "a "按OK   
----   2.在FILE-   > NEW-   > FILES中选择C++   SOURCE   FILE,在FILE中输入a.cpp,按OK 
----   3.在FILE-   > NEW-   > FILES中选择TEXT文件,在FILE中输入a.h,按OK   
----   4.在FILE-   > NEW-   > FILES中选择TEXT文件,在FILE中输入a.def,按OK   

----   5.源文件: 

代码     
//--------------------------- 
//a.cpp 
#include   <   windows   > 
WINAPI   int   add(int   a,int   b) 
{   return   (a+b); 

//--------------------------- 
//a.h 
WINAPI   int   add(int   a,int   b); 
//--------------------------- 
//a.def 
LIBRARY             "a ";指出DLL的名字 
DESCRIPTION     'a   Windows   Dynamic   Link   Library ' 
;描述DLL的用途(此句可选) 
EXPORTS             add;导出函数的名字   


------6.编译成a.dll 
------7.将a.dll复制到windows/system/目录下面 

二、建立vb程序 
在form1中输入 

代码     

Option   Explicit 
Private   Declare   Function   add   Lib   "a.dll "   (ByVal   a   As   Integer,   ByVal   b   As   Integer)   As   Integer 


Private   Sub   Command1_Click() 
Text3.Text   =   Str(add(Val(Text1.Text),   Val(Text2.Text))) 
End   Sub 
  


程序界面如下图: 


我在编程过程中遇到的问题: 
在将a.dll复制到程序目录下之后(此时我没有将a.dll复制到windows/system/目录下面),运行程序,结果报错!如下图: 


后来我将a.dll复制到E:盘,将 

代码     
Private   Declare   Function   add   Lib   "a.dll "   (ByVal   a   As   Integer,   ByVal   b   As   Integer)   As   Integer改为Private   Declare   Function   add   Lib   "E:/a.dll "   (ByVal   a   As   Integer,   ByVal   b   As   Integer)   As   Integer   


,再次运行程序,也成功了! 
不知道这是什么原因,书上说通常调用DLL时所需的DLL文件必须位于以下三个目录之一: 

  (1)Windows的系统目录:\windows\system; 

  (2)DOS中path所指出的任何目录; 

  (3)程序所在的目录。 
不知道我在满足第三个条件的情况下,为什么会出错? 
================================================= 
21:36   2003-12-3 
今天晚上,我到图书馆去看书,终于明白了为什么下午的程序会出错了. 

最主要的原因是因为按F5执行程序时,程序还是处于调试阶段,所以它找不 

到a.dll,想到这里,我把程序MAKE为应用程序,终于一切正常了。真是感到很欣 

慰~