欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

wfreerdp中剪切板原理

程序员文章站 2024-03-15 19:55:24
...

剪切板是freerdp中相对复杂的一个实现,主要难点在于整个通讯的流程,channel部分和rail的实现相似。主要是在剪切板初始化的时候实现MonitorReady、ServerFormatDataRequest、ServerFormatDataResponse函数。此处仅完成从client->server端的拷贝。

流程简介

wfreerdp中剪切板原理

  1. 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);
}

  1. 在 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);
}
  1. 当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;
}