wfreerdp中剪切板原理

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

流程简介

在这里插入图片描述

  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;
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
如果你想在一个 Office Add-in 拦截剪切板事件,可以使用 Office.js 的 API 来实现。具体来说,你可以使用 Office.js 的 Binding API 来创建一个与剪切板相关的数据绑定,然后通过该绑定来获取剪切板的数据。 下面是一个简单的示例代码,演示了如何在 Word Add-in 拦截剪切板事件: ```javascript Office.context.document.bindings.addFromSelectionAsync( Office.BindingType.Text, { id: "clipboardBinding" }, function (result) { if (result.status === Office.AsyncResultStatus.Succeeded) { var clipboardBinding = result.value; clipboardBinding.addHandlerAsync( Office.EventType.BindingDataChanged, onClipboardDataChanged); } else { console.log("Failed to create clipboard binding: " + result.error.message); } } ); function onClipboardDataChanged(eventArgs) { // 处理剪切板数据变化事件 console.log("Clipboard data changed: " + eventArgs.bindingData); } ``` 在这个示例代码,我们首先使用 `addFromSelectionAsync` 函数创建了一个文本数据绑定,并指定了一个 ID 为 "clipboardBinding"。然后,我们通过 `addHandlerAsync` 函数注册了一个事件处理程序 `onClipboardDataChanged`,该处理程序会在剪切板数据发生变化时被调用。 在 `onClipboardDataChanged` 处理程序,我们可以通过 `eventArgs.bindingData` 属性获取到剪切板的文本数据,并对其进行处理。需要注意的是,Office Add-in 的数据绑定是异步操作,因此需要在处理程序使用异步操作和回调函数来确保正确的执行顺序和异常处理。
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值