VirtualBox

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

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

Biggest check-in ever. New source code headers for all (C) innotek files.

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