0
点赞
收藏
分享

微信扫一扫

创建动态链接库dll的开发和使用

爱我中华8898 2022-04-13 阅读 46

         相信大家对后缀名为.dll已经很熟悉了,下图中是CALViewer软件的安装路径,可以看到该安装路径下存在很多相关的dll库,这些库称之为动态链接库,在windows中也叫应用程序扩展。

    为什么会有这些库呢,是因为在日常进行软件开发的时候,有些人会将软件的需求(即所有的功能)全部集合在一个工程目录中,这会导致整个工程看起来很臃肿,很笨重,也不利于后期的维护。解决臃肿的问题是将整个工程的需求分为多个子功能,然后可以对一些子功能进行封装,使其成为一个库的形式,在后面的工程中,如果需要用到的话就可以直接调用该库了。

    使用动态链接库的好处不仅仅只有上面的优点哦。

  1. 库可以采用多种编程语言来编写,你可以使用自己熟悉的语言来开发这个库,然后由其它语言编写的可执行程序来调用这些dll。

  2. 提供了二次开发的平台,可以采用dll形式提供一个二次开发的平台,让用户可以利用该dll调用其中实现的功能,编写符合自己业务需求的产品,从而实现二次开发。

  3. 可以节省磁盘空间和内存,如果多个应用程序需要访问同样的功能,那么可以将该功能以dll的形式提供,这样在机器上只需要存在一份该dll文件就可以了,从而节省了磁盘空间。另外,如果多个应用程序使用同一个dll,该dll的页面只需要放入内存一次,所有的应用程序就都可以共享它的页面了。这样,内存的使用将更加有效。

    例如:如图所示就是一个动态链接库被两个进程调用访问时的内存示意图,当32位进程被加载时,系统会为它先分配一个4GB的地址空间,接着分析该可执行模块,找到该程序要调用的dll,然后系统搜索这些dll,找到后就加载它们,并为它们分配虚拟的内存空间,最后将dll的页面映射到调用进程的地址空间。从图中,我们可以看到,dll的虚拟内存有代码页面和数据页面,它们被分别映射到第一个进程的代码页面和数据页面。如果这是第二个进程也启动了,并且它也需要访问该dll,那么这时只需要将该dll在虚拟内存中的代码页面和数据页面映射到第二个进程的地址空间即可。在内存中,只需要存在一份dll的代码和数据。多个进程可以共享dll的同一份代码,这样可以节省内存空间。

        下面我将用Visual Studio 2008编译平台来创建dll工程,然后将dll库挂载到项目中。(例如:创建一个计算器的dll库,该库工程名称为“TEST_DLL”,然后创建另外一个来调用该库的工程,名称为“TEST_USE”),即下面的逻辑,TEST_USE调用TEST_DLL的过程:

        对于TEST_USE基于对话框的工程创建步骤这里就不详细介绍了,按照以往的开发经验即可。下面将重点介绍TEST_DLL的开发过程。

第一步 创建dll的mfc工程

    选择"MFC DLL"选项,然后给库工程起一个名字“TEST_DLL”,并且选择要保存的路径。

        然后点击确定,再点击下一步,然后在该界面一定要选择“带静态链接MFC的规则”,这个选项和上面的“使用共享 MFC DLL 的规则”之间的区别就是,使用共享的生成出来的dll在可执行程序中调用时,要求可执行程序所在的电脑一定要安装Visual Studio环境,不然会报错,而使用“带静态链接 MFC 的规则”就不需要电脑上具备Visual Studio的环境要求。

选择后点击完成,就可以在界面上进行自己的功能需求编写了。

第二步 设计库界面

在编辑器的左边的“资源视图”可以看到我们的dll工程——TEST_DLL。

右键点击"TEST_DLL.rc",选择“添加资源”后,Visual Studio会弹出下面的对话框:

选择“Dialog”后选择右边的“新建”按钮后在“资源视图”可以看到有“Dialog”的目录,并且出现设计界面,我们可以在该界面上进行空间的布局:

点击对话框然后在右边一栏点击“属性”,再将“Border”设置为None,还有Style的属性一定要设置为“Child”

