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