VirtualBox

source: vbox/trunk/src/VBox/Main/ConsoleVRDPServer.cpp@ 3817

Last change on this file since 3817 was 3817, checked in by vboxsync, 17 years ago

LineSize -> BytesPerLine

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 62.1 KB
Line 
1/** @file
2 *
3 * VBox Console VRDP Helper class
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22#include "ConsoleVRDPServer.h"
23#include "ConsoleImpl.h"
24#include "DisplayImpl.h"
25#ifdef VRDP_NO_COM
26#include "KeyboardImpl.h"
27#include "MouseImpl.h"
28#include <VBox/VRDPOrders.h>
29#endif /* VRDP_NO_COM */
30
31#include "Logging.h"
32
33#include <iprt/asm.h>
34#include <iprt/ldr.h>
35
36#include <VBox/err.h>
37
38#ifdef VRDP_NO_COM
39class VRDPConsoleCallback : public IConsoleCallback
40{
41public:
42 VRDPConsoleCallback (ConsoleVRDPServer *server) :
43 m_server(server)
44 {
45#ifndef VBOX_WITH_XPCOM
46 refcnt = 0;
47#endif /* !VBOX_WITH_XPCOM */
48 }
49
50 virtual ~VRDPConsoleCallback() {}
51
52 NS_DECL_ISUPPORTS
53
54#ifndef VBOX_WITH_XPCOM
55 STDMETHOD_(ULONG, AddRef)() {
56 return ::InterlockedIncrement (&refcnt);
57 }
58 STDMETHOD_(ULONG, Release)()
59 {
60 long cnt = ::InterlockedDecrement (&refcnt);
61 if (cnt == 0)
62 delete this;
63 return cnt;
64 }
65 STDMETHOD(QueryInterface) (REFIID riid , void **ppObj)
66 {
67 if (riid == IID_IUnknown) {
68 *ppObj = this;
69 AddRef();
70 return S_OK;
71 }
72 if (riid == IID_IConsoleCallback) {
73 *ppObj = this;
74 AddRef();
75 return S_OK;
76 }
77 *ppObj = NULL;
78 return E_NOINTERFACE;
79 }
80#endif /* !VBOX_WITH_XPCOM */
81
82
83 STDMETHOD(OnMousePointerShapeChange)(BOOL visible, BOOL alpha, ULONG xHot, ULONG yHot,
84 ULONG width, ULONG height, BYTE *shape);
85
86 STDMETHOD(OnMouseCapabilityChange)(BOOL supportsAbsolute, BOOL needsHostCursor)
87 {
88 if (m_server)
89 {
90 m_server->NotifyAbsoluteMouse(!!supportsAbsolute);
91 }
92 return S_OK;
93 }
94
95 STDMETHOD(OnStateChange)(MachineState_T machineState)
96 {
97 return S_OK;
98 }
99
100 STDMETHOD(OnAdditionsStateChange)()
101 {
102 return S_OK;
103 }
104
105 STDMETHOD(OnKeyboardLedsChange)(BOOL fNumLock, BOOL fCapsLock, BOOL fScrollLock)
106 {
107 return S_OK;
108 }
109
110 STDMETHOD(OnUSBDeviceStateChange)(IUSBDevice *device, BOOL attached,
111 IVirtualBoxErrorInfo *message)
112 {
113 return S_OK;
114 }
115
116 STDMETHOD(OnRuntimeError)(BOOL fatal, INPTR BSTR id, INPTR BSTR message)
117 {
118 return S_OK;
119 }
120
121 STDMETHOD(OnCanShowWindow)(BOOL *canShow)
122 {
123 if (!canShow)
124 return E_POINTER;
125 /* we don't manage window activation here: always agree */
126 *canShow = TRUE;
127 return S_OK;
128 }
129
130 STDMETHOD(OnShowWindow) (ULONG64 *winId)
131 {
132 if (!winId)
133 return E_POINTER;
134 /* we don't manage window activation here */
135 *winId = 0;
136 return S_OK;
137 }
138
139private:
140 ConsoleVRDPServer *m_server;
141#ifndef VBOX_WITH_XPCOM
142 long refcnt;
143#endif /* !VBOX_WITH_XPCOM */
144};
145
146#ifdef VBOX_WITH_XPCOM
147#include <nsMemory.h>
148NS_DECL_CLASSINFO(VRDPConsoleCallback)
149NS_IMPL_ISUPPORTS1_CI(VRDPConsoleCallback, IConsoleCallback)
150#endif /* VBOX_WITH_XPCOM */
151
152static void findTopLeftBorder (uint8_t *pu8Shape, uint32_t width, uint32_t height, uint32_t *pxSkip, uint32_t *pySkip)
153{
154 /*
155 * Find the top border of the AND mask. First assign to special value.
156 */
157 uint32_t ySkipAnd = ~0;
158
159 uint8_t *pu8And = pu8Shape;
160 const uint32_t cbAndRow = (width + 7) / 8;
161 const uint8_t maskLastByte = (uint8_t)( 0xFF << (cbAndRow * 8 - width) );
162
163 Assert(cbAndRow > 0);
164
165 unsigned y;
166 unsigned x;
167
168 for (y = 0; y < height && ySkipAnd == ~(uint32_t)0; y++, pu8And += cbAndRow)
169 {
170 /* For each complete byte in the row. */
171 for (x = 0; x < cbAndRow - 1; x++)
172 {
173 if (pu8And[x] != 0xFF)
174 {
175 ySkipAnd = y;
176 break;
177 }
178 }
179
180 if (ySkipAnd == ~(uint32_t)0)
181 {
182 /* Last byte. */
183 if ((pu8And[cbAndRow - 1] & maskLastByte) != maskLastByte)
184 {
185 ySkipAnd = y;
186 }
187 }
188 }
189
190 if (ySkipAnd == ~(uint32_t)0)
191 {
192 ySkipAnd = 0;
193 }
194
195 /*
196 * Find the left border of the AND mask.
197 */
198 uint32_t xSkipAnd = ~0;
199
200 /* For all bit columns. */
201 for (x = 0; x < width && xSkipAnd == ~(uint32_t)0; x++)
202 {
203 pu8And = pu8Shape + x/8; /* Currently checking byte. */
204 uint8_t mask = 1 << (7 - x%8); /* Currently checking bit in the byte. */
205
206 for (y = ySkipAnd; y < height; y++, pu8And += cbAndRow)
207 {
208 if ((*pu8And & mask) == 0)
209 {
210 xSkipAnd = x;
211 break;
212 }
213 }
214 }
215
216 if (xSkipAnd == ~(uint32_t)0)
217 {
218 xSkipAnd = 0;
219 }
220
221 /*
222 * Find the XOR mask top border.
223 */
224 uint32_t ySkipXor = ~0;
225
226 uint32_t *pu32XorStart = (uint32_t *)( pu8Shape + ((cbAndRow * height + 3) & ~3) );
227
228 uint32_t *pu32Xor = pu32XorStart;
229
230 for (y = 0; y < height && ySkipXor == ~(uint32_t)0; y++, pu32Xor += width)
231 {
232 for (x = 0; x < width; x++)
233 {
234 if (pu32Xor[x] != 0)
235 {
236 ySkipXor = y;
237 break;
238 }
239 }
240 }
241
242 if (ySkipXor == ~(uint32_t)0)
243 {
244 ySkipXor = 0;
245 }
246
247 /*
248 * Find the left border of the XOR mask.
249 */
250 uint32_t xSkipXor = ~(uint32_t)0;
251
252 /* For all columns. */
253 for (x = 0; x < width && xSkipXor == ~(uint32_t)0; x++)
254 {
255 pu32Xor = pu32XorStart + x; /* Currently checking dword. */
256
257 for (y = ySkipXor; y < height; y++, pu32Xor += width)
258 {
259 if (*pu32Xor != 0)
260 {
261 xSkipXor = x;
262 break;
263 }
264 }
265 }
266
267 if (xSkipXor == ~(uint32_t)0)
268 {
269 xSkipXor = 0;
270 }
271
272 *pxSkip = RT_MIN (xSkipAnd, xSkipXor);
273 *pySkip = RT_MIN (ySkipAnd, ySkipXor);
274}
275
276
277STDMETHODIMP VRDPConsoleCallback::OnMousePointerShapeChange (BOOL visible, BOOL alpha, ULONG xHot, ULONG yHot,
278 ULONG width, ULONG height, BYTE *shape)
279{
280 Log(("VRDPConsoleCallback::OnMousePointerShapeChange: %d, %d, %dx%d, @%d,%d\n", visible, alpha, width, height, xHot, yHot));
281
282 if (m_server)
283 {
284 if (!shape)
285 {
286 if (!visible)
287 {
288 m_server->MousePointerHide ();
289 }
290 }
291 else if (width != 0 && height != 0)
292 {
293 /* Pointer consists of 1 bpp AND and 24 BPP XOR masks.
294 * 'shape' AND mask followed by XOR mask.
295 * XOR mask contains 32 bit (lsb)BGR0(msb) values.
296 *
297 * We convert this to RDP color format which consist of
298 * one bpp AND mask and 24 BPP (BGR) color XOR image.
299 *
300 * RDP clients expect 8 aligned width and height of
301 * pointer (preferably 32x32).
302 *
303 * They even contain bugs which do not appear for
304 * 32x32 pointers but would appear for a 41x32 one.
305 *
306 * So set pointer size to 32x32. This can be done safely
307 * because most pointers are 32x32.
308 */
309
310 /* Windows guest alpha pointers are wider than 32 pixels.
311 * Try to find out the top-left border of the pointer and
312 * then copy only meaningful bits. All complete top rows
313 * and all complete left columns where (AND == 1 && XOR == 0)
314 * are skipped. Hot spot is adjusted.
315 */
316 uint32_t ySkip = 0; /* How many rows to skip at the top. */
317 uint32_t xSkip = 0; /* How many columns to skip at the left. */
318
319 findTopLeftBorder (shape, width, height, &xSkip, &ySkip);
320
321 /* Must not skip the hot spot. */
322 xSkip = RT_MIN (xSkip, xHot);
323 ySkip = RT_MIN (ySkip, yHot);
324
325 /*
326 * Compute size and allocate memory for the pointer.
327 */
328 const uint32_t dstwidth = 32;
329 const uint32_t dstheight = 32;
330
331 VRDPCOLORPOINTER *pointer = NULL;
332
333 uint32_t dstmaskwidth = (dstwidth + 7) / 8;
334
335 uint32_t rdpmaskwidth = dstmaskwidth;
336 uint32_t rdpmasklen = dstheight * rdpmaskwidth;
337
338 uint32_t rdpdatawidth = dstwidth * 3;
339 uint32_t rdpdatalen = dstheight * rdpdatawidth;
340
341 pointer = (VRDPCOLORPOINTER *)RTMemTmpAlloc (sizeof (VRDPCOLORPOINTER) + rdpmasklen + rdpdatalen);
342
343 if (pointer)
344 {
345 uint8_t *maskarray = (uint8_t *)pointer + sizeof (VRDPCOLORPOINTER);
346 uint8_t *dataarray = maskarray + rdpmasklen;
347
348 memset (maskarray, 0xFF, rdpmasklen);
349 memset (dataarray, 0x00, rdpdatalen);
350
351 uint32_t srcmaskwidth = (width + 7) / 8;
352 uint32_t srcdatawidth = width * 4;
353
354 /* Copy AND mask. */
355 uint8_t *src = shape + ySkip * srcmaskwidth;
356 uint8_t *dst = maskarray + (dstheight - 1) * rdpmaskwidth;
357
358 uint32_t minheight = RT_MIN (height - ySkip, dstheight);
359 uint32_t minwidth = RT_MIN (width - xSkip, dstwidth);
360
361 unsigned x, y;
362
363 for (y = 0; y < minheight; y++)
364 {
365 for (x = 0; x < minwidth; x++)
366 {
367 uint32_t byteIndex = (x + xSkip) / 8;
368 uint32_t bitIndex = (x + xSkip) % 8;
369
370 bool bit = (src[byteIndex] & (1 << (7 - bitIndex))) != 0;
371
372 if (!bit)
373 {
374 byteIndex = x / 8;
375 bitIndex = x % 8;
376
377 dst[byteIndex] &= ~(1 << (7 - bitIndex));
378 }
379 }
380
381 src += srcmaskwidth;
382 dst -= rdpmaskwidth;
383 }
384
385 /* Point src to XOR mask */
386 src = shape + ((srcmaskwidth * height + 3) & ~3) + ySkip * srcdatawidth;
387 dst = dataarray + (dstheight - 1) * rdpdatawidth;
388
389 for (y = 0; y < minheight ; y++)
390 {
391 for (x = 0; x < minwidth; x++)
392 {
393 memcpy (dst + x * 3, &src[4 * (x + xSkip)], 3);
394 }
395
396 src += srcdatawidth;
397 dst -= rdpdatawidth;
398 }
399
400 pointer->u16HotX = (uint16_t)(xHot - xSkip);
401 pointer->u16HotY = (uint16_t)(yHot - ySkip);
402
403 pointer->u16Width = (uint16_t)dstwidth;
404 pointer->u16Height = (uint16_t)dstheight;
405
406 pointer->u16MaskLen = (uint16_t)rdpmasklen;
407 pointer->u16DataLen = (uint16_t)rdpdatalen;
408
409 m_server->MousePointerUpdate (pointer);
410
411 RTMemTmpFree (pointer);
412 }
413 }
414 }
415
416 return S_OK;
417}
418#endif /* VRDP_NO_COM */
419
420
421// ConsoleVRDPServer
422////////////////////////////////////////////////////////////////////////////////
423
424#ifdef VBOX_VRDP
425RTLDRMOD ConsoleVRDPServer::mVRDPLibrary;
426
427#ifdef VRDP_NO_COM
428PFNVRDPCREATESERVER ConsoleVRDPServer::mpfnVRDPCreateServer = NULL;
429
430VRDPENTRYPOINTS_1 *ConsoleVRDPServer::mpEntryPoints = NULL;
431
432VRDPCALLBACKS_1 ConsoleVRDPServer::mCallbacks =
433{
434 { VRDP_INTERFACE_VERSION_1, sizeof (VRDPCALLBACKS_1) },
435 ConsoleVRDPServer::VRDPCallbackQueryProperty,
436 ConsoleVRDPServer::VRDPCallbackClientLogon,
437 ConsoleVRDPServer::VRDPCallbackClientConnect,
438 ConsoleVRDPServer::VRDPCallbackClientDisconnect,
439 ConsoleVRDPServer::VRDPCallbackIntercept,
440 ConsoleVRDPServer::VRDPCallbackUSB,
441 ConsoleVRDPServer::VRDPCallbackClipboard,
442 ConsoleVRDPServer::VRDPCallbackFramebufferQuery,
443 ConsoleVRDPServer::VRDPCallbackFramebufferLock,
444 ConsoleVRDPServer::VRDPCallbackFramebufferUnlock,
445 ConsoleVRDPServer::VRDPCallbackInput,
446 ConsoleVRDPServer::VRDPCallbackVideoModeHint
447};
448#else
449int (VBOXCALL *ConsoleVRDPServer::mpfnVRDPStartServer) (IConsole *pConsole, IVRDPServer *pVRDPServer, HVRDPSERVER *phServer);
450int (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSetFramebuffer) (HVRDPSERVER hServer, IFramebuffer *pFramebuffer, uint32_t fFlags);
451void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSetCallback) (HVRDPSERVER hServer, VRDPSERVERCALLBACK *pcallback, void *pvUser);
452void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPShutdownServer) (HVRDPSERVER hServer);
453void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSendUpdateBitmap)(HVRDPSERVER hServer, unsigned uScreenId, unsigned x, unsigned y, unsigned w, unsigned h);
454void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSendResize) (HVRDPSERVER hServer);
455void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSendAudioSamples)(HVRDPSERVER hserver, void *pvSamples, uint32_t cSamples, VRDPAUDIOFORMAT format);
456void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSendAudioVolume) (HVRDPSERVER hserver, uint16_t left, uint16_t right);
457void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSendUSBRequest) (HVRDPSERVER hserver, uint32_t u32ClientId, void *pvParms, uint32_t cbParms);
458void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPSendUpdate) (HVRDPSERVER hServer, unsigned uScreenId, void *pvUpdate, uint32_t cbUpdate);
459void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPQueryInfo) (HVRDPSERVER hserver, uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut);
460void (VBOXCALL *ConsoleVRDPServer::mpfnVRDPClipboard) (HVRDPSERVER hserver, uint32_t u32Function, uint32_t u32Format, const void *pvData, uint32_t cbData, uint32_t *pcbActualRead);
461#endif /* VRDP_NO_COM */
462#endif /* VBOX_VRDP */
463
464#ifdef VRDP_NO_COM
465DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackQueryProperty (void *pvCallback, uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut)
466{
467 ConsoleVRDPServer *server = static_cast <ConsoleVRDPServer *> (pvCallback);
468
469 int rc = VERR_NOT_SUPPORTED;
470
471 switch (index)
472 {
473 case VRDP_QP_NETWORK_PORT:
474 {
475 ULONG port = 0;
476 server->mConsole->getVRDPServer ()->COMGETTER(Port) (&port);
477 if (port == 0)
478 {
479 port = VRDP_DEFAULT_PORT;
480 }
481
482 if (cbBuffer >= sizeof (uint32_t))
483 {
484 *(uint32_t *)pvBuffer = (uint32_t)port;
485 rc = VINF_SUCCESS;
486 }
487 else
488 {
489 rc = VINF_BUFFER_OVERFLOW;
490 }
491
492 *pcbOut = sizeof (uint32_t);
493 } break;
494
495 case VRDP_QP_NETWORK_ADDRESS:
496 {
497 com::Bstr address;
498 server->mConsole->getVRDPServer ()->COMGETTER(NetAddress) (address.asOutParam());
499
500 if (cbBuffer >= address.length ())
501 {
502 if (address.length () > 0)
503 {
504 memcpy (pvBuffer, address.raw(), address.length ());
505 }
506 rc = VINF_SUCCESS;
507 }
508
509 *pcbOut = address.length ();
510 } break;
511
512 case VRDP_QP_NUMBER_MONITORS:
513 {
514 ULONG cMonitors = 1;
515
516 server->mConsole->machine ()->COMGETTER(MonitorCount)(&cMonitors);
517
518 if (cbBuffer >= sizeof (uint32_t))
519 {
520 *(uint32_t *)pvBuffer = (uint32_t)cMonitors;
521 rc = VINF_SUCCESS;
522 }
523 else
524 {
525 rc = VINF_BUFFER_OVERFLOW;
526 }
527
528 *pcbOut = sizeof (uint32_t);
529 } break;
530
531 default:
532 break;
533 }
534
535 return rc;
536}
537
538DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackClientLogon (void *pvCallback, uint32_t u32ClientId, const char *pszUser, const char *pszPassword, const char *pszDomain)
539{
540 ConsoleVRDPServer *server = static_cast <ConsoleVRDPServer *> (pvCallback);
541
542 return server->mConsole->VRDPClientLogon (u32ClientId, pszUser, pszPassword, pszDomain);
543}
544
545DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackClientConnect (void *pvCallback, uint32_t u32ClientId)
546{
547 ConsoleVRDPServer *server = static_cast <ConsoleVRDPServer *> (pvCallback);
548
549 server->mConsole->VRDPClientConnect (u32ClientId);
550}
551
552DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackClientDisconnect (void *pvCallback, uint32_t u32ClientId, uint32_t fu32Intercepted)
553{
554 ConsoleVRDPServer *server = static_cast <ConsoleVRDPServer *> (pvCallback);
555
556 server->mConsole->VRDPClientDisconnect (u32ClientId, fu32Intercepted);
557}
558
559DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackIntercept (void *pvCallback, uint32_t u32ClientId, uint32_t fu32Intercept, void **ppvIntercept)
560{
561 ConsoleVRDPServer *server = static_cast <ConsoleVRDPServer *> (pvCallback);
562
563 int rc = VERR_NOT_SUPPORTED;
564
565 switch (fu32Intercept)
566 {
567 case VRDP_CLIENT_INTERCEPT_AUDIO:
568 {
569 server->mConsole->VRDPInterceptAudio (u32ClientId);
570 rc = VINF_SUCCESS;
571 } break;
572
573 case VRDP_CLIENT_INTERCEPT_USB:
574 {
575 server->mConsole->VRDPInterceptUSB (u32ClientId);
576 rc = VINF_SUCCESS;
577 } break;
578
579 case VRDP_CLIENT_INTERCEPT_CLIPBOARD:
580 {
581 server->mConsole->VRDPInterceptClipboard (u32ClientId);
582 rc = VINF_SUCCESS;
583 } break;
584
585 default:
586 break;
587 }
588
589 if (VBOX_SUCCESS (rc))
590 {
591 if (ppvIntercept)
592 {
593 *ppvIntercept = server;
594 }
595 }
596
597 return rc;
598}
599
600DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackUSB (void *pvCallback, void *pvIntercept, uint32_t u32ClientId, uint8_t u8Code, const void *pvRet, uint32_t cbRet)
601{
602 ConsoleVRDPServer *server = static_cast <ConsoleVRDPServer *> (pvCallback);
603
604 return USBClientResponseCallback (pvIntercept, u32ClientId, u8Code, pvRet, cbRet);
605}
606
607DECLCALLBACK(int) ConsoleVRDPServer::VRDPCallbackClipboard (void *pvCallback, void *pvIntercept, uint32_t u32ClientId, uint32_t u32Function, uint32_t u32Format, const void *pvData, uint32_t cbData)
608{
609 ConsoleVRDPServer *server = static_cast <ConsoleVRDPServer *> (pvCallback);
610
611 return ClipboardCallback (pvIntercept, u32ClientId, u32Function, u32Format, pvData, cbData);
612}
613
614DECLCALLBACK(bool) ConsoleVRDPServer::VRDPCallbackFramebufferQuery (void *pvCallback, unsigned uScreenId, VRDPFRAMEBUFFERINFO *pInfo)
615{
616 ConsoleVRDPServer *server = static_cast <ConsoleVRDPServer *> (pvCallback);
617
618 bool fAvailable = false;
619
620 IFramebuffer *pfb = NULL;
621 LONG xOrigin = 0;
622 LONG yOrigin = 0;
623
624 server->mConsole->getDisplay ()->GetFramebuffer (uScreenId, &pfb, &xOrigin, &yOrigin);
625
626 if (pfb)
627 {
628 pfb->Lock ();
629
630 /* Query framebuffer parameters. */
631 ULONG lineSize = 0;
632 pfb->COMGETTER(BytesPerLine) (&lineSize);
633
634 ULONG bitsPerPixel = 0;
635 pfb->COMGETTER(BitsPerPixel) (&bitsPerPixel);
636
637 BYTE *address = NULL;
638 pfb->COMGETTER(Address) (&address);
639
640 ULONG height = 0;
641 pfb->COMGETTER(Height) (&height);
642
643 ULONG width = 0;
644 pfb->COMGETTER(Width) (&width);
645
646 /* Now fill the information as requested by the caller. */
647 pInfo->pu8Bits = address;
648 pInfo->xOrigin = xOrigin;
649 pInfo->yOrigin = yOrigin;
650 pInfo->cWidth = width;
651 pInfo->cHeight = height;
652 pInfo->cBitsPerPixel = bitsPerPixel;
653 pInfo->cbLine = lineSize;
654
655 pfb->Unlock ();
656
657 fAvailable = true;
658 }
659
660 if (server->maFramebuffers[uScreenId])
661 {
662 server->maFramebuffers[uScreenId]->Release ();
663 }
664 server->maFramebuffers[uScreenId] = pfb;
665
666 return fAvailable;
667}
668
669DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackFramebufferLock (void *pvCallback, unsigned uScreenId)
670{
671 ConsoleVRDPServer *server = static_cast <ConsoleVRDPServer *> (pvCallback);
672
673 if (server->maFramebuffers[uScreenId])
674 {
675 server->maFramebuffers[uScreenId]->Lock ();
676 }
677}
678
679DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackFramebufferUnlock (void *pvCallback, unsigned uScreenId)
680{
681 ConsoleVRDPServer *server = static_cast <ConsoleVRDPServer *> (pvCallback);
682
683 if (server->maFramebuffers[uScreenId])
684 {
685 server->maFramebuffers[uScreenId]->Unlock ();
686 }
687}
688
689DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackInput (void *pvCallback, int type, const void *pvInput, unsigned cbInput)
690{
691 ConsoleVRDPServer *server = static_cast <ConsoleVRDPServer *> (pvCallback);
692 Console *pConsole = server->mConsole;
693
694 switch (type)
695 {
696 case VRDP_INPUT_SCANCODE:
697 {
698 if (cbInput == sizeof (VRDPINPUTSCANCODE))
699 {
700 const VRDPINPUTSCANCODE *pInputScancode = (VRDPINPUTSCANCODE *)pvInput;
701 pConsole->getKeyboard ()->PutScancode((LONG)pInputScancode->uScancode);
702 }
703 } break;
704
705 case VRDP_INPUT_POINT:
706 {
707 if (cbInput == sizeof (VRDPINPUTPOINT))
708 {
709 const VRDPINPUTPOINT *pInputPoint = (VRDPINPUTPOINT *)pvInput;
710
711 int mouseButtons = 0;
712 int iWheel = 0;
713
714 if (pInputPoint->uButtons & VRDP_INPUT_POINT_BUTTON1)
715 {
716 mouseButtons |= MouseButtonState_LeftButton;
717 }
718 if (pInputPoint->uButtons & VRDP_INPUT_POINT_BUTTON2)
719 {
720 mouseButtons |= MouseButtonState_RightButton;
721 }
722 if (pInputPoint->uButtons & VRDP_INPUT_POINT_BUTTON3)
723 {
724 mouseButtons |= MouseButtonState_MiddleButton;
725 }
726 if (pInputPoint->uButtons & VRDP_INPUT_POINT_WHEEL_UP)
727 {
728 mouseButtons |= MouseButtonState_WheelUp;
729 iWheel = -1;
730 }
731 if (pInputPoint->uButtons & VRDP_INPUT_POINT_WHEEL_DOWN)
732 {
733 mouseButtons |= MouseButtonState_WheelDown;
734 iWheel = 1;
735 }
736
737 if (server->m_fGuestWantsAbsolute)
738 {
739 pConsole->getMouse()->PutMouseEventAbsolute (pInputPoint->x + 1, pInputPoint->y + 1, iWheel, mouseButtons);
740 } else
741 {
742 pConsole->getMouse()->PutMouseEvent (pInputPoint->x - server->m_mousex,
743 pInputPoint->y - server->m_mousey,
744 iWheel, mouseButtons);
745 server->m_mousex = pInputPoint->x;
746 server->m_mousey = pInputPoint->y;
747 }
748 }
749 } break;
750
751 case VRDP_INPUT_CAD:
752 {
753 pConsole->getKeyboard ()->PutCAD();
754 } break;
755
756 case VRDP_INPUT_RESET:
757 {
758 pConsole->Reset();
759 } break;
760
761 default:
762 break;
763 }
764}
765
766DECLCALLBACK(void) ConsoleVRDPServer::VRDPCallbackVideoModeHint (void *pvCallback, unsigned cWidth, unsigned cHeight, unsigned cBitsPerPixel, unsigned uScreenId)
767{
768 ConsoleVRDPServer *server = static_cast <ConsoleVRDPServer *> (pvCallback);
769
770 server->mConsole->getDisplay ()->SetVideoModeHint(cWidth, cHeight, cBitsPerPixel, uScreenId);
771}
772#endif /* VRDP_NO_COM */
773
774ConsoleVRDPServer::ConsoleVRDPServer (Console *console)
775{
776 mConsole = console;
777
778 int rc = RTCritSectInit (&mCritSect);
779 AssertRC (rc);
780
781 mcClipboardRefs = 0;
782 mpfnClipboardCallback = NULL;
783
784#ifdef VBOX_WITH_USB
785 mUSBBackends.pHead = NULL;
786 mUSBBackends.pTail = NULL;
787
788 mUSBBackends.thread = NIL_RTTHREAD;
789 mUSBBackends.fThreadRunning = false;
790 mUSBBackends.event = 0;
791#endif
792
793#ifdef VBOX_VRDP
794 mhServer = 0;
795
796#ifdef VRDP_NO_COM
797 m_fGuestWantsAbsolute = false;
798 m_mousex = 0;
799 m_mousey = 0;
800
801 memset (maFramebuffers, 0, sizeof (maFramebuffers));
802
803 mConsoleCallback = new VRDPConsoleCallback(this);
804 mConsoleCallback->AddRef();
805 console->RegisterCallback(mConsoleCallback);
806#endif /* VRDP_NO_COM */
807#endif /* VBOX_VRDP */
808
809 mAuthLibrary = 0;
810}
811
812ConsoleVRDPServer::~ConsoleVRDPServer ()
813{
814 Stop ();
815
816#ifdef VRDP_NO_COM
817 if (mConsoleCallback)
818 {
819 mConsole->UnregisterCallback(mConsoleCallback);
820 mConsoleCallback->Release();
821 mConsoleCallback = NULL;
822 }
823
824 int i;
825 for (i = 0; i < ELEMENTS(maFramebuffers); i++)
826 {
827 if (maFramebuffers[i])
828 {
829 maFramebuffers[i]->Release ();
830 maFramebuffers[i] = NULL;
831 }
832 }
833#endif /* VRDP_NO_COM */
834 if (RTCritSectIsInitialized (&mCritSect))
835 {
836 RTCritSectDelete (&mCritSect);
837 memset (&mCritSect, 0, sizeof (mCritSect));
838 }
839}
840
841int ConsoleVRDPServer::Launch (void)
842{
843 LogFlowMember(("ConsoleVRDPServer::Launch\n"));
844#ifdef VBOX_VRDP
845 int rc = VINF_SUCCESS;
846 IVRDPServer *vrdpserver = mConsole->getVRDPServer ();
847 Assert(vrdpserver);
848 BOOL vrdpEnabled = FALSE;
849
850 HRESULT rc2 = vrdpserver->COMGETTER(Enabled) (&vrdpEnabled);
851 AssertComRC(rc2);
852
853 if (SUCCEEDED (rc2)
854 && vrdpEnabled
855 && loadVRDPLibrary ())
856 {
857#ifdef VRDP_NO_COM
858 rc = mpfnVRDPCreateServer (&mCallbacks.header, this, (VRDPINTERFACEHDR **)&mpEntryPoints, &mhServer);
859#else
860 rc = mpfnVRDPStartServer(mConsole, vrdpserver, &mhServer);
861#endif /* VRDP_NO_COM */
862
863 if (VBOX_SUCCESS(rc))
864 {
865#ifdef VBOX_WITH_USB
866 remoteUSBThreadStart ();
867#endif /* VBOX_WITH_USB */
868 }
869 else
870 AssertMsgFailed(("Could not start VRDP server: rc = %Vrc\n", rc));
871 }
872#else
873 int rc = VERR_NOT_SUPPORTED;
874#endif /* VBOX_VRDP */
875 return rc;
876}
877
878#ifdef VRDP_NO_COM
879void ConsoleVRDPServer::EnableConnections (void)
880{
881#ifdef VBOX_VRDP
882 if (mpEntryPoints)
883 {
884 mpEntryPoints->VRDPEnableConnections (mhServer, true);
885 }
886#endif /* VBOX_VRDP */
887}
888
889void ConsoleVRDPServer::MousePointerUpdate (const VRDPCOLORPOINTER *pPointer)
890{
891#ifdef VBOX_VRDP
892 if (mpEntryPoints)
893 {
894 mpEntryPoints->VRDPColorPointer (mhServer, pPointer);
895 }
896#endif /* VBOX_VRDP */
897}
898
899void ConsoleVRDPServer::MousePointerHide (void)
900{
901#ifdef VBOX_VRDP
902 if (mpEntryPoints)
903 {
904 mpEntryPoints->VRDPHidePointer (mhServer);
905 }
906#endif /* VBOX_VRDP */
907}
908#else
909void ConsoleVRDPServer::SetCallback (void)
910{
911#ifdef VBOX_VRDP
912 /* This is called after VM is created and allows the server to accept client connection. */
913 if (mhServer && mpfnVRDPSetCallback)
914 {
915 mpfnVRDPSetCallback (mhServer, mConsole->getVrdpServerCallback (), mConsole);
916 }
917#endif /* VBOX_VRDP */
918}
919#endif /* VRDP_NO_COM */
920
921void ConsoleVRDPServer::Stop (void)
922{
923 Assert(VALID_PTR(this)); /** @todo r=bird: there are(/was) some odd cases where this buster was invalid on
924 * linux. Just remove this when it's 100% sure that problem has been fixed. */
925#ifdef VBOX_VRDP
926 if (mhServer)
927 {
928 HVRDPSERVER hServer = mhServer;
929
930 /* Reset the handle to avoid further calls to the server. */
931 mhServer = 0;
932
933#ifdef VRDP_NO_COM
934 if (mpEntryPoints)
935 {
936 mpEntryPoints->VRDPDestroy (mhServer);
937 }
938#else
939 mpfnVRDPShutdownServer (hServer);
940#endif /* VRDP_NO_COM */
941 }
942#endif /* VBOX_VRDP */
943
944#ifdef VBOX_WITH_USB
945 remoteUSBThreadStop ();
946#endif /* VBOX_WITH_USB */
947
948 mpfnAuthEntry = NULL;
949 mpfnAuthEntry2 = NULL;
950
951 if (mAuthLibrary)
952 {
953 RTLdrClose(mAuthLibrary);
954 mAuthLibrary = 0;
955 }
956}
957
958/* Worker thread for Remote USB. The thread polls the clients for
959 * the list of attached USB devices.
960 * The thread is also responsible for attaching/detaching devices
961 * to/from the VM.
962 *
963 * It is expected that attaching/detaching is not a frequent operation.
964 *
965 * The thread is always running when the VRDP server is active.
966 *
967 * The thread scans backends and requests the device list every 2 seconds.
968 *
969 * When device list is available, the thread calls the Console to process it.
970 *
971 */
972#define VRDP_DEVICE_LIST_PERIOD_MS (2000)
973
974#ifdef VBOX_WITH_USB
975static DECLCALLBACK(int) threadRemoteUSB (RTTHREAD self, void *pvUser)
976{
977 ConsoleVRDPServer *pOwner = (ConsoleVRDPServer *)pvUser;
978
979 LogFlow(("Console::threadRemoteUSB: start. owner = %p.\n", pOwner));
980
981 pOwner->notifyRemoteUSBThreadRunning (self);
982
983 while (pOwner->isRemoteUSBThreadRunning ())
984 {
985 RemoteUSBBackend *pRemoteUSBBackend = NULL;
986
987 while ((pRemoteUSBBackend = pOwner->usbBackendGetNext (pRemoteUSBBackend)) != NULL)
988 {
989 pRemoteUSBBackend->PollRemoteDevices ();
990 }
991
992 pOwner->waitRemoteUSBThreadEvent (VRDP_DEVICE_LIST_PERIOD_MS);
993
994 LogFlow(("Console::threadRemoteUSB: iteration. owner = %p.\n", pOwner));
995 }
996
997 return VINF_SUCCESS;
998}
999
1000void ConsoleVRDPServer::notifyRemoteUSBThreadRunning (RTTHREAD thread)
1001{
1002 mUSBBackends.thread = thread;
1003 mUSBBackends.fThreadRunning = true;
1004 int rc = RTThreadUserSignal (thread);
1005 AssertRC (rc);
1006}
1007
1008bool ConsoleVRDPServer::isRemoteUSBThreadRunning (void)
1009{
1010 return mUSBBackends.fThreadRunning;
1011}
1012
1013void ConsoleVRDPServer::waitRemoteUSBThreadEvent (unsigned cMillies)
1014{
1015 int rc = RTSemEventWait (mUSBBackends.event, cMillies);
1016 Assert (VBOX_SUCCESS(rc) || rc == VERR_TIMEOUT);
1017 NOREF(rc);
1018}
1019
1020void ConsoleVRDPServer::remoteUSBThreadStart (void)
1021{
1022 int rc = RTSemEventCreate (&mUSBBackends.event);
1023
1024 if (VBOX_FAILURE (rc))
1025 {
1026 AssertFailed ();
1027 mUSBBackends.event = 0;
1028 }
1029
1030 if (VBOX_SUCCESS (rc))
1031 {
1032 rc = RTThreadCreate (&mUSBBackends.thread, threadRemoteUSB, this, 65536,
1033 RTTHREADTYPE_VRDP_IO, RTTHREADFLAGS_WAITABLE, "remote usb");
1034 }
1035
1036 if (VBOX_FAILURE (rc))
1037 {
1038 LogRel(("Warning: could not start the remote USB thread, rc = %Vrc!!!\n", rc));
1039 mUSBBackends.thread = NIL_RTTHREAD;
1040 }
1041 else
1042 {
1043 /* Wait until the thread is ready. */
1044 rc = RTThreadUserWait (mUSBBackends.thread, 60000);
1045 AssertRC (rc);
1046 Assert (mUSBBackends.fThreadRunning || VBOX_FAILURE (rc));
1047 }
1048}
1049
1050void ConsoleVRDPServer::remoteUSBThreadStop (void)
1051{
1052 mUSBBackends.fThreadRunning = false;
1053
1054 if (mUSBBackends.thread != NIL_RTTHREAD)
1055 {
1056 Assert (mUSBBackends.event != 0);
1057
1058 RTSemEventSignal (mUSBBackends.event);
1059
1060 int rc = RTThreadWait (mUSBBackends.thread, 60000, NULL);
1061 AssertRC (rc);
1062
1063 mUSBBackends.thread = NIL_RTTHREAD;
1064 }
1065
1066 if (mUSBBackends.event)
1067 {
1068 RTSemEventDestroy (mUSBBackends.event);
1069 mUSBBackends.event = 0;
1070 }
1071}
1072#endif /* VBOX_WITH_USB */
1073
1074VRDPAuthResult ConsoleVRDPServer::Authenticate (const Guid &uuid, VRDPAuthGuestJudgement guestJudgement,
1075 const char *pszUser, const char *pszPassword, const char *pszDomain,
1076 uint32_t u32ClientId)
1077{
1078 VRDPAUTHUUID rawuuid;
1079
1080 memcpy (rawuuid, ((Guid &)uuid).ptr (), sizeof (rawuuid));
1081
1082 LogFlow(("ConsoleVRDPServer::Authenticate: uuid = %Vuuid, guestJudgement = %d, pszUser = %s, pszPassword = %s, pszDomain = %s, u32ClientId = %d\n",
1083 rawuuid, guestJudgement, pszUser, pszPassword, pszDomain, u32ClientId));
1084
1085 /*
1086 * Called only from VRDP input thread. So thread safety is not required.
1087 */
1088
1089 if (!mAuthLibrary)
1090 {
1091 /* Load the external authentication library. */
1092
1093 ComPtr<IMachine> machine;
1094 mConsole->COMGETTER(Machine)(machine.asOutParam());
1095
1096 ComPtr<IVirtualBox> virtualBox;
1097 machine->COMGETTER(Parent)(virtualBox.asOutParam());
1098
1099 ComPtr<ISystemProperties> systemProperties;
1100 virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());
1101
1102 Bstr authLibrary;
1103 systemProperties->COMGETTER(RemoteDisplayAuthLibrary)(authLibrary.asOutParam());
1104
1105 Utf8Str filename = authLibrary;
1106
1107 LogRel(("VRDPAUTH: ConsoleVRDPServer::Authenticate: loading external authentication library '%ls'\n", authLibrary.raw()));
1108
1109 int rc = RTLdrLoad (filename.raw(), &mAuthLibrary);
1110 if (VBOX_FAILURE (rc))
1111 LogRel(("VRDPAUTH: Failed to load external authentication library. Error code: %Vrc\n", rc));
1112
1113 if (VBOX_SUCCESS (rc))
1114 {
1115 /* Get the entry point. */
1116 mpfnAuthEntry2 = NULL;
1117 int rc2 = RTLdrGetSymbol(mAuthLibrary, "VRDPAuth2", (void**)&mpfnAuthEntry2);
1118 if (VBOX_FAILURE (rc2))
1119 {
1120 LogRel(("VRDPAUTH: Could not resolve import '%s'. Error code: %Vrc\n", "VRDPAuth2", rc2));
1121 rc = rc2;
1122 }
1123
1124 /* Get the entry point. */
1125 mpfnAuthEntry = NULL;
1126 rc2 = RTLdrGetSymbol(mAuthLibrary, "VRDPAuth", (void**)&mpfnAuthEntry);
1127 if (VBOX_FAILURE (rc2))
1128 {
1129 LogRel(("VRDPAUTH: Could not resolve import '%s'. Error code: %Vrc\n", "VRDPAuth", rc2));
1130 rc = rc2;
1131 }
1132
1133 if (mpfnAuthEntry2 || mpfnAuthEntry)
1134 {
1135 LogRel(("VRDPAUTH: Using entry point '%s'.\n", mpfnAuthEntry2? "VRDPAuth2": "VRDPAuth"));
1136 rc = VINF_SUCCESS;
1137 }
1138 }
1139
1140 if (VBOX_FAILURE (rc))
1141 {
1142 mConsole->reportAuthLibraryError (filename.raw(), rc);
1143
1144 mpfnAuthEntry = NULL;
1145 mpfnAuthEntry2 = NULL;
1146
1147 if (mAuthLibrary)
1148 {
1149 RTLdrClose(mAuthLibrary);
1150 mAuthLibrary = 0;
1151 }
1152
1153 return VRDPAuthAccessDenied;
1154 }
1155 }
1156
1157 Assert (mAuthLibrary && (mpfnAuthEntry || mpfnAuthEntry2));
1158
1159 VRDPAuthResult result = mpfnAuthEntry2?
1160 mpfnAuthEntry2 (&rawuuid, guestJudgement, pszUser, pszPassword, pszDomain, true, u32ClientId):
1161 mpfnAuthEntry (&rawuuid, guestJudgement, pszUser, pszPassword, pszDomain);
1162
1163 switch (result)
1164 {
1165 case VRDPAuthAccessDenied:
1166 LogRel(("VRDPAUTH: external authentication module returned 'access denied'\n"));
1167 break;
1168 case VRDPAuthAccessGranted:
1169 LogRel(("VRDPAUTH: external authentication module returned 'access granted'\n"));
1170 break;
1171 case VRDPAuthDelegateToGuest:
1172 LogRel(("VRDPAUTH: external authentication module returned 'delegate request to guest'\n"));
1173 break;
1174 default:
1175 LogRel(("VRDPAUTH: external authentication module returned incorrect return code %d\n", result));
1176 result = VRDPAuthAccessDenied;
1177 }
1178
1179 LogFlow(("ConsoleVRDPServer::Authenticate: result = %d\n", result));
1180
1181 return result;
1182}
1183
1184void ConsoleVRDPServer::AuthDisconnect (const Guid &uuid, uint32_t u32ClientId)
1185{
1186 VRDPAUTHUUID rawuuid;
1187
1188 memcpy (rawuuid, ((Guid &)uuid).ptr (), sizeof (rawuuid));
1189
1190 LogFlow(("ConsoleVRDPServer::AuthDisconnect: uuid = %Vuuid, u32ClientId = %d\n",
1191 rawuuid, u32ClientId));
1192
1193 Assert (mAuthLibrary && (mpfnAuthEntry || mpfnAuthEntry2));
1194
1195 if (mpfnAuthEntry2)
1196 mpfnAuthEntry2 (&rawuuid, VRDPAuthGuestNotAsked, NULL, NULL, NULL, false, u32ClientId);
1197}
1198
1199int ConsoleVRDPServer::lockConsoleVRDPServer (void)
1200{
1201 int rc = RTCritSectEnter (&mCritSect);
1202 AssertRC (rc);
1203 return rc;
1204}
1205
1206void ConsoleVRDPServer::unlockConsoleVRDPServer (void)
1207{
1208 RTCritSectLeave (&mCritSect);
1209}
1210
1211DECLCALLBACK(int) ConsoleVRDPServer::ClipboardCallback (void *pvCallback,
1212 uint32_t u32ClientId,
1213 uint32_t u32Function,
1214 uint32_t u32Format,
1215 const void *pvData,
1216 uint32_t cbData)
1217{
1218 LogFlowFunc(("pvCallback = %p, u32ClientId = %d, u32Function = %d, u32Format = 0x%08X, pvData = %p, cbData = %d\n",
1219 pvCallback, u32ClientId, u32Function, u32Format, pvData, cbData));
1220
1221 int rc = VINF_SUCCESS;
1222
1223 ConsoleVRDPServer *pServer = static_cast <ConsoleVRDPServer *>(pvCallback);
1224
1225 NOREF(u32ClientId);
1226
1227 switch (u32Function)
1228 {
1229 case VRDP_CLIPBOARD_FUNCTION_FORMAT_ANNOUNCE:
1230 {
1231 if (pServer->mpfnClipboardCallback)
1232 {
1233 pServer->mpfnClipboardCallback (VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE,
1234 u32Format,
1235 (void *)pvData,
1236 cbData);
1237 }
1238 } break;
1239
1240 case VRDP_CLIPBOARD_FUNCTION_DATA_READ:
1241 {
1242 if (pServer->mpfnClipboardCallback)
1243 {
1244 pServer->mpfnClipboardCallback (VBOX_CLIPBOARD_EXT_FN_DATA_READ,
1245 u32Format,
1246 (void *)pvData,
1247 cbData);
1248 }
1249 } break;
1250
1251 default:
1252 rc = VERR_NOT_SUPPORTED;
1253 }
1254
1255 return rc;
1256}
1257
1258DECLCALLBACK(int) ConsoleVRDPServer::ClipboardServiceExtension (void *pvExtension,
1259 uint32_t u32Function,
1260 void *pvParms,
1261 uint32_t cbParms)
1262{
1263 LogFlowFunc(("pvExtension = %p, u32Function = %d, pvParms = %p, cbParms = %d\n",
1264 pvExtension, u32Function, pvParms, cbParms));
1265
1266 int rc = VINF_SUCCESS;
1267
1268#ifdef VBOX_VRDP
1269 ConsoleVRDPServer *pServer = static_cast <ConsoleVRDPServer *>(pvExtension);
1270
1271 VBOXCLIPBOARDEXTPARMS *pParms = (VBOXCLIPBOARDEXTPARMS *)pvParms;
1272
1273 switch (u32Function)
1274 {
1275 case VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK:
1276 {
1277 pServer->mpfnClipboardCallback = (PFNVRDPCLIPBOARDEXTCALLBACK)pParms->pvData;
1278 } break;
1279
1280 case VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE:
1281 {
1282 /* The guest announces clipboard formats. This must be delivered to all clients. */
1283#ifdef VRDP_NO_COM
1284 if (mpEntryPoints)
1285 {
1286 mpEntryPoints->VRDPClipboard (pServer->mhServer,
1287 VRDP_CLIPBOARD_FUNCTION_FORMAT_ANNOUNCE,
1288 pParms->u32Format,
1289 NULL,
1290 0,
1291 NULL);
1292 }
1293#else
1294 if (mpfnVRDPClipboard)
1295 {
1296 mpfnVRDPClipboard (pServer->mhServer,
1297 VRDP_CLIPBOARD_FUNCTION_FORMAT_ANNOUNCE,
1298 pParms->u32Format,
1299 NULL,
1300 0,
1301 NULL);
1302 }
1303#endif /* VRDP_NO_COM */
1304 } break;
1305
1306 case VBOX_CLIPBOARD_EXT_FN_DATA_READ:
1307 {
1308 /* The clipboard service expects that the pvData buffer will be filled
1309 * with clipboard data. The server returns the data from the client that
1310 * announced the requested format most recently.
1311 */
1312#ifdef VRDP_NO_COM
1313 if (mpEntryPoints)
1314 {
1315 mpEntryPoints->VRDPClipboard (pServer->mhServer,
1316 VRDP_CLIPBOARD_FUNCTION_DATA_READ,
1317 pParms->u32Format,
1318 pParms->pvData,
1319 pParms->cbData,
1320 &pParms->cbData);
1321 }
1322#else
1323 if (mpfnVRDPClipboard)
1324 {
1325 mpfnVRDPClipboard (pServer->mhServer,
1326 VRDP_CLIPBOARD_FUNCTION_DATA_READ,
1327 pParms->u32Format,
1328 pParms->pvData,
1329 pParms->cbData,
1330 &pParms->cbData);
1331 }
1332#endif /* VRDP_NO_COM */
1333 } break;
1334
1335 case VBOX_CLIPBOARD_EXT_FN_DATA_WRITE:
1336 {
1337#ifdef VRDP_NO_COM
1338 if (mpEntryPoints)
1339 {
1340 mpEntryPoints->VRDPClipboard (pServer->mhServer,
1341 VRDP_CLIPBOARD_FUNCTION_DATA_WRITE,
1342 pParms->u32Format,
1343 pParms->pvData,
1344 pParms->cbData,
1345 NULL);
1346 }
1347#else
1348 if (mpfnVRDPClipboard)
1349 {
1350 mpfnVRDPClipboard (pServer->mhServer,
1351 VRDP_CLIPBOARD_FUNCTION_DATA_WRITE,
1352 pParms->u32Format,
1353 pParms->pvData,
1354 pParms->cbData,
1355 NULL);
1356 }
1357#endif /* VRDP_NO_COM */
1358 } break;
1359
1360 default:
1361 rc = VERR_NOT_SUPPORTED;
1362 }
1363#endif /* VBOX_VRDP */
1364
1365 return rc;
1366}
1367
1368#ifdef VRDP_NO_COM
1369void ConsoleVRDPServer::ClipboardCreate (uint32_t u32ClientId)
1370#else
1371void ConsoleVRDPServer::ClipboardCreate (uint32_t u32ClientId, PFNVRDPCLIPBOARDCALLBACK *ppfn, void **ppv)
1372#endif /* VRDP_NO_COM */
1373{
1374 int rc = lockConsoleVRDPServer ();
1375
1376 if (VBOX_SUCCESS (rc))
1377 {
1378 if (mcClipboardRefs == 0)
1379 {
1380 rc = HGCMHostRegisterServiceExtension (&mhClipboard, "VBoxSharedClipboard", ClipboardServiceExtension, this);
1381
1382 if (VBOX_SUCCESS (rc))
1383 {
1384 mcClipboardRefs++;
1385 }
1386 }
1387
1388#ifdef VRDP_NO_COM
1389#else
1390 if (VBOX_SUCCESS (rc))
1391 {
1392 *ppfn = ClipboardCallback;
1393 *ppv = this;
1394 }
1395#endif /* VRDP_NO_COM */
1396
1397 unlockConsoleVRDPServer ();
1398 }
1399}
1400
1401void ConsoleVRDPServer::ClipboardDelete (uint32_t u32ClientId)
1402{
1403 int rc = lockConsoleVRDPServer ();
1404
1405 if (VBOX_SUCCESS (rc))
1406 {
1407 mcClipboardRefs--;
1408
1409 if (mcClipboardRefs == 0)
1410 {
1411 HGCMHostUnregisterServiceExtension (mhClipboard);
1412 }
1413
1414 unlockConsoleVRDPServer ();
1415 }
1416}
1417
1418/* That is called on INPUT thread of the VRDP server.
1419 * The ConsoleVRDPServer keeps a list of created backend instances.
1420 */
1421#ifdef VRDP_NO_COM
1422void ConsoleVRDPServer::USBBackendCreate (uint32_t u32ClientId)
1423#else
1424void ConsoleVRDPServer::USBBackendCreate (uint32_t u32ClientId, PFNVRDPUSBCALLBACK *ppfn, void **ppv)
1425#endif /* VRDP_NO_COM */
1426{
1427#ifdef VBOX_WITH_USB
1428 LogFlow(("ConsoleVRDPServer::USBBackendCreate: u32ClientId = %d\n", u32ClientId));
1429
1430 /* Create a new instance of the USB backend for the new client. */
1431 RemoteUSBBackend *pRemoteUSBBackend = new RemoteUSBBackend (mConsole, this, u32ClientId);
1432
1433 if (pRemoteUSBBackend)
1434 {
1435 pRemoteUSBBackend->AddRef (); /* 'Release' called in USBBackendDelete. */
1436
1437 /* Append the new instance in the list. */
1438 int rc = lockConsoleVRDPServer ();
1439
1440 if (VBOX_SUCCESS (rc))
1441 {
1442 pRemoteUSBBackend->pNext = mUSBBackends.pHead;
1443 if (mUSBBackends.pHead)
1444 {
1445 mUSBBackends.pHead->pPrev = pRemoteUSBBackend;
1446 }
1447 else
1448 {
1449 mUSBBackends.pTail = pRemoteUSBBackend;
1450 }
1451
1452 mUSBBackends.pHead = pRemoteUSBBackend;
1453
1454 unlockConsoleVRDPServer ();
1455
1456#ifdef VRDP_NO_COM
1457#else
1458 pRemoteUSBBackend->QueryVRDPCallbackPointer (ppfn, ppv);
1459#endif /* VRDP_NO_COM */
1460 }
1461
1462 if (VBOX_FAILURE (rc))
1463 {
1464 pRemoteUSBBackend->Release ();
1465 }
1466 }
1467#endif /* VBOX_WITH_USB */
1468}
1469
1470void ConsoleVRDPServer::USBBackendDelete (uint32_t u32ClientId)
1471{
1472#ifdef VBOX_WITH_USB
1473 LogFlow(("ConsoleVRDPServer::USBBackendDelete: u32ClientId = %d\n", u32ClientId));
1474
1475 RemoteUSBBackend *pRemoteUSBBackend = NULL;
1476
1477 /* Find the instance. */
1478 int rc = lockConsoleVRDPServer ();
1479
1480 if (VBOX_SUCCESS (rc))
1481 {
1482 pRemoteUSBBackend = usbBackendFind (u32ClientId);
1483
1484 if (pRemoteUSBBackend)
1485 {
1486 /* Notify that it will be deleted. */
1487 pRemoteUSBBackend->NotifyDelete ();
1488 }
1489
1490 unlockConsoleVRDPServer ();
1491 }
1492
1493 if (pRemoteUSBBackend)
1494 {
1495 /* Here the instance has been excluded from the list and can be dereferenced. */
1496 pRemoteUSBBackend->Release ();
1497 }
1498#endif
1499}
1500
1501void *ConsoleVRDPServer::USBBackendRequestPointer (uint32_t u32ClientId, const Guid *pGuid)
1502{
1503#ifdef VBOX_WITH_USB
1504 RemoteUSBBackend *pRemoteUSBBackend = NULL;
1505
1506 /* Find the instance. */
1507 int rc = lockConsoleVRDPServer ();
1508
1509 if (VBOX_SUCCESS (rc))
1510 {
1511 pRemoteUSBBackend = usbBackendFind (u32ClientId);
1512
1513 if (pRemoteUSBBackend)
1514 {
1515 /* Inform the backend instance that it is referenced by the Guid. */
1516 bool fAdded = pRemoteUSBBackend->addUUID (pGuid);
1517
1518 if (fAdded)
1519 {
1520 /* Reference the instance because its pointer is being taken. */
1521 pRemoteUSBBackend->AddRef (); /* 'Release' is called in USBBackendReleasePointer. */
1522 }
1523 else
1524 {
1525 pRemoteUSBBackend = NULL;
1526 }
1527 }
1528
1529 unlockConsoleVRDPServer ();
1530 }
1531
1532 if (pRemoteUSBBackend)
1533 {
1534 return pRemoteUSBBackend->GetBackendCallbackPointer ();
1535 }
1536
1537#endif
1538 return NULL;
1539}
1540
1541void ConsoleVRDPServer::USBBackendReleasePointer (const Guid *pGuid)
1542{
1543#ifdef VBOX_WITH_USB
1544 RemoteUSBBackend *pRemoteUSBBackend = NULL;
1545
1546 /* Find the instance. */
1547 int rc = lockConsoleVRDPServer ();
1548
1549 if (VBOX_SUCCESS (rc))
1550 {
1551 pRemoteUSBBackend = usbBackendFindByUUID (pGuid);
1552
1553 if (pRemoteUSBBackend)
1554 {
1555 pRemoteUSBBackend->removeUUID (pGuid);
1556 }
1557
1558 unlockConsoleVRDPServer ();
1559
1560 if (pRemoteUSBBackend)
1561 {
1562 pRemoteUSBBackend->Release ();
1563 }
1564 }
1565#endif
1566}
1567
1568RemoteUSBBackend *ConsoleVRDPServer::usbBackendGetNext (RemoteUSBBackend *pRemoteUSBBackend)
1569{
1570 LogFlow(("ConsoleVRDPServer::usbBackendGetNext: pBackend = %p\n", pRemoteUSBBackend));
1571
1572 RemoteUSBBackend *pNextRemoteUSBBackend = NULL;
1573#ifdef VBOX_WITH_USB
1574
1575 int rc = lockConsoleVRDPServer ();
1576
1577 if (VBOX_SUCCESS (rc))
1578 {
1579 if (pRemoteUSBBackend == NULL)
1580 {
1581 /* The first backend in the list is requested. */
1582 pNextRemoteUSBBackend = mUSBBackends.pHead;
1583 }
1584 else
1585 {
1586 /* Get pointer to the next backend. */
1587 pNextRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
1588 }
1589
1590 if (pNextRemoteUSBBackend)
1591 {
1592 pNextRemoteUSBBackend->AddRef ();
1593 }
1594
1595 unlockConsoleVRDPServer ();
1596
1597 if (pRemoteUSBBackend)
1598 {
1599 pRemoteUSBBackend->Release ();
1600 }
1601 }
1602#endif
1603
1604 return pNextRemoteUSBBackend;
1605}
1606
1607#ifdef VBOX_WITH_USB
1608/* Internal method. Called under the ConsoleVRDPServerLock. */
1609RemoteUSBBackend *ConsoleVRDPServer::usbBackendFind (uint32_t u32ClientId)
1610{
1611 RemoteUSBBackend *pRemoteUSBBackend = mUSBBackends.pHead;
1612
1613 while (pRemoteUSBBackend)
1614 {
1615 if (pRemoteUSBBackend->ClientId () == u32ClientId)
1616 {
1617 break;
1618 }
1619
1620 pRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
1621 }
1622
1623 return pRemoteUSBBackend;
1624}
1625
1626/* Internal method. Called under the ConsoleVRDPServerLock. */
1627RemoteUSBBackend *ConsoleVRDPServer::usbBackendFindByUUID (const Guid *pGuid)
1628{
1629 RemoteUSBBackend *pRemoteUSBBackend = mUSBBackends.pHead;
1630
1631 while (pRemoteUSBBackend)
1632 {
1633 if (pRemoteUSBBackend->findUUID (pGuid))
1634 {
1635 break;
1636 }
1637
1638 pRemoteUSBBackend = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
1639 }
1640
1641 return pRemoteUSBBackend;
1642}
1643#endif
1644
1645/* Internal method. Called by the backend destructor. */
1646void ConsoleVRDPServer::usbBackendRemoveFromList (RemoteUSBBackend *pRemoteUSBBackend)
1647{
1648#ifdef VBOX_WITH_USB
1649 int rc = lockConsoleVRDPServer ();
1650 AssertRC (rc);
1651
1652 /* Exclude the found instance from the list. */
1653 if (pRemoteUSBBackend->pNext)
1654 {
1655 pRemoteUSBBackend->pNext->pPrev = pRemoteUSBBackend->pPrev;
1656 }
1657 else
1658 {
1659 mUSBBackends.pTail = (RemoteUSBBackend *)pRemoteUSBBackend->pPrev;
1660 }
1661
1662 if (pRemoteUSBBackend->pPrev)
1663 {
1664 pRemoteUSBBackend->pPrev->pNext = pRemoteUSBBackend->pNext;
1665 }
1666 else
1667 {
1668 mUSBBackends.pHead = (RemoteUSBBackend *)pRemoteUSBBackend->pNext;
1669 }
1670
1671 pRemoteUSBBackend->pNext = pRemoteUSBBackend->pPrev = NULL;
1672
1673 unlockConsoleVRDPServer ();
1674#endif
1675}
1676
1677
1678void ConsoleVRDPServer::SendUpdate (unsigned uScreenId, void *pvUpdate, uint32_t cbUpdate) const
1679{
1680#ifdef VBOX_VRDP
1681#ifdef VRDP_NO_COM
1682 if (mpEntryPoints)
1683 {
1684 mpEntryPoints->VRDPUpdate (mhServer, uScreenId, pvUpdate, cbUpdate);
1685 }
1686#else
1687 if (mpfnVRDPSendUpdate)
1688 mpfnVRDPSendUpdate (mhServer, uScreenId, pvUpdate, cbUpdate);
1689#endif /* VRDP_NO_COM */
1690#endif
1691}
1692
1693void ConsoleVRDPServer::SendResize (void) const
1694{
1695#ifdef VBOX_VRDP
1696#ifdef VRDP_NO_COM
1697 if (mpEntryPoints)
1698 {
1699 mpEntryPoints->VRDPResize (mhServer);
1700 }
1701#else
1702 if (mpfnVRDPSendResize)
1703 mpfnVRDPSendResize (mhServer);
1704#endif /* VRDP_NO_COM */
1705#endif
1706}
1707
1708void ConsoleVRDPServer::SendUpdateBitmap (unsigned uScreenId, uint32_t x, uint32_t y, uint32_t w, uint32_t h) const
1709{
1710#ifdef VBOX_VRDP
1711#ifdef VRDP_NO_COM
1712 VRDPORDERHDR update;
1713 update.x = x;
1714 update.y = y;
1715 update.w = w;
1716 update.h = h;
1717 if (mpEntryPoints)
1718 {
1719 mpEntryPoints->VRDPUpdate (mhServer, uScreenId, &update, sizeof (update));
1720 }
1721#else
1722 if (mpfnVRDPSendUpdateBitmap)
1723 mpfnVRDPSendUpdateBitmap (mhServer, uScreenId, x, y, w, h);
1724#endif /* VRDP_NO_COM */
1725#endif
1726}
1727
1728#ifdef VRDP_NO_COM
1729#else
1730void ConsoleVRDPServer::SetFramebuffer (IFramebuffer *framebuffer, uint32_t fFlags) const
1731{
1732#ifdef VBOX_VRDP
1733 if (mpfnVRDPSetFramebuffer)
1734 mpfnVRDPSetFramebuffer (mhServer, framebuffer, fFlags);
1735#endif
1736}
1737#endif /* VRDP_NO_COM */
1738
1739void ConsoleVRDPServer::SendAudioSamples (void *pvSamples, uint32_t cSamples, VRDPAUDIOFORMAT format) const
1740{
1741#ifdef VBOX_VRDP
1742#ifdef VRDP_NO_COM
1743 if (mpEntryPoints)
1744 {
1745 mpEntryPoints->VRDPAudioSamples (mhServer, pvSamples, cSamples, format);
1746 }
1747#else
1748 if (mpfnVRDPSendAudioSamples)
1749 mpfnVRDPSendAudioSamples (mhServer, pvSamples, cSamples, format);
1750#endif /* VRDP_NO_COM */
1751#endif
1752}
1753
1754void ConsoleVRDPServer::SendAudioVolume (uint16_t left, uint16_t right) const
1755{
1756#ifdef VBOX_VRDP
1757#ifdef VRDP_NO_COM
1758 if (mpEntryPoints)
1759 {
1760 mpEntryPoints->VRDPAudioVolume (mhServer, left, right);
1761 }
1762#else
1763 if (mpfnVRDPSendAudioVolume)
1764 mpfnVRDPSendAudioVolume (mhServer, left, right);
1765#endif /* VRDP_NO_COM */
1766#endif
1767}
1768
1769void ConsoleVRDPServer::SendUSBRequest (uint32_t u32ClientId, void *pvParms, uint32_t cbParms) const
1770{
1771#ifdef VBOX_VRDP
1772#ifdef VRDP_NO_COM
1773 if (mpEntryPoints)
1774 {
1775 mpEntryPoints->VRDPUSBRequest (mhServer, u32ClientId, pvParms, cbParms);
1776 }
1777#else
1778 if (mpfnVRDPSendUSBRequest)
1779 mpfnVRDPSendUSBRequest (mhServer, u32ClientId, pvParms, cbParms);
1780#endif /* VRDP_NO_COM */
1781#endif
1782}
1783
1784void ConsoleVRDPServer::QueryInfo (uint32_t index, void *pvBuffer, uint32_t cbBuffer, uint32_t *pcbOut) const
1785{
1786#ifdef VBOX_VRDP
1787#ifdef VRDP_NO_COM
1788 if (mpEntryPoints)
1789 {
1790 mpEntryPoints->VRDPQueryInfo (mhServer, index, pvBuffer, cbBuffer, pcbOut);
1791 }
1792#else
1793 if (mpfnVRDPQueryInfo)
1794 mpfnVRDPQueryInfo (mhServer, index, pvBuffer, cbBuffer, pcbOut);
1795#endif /* VRDP_NO_COM */
1796#endif
1797}
1798
1799#ifdef VBOX_VRDP
1800/* note: static function now! */
1801bool ConsoleVRDPServer::loadVRDPLibrary (void)
1802{
1803 int rc = VINF_SUCCESS;
1804
1805 if (!mVRDPLibrary)
1806 {
1807 rc = RTLdrLoad("VBoxVRDP", &mVRDPLibrary);
1808
1809 if (VBOX_SUCCESS(rc))
1810 {
1811 LogFlow(("VRDPServer::loadLibrary(): successfully loaded VRDP library.\n"));
1812
1813 struct SymbolEntry
1814 {
1815 const char *name;
1816 void **ppfn;
1817 };
1818
1819 #define DEFSYMENTRY(a) { #a, (void**)&mpfn##a }
1820
1821#ifdef VRDP_NO_COM
1822 static const struct SymbolEntry symbols[] =
1823 {
1824 DEFSYMENTRY(VRDPCreateServer)
1825 };
1826#else
1827 static const struct SymbolEntry symbols[] =
1828 {
1829 DEFSYMENTRY(VRDPStartServer),
1830 DEFSYMENTRY(VRDPSetCallback),
1831 DEFSYMENTRY(VRDPShutdownServer),
1832 DEFSYMENTRY(VRDPSendUpdate),
1833 DEFSYMENTRY(VRDPSendUpdateBitmap),
1834 DEFSYMENTRY(VRDPSendResize),
1835 DEFSYMENTRY(VRDPSendAudioSamples),
1836 DEFSYMENTRY(VRDPSendAudioVolume),
1837 DEFSYMENTRY(VRDPSendUSBRequest),
1838 DEFSYMENTRY(VRDPQueryInfo),
1839 DEFSYMENTRY(VRDPClipboard)
1840 };
1841#endif /* VRDP_NO_COM */
1842
1843 #undef DEFSYMENTRY
1844
1845 for (unsigned i = 0; i < ELEMENTS(symbols); i++)
1846 {
1847 rc = RTLdrGetSymbol(mVRDPLibrary, symbols[i].name, symbols[i].ppfn);
1848
1849 AssertMsgRC(rc, ("Error resolving VRDP symbol %s\n", symbols[i].name));
1850
1851 if (VBOX_FAILURE(rc))
1852 {
1853 break;
1854 }
1855 }
1856 }
1857 else
1858 {
1859 LogFlow(("VRDPServer::loadLibrary(): failed to load VRDP library! VRDP not available.\n"));
1860 mVRDPLibrary = NULL;
1861 }
1862 }
1863
1864 // just to be safe
1865 if (VBOX_FAILURE(rc))
1866 {
1867 if (mVRDPLibrary)
1868 {
1869 RTLdrClose (mVRDPLibrary);
1870 mVRDPLibrary = NULL;
1871 }
1872 }
1873
1874 return (mVRDPLibrary != NULL);
1875}
1876#endif /* VBOX_VRDP */
1877
1878/*
1879 * IRemoteDisplayInfo implementation.
1880 */
1881// constructor / destructor
1882/////////////////////////////////////////////////////////////////////////////
1883
1884HRESULT RemoteDisplayInfo::FinalConstruct()
1885{
1886 return S_OK;
1887}
1888
1889void RemoteDisplayInfo::FinalRelease()
1890{
1891 if (isReady())
1892 uninit ();
1893}
1894
1895// public methods only for internal purposes
1896/////////////////////////////////////////////////////////////////////////////
1897
1898/**
1899 * Initializes the guest object.
1900 */
1901HRESULT RemoteDisplayInfo::init (Console *aParent)
1902{
1903 LogFlowMember (("RemoteDisplayInfo::init (%p)\n", aParent));
1904
1905 ComAssertRet (aParent, E_INVALIDARG);
1906
1907 AutoLock alock (this);
1908 ComAssertRet (!isReady(), E_UNEXPECTED);
1909
1910 mParent = aParent;
1911
1912 setReady (true);
1913 return S_OK;
1914}
1915
1916/**
1917 * Uninitializes the instance and sets the ready flag to FALSE.
1918 * Called either from FinalRelease() or by the parent when it gets destroyed.
1919 */
1920void RemoteDisplayInfo::uninit()
1921{
1922 LogFlowMember (("RemoteDisplayInfo::uninit()\n"));
1923
1924 AutoLock alock (this);
1925 AssertReturn (isReady(), (void) 0);
1926
1927 mParent.setNull();
1928
1929 setReady (false);
1930}
1931
1932// IRemoteDisplayInfo properties
1933/////////////////////////////////////////////////////////////////////////////
1934
1935#define IMPL_GETTER_BOOL(_aType, _aName, _aIndex) \
1936 STDMETHODIMP RemoteDisplayInfo::COMGETTER(_aName) (_aType *a##_aName) \
1937 { \
1938 if (!a##_aName) \
1939 return E_POINTER; \
1940 \
1941 AutoLock alock (this); \
1942 CHECK_READY(); \
1943 \
1944 uint32_t value; \
1945 uint32_t cbOut = 0; \
1946 \
1947 mParent->consoleVRDPServer ()->QueryInfo \
1948 (_aIndex, &value, sizeof (value), &cbOut); \
1949 \
1950 *a##_aName = cbOut? !!value: FALSE; \
1951 \
1952 return S_OK; \
1953 }
1954
1955#define IMPL_GETTER_SCALAR(_aType, _aName, _aIndex) \
1956 STDMETHODIMP RemoteDisplayInfo::COMGETTER(_aName) (_aType *a##_aName) \
1957 { \
1958 if (!a##_aName) \
1959 return E_POINTER; \
1960 \
1961 AutoLock alock (this); \
1962 CHECK_READY(); \
1963 \
1964 _aType value; \
1965 uint32_t cbOut = 0; \
1966 \
1967 mParent->consoleVRDPServer ()->QueryInfo \
1968 (_aIndex, &value, sizeof (value), &cbOut); \
1969 \
1970 *a##_aName = cbOut? value: 0; \
1971 \
1972 return S_OK; \
1973 }
1974
1975#define IMPL_GETTER_BSTR(_aType, _aName, _aIndex) \
1976 STDMETHODIMP RemoteDisplayInfo::COMGETTER(_aName) (_aType *a##_aName) \
1977 { \
1978 if (!a##_aName) \
1979 return E_POINTER; \
1980 \
1981 AutoLock alock (this); \
1982 CHECK_READY(); \
1983 \
1984 uint32_t cbOut = 0; \
1985 \
1986 mParent->consoleVRDPServer ()->QueryInfo \
1987 (_aIndex, NULL, 0, &cbOut); \
1988 \
1989 if (cbOut == 0) \
1990 { \
1991 Bstr str(""); \
1992 str.cloneTo (a##_aName); \
1993 return S_OK; \
1994 } \
1995 \
1996 char *pchBuffer = (char *)RTMemTmpAlloc (cbOut); \
1997 \
1998 if (!pchBuffer) \
1999 { \
2000 Log(("RemoteDisplayInfo::" \
2001 #_aName \
2002 ": Failed to allocate memory %d bytes\n", cbOut)); \
2003 return E_OUTOFMEMORY; \
2004 } \
2005 \
2006 mParent->consoleVRDPServer ()->QueryInfo \
2007 (_aIndex, pchBuffer, cbOut, &cbOut); \
2008 \
2009 Bstr str(pchBuffer); \
2010 \
2011 str.cloneTo (a##_aName); \
2012 \
2013 RTMemTmpFree (pchBuffer); \
2014 \
2015 return S_OK; \
2016 }
2017
2018IMPL_GETTER_BOOL (BOOL, Active, VRDP_QI_ACTIVE);
2019IMPL_GETTER_SCALAR (ULONG, NumberOfClients, VRDP_QI_NUMBER_OF_CLIENTS);
2020IMPL_GETTER_SCALAR (LONG64, BeginTime, VRDP_QI_BEGIN_TIME);
2021IMPL_GETTER_SCALAR (LONG64, EndTime, VRDP_QI_END_TIME);
2022IMPL_GETTER_SCALAR (ULONG64, BytesSent, VRDP_QI_BYTES_SENT);
2023IMPL_GETTER_SCALAR (ULONG64, BytesSentTotal, VRDP_QI_BYTES_SENT_TOTAL);
2024IMPL_GETTER_SCALAR (ULONG64, BytesReceived, VRDP_QI_BYTES_RECEIVED);
2025IMPL_GETTER_SCALAR (ULONG64, BytesReceivedTotal, VRDP_QI_BYTES_RECEIVED_TOTAL);
2026IMPL_GETTER_BSTR (BSTR, User, VRDP_QI_USER);
2027IMPL_GETTER_BSTR (BSTR, Domain, VRDP_QI_DOMAIN);
2028IMPL_GETTER_BSTR (BSTR, ClientName, VRDP_QI_CLIENT_NAME);
2029IMPL_GETTER_BSTR (BSTR, ClientIP, VRDP_QI_CLIENT_IP);
2030IMPL_GETTER_SCALAR (ULONG, ClientVersion, VRDP_QI_CLIENT_VERSION);
2031IMPL_GETTER_SCALAR (ULONG, EncryptionStyle, VRDP_QI_ENCRYPTION_STYLE);
2032
2033#undef IMPL_GETTER_BSTR
2034#undef IMPL_GETTER_SCALAR
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