Windows下DLL编程技能及应用
当前位置:以往代写 > C/C++ 教程 >Windows下DLL编程技能及应用
2019-06-13

Windows下DLL编程技能及应用

Windows下DLL编程技能及应用

副标题#e#

摘 要: 本文先容了DLL技能在Windows编程中的根基运用要领及应用,给出了直接内存会见及端口I/O的两个实用DLL的全部源代码。

要害词: DLL Windows编程 内存会见 I/O

一 、引 言

由于Windows为微机提供了前所未有的尺度用户界面、图形处理惩罚本领和简朴灵便的操纵,绝大大都措施体例人员都已转向或正在转向Windows编程。在很多用户设计的实际应用系统的编程任务中,经常要实现软件对硬件资源和内存资源的会见,譬喻端口I/O、DMA、间断、直接内存会见等等 。若是体例DOS措施,这是垂手可得的工作,但要是体例Windows措施,尤其是WindowsNT情况下的措施,就会显得较坚苦。

因为Windows具有"与设备无关"的特性,不倡导与呆板底层的对象打交道,假如直接用Windows的 API函数或I/O读写指令举办会见和操纵,措施运行时往往就会发生掩护模式错误甚至死机,更严重的环境会导致系统瓦解。那么在Windows下奈何利便地办理上述问题呢?用DLL(Dynamic Link Libraries)技能就是精采途径之一。

DLL是Windows最重要的构成要素,Windows中的很多新成果、新特性都是通过DLL来实现的,因此把握它、应用它长短常重要的。其实Windows自己就是由很多的DLL构成的,它最根基的三大构成模块Kernel、GDI和User 都是DLL,它所有的库模块也都设计成DLL。每每以.DLL、.DRV、.FON、.SYS和很多以.EXE为扩展名的系统文件都是DLL,要是打开Windows\System目次,就可以看到很多的DLL模块。尽量DLL在Ring3优先级下运行,仍是实现硬件接口的轻便途径。DLL可以有本身的数据段,但没有本身的仓库,利用与挪用它的应用措施沟通的仓库模式,淘汰了编程设计上的未便;同时,一个DLL在内存中只有一个实例,使之能高效经济地利用内存;DLL实现的代码封装性,使得措施简捷明了;另外尚有一个最大的特点,即DLL的体例与详细的编程语言及编译器无关,只要遵守DLL的开拓类型和编程计策,并布置正确的挪用接口,不管用何种编程语言体例的DLL都具有通用性。譬喻在BC31中体例的DLL措施,可用于BC、VC、VB、Delphi等多种语言情况中。笔者在BC31情况下编译了Windows下直接内存会见和端口I/O两个DLL,用在多个廉价系统的应用软件中,


#p#副标题#e#

运行精采。

二、DLL的成立和挪用

DLL的成立及挪用要领在很多资料上有具体的先容,为了节减篇幅,在这里仅作一些

主要的归纳综合。

1.DLL的成立

关于DLL的成立,有如下几个方面的要素是不行缺少和必需把握的:

?. 进口函数LibMain( )

就象C措施中的WinMain( )一样,Windows每次加载DLL时都要执行LibMain( )函数,主要用来举办一些初始化事情。凡是的形式是:

int FAR PASCAL LibMain(HINSTANCE hInstance,WORD wDataSeg,WORD
wHeapSize,LPSTR lpszCmdLine)
{
if(wHeapSize!=0) //使局部堆、数据段可移动
UnlockData(0); //解锁数据段
/*此处可举办一些用户须要的初始化事情*/
return 1; //初始化乐成
}

?出口函数WEP( )

Windows从内存中卸载DLL时,挪用相应的出口函数WEP( ),主要做一些清理事情,如释放占用的内存资源;扬弃某些字串、位图等资源;封锁打开的文件等等。

?自界说的输出函数

为了让位于差异内存段的应用措施举办长途挪用,自界说的输出函数必需界说为长途函数(利用FAR要害字),以防利用近程指针而获得意外的功效;同时,加上PASCAL要害字可加速措施的运行速度,使代码简朴高效,提高措施的运行速度。

?输出函数的引出要领

? 在DLL的模块界说文件中(.DEF)由EXPORTS语句对输出函数逐一列出。譬喻:

EXPORTS WEP @1 residentname //residentname可提高DLL效率和处理惩罚速度

PortIn @2

PortOut @3 //凡是对所有输出函数附加系列号

? 在每个输出函数界说的说明中利用_export要害字来对其引出。

以上两种要领任选个中的一种即可,不行反复。后头的两个实例别离利用了上述两种差异的引出方法,请寄望。

#p#副标题#e#

2.DLL的挪用

加载DLL时,Windows寻找相应DLL的序次如下:

?.当前事情盘。

?Windows目次;GetWindowsDirectory( )函数可提供该目次的路径名。

?Windows系统目次,即System子目次;挪用GetSystemDiretory( )函数可得到这个目次的路径名。

?DOS的PATH呼吁中摆列的所有目次。

?网络中映象的目次列表中的全部目次。

DLL模块中输出函数的挪用要领:

岂论利用何种语言对编译好的DLL举办挪用时,根基上都有两种挪用方法,即静态挪用方法和动态挪用方法。静态挪用方法由编译系统完成对DLL的加载和应用措施竣事时DLL卸载的编码(如尚有其它措施利用该DLL,则Windows对DLL的应用记录减1,直到所有相关措施都竣事对该DLL的利用时才释放它),简朴实用,但不足机动,只能满意一般要求。动态挪用方法是由编程者用API函数加载和卸载DLL来到达挪用DLL的目标,利用上较巨大,但能越发有效地利用内存,是体例大型应用措施时的重要方法。详细来说,可用如下的要领挪用:

?.在应用措施模块界说文件中,用IMPORTS语句列出所要挪用DLL的函数名。如:

IMPORTS MEMORYDLL.MemoryRead

MEMORYDLL.MemoryWrite

?让应用措施运行时与DLL模块动态链接

先用LoadLibrary加载DLL,再用GetProcAddress函数检取其输出函数的地点,得到其指针来挪用。如:

#p#分页标题#e#

HANDLE hLibrary;
FARPROC lpFunc;
int PortValue;
M
hLibrary=LoadLibrary("PORTDLL.DLL"); //加载DLL
if(hLibrary>31) //加载乐成
{
lpFunc=GetProcAddress(hLibrary,"PortIn"); //检取PortIn函数地点
if(lpFunc!=(FARPROC)NULL) //检取乐成则挪用
PortValue=(*lpFunc)(port); //读port端口的值
FreeLibrary(hLibrary); //释放占用的内存
}
M

#p#副标题#e#

三、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文件
#include <windows.h>
int FAR PASCAL LibMain(HINSTANCE hInstance,WORD wDataSeg,WORD
wHeapSize,LPSTR lpszCmdLine)
{
if(wHeapSize!=0)
UnlockData(0);
return 1;
}
int FAR PASCAL MemoryRead(unsigned int DosSeg,unsigned int DosOffset)
{
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)DosOffset); //置基地点
pData=(char far *)((DWORD)wSelector<<16);
value=*pData;
FreeSelector(wSelector); //释放选择器
return (value);
}
void FAR PASCAL MemoryWrite(unsigned int DosSeg,unsigned int DosOffset,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)DosOffset);
pData=(char far *)((DWORD)wSelector<<16);
*pData=Data;
FreeSelector(wSelector);
}
int FAR PASCAL WEP(int nParam)
{
return 1;
}

2.端口读写I/O的DLL源代码

//.DEF文件
LIBRARY PORTDLL
DESCRIPTION 'DLL FOR PORT_IN_OUT '
EXETYPE WINDOWS
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE SINGLE
HEAPSIZE 1024
//.CPP文件
#include <windows.h>
#include <dos.h>
int FAR PASCAL LibMain(HINSTANCE hInstance,WORD wDataSeg,WORD
wHeapSize,LPSTR lpszCmdLine)
{
if(wHeapSize!=0)
UnlockData(0);
return 1;
}
int FAR PASCAL _export PortOut(int port,unsigned char value)
{
outp(port,value);
return 1;
}
int FAR PASCAL _export PortIn(int port)
{
int result;
result=inp(port);
return (result);
}
int FAR PASCAL _export WEP(int nParam)
{
return 1;
}

别离将上面两个实例的.DEF文件和.CPP文件各自构成一个.PRJ文件,并举办编译链接成.EXE或.DLL文件就可以在应用措施中对其举办挪用。

四、结 束 语

在上面,我们操作DLL技能利便地实现了Windows情况下对内存的直接会见和端口I/O的会见,仿效这两个例子,还可以体例出更多的适合本身应用系统所需的DLL,如用于数据收罗卡的端口操纵及扩展内存区会见、视频区缓冲区及BIOS数据区操纵等很多实际应用的编程任务中。须要时只需直接更新DLL,而用不着对应用措施自己作任何窜改就可以对应用措施的成果和用户接口作较大的改进,实现版本进级。因此,把握好DLL技能对Windows措施开拓者很有裨益。

    关键字:

在线提交作业