然后选择工具箱,在界面上进行控件的布局,假设我们做个简单的计算器Demo:

双击Button,给dll添加类,设置类名为“TEST”:

第三步 添加代码

在类的头文件TEST.h中将TEST类名之前添加_declspec(dllexport),表示该类TEST为导出类。

class _declspec(dllexport) TEST : public CDialog
{
  DECLARE_DYNAMIC(TEST)

public:
  TEST(CWnd* pParent = NULL);   // 标准构造函数
  virtual ~TEST();

// 对话框数据
  enum { IDD = IDD_DIALOG1 };

protected:
  virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

  DECLARE_MESSAGE_MAP()
public:
  afx_msg void OnBnClickedButton1();
};

在TEST_DLL.h文件中添加创建TEST对话框界面的函数接口TEST *CreateTESTDialog(HWND hWndParent);的声明,该接口返回一个指针,该指针会赋值给调用该dll的TEST_USE工程操作,记住需要添加头文件#include "TEST.h"

// TEST_DLL.h : TEST_DLL DLL 的主头文件
//

#pragma once

#ifndef __AFXWIN_H__
  #error "在包含此文件之前包含“stdafx.h”以生成 PCH 文件"
#endif

#include "resource.h"    // 主符号
#include "TEST.h"

// CTEST_DLLApp
// 有关此类实现的信息,请参阅 TEST_DLL.cpp
//
// 声明这个接口供可执行程序调用创建该dll界面
TEST *CreateTESTDialog(HWND hWndParent);


class CTEST_DLLApp : public CWinApp
{
...
};

在相应的"TEST.cpp"文件中实现该接口:

TEST *CreateTESTDialog(HWND hWndParent)        
{
  AFX_MANAGE_STATE(AfxGetStaticModuleState());                    //模块转换
  TEST *test;
  test = new TEST;                
  CWnd *pWndParent = CWnd::FromHandle(hWndParent);
  test->Create(IDD_DIALOG1,pWndParent);
  return test;
}

接下来在文件“TEST_DLL_.def”中添加需要导出的函数 CreateTESTDialog  @1  

; TEST_DLL.def : 声明 DLL 的模块参数。

LIBRARY      "TEST_DLL"

EXPORTS
    ; 此处可以是显式导出
    CreateTESTDialog  @1    

其中,具体的控件代码编写这里就不多说了。

第四步 导出库到可执行程序

 选择编译器中的Debug(Release)生成对应的dll文件和lib文件,点击运行按钮,然后打开dll工程所在的文件路径,可以看到生成了对应的TEST_DLL.dll和TEST_DLL.lib。

将Debug(Release)中的dll和lib文件复制到要调用该dll的工程TEST_USE中的Debug(Release)文件夹中,此外还得把dll工程中的TEST_DLL.h和TEST.h文件复制到调用dll的工程TEST_USE中去。

第五步 在TEST_USE工程中使用dll

在工程TEST_USE的“TEST_USEDlg.cpp”中添加:


#include "TEST_DLL.h"
#pragma comment(lib,"../Debug/TEST_DLL.lib")

将TEST_USE中的“TEST.h”文件中的 enum { IDD = IDD_DIALOG1 };IDD修改为TEST_USE工程中的界面IDD。接下来在TEST_USEDlg.h中定义一个TEST类的指针,用来指向dll的界面。


public:
  TEST *test;

最后在TEST_USEDlg.cpp的OnInitDialog中添加以下代码(其中m_par表示在TEST_USE工程的界面上EDIT控件的控件变量,也就是说将计算器的界面挂载到TEST_USE中的EDIT控件中显示):

// 调用库dll工程中的界面,并且将指针返回给test
  test = CreateTESTDialog(m_par.m_hWnd);

  // 在TEST_USE工程中放置的控件Edit,设置窗口大小,以便dll界面可以放置到这个控件当中
  CRect rect;
  m_par.GetClientRect(&rect);
  rect.top += 22;
  rect.left +=2;
  rect.right -= 2;
  rect.bottom -=2;

  
  test->MoveWindow(&rect);
  test->ShowWindow(SW_SHOW);

第六步 运行

举报

相关推荐

0 条评论