Windows動態連結庫DLL的使用
windows程式設計使用動態連結庫可以有效的分隔大型專案的模組,DLL裡面主要提供函式的呼叫介面(函式名)供其他的外部引用程式呼叫,呼叫者在完全不知道動態連結庫中的實現方式的情況下,仍然能根據其提供的函式名,函式型別, 和函式的引數實現呼叫。windows程式中建立DLL時可以選擇Win32 Dynamic-Link Library和MFC AppWizard[dll]兩者型別的DLL兩者的區別如下:
a、Non-MFC DLL:指的是不用MFC的類庫結構,直接用C語言寫的DLL,其輸出的函式一般用的是標準C介面,並能被非MFC或MFC編寫的應用程式所呼叫。
b、Regular DLL:和下述的Extension Dlls一樣,是用MFC類庫編寫的。明顯的特點是在原始檔裡有一個繼承CWinApp的類。其又可細分成靜態連線到MFC和動態連線到MFC上的。
c、Extension DLL:用來實現從MFC所繼承下來的類的重新利用,也就是說,用這種型別的動態連線庫,可以用來輸出一個從MFC所繼承下來的類。它輸出的函式僅可以被使用MFC且動態連結到MFC的應用程式使用。可以從MFC繼承你所想要的、更適於你自己用的類,並把它提供給你的應用程式。你也可隨意的給你的應用程式提供MFC或MFC繼承類的物件指標。Extension DLL使用MFC的動態連線版本所建立的,並且它只被用MFC類庫所編寫的應用程式所呼叫。
對於Win32 Dynamic-Link Library建立的DLL使用過程如下:
1. 建立基於Win32 Dynamic-Link Library 的一個工程
2. 分別建立.cpp和.h檔案,.h檔案中定義匯出函式,也就是供其他程式呼叫的函式, .cpp實現.h中定義的匯出函式
例如:
在.h 檔案中定義兩個匯出函式MaxYueShu, MinBeiShu
#ifndef ADDDLL_H
#define ADDDLL_H
extern "C" int _declspec(dllexport)MaxYueShu(int num1, int num2);//定義匯出函式
extern "C" int _declspec(dllexport)MinBeiShu(int num1, int num2);
#endif
在.cpp檔案中實現匯出函式,這裡為求兩個數的最大公約數和最下公倍數
#include "addDLL.h"
int MaxYueShu(int num1, int num2)
{
int temp;
while (num1 % num2)
{
temp = num2;
num2 = num1 % num2;
num1 = temp;
}
return num2;
}
int MinBeiShu(int num1, int num2)
{
int temp;
if(num1 < num2)
{
temp = num1;
num1 = num2;
num2 = temp;
}
for(int i = 1; i <= num2; i++)
{
if(!((num1 * i) % num2))
{
return num1 * i;
}
}
}
然後編譯連線就可以在Debug目錄下生成相應的dll檔案,這樣就完成了一個dll檔案的建立,接下來是引用它,重新建立一個工程,將上述生成的dll檔案複製到該工程的Debug目錄下,然後在需要引用的地方新增程式碼
typedef int(*lpAddFun)(int, int);//宣告函式指標
HINSTANCE hDll;//定義接收dll檔案的控制代碼
lpAddFun addFun;
hDll = LoadLibrary("..\\Debug\\AddDLL2.dll");//載入DLL
if(hDll != NULL)
{
addFun = (lpAddFun)GetProcAddress(hDll, "MinBeiShu");//獲取DLL中MinBeiShu函式的地址
if(addFun != NULL)
{
int result = addFun(2, 3); //呼叫函式
CString str;
str.Format("%d", result);
m_Result.SetWindowText(str);
}
FreeLibrary(hDll);//釋放DLL
}
這樣就完成了一個Win32 Dynamic-Link Library的DLL使用。
接下來介紹MFC AppWizard[dll](常規dll)的使用方法,常規DLL又分為靜態連線,動態連線,和擴充套件DLL,因為動態連線到MFC的常規DLL 比較小,所以介紹動態連線到MFC的常規DLL的使用方法;
1. 建立MFC AppWizard[dll工程的DLL
2. 在.def檔案中新增匯出函式,下列聲明瞭兩個匯出函式同上,
例如:
; maxYueshuAndMinBeishu.def : Declares the module parameters for the DLL.
LIBRARY "maxYueshuAndMinBeishu"//DLL的識別符號(名字)
DESCRIPTION 'maxYueshuAndMinBeishu Windows Dynamic Link Library'//DLL的描述
EXPORTS
; Explicit exports can go here
MaxYueShu;//匯出函式
MinBeiShu;
3. 在.h檔案中宣告匯出函式
// maxYueshuAndMinBeishu.h : main header file for the MAXYUESHUANDMINBEISHU DLL
//
#if !defined(AFX_MAXYUESHUANDMINBEISHU_H__4FCC0A2B_E9E9_4E33_964E_B4627D2195C6__INCLUDED_)
#define AFX_MAXYUESHUANDMINBEISHU_H__4FCC0A2B_E9E9_4E33_964E_B4627D2195C6__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include "resource.h" // main symbols
/////////////////////////////////////////////////////////////////////////////
// CMaxYueshuAndMinBeishuApp
// See maxYueshuAndMinBeishu.cpp for the implementation of this class
//
class CMaxYueshuAndMinBeishuApp : public CWinApp
{
public:
CMaxYueshuAndMinBeishuApp();
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMaxYueshuAndMinBeishuApp)
//}}AFX_VIRTUAL
//{{AFX_MSG(CMaxYueshuAndMinBeishuApp)
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
extern "C" int PASCAL MaxYueShu(int num1, int num2);
extern "C" int PASCAL MinBeiShu(int num1, int num2);
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_MAXYUESHUANDMINBEISHU_H__4FCC0A2B_E9E9_4E33_964E_B4627D2195C6__INCLUDED_)
4. 然後在.cpp檔案中實現
// maxYueshuAndMinBeishu.cpp : Defines the initialization routines for the DLL.
//
#include "stdafx.h"
#include "maxYueshuAndMinBeishu.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//
// Note!
//
// If this DLL is dynamically linked against the MFC
// DLLs, any functions exported from this DLL which
// call into MFC must have the AFX_MANAGE_STATE macro
// added at the very beginning of the function.
//
// For example:
//
// extern "C" BOOL PASCAL EXPORT ExportedFunction()
// {
// AFX_MANAGE_STATE(AfxGetStaticModuleState());
// // normal function body here
// }
//
// It is very important that this macro appear in each
// function, prior to any calls into MFC. This means that
// it must appear as the first statement within the
// function, even before any object variable declarations
// as their constructors may generate calls into the MFC
// DLL.
//
// Please see MFC Technical Notes 33 and 58 for additional
// details.
//
/////////////////////////////////////////////////////////////////////////////
// CMaxYueshuAndMinBeishuApp
BEGIN_MESSAGE_MAP(CMaxYueshuAndMinBeishuApp, CWinApp)
//{{AFX_MSG_MAP(CMaxYueshuAndMinBeishuApp)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMaxYueshuAndMinBeishuApp construction
CMaxYueshuAndMinBeishuApp::CMaxYueshuAndMinBeishuApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}
/////////////////////////////////////////////////////////////////////////////
// The one and only CMaxYueshuAndMinBeishuApp object
CMaxYueshuAndMinBeishuApp theApp;
//實現匯出函式
extern "C" int PASCAL MaxYueShu(int num1, int num2)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
int temp;
while (num1 % num2)
{
temp = num2;
num2 = num1 % num2;
num1 = temp;
}
return num2;
}
extern "C" int PASCAL MinBeiShu(int num1, int num2)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
int temp;
if(num1 < num2)
{
temp = num1;
num1 = num2;
num2 = temp;
}
for(int i = 1; i <= num2; i++)
{
if(!((num1 * i) % num2))
{
return num1 * i;
}
}
}
5. 編譯,連線,同樣會在Debug目錄下生成了相應的dll檔案,然後就可以供其他的程式呼叫
新建一個MFC工程,呼叫程式碼如下:
UpdateData(true);
int (__stdcall * lpfn)(int, int);//宣告函式指標
HINSTANCE hinst;//宣告DLL控制代碼
hinst = LoadLibrary("maxYueshuAndMinBeishu.dll");//載入DLL
if(hinst == NULL)
{
AfxMessageBox("載入DLL失敗!");
return;
}
(FARPROC & )lpfn = GetProcAddress(hinst, "MaxYueShu");//獲取MaxYueShu函式地址,GetProcAddress函式返回的是一個FARPROC
if(lpfn == NULL)
{
AfxMessageBox("讀取函式地址失敗!");
return;
}
int result = lpfn(m_Num1, m_Num2);
CString str;
str.Format("%d", result);
m_Result.SetWindowText(str);
FreeLibrary(hinst);
這樣就完成了一次呼叫。