⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 05o023.htm

📁 VC知识库5_chm_decompile_20040520_210715
💻 HTM
字号:
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title></title>
<link rel="stylesheet" type="text/css" href="../../vckbase.css">
</head>

<body>

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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -