vb调用vc++dll文件

VC编程 专栏收录该内容
8 篇文章 0 订阅
  ① 关于DLL的创建与调用

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

  之后将入口函数DLLMain()补充完整,再添加你自定义的函数的代码。如果你自定义的函数很多,可以将这些函数的声明部分统一写入一个头文件中。再在.cpp文件首部用“#i nclude”语句引入这个头文件。注意函数声明前要加上“__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 453)”在调试中耗费1.5天时间在网上找资料解决此问题。

网上指出可能原因:

1。没有注意函数名大小写。DLL中的函数与VB中的函数声明必须大小写完全相同。

2。没有声明入口函数。需要在dll的.def文件中加上入口函数。

    如:EXPORTS

        SetData @1

        GetData @2

    如果DLL工程原本没有使用.def文件,可以自己建立一个加入到工程中。

3。采用了C++编译方式

    在C++中编译函数时会将函数名进行转换。解决的方法有两个:

  (1)如果没有使用C++的类,可以将.cpp文件改名为.c,就不进行这种转换了。

  (2)在函数定义前加上extern "c",如:

       extern "c" void _stdcall kk(double k)

需要指出的是,VC++允许不编写.def文件,而是在函数定义前加

_declspec(dllexport)修饰符,这样的函数也可以被外部程序调用。

 

实际问题所在:(.DEF是关键)

排查完上面可能存在的问题后,发现VB调用时依旧是“找不到DLL入口点”

查看VC程序结构,发现编译时没有将.DEF文件加载进工程里面。

这就导致生成的DLL文件没有外部接口。总结自己还是VC不熟悉所致。

 

出现这一错误的原因是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中调用,运行正常。注意使用了.def文件,就不需要再使用“extern "C" ”了。

 

③ 关于调用约定

  采用②中第二种解决方法,运行,出现错误信息“DLL调用约定错误(Error 49)”。

原因是调用约定共有5种方式:__fastcall、__pascal、__stdcall、__cdecl及__thiscall(成员函数的调用方式,但不能使用它显示声明一个函数),VC++默认调用方式为__cdecl,而VB默认调用方式则为__stdcall。

 

解决方法是,更改代码如下(指定调用方式):

  __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内容:

  //引入预编译头文件  __declspec(dllexport)是关键

  #include “stdafx.h”

  #define CIPHER_API __declspec(dllexport)   //宏替换功能

   //声明我的函数  

  CIPHER_API int __stdcall Encrypt( int p, int k )

 ………… 多个函数…

以上两条语句等价于:

__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;

   }

   //我的函数__stdcall关键

   int __stdcall Encrypt(int p, int k)

   {

       int c = p + k;

       return c;

   }

…多个函数…

…………………

//我的问题:没有将.DEF文件加入工程,导致生成的dll文件调用函数没有入口点

Cipher.def:

  LIBRARY Cipher

  EXPORTS Encrypt

编译后,将Cipher.dll复制到VB程序可执行文件所在目录。

也可以在调用时输入一个完整的路径。

 

在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

  • 1
    点赞
  • 0
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值