Windows 环境下 Visual C++ 、GCC 、Visual Basic6 动态访问DLL库应注意的有关事项
一 前言
前几天,遇到使用古老的Visual Basic6 访问DLL动态库的情况,并顺便探讨了C++ 动态加载DLL的情况,作为总结记录如下。
1 环境
- 操作系统:Win10 专业版
- Visual studio 2019
- mingw-w32 Gcc 在Windows环境的编译器
- Visual Basic6
2 提供的资料
DLL 库文件、DLL 库文件中使用的头文件、DLL 库输出函数的说明书
二 探索DLL常用的工具
DLL 库文件有哪些输出函数可供调用?输出函数的偏移地址是多少?这些信息可通过工具进行查看。常用的查看DLL 信息的工具有微软的dumpbin和Nir Sofer 的DLL Export Viewer。
1 dumpbin.exe
dumpbin 包含在 visual studio 开发套件中,可在Tools文件夹下查找。在dumpbin所在的文件夹,打开命令行窗口,执行之。
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30037\bin\Hostx86\x64
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30037\bin\Hostx86\x86
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30037\bin\Hostx64\x86
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.29.30037\bin\Hostx64\x64
dumpbin /EXPORTS F:\tmp\aeobb32.dll
2 Nir Sofer 开发的 DLL Export Viewer 工具
- 运行 dllexp.exe
- 选择 DLL:点击“浏览按钮进行选择”
- 点击“确认”,输出如下
三 Visual Basic开发平台使用DLL 的步骤及应注意事项
1 VB中使用DLL中函数的步骤
- 数据类型的声明
- 使用DLL函数的声明
- 调用DLL函数
- 关闭DLL库
2 C语言中的类型定义转换为 Visual Basic中的自定义类型
如果DLL不是VB编写的,就涉及到变量类型转换问题。譬如DLL是由C语言编写的,其struct结构类型就必须转换为VB环境下的自定义类型。
// C 语言中的结构类型定义
struct inpstr
{
double vreq;
long total;
char fancode[31];
char serie[4];
float t_jkgmvv;
};
' 在VB中的类型声明
Type inpstr
vreq As Double
total As Long
fancode As String * 31
serie As String * 4
t_jkgmvv as single
End Type
3 声明引入DLL的函数
函数声明要严格按照DLL中函数的格式进行,下面举例说明。
Public Declare Function calc_fan _
Lib "aeobb32.dll" _
Alias "_calc_fan@4" (ByRef inppar As inpstr) _
As Long
-
VB中声明的函数名
-
动态库文件
-
动态库中实际的函数名
-
函数参数,使用在VB中转换后的类型
-
函数的返回类型
4 应注意的事项
- 对字符串的赋值,一般在末尾加上 chr$(0)【因为C语言的字符串是以"\0"作为分隔的,想必是为了确保传入的字符串参数以"\0"结束。
' 给 VB的结构体赋值
With inppar
.vreq = 2000
.total = 1
.fancode = "" & Chr$(0)
.serie = "TLZ" & Chr$(0)
.t_jkgmvv = 23.34
End With
四 Visual C++ 开发平台动态加载DLL 的步骤及应注意事项
1 首先确定编译类型是32位或是64位
如果 DLL库是32位的,为了确保使用 LoadLibrary函数顺利加载DLL动态库,最好选择 32位编译器。
对于 Visual Studio 2019,在创建项目时,选择
2 选择 X86 编译(32位),如果选择 X64,程序会出错。
3 部分程序源码
#include <iostream>
#include <Windows.h>
#include "aeobb32.h"
#include <string>
#include <stdlib.h>
#include <tchar.h>
//定义引入函数指针
typedef long (WINAPI* FPSETDLLPATH)(char* DLLpath);
typedef long (WINAPI* FPcalc_fan)(const struct inpstr* InpPar);
typedef long (WINAPI* FPget_working_data)(struct outstr* const OutRow, long Row);
int main()
{
struct inpstr inpstr_;
struct outstr out_;
inpstr_.vreq = 2000;
inpstr_.preq = 1000;
inpstr_.diameter = 0;
inpstr_.rotq = 1.2;
inpstr_.ro20 = 1.2;
inpstr_.total = 1;
inpstr_.debug_level = 0;
strcpy_s(inpstr_.fancode, "");
strcpy_s(inpstr_.serie, "TLZ");
inpstr_.isfreout = 1;
FPSETDLLPATH SETDLLPATH;
FPcalc_fan calc_fan;
FPget_working_data get_working_data;
HINSTANCE hInstLibrary = LoadLibrary(_T("E:\\tmp\\LoadDll_test\\aeobb32.dll"));
SETDLLPATH = (FPSETDLLPATH)GetProcAddress(hInstLibrary, "_SETDLLPATH@4");
calc_fan = (FPcalc_fan)GetProcAddress(hInstLibrary, "_calc_fan@4");
get_working_data = (FPget_working_data)GetProcAddress(hInstLibrary, "_get_working_data@8");
char DLLpath[] = "E:\\tmp\\LoadDll_test\\database";
long lRet = SETDLLPATH(DLLpath);
long CalcRis = calc_fan(&inpstr_);
//long out_result = get_working_data(&out_, CalcRis);
long out_result = get_working_data(&out_, 0);
printf("sizeof char:%d \n", sizeof(out_.t_codven));
printf("sizeof long:%d \n", sizeof(out_.t_palava));
printf("sizeof float:%d \n", sizeof(out_.t_jkgmvv));
printf("sizeof double:%d \n", sizeof(out_.t_phifun));
printf("t_codven:%s \n", out_.t_codven);
printf("t_palava:%d \n", out_.t_palava);
printf("t_jkgmvv:%f \n",out_.t_jkgmvv);
printf("t_phifun:%f \n", out_.t_phifun);
FreeLibrary(hInstLibrary);
getchar();
}
4 类型的转换问题
如果形参的类型是 LPCWSTR,如果实参是"const char *" 类型,必须进行转换,宏 _T是转换方式之一。
_T("E:\\tmp\\LoadDll_test\\aeobb32.dll")
五 mingw即Gcc 开发平台动态加载DLL库文件的步骤及应注意事项
如果 DLL库是32位的,为了确保使用 LoadLibrary函数顺利加载DLL动态库,编译器最好选择 32位编译器。其它方面与Visual studio 相同。
2022-11-12
*" 类型,必须进行转换,宏 _T是转换方式之一。
_T("E:\\tmp\\LoadDll_test\\aeobb32.dll")
五 mingw即Gcc 开发平台动态加载DLL库文件的步骤及应注意事项
如果 DLL库是32位的,为了确保使用 LoadLibrary函数顺利加载DLL动态库,编译器最好选择 32位编译器。其它方面与Visual studio 相同。
2022-11-12