VC++ 私类封装DLL的详细步骤

前言

前端时间整理私类生成DLL文件,遇到一些问题,结合自己的实践,整理出来,奉献给大家。
编程环境:Win10+VS2015

一、第一步:创建DLL项目

在这里插入图片描述
选择项目名称DllStone
在这里插入图片描述
默认Unicode字符集,这样就生成DLL的基础文件,DllStone.h和DllStone.cpp

//DllSTone.h
// 下列 ifdef 块是创建使从 DLL 导出更简单的
// 宏的标准方法。此 DLL 中的所有文件都是用命令行上定义的 DLLSTONE_EXPORTS
// 符号编译的。在使用此 DLL 的
// 任何其他项目上不应定义此符号。这样,源文件中包含此文件的任何其他项目都会将
// DLLSTONE_API 函数视为是从 DLL 导入的,而此 DLL 则将用此宏定义的
// 符号视为是被导出的。
#ifdef DLLSTONE_EXPORTS
#define DLLSTONE_API __declspec(dllexport)
#else
#define DLLSTONE_API __declspec(dllimport)
#endif

// 此类是从 DllStone.dll 导出的
class DLLSTONE_API CDllStone {
public:
	CDllStone(void);
	// TODO:  在此添加您的方法。
};

extern DLLSTONE_API int nDllStone;

DLLSTONE_API int fnDllStone(void);
// DllStone.cpp : 定义 DLL 应用程序的导出函数。
//

#include "stdafx.h"
#include "DllStone.h"

// 这是导出变量的一个示例
DLLSTONE_API int nDllStone=0;

// 这是导出函数的一个示例。
DLLSTONE_API int fnDllStone(void)
{
    return 42;
}

// 这是已导出类的构造函数。
// 有关类定义的信息,请参阅 DllStone.h
CDllStone::CDllStone()
{
    return;
}

二、第二步:添加私类定义及库函数

分别在DllStone.h包含文件中,添加CDllStone类函数定义
CString GetStringFromInt(int n);
以及 CString类的包含文件#include <afx.h>

#ifdef DLLSTONE_EXPORTS
#define DLLSTONE_API __declspec(dllexport)
#else
#define DLLSTONE_API __declspec(dllimport)
#endif

#include <afx.h>

// 此类是从 DllStone.dll 导出的
class DLLSTONE_API CDllStone {
public:
	CDllStone(void);
	// TODO:  在此添加您的方法。
	CString GetStringFromInt(int n);
};

extern DLLSTONE_API int nDllStone;

DLLSTONE_API int fnDllStone(void);

在CDllStone.cpp执行文件中,添加CString CDllStone::GetStringFromInt(int n)


#include "stdafx.h"
#include "DllStone.h"

// 这是导出变量的一个示例
DLLSTONE_API int nDllStone=0;

// 这是导出函数的一个示例。
DLLSTONE_API int fnDllStone(void)
{
    return 42;
}

// 这是已导出类的构造函数。
// 有关类定义的信息,请参阅 DllStone.h
CDllStone::CDllStone()
{
    return;
}

CString CDllStone::GetStringFromInt(int n)
{
	CString str;
	str.Format(_T("%d"),n);
	return str;
}

同时,增加其他成员变量及函数,方法类似,略。

三、第三步:编译

1、完成以上步骤后编译,显示:错误 C1189 #error: Building MFC application with /MD[d] (CRT dll version) requires MFC shared dll version. Please #define _AFXDLL or do not use /MD[d]。
修改配置代码生成->运行库为 MTd(Debug)/MT(Release)
在这里插入图片描述
2、继续编译,显示错误 C1189 #error: WINDOWS.H already included. MFC apps must not #include <windows.h>。这是因为在DllStone.h中加入#include <afx.h>所致,把DllStone.h的#include <afx.h>,调整到stdafx.h文件#include <windows.h>之前。

// stdafx.h : 标准系统包含文件的包含文件,
// 或是经常使用但不常更改的
// 特定于项目的包含文件
//

#pragma once

#include "targetver.h"

#include <afx.h>

#define WIN32_LEAN_AND_MEAN             // 从 Windows 头中排除极少使用的资料
// Windows 头文件: 
#include <windows.h>

3、继续编译,显示错误LNK2005 _DllMain@12 已经在 dllmain.obj 中定义 ,打开项目属性对话框, C/C++ ->预处理器->预处理器定义中,去掉 _USRDLL项。编译生成DllStone.lib和DLLStone.dll两个文件,封装DLL完成。

四、第四步:DLL应用

1、在应用程序中加入 #include “DllSTone.h”//注意文件路径,最好将DllStone.h文件拷贝到项目子目录下。
2、添加lib依赖项。Release模式方法相同.
在这里插入图片描述
3、加载DLL函数

     HINSTANCE hDLL = LoadLibrary(L"DllStone.dll");
	if (hDLL == NULL)
	{
		MessageBox(_T("DllStone.DLL加载失败"),_T("操作提示"),MB_OK|MB_ICONSTOP);
	}
	CDllStone MyDll;
	CString str = MyDll.GetStringFromInt(12);

