VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedClipboard/service.cpp@ 13073

Last change on this file since 13073 was 11408, checked in by vboxsync, 16 years ago

RDP clipboard fixes: serialize data reading and annoncements of new data from a RDP client.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.1 KB
Line 
1/** @file
2 *
3 * Shared Clipboard:
4 * Host service entry points.
5 */
6
7/*
8 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
19 * Clara, CA 95054 USA or visit http://www.sun.com if you need
20 * additional information or have any questions.
21 */
22
23#include <VBox/HostServices/VBoxClipboardSvc.h>
24#include <VBox/HostServices/VBoxClipboardExt.h>
25
26#include <iprt/alloc.h>
27#include <iprt/string.h>
28#include <iprt/assert.h>
29#include <iprt/critsect.h>
30#include <VBox/ssm.h>
31
32#include "VBoxClipboard.h"
33
34static void VBoxHGCMParmUInt32Set (VBOXHGCMSVCPARM *pParm, uint32_t u32)
35{
36 pParm->type = VBOX_HGCM_SVC_PARM_32BIT;
37 pParm->u.uint32 = u32;
38}
39
40static int VBoxHGCMParmUInt32Get (VBOXHGCMSVCPARM *pParm, uint32_t *pu32)
41{
42 if (pParm->type == VBOX_HGCM_SVC_PARM_32BIT)
43 {
44 *pu32 = pParm->u.uint32;
45 return VINF_SUCCESS;
46 }
47
48 return VERR_INVALID_PARAMETER;
49}
50
51#if 0
52static void VBoxHGCMParmPtrSet (VBOXHGCMSVCPARM *pParm, void *pv, uint32_t cb)
53{
54 pParm->type = VBOX_HGCM_SVC_PARM_PTR;
55 pParm->u.pointer.size = cb;
56 pParm->u.pointer.addr = pv;
57}
58#endif
59
60static int VBoxHGCMParmPtrGet (VBOXHGCMSVCPARM *pParm, void **ppv, uint32_t *pcb)
61{
62 if (pParm->type == VBOX_HGCM_SVC_PARM_PTR)
63 {
64 *ppv = pParm->u.pointer.addr;
65 *pcb = pParm->u.pointer.size;
66 return VINF_SUCCESS;
67 }
68
69 return VERR_INVALID_PARAMETER;
70}
71
72static PVBOXHGCMSVCHELPERS g_pHelpers;
73
74static RTCRITSECT critsect;
75static uint32_t g_u32Mode;
76
77static PFNHGCMSVCEXT g_pfnExtension;
78static void *g_pvExtension;
79
80static VBOXCLIPBOARDCLIENTDATA *g_pClient;
81
82/* Serialization of data reading and format announcements from the RDP client. */
83static bool g_fReadingData = false;
84static bool g_fDelayedAnnouncement = false;
85static uint32_t g_u32DelayedFormats = 0;
86
87static uint32_t vboxSvcClipboardMode (void)
88{
89 return g_u32Mode;
90}
91
92static void vboxSvcClipboardModeSet (uint32_t u32Mode)
93{
94 switch (u32Mode)
95 {
96 case VBOX_SHARED_CLIPBOARD_MODE_OFF:
97 case VBOX_SHARED_CLIPBOARD_MODE_HOST_TO_GUEST:
98 case VBOX_SHARED_CLIPBOARD_MODE_GUEST_TO_HOST:
99 case VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL:
100 g_u32Mode = u32Mode;
101 break;
102
103 default:
104 g_u32Mode = VBOX_SHARED_CLIPBOARD_MODE_OFF;
105 }
106}
107
108bool vboxSvcClipboardLock (void)
109{
110 return VBOX_SUCCESS(RTCritSectEnter (&critsect));
111}
112
113void vboxSvcClipboardUnlock (void)
114{
115 RTCritSectLeave (&critsect);
116}
117
118/* Set the HGCM parameters according to pending messages.
119 * Executed under the clipboard lock.
120 */
121static bool vboxSvcClipboardReturnMsg (VBOXCLIPBOARDCLIENTDATA *pClient, VBOXHGCMSVCPARM paParms[])
122{
123 /* Message priority is taken into account. */
124 if (pClient->fMsgQuit)
125 {
126 LogFlow(("vboxSvcClipboardReturnMsg: Quit\n"));
127 VBoxHGCMParmUInt32Set (&paParms[0], VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT);
128 VBoxHGCMParmUInt32Set (&paParms[1], 0);
129 pClient->fMsgQuit = false;
130 }
131 else if (pClient->fMsgReadData)
132 {
133 LogFlow(("vboxSvcClipboardReturnMsg: ReadData %02X\n", pClient->u32RequestedFormat));
134 VBoxHGCMParmUInt32Set (&paParms[0], VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA);
135 VBoxHGCMParmUInt32Set (&paParms[1], pClient->u32RequestedFormat);
136 pClient->fMsgReadData = false;
137 }
138 else if (pClient->fMsgFormats)
139 {
140 LogFlow(("vboxSvcClipboardReturnMsg: Formats %02X\n", pClient->u32AvailableFormats));
141 VBoxHGCMParmUInt32Set (&paParms[0], VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS);
142 VBoxHGCMParmUInt32Set (&paParms[1], pClient->u32AvailableFormats);
143 pClient->fMsgFormats = false;
144 }
145 else
146 {
147 /* No pending messages. */
148 LogFlow(("vboxSvcClipboardReturnMsg: no message\n"));
149 return false;
150 }
151
152 /* Message information assigned. */
153 return true;
154}
155
156void vboxSvcClipboardReportMsg (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Msg, uint32_t u32Formats)
157{
158 if (vboxSvcClipboardLock ())
159 {
160 switch (u32Msg)
161 {
162 case VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT:
163 {
164 LogFlow(("vboxSvcClipboardReportMsg: Quit\n"));
165 pClient->fMsgQuit = true;
166 } break;
167 case VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA:
168 {
169 if ( vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_GUEST_TO_HOST
170 && vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL)
171 {
172 /* Skip the message. */
173 break;
174 }
175
176 LogFlow(("vboxSvcClipboardReportMsg: ReadData %02X\n", u32Formats));
177 pClient->u32RequestedFormat = u32Formats;
178 pClient->fMsgReadData = true;
179 } break;
180 case VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS:
181 {
182 if ( vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_HOST_TO_GUEST
183 && vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL)
184 {
185 /* Skip the message. */
186 break;
187 }
188
189 LogFlow(("vboxSvcClipboardReportMsg: Formats %02X\n", u32Formats));
190 pClient->u32AvailableFormats = u32Formats;
191 pClient->fMsgFormats = true;
192 } break;
193 default:
194 {
195 /* Invalid message. */
196 LogFlow(("vboxSvcClipboardReportMsg: invalid message %d\n", u32Msg));
197 } break;
198 }
199
200 if (pClient->fAsync)
201 {
202 /* The client waits for a responce. */
203 bool fMessageReturned = vboxSvcClipboardReturnMsg (pClient, pClient->async.paParms);
204
205 /* Make a copy of the handle. */
206 VBOXHGCMCALLHANDLE callHandle = pClient->async.callHandle;
207
208 if (fMessageReturned)
209 {
210 /* There is a responce. */
211 pClient->fAsync = false;
212 }
213
214 vboxSvcClipboardUnlock ();
215
216 if (fMessageReturned)
217 {
218 LogFlow(("vboxSvcClipboardReportMsg: CallComplete\n"));
219 g_pHelpers->pfnCallComplete (callHandle, VINF_SUCCESS);
220 }
221 }
222 else
223 {
224 vboxSvcClipboardUnlock ();
225 }
226 }
227}
228
229static int svcInit (void)
230{
231 int rc = RTCritSectInit (&critsect);
232
233 if (RT_SUCCESS (rc))
234 {
235 vboxSvcClipboardModeSet (VBOX_SHARED_CLIPBOARD_MODE_OFF);
236
237 rc = vboxClipboardInit ();
238
239 /* Clean up on failure, because 'svnUnload' will not be called
240 * if the 'svcInit' returns an error.
241 */
242 if (VBOX_FAILURE (rc))
243 {
244 RTCritSectDelete (&critsect);
245 }
246 }
247
248 return rc;
249}
250
251static DECLCALLBACK(int) svcUnload (void *)
252{
253 vboxClipboardDestroy ();
254 RTCritSectDelete (&critsect);
255 return VINF_SUCCESS;
256}
257
258/**
259 * Disconnect the host side of the shared clipboard and send a "host disconnected" message
260 * to the guest side.
261 */
262static DECLCALLBACK(int) svcDisconnect (void *, uint32_t u32ClientID, void *pvClient)
263{
264 VBOXCLIPBOARDCLIENTDATA *pClient = (VBOXCLIPBOARDCLIENTDATA *)pvClient;
265
266 vboxSvcClipboardReportMsg (pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT, 0);
267
268 vboxClipboardDisconnect (pClient);
269
270 memset (pClient, 0, sizeof (*pClient));
271
272 g_pClient = NULL;
273
274 return VINF_SUCCESS;
275}
276
277static DECLCALLBACK(int) svcConnect (void *, uint32_t u32ClientID, void *pvClient)
278{
279 VBOXCLIPBOARDCLIENTDATA *pClient = (VBOXCLIPBOARDCLIENTDATA *)pvClient;
280
281 int rc = VINF_SUCCESS;
282
283 /* If there is already a client connected then we want to release it first. */
284 if (g_pClient != NULL)
285 {
286 uint32_t u32ClientID = g_pClient->u32ClientID;
287
288 svcDisconnect(NULL, u32ClientID, g_pClient);
289 /* And free the resources in the hgcm subsystem. */
290 g_pHelpers->pfnDisconnectClient(g_pHelpers->pvInstance, u32ClientID);
291 }
292
293 /* Register the client. */
294 memset (pClient, 0, sizeof (*pClient));
295
296 pClient->u32ClientID = u32ClientID;
297
298 rc = vboxClipboardConnect (pClient);
299
300 if (VBOX_SUCCESS (rc))
301 {
302 g_pClient = pClient;
303 }
304
305 Log(("vboxClipboardConnect: rc = %Vrc\n", rc));
306
307 return rc;
308}
309
310static DECLCALLBACK(void) svcCall (void *,
311 VBOXHGCMCALLHANDLE callHandle,
312 uint32_t u32ClientID,
313 void *pvClient,
314 uint32_t u32Function,
315 uint32_t cParms,
316 VBOXHGCMSVCPARM paParms[])
317{
318 int rc = VINF_SUCCESS;
319
320 Log(("svcCall: u32ClientID = %d, fn = %d, cParms = %d, pparms = %d\n",
321 u32ClientID, u32Function, cParms, paParms));
322
323 VBOXCLIPBOARDCLIENTDATA *pClient = (VBOXCLIPBOARDCLIENTDATA *)pvClient;
324
325 bool fAsynchronousProcessing = false;
326
327#ifdef DEBUG
328 uint32_t i;
329
330 for (i = 0; i < cParms; i++)
331 {
332 /** @todo parameters other than 32 bit */
333 Log((" pparms[%d]: type %d value %d\n", i, paParms[i].type, paParms[i].u.uint32));
334 }
335#endif
336
337 switch (u32Function)
338 {
339 case VBOX_SHARED_CLIPBOARD_FN_GET_HOST_MSG:
340 {
341 /* The quest requests a host message. */
342 Log(("svcCall: VBOX_SHARED_CLIPBOARD_FN_GET_HOST_MSG\n"));
343
344 if (cParms != VBOX_SHARED_CLIPBOARD_CPARMS_GET_HOST_MSG)
345 {
346 rc = VERR_INVALID_PARAMETER;
347 }
348 else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* msg */
349 || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* formats */
350 )
351 {
352 rc = VERR_INVALID_PARAMETER;
353 }
354 else
355 {
356 /* Atomically verify the client's state. */
357 if (vboxSvcClipboardLock ())
358 {
359 bool fMessageReturned = vboxSvcClipboardReturnMsg (pClient, paParms);
360
361 if (fMessageReturned)
362 {
363 /* Just return to the caller. */
364 pClient->fAsync = false;
365 }
366 else
367 {
368 /* No event available at the time. Process asynchronously. */
369 fAsynchronousProcessing = true;
370
371 pClient->fAsync = true;
372 pClient->async.callHandle = callHandle;
373 pClient->async.paParms = paParms;
374
375 Log(("svcCall: async.\n"));
376 }
377
378 vboxSvcClipboardUnlock ();
379 }
380 else
381 {
382 rc = VERR_NOT_SUPPORTED;
383 }
384 }
385 } break;
386
387 case VBOX_SHARED_CLIPBOARD_FN_FORMATS:
388 {
389 /* The guest reports that some formats are available. */
390 Log(("svcCall: VBOX_SHARED_CLIPBOARD_FN_FORMATS\n"));
391
392 if (cParms != VBOX_SHARED_CLIPBOARD_CPARMS_FORMATS)
393 {
394 rc = VERR_INVALID_PARAMETER;
395 }
396 else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* formats */
397 )
398 {
399 rc = VERR_INVALID_PARAMETER;
400 }
401 else
402 {
403 uint32_t u32Formats;
404
405 rc = VBoxHGCMParmUInt32Get (&paParms[0], &u32Formats);
406
407 if (VBOX_SUCCESS (rc))
408 {
409 if ( vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_GUEST_TO_HOST
410 && vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL)
411 {
412 rc = VERR_NOT_SUPPORTED;
413 break;
414 }
415
416 if (g_pfnExtension)
417 {
418 VBOXCLIPBOARDEXTPARMS parms;
419
420 parms.u32Format = u32Formats;
421
422 g_pfnExtension (g_pvExtension, VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE, &parms, sizeof (parms));
423 }
424 else
425 {
426 vboxClipboardFormatAnnounce (pClient, u32Formats);
427 }
428 }
429 }
430 } break;
431
432 case VBOX_SHARED_CLIPBOARD_FN_READ_DATA:
433 {
434 /* The guest wants to read data in the given format. */
435 Log(("svcCall: VBOX_SHARED_CLIPBOARD_FN_READ_DATA\n"));
436
437 if (cParms != VBOX_SHARED_CLIPBOARD_CPARMS_READ_DATA)
438 {
439 rc = VERR_INVALID_PARAMETER;
440 }
441 else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* format */
442 || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* ptr */
443 || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* size */
444 )
445 {
446 rc = VERR_INVALID_PARAMETER;
447 }
448 else
449 {
450 uint32_t u32Format;
451 void *pv;
452 uint32_t cb;
453
454 rc = VBoxHGCMParmUInt32Get (&paParms[0], &u32Format);
455
456 if (VBOX_SUCCESS (rc))
457 {
458 rc = VBoxHGCMParmPtrGet (&paParms[1], &pv, &cb);
459
460 if (VBOX_SUCCESS (rc))
461 {
462 if ( vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_HOST_TO_GUEST
463 && vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL)
464 {
465 rc = VERR_NOT_SUPPORTED;
466 break;
467 }
468
469 uint32_t cbActual = 0;
470
471 if (g_pfnExtension)
472 {
473 VBOXCLIPBOARDEXTPARMS parms;
474
475 parms.u32Format = u32Format;
476 parms.pvData = pv;
477 parms.cbData = cb;
478
479 g_fReadingData = true;
480 rc = g_pfnExtension (g_pvExtension, VBOX_CLIPBOARD_EXT_FN_DATA_READ, &parms, sizeof (parms));
481 LogFlow(("DATA: g_fDelayedAnnouncement = %d, g_u32DelayedFormats = 0x%x\n", g_fDelayedAnnouncement, g_u32DelayedFormats));
482 if (g_fDelayedAnnouncement)
483 {
484 vboxSvcClipboardReportMsg (g_pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS, g_u32DelayedFormats);
485 g_fDelayedAnnouncement = false;
486 g_u32DelayedFormats = 0;
487 }
488 g_fReadingData = false;
489
490 if (VBOX_SUCCESS (rc))
491 {
492 cbActual = parms.cbData;
493 }
494 }
495 else
496 {
497 rc = vboxClipboardReadData (pClient, u32Format, pv, cb, &cbActual);
498 }
499
500 if (VBOX_SUCCESS (rc))
501 {
502 VBoxHGCMParmUInt32Set (&paParms[2], cbActual);
503 }
504 }
505 }
506 }
507 } break;
508
509 case VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA:
510 {
511 /* The guest writes the requested data. */
512 Log(("svcCall: VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA\n"));
513
514 if (cParms != VBOX_SHARED_CLIPBOARD_CPARMS_WRITE_DATA)
515 {
516 rc = VERR_INVALID_PARAMETER;
517 }
518 else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* format */
519 || paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* ptr */
520 )
521 {
522 rc = VERR_INVALID_PARAMETER;
523 }
524 else
525 {
526 void *pv;
527 uint32_t cb;
528 uint32_t u32Format;
529
530 rc = VBoxHGCMParmUInt32Get (&paParms[0], &u32Format);
531
532 if (VBOX_SUCCESS (rc))
533 {
534 rc = VBoxHGCMParmPtrGet (&paParms[1], &pv, &cb);
535
536 if (VBOX_SUCCESS (rc))
537 {
538 if ( vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_GUEST_TO_HOST
539 && vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL)
540 {
541 rc = VERR_NOT_SUPPORTED;
542 break;
543 }
544
545 if (g_pfnExtension)
546 {
547 VBOXCLIPBOARDEXTPARMS parms;
548
549 parms.u32Format = u32Format;
550 parms.pvData = pv;
551 parms.cbData = cb;
552
553 g_pfnExtension (g_pvExtension, VBOX_CLIPBOARD_EXT_FN_DATA_WRITE, &parms, sizeof (parms));
554 }
555 else
556 {
557 vboxClipboardWriteData (pClient, pv, cb, u32Format);
558 }
559 }
560 }
561 }
562 } break;
563
564 default:
565 {
566 rc = VERR_NOT_IMPLEMENTED;
567 }
568 }
569
570 LogFlow(("svcCall: rc = %Vrc\n", rc));
571
572 if (!fAsynchronousProcessing)
573 {
574 g_pHelpers->pfnCallComplete (callHandle, rc);
575 }
576}
577
578/*
579 * We differentiate between a function handler for the guest and one for the host.
580 */
581static DECLCALLBACK(int) svcHostCall (void *,
582 uint32_t u32Function,
583 uint32_t cParms,
584 VBOXHGCMSVCPARM paParms[])
585{
586 int rc = VINF_SUCCESS;
587
588 Log(("svcHostCall: fn = %d, cParms = %d, pparms = %d\n",
589 u32Function, cParms, paParms));
590
591 switch (u32Function)
592 {
593 case VBOX_SHARED_CLIPBOARD_HOST_FN_SET_MODE:
594 {
595 Log(("svcCall: VBOX_SHARED_CLIPBOARD_HOST_FN_SET_MODE\n"));
596
597 if (cParms != 1)
598 {
599 rc = VERR_INVALID_PARAMETER;
600 }
601 else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* mode */
602 )
603 {
604 rc = VERR_INVALID_PARAMETER;
605 }
606 else
607 {
608 uint32_t u32Mode = VBOX_SHARED_CLIPBOARD_MODE_OFF;
609
610 rc = VBoxHGCMParmUInt32Get (&paParms[0], &u32Mode);
611
612 /* The setter takes care of invalid values. */
613 vboxSvcClipboardModeSet (u32Mode);
614 }
615 } break;
616
617 default:
618 break;
619 }
620
621 LogFlow(("svcHostCall: rc = %Vrc\n", rc));
622 return rc;
623}
624
625static DECLCALLBACK(int) svcSaveState(void *, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM)
626{
627 /* If there are any pending requests, they must be completed here. Since
628 * the service is single threaded, there could be only requests
629 * which the service itself has postponed.
630 *
631 * HGCM knows that the state is being saved and that the pfnComplete
632 * calls are just clean ups. These requests are saved by the VMMDev.
633 *
634 * When the state will be restored, these requests will be reissued
635 * by VMMDev. The service therefore must save state as if there were no
636 * pending request.
637 */
638 Log(("svcSaveState: u32ClientID = %d\n", u32ClientID));
639
640 VBOXCLIPBOARDCLIENTDATA *pClient = (VBOXCLIPBOARDCLIENTDATA *)pvClient;
641
642 /* Save client structure length & contents */
643 int rc = SSMR3PutU32(pSSM, sizeof(*pClient));
644 AssertRCReturn(rc, rc);
645
646 rc = SSMR3PutMem(pSSM, pClient, sizeof(*pClient));
647 AssertRCReturn(rc, rc);
648
649 if (pClient->fAsync)
650 {
651 g_pHelpers->pfnCallComplete (pClient->async.callHandle, VINF_SUCCESS /* error code is not important here. */);
652 pClient->fAsync = false;
653 }
654
655 return VINF_SUCCESS;
656}
657
658static DECLCALLBACK(int) svcLoadState(void *, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM)
659{
660 Log(("svcLoadState: u32ClientID = %d\n", u32ClientID));
661
662 VBOXCLIPBOARDCLIENTDATA *pClient = (VBOXCLIPBOARDCLIENTDATA *)pvClient;
663
664 /* Existing client can not be in async state yet. */
665 Assert(!pClient->fAsync);
666
667 /* Restore the client data. */
668 uint32_t len;
669 int rc = SSMR3GetU32(pSSM, &len);
670 AssertRCReturn(rc, rc);
671
672 if (len != sizeof(VBOXCLIPBOARDCLIENTDATA))
673 {
674 Log(("Client len mismatch: %d %d\n", len, sizeof (VBOXCLIPBOARDCLIENTDATA)));
675 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
676 }
677
678 VBOXCLIPBOARDCLIENTDATA client;
679 rc = SSMR3GetMem(pSSM, &client, sizeof(client));
680 AssertRCReturn(rc, rc);
681
682 /* Verify the loaded clients data and update the pClient. */
683 if (pClient->u32ClientID != client.u32ClientID)
684 {
685 Log(("Client ID mismatch: %d %d\n", pClient->u32ClientID, client.u32ClientID));
686 return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
687 }
688
689 pClient->fMsgQuit = client.fMsgQuit;
690 pClient->fMsgReadData = client.fMsgReadData;
691 pClient->fMsgFormats = client.fMsgFormats;
692 pClient->u32RequestedFormat = client.u32RequestedFormat;
693
694 /* Actual host data are to be reported to guest (SYNC). */
695 vboxClipboardSync (pClient);
696
697 return VINF_SUCCESS;
698}
699
700static DECLCALLBACK(int) extCallback (uint32_t u32Function, uint32_t u32Format, void *pvData, uint32_t cbData)
701{
702 if (g_pClient != NULL)
703 {
704 switch (u32Function)
705 {
706 case VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE:
707 {
708 LogFlow(("ANNOUNCE: g_fReadingData = %d\n", g_fReadingData));
709 if (g_fReadingData)
710 {
711 g_fDelayedAnnouncement = true;
712 g_u32DelayedFormats = u32Format;
713 }
714 else
715 {
716 vboxSvcClipboardReportMsg (g_pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS, u32Format);
717 }
718 } break;
719
720 case VBOX_CLIPBOARD_EXT_FN_DATA_READ:
721 {
722 vboxSvcClipboardReportMsg (g_pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA, u32Format);
723 } break;
724
725 default:
726 return VERR_NOT_SUPPORTED;
727 }
728 }
729
730 return VINF_SUCCESS;
731}
732
733static DECLCALLBACK(int) svcRegisterExtension(void *, PFNHGCMSVCEXT pfnExtension, void *pvExtension)
734{
735 LogFlowFunc(("pfnExtension = %p\n", pfnExtension));
736
737 VBOXCLIPBOARDEXTPARMS parms;
738
739 if (pfnExtension)
740 {
741 /* Install extension. */
742 g_pfnExtension = pfnExtension;
743 g_pvExtension = pvExtension;
744
745 parms.pvData = (void *)extCallback;
746 g_pfnExtension (g_pvExtension, VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK, &parms, sizeof (parms));
747 }
748 else
749 {
750 if (g_pfnExtension)
751 {
752 parms.pvData = NULL;
753 g_pfnExtension (g_pvExtension, VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK, &parms, sizeof (parms));
754 }
755
756 /* Uninstall extension. */
757 g_pfnExtension = NULL;
758 g_pvExtension = NULL;
759 }
760
761 return VINF_SUCCESS;
762}
763
764extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad (VBOXHGCMSVCFNTABLE *ptable)
765{
766 int rc = VINF_SUCCESS;
767
768 LogFlowFunc(("ptable = %p\n", ptable));
769
770 if (!ptable)
771 {
772 rc = VERR_INVALID_PARAMETER;
773 }
774 else
775 {
776 Log(("VBoxHGCMSvcLoad: ptable->cbSize = %d, ptable->u32Version = 0x%08X\n", ptable->cbSize, ptable->u32Version));
777
778 if ( ptable->cbSize != sizeof (VBOXHGCMSVCFNTABLE)
779 || ptable->u32Version != VBOX_HGCM_SVC_VERSION)
780 {
781 rc = VERR_INVALID_PARAMETER;
782 }
783 else
784 {
785 g_pHelpers = ptable->pHelpers;
786
787 ptable->cbClient = sizeof (VBOXCLIPBOARDCLIENTDATA);
788
789 ptable->pfnUnload = svcUnload;
790 ptable->pfnConnect = svcConnect;
791 ptable->pfnDisconnect = svcDisconnect;
792 ptable->pfnCall = svcCall;
793 ptable->pfnHostCall = svcHostCall;
794 ptable->pfnSaveState = svcSaveState;
795 ptable->pfnLoadState = svcLoadState;
796 ptable->pfnRegisterExtension = svcRegisterExtension;
797 ptable->pvService = NULL;
798
799 /* Service specific initialization. */
800 rc = svcInit ();
801 }
802 }
803
804 return rc;
805}
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