?? chap9_3.htm
字號:
<html>
<head>
<title>9.3創建動態連接庫</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="GENERATOR" content="Microsoft FrontPage 3.0">
<link rel="stylesheet" href="../../../cpcw.css"></head>
<body link="#3973DE" alink="#3973DE" background="../../bg.gif">
<div align="center"><center>
<table width="85%" border="0">
<tr bgcolor="#FFFFFF">
<td>
<div align="center">
<center>
</center>
</div>
<p align="CENTER"><b><font color="red">9.3創建動態連接庫</font></b></p>
<p> 在一些情況下,必須使用動態連接庫:</p>
<p> 1.多個應用程序共享代碼和數據:比如Office軟件的各個組成部分有相似的外觀和功能,這就是通過共享動態連接庫實現的。</p>
<p> 2.在鉤子程序過濾系統消息時必須使用動態連接庫</p>
<p> 3.設備驅動程序必須是動態連接庫</p>
<p> 4.如果要在對話框編輯器中使用自己定義的控件,也必須使用動態連接庫</p>
<p> 5.動態連接庫以一種自然的方式將一個大的應用程序劃分為幾個小的模塊,有利于小組內部成員的分工與合作。而且,各個模塊可以獨立升級。如果小組中的一個成員開發了一組實用例程,他就可以把這些例程放在一個動態連接庫中,讓小組的其他成員使用。</p>
<p> 6.為了實現應用程序的國際化,往往需要使用動態連接庫。使用動態連接庫可以將針對某一國家、語言的信息存放在其中。對于不同的版本,使用不同的動態連接庫。在使用AppWizard生成應用程序時,我們可以指定資源文件使用的語言,這就是通過提供不同的動態連接庫實現的。</p>
<p> MFC支持兩類動態連接庫的創建:</p>
<p> 用戶動態連接庫</p>
<p> MFC擴展類庫。</p>
<p> <b></b>9.3.1用戶動態連接庫(_USRDLL)</p>
<p> </p>
<p> 用戶動態連接庫一般使用C語言接口。要創建一個動態連接庫,選擇File->New菜單,彈出New對話框。在Projects標簽頁下,選擇“Win32
Dynamic-Link Library”。Visual
C++就會創建動態連接庫所需的工程文件和MAK文件。</p>
<p> 然后把下面兩個文件加入到工程中(Project-Add
to Project-Files菜單)。</p>
<p> 文件1:mymaths.cpp</p>
<p>////////////////////////////</p>
<p>//mymaths.cpp</p>
<p>//</p>
<p>//a maths API DLL.</p>
<p>//</p>
<p>///////////////////////////</p>
<p>#include<windows.h></p>
<p>//Declare the DLL functions prototypes</p>
<p>int Summary(int);</p>
<p>int Factorial(int);</p>
<p>//////////////////////////</p>
<p>//DllEntryPoint():The entry point of the DLL</p>
<p>//</p>
<p>/////////////////////////</p>
<p>BOOL WINAPI DLLEntryPoint(HINSTANCE hDLL,DWORD dwReason,</p>
<p>LPVOID Reserved)</p>
<p>{</p>
<p>switch(dwReason)</p>
<p>{</p>
<p>case DLL_PROCESS_ATTACH:</p>
<p>{</p>
<p>//一些初始化代碼</p>
<p>break;</p>
<p>}</p>
<p>case DLL_PROCESS_DETACH:</p>
<p>{</p>
<p>//一些用于清理的代碼</p>
<p>break;</p>
<p>}</p>
<p>}</p>
<p>return TRUE;</p>
<p>}</p>
<p>int Summary(int n)</p>
<p>{</p>
<p>int sum=0;</p>
<p>int i;</p>
<p>for(i=1;i<=n;i++)</p>
<p>{</p>
<p>sum+=i;</p>
<p>}</p>
<p>return sum;</p>
<p>}</p>
<p>int Factorial(int n)</p>
<p>{</p>
<p>int Fact=1;</p>
<p>int i;</p>
<p>for(i=1;i<=n;i++)</p>
<p>{</p>
<p>Fact=Fact*i;</p>
<p>}</p>
<p>return Fact;</p>
<p>}</p>
<p> 文件2:mymaths.def</p>
<p>;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;</p>
<p>;Mymaths.DEF</p>
<p>;</p>
<p>;The DEF file for the Mymaths.DLL DLL.</p>
<p>;</p>
<p>LIBRARY mymaths</p>
<p>CODE PRELOAD MOVEABLE DISCARDABLE</p>
<p>DATA PRELOAD SINGLE</p>
<p>EXPORTS</p>
<p>;The names of the DLL functions</p>
<p>Summary</p>
<p>Factorial</p>
<p>在文件mymaths.cpp開頭,聲明了動態連接庫所包含的兩個函數:Summary和Factorial。接著是DllEntryPoint()函數的定義。DllEntryPoint()顧名思義是動態連接庫的入口,應用程序通過該入口訪問動態連接庫提供的服務。DllEntryPoint()主體是一個switch/case語句:</p>
<p>switch(dwReason)</p>
<p>{</p>
<p>case DLL_PROCESS_ATTACH:</p>
<p>{</p>
<p>//一些初始化代碼</p>
<p>break;</p>
<p>}</p>
<p>case DLL_PROCESS_DETACH:</p>
<p>{</p>
<p>//一些用于清理的代碼</p>
<p>break;</p>
<p>}</p>
<p>}</p>
<p>其中,在case
DLL_PROCESS_ATTACH分支可加入動態連接庫執行時的一些初始化代碼。在case
DLL_PROCESS_DETACH加入動態連接庫被卸載時的一些清理代碼,比如釋放動態連接庫運行時申請的內存等。</p>
<p> 在DllEntryPoint()函數后,是兩個函數Summary和Factorial函數的定義。它們的定義與前面的靜態庫完全相同。在這里用戶可以放入任何函數。</p>
<p> 另外,我們還需要一個mymaths.def文件。這個文件記錄了可被外部應用程序使用的DLL庫函數名字。這些名字信息和對應的函數位置的信息將被編譯進動態連接庫文件中,然后應用程序根據函數名字和函數位置對照表來找到對應的函數。</p>
<p> 按F7編譯工程,Visual
C++就在mymaths\debug目錄下生成一個mymaths.dll動態連接庫文件。</p>
<p> 現在,我們來使用剛才生成的動態連接庫。我們并不重新生成一個程序,而是修改前面測試靜態庫時的test程序。首先,把mymaths\debug目錄下的mymaths.dll拷貝到test\debug目錄下。test程序運行時,會在該目錄下搜索動態連接庫文件。然后修改testdlg.h,在其中加入一個函數LoadDLL()的聲明,見清單9.4。LoadDLL用于載入動態連接庫。</p>
<p> <b>清單</b><b>9.4
修改后的對話框頭文件</b></p>
<p>class CTestDlg : public CDialog</p>
<p>{</p>
<p>// Construction</p>
<p>public:</p>
<p>CTestDlg(CWnd* pParent = NULL); // standard constructor</p>
<p>protected:</p>
<p>void LoadDLL();</p>
<p>//......</p>
<p>}</p>
<p>然后修改testdlg.cpp,修改后如清單9.5。</p>
<p> <b>清單</b><b>95.
TestDlg.cpp文件</b></p>
<p>// TestDlg.cpp : implementation file</p>
<p>//</p>
<p>#include "stdafx.h"</p>
<p>#include "Test.h"</p>
<p>#include "TestDlg.h"</p>
<p>//#include "mymath.h"
//注釋掉mymath.h頭文件</p>
<p>#ifdef _DEBUG</p>
<p>#define new DEBUG_NEW</p>
<p>#undef THIS_FILE</p>
<p>static char THIS_FILE[] = __FILE__;</p>
<p>#endif</p>
<p>//The instance of the Mymaths.DLL library</p>
<p>HINSTANCE ghMathsDLL=NULL;</p>
<p>//declare the Summary() function from the Mymaths.DLL libray.</p>
<p>typedef int (*SUMMARY)(int);</p>
<p>SUMMARY Summary;</p>
<p>//declare the Factorial() function from</p>
<p>//the Mymaths.DLL library.</p>
<p>typedef int (*FACTORIAL)(int);</p>
<p>FACTORIAL Factorial;</p>
<p>/////////////////////////////////////////////////////////////////////////////</p>
<p>// CAboutDlg dialog used for App About</p>
<p>class CAboutDlg : public CDialog</p>
<p>{</p>
<p>//...</p>
<p>};</p>
<p>//CAboutDlg的一些成員函數定義</p>
<p> //CTestDlg的一些成員函數定義</p>
<p>void CTestDlg::OnSum() </p>
<p>{</p>
<p>// TODO: Add your control notification handler code here</p>
<p>LoadDLL();</p>
<p>int nSum=Summary(10);</p>
<p>CString sResult;</p>
<p>sResult.Format("Sum(10)=%d",nSum);</p>
<p>AfxMessageBox(sResult);</p>
<p>}</p>
<p>void CTestDlg::OnFactorial() </p>
<p>{</p>
<p>// TODO: Add your control notification handler code here</p>
<p>LoadDLL();</p>
<p>int nFact=Factorial(10);</p>
<p>CString sResult;</p>
<p>sResult.Format("10!=%d",nFact);</p>
<p>AfxMessageBox(sResult);</p>
<p>}</p>
<p>void CTestDlg::LoadDLL()</p>
<p>{</p>
<p>//如果DLL已經載入,則返回</p>
<p>if(ghMathsDLL!=NULL)</p>
<p>{</p>
<p>return; </p>
<p>}</p>
<p>//載入Mymaths.DLL文件.</p>
<p>ghMathsDLL=LoadLibrary("mymaths.DLL");</p>
<p>//如果載入DLL失敗,提示用戶</p>
<p>if(ghMathsDLL==NULL)</p>
<p>{</p>
<p>AfxMessageBox("Cannot load DLL file!");</p>
<p>}</p>
<p>//獲得DLL中Summary函數的地址</p>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -