封装socketclient动态链接库

Posted 锋邢天下

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了封装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中的代码。

以上是关于封装socketclient动态链接库的主要内容,如果未能解决你的问题,请参考以下文章

C++封装Halcon算法动态链接库Dll补充

如何从一个动态链接库DLL中查看接口函数

Delphi 动态链接库的动态和静态调用 (仔细读一下)

单例模式 静态库和动态库的区别

iOS 8是否支持动态链接?

我的OpenGL学习进阶之旅NDK开发中find_library查找的系统动态库在哪里?