Merge branch 'master' of github.com:FreeRDP/FreeRDP
This commit is contained in:
commit
b4a78c31bb
@ -227,6 +227,7 @@ void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data
|
||||
cb_event->raw_format_data = (BYTE*) malloc(dataLen);
|
||||
memcpy(cb_event->raw_format_data, Stream_Pointer(s), dataLen);
|
||||
cb_event->raw_format_data_size = dataLen;
|
||||
cb_event->raw_format_unicode = (msgFlags & CB_ASCII_NAMES) ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
if (cliprdr->use_long_format_names)
|
||||
|
@ -110,6 +110,7 @@ static void cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream*
|
||||
{
|
||||
UINT32 version;
|
||||
UINT32 generalFlags;
|
||||
RDP_CB_CLIP_CAPS *caps_event;
|
||||
|
||||
Stream_Read_UINT32(s, version); /* version (4 bytes) */
|
||||
Stream_Read_UINT32(s, generalFlags); /* generalFlags (4 bytes) */
|
||||
@ -120,6 +121,9 @@ static void cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream*
|
||||
cliprdr_print_general_capability_flags(generalFlags);
|
||||
#endif
|
||||
|
||||
caps_event = (RDP_CB_CLIP_CAPS *)freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_ClipCaps, NULL, NULL);
|
||||
caps_event->capabilities = generalFlags;
|
||||
|
||||
if (generalFlags & CB_USE_LONG_FORMAT_NAMES)
|
||||
cliprdr->use_long_format_names = TRUE;
|
||||
|
||||
@ -133,6 +137,9 @@ static void cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream*
|
||||
cliprdr->can_lock_clipdata = TRUE;
|
||||
|
||||
cliprdr->received_caps = TRUE;
|
||||
|
||||
svc_plugin_send_event((rdpSvcPlugin *)cliprdr, (wMessage *)caps_event);
|
||||
|
||||
}
|
||||
|
||||
static void cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, UINT16 length, UINT16 flags)
|
||||
@ -188,14 +195,14 @@ static void cliprdr_send_clip_caps(cliprdrPlugin* cliprdr)
|
||||
|
||||
static void cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr, wStream* s, UINT16 length, UINT16 flags)
|
||||
{
|
||||
wMessage* event;
|
||||
RDP_CB_MONITOR_READY_EVENT* event;
|
||||
|
||||
if (cliprdr->received_caps)
|
||||
cliprdr_send_clip_caps(cliprdr);
|
||||
|
||||
event = freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_MonitorReady, NULL, NULL);
|
||||
event = (RDP_CB_MONITOR_READY_EVENT *)freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_MonitorReady, NULL, NULL);
|
||||
|
||||
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, event);
|
||||
svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage *)event);
|
||||
}
|
||||
|
||||
static void cliprdr_process_receive(rdpSvcPlugin* plugin, wStream* s)
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include <freerdp/utils/event.h>
|
||||
@ -29,54 +30,575 @@
|
||||
|
||||
#include "wf_cliprdr.h"
|
||||
|
||||
/* this macro will update _p pointer */
|
||||
#define Read_UINT32(_p, _v) do { _v = \
|
||||
(UINT32)(*_p) + \
|
||||
(((UINT32)(*(_p + 1))) << 8) + \
|
||||
(((UINT32)(*(_p + 2))) << 16) + \
|
||||
(((UINT32)(*(_p + 3))) << 24); \
|
||||
_p += 4; } while (0)
|
||||
|
||||
/* this macro will NOT update _p pointer */
|
||||
#define Write_UINT32(_p, _v) do { \
|
||||
*(_p) = (_v) & 0xFF; \
|
||||
*(_p + 1) = ((_v) >> 8) & 0xFF; \
|
||||
*(_p + 2) = ((_v) >> 16) & 0xFF; \
|
||||
*(_p + 3) = ((_v) >> 24) & 0xFF; } while (0)
|
||||
|
||||
|
||||
static UINT32 get_local_format_id_by_name(cliprdrContext *cliprdr, void *format_name)
|
||||
{
|
||||
formatMapping *map;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cliprdr->map_size; i++) {
|
||||
map = &cliprdr->format_mappings[i];
|
||||
if ((cliprdr->capabilities & CAPS_USE_LONG_FORMAT_NAMES) != 0) {
|
||||
if (map->name) {
|
||||
if (memcmp(map->name, format_name, wcslen((LPCWSTR)format_name)) == 0)
|
||||
return map->local_format_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static UINT32 get_remote_format_id(cliprdrContext *cliprdr, UINT32 local_format)
|
||||
{
|
||||
formatMapping *map;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cliprdr->map_size; i++) {
|
||||
map = &cliprdr->format_mappings[i];
|
||||
if (map->local_format_id == local_format) {
|
||||
return map->remote_format_id;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void map_ensure_capacity(cliprdrContext *cliprdr)
|
||||
{
|
||||
if (cliprdr->map_size >= cliprdr->map_capacity) {
|
||||
cliprdr->format_mappings = (formatMapping *)realloc(cliprdr->format_mappings,
|
||||
cliprdr->map_capacity * 2);
|
||||
cliprdr->map_capacity *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
static void clear_format_map(cliprdrContext *cliprdr)
|
||||
{
|
||||
formatMapping *map;
|
||||
int i;
|
||||
|
||||
if (cliprdr->format_mappings) {
|
||||
for (i = 0; i < cliprdr->map_size; i++) {
|
||||
map = &cliprdr->format_mappings[i];
|
||||
map->remote_format_id = 0;
|
||||
map->local_format_id = 0;
|
||||
|
||||
if (map->name) {
|
||||
free(map->name);
|
||||
map->name = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cliprdr->map_size= 0;
|
||||
}
|
||||
|
||||
static void cliprdr_send_format_list(cliprdrContext *cliprdr)
|
||||
{
|
||||
RDP_CB_FORMAT_LIST_EVENT *cliprdr_event;
|
||||
BYTE *format_data;
|
||||
int format = 0;
|
||||
int data_size;
|
||||
int format_count;
|
||||
int len = 0;
|
||||
int namelen;
|
||||
|
||||
if (!OpenClipboard(cliprdr->hwndClipboard)) {
|
||||
DEBUG_CLIPRDR("OpenClipboard failed with 0x%x", GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
format_count = CountClipboardFormats();
|
||||
data_size = format_count * (4 + MAX_PATH * 2);
|
||||
|
||||
format_data = (BYTE *)calloc(1, data_size);
|
||||
assert(format_data != NULL);
|
||||
|
||||
while (format = EnumClipboardFormats(format)) {
|
||||
Write_UINT32(format_data + len, format);
|
||||
len += 4;
|
||||
if ((cliprdr->capabilities & CAPS_USE_LONG_FORMAT_NAMES) != 0) {
|
||||
if (format >= CF_MAX) {
|
||||
namelen = GetClipboardFormatNameW(format, (LPWSTR)(format_data + len), MAX_PATH);
|
||||
len += namelen * sizeof(WCHAR);
|
||||
}
|
||||
len += 2; /* end of Unicode string */
|
||||
} else {
|
||||
ZeroMemory(format_data + len, 32);
|
||||
if (format >= CF_MAX) {
|
||||
static wchar_t wName[MAX_PATH] = {0};
|
||||
|
||||
ZeroMemory(wName, MAX_PATH*2);
|
||||
GetClipboardFormatNameW(format, wName, MAX_PATH);
|
||||
memcpy(format_data + len, wName, 32); /* truncate the long name to 32 bytes */
|
||||
}
|
||||
len += 32;
|
||||
}
|
||||
}
|
||||
|
||||
CloseClipboard();
|
||||
|
||||
cliprdr_event = (RDP_CB_FORMAT_LIST_EVENT *) freerdp_event_new(CliprdrChannel_Class,
|
||||
CliprdrChannel_FormatList, NULL, NULL);
|
||||
|
||||
cliprdr_event->raw_format_data = (BYTE *)calloc(1, len);
|
||||
assert(cliprdr_event->raw_format_data != NULL);
|
||||
|
||||
CopyMemory(cliprdr_event->raw_format_data, format_data, len);
|
||||
cliprdr_event->raw_format_data_size = len;
|
||||
|
||||
free(format_data);
|
||||
|
||||
freerdp_channels_send_event(cliprdr->channels, (wMessage *) cliprdr_event);
|
||||
}
|
||||
|
||||
int cliprdr_send_data_request(cliprdrContext *cliprdr, UINT32 format)
|
||||
{
|
||||
RDP_CB_DATA_REQUEST_EVENT *cliprdr_event;
|
||||
int ret;
|
||||
|
||||
cliprdr_event = (RDP_CB_DATA_REQUEST_EVENT *)freerdp_event_new(CliprdrChannel_Class,
|
||||
CliprdrChannel_DataRequest, NULL, NULL);
|
||||
|
||||
if (!cliprdr_event)
|
||||
return -1;
|
||||
|
||||
cliprdr_event->format = get_remote_format_id(cliprdr, format);
|
||||
|
||||
ret = freerdp_channels_send_event(cliprdr->channels, (wMessage *)cliprdr_event);
|
||||
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
|
||||
WaitForSingleObject(cliprdr->response_data_event, INFINITE);
|
||||
ResetEvent(cliprdr->response_data_event);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
static cliprdrContext *cliprdr = NULL;
|
||||
|
||||
switch (Msg) {
|
||||
case WM_CREATE:
|
||||
cliprdr = (cliprdrContext *)((CREATESTRUCT *)lParam)->lpCreateParams;
|
||||
cliprdr->hwndNextViewer = SetClipboardViewer(hWnd);
|
||||
|
||||
if (cliprdr->hwndNextViewer == NULL && GetLastError() != 0) {
|
||||
DEBUG_CLIPRDR("error: SetClipboardViewer failed with 0x%0x.", GetLastError());
|
||||
}
|
||||
cliprdr->hwndClipboard = hWnd;
|
||||
break;
|
||||
|
||||
case WM_CLOSE:
|
||||
ChangeClipboardChain(hWnd, cliprdr->hwndNextViewer);
|
||||
break;
|
||||
|
||||
case WM_CHANGECBCHAIN:
|
||||
if (cliprdr->hwndNextViewer == (HWND)wParam) {
|
||||
cliprdr->hwndNextViewer = (HWND)lParam;
|
||||
} else if (cliprdr->hwndNextViewer != NULL) {
|
||||
SendMessage(cliprdr->hwndNextViewer, Msg, wParam, lParam);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_DRAWCLIPBOARD:
|
||||
if (cliprdr->channel_initialized) {
|
||||
if (GetClipboardOwner() != cliprdr->hwndClipboard) {
|
||||
if (!cliprdr->hmem) {
|
||||
cliprdr->hmem = GlobalFree(cliprdr->hmem);
|
||||
}
|
||||
cliprdr_send_format_list(cliprdr);
|
||||
}
|
||||
}
|
||||
if (cliprdr->hwndNextViewer != NULL && cliprdr->hwndNextViewer != hWnd)
|
||||
SendMessage(cliprdr->hwndNextViewer, Msg, wParam, lParam);
|
||||
break;
|
||||
|
||||
case WM_RENDERALLFORMATS:
|
||||
/* discard all contexts in clipboard */
|
||||
if (!OpenClipboard(cliprdr->hwndClipboard)) {
|
||||
DEBUG_CLIPRDR("OpenClipboard failed with 0x%x", GetLastError());
|
||||
break;
|
||||
}
|
||||
EmptyClipboard();
|
||||
CloseClipboard();
|
||||
break;
|
||||
|
||||
case WM_RENDERFORMAT:
|
||||
if (cliprdr_send_data_request(cliprdr, (UINT32)wParam) != 0) {
|
||||
DEBUG_CLIPRDR("error: cliprdr_send_data_request failed.");
|
||||
break;
|
||||
}
|
||||
|
||||
if (SetClipboardData(wParam, cliprdr->hmem) == NULL) {
|
||||
DEBUG_CLIPRDR("SetClipboardData failed with 0x%x", GetLastError());
|
||||
cliprdr->hmem = GlobalFree(cliprdr->hmem);
|
||||
}
|
||||
/* Note: GlobalFree() is not needed when success */
|
||||
break;
|
||||
|
||||
case WM_CLIPBOARDUPDATE:
|
||||
case WM_DESTROYCLIPBOARD:
|
||||
case WM_ASKCBFORMATNAME:
|
||||
case WM_HSCROLLCLIPBOARD:
|
||||
case WM_PAINTCLIPBOARD:
|
||||
case WM_SIZECLIPBOARD:
|
||||
case WM_VSCROLLCLIPBOARD:
|
||||
default:
|
||||
return DefWindowProc(hWnd, Msg, wParam, lParam);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
static int create_cliprdr_window(cliprdrContext *cliprdr)
|
||||
{
|
||||
WNDCLASSEX wnd_cls;
|
||||
|
||||
ZeroMemory(&wnd_cls, sizeof(WNDCLASSEX));
|
||||
wnd_cls.cbSize = sizeof(WNDCLASSEX);
|
||||
wnd_cls.style = CS_OWNDC;
|
||||
wnd_cls.lpfnWndProc = cliprdr_proc;
|
||||
wnd_cls.cbClsExtra = 0;
|
||||
wnd_cls.cbWndExtra = 0;
|
||||
wnd_cls.hIcon = NULL;
|
||||
wnd_cls.hCursor = NULL;
|
||||
wnd_cls.hbrBackground = NULL;
|
||||
wnd_cls.lpszMenuName = NULL;
|
||||
wnd_cls.lpszClassName = L"ClipboardHiddenMessageProcessor";
|
||||
wnd_cls.hInstance = GetModuleHandle(NULL);
|
||||
wnd_cls.hIconSm = NULL;
|
||||
RegisterClassEx(&wnd_cls);
|
||||
|
||||
cliprdr->hwndClipboard = CreateWindowEx(WS_EX_LEFT,
|
||||
L"ClipboardHiddenMessageProcessor",
|
||||
L"rdpclip",
|
||||
0, 0, 0, 0, 0, HWND_MESSAGE, NULL, GetModuleHandle(NULL), cliprdr);
|
||||
|
||||
if (cliprdr->hwndClipboard == NULL) {
|
||||
DEBUG_CLIPRDR("error: CreateWindowEx failed with %x.", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *cliprdr_thread_func(void *arg)
|
||||
{
|
||||
cliprdrContext *cliprdr = (cliprdrContext *)arg;
|
||||
BOOL mcode;
|
||||
MSG msg;
|
||||
int ret;
|
||||
HRESULT result;
|
||||
|
||||
if ((ret = create_cliprdr_window(cliprdr)) != 0) {
|
||||
DEBUG_CLIPRDR("error: create clipboard window failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while ((mcode = GetMessage(&msg, 0, 0, 0) != 0)) {
|
||||
if (mcode == -1) {
|
||||
DEBUG_CLIPRDR("error: clipboard thread GetMessage failed.");
|
||||
break;
|
||||
} else {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void wf_cliprdr_init(wfContext* wfc, rdpChannels* channels)
|
||||
{
|
||||
cliprdrContext *cliprdr;
|
||||
|
||||
wfc->cliprdr_context = (cliprdrContext *) calloc(1, sizeof(cliprdrContext));
|
||||
cliprdr = (cliprdrContext *) wfc->cliprdr_context;
|
||||
assert(cliprdr != NULL);
|
||||
|
||||
cliprdr->channels = channels;
|
||||
cliprdr->channel_initialized = FALSE;
|
||||
|
||||
cliprdr->map_capacity = 32;
|
||||
cliprdr->map_size = 0;
|
||||
|
||||
cliprdr->format_mappings = (formatMapping *)calloc(1, sizeof(formatMapping) * cliprdr->map_capacity);
|
||||
assert(cliprdr->format_mappings != NULL);
|
||||
|
||||
cliprdr->response_data_event = CreateEvent(NULL, TRUE, FALSE, L"response_data_event");
|
||||
assert(cliprdr->response_data_event != NULL);
|
||||
|
||||
cliprdr->cliprdr_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)cliprdr_thread_func, cliprdr, 0, NULL);
|
||||
assert(cliprdr->cliprdr_thread != NULL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void wf_cliprdr_uninit(wfContext* wfc)
|
||||
{
|
||||
cliprdrContext *cliprdr = (cliprdrContext *) wfc->cliprdr_context;
|
||||
|
||||
if (!cliprdr)
|
||||
return;
|
||||
|
||||
if (cliprdr->hwndClipboard)
|
||||
PostMessage(cliprdr->hwndClipboard, WM_QUIT, 0, 0);
|
||||
|
||||
if (cliprdr->cliprdr_thread) {
|
||||
WaitForSingleObject(cliprdr->cliprdr_thread, INFINITE);
|
||||
CloseHandle(cliprdr->cliprdr_thread);
|
||||
}
|
||||
|
||||
if (cliprdr->response_data_event)
|
||||
CloseHandle(cliprdr->response_data_event);
|
||||
|
||||
clear_format_map(cliprdr);
|
||||
|
||||
if (cliprdr->format_mappings)
|
||||
free(cliprdr->format_mappings);
|
||||
|
||||
free(cliprdr);
|
||||
}
|
||||
|
||||
static void wf_cliprdr_process_cb_monitor_ready_event(wfContext* wfc)
|
||||
static void wf_cliprdr_process_cb_clip_caps_event(wfContext *wfc, RDP_CB_CLIP_CAPS *caps_event)
|
||||
{
|
||||
cliprdrContext *cliprdr = (cliprdrContext *)wfc->cliprdr_context;
|
||||
|
||||
cliprdr->capabilities = caps_event->capabilities;
|
||||
}
|
||||
|
||||
static void wf_cliprdr_process_cb_data_request_event(wfContext* wfc, RDP_CB_DATA_REQUEST_EVENT* event)
|
||||
static void wf_cliprdr_process_cb_monitor_ready_event(wfContext *wfc, RDP_CB_MONITOR_READY_EVENT *ready_event)
|
||||
{
|
||||
cliprdrContext *cliprdr = (cliprdrContext *)wfc->cliprdr_context;
|
||||
|
||||
cliprdr->channel_initialized = TRUE;
|
||||
|
||||
cliprdr_send_format_list(wfc->cliprdr_context);
|
||||
}
|
||||
|
||||
static void wf_cliprdr_process_cb_format_list_event(wfContext* wfc, RDP_CB_FORMAT_LIST_EVENT* event)
|
||||
static void wf_cliprdr_process_cb_data_request_event(wfContext *wfc, RDP_CB_DATA_REQUEST_EVENT *event)
|
||||
{
|
||||
cliprdrContext *cliprdr = (cliprdrContext *)wfc->cliprdr_context;
|
||||
RDP_CB_DATA_RESPONSE_EVENT *responce_event;
|
||||
HANDLE hClipdata;
|
||||
int size = 0;
|
||||
char *buff = NULL;
|
||||
char *globlemem = NULL;
|
||||
UINT32 local_format;
|
||||
|
||||
local_format = event->format;
|
||||
|
||||
if (local_format == 0x9) { /* FORMAT_ID_PALETTE */
|
||||
/* TODO: implement this */
|
||||
DEBUG_CLIPRDR("FORMAT_ID_PALETTE is not supported yet.");
|
||||
} else if (local_format == 0x3) { /* FORMAT_ID_MATEFILE */
|
||||
/* TODO: implement this */
|
||||
DEBUG_CLIPRDR("FORMAT_ID_MATEFILE is not supported yet.");
|
||||
} else if (local_format == RegisterClipboardFormatW(L"FileGroupDescriptorW")) {
|
||||
/* TODO: implement this */
|
||||
DEBUG_CLIPRDR("FileGroupDescriptorW is not supported yet.");
|
||||
} else {
|
||||
if (!OpenClipboard(cliprdr->hwndClipboard)) {
|
||||
DEBUG_CLIPRDR("OpenClipboard failed with 0x%x", GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
hClipdata = GetClipboardData(event->format);
|
||||
if (!hClipdata) {
|
||||
DEBUG_CLIPRDR("GetClipboardData failed.");
|
||||
CloseClipboard();
|
||||
return;
|
||||
}
|
||||
|
||||
globlemem = (char *)GlobalLock(hClipdata);
|
||||
size = GlobalSize(hClipdata);
|
||||
|
||||
buff = (char *)malloc(size);
|
||||
memcpy(buff, globlemem, size);
|
||||
|
||||
GlobalUnlock(hClipdata);
|
||||
|
||||
CloseClipboard();
|
||||
}
|
||||
|
||||
responce_event = (RDP_CB_DATA_RESPONSE_EVENT *)freerdp_event_new(CliprdrChannel_Class,
|
||||
CliprdrChannel_DataResponse, NULL, NULL);
|
||||
|
||||
responce_event->data = (BYTE *)buff;
|
||||
responce_event->size = size;
|
||||
|
||||
freerdp_channels_send_event(cliprdr->channels, (wMessage *) responce_event);
|
||||
|
||||
/* Note: don't free buff here. */
|
||||
}
|
||||
|
||||
static void wf_cliprdr_process_cb_data_response_event(wfContext* wfc, RDP_CB_DATA_RESPONSE_EVENT* event)
|
||||
static void wf_cliprdr_process_cb_format_list_event(wfContext *wfc, RDP_CB_FORMAT_LIST_EVENT *event)
|
||||
{
|
||||
cliprdrContext *cliprdr = (cliprdrContext *)wfc->cliprdr_context;
|
||||
UINT32 left_size = event->raw_format_data_size;
|
||||
int i = 0;
|
||||
BYTE *p;
|
||||
BYTE* end_mark;
|
||||
BOOL format_forbidden = FALSE;
|
||||
|
||||
/* ignore the formats member in event struct, only parsing raw_format_data */
|
||||
|
||||
p = event->raw_format_data;
|
||||
end_mark = p + event->raw_format_data_size;
|
||||
|
||||
clear_format_map(cliprdr);
|
||||
|
||||
if ((cliprdr->capabilities & CAPS_USE_LONG_FORMAT_NAMES) != 0) {
|
||||
while (left_size >= 6) {
|
||||
formatMapping *map;
|
||||
BYTE* tmp;
|
||||
int name_len;
|
||||
|
||||
map = &cliprdr->format_mappings[i++];
|
||||
|
||||
Read_UINT32(p, map->remote_format_id);
|
||||
|
||||
/* get name_len */
|
||||
for (tmp = p, name_len = 0; tmp + 1 < end_mark; tmp += 2, name_len += 2) {
|
||||
if (*((unsigned short*) tmp) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (name_len > 0) {
|
||||
map->name = malloc(name_len + 2);
|
||||
memcpy(map->name, p, name_len + 2);
|
||||
|
||||
map->local_format_id = RegisterClipboardFormatW((LPCWSTR)map->name);
|
||||
} else {
|
||||
map->local_format_id = map->remote_format_id;
|
||||
}
|
||||
|
||||
left_size -= name_len + 4 + 2;
|
||||
p += name_len + 2; /* p's already +4 when Read_UINT32() is called. */
|
||||
|
||||
cliprdr->map_size++;
|
||||
|
||||
map_ensure_capacity(cliprdr);
|
||||
}
|
||||
} else {
|
||||
int k;
|
||||
|
||||
for (k = 0; k < event->raw_format_data_size / 36; k++) {
|
||||
formatMapping *map;
|
||||
int name_len;
|
||||
|
||||
map = &cliprdr->format_mappings[i++];
|
||||
|
||||
Read_UINT32(p, map->remote_format_id);
|
||||
|
||||
if (event->raw_format_unicode) {
|
||||
/* get name_len, in bytes, if the file name is truncated, no terminated null will be included. */
|
||||
for (name_len = 0; name_len < 32; name_len += 2) {
|
||||
if (*((unsigned short*) (p + name_len)) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (name_len > 0) {
|
||||
map->name = calloc(1, name_len + 2);
|
||||
memcpy(map->name, p, name_len);
|
||||
map->local_format_id = RegisterClipboardFormatW((LPCWSTR)map->name);
|
||||
} else {
|
||||
map->local_format_id = map->remote_format_id;
|
||||
}
|
||||
} else {
|
||||
/* get name_len, in bytes, if the file name is truncated, no terminated null will be included. */
|
||||
for (name_len = 0; name_len < 32; name_len += 1) {
|
||||
if (*((unsigned char*) (p + name_len)) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (name_len > 0) {
|
||||
map->name = calloc(1, name_len + 1);
|
||||
memcpy(map->name, p, name_len);
|
||||
map->local_format_id = RegisterClipboardFormatA((LPCSTR)map->name);
|
||||
} else {
|
||||
map->local_format_id = map->remote_format_id;
|
||||
}
|
||||
}
|
||||
|
||||
p += 32; /* p's already +4 when Read_UINT32() is called. */
|
||||
cliprdr->map_size++;
|
||||
map_ensure_capacity(cliprdr);
|
||||
}
|
||||
}
|
||||
|
||||
if (!OpenClipboard(cliprdr->hwndClipboard)) {
|
||||
DEBUG_CLIPRDR("OpenClipboard failed with 0x%x", GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!EmptyClipboard()) {
|
||||
DEBUG_CLIPRDR("EmptyClipboard failed with 0x%x", GetLastError());
|
||||
CloseClipboard();
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < cliprdr->map_size; i++) {
|
||||
SetClipboardData(cliprdr->format_mappings[i].local_format_id, NULL);
|
||||
}
|
||||
|
||||
CloseClipboard();
|
||||
}
|
||||
|
||||
void wf_process_cliprdr_event(wfContext* wfc, wMessage* event)
|
||||
static void wf_cliprdr_process_cb_data_response_event(wfContext *wfc, RDP_CB_DATA_RESPONSE_EVENT *event)
|
||||
{
|
||||
switch (GetMessageType(event->id))
|
||||
{
|
||||
cliprdrContext *cliprdr = (cliprdrContext *)wfc->cliprdr_context;
|
||||
HANDLE hMem;
|
||||
char *buff;
|
||||
|
||||
hMem = GlobalAlloc(GMEM_FIXED, event->size);
|
||||
buff = (char *) GlobalLock(hMem);
|
||||
memcpy(buff, event->data, event->size);
|
||||
GlobalUnlock(hMem);
|
||||
|
||||
cliprdr->hmem = hMem;
|
||||
SetEvent(cliprdr->response_data_event);
|
||||
}
|
||||
|
||||
void wf_process_cliprdr_event(wfContext *wfc, wMessage *event)
|
||||
{
|
||||
switch (GetMessageType(event->id)) {
|
||||
case CliprdrChannel_ClipCaps:
|
||||
wf_cliprdr_process_cb_clip_caps_event(wfc, (RDP_CB_CLIP_CAPS *)event);
|
||||
break;
|
||||
|
||||
case CliprdrChannel_MonitorReady:
|
||||
wf_cliprdr_process_cb_monitor_ready_event(wfc);
|
||||
wf_cliprdr_process_cb_monitor_ready_event(wfc, (RDP_CB_MONITOR_READY_EVENT *)event);
|
||||
break;
|
||||
|
||||
case CliprdrChannel_FormatList:
|
||||
wf_cliprdr_process_cb_format_list_event(wfc, (RDP_CB_FORMAT_LIST_EVENT*) event);
|
||||
wf_cliprdr_process_cb_format_list_event(wfc, (RDP_CB_FORMAT_LIST_EVENT *) event);
|
||||
break;
|
||||
|
||||
case CliprdrChannel_DataRequest:
|
||||
wf_cliprdr_process_cb_data_request_event(wfc, (RDP_CB_DATA_REQUEST_EVENT*) event);
|
||||
wf_cliprdr_process_cb_data_request_event(wfc, (RDP_CB_DATA_REQUEST_EVENT *) event);
|
||||
break;
|
||||
|
||||
case CliprdrChannel_DataResponse:
|
||||
wf_cliprdr_process_cb_data_response_event(wfc, (RDP_CB_DATA_RESPONSE_EVENT*) event);
|
||||
wf_cliprdr_process_cb_data_response_event(wfc, (RDP_CB_DATA_RESPONSE_EVENT *) event);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -21,6 +21,40 @@
|
||||
|
||||
#include "wf_interface.h"
|
||||
|
||||
#ifdef WITH_DEBUG_CLIPRDR
|
||||
#define DEBUG_CLIPRDR(fmt, ...) DEBUG_CLASS(WIN_CLIPRDR, fmt, ## __VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_CLIPRDR(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
typedef struct format_mapping formatMapping;
|
||||
struct format_mapping {
|
||||
UINT32 remote_format_id;
|
||||
UINT32 local_format_id;
|
||||
void *name; /* Unicode or ASCII characters with NULL terminate */
|
||||
};
|
||||
|
||||
typedef struct cliprdr_context cliprdrContext;
|
||||
struct cliprdr_context {
|
||||
rdpChannels *channels;
|
||||
|
||||
UINT32 capabilities;
|
||||
|
||||
formatMapping *format_mappings;
|
||||
int map_capacity;
|
||||
int map_size;
|
||||
|
||||
UINT32 request_format;
|
||||
BOOL channel_initialized;
|
||||
|
||||
HWND hwndClipboard;
|
||||
HWND hwndNextViewer;
|
||||
|
||||
HANDLE cliprdr_thread;
|
||||
HANDLE hmem;
|
||||
HANDLE response_data_event;
|
||||
};
|
||||
|
||||
void wf_cliprdr_init(wfContext* wfc, rdpChannels* channels);
|
||||
void wf_cliprdr_uninit(wfContext* wfc);
|
||||
void wf_process_cliprdr_event(wfContext* wfc, wMessage* event);
|
||||
|
@ -543,12 +543,26 @@ int wf_receive_channel_data(freerdp* instance, int channelId, BYTE* data, int si
|
||||
|
||||
void wf_process_channel_event(rdpChannels* channels, freerdp* instance)
|
||||
{
|
||||
wfContext* wfc;
|
||||
wMessage* event;
|
||||
|
||||
wfc = (wfContext*) instance->context;
|
||||
event = freerdp_channels_pop_event(channels);
|
||||
|
||||
if (event)
|
||||
{
|
||||
switch (GetMessageClass(event->id))
|
||||
{
|
||||
case CliprdrChannel_Class:
|
||||
wf_process_cliprdr_event(wfc, event);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
freerdp_event_free(event);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL wf_get_fds(freerdp* instance, void** rfds, int* rcount, void** wfds, int* wcount)
|
||||
|
@ -63,6 +63,7 @@ struct wf_pointer
|
||||
};
|
||||
typedef struct wf_pointer wfPointer;
|
||||
|
||||
typedef struct cliprdr_context cliprdrContext;
|
||||
struct wf_context
|
||||
{
|
||||
rdpContext context;
|
||||
@ -130,6 +131,7 @@ struct wf_context
|
||||
int yMinScroll; // minimum vertical scroll value
|
||||
int yCurrentScroll; // current vertical scroll value
|
||||
int yMaxScroll; // maximum vertical scroll value
|
||||
cliprdrContext *cliprdr_context;
|
||||
};
|
||||
typedef struct wf_context wfContext;
|
||||
|
||||
|
@ -99,7 +99,24 @@ typedef struct _CLIPRDR_FORMAT_NAME CLIPRDR_FORMAT_NAME;
|
||||
/**
|
||||
* Clipboard Events
|
||||
*/
|
||||
typedef wMessage RDP_CB_MONITOR_READY_EVENT;
|
||||
#define CAPS_USE_LONG_FORMAT_NAMES 0x00000002
|
||||
#define CAPS_STREAM_FILECLIP_ENABLED 0x00000004
|
||||
#define CAPS_FILECLIP_NO_FILE_PATH 0x00000008
|
||||
#define CAPS_CAN_LOCK_CLIPDATA 0x00000010
|
||||
|
||||
struct _RDP_CB_CLIP_CAPS
|
||||
{
|
||||
wMessage event;
|
||||
UINT32 capabilities;
|
||||
};
|
||||
typedef struct _RDP_CB_CLIP_CAPS RDP_CB_CLIP_CAPS;
|
||||
|
||||
struct _RDP_CB_MONITOR_READY_EVENT
|
||||
{
|
||||
wMessage event;
|
||||
UINT32 capabilities;
|
||||
};
|
||||
typedef struct _RDP_CB_MONITOR_READY_EVENT RDP_CB_MONITOR_READY_EVENT;
|
||||
|
||||
struct _RDP_CB_FORMAT_LIST_EVENT
|
||||
{
|
||||
@ -108,6 +125,7 @@ struct _RDP_CB_FORMAT_LIST_EVENT
|
||||
UINT16 num_formats;
|
||||
BYTE* raw_format_data;
|
||||
UINT32 raw_format_data_size;
|
||||
BOOL raw_format_unicode;
|
||||
};
|
||||
typedef struct _RDP_CB_FORMAT_LIST_EVENT RDP_CB_FORMAT_LIST_EVENT;
|
||||
|
||||
|
@ -260,11 +260,13 @@
|
||||
#define CliprdrChannel_FormatList 2
|
||||
#define CliprdrChannel_DataRequest 3
|
||||
#define CliprdrChannel_DataResponse 4
|
||||
#define CliprdrChannel_ClipCaps 5
|
||||
|
||||
#define FREERDP_CLIPRDR_CHANNEL_MONITOR_READY MakeMessageId(CliprdrChannel, MonitorReady)
|
||||
#define FREERDP_CLIPRDR_CHANNEL_FORMAT_LIST MakeMessageId(CliprdrChannel, FormatList)
|
||||
#define FREERDP_CLIPRDR_CHANNEL_FORMAT_LIST MakeMessageId(CliprdrChannel, FormatList)
|
||||
#define FREERDP_CLIPRDR_CHANNEL_DATA_REQUEST MakeMessageId(CliprdrChannel, DataRequest)
|
||||
#define FREERDP_CLIPRDR_CHANNEL_DATA_RESPONSE MakeMessageId(CliprdrChannel, DataResponse)
|
||||
#define FREERDP_CLIPRDR_CHANNEL_CLIP_CAPS MakeMessageId(CliprdrChannel, ClipCaps)
|
||||
|
||||
/**
|
||||
* Multimedia Redirection Channel
|
||||
|
@ -67,6 +67,12 @@ static wMessage* freerdp_cliprdr_event_new(UINT16 event_type)
|
||||
ZeroMemory(event.v, sizeof(RDP_CB_DATA_RESPONSE_EVENT));
|
||||
event.m->id = MakeMessageId(CliprdrChannel, DataResponse);
|
||||
break;
|
||||
|
||||
case CliprdrChannel_ClipCaps:
|
||||
event.v = malloc(sizeof(RDP_CB_CLIP_CAPS));
|
||||
ZeroMemory(event.v, sizeof(RDP_CB_CLIP_CAPS));
|
||||
event.m->id = MakeMessageId(CliprdrChannel, ClipCaps);
|
||||
break;
|
||||
}
|
||||
|
||||
return event.v;
|
||||
|
Loading…
Reference in New Issue
Block a user