wfreerdp中剪切板原理
程序员文章站
2024-03-15 19:55:24
...
剪切板是freerdp中相对复杂的一个实现,主要难点在于整个通讯的流程,channel部分和rail的实现相似。主要是在剪切板初始化的时候实现MonitorReady、ServerFormatDataRequest、ServerFormatDataResponse函数。此处仅完成从client->server端的拷贝。
流程简介
- MonitorReady部分,剪切板准备部分。主要是把本地支持的剪切板类型发送给rdp server,这部固定写法,不用纠结。
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 server,这里需要监听windows事件:WM_CLIPBOARDUPDATE。重点:这里只需要通知rdp server支持的类型即可,只有当rdp server内部需要使用剪切板的时候才会找客户端获取。
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 server内部按ctrl-v或者右键->粘贴的时候,freerdp内部会调用swf_cliprdr_server_format_data_request回调。在回调中,打开剪切板、获取数据、发送给rdp server(ClientFormatDataResponse)。
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;
}
上一篇: RTB 广告投放流程详解