[原创] VC导入库的导入名修改工具(用于从DLL导入STDCALL函数)
LIBRARY MyDLL
EXPORTS
function
dosomething
此时如果用lib.exe工具从这个def文件生成lib文件,那么这个lib文件将从DLL导入function和dosomething,同时向链接器提供_function和_dosomething。这样的话对于__cdecl方式导出的函数是没有问题的。但是如果DLL的导出符号仍然是function和dosomething,但是调用方式却是__stdcall,就会遇上了问题:如果function有一个int型参数,那么链接器将去寻找_function@4而不是_function,因为找不到符号,所以链接失败了。
如果DLL中导出的符号名是function@4,此时生成的lib就会从DLL导入function@4并向链接器提供_function@4,但是实际上以__stdcall方式调用,但是最后导出的时候不带@nn的情况是非常多的。最典型的情况就是Windows API。而且实话说吧因为@nn这样的实在不怎么好看,所以我自己写DLL的时候也会通过使用DEF文件的方式或者#pragma comment(linker, “/EXPORT:xxxxxx”)这样的预编译语句让导出的函数不带如此的后缀。
于是这样需求就变得简单:让生成的导入库从DLL引入的时候是不带后缀的,但是向链接器提供的符号是带后缀的。
这并非不可能,调用Windows API的时候就是这样:Windows SDK里面那些LIB文件,就是实现这样的功能。对其格式进行研究,根本就是和普通的导入库一样。除了……呃,除了某些细节上的参数。
于是我的目的就是修改这些细节上的参数。Microsoft PE and COFF Specification里也提供了这方面的详细资料。
方法的话,遍历LIB文件中的每个member,LIB文件的格式可以从上面提到的资料中找到,不会太复杂。注意每个member的第一个字节似乎是对其到偶数边界的,没有对齐的用\n来补。在遍历的过程中分析前四个字节就知道这个member是不是声明了一个导入函数,如果是,根据导入的格式分析其头部信息,然后获得DLL名、函数名等。
在这个导入member的“头部信息”中,有关于导入名应该如何计算的属性。但是LIB.exe工具却没有这方面的参数可以调整,默认就是先前面给你加一个_下划线,然后方式是NoPrefix就是再把这个下划线去掉。也就是说,def文件中如果写的是function,那么它就先加一个下划线,变成_function,作为向链接器提供的符号。然后导入名生成方式是NoPrefix,也就是链接器在链接的时候会再从_function去掉前缀的下划线变回function作为从DLL导入的名。
这个导入名的计算方式有
IMPORT_ORDINAL:通过标号导入,此时不会计算导入名
IMPORT_NAME:原原本本的,和向链接器提供的符号保持一致
IMPORT_NAME_NOPREFIX:不带前缀的,LIB.EXE生成的就是这种。前缀是指?、@或者可选的下划线_
IMPORT_NAME_UNDECORATE:不带前缀并且只取@之前的部分,此时如果向链接器提供的符号名是_function@4,那么导入名就是function,也就是我们需要的。
有了这些资料,思路就非常清楚,比如有以下两个函数
__declspec(dllimport) int __stdcall add2(int, int);
__declspec(dllimport) int __stdcall add3(int, int, int);
然后DLL里的导出名分别是add2和add3而不是add2@8和add3@12,此时可以写这样一个DEF文件
LIBRARY doadd
EXPORTS
add2@8
add3@12
此时生成的lib文件中,向链接器提供的符号这一边已经是所需要的_add2@8和_add3@12了。然后这个时候要修正的是导入名计算方式,因为现在是IMPORT_NAME_NOPREFIX,要改成IMPORT_NAME_UNDECORATE才行。这个时候就要用十六进制编辑器来修改,但是手工做这种事情实在太麻烦,这种事情应该给程序去做。所以就写了个工具,来解决这种问题。

