Windows Embedded Compact 7中的dll编程(上)

   动态连接库(Dynamic Link Library,DLL)是一些编译过的可执行程序模块,它包含代c++

码、数据或资源,能够在应用程序中或其余DLL中被调用。动态连接库的文件扩展名通常为.dll,也能够是.drv(设备驱动程序)、.sys(系统文件)和.fon(字体文件)。DLL的应用很是普遍,能够实现多个应用程序问的代码和资源共享,是Windows Embedded Compact 7程序设计中的一个很是重要的组成部分。ide

12.1 dll概述模块化

当使用普通的函数库时,能够在程序连接时将库中的代码拷贝到可执行文件中,这是一种函数

静态连接。而在多个一样的程序执行时,系统将保留许多重复的代码副本,很容易形成内存资源的浪费。若是使用DLL动态连接库,那么在创建应用程序的可执行文件时,就没必要将DLL连接到程序中,只须要在应用程序运行时动态地装载DLL。装载时DLL将被映射到进程的地址空间中,所以使用DLL动态连接并不就是拷贝库代码,只是在程序中记录了函数的入口点和接口,在程序执行时才将库代码装入内存。因此无论多少程序使用了DLL,内存中都将只有该DLL的一个副本,当没有程序使用它时,系统就将它移出内存,减小了对内存和磁盘的要求。因而可知,使用DLL的一个明显的好处就是节省系统资源。测试

    除了以上的优势外,使用DLL设计程序还有如下一些优势:字体

    ·  共享代码、资源和数据。DLL做为一种基于WindoWS的程序模块,不只能够包含可spa

    执行代码,还能够包括数据和各类资源等,扩大了库文件的使用范围。操作系统

    DLL提供了共享资源的途径,例如位图、字体或者图表等均可以放到一个资源文件中,线程

并直接链接到应用程序中。若是将这些资源都放到DLL中,那么许多应用程序均可以直接使设计

用,而没必要在内存里重复装入这些数据。

    在16位的Windows中,DLL有本身的数据段,所以全部须要调用同一个DLL的应用程

序都可以访问同一个全局变量和静态变量。可是在32位的系统中,状况就不一样了。由于DLL

的映像被映射到每一个进程的地址空间,该DLL的全部数据将属于映射到的进程。值得注意的

是,尽管进程间不能共享DLL的数据,可是同一个进程的全部线程则能够共享。因为线程间

相互独立,所以在访问某一DLL全局变量时,要注意保持同步,以避免冲突。

    尽DLL的映像被映射到每一个进程的地址空间时,该DLL的全部数据将属于映射到的进

程,这也并不意味着没有办法在进程间共享DLL的数据。利用内存映射文件就能够实现,只要将数据存储到内存映射的共享区,那么一切须要调用DLL的应用程序都能够读取这些存储在内存中的共享区域的数据。

    ·  可将系统模块化,方便升级。DLL技术对于开发大型软件系统也大有好处。若是使

    用一个执行文件完成一个大型系统,那么程序将会很庞大,并且还可能存在许多重复

    的功能。而若是将程序分红一系列的主程序和DLL,则能够减小开发的工做量并加

    快开发的速度。并且,若是开发过程当中就将一些功能模块作成DLL,那么在须要对

    系统进行升级的时候,只须要升级个别DLL,而后用新的DLL文件覆盖掉旧的DLL

    文件就.-1以Y,如此一来,就不须要对整个系统进行从新编译和连接,极大地方便了

    系统的升级和维护。

    ·  隐藏实现的细节。在某些状况下,用户可能想隐藏例程实现的细节,DLL就是一个

    很是不错的实现方法。DLL的例程能够被应用程序访问,而不显示其中的代码细节。

    还有很重要的一点就是DLL与语言无关。

12.2 dll的调用

12.2.1 静态调用

静态调用指由编译系统完成对DLL的加载而且在应用程序结束时对DLL进行释放。静态

调用相对于动态调用而言,其优势是简单实用,弊端就是不够灵活。

    在Visual C++中静态调用DLL也很是简单,首先将动态链接库的.LIB文件加入到应用程

序的工程中,而后在使用DLL函数的文件里引用DLL的头文件便可。

    静态调用不须要调用LoadLibrary和FreeLibrary,这是由于开发人员在创建一个DLL文

件时,连接程序会自动生成一个与之对应的LIB导入文件。该文件包含了每个DLL导出函

