封装socketclient动态链接库
一 生成DLL
1 VS2017中新建项目,选择Visual C++ -> Windows桌面 -> 动态链接库
项目名称输入socketclient,点击确定。
2 删除vs默认创建的dllmain.c,stdafx.h,stdafx.c,targetver.h等文件(照顾VS2013等低版本)
3 配置C环境
右键项目 -> 属性 -> C/C++ -> 预编译头 -> 预编译头:改成 创建;
右键项目 -> 属性 -> C/C++ -> 高级 -> 编译 -> 编译为:修改成编译为C代码。点击确定保存
4 在socketclient.h中写函数声明,在socketclient.c中写函数的实现及导出函数
5 点击生成 -> 生成解决方案
会生成socketclient.dll,socketclient.lib等文件
socketclient.h代码如下:
//written by wangbaoming1999@163.com //20140323 23:10 /* 下面定义了一套socket客户端发送报文接受报文的api接口 请写出这套接口api的调用方法 */ #ifndef _INC_Demo01_H #define _INC_Demo01_H #ifdef __cplusplus extern "C" { #endif //------------------第一套api接口---Begin--------------------------------// //客户端初始化 获取handle上下 int cltSocketInit(void **handle /*out*/); //客户端发报文 int cltSocketSend(void *handle /*in*/, unsigned char *buf /*in*/, int buflen /*in*/); //客户端收报文 int cltSocketRev(void *handle /*in*/, unsigned char *buf /*in*/, int *buflen /*in out*/); //客户端释放资源 int cltSocketDestory(void *handle/*in*/); //------------------第一套api接口---End-----------------------------------// //------------------第二套api接口---Begin--------------------------------// int cltSocketInit2(void **handle); //客户端发报文 int cltSocketSend2(void *handle, unsigned char *buf, int buflen); //客户端收报文 int cltSocketRev2(void *handle, unsigned char **buf, int *buflen); int cltSocketRev2_Free(unsigned char **buf); //客户端释放资源 int cltSocketDestory2(void **handle); //------------------第二套api接口---End--------------------------------// #ifdef __cplusplus } #endif #endif /* _INC_Demo01_H */
别忘了在要导出的函数前加__declspec(dllexport)
socketclient.c中代码如下 :
#define _CRT_SECURE_NO_WARNINGS #include <stdlib.h> #include <string.h> #include <stdio.h> #include "itcastlog.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 /*out*/) { int ret = 0; SCK_HANDLE *hdl = NULL; ITCAST_LOG(__FILE__, __LINE__, LogLevel[2], ret, "func cltSocketInit() Begin 22222:%d", ret); hdl = (SCK_HANDLE *)malloc(sizeof(SCK_HANDLE)); if (hdl == NULL) { ret = -1; ITCAST_LOG(__FILE__, __LINE__, LogLevel[4], ret, "func cltSocketInit() err:%d", ret); return ret; } memset(hdl, 0, sizeof(SCK_HANDLE)); //把指针所指向的内存空间 赋值成 0; strcpy(hdl->ip, "192.168.6.254"); hdl->port = 8081; *handle = hdl; ITCAST_LOG(__FILE__, __LINE__, LogLevel[2], ret, "func cltSocketInit() End:%d \n", ret); return ret; } //客户端发报文 __declspec(dllexport) int cltSocketSend(void *handle /*in*/, unsigned char *buf /*in*/, int buflen /*in*/) { int ret = 0; SCK_HANDLE *hdl = NULL; if (handle==NULL || buf==NULL ) { ret = -1; ITCAST_LOG(__FILE__, __LINE__, LogLevel[4], ret, "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; ITCAST_LOG(__FILE__, __LINE__, LogLevel[4], ret, "func cltSocketSend() err: buflen:%d ", buflen); ITCAST_LOG(__FILE__, __LINE__, LogLevel[4], ret, "func cltSocketSend() err:%d\n (unsigned char *)malloc(buflen *sizeof(unsigned char) ", ret); return ret; } memcpy(hdl->p, buf, buflen); hdl->plen = buflen; return 0; } //客户端收报文 __declspec(dllexport) int cltSocketRev(void *handle /*in*/, unsigned char *buf /*in*/, int *buflen /*in out*/) { int ret = 0; SCK_HANDLE *hdl = NULL; if (handle==NULL || buf==NULL ||buflen==NULL) { ret = -1; ITCAST_LOG(__FILE__, __LINE__, LogLevel[4], ret, "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; return ret; } //客户端释放资源 __declspec(dllexport) int cltSocketDestory(void *handle/*in*/) { int ret = 0; SCK_HANDLE *hdl = NULL; if (handle==NULL ) { ret = -1; ITCAST_LOG(__FILE__, __LINE__, LogLevel[4], ret, "func cltSocketDestory() err:%d\n (handle==NULL || buf==NULL ) ", ret); return ret; } hdl = (SCK_HANDLE *)handle; if (hdl->p) { free(hdl->p); } free(hdl); return ret; } //-----------------------第二套api函数--------------------------------*/ __declspec(dllexport) int cltSocketInit2(void **handle) { return cltSocketInit(handle); } //客户端发报文 __declspec(dllexport) int cltSocketSend2(void *handle, unsigned char *buf, int buflen) { return cltSocketSend(handle, buf, buflen); } //客户端收报文 __declspec(dllexport) int cltSocketRev2(void *handle, unsigned char **buf, int *buflen) { int ret = 0; SCK_HANDLE *hdl = NULL; unsigned char *tmp = NULL; if (handle==NULL || buf==NULL ||buflen==NULL) { ret = -1; ITCAST_LOG(__FILE__, __LINE__, LogLevel[4], ret, "func cltSocketRev2() err:%d\n (handle==NULL || buf==NULL ) ", ret); return ret; } hdl = (SCK_HANDLE *)handle; tmp = (unsigned char *)malloc(hdl->plen); if (tmp == NULL) { ret = -2; ITCAST_LOG(__FILE__, __LINE__, LogLevel[4], ret, "func cltSocketRev2() err:%d\n (malloc err ) ", ret); return ret; } memcpy(tmp, hdl->p, hdl->plen); *buflen = hdl->plen; *buf = tmp; //间接赋值 return ret; } __declspec(dllexport) int cltSocketRev2_Free(unsigned char **buf) { if (buf == NULL) { return -1; } if (*buf != NULL) { free(*buf); } *buf = NULL; //*实参的地址 去间接的修改实参的值 重新初始化NULL return 0; } //客户端释放资源 __declspec(dllexport) int cltSocketDestory2(void **handle) { SCK_HANDLE *tmp = NULL; if (handle==NULL) { return -1; } tmp = *handle; if (tmp != NULL) { if (tmp->p) { free(tmp->p); tmp->p = NULL; } free(tmp); } *handle = NULL; //*实参的地址 去间接的修改实参的值 重新初始化NULL return 0; }
二 使用DLL
创建空项目,创建testsocket.c。
①把socketclient.h,socketclient.dll,socketclient.lib复制到testsocket.c的同目录下。添加现有项添加socketclient.h
②右键项目 -> 属性 -> 链接器 -> 输入 -> 附加依赖项:加入mysocketclient.lib
然后就可以在testsocket.c中调用dll中的函数了,即使不使用dllimport关键字也可以。
PS:开着二个项目的vs,在testsocket.c中下断点,F11进入cltSocketInit等接口会发现,VS调试可以进入DLL中的代码。