1.靜態調用MyCEDLLdom
在本章的第2節中介紹了調用DLL的兩種方式:靜態調用和動態調用,在下面的示例中異步
就來演示使用靜態方法調用上面建立的MyCEDLL.dll的步驟。ide
(1)使用VS2008智能設備MFC智能設備應用程序嚮導建立一個基於對話框的應函數
用程序CallDLLByStatic,編譯環境設置爲yincheng_OS。測試
(2)將MyCEDLL工程中的MyCEDLL.dll和MyCEDLL.1ib兩個文件拷貝到本工程目錄this
下,而後選擇VS2008主菜單中的「項目ICalIDLLByStatic屬性」項打開項目屬性設置窗口,spa
右邊導航欄選擇「配置屬性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.