VS2005新建WINCE设备的DLL工程

 

一、       动态链接库简介

1.1 DLL概述

动态链接库(Dynamic Link Library, j简称DLL)是一些编译过的可执行的程序模块,可以在应用程序中或其他DLL中被调用。DLL应用非常广泛,可以实现多个应用程序的代码和资源共享,是WinCE程序设计中的一个非常重要的组成部分。

DLL设计程序的优点:

l         共享代码、资源和数据。DLL作为一种基于Windows的程序模块,不仅可以包含可执行代码,还可以包括数据和各种资源等,扩大了库文件的使用范围;

l         可将系统模块化,方便升级。

l         隐藏实现细节。

l         DLL与语言无关。

 1.2 DLL的调用

    不论使用何种语言对编译好的DLL进行调用时,基本上都有两种调用方式,即静态调用方式和动态调用方式。静态调用方式由编译系统完成对DLL的加载和应用程序结束时DLL卸载的编码(如还有其他程序使用该DLL,则Windows对DLL的应用记录减1,直到所有相关程序都结束对该DLL的使用时才释放它),简单使用,但不灵活,只能满足一般要求。动态调用方式是由编程者用API函数加载和卸载DLL来达到调用DLL的目的,使用上较复杂,但能更加有效地使用内存,是编制大型应用程序时的重要方式。

1.2.1 DLL的静态调用

    DLL的静态调用由编译系统完成对DLL的加载和应用程序结束时DLL卸载,在VS2005中静态调用DLL非常简单:首先在VS2005的“工具->选项->项目和解决方案->VC++目录”里设置库文件的路径;然后将需要的lib文件的名称加入到“项目-〉属性-〉配置属性-〉连接器-〉输入-〉附属依赖项”,文件名称之间用空格间隔;最后在使用DLL中的函数文件里引用DLL的头文件(.h)即可。

    当开发人员通过静态方式编译并生成应用程序时,应用程序中的调用函数与LIB文件中的导出符号相匹配,这些符号或标示进入到生成的EXE文件中。当应用程序运行过程中需要加载DLL文件时,操作系统将根据这些信息查寻并加载DLL,然后通过符号或标示实现对DLL函数的动态链接。当加载应用程序的EXE文件时,所有被应用程序调用的DLL文件都被加载到内存中,这时可执行程序直接通过函数名调用DLL的输出函数,其调用方法与调用程序内部函数相同。

    因此,如果设备上没有应用程序所要加载的DLL库时,用户需自己将DLL库拷贝到应用程序所在目录,或系统根目录。

1.2.2 DLL的动态调用

        动态调用方式是由编程者用API函数加载和卸载DLL来达到调用DLL的目的,动态调用是指在应用程序中使用LoadLibrary函数或MFC提供的AfxLoadLibrary函数显式调用自己所需要的动态链接库,动态链接库的文件名就是上面两个函数的参数,然后在使用GetProAddress()函数获取所需要引入的函数。完成上述操作后,应用程序可以调用引入的函数。在应用程序退出之前,应该使用FreeLibrary函数或MFC提供的AfxFreeLibrary函数来释放动态链接库。

二 DLL工程的实现

2.1 动态链接库的创建

2.1.1

1、新建一个基于Smart Device的 MFC Smart Device DLL,将项目名称设为eSOM9261API,如图2-1所示。

图 2-1 新建DLL工程名

2、 单击OK,此时将出现DLL的支持平台对话框,选择所支持的平台,由于我们这里的DLL动态库使用eSOM/9261目标板,所以选择EEIC08SDK(eSOM/9261产品自带的SDK包)平台。如图2-2所示。

图 2-2 平台选择

3、 单击Next,将出现DLL的类型选择(如图2-3所示),选中MFC Extension DLL,按Finish可完成DLL向导工作。此时向导将自动生成DLL基本框架。

图 2-3 DLL类型选择

2.1.2

每个DLL必须有一个入口点,这就如如同使用C语言编写的应用程序必须有一个main函数一样,DllMain是一个默认的入口函数,它负责初始化和结束工作,当一个新的线程访问DLL时,都会调用DllMain函数。

    打开利用向导生成的eSOM9261API.cpp文件,即可看到DllMain函数的实现。

extern "C" BOOL APIENTRY

DllMain(HANDLE hInstance, DWORD dwReason, LPVOID lpReserved)

{

    // Remove this if you use lpReserved

    UNREFERENCED_PARAMETER(lpReserved);

 

    if (dwReason == DLL_PROCESS_ATTACH)

    {

        TRACE0("eSOM9261API.DLL Initializing!/n");

       

        // Extension DLL one-time initialization

        if (!AfxInitExtensionModule(eSOM9261APIDLL, reinterpret_cast<HMODULE>(hInstance)))

            return 0;

        new CDynLinkLibrary(eSOM9261APIDLL);

    }

    else if (dwReason == DLL_PROCESS_DETACH)

    {

        TRACE0("eSOM9261API.DLL Terminating!/n");

        // Terminate the library before destructors are called

        AfxTermExtensionModule(eSOM9261APIDLL);

    }

    return 1;   // ok

}

2.1.3 输出函数的实现方法

    DLL中导出函数的声明有两种方式:一种方法在函数名称声明中加上修饰符__declspec(dllexport),表示输出,此外,还有一种修饰符 extern "C"  __declspec(dllexport),也表示输出,而且该类DLL不仅可以被C++调用,还可以被C调用。在C++下定义C函数时,需要加上extern "C"关键字。下面为DLL测试程序的输出函数的声明。(在eSOM9261API.h文件中)。

#ifdef ESOM9261API_EXPORTS

#define ESOM9261API_API _declspec(dllexport)

#else

