GEQ(代号而已)是公司最近要做的一个项目,计划先项目后产品。项目是为了解决BDZ的工程计量问题的,BDZ的特点就是多专业多工程,但现在GAEA的产品各自为政,模型不统一。为了充分复用现有产品的功能,初步想法是把公司一些产品整合起来,包括CL,GJ和QI,并在外面包一层GEQ。 如何将这三个产品集成在一起是迫切需要解决的问题,当时直觉想法是采用dll封装的这种方式,很遗憾这个方案是不通的,但在这个过程中收获了很多,作为【GEQ闯关记】的开篇之作,我觉得还是有些份量的。
为什么DLL就不行呢?
采用DLL封装三个产品,本质上这三个产品起来后仍在一个进程内运行,这就意味着所有的接口和类仍然在一个命名空间内。如果相同的名字的接口内方法、属性不一致,实现方式不一致,那么就会出现冲突,遗憾的是现在的CL、GJ和QI真心存在命名冲突的问题,更遗憾的是解决这个问题要改动大量的代码!鉴于目前这三个产品实现现状,结论是最好不采用DLL封装。
DLL相关知识
虽然本次整合产品未能采用DLL,但DLL本身还是蕴含了很多的知识,即使没有借上力,也不能空手而归,简单总结下DLL的相关知识。
什么是DLL
动态链接库是程序模块,它包含代码、数据和资源,能够被其他windows应用程序通过在运行时调用执行的方式进行共享。DLL有利于应用程序的模块化,隐藏实现细节。
每个应用程序将DLL映射到自己的地址空间,同时DLL的数据也随之映射,这样每个应用程序都有自己的DLL数据实例,避免修改全局变量而影响其他应用程序。
显示调用DLL
显示调用DLL时主要采用下述几个函数,在GJ和QI中用这些关键词可以搜索到类似的代码。
- function LoadLibrary(lpLibFileName: PChar): HMODULE; stdcall 调入指定dll模块,将其映射到调用进程的地址空间;
- function FreeLibrary(hLibModule: HMODULE): BOOL; stdcall 减少指定库的实例计数,当实例计数为零时,DLL将会被释放;
- function GetProcAddress(hModule: HMODULE; lpProcName: LPCSTR): FARPROC; stdcall 返回一个函数在模块中的地址;
DLL的入口函数和出口函数
在DLL初始化或者中止化时可以设置DLLProc回调函数,对不同的事件进行处理。
主要包括4个事件,其中前两个比较常用,分别为:DLL_PROCESS_ATTACH, DLL_PROCESS_DETACH。
DLL异常
必须保证Sysutils在DLL的Uses子句里,主要可以把DLL的异常映射为Win32的异常,否则不能处理DLL中的异常。
SaftCall指示符用于COM和异常处理,主要可以确保任何异常都会被传播给函数的调用者,并将异常转换为HResult类型的返回值。
Function Foo(i: Integer): string; Saftcall <==> Function Foo(i: Integer): string; HResult; StdCall。