1.静态调用MyCEDLL
在本章的第2节中介绍了调用DLL的两种方式:静态调用和动态调用,在下面的示例中
就来演示使用静态方法调用上面创建的MyCEDLL.dll的步骤。
(1)使用VS2008智能设备MFC智能设备应用程序向导创建一个基于对话框的应
用程序CallDLLByStatic,编译环境设置为yincheng_OS。
(2)将MyCEDLL工程中的MyCEDLL.dll和MyCEDLL.1ib两个文件拷贝到本工程目录
下,然后选择VS2008主菜单中的“项目ICalIDLLByStatic属性”项打开项目属性设置窗口,
右边导航栏选择“配置属性J链接器I输入”,在该页框中的“附加依赖项”输入框中输入
MyCEDll.1ib,实际页面下图所示。
(3)将MyCEDLL工程的MyCEDLL.h头文件拷贝到本工程目录中,并且在
CaIlDLLByStaticDl9.cpp文件中引用MyCEDLL.h头文件,代码如下: #include”MyCEDLL.h” 如图12-4
图12-4配置DLL调用
(4)在对话框窗体上放置一个“调用”按钮,通过单击该按钮来实现调用MyCEDLL中
TestDll方法的功能。“调用”按钮的单击事件代码如程序
//演示静态调用DLL
void CCallDLLByStaticDlg::0nBnClickedBtnCall()
{
//TestDll函数为MyCEDLL.dll中的一个输出函数
TestDll();
}
(5)编译并下载到yincheng.OS\RelDir\VirtualPC_x86_Release在虚拟机中运行,单击“调用”按钮后效果如下。效果如图12-5
图12-5程序效果图
在上中介绍了以静态方式调用DLL的示例,在下面的示例中将继续介绍以动态
方式调用DLL的方法步骤,这里还是以MyCEDLL.dll文件为例。
(1)使用VS2008智能设备IMFC智能设备应用程序向导创建一个基于对话框的应
用程序CallDLLByDynamic,编译环境设置为yincheng_OS SDK)。
(2)在CallDLLByDynamicDlg.h文件中添加MyCEDLL文件中的TestDll函数定义,代
码如下:
//定义MyCEDLL.dll中TestDll输出函数原型
typedef void(*pTestDII)(void);
(3)在对话框上放置一个“调用”按钮,用来调用MyCEDLL文件中的TestDll函数,
该按钮的单击事件代码如下列所示。
//动态调用DLL示例
void CCallDLLByDynamicDlg::OnBnClickedBtnCall()
{
//1、加载DLL
HINSTANCEhModule = LoadLibrary(_T("MyCEDLL.dll"));
if (hModule == NULL)
{
AfxMessageBox(_T("加载DLL失败"));
return;
}
//得到MyCEDLL中TestDll函数地址
pTestDll pFun = (pTestDll)GetProcAddress(hModule,_T("TestDll"));
if ( pFun == NULL )
{
AfxMessageBox(_T("获取TestDll函数失败"));
}
else
{
//执行MyCEDLL中TestDll函数
pFun();
}
//3、释放DLL;
FreeLibrary(hModule);
}
(4)编译并下载到模拟器中运行,其运行界面如图l2-6所示。
图12-6程序运行效果
12.3.2 基于mfc的regular dll的创建
基于MFC的Regular DLL是用MFC类库编写的,其明显的特点就是在源文件里有一个
继承CWinApp的类。该类动态链接库的输出函数具有如下形式:
extern ”C” EXPORT YourExportedFunction()j
如果没有extern”C”修饰,输出函数仅仅只能从C++代码中调用。
注意:所有从DLL输出的函数都应该以如下语句开始:
AFX—MANAGE—STATE(AfxGetStaticModuleState())
以上语句用来正确地切换MFC模块状态。Regular DLL能够被所有支持DLL技术的语言
所编写的应用程序调用。在这种动态连接库中,它必须有一个从CwinApp类继承下来的类,
DllMain函数被MFC所提供,不用显式地写出来。
下面就来创建一个基于MFC的Regular DLL。这个DLL会提供一个异步处理方法,当方
法执行完成后,将提供回调函数通知用户方法执行完成。该动态链接库典型的用处就是,当用
户执行一个查询时,可能需要一段时间,如果采用同步的方式,用户必须等待查询结束后才能
执行其他任务,但是如果将其改成异步(通过单独的线程)的方式,在执行完成后,将以回调
函数通知用户,那么在查询的这段时间中,用户还可以执行其他任务,提高了工作的效率。
1.基于MFC的Regular DPLL的创建
创建一个基于MFC的Regular DLL的具体步骤如下:
(1)使用向导建立基于MFC的Regular Dll项目。
新建一个基于“MFC智能设备DLL”的项目,将项目名称设为AsynDll,如图12-7所示。
选择yinchengOS编译环境如图12-8
单击“确定”按钮,此时将出现“MFC智能设备DLL向导”对话框,如图12-9所示。
单击“完成”按钮就完成了AsynDll工程的创建。
图12-7设置项目模板
图12-8,设置编译环境
图12-9定义动态函数链接库类型
(2)定义DLL输出函数。
在AsynDll.h头文件中添加Dll输出函数定义,
//定义DLL函数导出类型
#define ASynDLL_EXPORT_API __declspec(dllexport)
//导出Dll函数
extern "C"
{
//查询数据,异步方法
long ASynDLL_EXPORT_API QueryData(void);
//设置回调函数
long ASynDLL_EXPORT_API SetCallbackProcAddr(long);
}
//定义回调函数类型
typedef void (* TDataReadNotify)(long);
在AsynDll.cpp文件中,添加DLL函数的实现代码,具体位置是CASynDIIApp
语句的下面,代码如程序所示。
//定义回调函数
TDataReadNotify DataReadNotify;
//线程处理函数
DWORD DoTheWork(LPVOID lpParameter)
{
long lDBData;
Sleep(5000);
lDBData = Random();
//通知用户,函数执行完成
if (DataReadNotify != NULL)
{
//执行回调函数
DataReadNotify(lDBData);
}
return 0;
};
//查询数据
long ASynDLL_EXPORT_API QueryData(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
HANDLE hThread;
DWORD pThreadId;
long lProcAdr;
//设置线程函数
lProcAdr = (long)(&DoTheWork);
//创建线程,并执行线程
hThread = CreateThread(NULL,
0,
(LPTHREAD_START_ROUTINE)lProcAdr,
NULL,
0,
&pThreadId);
return 0;
};
//设置回调函数指针
long ASynDLL_EXPORT_API SetCallbackProcAddr(long lProcAddress)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
long Result = 0;
//设置回调函数
DataReadNotify = (TDataReadNotify)lProcAddress;
if (DataReadNotify != NULL)
{
Result = 1;
}
return Result;
};
ASynDIl就编写完成了。此时就可以把它编译并下载到虚拟机中了。
2.测试ASynDll.dll
(1)使用Vs2008智能设备MFc智能设备应用程序向导创建一个基于对话框的应
用程序ASynDIITest,编译环境设置为yinchengOS.
(2)在ASynDllTestDlg.h文件中定义AsynDll.dll里的两个输出函数类型。具体操作是将
如下代码添加到CASynDllTestDlg类定义之前。
//定义ASynDIl中的函数类型
typedef long(*TQueryData)(void);
typedef long(*TSetCallbackProcAddr)(long);
(3)在ASynDllTestDlg.h文件中添加如下所示的引入函数定义。
private:
//存储Dll句柄
HINSTANCEm_hModule;
//定义Dll中的输入函数
TQueryData m_pQueryData;
TSetCallbackProcAddr m_pSetCallbackProcAddr;
(4)在ASynDllTestDlg.Cpp中,添加回调函数处理方法,代码如程序
//回调函数,当DLL中QueryData方法执行完毕时执行
void QueryReadNotify(long lDBData)
{
TCHAR sDBData[11];
TCHAR sMessage[64];
_ltow(lDBData, sDBData, 10);
wcscpy(sMessage, _T("DBData from DLL is: "));
wcscat(sMessage, sDBData);
::MessageBox(0, sMessage,
_T("Sample App"), MB_OK + MB_ICONINFORMATION);
};
(5)在cAsynDllTestDlg::0nInitDialog()方法中初始化DLL,代码如下
//加载ASynDll
m_hModule = LoadLibrary(_T("ASynDll.dll"));
if (m_hModule == NULL)
{
AfxMessageBox(_T("加载DLL失败"));
return FALSE;
}
//得到ASynDll中QueryData函数地址
m_pQueryData = (TQueryData)GetProcAddress(m_hModule,_T("QueryData"));
if ( m_pQueryData == NULL )
{
AfxMessageBox(_T("获取QueryData函数失败"));
FreeLibrary(m_hModule);
return FALSE;
}
//得到ASynDll中SetCallbackProcAddr函数地址
m_pSetCallbackProcAddr =
(TSetCallbackProcAddr)GetProcAddress(m_hModule,_T("SetCallbackProcAddr"));
if ( m_pSetCallbackProcAddr == NULL )
{
AfxMessageBox(_T("获取SetCallbackProcAddr函数失败"));
FreeLibrary(m_hModule);
return FALSE ;
}
(6)在窗体释放时,释放ASynDll动态链接库,代码如程序所示。
void CASynDllTestDlg::OnDestroy()
{
//释放AsynDll库
FreeLibrary(m_hModule);
CDialog::OnDestroy();
} (7)在窗体上放置一个“调用”按钮,用来调用DLL中的QueryData方法。
钮的单击事件代码如程序所示。
//调用DLL
void CASynDllTestDlg::OnBnClickedBtnCall()
{
long lProcAdr;
//设置回调函数地址
lProcAdr = (long)(&QueryReadNotify);
m_pSetCallbackProcAddr(lProcAdr);
//执行异步查询操作
m_pQueryData();
} 以上操作完成后,就可以编译它并下载到虚拟机中运行了。用户可以多次单击“调用”
按钮,此时的运行效果将如图12-10所示。
图12-10 程序运行效果
12.3.3 资源dll
1.资源DLL的创建
在这个小节中将介绍一个资源DLL的例子,该DLL将存储位图和图标两种资源,下面就
来介绍它的具体实现过程。
(1)新建项目。
新建一个基于“Win32智能设备DLL项目”的项目,将项目名称设为ResDll。将编译
环境设置为yinchengOS.
(2)向DLL工程中添加资源。
在资源视图中,通过鼠标右击快捷菜单“添加资源”,打开添加资源对话框,然后选择
Bitmap,单击“新建”按钮,创建一个新的位图。该位图的默认名称为IDB—BITMAPl,将它
重命名为IDB RESBMP。接着重复插入位图的操作,添加一个图标(ICON),命名为
IDl—RESICON。
最后编译项目,就生成所需的资源DLL文件。
下面接着讲介绍如何使用DLL里的资源。
2.测试ResDll.dll
(1)创建应用程序。
使用VS2008智能设备MFC智能设备应用程序向导创建一个基于对话框的应用程
序ResDllTest,编译环境设置为yinchengOS SDK.
(2)测试程序界面设置。
在对话框上放置4个按钮,这些控件的基本属性设置如表12.1所示。
表12.1 测试程序界面控件属性设置表
标识 | 属性 |
IDC—B观LOAD | 标题设为“加载DLL” |
IDC——BTN——FREE | 标题设为释放DLL |
IDC——BTN——BMP | 标题设为“显示位图” |
IDC—BTNjCON | 标题设为“显示图标” |
此时应用程序界面如图l2.11所示。
图12—11测试程序界面
(3)为CResDllTestDlg类添加一个私有成员变量m_hDll,用于存储资源DLL句柄,代
码如下:
private:
//DLL句柄
HINSTANCE m_hDll;
注意:由于这里是通过资源ID调用了资源DLL里的资源,因此应打开ResDll工程中的
Resource.h文件,将其中的资源定义拷贝到ResDllTestDl9.Cpp文件中,代码片段如下:
//添加资源定义标识
#define IDB_RESBMP l01
#define IDl_RESICON l02
(4)为“加载DLL”、“释放DLL”、“显示图片”、“显示图标”这4个按钮添加单击事件
代码。其中“加载DLL”按钮用于将DLL加载到应用程序中;“释放DLL”按钮用于从应用
程序中释放DLL。这4个按钮的单击事件代码如程序所示。
//加载资源DLL
void CResDllTestDlg::OnBnClickedBtnLoad()
{
//加载DLL
m_hDll = LoadLibrary(_T("ResDll.dll"));
if (m_hDll == NULL)
{
AfxMessageBox(_T("加载Dll失败"));
}
}
//释放资源DLL
void CResDllTestDlg::OnBnClickedBtnFree()
{
//释放DLL
if (m_hDll != NULL)
{
FreeLibrary(m_hDll);
}
}
//显示资源里的位图
void CResDllTestDlg::OnBnClickedBtnBmp()
{
HBITMAP hOldBmp;
//从DLL里加载指定的资源
HBITMAP bmp = LoadBitmap(m_hDll,MAKEINTRESOURCE(IDB_RESBMP));
if (bmp == NULL)
{
AfxMessageBox(_T("调用位图资源失败"));
return;
}
//获得绘图环境资源
CDC memdc;
CDC *pDC = new CClientDC(this);
memdc.CreateCompatibleDC(pDC);
hOldBmp = (HBITMAP)memdc.SelectObject(bmp);
pDC->BitBlt(0,0,200,200,&memdc,0,0,SRCCOPY);
memdc.SelectObject(hOldBmp);
//释放资源
DeleteObject(bmp);
//释放DC
delete pDC;
pDC = NULL;
}
//显示资源里的图标
void CResDllTestDlg::OnBnClickedBtnIcon()
{
//从DLL里加载指定的资源
HICON icn = LoadIcon(m_hDll,MAKEINTRESOURCE(IDI_RESICON));
if (icn == NULL)
{
AfxMessageBox(_T("调用图标资源失败"));
return;
}
CDC *pDC = new CClientDC(this);
//绘制图标
pDC->DrawIcon(CPoint(100,100),icn);
DeleteObject(icn);
//释放CDC对象
delete pDC;
pDC = NULL;
}
至此,资源DLL的测试程序就编写完成了。在运行该应用程序时,单击“加载DLL”按
钮后,就可以使用“显示图片”和“显示图标”按钮了。使用结束后,应该单击“释放DLL”
按钮以释放DLL。测试程序的运行效果如图12-12所示。
图12-12程序运行效果
12.4小结
综合简介了如何在Windows Embedded Compact 7中开发各种Dll,请认真实践,并在工作中根据需求开发自己的dll.