大功告成!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
/*====================================================================================================== =======================================================================================================*/ /*======================================================================================================== 如何使用? 1.引入DLL文件,引入头本文件,就已声明了导入函数 //要引入DLL的方法 //1、把SERIALPORTDLL1.dll和SERIALPORTDLL1.lib拷贝到工程目录下 //2、然后在 工程->设置->连接->分类->常规->对象/库模块输入:SERIALPORTDLL1.lib 2.调用Init初始化串口 3.调用SetReceiveFuntion(&ReveveChar);指定接收和处理数据的函数 4.实现void ReveveChar(WPARAM data, LPARAM port)这个函数 5.调用SendData发送数据 6.ClosePort(); ========================================================================================================*/ /*======================================================================================================= 函 数 名: Init 功 能: 打开并初始化串口 参数说明: UINT port //端口号 UINT baud //波特率 char parity = 'N' //校验位,默认为无校验位 UINT databits = 8 //数据位,一个字节的位数,默认为8位 UINT stopbit = 1 //停止位,默认为1位 使用例子: Init(2,9600); //打开串口2,波特率9600,其它值为默认值(无奇偶校验、数据位为8、停止位为1) Init(4,4800,'N',10);//打开串口4,波特率为4800,无奇偶校验,数据位为10,(停止位默认为1) ... ... ======================================================================================================*/ extern "C" __declspec(dllimport) void Init( UINT port, //端口号 UINT baud, //波特率 char parity = 'N', //校验位 UINT databits=8 , //数据位 UINT stopbit=1 //停止位 ); /*========================================================================================================== 函 数 名: SendData 功 能: 向串口发送数据,使用之前必须先调用Init函数初始化串口 参数说明: char data[] //要发送的数据 int datalen //发送数据的长度 使用例子: 例1: char a[] = {0x01,0x03,0x00,0x03,0x00,0x02,0x34,0x0B};//准备要发送的十六进制:01 03 00 03 00 02 34 0B SendData(a,8); //向串口发送十六进制数:01 03 00 03 00 02 34 0B 例2: char a[] = "$01001000020110*" //准备要发送的字符串$01001000020110* SendData(a,16); //向串口发送:$01001000020110* ============================================================================================================*/ extern "C" __declspec(dllimport) void SendData( char data[], int datalen ); /*=================================================================================================================== 函 数 名: SetReceiveFuntion 功 能: 指定接收数据的函数,指定好后,串口接收缓冲区每有一个字节的数据时会自动触发和调用所指定的函数 参数说明: a、参数需要一个函数指针, b、该指针指向一个用于接收数据的函数(该函数由用户自己声明、定义和实现), c、用户定义该函数时必须要满足一下条件: 1、该函数为全局函数 2、返回值为void 3、形参为两个,类型为:形参为UINT,LONG 使用例子: 1、void ReveveChar(WPARAM data, LPARAM port);//声明一个用于接收数据的全局函数,本头文件已默认声明这个函数,用户无需再次声明 2、 CString strTemp; void ReveveChar(WPARAM data, LPARAM port)//实现这个接收数据并处理数据的函数 { static int RecevCount = 0; //用于接收字节数的计数 char str[512] = ""; sprintf(str,"%02x",data); //接收十六进制数,并格式化为字符形式 strTemp += str; RecevCount++; if (RecevCount >= 8) //接收到数据长度等于了协议长度,则开始进行协议的处理 { RecevCount = 0; strTemp = "接收到得数据协议为" + strTemp; AfxMessageBox(strTemp); strTemp = ""; } } 3、SetReceiveFuntion(&ReveveChar);//指定void ReveveChar(WPARAM data, LPARAM port);该函数接收和处理数据 =========================================================================================================================*/ extern "C" __declspec(dllimport) void SetReceiveFuntion(void (*pfCallBack)(WPARAM data, LPARAM port)); /*================================================= 函 数 名: ClosePort 功 能: 关闭由Init函数打开的串口 参数说明: 无需参数 调用例子: ClosePort(); =================================================*/ extern "C" __declspec(dllimport) void ClosePort(); /*=============================================================================================================== 函 数 名: ReveveChar 功 能: 每当串口接收到一个字符(字节)时就会自动触发和调用这个函数, 用户只需实现不必也不能去亲自调用, 注意:打开串口后,必须要调用SetReceiveFuntion(ReveveChar) 参数说明: data //接收到的是串口中的一个字节数据 port //端口号,表明是哪个端口接收到的数据 调用例子: 只要实现,无需自己调用。 实现处理数据可参考如下简单的例子,思想是边接收数据边处理 void ReveveChar(WPARAM data, LPARAM port) { static int RecevCount = 0; //用于接收字节数的计数 char str[512] = ""; sprintf(str,"%02x",data); //接收十六进制数,并格式化为字符形式 strTemp += str; RecevCount++; if (RecevCount >= 8) //接收到数据长度等于了协议长度,则开始进行协议的处理 { RecevCount = 0; strTemp = "接收到得数据协议为" + strTemp; AfxMessageBox(strTemp); strTemp = ""; } } 说明:本函数并非为导出函数,写在这里仅仅是起到声明一个函数的作用,用户也可以删除掉,自己声明和实现! ===============================================================================================================*/ void ReveveChar(WPARAM data, LPARAM port);

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值