天天看点

C/C++ DLL封装及调用操作步骤

目录

  • 操作步骤
    • 1. 创建dll
    • 2. 创建测试程序

需求:C开发的控制台程序封装为dll,用于C++程序调用

开发环境:VS 2013 Pro

操作步骤

1. 创建dll

  1. 新建工程:C/C++ -> Win32项目, 工程命名dll_generate
    C/C++ DLL封装及调用操作步骤
  2. win32应用程序向导设置:应用程序类型 - DLL,附加选项 - 空项目
    C/C++ DLL封装及调用操作步骤
  3. 在解决方案资源管理器中,在项目选项上右键 - 属性
    C/C++ DLL封装及调用操作步骤
  4. 弹出的项目属性页面中,配置属性 - 常规,右侧配置选项中选择 平台工具集,在下拉列表中选择Visual Studio 2013 - Windows XP(v120_xp)
    C/C++ DLL封装及调用操作步骤
  5. 资源管理器中,头文件 - 右键 - 添加 - 新建项
    C/C++ DLL封装及调用操作步骤
  6. 选择头文件,命名 dll_generate.h。同样方法,添加 component1.h 和 component2.h
    C/C++ DLL封装及调用操作步骤
  7. 编辑头文件代码如下
// dll_generate.h
#pragma once

#ifdef DLL_IMPLEMENT
#define DLL_API _declspec(dllexport)
#else
#define DLL_API _declspec(dllimport)
#endif

#ifdef _cplusplus
extern "C" {
#endif

	int DLL_API Add(int a, int b);

#ifdef _cplusplus
}
#endif
           

dll_generate.h 中

  • DLL_IMPLEMENT用于区分引用该头文件的源文件需要导入dll还是导出dll,由此决定加在函数声明之前的宏定义 DLL_API 为导入命令还是导出命令
  • 如果文件中定义了标志_cplusplus,认为该文件为C++文件。C++语言编写的dll头文件,函数声明需要采用

    extern "C" { *function declaration* }

    的形式
  • 只有添加DLL_API或等效的导入、导出语句的函数声明,才是可以使用dll调用的函数,调用形式与函数声明格式相同
// component1.h
#ifndef __COMPONENT1__
#define __COMPONENT1__

extern int Mul(int a, int b);

#endif
           

component1.h 中声明了一个函数 Mul,实现两数相乘的计算。该函数不在dll中导出,仅在程序内部调用,函数体在源文件中实现

// component2.h
#ifndef __COMPONENT2__
#define __COMPONENT2__

extern int COMP(int a, int b);

#endif
           

component2.h 中声明了一个函数 COMP,实现两数的比较。该函数不在dll中导出,仅在程序内部调用,函数体在源文件中实现

头文件中的

#ifndef ... #define ... #endif

用于防止重复定义
  1. 采用类似的方法,新建三个源文件 dll_generate.c, component1.c, component2.c,添加代码如下
// component1.c
#include "component1.h"

int Mul(int a, int b)
{
	return (a * b);
}
           

component1.c 只需要包含 component1.h

component1.c 中实现了其头文件中定义的 Mul 函数,且Mul函数体只依赖传入参数,没有调用其他函数

// component2.c
#include "component2.h"

int COMP(int a, int b)
{
	if (a > b)
		return a;
	else
		return b;
}
           

component2.c 只需要包含 component2.h

component2.c 中实现了其头文件中定义的 COMP 函数,且 COMP 函数体只依赖传入参数,没有调用其他函数

// dll_generate.c
#define DLL_IMPLEMENT

#include "dll_generate.h"

#include "component1.h"
#include "component2.h"

int Add(int a, int b)
{
	int c = Mul(a, b);
	int d = COMP(a, b);
	return (c * d);
}
           

dll_generate.c 中

  • 由于其定义的函数体 Add 中调用了 Mul 和 COMP,需要包含 component1.h 和 component2.h
  • 该dll工程需要导出dll,所以需要宏定义 DLL_IMPLEMENT
  • 由于dll_generate.h 中的预定义,DLL_IMPLEMENT 宏定义需要在包含 dll_generate.h之前
  • Add 函数体中调用了在其他头文件中声明的函数 (Mul 和 COMP),但是在dll_generate.h 中没有包含其他头文件——声明导出函数的头文件中不需要包含其他头文件,但被导出的函数定义中如果调用了其他函数,需要在源文件中包含对应的头文件
  1. 菜单栏 生成 - 生成解决方案(重新生成解决方案)。输出窗口显示成功,并生成 dll_generate.dll
    C/C++ DLL封装及调用操作步骤
    C/C++ DLL封装及调用操作步骤
  2. 查看生成结果的文件夹(本次采用debug模式,所以产生的文件在Debug目录下),产生了 dll_generate.dll 和 dll_generate.lib 连个文件,dll生成成功
    C/C++ DLL封装及调用操作步骤

2. 创建测试程序

  1. 新建项目,选择 Win32控制台程序,命名为 dll_test
    C/C++ DLL封装及调用操作步骤
  2. Win32向导中,选择 控制台应用程序 - 预编译头,完成
    C/C++ DLL封装及调用操作步骤
  3. 在dll_test\dll_test 目录下新建目录 include 和 lib,将刚刚生成的 dll_generate.lib 复制到新建的 lib 文件夹下,将 dll_generate项目中包含导出函数声明的的 dll_generate.h 复制到新建的include 文件夹下
    C/C++ DLL封装及调用操作步骤
  4. 配置 dll_test 属性
  • 配置属性 - 常规 - 平台工具集,选择 Visual Studio 2013 - Windows XP (v120_xp)
  • 配置属性 - VC++目录 - 包含目录,添加新建的 include 文件夹路径
  • 配置属性 - VC++目录 - 库目录,添加新建的 lib 文件夹
  • 链接器 - 输入 - 附加依赖项,手动输入添加 dll_generate.lib
    C/C++ DLL封装及调用操作步骤
    C/C++ DLL封装及调用操作步骤
    C/C++ DLL封装及调用操作步骤
    C/C++ DLL封装及调用操作步骤
    C/C++ DLL封装及调用操作步骤
  1. 头文件 - 添加 - 现有项,添加复制的 dll_generate.h
  2. 编辑源文件 dll_test.cpp
  • 添加预编译语句
#define _cplusplus
#include "./include/dll_generate.h"
           

此处。由于调用 dll 的 dll_test 为c++编写,所以需要预定义标志 _cplusplus,使 dll_generate.h编译为c++调用的形式

  • main 函数中调用 dll 封装的函数
int c = Add(2, 3);
printf("%d", c);
getchar();
           
  1. 生成解决方案

    不要此时运行程序,否则会由于尚未添加dll文件而出现如下报错

    C/C++ DLL封装及调用操作步骤
  2. 将 dll_generate.dll 复制到生成的 dll_test.exe同一目录下(此处为 dll_test\Debug)
    C/C++ DLL封装及调用操作步骤
  3. 运行程序,弹出窗口并显示正确结果,说明调用成功
    C/C++ DLL封装及调用操作步骤

至此,dll的封装和调用成功。

  • 本案例仅作为 dll 封装的示范,不同版本的VS,操作和设置可能会有不同
  • 案例说明,无论dll中封装的函数调用或嵌套了多少其他函数,无论源文件引用了多少头文件,只需要封装被调用的函数即可,其他内部调用函数不需要封装

继续阅读