一、動態庫生成
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)注入動態庫定義好的句柄指針中。
動態庫預先設計好句柄的結構體留有該接口,然後設計一個函數,可以主動地將外部函數指針和需要的參數注入該句柄中。 此後其它函數可以使用接回來的指針和數據。