|
最简单省事的办法就是用 _declspec(dllexport) 来修饰了.这种方法简单.而且直接就可以在DLL实现源码中的函数中加上.非常省事.
另一种就是使用DEF文件导出了.这种方法需要有一个DEF文件.大致格式如下:
EXPORTS
MyDLLFuncUserCall
最简单的写法就这样.关于def文件中的注释.这个注释符号就不像C++中使用的那个 //或/* */了
而是用 ; 号 .哈.跟汇编中的注释符号一样.
DEF文件可以很灵活的控制导出函数的格式.
偶们知道DLL除了可以按名字导出还可以按序号导出.额..好像是废话哦.
EXPORTS
MyDLLFunc_1
MyDLLFunc_2
这样子做导出的话.虽然没有显式指写导出的序号.但是VC链接器(偶用的是VC6其它版本的没有试)
为自动帮偶们弄上序号.序号的基数是从1开始.而且是按你所提供的def文件中函数名出现的顺序从上往下排.
随便用一些PE查看工具就能看到.比如像这样子的:
MyDLLFunc_1 rva: 00004E30 ord: 1
MyDLLFunc_2 rva: 00002F60 ord: 2
ord: 后面的就是序号.
既然说def文件灵活.那么偶们就可以改变这个序号.当然序号不可以重复.(又是废话.)
把 def 文件的内容替换成以下这个样子.
EXPORTS
MyDLLFunc_1 @3
MyDLLFunc_2
编译后用PE工具查看内容如下:
MyDLLFunc_1 rva: 00004E30 ord: 3
MyDLLFunc_2 rva: 00002F60 ord: 4
序号改了.而且虽然偶们没有指定 MyDLLFunc_2 的序号.链接器自动会以你有指定的最小序号做为基数给那些没有显式指定序号的函数编号.顺序还是跟上面说的一样.按导出函数名在DEF文件中出现的顺序来.
再看另一种情形.偶们把序号断开(也就是不让序号连续)
把def 文件的内容换成下面这个样子:
EXPORTS
MyDLLFunc_1 @3
MyDLLFunc_2 @5
MyDLLFunc_3 @7
MyDLLFunc_4
MyDLLFunc_5
再用工具查看结果如下:
MyDLLFunc_1 rva: 00004E30 ord: 3
MyDLLFunc_4 rva: 00003A10 ord: 4
MyDLLFunc_2 rva: 00002F60 ord: 5
MyDLLFunc_5 rva: 00003C70 ord: 6
MyDLLFunc_3 rva: 000034A0 ord: 7
做了上面的几种方式的测试.不难发现链接器导出DLL函数的规则.
1.如果程序作者显示指定了序号则按其指定的序号将函数导出.
2.如果导出的序号不连续,并且需要被导出的函数中还有一部分没有显式指定导出序号.那么链接器会使用已被显式指定的序号中的最小的那个做为基数并按导出函数名在文件中出现的顺序为这些函数编号.
大概了解了序号之后.再来看看函数名.
1.按别名导出:
什么意思呢.假设有这么一种情形:自己的代码中的某个函数现在想要将它导出供别人调用.但是可能函数名原先取得不是太好.别人使用看函数名可能会选成歧义. 所以这个时候就可以派上用场了.当然了如果直接去代码中修改那个函数也是可以的.不过要是DLL内部中的函数也用到了这个函数那么也要一并改掉了.好像有点烦琐哦.用别名吧.
把 def 文件的内容换成这样子:
EXPORTS
AliasName=MyDLLFunc_1
MyDLLFunc_2
AliasName 这个就是别名了.AliasName这个函数在DLL中根本不存在而MyDLLFunc_1是存在的.
用PE工具查看结果:
AliasName rva: 00004E30 ord: 1
MyDLLFunc_2 rva: 00003C70 ord: 2
2.只按序号导出,不导出函数名.
意思就是只有序号没有函数名.(什么?不导出序号也不导出函数名? 链接器不答应.)
把 def 文件内容换成这样子:
EXPORTS
MyDLLFunc_1 @3 NONAME
MyDLLFunc_2 @5 NONAME
用PE工具查看结果:
No name rva: 00004E30 ord: 3
No name rva: 00002F60 ord: 5
呼呼~~~ 再也不用为取名字为难了~~哈.
def文件的用途还有很多.比如指定DLL的SECTION 的一些属性.指定基址了等. 目前只了解这么点.
|
|