如何通过dll文件生成对应的lib文件(开发人员的一个小技巧)
如若转载,请尊重个人劳动,务必注明原始出处。iihero 2008-9-28于CSDN
转载自:http://blog.csdn.net/iihero/archive/2008/09/28/2990946.aspx
前几天,偶然从论坛里看到帖子,有人问:
手头只有oci.dll文件,似乎对应的头文件也有。但是就是找不到对应的lib文件。想让人家邮件发给他一个。
我回忆了一下,好像微软的VC开发工具包里头,有命令可以直接生成对应的lib文件,这样,对于开发人员来说,只要有相应版本的dll文件和头文件,无须对应的lib文件,一样可以隐式加载dll,生成可以执行程序。
其实,现在,想链接某dll,无非两种方式:
1. 编译时通过导入库,进而链接dll,Unix下则通过-l链接指令链接具体的动态库,windows下通过
link /MAP /SUBSYSTEM:CONSOLE /out:<file>.exe *.obj <abc>.lib 来链接
2. 在程序里显式的加载动态库,dlopen/LoadLibrary的API调用可以实现此任务,这时是不需要lib文件的。
当然,对于Unix/Linux平台而言,静态库动态库,都是通过-l指令来编译完成的。只是运行期,如果是动态库,则需要对应的.so,如果是静态库,不需要对应的.a静态库文件。
下面,我就介绍:已知dll文件,如何得到我们第一种方式要用到的导入库lib文件?
这里以PostgreSQL数据库的libpq为例,在%PGHOME%/bin下边有一个动态库文件libpq.dll,它是PostgreSQL客户端要用到的唯一的一个库文件。利用VC带的工具depends,我们看到它里边导出了很多API函数,如下图:
好,我们下边先进入Visual Studio .net 2003 command prompt,这个在你安装的VS的菜单或者对应的目录里边,一般都是一个批处理器文件:VSVars**.bat之类的,我这里就用VC6来演示,效果是一样的:
Microsoft Windows XP [版本 5.1.2600]
(C) 版权所有 1985-2001 Microsoft Corp.
D:/msdev/VC98/Bin>cp d:/pgsql8.3.3/bin/libpq.dll f:/t/
D:/msdev/VC98/Bin>cd /d f:/t/
F:/t>dumpbin /EXPORTS libpq.dll > libpq.txt
F:/t>more libpq.txt
Microsoft (R) COFF Binary File Dumper Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
Dump of file libpq.dll
File Type: DLL
Section contains the following exports for LIBPQ.dll
0 characteristics
484CFEC1 time date stamp Mon Jun 09 17:58:25 2008
0.00 version
1 ordinal base
140 number of functions
140 number of names
ordinal hint RVA name
17 0 000011FE PQbackendPID
36 1 000011DB PQbinaryTuples
122 2 0000111D PQcancel
48 3 00001325 PQclear
72 4 000011C2 PQclientEncoding
F:/t>
我们要注意的一个重要的参数列ordinal列是表示右边的API在dll中的相对序号,这个在后边的def文件里头很重要。
然后使用UltraEdit等带列模式的编辑器,编辑libpq.txt,编辑成文件libpq.def,格式如下:
EXPORTS
PQbackendPID @ 17
PQbinaryTuples @ 36
PQcancel @ 122
PQclear @ 48
PQclientEncoding @ 72
PQcmdStatus @ 42
PQcmdTuples @ 44
PQconndefaults @ 3
PQconnectPoll @ 79
PQconnectStart @ 80
PQconnectdb @ 1
PQconnectionNeedsPassword @ 140
PQconnectionUsedPassword @ 138
PQconninfoFree @ 78
PQconsumeInput @ 26
PQdb @ 7
PQdescribePortal @ 134
PQdescribePrepared @ 133
PQdisplayTuples @ 51
PQdsplen @ 112
PQencryptPassword @ 128
PQendcopy @ 31
PQenv2encoding @ 73
PQerrorMessage @ 15
PQescapeBytea @ 89
PQescapeByteaConn @ 127
PQescapeString @ 88
PQescapeStringConn @ 126
PQexec @ 21
PQexecParams @ 101
PQexecPrepared @ 110
PQfformat @ 109
PQfinish @ 4
PQflush @ 81
PQfmod @ 41
PQfn @ 32
PQfname @ 37
PQfnumber @ 38
PQfreeCancel @ 121
PQfreeNotify @ 87
PQfreemem @ 95
PQfsize @ 40
PQftable @ 107
PQftablecol @ 108
PQftype @ 39
PQgetCancel @ 120
PQgetCopyData @ 105
PQgetResult @ 24
PQgetisnull @ 47
PQgetlength @ 46
PQgetline @ 27
PQgetlineAsync @ 29
PQgetssl @ 114
PQgetvalue @ 45
PQhost @ 10
PQinitSSL @ 124
PQisBusy @ 25
PQisnonblocking @ 82
PQisthreadsafe @ 129
PQmakeEmptyPGresult @ 49
PQmblen @ 64
PQnfields @ 35
PQnotifies @ 22
PQnparams @ 131
PQntuples @ 34
PQoidStatus @ 43
PQoidValue @ 71
PQoptions @ 13
PQparameterStatus @ 97
PQparamtype @ 132
PQpass @ 9
PQport @ 11
PQprepare @ 118
PQprint @ 50
PQprintTuples @ 52
PQprotocolVersion @ 98
PQputCopyData @ 103
PQputCopyEnd @ 104
PQputline @ 28
PQputnbytes @ 30
PQregisterThreadLock @ 125
PQrequestCancel @ 6
PQresStatus @ 66
PQreset @ 5
PQresetPoll @ 83
PQresetStart @ 84
PQresultErrorField @ 106
PQresultErrorMessage @ 65
PQresultStatus @ 33
PQsendDescribePortal @ 136
PQsendDescribePrepared @ 135
PQsendPrepare @ 119
PQsendQuery @ 23
PQsendQueryParams @ 102
PQsendQueryPrepared @ 111
PQserverVersion @ 113
PQsetClientEncoding @ 85
PQsetErrorVerbosity @ 99
PQsetNoticeProcessor @ 20
PQsetNoticeReceiver @ 100
PQsetdbLogin @ 2
PQsetnonblocking @ 86
PQsocket @ 16
PQstatus @ 14
PQtrace @ 18
PQtransactionStatus @ 96
PQtty @ 12
PQunescapeBytea @ 94
PQuntrace @ 19
PQuser @ 8
appendBinaryPQExpBuffer @ 74
appendPQExpBuffer @ 91
appendPQExpBufferChar @ 68
appendPQExpBufferStr @ 75
createPQExpBuffer @ 77
destroyPQExpBuffer @ 76
enlargePQExpBuffer @ 130
initPQExpBuffer @ 69
lo_close @ 54
lo_creat @ 58
lo_create @ 123
lo_export @ 62
lo_import @ 61
lo_lseek @ 57
lo_open @ 53
lo_read @ 55
lo_tell @ 59
lo_truncate @ 137
lo_unlink @ 60
lo_write @ 56
pg_char_to_encoding @ 115
pg_encoding_to_char @ 92
pg_utf_mblen @ 93
pg_valid_server_encoding @ 116
pg_valid_server_encoding_id @ 139
pgresStatus @ 63
pqsignal @ 117
printfPQExpBuffer @ 90
resetPQExpBuffer @ 70
termPQExpBuffer @ 67
接着使用lib命令即可生成对应的导入库及导出文件libpq.lib和libpq.exp,libpq.lib文件你终于可以得到了。
F:/t>lib /def:libpq.def
Microsoft (R) Library Manager Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
LIB : warning LNK4068: /MACHINE not specified; defaulting to IX86
Creating library libpq.lib and object libpq.exp
F:/t>dir libpq.*
驱动器 F 中的卷没有标签。
卷的序列号是 4CDC-CD55
F:/t 的目录
2008-09-28 10:44 6,868 libpq.def
2008-09-28 10:36 167,936 libpq.dll
2008-09-28 10:46 16,299 libpq.exp
2008-09-28 10:46 28,488 libpq.lib
2008-09-28 10:37 6,268 libpq.txt
5 个文件 225,859 字节
0 个目录 1,673,240,576 可用字节
F:/t>
这个文件拿到你的vc6程序当中,直接可以使用。
当然如果是用vc7, vc71, vc8, vc9,那就拿对应命令行环境控制台窗口进去执行上述命令就可以了。
当然,上述方法,一样适用于C++生成的dll。只不过那些导出符号可读性不会那么好了。
最后总结一下,感觉,长期以来,我们习惯了使用微软的Visual Studio IDE,对于普通的命令行使用,反而感到有些茫然,这种现象不太正常,其实,应该像在Unix平台下边一样,学会使用基础的编译命令和makefile的手动编写,那样,你完全可以脱离编译器,使用gvim等编辑器,进行开发,这样反而更能加深对编译链接生成可执行码,有一个比较清晰的思路。
好像新的vc9里头,dll文件中可以有强链接,即,它能指定自己依赖的dll的全路径,那么有些东西是不是发生变化,还有待进一步验证。但是对于传统的dll(相信工业级软件不至于傻到所有dll全用vc9的最新特性来生成),上述方法,依然是一个补救措施。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/iihero/archive/2008/09/28/2990946.aspx
从dll导出lib
版权声明
本文为原创作品,请尊重作者的劳动成果。转载必须保持文章完整性,并以超链接形式注明原始作者“tingsking18”和主站点地址,方便其他朋友提问和指正。
转载自:http://blog.csdn.net/tingsking18/archive/2010/03/18/5394466.aspx
一、使用VC++的工具DUMPBIN将DLL中的导出函数表导出到一定义(.DEF)文件
EXAMPLE:
DUMPBIN VideoDeCoder.dll /EXPROTS /OUT:VideoDeCoder.def
二、将导出的.DEF文件整理为一符合.DEF个数的函数导出文件
EXAMPLE:VideoDeCoder.DEF 文件内容如下Dump of file VideoDeCoder.dll
File Type: DLL
Section contains the following exports for VideoDeCoder.dll
0 characteristics
3D49E48F time date stamp Fri Aug 02 09:46:55 2002
0.00 version
1 ordinal base
11 number of functions
11 number of names
ordinal hint RVA name
1 0 00010F60 _TM_ClearDecoderBuff@4
2 1 00010E80 _TM_CloseDecoder@4
3 2 00010F00 _TM_DecodePicture@4
4 3 00010ED0 _TM_DecodePictureHeader@4
5 4 00010FD0 _TM_GetFileEnd@4
6 5 00011030 _TM_GetUValue@4
7 6 00011060 _TM_GetVValue@4
8 7 00011000 _TM_GetYValue@4
9 8 00010E10 _TM_OpenDecoder@8
10 9 00010F30 _TM_ReturnType@4
11 A 00010F90 _TM_SetFileEnd@8
Summary
2000 .data
1000 .rdata
1000 .reloc
15000 .text
按照以下方法整理:
1)添加LIB说明 LIBRARY "VideoDeCoder" ;"xx"为DLL名称
DESCRIPTION "VideoDeCoder library"
2)去掉导出函数说明端以外的内容,在LIB说明下添加 "EXPROTS" 说明导出函数 LIBRARY "VideoDeCoder"
DESCRIPTION "VideoDeCoder library"
EXPORTS
ordinal hint RVA name
1 0 00010F60 _TM_ClearDecoderBuff@4
2 1 00010E80 _TM_CloseDecoder@4
3 2 00010F00 _TM_DecodePicture@
4 3 00010ED0 _TM_DecodePictureH
5 4 00010FD0 _TM_GetFileEnd@4
6 5 00011030 _TM_GetUValue@4
7 6 00011060 _TM_GetVValue@4
8 7 00011000 _TM_GetYValue@4
9 8 00010E10 _TM_OpenDecoder@8
10 9 00010F30 _TM_ReturnType@4
11 A 00010F90 _TM_SetFileEnd@8
3)将所有的函数放至行首,去掉 "hint" 和 "RVA" 数据,留下函数的序号 "ordinal" ,在序号前加上 "@" 符号 形成 "_导出函数名@参数字节和 @序号" 此种格式(__stdcall 方式调用导出的函数符号是 "函数名称@参数字节和"). 最后形成.DEF文件如下: LIBRARY "VideoDeCoder"
DESCRIPTION "VideoDeCoder library"
EXPORTS
TM_ClearDecoderBuff@4 @1
TM_CloseDecoder@4 @2
TM_DecodePicture@4 @3
TM_DecodePictureHeader@4 @4
TM_GetFileEnd@4 @5
TM_GetUValue@4 @6
TM_GetVValue@4 @7
TM_GetYValue@4 @8
TM_OpenDecoder@8 @9
TM_ReturnType@4 @10
TM_SetFileEnd@8 @11
三、使用VC++的LIB工具,带/DEF:(.def文件名) /MACHINE:IX86(80X86机器),就输出符合VC++格式的的LIB文件了.
EXAMPLE:LIB /DEF:VideoDeCoder.def /MACHINE:IX86
四、接时带上LIB文件链接;注意的是当有些动态库DUMPBIN的只有函数名,无"@nn"的参数格式,如C++Builder写的DLL,输出就只有函数名符号,链接时就会报错: error LNK2002:unresolved external symbol "functionname@nn" 提示程序中引入的函数符号无法识别,这时只要将DEF文件中相应的函数名称改为functionname@nn方式,重新建立 LIB,重新链接即可.
最后还有一句,要自动生成.h文件好象是不行的.因为dll里没有保存函数原型,需要反汇编并分析代码才知道每个函数的参数情况.
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/tingsking18/archive/2010/03/18/5394466.aspx