VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/VBoxTray/VBoxClipboard.cpp@ 55628

Last change on this file since 55628 was 55401, checked in by vboxsync, 10 years ago

added a couple of missing Id headers

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.7 KB
Line 
1/* $Id: VBoxClipboard.cpp 55401 2015-04-23 10:03:17Z vboxsync $ */
2/** @file
3 *
4 * VBoxClipboard - Shared clipboard
5 *
6 */
7
8/*
9 * Copyright (C) 2006-2014 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20#include "VBoxTray.h"
21#include "VBoxHelpers.h"
22
23#include <VBox/HostServices/VBoxClipboardSvc.h>
24#include <strsafe.h>
25
26#include <VBox/VMMDev.h>
27#ifdef DEBUG
28# define LOG_ENABLED
29# define LOG_GROUP LOG_GROUP_DEFAULT
30#endif
31#include <VBox/log.h>
32
33
34
35typedef struct _VBOXCLIPBOARDCONTEXT
36{
37 const VBOXSERVICEENV *pEnv;
38
39 uint32_t u32ClientID;
40
41 ATOM atomWindowClass;
42
43 HWND hwnd;
44
45 HWND hwndNextInChain;
46
47 UINT timerRefresh;
48
49 bool fCBChainPingInProcess;
50
51// bool fOperational;
52
53// uint32_t u32LastSentFormat;
54// uint64_t u64LastSentCRC64;
55
56} VBOXCLIPBOARDCONTEXT;
57
58static char gachWindowClassName[] = "VBoxSharedClipboardClass";
59
60enum { CBCHAIN_TIMEOUT = 5000 /* ms */ };
61
62static int vboxClipboardChanged(VBOXCLIPBOARDCONTEXT *pCtx)
63{
64 AssertPtr(pCtx);
65
66 /* Query list of available formats and report to host. */
67 int rc = VINF_SUCCESS;
68 if (FALSE == OpenClipboard(pCtx->hwnd))
69 {
70 rc = RTErrConvertFromWin32(GetLastError());
71 }
72 else
73 {
74 uint32_t u32Formats = 0;
75 UINT format = 0;
76
77 while ((format = EnumClipboardFormats (format)) != 0)
78 {
79 LogFlowFunc(("vboxClipboardChanged: format = 0x%08X\n", format));
80 switch (format)
81 {
82 case CF_UNICODETEXT:
83 case CF_TEXT:
84 u32Formats |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
85 break;
86
87 case CF_DIB:
88 case CF_BITMAP:
89 u32Formats |= VBOX_SHARED_CLIPBOARD_FMT_BITMAP;
90 break;
91
92 default:
93 if (format >= 0xC000)
94 {
95 TCHAR szFormatName[256];
96
97 int cActual = GetClipboardFormatName(format, szFormatName, sizeof(szFormatName)/sizeof (TCHAR));
98 if (cActual)
99 {
100 if (strcmp (szFormatName, "HTML Format") == 0)
101 {
102 u32Formats |= VBOX_SHARED_CLIPBOARD_FMT_HTML;
103 }
104 }
105 }
106 break;
107 }
108 }
109
110 CloseClipboard ();
111 rc = VbglR3ClipboardReportFormats(pCtx->u32ClientID, u32Formats);
112 }
113 return rc;
114}
115
116/* Add ourselves into the chain of cliboard listeners */
117static void addToCBChain (VBOXCLIPBOARDCONTEXT *pCtx)
118{
119 pCtx->hwndNextInChain = SetClipboardViewer (pCtx->hwnd);
120}
121
122/* Remove ourselves from the chain of cliboard listeners */
123static void removeFromCBChain (VBOXCLIPBOARDCONTEXT *pCtx)
124{
125 ChangeClipboardChain (pCtx->hwnd, pCtx->hwndNextInChain);
126 pCtx->hwndNextInChain = NULL;
127}
128
129/* Callback which is invoked when we have successfully pinged ourselves down the
130 * clipboard chain. We simply unset a boolean flag to say that we are responding.
131 * There is a race if a ping returns after the next one is initiated, but nothing
132 * very bad is likely to happen. */
133VOID CALLBACK CBChainPingProc(HWND hwnd, UINT uMsg, ULONG_PTR dwData, LRESULT lResult)
134{
135 (void) hwnd;
136 (void) uMsg;
137 (void) lResult;
138 VBOXCLIPBOARDCONTEXT *pCtx = (VBOXCLIPBOARDCONTEXT *)dwData;
139 pCtx->fCBChainPingInProcess = FALSE;
140}
141
142static LRESULT vboxClipboardProcessMsg(VBOXCLIPBOARDCONTEXT *pCtx, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
143{
144 LRESULT rc = 0;
145
146 switch (msg)
147 {
148 case WM_CHANGECBCHAIN:
149 {
150 HWND hwndRemoved = (HWND)wParam;
151 HWND hwndNext = (HWND)lParam;
152
153 LogFlowFunc(("WM_CHANGECBCHAIN: hwndRemoved %p, hwndNext %p, hwnd %p\n", hwndRemoved, hwndNext, pCtx->hwnd));
154
155 if (hwndRemoved == pCtx->hwndNextInChain)
156 {
157 /* The window that was next to our in the chain is being removed.
158 * Relink to the new next window. */
159 pCtx->hwndNextInChain = hwndNext;
160 }
161 else
162 {
163 if (pCtx->hwndNextInChain)
164 {
165 /* Pass the message further. */
166 DWORD_PTR dwResult;
167 rc = SendMessageTimeout(pCtx->hwndNextInChain, WM_CHANGECBCHAIN, wParam, lParam, 0, CBCHAIN_TIMEOUT, &dwResult);
168 if (!rc)
169 rc = (LRESULT) dwResult;
170 }
171 }
172 } break;
173
174 case WM_DRAWCLIPBOARD:
175 {
176 LogFlowFunc(("WM_DRAWCLIPBOARD, hwnd %p\n", pCtx->hwnd));
177
178 if (GetClipboardOwner () != hwnd)
179 {
180 /* Clipboard was updated by another application. */
181 /* WM_DRAWCLIPBOARD always expects a return code of 0, so don't change "rc" here. */
182 int vboxrc = vboxClipboardChanged(pCtx);
183 if (RT_FAILURE(vboxrc))
184 LogFlowFunc(("vboxClipboardChanged failed, rc = %Rrc\n", vboxrc));
185 }
186
187 /* Pass the message to next windows in the clipboard chain. */
188 SendMessageTimeout(pCtx->hwndNextInChain, msg, wParam, lParam, 0, CBCHAIN_TIMEOUT, NULL);
189 } break;
190
191 case WM_TIMER:
192 {
193 HWND hViewer = GetClipboardViewer();
194
195 /* Re-register ourselves in the clipboard chain if our last ping
196 * timed out or there seems to be no valid chain. */
197 if (!hViewer || pCtx->fCBChainPingInProcess)
198 {
199 removeFromCBChain(pCtx);
200 addToCBChain(pCtx);
201 }
202 /* Start a new ping by passing a dummy WM_CHANGECBCHAIN to be
203 * processed by ourselves to the chain. */
204 pCtx->fCBChainPingInProcess = TRUE;
205 hViewer = GetClipboardViewer();
206 if (hViewer)
207 SendMessageCallback(hViewer, WM_CHANGECBCHAIN, (WPARAM)pCtx->hwndNextInChain, (LPARAM)pCtx->hwndNextInChain, CBChainPingProc, (ULONG_PTR) pCtx);
208 } break;
209
210 case WM_CLOSE:
211 {
212 /* Do nothing. Ignore the message. */
213 } break;
214
215 case WM_RENDERFORMAT:
216 {
217 /* Insert the requested clipboard format data into the clipboard. */
218 uint32_t u32Format = 0;
219 UINT format = (UINT)wParam;
220
221 LogFlowFunc(("WM_RENDERFORMAT, format = %x\n", format));
222 switch (format)
223 {
224 case CF_UNICODETEXT:
225 u32Format |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
226 break;
227
228 case CF_DIB:
229 u32Format |= VBOX_SHARED_CLIPBOARD_FMT_BITMAP;
230 break;
231
232 default:
233 if (format >= 0xC000)
234 {
235 TCHAR szFormatName[256];
236
237 int cActual = GetClipboardFormatName(format, szFormatName, sizeof(szFormatName)/sizeof (TCHAR));
238 if (cActual)
239 {
240 if (strcmp (szFormatName, "HTML Format") == 0)
241 {
242 u32Format |= VBOX_SHARED_CLIPBOARD_FMT_HTML;
243 }
244 }
245 }
246 break;
247 }
248
249 if (u32Format == 0)
250 {
251 /* Unsupported clipboard format is requested. */
252 LogFlowFunc(("Unsupported clipboard format requested: %ld\n", u32Format));
253 EmptyClipboard();
254 }
255 else
256 {
257 const uint32_t cbPrealloc = 4096; /* @todo r=andy Make it dynamic for supporting larger text buffers! */
258 uint32_t cb = 0;
259
260 /* Preallocate a buffer, most of small text transfers will fit into it. */
261 HANDLE hMem = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, cbPrealloc);
262 LogFlowFunc(("Preallocated handle hMem = %p\n", hMem));
263
264 if (hMem)
265 {
266 void *pMem = GlobalLock(hMem);
267 LogFlowFunc(("Locked pMem = %p, GlobalSize = %ld\n", pMem, GlobalSize(hMem)));
268
269 if (pMem)
270 {
271 /* Read the host data to the preallocated buffer. */
272 int vboxrc = VbglR3ClipboardReadData(pCtx->u32ClientID, u32Format, pMem, cbPrealloc, &cb);
273 LogFlowFunc(("VbglR3ClipboardReadData returned with rc = %Rrc\n", vboxrc));
274
275 if (RT_SUCCESS(vboxrc))
276 {
277 if (cb == 0)
278 {
279 /* 0 bytes returned means the clipboard is empty.
280 * Deallocate the memory and set hMem to NULL to get to
281 * the clipboard empty code path. */
282 GlobalUnlock(hMem);
283 GlobalFree(hMem);
284 hMem = NULL;
285 }
286 else if (cb > cbPrealloc)
287 {
288 GlobalUnlock(hMem);
289
290 /* The preallocated buffer is too small, adjust the size. */
291 hMem = GlobalReAlloc(hMem, cb, 0);
292 LogFlowFunc(("Reallocated hMem = %p\n", hMem));
293
294 if (hMem)
295 {
296 pMem = GlobalLock(hMem);
297 LogFlowFunc(("Locked pMem = %p, GlobalSize = %ld\n", pMem, GlobalSize(hMem)));
298
299 if (pMem)
300 {
301 /* Read the host data to the preallocated buffer. */
302 uint32_t cbNew = 0;
303 vboxrc = VbglR3ClipboardReadData(pCtx->u32ClientID, u32Format, pMem, cb, &cbNew);
304 LogFlowFunc(("VbglR3ClipboardReadData returned with rc = %Rrc, cb = %d, cbNew = %d\n", vboxrc, cb, cbNew));
305
306 if (RT_SUCCESS (vboxrc) && cbNew <= cb)
307 {
308 cb = cbNew;
309 }
310 else
311 {
312 GlobalUnlock(hMem);
313 GlobalFree(hMem);
314 hMem = NULL;
315 }
316 }
317 else
318 {
319 GlobalFree(hMem);
320 hMem = NULL;
321 }
322 }
323 }
324
325 if (hMem)
326 {
327 /* pMem is the address of the data. cb is the size of returned data. */
328 /* Verify the size of returned text, the memory block for clipboard
329 * must have the exact string size.
330 */
331 if (u32Format == VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
332 {
333 size_t cbActual = 0;
334 HRESULT hrc = StringCbLengthW((LPWSTR)pMem, cb, &cbActual);
335 if (FAILED (hrc))
336 {
337 /* Discard invalid data. */
338 GlobalUnlock(hMem);
339 GlobalFree(hMem);
340 hMem = NULL;
341 }
342 else
343 {
344 /* cbActual is the number of bytes, excluding those used
345 * for the terminating null character.
346 */
347 cb = (uint32_t)(cbActual + 2);
348 }
349 }
350 }
351
352 if (hMem)
353 {
354 GlobalUnlock(hMem);
355
356 hMem = GlobalReAlloc(hMem, cb, 0);
357 LogFlowFunc(("Reallocated hMem = %p\n", hMem));
358
359 if (hMem)
360 {
361 /* 'hMem' contains the host clipboard data.
362 * size is 'cb' and format is 'format'. */
363 HANDLE hClip = SetClipboardData(format, hMem);
364 LogFlowFunc(("WM_RENDERFORMAT hClip = %p\n", hClip));
365
366 if (hClip)
367 {
368 /* The hMem ownership has gone to the system. Finish the processing. */
369 break;
370 }
371
372 /* Cleanup follows. */
373 }
374 }
375 }
376 if (hMem)
377 GlobalUnlock(hMem);
378 }
379 if (hMem)
380 GlobalFree(hMem);
381 }
382
383 /* Something went wrong. */
384 EmptyClipboard();
385 }
386 } break;
387
388 case WM_RENDERALLFORMATS:
389 {
390 /* Do nothing. The clipboard formats will be unavailable now, because the
391 * windows is to be destroyed and therefore the guest side becomes inactive.
392 */
393 if (OpenClipboard(hwnd))
394 {
395 EmptyClipboard();
396 CloseClipboard();
397 }
398 } break;
399
400 case WM_USER:
401 {
402 /* Announce available formats. Do not insert data, they will be inserted in WM_RENDER*. */
403 uint32_t u32Formats = (uint32_t)lParam;
404
405 if (FALSE == OpenClipboard(hwnd))
406 {
407 LogFlowFunc(("WM_USER: Failed to open clipboard! Last error = %ld\n", GetLastError()));
408 }
409 else
410 {
411 EmptyClipboard();
412
413 HANDLE hClip = NULL;
414
415 if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
416 {
417 LogFlowFunc(("WM_USER: VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT\n"));
418 hClip = SetClipboardData(CF_UNICODETEXT, NULL);
419 }
420
421 if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
422 {
423 LogFlowFunc(("WM_USER: VBOX_SHARED_CLIPBOARD_FMT_BITMAP\n"));
424 hClip = SetClipboardData(CF_DIB, NULL);
425 }
426
427 if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_HTML)
428 {
429 UINT format = RegisterClipboardFormat ("HTML Format");
430 LogFlowFunc(("WM_USER: VBOX_SHARED_CLIPBOARD_FMT_HTML 0x%04X\n", format));
431 if (format != 0)
432 {
433 hClip = SetClipboardData(format, NULL);
434 }
435 }
436
437 CloseClipboard();
438 LogFlowFunc(("WM_USER: hClip = %p, err = %ld\n", hClip, GetLastError ()));
439 }
440 } break;
441
442 case WM_USER + 1:
443 {
444 /* Send data in the specified format to the host. */
445 uint32_t u32Formats = (uint32_t)lParam;
446 HANDLE hClip = NULL;
447
448 if (FALSE == OpenClipboard(hwnd))
449 {
450 LogFlowFunc(("WM_USER: Failed to open clipboard! Last error = %ld\n", GetLastError()));
451 }
452 else
453 {
454 int vboxrc;
455 if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
456 {
457 hClip = GetClipboardData(CF_DIB);
458
459 if (hClip != NULL)
460 {
461 LPVOID lp = GlobalLock(hClip);
462 if (lp != NULL)
463 {
464 LogFlowFunc(("WM_USER + 1: CF_DIB\n"));
465 vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_BITMAP,
466 lp, GlobalSize(hClip));
467 GlobalUnlock(hClip);
468 }
469 else
470 {
471 hClip = NULL;
472 }
473 }
474 }
475 else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
476 {
477 hClip = GetClipboardData(CF_UNICODETEXT);
478
479 if (hClip != NULL)
480 {
481 LPWSTR uniString = (LPWSTR)GlobalLock(hClip);
482
483 if (uniString != NULL)
484 {
485 LogFlowFunc(("WM_USER + 1: CF_UNICODETEXT\n"));
486 vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT,
487 uniString, (lstrlenW(uniString) + 1) * 2);
488 GlobalUnlock(hClip);
489 }
490 else
491 {
492 hClip = NULL;
493 }
494 }
495 }
496 else if (u32Formats & VBOX_SHARED_CLIPBOARD_FMT_HTML)
497 {
498 UINT format = RegisterClipboardFormat ("HTML Format");
499 if (format != 0)
500 {
501 hClip = GetClipboardData(format);
502 if (hClip != NULL)
503 {
504 LPVOID lp = GlobalLock(hClip);
505
506 if (lp != NULL)
507 {
508 LogFlowFunc(("WM_USER + 1: CF_HTML\n"));
509 vboxrc = VbglR3ClipboardWriteData(pCtx->u32ClientID, VBOX_SHARED_CLIPBOARD_FMT_HTML,
510 lp, GlobalSize(hClip));
511 GlobalUnlock(hClip);
512 }
513 else
514 {
515 hClip = NULL;
516 }
517 }
518 }
519 }
520
521 CloseClipboard();
522 }
523
524 if (hClip == NULL)
525 {
526 /* Requested clipboard format is not available, send empty data. */
527 VbglR3ClipboardWriteData(pCtx->u32ClientID, 0, NULL, 0);
528 }
529 } break;
530
531 default:
532 {
533 rc = DefWindowProc(hwnd, msg, wParam, lParam);
534 }
535 }
536
537#ifndef DEBUG_andy
538 LogFlowFunc(("vboxClipboardProcessMsg returned with rc = %ld\n", rc));
539#endif
540 return rc;
541}
542
543static LRESULT CALLBACK vboxClipboardWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
544
545static int vboxClipboardInit (VBOXCLIPBOARDCONTEXT *pCtx)
546{
547 /* Register the Window Class. */
548 WNDCLASS wc;
549
550 wc.style = CS_NOCLOSE;
551 wc.lpfnWndProc = vboxClipboardWndProc;
552 wc.cbClsExtra = 0;
553 wc.cbWndExtra = 0;
554 wc.hInstance = pCtx->pEnv->hInstance;
555 wc.hIcon = NULL;
556 wc.hCursor = NULL;
557 wc.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
558 wc.lpszMenuName = NULL;
559 wc.lpszClassName = gachWindowClassName;
560
561 pCtx->atomWindowClass = RegisterClass (&wc);
562
563 int rc = VINF_SUCCESS;
564 if (pCtx->atomWindowClass == 0)
565 {
566 rc = VERR_NOT_SUPPORTED;
567 }
568 else
569 {
570 /* Create the window. */
571 pCtx->hwnd = CreateWindowEx (WS_EX_TOOLWINDOW | WS_EX_TRANSPARENT | WS_EX_TOPMOST,
572 gachWindowClassName, gachWindowClassName,
573 WS_POPUPWINDOW,
574 -200, -200, 100, 100, NULL, NULL, pCtx->pEnv->hInstance, NULL);
575
576 if (pCtx->hwnd == NULL)
577 {
578 rc = VERR_NOT_SUPPORTED;
579 }
580 else
581 {
582 SetWindowPos(pCtx->hwnd, HWND_TOPMOST, -200, -200, 0, 0,
583 SWP_NOACTIVATE | SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_NOSIZE);
584
585 addToCBChain(pCtx);
586 pCtx->timerRefresh = SetTimer(pCtx->hwnd, 0, 10 * 1000, NULL);
587 }
588 }
589
590 LogFlowFunc(("vboxClipboardInit returned with rc = %Rrc\n", rc));
591 return rc;
592}
593
594static void vboxClipboardDestroy(VBOXCLIPBOARDCONTEXT *pCtx)
595{
596 if (pCtx->hwnd)
597 {
598 removeFromCBChain(pCtx);
599 if (pCtx->timerRefresh)
600 KillTimer(pCtx->hwnd, 0);
601
602 DestroyWindow (pCtx->hwnd);
603 pCtx->hwnd = NULL;
604 }
605
606 if (pCtx->atomWindowClass != 0)
607 {
608 UnregisterClass(gachWindowClassName, pCtx->pEnv->hInstance);
609 pCtx->atomWindowClass = 0;
610 }
611}
612
613/* Static since it is the single instance. Directly used in the windows proc. */
614static VBOXCLIPBOARDCONTEXT gCtx = { NULL };
615
616static LRESULT CALLBACK vboxClipboardWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
617{
618 /* Forward with proper context. */
619 return vboxClipboardProcessMsg(&gCtx, hwnd, msg, wParam, lParam);
620}
621
622int VBoxClipboardInit(const VBOXSERVICEENV *pEnv, void **ppInstance, bool *pfStartThread)
623{
624 LogFlowFunc(("VBoxClipboardInit\n"));
625 if (gCtx.pEnv)
626 {
627 /* Clipboard was already initialized. 2 or more instances are not supported. */
628 return VERR_NOT_SUPPORTED;
629 }
630
631 if (VbglR3AutoLogonIsRemoteSession())
632 {
633 /* Do not use clipboard for remote sessions. */
634 LogRel(("VBoxTray: clipboard has been disabled for a remote session.\n"));
635 return VERR_NOT_SUPPORTED;
636 }
637
638 RT_ZERO (gCtx);
639 gCtx.pEnv = pEnv;
640
641 int rc = VbglR3ClipboardConnect(&gCtx.u32ClientID);
642 if (RT_SUCCESS (rc))
643 {
644 rc = vboxClipboardInit(&gCtx);
645 if (RT_SUCCESS (rc))
646 {
647 /* Always start the thread for host messages. */
648 *pfStartThread = true;
649 }
650 else
651 {
652 VbglR3ClipboardDisconnect(gCtx.u32ClientID);
653 }
654 }
655
656 if (RT_SUCCESS(rc))
657 *ppInstance = &gCtx;
658 return rc;
659}
660
661unsigned __stdcall VBoxClipboardThread(void *pInstance)
662{
663 LogFlowFunc(("VBoxClipboardThread\n"));
664
665 VBOXCLIPBOARDCONTEXT *pCtx = (VBOXCLIPBOARDCONTEXT *)pInstance;
666 AssertPtr(pCtx);
667
668 /* The thread waits for incoming messages from the host. */
669 for (;;)
670 {
671 uint32_t u32Msg;
672 uint32_t u32Formats;
673 int rc = VbglR3ClipboardGetHostMsg(pCtx->u32ClientID, &u32Msg, &u32Formats);
674 if (RT_FAILURE(rc))
675 {
676 LogFlowFunc(("VBoxClipboardThread: Failed to call the driver for host message! rc = %Rrc\n", rc));
677 if (rc == VERR_INTERRUPTED)
678 {
679 /* Wait for termination event. */
680 WaitForSingleObject(pCtx->pEnv->hStopEvent, INFINITE);
681 break;
682 }
683 /* Wait a bit before retrying. */
684 AssertPtr(pCtx->pEnv);
685 if (WaitForSingleObject(pCtx->pEnv->hStopEvent, 1000) == WAIT_OBJECT_0)
686 {
687 break;
688 }
689 continue;
690 }
691 else
692 {
693 LogFlowFunc(("VBoxClipboardThread: VbglR3ClipboardGetHostMsg u32Msg = %ld, u32Formats = %ld\n", u32Msg, u32Formats));
694 switch (u32Msg)
695 {
696 case VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS:
697 {
698 /* The host has announced available clipboard formats.
699 * Forward the information to the window, so it can later
700 * respond to WM_RENDERFORMAT message. */
701 ::PostMessage (pCtx->hwnd, WM_USER, 0, u32Formats);
702 } break;
703
704 case VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA:
705 {
706 /* The host needs data in the specified format. */
707 ::PostMessage (pCtx->hwnd, WM_USER + 1, 0, u32Formats);
708 } break;
709
710 case VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT:
711 {
712 /* The host is terminating. */
713 rc = VERR_INTERRUPTED;
714 } break;
715
716 default:
717 {
718 LogFlowFunc(("VBoxClipboardThread: Unsupported message from host! Message = %ld\n", u32Msg));
719 }
720 }
721 }
722 }
723 return 0;
724}
725
726void VBoxClipboardDestroy(const VBOXSERVICEENV *pEnv, void *pInstance)
727{
728 VBOXCLIPBOARDCONTEXT *pCtx = (VBOXCLIPBOARDCONTEXT *)pInstance;
729 if (pCtx != &gCtx)
730 {
731 LogFlowFunc(("VBoxClipboardDestroy: invalid instance %p (our = %p)!\n", pCtx, &gCtx));
732 pCtx = &gCtx;
733 }
734
735 vboxClipboardDestroy (pCtx);
736 VbglR3ClipboardDisconnect(pCtx->u32ClientID);
737 memset (pCtx, 0, sizeof (*pCtx));
738 return;
739}
740
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette