C++:动态库生成与测试

一、动态库生成
1.新建项目
(1)使用vs建立动态库项目时要选择windows桌面开发向导,选动态库,空项目
(2)要在函数前加导出函数的宏定义__declspec(dllexport)
实例一:每个函数定义前都加该宏定义
__declspec(dllexport)
int cltSocketInit(void **handle)
{
}
实例二:建成头文件,加在函数声明前
__declspec(dllexport)
int cltSocketInit(void **handle);
__declspec(dllexport)
int cltSocketSend(void *handle, unsigned char *buf, int buflen);
实例三:宏定义放在函数定义前,但新建个头文件专门管理函数的声明。这样也方便将该动态库传给他人去调用。

socket动态库实例
mysocketclient.c

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<stdlib.h>
#include<string.h>


typedef struct _SCK_HANDLE
{
	char	version[64];
	char	ip[128];
	int		port;
	unsigned char	*p;
	int		plen;

}SCK_HANDLE;

__declspec(dllexport)
int cltSocketInit(void **handle /*in*/)
{
	int ret = 0;
	SCK_HANDLE *hdl = NULL;

	printf("func begin\n");
	hdl = (SCK_HANDLE*)malloc(sizeof(SCK_HANDLE));
	if (hdl == NULL)
	{
		ret = -1;
		printf("func cltSocketInit() err:%d  \n", ret);
		return ret;
	}
	memset(hdl, 0, sizeof(SCK_HANDLE));  //clear  
	strcpy(hdl->ip, "192.168.6.254");
	hdl->port = 8081;
	*handle = hdl;
	printf("func end\n");
	return 0;
}

__declspec(dllexport)
int cltSocketSend(void *handle, unsigned char *buf, int buflen)
{
	int ret = 0;
	SCK_HANDLE *hdl = NULL;
	printf("send work begin");
	if (handle == NULL || buf == NULL)
	{	
		ret = -1;
		printf("func cltSocketSend() err:%d\n  (handle == NULL)|| buf == NULL", ret);
		return ret;
	}
	hdl = (SCK_HANDLE *)handle;
	hdl->p = (unsigned char *)malloc(buflen * sizeof(unsigned char));
	if (hdl->p == NULL)
	{
		ret = -2;
		printf("func cltSocketSend() err:%d\n  (unsigned char *)malloc(buflen *sezeof(unsigned char)", ret);
		return ret;
	}
	memcpy(hdl->p, buf, buflen);
	hdl->plen = buflen;
	printf("send work end");
	return 0;
}

__declspec(dllexport)
int cltSocketRev(void *handle, unsigned char *buf, int *buflen)
{
	int ret = 0;
	SCK_HANDLE *hdl = NULL;
	printf("  rev work");
	if (handle == NULL || buf == NULL || buflen == NULL)
	{
		ret = -1;
		printf("func cltSocketRev() err:%d\n  (handle == NULL)|| buf == NULL", ret);
		return ret;
	}
	hdl = (SCK_HANDLE *)handle;

	memcpy(buf, hdl->p, hdl->plen);
	*buflen = hdl->plen;
	printf("rev  work end ");
	return 0;
}

__declspec(dllexport)
int cltSocketDestory(void *handle)
{
	int ret = 0;
	SCK_HANDLE *hdl = NULL;
	printf(" des rev work");
	if (handle == NULL )
	{
		ret = -1;
		printf("func cltSocketDestory() err:%d\n  (handle == NULL)", ret);
		return ret;
	}
	hdl = (SCK_HANDLE *)handle;

	if (hdl->p)
	{
		free(hdl -> p);

	}
	free(hdl);
	printf(" des rev work end ");
	return 0;
}

mysocketclient.h

#pragma once

#ifndef  _cplusplus
extern "C" {
#endif // ! _cplusplus

	int cltSocketInit(void **handle);


	int cltSocketSend(void *handle, unsigned char *buf, int buflen);


	int cltSocketRev(void *handle, unsigned char *buf, int *buflen);

#ifndef  _cplusplus
}
#endif // ! _cplusplus

2.动态库的使用
(1)在项目属性,输入的附加依赖项中把.lib包含进来 。
这里可选择给debug 或是 release版本加。 同时,生成动态库时也应该有这两种版本
(2)还包括动态库中用日志记录,加内存监测等功能 , 这个需要加入这俩个功能的.c和.h 并且调用 。后续需要时去找。
FILE LINE 是编译器定义的两个宏, 当前文件,当前行,用于输出日志。
(3)vs中添加预处理的宏: 在属性->c/c++ ->预处理中。 有时候一些应用需要加些宏头

test.c

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include "mysocketclient.h"


int main()
{
	int ret = 0;
	void *handle = NULL;

	unsigned char buf[128] = {0};
	int buflen = 3;

	unsigned char outbuf[128] = {0};
	int outbuflen = 3;

	strcpy(buf, "dssssbdsf");
	ret = cltSocketInit(&handle);
	if (ret != 0)
	{
		printf("func cltSocketInit() err:%d \n", ret);
		return ret;
	}
	ret = cltSocketSend(handle, buf, buflen);
	if (ret != 0)
	{
		printf("func cltSocketSend() err:%d \n", ret);
		return ret;
	}
	ret = cltSocketRev(handle,outbuf,&outbuflen);
	if (ret != 0)
	{
		printf("func cltSocketRev() err:%d \n", ret);
		return ret;
	}
	ret = cltSocketDestory(handle);
	if (ret != 0)
	{
		printf("func cltSocketDestory() err:%d \n", ret);
		return ret;
	}
	printf("outbuf:%s", outbuf);
	system("pause");
	return ret;
}

3.动态库升级成框架
回调函数:利用函数指针做函数参数,实现的一种调用机制,具体任务的实现者,可以不知道什么时候被调用。
回调机制原理:
当具体事件发生时,调用者通过函数指针调用具体函数
回调机制的将调用者和被调函数分开,两者互不依赖

如何实现:
(1)在动态库中预先定义好接口指针。 当某一函数通过调用将要调的这个函数指针和所需要的参数接收回来时,
动态库执行该函数,回调至该函数实现。

(2)注入动态库定义好的句柄指针中。
动态库预先设计好句柄的结构体留有该接口,然后设计一个函数,可以主动地将外部函数指针和需要的参数注入该句柄中。 此后其它函数可以使用接回来的指针和数据。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值