图片为修改一个函数的导入名计算方式后的截图。改完以后保存,就可以实现目的了。
这里给出这个自制工具的下载:(上传时间:2014年2月13日。工具有修改的话,这里可能不会同步更新。)
这里下载工具
http://download.csdn.net/detail/fwleiming/6919785
运行需要.net framework 2.0环境。修改完成后记得保存。
里面的DLL其实是COM组件形式的,我在资源里面嵌入了tlb文件,接口应该算是比较简单,想自己在程序里调用的话,要注意最初SetSource的时候送入的指针要在整个操作过程中有效(因为在.net环境中,对象的内存地址是有可能被GC给移动的)
p.s. 这坑爹的论坛我又不是发求助帖怎么还一定要积分……
相关推荐
自制VC导入库导入名计算方式修改工具
自制工具用于解决通过def文件制作的导入库无法从dll导入不带@nn后缀的stdcall函数的问题。需要.net framework 2.0才能运行。
MingW VC 之.a .lib .dll .def 关系
MSVC vs. MinGW 之 (lib,dll,def,obj,exe) vs (a,dll,def,o,exe) 玩转攻略手记 一份粗糙的研究记录,有待补完和整理。 MinGW: c -> o gcc -c a.c c -> exe gcc a.c libs.o -o a.exe (从主程序a.c,附加libs,生成a.exe) o -> exe gcc a.o b.o ... -o main.exe c -> dll,def,a gcc a.c -shared -o a.dll -Wl,--output-def,a.def,--out-implib,liba.a a -> dll a2dll liba.a dll -> a: dlltool --dllname a.dll --def a.def --output-lib liba.a (需要def文件) a -> def: dumpbin /exports lib.a > lib.def (在windows上调用,def需要修改) dll -> def : pexports a.dll -o > a.def (这里的-o是指给函数标序号) lib -> def : reimp -d a.lib lib -> a: (for __cdecl functions in most case) reimp a.lib; (for __stdcall functions) MSVC: c -> lib cl /LD a.c (注意已经定义了export列表) c -> dll cl /LD a.c c -> obj cl /c a.c c -> exe cl a.c /out:a.exe dll ->lib lib /machine:ix86 /def:a.def /out:a.lib (需要def文件) obj ->lib lib a.obj b.obj... /out:mylib.lib dll ->def DUMPBIN a.dll /EXPORTS /OUT:a.def (生成的def需要做修正) lib ->def reimp -d a.lib (这个要在MSYS+MinGW下用) 关于这些工具的适用范围可以很容易的理解和记忆。 dll和exe都是PE文件,所以可以使用pexports. lib和a是静态库文件,都是归档类型,不是PE格式。所以不能使用pexports. dll可以使用dlltool. lib可以使用lib, 和reimp(lib->a工具) 所有的bin文件,包括dll,exe,lib,a都可以使用dumpbin. 参考: http://hi.baidu.com/kaien_space/blog/item/5e77fafa2ba9ff16a8d3110a.html Mingw官网文档: http://www.mingw.org/wiki/MSVC_and_MinGW_DLLs http://oldwiki.mingw.org/index.php/CreateImportLibraries http://www.mingw.org/wiki/FAQ http://hi.baidu.com/opaquefog/blog/item/9b21b6deb324e25dccbf1ab7.html http://qzone.qq.com/blog/8330936-1238659272 http://hi.baidu.com/jzinfo/blog/item/b0aa1d308de99f9da8018e00.html 本篇测试用代码: 1. main.cpp #include #include #include "mylib.h" using namespace std; int main() { char str[]="Hello world!"; printhello(str); return 0; } 2. mylib.cpp #include #include #include "mylib.h" using namespace std; void EXPORT printhello(char *str) { cout << str << endl; } 3. mylib.h #define EXPORT __declspec(
BCB调用VC的DLL
BCB调用VC的DLL
vc调用dev-c++动态链接库dll示例
描述了如何从vc中调用dev-c++写的dll的过程与方法。 1、设置导出关键字__stdcall 2、修改vc调用方式为stdcall 3、实现函数调用call
VC中回调函数(callback)深入解析
通过此文讲解,让希望学好vc的同学真正理解vc中回调函数的结构和意义


工具平台和程序库

