dll是非常实用代码复用机制,所有的方法在物理内存或者disk page中只有一份,数据可以是一份也可以定义为多份。这就为数据,方法共享和多任务操作,提供了非常大的便利。
——————>dll
dll当然是PE格式的文件,就像许多其他含有公用方法的文件一样,这些功能上都算是动态链接库。
当然了,关于PE文件,还得另行研究了。
——————>编写要点
1 dll同样可以使用资源,同样可以导入其他动态链接库的函数。
2 dll的方法被某PE使用之后,这个方法就相当于是该PE自身的,没有区别。
3 dll需要一个入口方法,也就是MSDN中的DLLMAIN:
这里得到的_hInstance是dll本身的handle。也是唯一一次dll得到自己的handle 的机会
_dwReason有4种:
DLL_PROCESS_ATTACH
得到这个消息就表示,dll已经载入到线性地址中了。
这里可以做一些申请保留地址,以及初始化工作。
DLL_PROCESS_DETACH
可以做释放内存的工作,或将打开文件关闭等等工作。
DLL_THREAD_ATTACH
得到这个消息的时候,说明这个进程新建了一个线程。
MSDN上说这个时候可以去做一个TLS slot
DLL_THREAD_DETACH
这里可以把做TLS slot的memory 释放。
——————>也是,关于内存的操作一般都写在dll中的,exe都是处理逻辑上的事物,方法和模块都另外封装吧。
4文件的最后结尾是:end 入口方法名
5写完之后,我们还需要写一个def文件,这个是链接器需要的
要是详细了解还是要参看MSDN的”链接”这一个关键词
一个主要的写法就是:
EXPORTS
方法名A
方法名B
…
也可以定义变量。
(因为类里面有公有和私有,而EXPORTS的意思就是公有化。)
——————>link的选项
基本写法就是
/subsystem:windows /Dll /DEF DEF文件名 obj文件 RES文件
——————>
这里面,如果需要数据段共享,那么可以加上个选项/Section .bss,S
MSDN上对这个选项的解释不太明确,还是要参考一篇文章:
http://msdn.microsoft.com/en-us/library/ms809762.aspx
——————>
编译链接之后,会生成需要的dll和lib文件
编程使用的话,需要lib来找dll
要是使用include的方式来加载lib,则需要用写一个prototype列表文件。
——————>
prototype在JavaScript里面有很广泛的应用,但是之前我在C里面是根本没有见过这个词
不过现在MASM里面却是出现了这个伪指令PROTO,其实这个词的意思就是函数声明,是编译器需要的。
感觉一部分用途是生成方法入口地址,另一部分是提供一个函数的参考模板,看看参数的数量类型(这个汇编里面没有返回值数量类型一说。。)是否匹配
prototypelist也就是模板的主要内容了。
所以,prototype就是个set default structure的意思。
——————>
回到dll的使用中
这里有2个扩展应用,一个是动态加载dll。另一个是其他语言加载汇编的dll
————————————>动态加载dll
这个比较麻烦,不过却解决了很多问题。反正大概知道有好处就是了,反正好处越大,代码就越复杂。。
就像传统的C和高级语言相比,写起来慢,但是好处是巨大的,这个不用说的。
动态加载dll涉及到3个API方法:
invoke LoadLibrary,addr szDll
参数是Dll的名字的string,如果成功,返回值是dll的handle(每个进程得到的handle是不一样的)
invoke GetProcAddress,hDllInstance,addr szIncCounter
第二个参数是存有公开的方法名的,string。返回值是方法的入口地址
invoke FreeLibrary,hDllInstance
释放这个dll。
——————>
1。操作系统会给dll上加个计数器,每加载一次+1,每free 1次就-1。当为0时,清楚掉dll在内存中的数据
2。要调用的时候,需要把dll的名称和方法都存到const里面去,这样也是麻烦不小。
3。调用过程,这个方法我们不能使用invoke。应该是编译器认为这只是个地址而不是的proc的缘故。毕竟我们之前没有函数声明。
所以我们变通的写两个数据类型的宏,即用typedef
先做个proto数据类型的宏,然后给这个宏的地址再用typedef做个宏。
_PROCVAR4 typedef proto :dword,:dword,:dword,:dword
_PROCVAR3 typedef proto :dword,:dword,:dword
_PROCVAR2 typedef proto :dword,:dword
_PROCVAR1 typedef proto :dword
_PROCVAR0 typedef proto
PROCVAR4 typedef ptr _PROCVAR4
PROCVAR3 typedef ptr _PROCVAR3
PROCVAR2 typedef ptr _PROCVAR2
PROCVAR1 typedef ptr _PROCVAR1
PROCVAR0 typedef ptr _PROCVAR0
我们就可以定义PROCVARx类型的指针数据了。
这个可以用invoke 来传参数了。
——————>
要让这个lib在C以及C++可以调用,那么,就必须写个头文件了。
要更深一步,比如在C和C++里面动态调用dll。我就不知道了。
头文件大致这样写:
#ifdef __cplusplus
extern “C” {
#endif
__stdcall _IncCounter();
__stdcall _DecCounter();
__stdcall _Mod(unsigned num1,unsigned num2);
#ifdef __cplusplus
}
#endif
在C和C++里面,汇编的返回值,那就是eax中,以unsigned表示了。