最近工作中遇到需要调用别人的动态链接库,但是只有个dll文件,别的一概没有,这可怎么办呢。还有不少dll导出的都是类,直接显式调用不太方便,最后综合网上的办法,自己再写两个工具,终于实现了将dll导出lib文件,并同时生成.h头文件。
还是自己动手才能丰衣足食啊。
=========================================================================
问题:如果手上只有一个DLL文件,没有lib文件.h头文件,程序里怎么调用它
方法当然很简单,
先用VC的工具Depends.exe查看导出函数的函数名啊
用IDAPro或者其他反汇编工具分析函数原型
再用API函数:LoadLibrary,GetProcAddress
完成!
但是……如果Dll导出的是一个个的类呢,这就稍微有点麻烦
========================================================================
方法1:还是用显式调用,LoadLibrary,GetProcAddress,
这时候就要在头文件里声明一个个的“类成员函数的函数指针”了,
把GetProcAddress返回值赋给这些指针,使用时调用指针即可。
如何知道类的成员函数原型是长什么样的呢?
还是Depends工具,如果直接看,会发现导出函数名中有好多"?","@"等符号,
Depends的上面有个按钮"C++"(如果没有这个按钮,说明你的Depends太老了,下载个新的吧),点了这个按钮,再看看函数名有啥变化,是不是变得比较好理解了
不过Depends解析得还不够完全,看不出来成员函数是public、protected还是private,也不知道调用约定是__cdecl、__stdcall还是__fastcall,是虚函数还是静态成员函数。
如果要知道这些,还是用VC的undname.exe看得比较全面。
=======================================================================
方法2:用lib文件进行隐式链接,这样无需LoadLibrary,个人感觉比较方便的
如何生成lib文件呢,假设动态链接库名为example.dll,步骤如下
1、执行dumpbin.exe/EXPORTS example.dll>example.def
生成了一个def文件,里面的内容大概是下面这样:
ordinal hint RVA name
1 0 00004570?function1@@
2 1 00004540?function2@@
2、编辑这个def文件,删掉没用的信息,将它整理成这样的格式 :
LIBRARY "example"
EXPORTS
?function1@@ @1
?function2@@ @2
上面的@1和@2是根据第1个步骤中的ordinal序号来的
这个步骤我写了个程序HandleDef.exe来自动修改,否则太多函数的话手动改就累死了
3、运行lib.exe/def:example.def
生成了example.lib和example.exp文件。这个lib文件就可以在VC里用了,
比如这样 #pragma comment(lib,"example.lib")
4、新建一个文件example.tmp,里面保存函数名
?function1@@
?function2@@
然后运行undname.exeexample.tmp>example.txt
这样函数名就解析到example.txt文件里了
5、自己写了个HandleTxt.exe程序,把example.txt转换为example.h
转换后变成类似下面这样:
1. class __declspec(dllimport) CExample
2. {
3. public:
int
function1(void);
4. public: void function2(
char
);
5. };
这个样子的基本就能直接拷到VC里用了。
不过,如果自己的程序要用到构造函数来新建一个对象的话,对导入类进行声明的时候要事先分析好类对象的内存分布(这可不是个简单的事啊),上面这个CExample类应该这样声明
1. class __declspec(dllimport) CExample
2. {
3. public:
int
function1(void);
4. public: void function2(
char
);
5. public:
BYTE
m_data[256];
6. };
//上面m_data具体多少个字节,要靠自己反汇编分析,没法自动生成,具体方法比较麻烦,有兴趣的可以去网上查一些C++类的反汇编资料。
==========================================
总结:
为了方便,把以下内容写到一个批处理文件中
set name=example
dumpbin.exe/EXPORTS %name%.dll>%name%.def
HandleDef.exe %name%.def
lib.exe /def:%name%.def /MACHINE:IX86
undname.exe %name%.tmp>%name%.txt
HandleTxt.exe %name%.txt
执行完之后生成lib文件和h文件。
=========================================
上面提到的HandleDef.exe和HandleTxt.exe是我自己用C#写的小程序。
写了这么多,也不知道有没有人会感兴趣。
注:我这个还只是适用于VC编写的dll导出的类
如果用extern"c"导出的函数,除了自己反汇编分析原型,貌似没有别的办法
如何调用非VC编译器编译出来的类,暂时未研究过。
下载地址:
http://pan.baidu.com/netdisk/singlepublic?fid=795627_2574562052
最近工作中遇到需要调用别人的动态链接库,但是只有个dll文件,别的一概没有,这可怎么办呢。还有不少dll导出的都是类,直接显式调用不太方便,最后综合网上的办法,自己再写两个工具,终于实现了将dll导出lib文件,并同时生成.h头文件。 还是自己动手才能丰衣足食啊。=====================================================
各位从事应用开发工作的小伙伴们,我们在以往的项目开发工作中经常会调用三方的
DLL
,突然有一天我们发现
DLL
的.
LIB
和.H
文件
丢失了,这让我们无法应用该
DLL
到我们的项目中,是不是感觉相当的郁闷。现在让我分享一种方法给大家去解决这个问题。
首先我们得获取该
DLL
得
导出
函数,就是知道我们能使用该库得哪些函数名。我们可以用dumpbin 这个命令查询
DLL
中的
导出
函数。例如我们有Test.
dll
这个动态库。
DUMPBIN /EXPORTS DTest.
dll
ordinal hin
1.选择生成.
dll
项目
文件
;
2.编写自己的多个.h和.cpp
文件
, 当功能函数,或者所需要的接口或者类都给完成了之后,选择生成(而不是点击调试运行 Crtl+F5)
3.将生成的*.
dll
和*.
lib
文件
都直接
导出
到自定义的指定目录
4.VS 生成*.exe
文件
到指定目录
5.包含指定的.h和.
lib
文件
夹,方便使用和调用。
1 基本概念
1.1 动态链接库
库是写好的现有的,并且可以复用的代码。现实开发中每个程序都要依赖很多基础的底层库,不可能每个功能都从零开始开发,因此库是必须存在的。库的本质是一种可执行的二进制
文件
,可以被操作系统加载到内存中执行,库有两种:静态链接库(简称为静态库)和动态链接库(简称为动态库),所谓静态、动态是指链接,一个程序编译成可执行
文件
步骤如下图所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FgwmgSGt-1646739553600)(img\编译过程.PN
如果要在 Python 中读取 Excel
文件
并生成 .h
头文件
,可以使用 pandas 库。首先,使用 pandas 的 read_excel() 函数读取 Excel
文件
,然后使用 to_csv() 函数将数据转换为 CSV 格式,最后使用 csv 模块将 CSV
文件
写入 .h
头文件
即可。
以下是一个简单的示例代码:
import pandas as pd
import csv
# 读取 Excel
文件
df = pd.read_excel('file.xlsx')
# 将数据转换为 CSV 格式
df.to_csv('file.csv', index=False, quoting=csv.QUOTE_NONNUMERIC)
# 将 CSV
文件
写入 .h
头文件
with open('file.h', 'w') as f:
f.write('#ifndef FILE_H\n')
f.write('#define FILE_H\n\n')
with open('file.csv', 'r') as csv_file:
reader = csv.reader(csv_file)
for row in reader:
f.write(' '.join(row) + '\n')
f.write('\n#endif')
在这段代码中,首先使用 pandas 的 read_excel() 函数读取 Excel
文件
,然后使用 to_csv() 函数将数据转换为 CSV 格式。接着,使用 csv 模块的 reader() 函数读取 CSV
文件
,并使用 for 循环将数据写入 .h
头文件
。