windows.dll:Windows下DLL编程技术及应用来源: 发布时间:星期二, 2008年12月30日 浏览:2次 评论:0
摘 要:
本文介绍了DLL技术在Windows编程中基本运用思路方法及应用给出了直接内存访问及端口I/O两个实用DLL全部源代码 关键词: DLL Windows编程 内存访问 I/O 、引 言 由于Windows为微机提供了前所未有标准用户界面、图形处理能力和简单灵便操作绝大多数编制人员都已转向或正在转向Windows编程在许多用户设计实际应用系统编程任务中常常要实现软件Software对硬件资源和内存资源访问例如端口I/O、DMA、中断、直接内存访问等等若是编制DOS这是轻而易举事情但要是编制Windows尤其是WindowsNT环境下就会显得较困难 Windows具有"和设备无关"特性不提倡和机器底层东西打交道如果直接用WindowsAPI或I/O读写指令进行访问和操作运行时往往就会产生保护模式甚至死机更严重情况会导致系统崩溃那么在Windows下怎样方便地解决上述问题呢?用DLL(Dynamic Link Libraries)技术就是良好途径的 DLL是Windows最重要组成要素Windows中许多新功能、新特性都是通过DLL来实现因此掌握它、应用它是非常重要其实Windows本身就是由许多DLL组成它最基本 3大组成模块Kernel、GDI和User都是DLL它所有库模块也都设计成DLL凡是以.DLL、.DRV、.FON、.SYS和许多以.EXE为扩展名系统文件都是DLL要是打开Windows\目录就可以看到许多DLL模块尽管DLL在Ring3优先级下运行仍是实现硬件接口简便途径DLL可以有自己数据段但没有自己堆栈使用和它应用相同堆栈模式减少了编程设计上不便;同时个DLL在内存中只有个例子使的能高效经济地使用内存;DLL实现代码封装性使得简洁明晰;此外还有个最大特点即DLL编制和具体编程语言及编译器无关只要遵守DLL开发规范标准和编程策略并安排正确接口不管用何种编程语言编制DLL都具有通用性例如在BC31中编制DLL可用于BC、VC、VB、Delphi等多种语言环境中笔者在BC31环境下编译了Windows下直接内存访问和端口I/O两个DLL用在多个自制系统应用软件Software中运行良好 2、DLL建立和 DLL建立及思路方法在许多资料上有详细介绍为了节省篇幅在这里仅作些主要概括 1.DLL建立 有关DLL建立有如下几个方面要素是不可缺少和必须掌握: 入口LibMain( ) 就象C中WinMain( )样Windows每次加载DLL时都要执行LibMain( )主要用来进行些化工作通常形式是: FAR PASCAL LibMain(HINSTANCE hInstance,WORD wDataSeg,WORD wHeapSize,LPSTR lpszCmdLine) { (wHeapSize!=0) //使局部堆、数据段可移动 UnlockData(0); //解锁数据段 /*此处可进行些用户必要化工作*/ 1; //化成功 } 出口WEP( ) Windows从内存中卸载DLL时相应出口WEP( )主要做些清理工作如释放占用内存资源;丢弃某些字串、位图等资源;关闭打开文件等等 自定义输出 为了让位于区别内存段应用进行远程自定义输出必须定义为远程(使用FAR关键字)以防使用近程指针而得到意外结果;同时加上PASCAL关键字可加快运行速度使代码简单高效提高运行速度 输出引出思路方法 在DLL模块定义文件中(.DEF)由EXPORTS语句对输出逐列出例如: EXPORTS WEP @1 residentname //residentname可提高DLL效率和处理速度 PortIn @2 PortOut @3 //通常对所有输出附加系列号 在每个输出定义介绍说明中使用_export关键字来对其引出 以上两种思路方法任选其中种即可不可重复后面两个例子分别使用了上述两种区别引出方式请留意 2.DLL 加载DLL时Windows寻找相应DLL次序如下: .当前工作盘 Windows目录;GetWindowsDirectory( )可提供该目录路径名 Windows系统目录即子目录;GetDiretory( )可获得这个目录路径名 DOSPATH命令中罗列所有目录 网络中映象目录列表中全部目录 DLL模块中输出思路方法: 不论使用何种语言对编译好DLL进行时基本上都有两种方式即静态方式和动态方式静态方式由编译系统完成对DLL加载和应用结束时DLL卸载编码(如还有其它使用该DLL则Windows对DLL应用记录减1直到所有相关都结束对该DLL使用时才释放它)简单实用但不够灵活只能满足般要求动态方式是由编程者用API加载和卸载DLL来达到DLL目使用上较复杂但能更加有效地使用内存是编制大型应用时重要方式具体来说可用如下思路方法.在应用模块定义文件中用IMPORTS语句列出所要DLL名如: IMPORTS MEMORYDLL.MemoryRead MEMORYDLL.MemoryWrite 让应用运行时和DLL模块动态链接 先用LoadLibrary加载DLL再用GetProcAddress检取其输出地址获得其指针来如: HANDLE hLibrary; FARPROC lpFunc; PortValue; hLibrary=LoadLibrary("PORTDLL.DLL"); //加载DLL (hLibrary>31) //加载成功 { lpFunc=GetProcAddress(hLibrary,"PortIn"); //检取PortIn地址 (lpFunc!=(FARPROC)NULL) //检取成功则 PortValue=(*lpFunc)(port); //读port端口值 FreeLibrary(hLibrary); //释放占用内存 } 3、DLL应用例子源 1.直接内存访问DLL源代码 //.DEF文件 LIBRARY MEMORYDLL DESCRIPTION 'DLL FOR MEMORY_READ_WRITE ' EXETYPE WINDOWS CODE PRELOAD MOVEABLE DISCARDABLE DATA PRELOAD MOVEABLE SINGLE HEAPSIZE 1024 //DLL无自己堆栈故没有STACKSIZE语句 EXPORTS WEP @1 residentname ReadMemory @2 WriteMemory @3 //.CPP文件 # <windows.h> FAR PASCAL LibMain(HINSTANCE hInstance,WORD wDataSeg,WORD wHeapSize,LPSTR lpszCmdLine) { (wHeapSize!=0) UnlockData(0); 1; } FAR PASCAL MemoryRead(unsigned DosSeg,unsigned DosOff) { WORD wDataSelector,wSelector; char far *pData; char value; wDataSelector=HIWORD((DWORD)(WORD FAR *)&wDataSelector); wSelector=AllocSelector(wDataSelector); //分配选择器 SetSelectorLimit(wSelector,0x2000); //置存取界限 SetSelectorBase(wSelector,(((DWORD)DosSeg)<<4)+(DWORD)DosOff); //置基地址 pData=(char far *)((DWORD)wSelector<<16); value=*pData; FreeSelector(wSelector); //释放选择器 (value); } void FAR PASCAL MemoryWrite(unsigned DosSeg,unsigned DosOff,char Data) { WORD wDataSelector,wSelector; char far *pData; wDataSelector=HIWORD((DWORD)(WORD FAR *)&wDataSelector); wSelector=AllocSelector(wDataSelector); SetSelectorLimit(wSelector,0x2000); SetSelectorBase(wSelector,(((DWORD)DosSeg)<<4)+(DWORD)DosOff); pData=(char far *)((DWORD)wSelector<<16); *pData=Data; FreeSelector(wSelector); } FAR PASCAL WEP( nParam) { 1; } 2.端口读写I/ODLL源代码 //.DEF文件 LIBRARY PORTDLL DESCRIPTION 'DLL FOR PORT_IN_OUT ' EXETYPE WINDOWS CODE PRELOAD MOVEABLE DISCARDABLE DATA PRELOAD MOVEABLE SINGLE HEAPSIZE 1024 //.CPP文件 # <windows.h> # <dos.h> FAR PASCAL LibMain(HINSTANCE hInstance,WORD wDataSeg,WORD wHeapSize,LPSTR lpszCmdLine) { (wHeapSize!=0) UnlockData(0); 1; } FAR PASCAL _export PortOut( port,unsigned char value) { outp(port,value); 1; } FAR PASCAL _export PortIn( port) { result; result=inp(port); (result); } FAR PASCAL _export WEP( nParam) { 1; } 分别将上面两个例子.DEF文件和.CPP文件各自组成个.PRJ文件,并进行编译链接成.EXE或.DLL文件就可以在应用中对其进行 4、结束语 在上面我们利用DLL技术方便地实现了Windows环境下对内存直接访问和端口I/O访问仿效这两个例子还可以编制出更多适合自己应用系统所需DLL如用于数据采集卡端口操作及扩展内存区访问、视频区缓冲区及BIOS数据区操作等许多实际应用编程任务中必要时只需直接更新DLL而用不着对应用本身作任何改动就可以对应用功能和用户接口作较大改善实现版本升级因此掌握好DLL技术对Windows开发者很有裨益 0
相关文章
读者评论
发表评论 |