您好,欢迎来到意榕旅游网。
搜索
您的当前位置:首页VC++中各种类型DLL编程方法

VC++中各种类型DLL编程方法

来源:意榕旅游网
各种DLL制作方法

一.创建MFC 的常规DLL(设工程名为MyDLL1)(详工程F:\\VcSample\\DLL示例\\DLL动态联接库之构共享内存)

1. 新建工程MFC AppWizard(dll),选第二项- Regular DLL using shared MFC DLL

(选第一项:Regular DLL with MFC statically linked,同第二项的区别是静态联接MFC) 2. 则系统自动建立文件:MyDLL1.h、MyDLL1.cpp、MyDLL1.def等文件. 文件MyDLL1.h内容: (略写) class CMyDLL1 App : public CWinApp {public: CMyDLL1App(); DECLARE_MESSAGE_MAP() }; //+1 MyDLL1.cpp内容(略写) //+3 BEGIN_MESSAGE_MAP(CMyDLL1App, CWinApp) END_MESSAGE_MAP() CMyDLL1App:: CMyDLL1App() { } //+2 CMyDLL1App theApp; 在.def文件中,每行前加上分号表示 注释内容 文件MyDLL1.def 内容 LIBRARY \" MyDLL1\" DESCRIPTION 'MyDLL1 Windows Dynamic Link Library' EXPORTS ; 外部函数出口写在这里 3. 在+1的位置上加入自定义的函数

如:#define DLLEXPORT extern \"C\" _declspec(dllexport)

DLLEXPORT int WINAPI GetCount(); //DLL中定义的函数GetCount() DLLEXPORT void WINAPI AddCount(); // DLL中定义的函数AddCount() 4. 在+2的地方加入在头文件定义的函数的函数体代码内容 int WINAPI GetCount()

{return iCount; } //返回计数值 void WINAPI AddCount()

{ iCount++;} //增加计数值

5. 若要求支持DLL中某些变量为全局共享变量(任何进程改动该变量都会影响其它进程调

用的值),则应在+3的位置加入代码段

#pragma data_seg(\"PANTO\") //字符参数”PANTO“详文件DLLDemo.def中的定义,

//表示这#... #段之间的变量为共享内存变量

int iCount=0; //初始化共享类成员变量为0

#pragma data_seg() //即变量iCount不管哪个进程何时调用并更改后,其以

后调//用均采用最后一次更改的值

6. 更改MyDLL1.def的内容如下:

; DLLDemo.def :在这个文件中为这个DLL声明和定义模块参数. LIBRARY \"DLLDemo\"

DESCRIPTION 'DLLDemo Windows 动态联接库' EXPORTS

; 在这里写输出定义的函数及分配序号

1

;给函数指定一个顺序号以便可以用函数GetProcAddress()调用这个数字 GetCount @1 AddCount @2

;声明PANTO段为共享段,详执行文件DLLDemo.cpp中的变量定义及初始化 SECTIONS

PANTO SHARED ;PANTO仅表示一标签不是关键字,表示在PANTO块中为共享变量 7. 在EXE工程中要调用这个DLL库中的两个函数应: 1>在要调用的函数相关文件中 #include \" MyDLL1.h\" 2>在调用时,不必寻找DLL中函数入口地址,如:

