wfreerdp中剪切板原理
剪切板是中相对复杂的一个实现,主要难点在于整个通讯的流程,部分和rail的实现相似。主要是在剪切板初始化的时候实现、est、onse函数。此处仅完成从->端的拷贝。
流程简介
部分,剪切板准备部分。主要是把本地支持的剪切板类型发送给rdp ,这部固定写法,不用纠结。
UINT cliprdr_send_capabilities(CliprdrClientContext* clipboard) {CLIPRDR_GENERAL_CAPABILITY_SET cap_set = {.capabilitySetType = CB_CAPSTYPE_GENERAL, /* CLIPRDR specification requires that this is CB_CAPSTYPE_GENERAL, the only defined set type */.capabilitySetLength = 12, /* The size of the capability set within the PDU - for CB_CAPSTYPE_GENERAL, this is ALWAYS 12 bytes */.version = CB_CAPS_VERSION_2, /* The version of the CLIPRDR specification supported */.generalFlags = CB_USE_LONG_FORMAT_NAMES /* Bitwise OR of all supported feature flags */};CLIPRDR_CAPABILITIES caps = {.cCapabilitiesSets = 1,.capabilitySets = (CLIPRDR_CAPABILITY_SET*)&cap_set};return clipboard->ClientCapabilities(clipboard, &caps);
}
在 rdp 客户端剪切板有变化的时候,通知rdp ,这里需要监听事件:。重点:这里只需要通知rdp 支持的类型即可,只有当rdp 内部需要使用剪切板的时候才会找客户端获取。
case WM_CLIPBOARDUPDATE:cliprdr_send_format_list(swfc->clipboard->context);break;
UINT cliprdr_send_format_list(CliprdrClientContext* cliprdr) {CLIPRDR_FORMAT_LIST format_list = {.formats = (CLIPRDR_FORMAT[]) {{.formatId = CF_TEXT },{ .formatId = CF_UNICODETEXT }},.numFormats = 2};return cliprdr->ClientFormatList(cliprdr, &format_list);
}
当rdp 内部按ctrl-v或者右键->粘贴的时候,内部会调用回调。在回调中,打开剪切板、获取数据、发送给rdp (onse)。
UINT swf_cliprdr_server_format_data_request(CliprdrClientContext* context, CLIPRDR_FORMAT_DATA_REQUEST* formatDataRequest) {UINT rc = CHANNEL_RC_OK;HANDLE hClipdata;swfContext * swfContxt = (swfContext *)context->custom;UINT32 requestedFormatId = formatDataRequest->requestedFormatId;CLIPRDR_FORMAT_DATA_RESPONSE response;size_t size = 0;char* globlemem = NULL;void* buff = NULL;if (!OpenClipboard(swfContxt->hwnd))return ERROR_INTERNAL_ERROR;hClipdata = GetClipboardData(requestedFormatId);if (!hClipdata){CloseClipboard();return ERROR_INTERNAL_ERROR;}globlemem = (char*)GlobalLock(hClipdata);size = (int)GlobalSize(hClipdata);buff = malloc(size);CopyMemory(buff, globlemem, size);GlobalUnlock(hClipdata);CloseClipboard();response.msgFlags = CB_RESPONSE_OK;response.dataLen = size;response.requestedFormatData = (BYTE*)buff;rc = context->ClientFormatDataResponse(context,&response);free(buff);return rc;
}