受限创建一个win32的控制台DLL项目,添加.c文件和.h文件,需要导出的接口
可以为dll添加错误日志处理,可参考如下
添加日志的时候可以这样调用ITCAST_LOG(__FILE__, __LINE__, LogLevel[4], 4, "func cltSocketInit() err:%d", ret);
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
typedef struct _SCK_HANDLE {
char version[16];
char serverip[16];
int serverport;
char *pBuf;
int buflen ;
}SCK_HANDLE;
//------------------第一套api接口---Begin--------------------------------//
//客户端初始化 获取handle上下
__declspec(dllexport)
int cltSocketInit(void **handle /*out*/)
{
SCK_HANDLE* sh = (SCK_HANDLE*)malloc(sizeof(SCK_HANDLE));
if (!sh)
{
return -1;
}
strcpy(sh->version, "1.0.0");
strcpy(sh->serverip, "192.168.0.100");
sh->serverport = 8080;
*handle = sh;
return 1;
}
//客户端发报文
__declspec(dllexport)
int cltSocketSend(void *handle /*in*/, unsigned char *buf /*in*/, int buflen /*in*/)
{
SCK_HANDLE* sh = NULL;
if (!handle || !buf)
{
return -1;
}
sh = (SCK_HANDLE*)handle;
sh->pBuf = (char *)malloc(buflen * sizeof(char));
if (!sh->pBuf)
{
return -1;
}
memcpy(sh->pBuf, buf, buflen);
sh->buflen = buflen;
return 1;
}
//客户端收报文
__declspec(dllexport)
int cltSocketRev(void *handle /*in*/, unsigned char *buf /*in*/, int *buflen /*in out*/)
{
SCK_HANDLE* sh = NULL;
if (!handle || !buf)
{
return -1;
}
sh = (SCK_HANDLE*)handle;
if (!sh->pBuf)
{
return -1;
}
memcpy(buf, sh->pBuf, sh->buflen);
*buflen = sh->buflen;
return 1;
}
//客户端释放资源
__declspec(dllexport)
int cltSocketDestory(void *handle/*in*/)
{
SCK_HANDLE* sh = NULL;
if (!handle)
{
return 1;
}
sh = (SCK_HANDLE*)handle;
if (sh->pBuf)
{
free(sh->pBuf);
}
free(sh);
return 1;
}
//------------------第一套api接口---End-----------------------------------//
//------------------第二套api接口---Begin--------------------------------//
__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)
{
SCK_HANDLE* sh = NULL;
unsigned char* bufTmp = NULL;
if (!handle || !buf)
{
return -1;
}
sh = (SCK_HANDLE*)handle;
if (!sh->pBuf)
{
return -1;
}
bufTmp = (char*)malloc(sh->buflen * sizeof(char));
if (!bufTmp)
{
return -1;
}
strcpy(bufTmp, sh->pBuf);
*buf = bufTmp;
*buflen = sh->buflen;
return 1;
}
int cltSocketRev2_Free(unsigned char **buf)
{
if (buf == NULL)
{
return -1;
}
free(*buf);
*buf = NULL; //间接的把实参给修改了
return 1;
}
//客户端释放资源
__declspec(dllexport)
int cltSocketDestory2(void **handle)
{
int ret = 0;
SCK_HANDLE *sh = NULL;
if (handle == NULL)
{
return -1;
}
sh = (SCK_HANDLE *) *handle;
if (sh->pBuf != NULL)
{
free(sh->pBuf);
}
free(sh);
*handle = NULL; //间接修改实参的值 避免野指针
return 1;
}
//------------------第二套api接口---End--------------------------------//
#ifndef _INC_Demo01_H
#define _INC_Demo01_H
#ifdef __cplusplus //__cplusplus是cpp中自定义的一个宏
extern "C" { //告诉编译器,这部分代码按C语言的格式进行编译,而不是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)这个声明是告诉编译器该函数是要导出函数,没有这个声明在lib中是不会生成对应接口的,在别的工程中也就不能够调用
该dll编译完成后需要将dll,lib和.h文件拷贝到你的主调用的工程中,然后在项目属性的项目依赖里面添加lib依赖即可调用接口。
#include "stdlib.h"
#include "stdio.h"
#include "string.h"
#include "socketclientdll.h"
int main1()
{
void *handle = NULL;
int resul = -1;
unsigned char buf[128];
int inBufLen = 11;
unsigned char outbuf[128];
int outBufLen = 11;
strcpy(buf, "ddddddddddd");
//客户端初始化 获取handle上下
resul = cltSocketInit(&handle /*out*/);
if (resul != 1)
{
goto End;
}
//客户端发报文
resul = cltSocketSend(handle /*in*/, buf /*in*/, inBufLen /*in*/);
if (resul != 1)
{
goto End;
}
//客户端收报文
resul = cltSocketRev(handle /*in*/, outbuf /*in*/, &outBufLen /*in out*/);
if (resul != 1)
{
goto End;
}
//客户端释放资源
End:
if (handle)
{
cltSocketDestory(handle/*in*/);
}
return 0;
}
int main2()
{
void *handle = NULL;
int resul = -1;
unsigned char buf[128];
int inBufLen = 11;
unsigned char* outbuf = NULL;
int outBufLen = 11;
strcpy(buf, "ddddddddddd");
//客户端初始化 获取handle上下
resul = cltSocketInit2(&handle /*out*/);
if (resul != 1)
{
goto End;
}
//客户端发报文
resul = cltSocketSend2(handle /*in*/, buf /*in*/, inBufLen /*in*/);
if (resul != 1)
{
goto End;
}
//客户端收报文
resul = cltSocketRev2(handle /*in*/, &outbuf /*in*/, &outBufLen /*in out*/);
if (resul != 1)
{
goto End;
}
//客户端释放资源
End:
if (handle)
{
cltSocketDestory2(&handle/*in*/);
}
return 0;
}
可以为dll添加错误日志处理,可参考如下
//written by wangbaoming1999@163.com
//20140323
//itcastlog.h 日志头文件
#ifndef _ITCAST_LOG_H_
#define _ITCAST_LOG_H_
/*
#define IC_NO_LOG_LEVEL 0
#define IC_DEBUG_LEVEL 1
#define IC_INFO_LEVEL 2
#define IC_WARNING_LEVEL 3
#define IC_ERROR_LEVEL 4;
*/
/************************************************************************/
/*
const char *file:文件名称
int line:文件行号
int level:错误级别
0 -- 没有日志
1 -- debug级别
2 -- info级别
3 -- warning级别
4 -- err级别
int status:错误码
const char *fmt:可变参数
*/
/************************************************************************/
//实际使用的Level
extern int LogLevel[5];
void ITCAST_LOG(const char *file, int line, int level, int status, const char *fmt, ...);
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "ItcastLog.h"
#define ITCAST_DEBUG_FILE_ "socketclient.log"
#define ITCAST_MAX_STRING_LEN 10240
//Level类别
#define IC_NO_LOG_LEVEL 0
#define IC_DEBUG_LEVEL 1
#define IC_INFO_LEVEL 2
#define IC_WARNING_LEVEL 3
#define IC_ERROR_LEVEL 4
int LogLevel[5] = {IC_NO_LOG_LEVEL, IC_DEBUG_LEVEL, IC_INFO_LEVEL, IC_WARNING_LEVEL, IC_ERROR_LEVEL};
//Level的名称
char ICLevelName[5][10] = {"NOLOG", "DEBUG", "INFO", "WARNING", "ERROR"};
static int ITCAST_Error_GetCurTime(char* strTime)
{
struct tm* tmTime = NULL;
size_t timeLen = 0;
time_t tTime = 0;
tTime = time(NULL);
tmTime = localtime(&tTime);
//timeLen = strftime(strTime, 33, "%Y(Y)%m(M)%d(D)%H(H)%M(M)%S(S)", tmTime);
timeLen = strftime(strTime, 33, "%Y.%m.%d %H:%M:%S", tmTime);
return timeLen;
}
static int ITCAST_Error_OpenFile(int* pf)
{
char fileName[1024];
memset(fileName, 0, sizeof(fileName));
#ifdef WIN32
sprintf(fileName, "c:\\itcast\\%s",ITCAST_DEBUG_FILE_);
#else
//sprintf(fileName, "%s/log/%s", getenv("HOME"), ITCAST_DEBUG_FILE_);
sprintf(fileName, "c:\\itcast\\%s",ITCAST_DEBUG_FILE_);
#endif
*pf = open(fileName, O_WRONLY|O_CREAT|O_APPEND, 0666);
if(*pf < 0)
{
return -1;
}
return 0;
}
static void ITCAST_Error_Core(const char *file, int line, int level, int status, const char *fmt, va_list args)
{
char str[ITCAST_MAX_STRING_LEN];
int strLen = 0;
char tmpStr[64];
int tmpStrLen = 0;
int pf = 0;
//初始化
memset(str, 0, ITCAST_MAX_STRING_LEN);
memset(tmpStr, 0, 64);
//加入LOG时间
tmpStrLen = ITCAST_Error_GetCurTime(tmpStr);
tmpStrLen = sprintf(str, "[%s] ", tmpStr);
strLen = tmpStrLen;
//加入LOG等级
tmpStrLen = sprintf(str+strLen, "[%s] ", ICLevelName[level]);
strLen += tmpStrLen;
//加入LOG状态
if (status != 0)
{
tmpStrLen = sprintf(str+strLen, "[ERRNO is %d] ", status);
}
else
{
tmpStrLen = sprintf(str+strLen, "[SUCCESS] ");
}
strLen += tmpStrLen;
//加入LOG信息
tmpStrLen = vsprintf(str+strLen, fmt, args);
strLen += tmpStrLen;
//加入LOG发生文件
tmpStrLen = sprintf(str+strLen, " [%s]", file);
strLen += tmpStrLen;
//加入LOG发生行数
tmpStrLen = sprintf(str+strLen, " [%d]\n", line);
strLen += tmpStrLen;
//打开LOG文件
if(ITCAST_Error_OpenFile(&pf))
{
return ;
}
//写入LOG文件
write(pf, str, strLen);
//IC_Log_Error_WriteFile(str);
//关闭文件
close(pf);
return ;
}
void ITCAST_LOG(const char *file, int line, int level, int status, const char *fmt, ...)
{
va_list args;
//判断是否需要写LOG
// if(level!=IC_DEBUG_LEVEL && level!=IC_INFO_LEVEL && level!=IC_WARNING_LEVEL && level!=IC_ERROR_LEVEL)
if(level == IC_NO_LOG_LEVEL)
{
return ;
}
//调用核心的写LOG函数
va_start(args, fmt);
ITCAST_Error_Core(file, line, level, status, fmt, args);
va_end(args);
return ;
}
添加日志的时候可以这样调用ITCAST_LOG(__FILE__, __LINE__, LogLevel[4], 4, "func cltSocketInit() err:%d", ret);
__FILE__和 __LINE__是编译器提供的两个宏定义可以定位当前文件和当前行,具体的可以问百度