#define ESOM9261API_API _declspec(dllimport)

#endif

 

extern "C"

{

    void ESOM9261API_API SetBuzz(void);

    void ESOM9261API_API ClearBuzz(void);

}

    对应的原文件(eSOM9261API.c)的实现函数如下:

void SetBuzz(void)

{

    return;

}

void ClearBuzz (void)

{

    return;

}

导出函数另外一种方式是采用模块定义(.def) 文件声明,.def文件为链接器提供了有关被链接程序的导出、属性及其他方面的信息。(eSOM9261API.def的内容)

; eSOM9261API.def : Declares the module parameters for the DLL.

LIBRARY      "eSOM9261API"

 

EXPORTS

    SetBuzz

    ClearBuzz  

    采用模块定义.def导出函数声明,如果要求导出函数能够被C语言掉用,必须在函数的实现前加 extern "C"进行修饰。

extern "C" void SetBuzz (void)

{  

    return ;

}

2.2 动态链接库的调用

2.2.1 静态调用DLL的步骤

    利用VS2005生成一个DLL调用测试应用程序eSOM9261Test.sln,并将上述编译好的eSOM9261API.dll和eSOM9261API.lib文件拷贝到本工程的目录下。然后使用VS2005的Project->Properties属性设置中,选中Linker,在Linker的Input选项的Additional Dependencies中输入eSOM9261API.lib如图2-4所示

图 2-4 应用程序引入动态链接库文件

    如果在DLL的函数的导出采用头文件的实现方法,必须将DLL的头文件eSOM9261API.h拷贝到在调用DLL的工程中,并在实现文件中引用eSOM9261API.h文件,代码如下:

#include "eSOM9261API.h"

这样就可以使用DLL的导出函数。

    如果采用模块(.def)导出DLL中实现函数,则必须在调用DLL的实现文件声明导入函数,代码如下:

extern "C"  void __declspec(dllimport) SetBuzz(void);

extern "C"  void __declspec(dllimport) ClearBuzz(void);

2.2.2 动态调用DLL的步骤

    动态调用方式是使用LoadLibrary API函数加载DLL,然后在使用GetProAddress()函数获取所需要引入的函数。

具体实现方式:

l         添加eSOM9261Test动态链接库工程的实现函数的定义,代码如下:

typedef void (*pSetBuzz)  (void);

typedef void (*pClearBuzz) (void);

利用LoadLibrary API函数动态加载动态链接库,代码的黑体部分;

BOOL CTestDllDlg::OnInitDialog()

{

    CDialog::OnInitDialog();

    SetIcon(m_hIcon, TRUE);         // Set big icon

    SetIcon(m_hIcon, FALSE);        // Set small icon

    hModule=LoadLibrary(_T("eSOM9261API.dll"));

    if(hModule==NULL)

       MessageBox(_T("Load Dll file failed"),_T("System Information"),MB_OK|MB_ICONERROR);

    return TRUE;  // return TRUE  unless you set the focus to a control

}

l         利用GetProcAddress API函数获取需要引用的函数,代码如下:

void CTestDllDlg::OnBnClickedbtnstop()

{

    pSetBuzz SetBuzz =(pLedControl)GetProcAddress (hModule,_T("SetBuzz"));

    if(LedControl==NULL)

MessageBox(_T("Load LedControl function failed"),_T("System Information"),MB_OK|MB_ICONERROR);

    else

        SetBuzz();

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
大家在实际工作学习C#的时候,可能会问:为什么我们要为一些已经存在的功能(比如Windows中的一些功能,C++中已经编写好的一些方法)要重新编写代码,C#有没有方法可以直接都用这些原本已经存在的功能呢?答案是肯定的,大家可以通过C#中的DllImport直接调用这些功能。 DllImport所在的名字空间 using System.Runtime.InteropServices; MSDN中对DllImportAttribute的解释是这样的:可将该属性应用于方法。DllImportAttribute 属性提供对从非托管 DLL 导出的函数进行调用所必需的信息。作为最低要求,必须提供包含入口点的 DLL 的名称。 DllImport 属性定义如下: namespace System.Runtime.InteropServices {   [AttributeUsage(AttributeTargets.Method)]   public class DllImportAttribute: System.Attribute   {    public DllImportAttribute(string dllName) {...}    public CallingConvention CallingConvention;    public CharSet CharSet;    public string EntryPoint;    public bool ExactSpelling;    public bool PreserveSig;    public bool SetLastError;    public string Value { get {...} }   } }   说明:   1、DllImport只能放置在方法声明上。   2、DllImport具有单个定位参数:指定包含被导入方法的 dll 名称的 dllName 参数。   3、DllImport具有五个命名参数:    a、CallingConvention 参数指示入口点的调用约定。如果未指定 CallingConvention,则使用默认值 CallingConvention.Winapi。    b、CharSet 参数指示用在入口点中的字符集。如果未指定 CharSet,则使用默认值 CharSet.Auto。    c、EntryPoint 参数给出 dll 中入口点的名称。如果未指定 EntryPoint,则使用方法本身的名称。    d、ExactSpelling 参数指示 EntryPoint 是否必须与指示的入口点的拼写完全匹配。如果未指定 ExactSpelling,则使用默认值 false。    e、PreserveSig 参数指示方法的签名应当被保留还是被转换。当签名被转换时,它被转换为一个具有 HRESULT 返回值和该返回值的一个名为 retval 的附加输出参数的签名。如果未指定 PreserveSig,则使用默认值 true。    f、SetLastError 参数指示方法是否保留 Win32"上一错误"。如果未指定 SetLastError,则使用默认值 false。   4、它是一次性属性类。   5、此外,用 DllImport 属性修饰的方法必须具有 extern 修饰符。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值