浅析minigui-1.6.10粘贴板-clipboard
粘贴板是一个在各个独立的进程之间共享数据的IPC通信机制,
对于编译为非lite版本,即threads版本的minigui来说,粘贴板的IPC意义就没有那么明显了,
因为threads是一个只有一个进程,包含多个threads线程,即便不使用粘贴板,
数据仍然可以通过全局量的方式来共享(其实trheads中cbs[]粘贴板管理区数组就是一个全局量了).
InitGUI==>InitMisc==>InitClipBoard()
void InitClipBoard (void)
{
#ifndef _LITE_VERSION // 我们在pc上直接编译的为非lite版本,即没有mginit服务进程的版本[luther.gliethttp].
sem_init (&cb_lock, 0, 1); // 锁信号初始化
#endif
#if defined(_LITE_VERSION) && !defined(_STAND_ALONE)
if (mgIsServer)
#endif
// minigui.h
// #define CBNAME_TEXT ("text")
create_clip_board (CBNAME_TEXT, 1024); // 创建一个名字为,大小为1024字节粘贴板
}
// 定义管理粘贴板的专用数组,该数组中包含每个粘贴板的所有信息:大小,名字,它自己的缓冲区等[luther.gliethttp]
// minigui.h
// #define NR_CLIPBOARDS 4
static CLIPBOARD cbs [NR_CLIPBOARDS];
static int create_clip_board (const char* cb_name, size_t size)
{
int i;
int empty = -1;
if (size <= 0)
return -1;
for (i = 0; i < NR_CLIPBOARDS; i++) {
if (strncmp (cb_name, cbs [i].name, LEN_CLIPBOARD_NAME) == 0) {
// 该名字粘贴板已经有了[luther.gliethttp]
fprintf (stderr, "create clip board error: already existed name.\n");
return CBERR_BADNAME;
}
if (empty < 0 && cbs [i].name [0] == '\0') {
empty = i;
// 之所以这里不break出去,因为后面可能有与cb_name相同的粘贴板了,所以需要继续遍历剩下的所有NR_CLIPBOARDS个粘贴板管理区
}
}
if (empty == NR_CLIPBOARDS)
return CBERR_NOMEM;
// ok, 可以安全创建粘贴板
if (empty >= 0) {
if ((cbs [empty].buff = malloc (size)) == NULL) { // 申请size大小内存
return CBERR_NOMEM;
}
strncpy (cbs [empty].name, cb_name, LEN_CLIPBOARD_NAME); // 拷贝粘贴板名称
cbs[empty].name[LEN_CLIPBOARD_NAME] = 0; // 追加字符串结尾0
cbs [empty].buff_len = size; // 粘贴板大小
cbs [empty].data_len = 0; // 当前粘贴板包含数据大小[luther.gliethttp]
}
return CBERR_OK;
}
// 释放粘贴板
int GUIAPI DestroyClipBoard (const char* cb_name)
{
int ret;
sem_wait (&cb_lock);
ret = destroy_clip_board (cb_name);
sem_post (&cb_lock);
return ret;
}
int GUIAPI destroy_clip_board (const char* cb_name)
{
int i;
for (i = 0; i < NR_CLIPBOARDS; i++) {
if (strcmp (cb_name, cbs [i].name) == 0) {
// 在cbs[]管理区数组中找到注册了的名为cb_name的粘贴板
free (cbs [i].buff); // 释放注册时malloc到的数据存储内存
cbs [i].name [0] = '\0'; // 管理区名字字符串清0
cbs [i].buff = NULL; // 标识无内存指向[luther.gliethttp]
cbs [i].buff_len = 0;
cbs [i].data_len = 0;
return CBERR_OK;
}
}
return CBERR_BADNAME;
}
// 粘贴板创建和销毁都已经说了,来看看怎么使用粘贴板中的数据
1.发送数据到粘贴板
int GUIAPI SetClipBoardData (const char* cb_name, void* data, size_t n, int cbop)
{
int ret;
sem_wait (&cb_lock);
ret = set_clip_board_data (cb_name, data, n, cbop);
sem_post (&cb_lock);
return ret;
}
static int set_clip_board_data (const char* cb_name, void* data, size_t n, int cbop)
{
int i;
CLIPBOARD* cb = NULL;
int dataLen;
for (i = 0; i < NR_CLIPBOARDS; i++) {
if (strncmp (cb_name, cbs [i].name, LEN_CLIPBOARD_NAME) == 0) {
cb = cbs + i;
// ok, 向cb_name粘贴板发送数据初步检验通过,cb_name粘贴板已注册.
break;
}
}
if (cb == NULL)
return CBERR_BADNAME;
if (cbop == CBOP_APPEND) { // 将数据追加到粘贴板以后数据之后
dataLen = MIN (n, cb->buff_len - cb->data_len);
memcpy (cb->buff + cb->data_len, data, dataLen);
cb->data_len += dataLen;
}
else {
// 覆盖粘贴板原有数据,本次操作数据独占该粘贴板[luther.gliethttp]
cb->data_len = MIN (n, cb->buff_len);
if (data && cb->data_len > 0)
memcpy (cb->buff, data, cb->data_len);
}
return CBERR_OK;
}
举例说明:
比如libminigui-1.6.10/src/control/edit.c
RegisterSLEditControl==>WndClass.WinProc = SLEditCtrlProc==>SLEditCtrlProc==>sleKeyDown()
#ifdef _CLIPBOARD_SUPPORT
case SCANCODE_C:
case SCANCODE_X:
{
if ((lParam & KS_CTRL) && (sled->selEnd - sled->selStart > 0)) {
// 将edit中选中数据送到粘贴板[luther.gliethttp]
SetClipBoardData (CBNAME_TEXT, sled->content.string + sled->selStart,
sled->selEnd - sled->selStart, CBOP_NORMAL);
if (wParam == SCANCODE_X && !(GetWindowStyle(hWnd) & ES_READONLY)) {
sleInsertText (hWnd, sled, NULL, 0);
}
}
return 0;
}
2.获取粘贴板所有数据
首先获取粘贴板包含数据字节数
size_t GUIAPI GetClipBoardDataLen (const char* cb_name)
{
int ret;
sem_wait (&cb_lock);
ret = get_clip_board_data_len (cb_name);
sem_post (&cb_lock);
return ret;
}
static size_t get_clip_board_data_len (const char* cb_name)
{
int i;
CLIPBOARD* cb = NULL;
for (i = 0; i < NR_CLIPBOARDS; i++) {
if (strncmp (cb_name, cbs [i].name, LEN_CLIPBOARD_NAME) == 0) {
cb = cbs + i;
break;
}
}
if (cb)
return cb->data_len;
return 0;
}
获取粘贴板数据
size_t GUIAPI GetClipBoardData (const char* cb_name, void* data, size_t n)
{
int ret;
sem_wait (&cb_lock);
ret = get_clip_board_data (cb_name, data, n);
sem_post (&cb_lock);
return ret;
}
static size_t get_clip_board_data (const char* cb_name, void* data, size_t n)
{
int i;
CLIPBOARD* cb = NULL;
int copied_len = 0;
if (!data || n <= 0)
return -1;
for (i = 0; i < NR_CLIPBOARDS; i++) {
if (strncmp (cb_name, cbs [i].name, LEN_CLIPBOARD_NAME) == 0) {
cb = cbs + i;
break;
}
}
if (cb) {
copied_len = MIN (n, cb->data_len);
if (copied_len > 0) {
memcpy (data, cb->buff, copied_len); // 拷贝粘贴板数据
}
}
return copied_len;
}
举例说明:
比如libminigui-1.6.10/src/control/edit.c
RegisterSLEditControl==>WndClass.WinProc = SLEditCtrlProc==>SLEditCtrlProc==>sleKeyDown()==>sleInsertCbText
static int sleInsertCbText (HWND hWnd, PSLEDITDATA sled)
{
int inserting;
unsigned char *txtBuffer;
if (GetWindowStyle(hWnd) & ES_READONLY) {
return 0;
}
inserting = GetClipBoardDataLen (CBNAME_TEXT);// 获取"text"粘贴板包含数据字节数
txtBuffer = ALLOCATE_LOCAL (inserting); // malloc和粘贴板中字节数一致的内存
GetClipBoardData (CBNAME_TEXT, txtBuffer, inserting); // 将粘贴板中数据拷贝到上面malloc到的内存空间[luther.gliethttp]
sleInsertText (hWnd, sled, (char *)txtBuffer, inserting); // 显示粘贴板中数据
DEALLOCATE_LOCAL(txtBuffer); // 释放malloc到的内存空间
return 0;
}
3.获取粘贴板中第x个数据
int GUIAPI GetClipBoardByte (const char* cb_name, int index, unsigned char* byte)
{
int ret;
sem_wait (&cb_lock);
ret = get_clip_board_byte (cb_name, index, byte);
sem_post (&cb_lock);
return ret;
}
static int get_clip_board_byte (const char* cb_name, int index, unsigned char* byte)
{
int i;
CLIPBOARD* cb = NULL;
for (i = 0; i < NR_CLIPBOARDS; i++) {
if (strncmp (cb_name, cbs [i].name, LEN_CLIPBOARD_NAME) == 0) {
cb = cbs + i;
break;
}
}
if (cb) {
if (index < 0 || index >= cb->data_len) {
return CBERR_NOMEM;
}
*byte = cb->buff [index]; // 读取第index偏移处的字节
}
else
return CBERR_BADNAME;
return CBERR_OK;
}
举例说明: 没有发现该用法的实例[luther.gliethttp]
阅读(1582) | 评论(0) | 转发(0) |