数的符号名和可选的标识号,可是并不包含实际的代码,LIB文件会做为DLL的替代文件被

编译到应用程序项目中。当开发人员经过静态连接方式编译并生成应用程序时,应用程序中的

调用函数与LIB文件中的导出符号相匹配,这些符号或标识号进入到生成的EXE文件中。LIB

文件中也包含了对应的DLL文件名(但不是彻底的路径名),连接程序将其存储在EXE文件

内部。当应用程序运行过程当中须要加载DLL文件时,Windows将根据这些信息查寻并加载

DLL,而后经过符号名或标识号实现对DLL函数的动态连接。当加载应用程序的EXE文件时,

全部被应用程序调用的DLL文件都将被加载在到内存中。可执行程序直接经过函数名调用

DLL的输出函数,其调用方法与调用程序内部的其余的函数相同。

12.2.2 动态调用

动态调用是由开发人员使用APl函数手工加载和卸载DLL,以达到调用DLL的目的。动

态调用较之静态调用,在使用上更为复杂,但却能更加有效地使用内存,所以是编写大型应用

程序的重要方式。

    动态调用是指在应用程序中使用LoadLibrary函数或MFC提供的AfxLoadLibrary函数显

式地调入所需的动态链接库,动态链接库的文件名即上面两个函数的参数,而后再使用

GetProeAddress获取所需引入的函数。完成以上操做后,就能够像使用本应用程序自定义的函数同样来调用引入函数了。在应用程序退出以前,应该使用FreeLibrary函数或MFC提供的

AfxFreeLibrary函数来释放动态链接库。

    动态调用DLL的第l步就是调用LoadLibrary函数来加载DLL。该函数的定义以下:

    HINSTANCE LoadLibrary(  LPCTSTR ipLibFi leName)

    参数lpLibFileName用于指定DLL的文件名,而且该文件名能够包含文件名的目录。如

果不包含文件名的目录,那么该函数将遵循下面的搜索顺序来定位DLL。

  ·  包含EXE文件的目录

  ·  进程的当前工做目录

  ·  Windows系统目录

  ·  Windows目录

  ·  列在Path环境变量中的一系列目录

  成功加载DLL后,函数将返回指向该DLL的句柄,不然将返回NULL。

  成功执行第1步(加载DLL)以后,就能够执行第2个步骤了。执行该步骤的目的就是

获取DLL里的输出函数接口,能够经过GetProcAddress函数来实现该目标。GetProcAddress

函数的定义以下:

    FARPROC GetProcAddress(

    HMODULE hModule,

    LPCWSTR lpprocName);

    ·  参数hModule用于指定DLL旬柄,即LoadLibrary函数的返回值。

    ·  参数lpProcName指定想要获得的函数名称。

    若是函数执行成功,那么将返回指定函数的地址指针,不然返回NULL。若是DLL里有

N个须要获取的输出函数,就须要执行GetProcAddress函数N次,来获取这N个函数的地址。

获取DLL里的输出函数以后,直接调用输出函数便可。

    动态调用DLL的最后一个步骤就是当再也不使用DLL里的输出函数时,调用FreeLibrary

函数释放DLL,该函数的定义以下:

    BOOL  FreeLibrary(

    HMODULE hLibModule)j

    参数hLibModule用于指定DLL句柄,即LoadLibrary函数的返回值。

    若是该函数成功的释放了DLL,将返回TRUE,不然返回FALSE。

12.3 dll的建立

本节将分别介绍以下3种类型的DLL动态连接库建立方法和建立过程。

    ●  Windows Embedded Compact 7  DLL。

   Windows Embedded Compact 7是指不使用MFC建立的DLL。Windows Embedded Compact 7导出函数一般使用标

C接口,这些函数能够被MFC或非MFC应用程序调用。

    ·  MFC常规DLL(动态链接MFC)。    .

    MFC常规DLL是使用MFC建立的,其导出函数也一般使用标准C接口,它们能够被

MFC或非MFC应用程序调用。按照与MFC连接方式的不一样,MFC常规DLL又能够分为动

态链接和静态链接两种,前者使用MFC的动态连接库(即共享版本),后者使用MFC的静态

连接版本。

    ·  纯资源DLL。

    纯资源DLL只包含共享的资源,如菜单、字符串、图标、位图以及声音等。

    下面就分别介绍以上3类DLL动态连接库的建立方法。

12.3.1 Windows Embedded Compact 7中 dll的建立

新建一个基于“Win32智能设备项目’’的项目,将项目名称设为MyCEDLL,实现页面

如图12-1所示。

图12-1建立动态函数连接库

选择yincheng_OS,如图12-2

图12-2选择程序开发环境yincheng_OS

选择DLL,如图12-3

图12-3选择程序类

单击“finish”按钮就完成了MyCEDLL工程的建立。

下面先来了解一下非MFC的DLL工程实现原理。

    首先,每一个DLL必须有一个入口点,这就如同使用C语言编写的应用程序必须有一个

WINMAlN函数同样。DllMain是一个缺省的入口函数,它负责初始化(Initialization)和结束

(Termination)工做。当一个新的进程或者该进程的新的线程访问DLL,以及访问DLL的每一

个进程或者线程再也不使用此DLL时,都会调用DllMain函数。可是有一种特殊状况,那就是如

果使用TerminateProcess或TerminateThread方法结束进程或线程,就不会调用DllMain函数。

    用户只须要打开MyCEDLL.cpp文件,就能够看到DllMain函数的实现,它的函数原型

以下:

    BOOL APIENTRY DllMain( HANDLE hModule, 

                       DWORD  ul_reason_for_call, 

                       LPVOID lpReserved

 )

{

switch (ul_reason_for_call)

{

case DLL_PROCESS_ATTACH:

case DLL_THREAD_ATTACH:

case DLL_THREAD_DETACH:

case DLL_PROCESS_DETACH:

break;

}

    return TRUE;

}

    ·  参数Moudle是动态库被调用时所传递来的一个指向本身的句柄

    ·  参数ul reason for call是一个说明动态库被调用缘由的标志。当进程或者线程装载、

    卸载动态连接库的时候,操做系统便调用入口函数,并说明动态连接库被调用的缘由。

    该参数能够取以下所示的值:

    >DLL PROCESS ATTACHt进程被建立。

    >DLL THREAD ATTACH:线程被建立。

    >LL PROCESS DETACH:进程被中止。

    >LL THREAD DETACH:线程被中止。

    ·  参数lpReserved是一个被系统所保留的参数。

    在理解了DllMain函数的实现原理后,就要接着考虑输出函数的实现方法了。

    输出函数须要在函数名称前加上修饰符declspec(dllexport),表示输出。此外,还有一种

修饰符extem”C”declspec(dllexport),它也表示输出,并且该类DLL不只能够被c++调用,

还能够被c调用。在c++下定义c函数时,须要加上extem”C”关键词,用extern”C”来指明

该函数使用C的编译方式,输出的c函数能够从c代码里调用,extern”C”使得在C++中使用C编译方式成为可能。

    本示例向导完成后,会自动导出3种类型示例符号:一个是导出了一个“C++类”、一个

是导出了一个“全局变量”、另一个导出了一个“函数”。读者能够效仿示例进行添加自定义

的导出符号。这3个示例符号定义以下:

    //此类是从MyCEDLLdll导出的

    class MYCEDLL_API CMyCEDLL{

    public

    CMyCEDLL(void)

    //TODO:在此添加您的方法

    )

    extern MYCEDLL_API int nMyCEDLL;

    函数实现代码中的修饰符MYCEDLL_APl其实就是_declspec(dllexport),由于在

MyCEDLL.h文件中含有以下宏代码:

    ifdef MYCEDLL—EXPORTS

    #define MYCEDLL—API declspec(dllexport)

    #else

    #define MYCEDLL—API declspec(dllimport)

    #endif    

    MYCEDLL_API int fnMyCEDLL(void);

    下面就来为MyCEDLL.dll动态连接库增长一个输出函数TestDll。

    首先在MyCEDLL.h头文件中添加TestDll函数的声明,代码以下:

    extern”C”MYCEDLL_API void TestDll(void)

而后在MyCEDLL.cpp文件中添加以下所示的TestDll函数的实现代码:

extern "C" MYCEDLL_API void TestDll(void)

{

MessageBox(NULL,_T("此信息来自DLL"),_T("测试所编DLL"),MB_OK);

}

    完成以上操做后,一个简单的DLL就编写完了。按下F5编译就会生成MyCEDLL.dll文件,将此文件下载到yincheng.OS\RelDir\VirtualPC_x86_Release目录下。在下面的一个小节中,将以MyCEDll.dll为例,介绍静态调用和动态调用该DLL的方法步骤。

相关文章
相关标签/搜索