txt.Format(\"从DLL中调用共享内存变量iCount当前值=%d\GetCount()); (由于在EXE工程//中已包含了DLL工程中的主头文件,这里就不必写判断函数入口地址的代码了) pDC->DrawText(txt,&ClientRect,DT_BOTTOM); //往视图上写字符 AddCount(); //调用DLL中的函数,如使公用变量iCount值+1。

二.创建MFC扩展DLL工程(设工程名为MyDLL2) (详工程 F:\\VcSample\\DLL示例\\VC动态联接库示例\\DYNLINK3)

1. MFC AppWizard(dll),选第三项-MFC Extension DLL(using shared MFC DLL) 2. 则系统自动建立文件:MyDLL2.cpp、MyDLL2.def等文件. 文件MyDLL2.cpp内容: (略写) static AFX_EXTENSION_MODULE MyDLL2DLL = { NULL, NULL }; extern \"C\" int APIENTRY DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) {//删除这些若你使用lpReserved UNREFERENCED_PARAMETER(lpReserved); if (dwReason == DLL_PROCESS_ATTACH) { TRACE0(\"MYDLL2.DLL 正初始化!\\n\"); if (!AfxInitExtensionModule(MyDLL2DLL, hInstance)) return 0; new CDynLinkLibrary(MyDLL2DLL); } else if (dwReason == DLL_PROCESS_DETACH) { TRACE0(\"MYDLL2.DLL终止!\\n\"); AfxTermExtensionModule(MyDLL2DLL); } return 1; // 成功 } 文件MyDLL2.def 内容 LIBRARY \" MyDLL2\" DESCRIPTION 'MyDLL2 Windows Dynamic Link Library' EXPORTS ; 外部函数出口写在这里 3. 在DLL工程中任意加入MFC类或继承类(可为对话框类等等),若增加的类要求在

2

EXE工程中可以象在本工程一样的引用方式,则定义的类名前应加上AFX_EXT_CLASS关键字:如class AFX_EXT_CLASS CDllDialog : public Cdialog {„};

4. 将生成的MyDLL2.dll及MyDLL2.lib文件拷贝到EXE工程目录下,并将MyDLL2.lib文

件包含到EXE工程的资源中。

5. 若在EXE文件中要用到DLL中的D11Dialog对话框类,则还应在相应头文件include

#include “D11Dialog.h” //可将此文件从DLL工程目录复制到EXE工程目录 6. 在调用时DLL中函数或引用DLL中类时,无需再查找DLL入口地址,可象本工程中的

其它函数或类一样直接使用.

如: CDllDialog dll; //CDllDialog类在动态联接库文件DYNLINK3.DLL中定义的 dll.DoModal();

三.寻址方式调用DLL(DLL工程中的任何文件不包含在EXE工程中)

1. 新建一Win32 Dynamic-Link Library类型工程,选项二-A mpty DLL project

2.则生成的DLL工程中不含有任何代码文件,这时可自行加入以下代码,若文件名为MyDLL3.c(把文件包含工程中) #include #include #include

#define DllExport __declspec(dllexport)

/////////////////////////////////////////////////////////////////// //定义一个可输出的返回值为long类型的函数Multiply2Longs DllExport long Multiply2Longs(LONG lNum1, LONG lNum2) { return lNum1 * lNum2; }

//定义一个可输出的返回值为char*的函数GetStr DllExport char* GetStr(char* str1) {static char mychar[81]; char* CHARlink;

strcpy(mychar,\"static char mychar[81]=DLL中定义的的字符串\"); CHARlink=mychar;

strcat(CHARlink,\"(加EXE传入DLL中的char *str1=)\"); strcat(CHARlink,str1); return CHARlink; }

3.若要使用DLL中的GetStr函数,则先应把DLL文件复制到EXE工程目录下 void CMainWnd::OnGetStr() { CHAR *CResult; HINSTANCE hModule;

typedef CHAR *(MyType)(CHAR *); MyType* pfunMyType =NULL; //*

VERIFY(hModule = ::LoadLibrary(\"MyDLL3.dll\")); //导入文件MyDLL3.DLL try{ //得到DLL中函数GetStr()的地址 VERIFY(

pfunMyType =

3

(MyType*)::GetProcAddress(

(HMODULE) hModule, \"GetStr\") );

CHAR *ch;

ch=\"EXE传过去的字符串\"; CResult = (*pfunMyType)(ch); CString sMsg; //显示测试结果

sMsg.Format(\"调用DLL文件MyDLL3.dll中函数:\\n DllExport CHAR *GetStr(CHAR * str1)\\n{char *mychar;\\nmychar=\\'\\'.......\\'\\';\\n..........\\n return mychar;(以下为DLL中返回字符串内容:)\\n}\\n :\\n\\n\\n %s\ CResult); ::MessageBeep(MB_OK);

MessageBox(sMsg, \"GetStr()\ }

catch(...)// 释放DLL

{MessageBox(\"调用DLL中函数失败\错误\ FreeLibrary(hModule); }

(注:所有的同EXE无任何关联的DLL都可以用上述方法调用,但必须保证函数名和参数准确) 四.静态调用(设工程名为MyDLL4)

1.同第一种新建工程MFC AppWizard(dll),选第二项- Regular DLL using shared MFC DLL 2.可删除MyDLL4.def文件不用,将系统生成的MyDLL4.h 及MyDLL4.cpp文件更改如下: MyDLL4.h内容 define DllExport __declspec(dllexport) //定义DLL中可导出的全局函数 extern \"C\" DllExport FLOAT MyDLLSub( FLOAT f1, FLOAT f2); class CMyDLL4App : public CWinApp { public: CMyDLL4App(); }; MyDLL4.cpp内容 #include \"stdafx.h\" #include \"resource.h\" // main symbols #include \"MyDLL4.h\" /////////////////////////////////////////////////////CMyDLL4App:: MyDLLSub () { } extern \"C\" DllExport FLOAT MyDLLSub (FLOAT f1, FLOAT { return f1 * f2; } /////////////////////////////////////////////////////CMyDLL4App MyDll; 3.将编绎的MyDLL4.lib文件复制到EXE工程目录下并将它包含含到EXE工程资源中。 1>在EXE主头文件中加入行:

#define DllImport __declspec(dllimport)

extern \"C\" DllImport FLOAT MyDLLSub(FLOAT f1, FLOAT f2); 2>在要调用DLL中的函数MyDLLSub的模块文件中 void CMainWnd::OnFileCallRegularDll() { FLOAT f1 = 25.3f; FLOAT f2 = 13.5f;

FLOAT fResult = MyDLLSub(f1, f2); //不用寻找DLL入口地址 CString sMsg;

4

sMsg.Format(\"调用DLL文件dynlink2.dll中函数:\\n extern \\'C\\'\\' DllExport FLOAT MyDLLSub(FLOAT f1, FLOAT f2)\\n {return f1 * f2;}\\n %0.2f * %0.2f = %0.2f\ f1, f2, fResult); //显示测试结果 ::MessageBeep(MB_OK);

MessageBox(sMsg, \"从MyDLL4.dll中调用函数MyDLLSub()\

MB_ICONINFORMATION);

}

五.纯资源DLL的编制

1.新建工程: 创建一个WIN32 DLL(Win32 Dynamic-Link Library)工程,不是MFC的DLL 2. 资源的DLL就是只包含资源的DLL,例如:图标,位图,字符串,声音,视频,对话框等。使用纯资源DLL可以节约可执行文件的大小,可以被所有的应用程序所共享,从而提高系统性能。纯资源DLL的编写比普通的DLL要简单的多,工程工作空间并没有资源TAB栏,需在向工程中插入资源后系统会提示产生.RC文件,或创建一个资源文件 *.RC,添加到资源DLL的工程中去。然后添加一个初始化DLL的原文件。 如系统默认提供了以下几种:

Accelerator:加速键 Dialog: 对话框 Bitmap: 位图 HTML: 超文本文件 Cursor: 光标 Icon: 图标 Menu: 菜单 String Table:字符串表 Toolbar: 工具条 Version: 版本号 还可以自行导入任何类型的资源(资源名称自己定)如:

AVI:动画 WAV:声音文件 DATA:二进制文件 等等 注意:加入这些自定义资源后,在工作空间资源TAB上显示的资源名有双引号括起 3.示例代码

#include extern \"C\"

BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID ) { return 1;}

这是纯资源DLL所必须需的代码,保存这个文件为*.CPP。编译这个资源DLL。

在应用程序显示的调用这个DLL,使用LoadLibrary函数装入资源DLL,FindResource和LoadResource来装入各种资源,或者使用下列的特定的资源装入函数: FormatMessage LoadAccelerators LoadBitmap LoadCursor LoadIcon LoadMenu LoadString

4. 在EXE工程中调用纯资源DLL的方法:

当资源使用结束,你的应用程序须调用FreeLibrary函数来释放资源。 下面就讲一下如何调用编写好的资源DLL

首先在应用程序中声明一个DLL的句柄,HINSTANCE m_hLibrary;在OnCreate( ) 函数中调用LoadLirbrary( ),在OnDestory( )中调用FreeLibrary()。

5

六.自定义LIB类库的DLL制作过程:

1.在StdAfx.h文件中加入定义 #ifndef _CJX_EXT_CLASS

#ifdef _AFXDLL

#define _CJX_EXT_CLASS AFX_CLASS_EXPORT //总时输出本类库文件... #define _CJX_EXT_CLASS //不使用静态联编辑. #else #endif

#endif // _CJX_EXT_CLASS

2.在DLL主头文件中加入(主头文件要自己加入) //define中的字符串可根据实际进行更改,以符合字意 #ifndef _CJXLIB_INLINE #define _CJXLIB_INLINE inline #endif // _AFXCMN_INLINE #ifndef _CJX_EXT_CLASS #ifdef _AFXDLL

#define _CJX_EXT_CLASS AFX_CLASS_EXPORT //总是输出本DLL文件... #else

#define _CJX_EXT_CLASS // 静态联编DLL文件. #endif

#endif // _CJX_EXT_CLASS #ifndef __AFXTEMPL_H__ #include #endif

#ifndef __AFXPRIV_H__ #include #endif

//#include <..\\src\\afximpl.h> //屏蔽这一系统产生的这一行 #define _delete(p){if(p){delete p;p=NULL;}}

#define _deleteMeta(p){if(p){::DeleteEnhMetaFile(p);p=NULL;}}

#ifndef __MYCOMBOBOXEX_H__ //示例:DLL中有一自定义类CMyComboBox 中的定义#define __MYCOMBOBOXEX_H__ #include \"MyComboBox.h\" #endif

//..............

//以下定义在EXE工程中编绎加载LIB库时出现的编绎信息 #ifdef _AFXDLL #ifdef _DEBUG

#define _CJX_COMMENT \"MyLibd.lib\"

#define _CJX_MESSAGE \"MyLibd类库将自动联接使用动态联接调试版 MyLibd.dll\" #else

#define _CJX_COMMENT \"MyLib.lib\"

#define _CJX_MESSAGE \"MyLib类库将自动联接使用动态联接发行版MyLib.dll\"

6

#endif // _DEBUG #else

#ifdef _DEBUG

#define _CJX_COMMENT \"MyLibdStaticd.lib\"

#define _CJX_MESSAGE \"MyLib类库将自动联接使用静态联接调试版MyLibdStaticd.dll\" #else

#define _CJX_COMMENT \"MyLibStatic.lib\"

#define _CJX_MESSAGE \"MyLib类库将自动联接使用静态联接发行版MyLibStaticd.dll\" #endif // _DEBUG #endif // _AFXDLL

#pragma comment(lib, _CJX_COMMENT) #pragma message(_CJX_MESSAGE)

#endif // __CJLIBRARY_H__

/////////////////////////////////////////////////////////////////////// 3.在DLL主模块文件中加入 #include \"DLL主头文件\"

在DllMain()函数尾加入处理当前打开的是否是正确的DLL版本[可选]

_GetComCtlVersion(); //函数为自定义函数,用于得到系统COMCTL32.DLL的版本号 if (_ComCtlVersion < VERSION_IE4) { }

return 1; // ok

CString str = \"你调用的COMCTL32.DLL文件版本应在 4.2或更高才可以保证程序正常运::MessageBox(NULL, str, \"加载 COMCTL32.DLL失败\return 0;

行...\\n注意!\\n\\nCopyright ?1998-99 罗伟\";

////////////////////////////////////////////////////////////////// 4.向DLL工程中加入类的定义:如重载CComboBox为CMyComboBox

1>用向导向工程中加入类CMyComboBox 生成对应的两文件MyComboBox.h MyComboBox.CPP 2>修改头文件的define定义为(也可不修改,但向导产生的太长) #ifndef __MYCOMBOBOXEX_H__ #define __MYCOMBOBOXEX_H__ 3>修改类名定义为

class _CJX_EXT_CLASS CMyComboBoxEx : public CComboBox { };

//可在类体外加入内联函数的函数定义.如: _CJXLIB_INLINE CMyComboBoxEx::CMyComboBoxEx()

{ }

{ ASSERT(::IsWindow(m_hWnd)); return (BOOL) ::SendMessage(m_hWnd, CBEM_GETEXTENDEDSTYLE, _CJXLIB_INLINE DWORD CMyComboBoxEx::GetExtendedStyle() const

DECLARE_DYNAMIC(CMyComboBoxEx) ...........................

7

0, 0); }

_CJXLIB_INLINE DWORD CMyComboBoxEx::SetExtendedStyle(DWORD dwExMask, DWORD dwExStyles)

{ ASSERT(::IsWindow(m_hWnd)); return (DWORD) ::SendMessage(m_hWnd, CBEM_SETEXTENDEDSTYLE, (DWORD) dwExMask, (LPARAM) dwExStyles); } 4>在类中加入重载或自定义的函数体如:

int CMyComboBoxEx::InsertItem(int iItem, LPCTSTR lpszItem, int iIndent, int iImage, int iSelectedImage, UINT mask) { }

BOOL CMyComboBoxEx::SetItem(const COMBOBOXEXITEM* pCBItem) { }

////////////////////////////////////////////////////////////////////////////////////////////5.在EXE中使用LIB类库的方法

1>在EXE 工程中的StdAfx.h文件中包含DLL工程主头文件

#include \"..\\\\include\\\\CJLibrary.h\" //包含这个文件,可用DLL工程CJLibary动态联接库中的所有类 2>将.DLL 和.LIB文件复制到EXE 工程目录下或在EXE工程中设置LIB库文件所在目录即可 3>在要使用DLL 中的类定义的类中定义成员变量 CMyComboBoxEx * cCombo;

在函数体中象一般变量一样使用DLL中的类函数 3>也可以重载DLL中的类如下例

class CCombo :public CmyComboBoxEx{„..}

ASSERT(::IsWindow(m_hWnd)); ASSERT(pCBItem != NULL);

ASSERT(AfxIsValidAddress(pCBItem, sizeof(COMBOBOXEXITEM), FALSE)); return (int) ::SendMessage(m_hWnd, CBEM_SETITEM, 0, (LPARAM) pCBItem); cbItem.mask cbItem.iItem cbItem.pszText cbItem.iImage cbItem.iIndent

= mask;

= (LPSTR)lpszItem; = iItem; = iImage;

= iIndent;

COMBOBOXEXITEM cbItem;

cbItem.iSelectedImage = iSelectedImage; return InsertItem(&cbItem);

8

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- yrrf.cn 版权所有

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务