Create a branch for network fixes.
[reactos.git] / base / applications / tsclient / porting-tools / rdesktop-core-tester / activex.cpp
1 #include "stdafx.h"
2
3 namespace MSTSCLib
4 {
5 #include "mstsclib_h.h"
6 };
7
8 namespace MSTSCLib_Redist
9 {
10 // extremely ew, but actually the cleanest way to import the alternate UUIDs
11 #include "mstsclib_redist_i.c"
12 };
13
14 #include "rdesktop/rdesktop.h"
15 #include "rdesktop/proto.h"
16
17 namespace
18 {
19 #ifdef _MSC_VER
20 extern "C" char __ImageBase;
21 #endif
22
23 HMODULE GetCurrentModule()
24 {
25 return reinterpret_cast<HMODULE>(&__ImageBase);
26 }
27
28 }
29
30 namespace
31 {
32
33 LONG g_moduleRefCount = 0;
34
35 void lockServer()
36 {
37 InterlockedIncrement(&g_moduleRefCount);
38 }
39
40 void unlockServer()
41 {
42 InterlockedDecrement(&g_moduleRefCount);
43 }
44
45 bool canUnloadServer()
46 {
47 return g_moduleRefCount == 0;
48 }
49
50 }
51
52 namespace
53 {
54
55 void FreeLpsz(LPSTR lpsz)
56 {
57 if(lpsz)
58 delete[] lpsz;
59 }
60
61 LPSTR AllocLpsz(const CHAR * lpsz, size_t cb)
62 {
63 LPSTR lpszNew = new CHAR[cb + 1];
64
65 if(lpszNew == NULL)
66 return NULL;
67
68 CopyMemory(lpszNew, lpsz, cb);
69 lpszNew[cb] = 0;
70
71 return lpszNew;
72 }
73
74 LPSTR AllocLpsz(const WCHAR * lpwsz, int cchIn)
75 {
76 int cch = WideCharToMultiByte(CP_ACP, 0, lpwsz, cchIn, NULL, 0, NULL, NULL);
77
78 if(cch <= 0)
79 return NULL;
80
81 LPSTR lpsz = new CHAR[cch];
82
83 if(lpsz == NULL)
84 return NULL;
85
86 cch = WideCharToMultiByte(CP_ACP, 0, lpwsz, cchIn, lpsz, cch, NULL, NULL);
87
88 if(cch <= 0)
89 {
90 FreeLpsz(lpsz);
91 return NULL;
92 }
93
94 return lpsz;
95 }
96
97 LPSTR BstrToLpsz(BSTR bstr)
98 {
99 return AllocLpsz(bstr, SysStringLen(bstr));
100 }
101
102 BSTR LpszToBstr(LPSTR lpsz)
103 {
104 int cch = MultiByteToWideChar(CP_ACP, 0, lpsz, -1, NULL, 0);
105
106 if(cch <= 0)
107 return NULL;
108
109 BSTR bstr = SysAllocStringLen(NULL, cch);
110
111 if(bstr == NULL)
112 return NULL;
113
114 cch = MultiByteToWideChar(CP_ACP, 0, lpsz, -1, bstr, cch);
115
116 if(cch <= 0)
117 {
118 SysFreeString(bstr);
119 return NULL;
120 }
121
122 return bstr;
123 }
124
125 }
126
127 namespace
128 {
129
130 template<class T, class U> T aligndown(const T& X, const U& align)
131 {
132 return X & ~(T(align) - 1);
133 }
134
135 template<class T, class U> T alignup(const T& X, const U& align)
136 {
137 return aligndown(X + (align - 1), align);
138 }
139
140 /* Convert between bitmap formats */
141 uint8 * win32_convert_scanlines(int width, int height, int bitcount, int fromalign, int toalign, const uint8 * data, uint8 ** buffer)
142 {
143 // TBD: profile & optimize the most common cases
144 assert(width > 0);
145 assert(height);
146 assert(bitcount && bitcount <= 32);
147 assert(fromalign <= toalign);
148 assert(data);
149 assert(buffer);
150
151 bool flipped = height < 0;
152
153 if(flipped)
154 height = - height;
155
156 int bytesperrow = alignup(width * bitcount, 8) / 8;
157 int fromstride = alignup(bytesperrow, fromalign);
158 int tostride = alignup(bytesperrow, toalign);
159 assert(fromstride <= tostride);
160
161 int datasize = tostride * height;
162
163 uint8 * dibits = new uint8[datasize];
164
165 const uint8 * src = data;
166 uint8 * dest = dibits;
167
168 const int pad = tostride - fromstride;
169
170 assert(pad < 4);
171 __assume(pad < 4);
172
173 if(flipped)
174 {
175 dest += (height - 1) * tostride;
176 tostride = - tostride;
177 }
178
179 for(int i = 0; i < height; ++ i)
180 {
181 memcpy(dest, src, fromstride);
182 memset(dest + fromstride, 0, pad);
183 src += fromstride;
184 dest += tostride;
185 }
186
187 *buffer = dibits;
188 return dibits;
189 }
190
191 /* Creates bitmaps */
192 HBITMAP win32_create_dib(LONG width, LONG height, WORD bitcount, const BYTE * data)
193 {
194 struct b_
195 {
196 BITMAPINFO bmi;
197 RGBQUAD colormap[256 - ARRAYSIZE(RTL_FIELD_TYPE(BITMAPINFO, bmiColors))];
198 }
199 b;
200
201 b.bmi.bmiHeader.biSize = sizeof(b.bmi.bmiHeader);
202 b.bmi.bmiHeader.biWidth = width;
203 b.bmi.bmiHeader.biHeight = height;
204 b.bmi.bmiHeader.biPlanes = 1;
205 b.bmi.bmiHeader.biBitCount = bitcount;
206 b.bmi.bmiHeader.biCompression = BI_RGB;
207 b.bmi.bmiHeader.biSizeImage = 0;
208 b.bmi.bmiHeader.biXPelsPerMeter = 0;
209 b.bmi.bmiHeader.biYPelsPerMeter = 0;
210
211 if(bitcount > 8)
212 {
213 b.bmi.bmiHeader.biClrUsed = 0;
214 b.bmi.bmiHeader.biClrImportant = 0;
215 }
216 else
217 {
218 b.bmi.bmiHeader.biClrUsed = 2 << bitcount;
219 b.bmi.bmiHeader.biClrImportant = 2 << bitcount;
220
221 // TODO: palette
222 }
223
224 // FIXME: beyond ugly
225 HDC hdc = CreateCompatibleDC(NULL);
226
227 if(hdc == NULL)
228 return NULL;
229
230 HBITMAP hbm = CreateDIBitmap(hdc, &b.bmi.bmiHeader, CBM_INIT, data, &b.bmi, DIB_RGB_COLORS);
231
232 if(hbm == NULL)
233 error("CreateDIBitmap %dx%dx%d failed\n", width, height, bitcount);
234
235 DeleteDC(hdc);
236 return hbm;
237 }
238
239 /* Creates brushes */
240 HBRUSH win32_create_brush(BRUSH * brush, COLORREF fgcolour)
241 {
242 if(brush == NULL)
243 return (HBRUSH)GetStockObject(NULL_BRUSH);
244
245 switch(brush->style)
246 {
247 case BS_SOLID:
248 case BS_NULL:
249 case BS_HATCHED:
250 case BS_PATTERN:
251 case BS_PATTERN8X8:
252 break;
253
254 default:
255 return NULL;
256 }
257
258 switch(brush->style)
259 {
260 case BS_SOLID:
261 return CreateSolidBrush(fgcolour);
262
263 case BS_HATCHED:
264 return CreateHatchBrush(brush->pattern[0], fgcolour);
265
266 case BS_NULL:
267 return (HBRUSH)GetStockObject(NULL_BRUSH);
268
269 case BS_PATTERN:
270 case BS_PATTERN8X8:
271 {
272 uint16 pattern[8];
273
274 for(size_t i = 0; i < 8; ++ i)
275 pattern[i] = brush->pattern[i];
276
277 HBITMAP hpattern = CreateBitmap(8, 8, 1, 1, pattern);
278 HBRUSH hbr = CreatePatternBrush(hpattern);
279 DeleteObject(hpattern);
280 return hbr;
281 }
282
283 DEFAULT_UNREACHABLE;
284 }
285 }
286 };
287
288 /*
289 "sealed" can improve optimizations by asserting a class cannot be derived
290 from, optimizing out accesses to the v-table from inside the class
291 */
292 #if defined(_MSC_VER) && _MSC_VER >= 1400
293 #define SEALED_ sealed
294 #else
295 #define SEALED_
296 #endif
297
298
299 /* Class that implements the RDP client GUI */
300 class RdpClientUI
301 {
302 public:
303 // TODO: pass the client settings relevant to the GUI here
304 HRESULT Initialize(HWND hwndParent)
305 {
306 // TODO: create the various windows
307 // TODO: create display window thread
308 // TODO: create input thread
309 return E_FAIL;
310 }
311
312 public:
313 static BOOL Startup()
314 {
315 WNDCLASSEX wcexUI = { sizeof(wcexUI) };
316 WNDCLASSEX wcexConsole = { sizeof(wcexConsole) };
317 WNDCLASSEX wcexDisplay = { sizeof(wcexDisplay) };
318 WNDCLASSEX wcexInput = { sizeof(wcexInput) };
319
320 HBRUSH nullBrush = (HBRUSH)GetStockObject(HOLLOW_BRUSH);
321
322 wcexUI.lpfnWndProc = NULL; // TODO
323 wcexUI.hInstance = GetCurrentModule();
324 wcexUI.hCursor = LoadCursor(NULL, IDC_ARROW);
325 wcexUI.hbrBackground = nullBrush;
326 wcexUI.lpszClassName = TEXT("MissTosca_UI");
327
328 wcexConsole.style = CS_VREDRAW | CS_HREDRAW;
329 wcexConsole.lpfnWndProc = NULL; // TODO
330 wcexConsole.hInstance = GetCurrentModule();
331 wcexConsole.hCursor = LoadCursor(NULL, IDC_ARROW);
332 wcexConsole.hbrBackground = nullBrush;
333 wcexConsole.lpszClassName = TEXT("MissTosca_Console");
334
335 wcexDisplay.style = CS_VREDRAW | CS_HREDRAW;
336 wcexDisplay.lpfnWndProc = NULL; // TODO
337 wcexDisplay.hInstance = GetCurrentModule();
338 wcexDisplay.hCursor = LoadCursor(NULL, IDC_ARROW);
339 wcexDisplay.hbrBackground = nullBrush;
340 wcexDisplay.lpszClassName = TEXT("MissTosca_Display");
341
342 wcexInput.style = CS_VREDRAW | CS_HREDRAW;
343 wcexInput.lpfnWndProc = NULL; // TODO
344 wcexInput.hInstance = GetCurrentModule();
345 wcexInput.hCursor = NULL;
346 wcexInput.hbrBackground = nullBrush;
347 wcexInput.lpszClassName = TEXT("MissTosca_Input");
348
349 return
350 RegisterClassEx(&wcexUI) &&
351 RegisterClassEx(&wcexConsole) &&
352 RegisterClassEx(&wcexDisplay) &&
353 RegisterClassEx(&wcexInput);
354 }
355
356 static void Shutdown()
357 {
358 // TODO
359 }
360
361 /*
362 This is the main UI window. It's the direct child of the control
363 window, it fills its whole extent and it contains the scrollbars.
364 When activated, it will move keyboard focus to the input window
365 */
366 private:
367 HWND m_uiWindow;
368 LONG m_scrollHPos;
369 LONG m_scrollVPos;
370
371 LRESULT UIWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
372 {
373 switch(uMsg)
374 {
375 // Keep the keyboard focus on the input window
376 case WM_ACTIVATE:
377 switch(LOWORD(wParam))
378 {
379 case WA_INACTIVE:
380 break;
381
382 case WA_ACTIVE:
383 case WA_CLICKACTIVE:
384 if(!HIWORD(wParam))
385 SetFocus(m_inputWindow);
386 }
387
388 return 0;
389
390 // Resized: rearrange children windows, adjust scrollbars
391 case WM_SIZE:
392 {
393 if(IsIconic(m_uiWindow))
394 break;
395
396 RECT rcClient;
397 GetWindowRect(m_uiWindow, &rcClient);
398
399 if(m_smartSizing)
400 {
401 // we are not supposed to maintain aspect ratio. Container has to do that
402 m_consoleX = 0;
403 m_consoleY = 0;
404 m_consoleWidth = rcClient.right;
405 m_consoleHeight = rcClient.bottom;
406 }
407 else
408 {
409 // center horizontally, no horizontal scrollbar
410 if(rcClient.right >= m_consoleWidth)
411 m_consoleX = (m_consoleWidth - rcClient.right) / 2;
412
413 // center vertically, no vertical scrollbar
414 if(rcClient.bottom >= m_consoleHeight)
415 m_consoleY = (m_consoleHeight - rcClient.right) / 2;
416 }
417
418 SCROLLINFO scroll = { sizeof(scroll), SIF_ALL, 0 };
419
420 // update the horizontal scrollbar
421 scroll.nMax = m_consoleWidth;
422 scroll.nPage = rcClient.right;
423 scroll.nPos = 0 - m_consoleX;
424 SetScrollInfo(m_uiWindow, SB_HORZ, &scroll, TRUE);
425
426 // update the vertical scrollbar
427 scroll.nMax = m_consoleHeight;
428 scroll.nPage = rcClient.bottom;
429 scroll.nPos = 0 - m_consoleY;
430 SetScrollInfo(m_uiWindow, SB_VERT, &scroll, TRUE);
431
432 // move/resize the console window
433 MoveWindow(m_consoleWindow, m_consoleX, m_consoleY, m_consoleWidth, m_consoleHeight, TRUE);
434 }
435
436 return 0;
437
438 case WM_HSCROLL:
439 {
440 SCROLLINFO scroll = { sizeof(scroll), SIF_TRACKPOS };
441 GetScrollInfo(m_uiWindow, SB_HORZ, &scroll);
442 m_consoleX = - scroll.nTrackPos;
443 MoveWindow(m_consoleWindow, m_consoleX, m_consoleY, m_consoleWidth, m_consoleHeight, TRUE);
444 }
445
446 return 0;
447
448 case WM_VSCROLL:
449 {
450 SCROLLINFO scroll = { sizeof(scroll), SIF_TRACKPOS };
451 GetScrollInfo(m_uiWindow, SB_VERT, &scroll);
452 m_consoleY = - scroll.nTrackPos;
453 MoveWindow(m_consoleWindow, m_consoleX, m_consoleY, m_consoleWidth, m_consoleHeight, TRUE);
454 }
455
456 return 0;
457
458 default:
459 break;
460 }
461
462 return DefWindowProc(m_uiWindow, uMsg, wParam, lParam);
463 }
464
465 /*
466 This is the full-screen title bar. It's displayed at the top of the
467 main UI window while in full-screen mode, and it contains two toolbars
468 with the pin, minimize, restore and close buttons
469 */
470 HWND m_fullScreenBarWindow;
471
472 /*
473 This is the console window. It has the same extent as the display on
474 the remote computer, or it fills the UI window in smart resizing mode,
475 and it contains the input and display windows
476 */
477 private:
478 HWND m_consoleWindow;
479 LONG m_consoleX;
480 LONG m_consoleY;
481 LONG m_consoleWidth;
482 LONG m_consoleHeight;
483 bool m_smartSizing;
484
485 LRESULT ConsoleWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
486 {
487 switch(uMsg)
488 {
489 case WM_SIZE:
490 {
491 RECT rcClient;
492 GetClientRect(m_consoleWindow, &rcClient);
493
494 MoveWindow(m_inputWindow, 0, 0, rcClient.right, rcClient.bottom, TRUE);
495 MoveWindow(m_displayWindow, 0, 0, rcClient.right, rcClient.bottom, TRUE);
496 }
497
498 return 0;
499
500 default:
501 break;
502 }
503
504 return DefWindowProc(m_consoleWindow, uMsg, wParam, lParam);
505 }
506
507 /*
508 This is the display window. It represents the virtual display of the
509 remote computer. It completely fills its parent, the console window,
510 and it runs in its own thread for performance reasons
511 */
512 private:
513 HWND m_displayWindow;
514 LONG m_displayBufferWidth;
515 LONG m_displayBufferHeight;
516 HDC m_displayBuffer;
517 void * m_displayBufferRaw;
518 int m_displayBufferSave;
519 int m_displayBufferBitDepth;
520 int m_displayBufferByteDepth;
521 int m_displayBufferStride;
522 RECT m_displayBufferClip;
523 CRITICAL_SECTION m_displayBufferMutex;
524
525 LRESULT DisplayWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
526 {
527 switch(uMsg)
528 {
529 case WM_DESTROY:
530 PostQuitMessage(0);
531 return 0;
532
533 case WM_PRINTCLIENT:
534 if(wParam == 0)
535 break;
536
537 case WM_PAINT:
538 {
539 HDC hdc = (HDC)wParam;
540
541 EnterCriticalSection(&m_displayBufferMutex);
542
543 if(hdc)
544 {
545 RECT rc;
546 GetClientRect(m_displayWindow, &rc);
547 BitBlt(hdc, 0, 0, rc.right, rc.bottom, m_displayBuffer, 0, 0, SRCCOPY);
548 }
549 else
550 {
551 PAINTSTRUCT ps;
552 hdc = BeginPaint(m_displayWindow, &ps);
553
554 if(!m_smartSizing)
555 {
556 BitBlt
557 (
558 hdc,
559 ps.rcPaint.left,
560 ps.rcPaint.top,
561 ps.rcPaint.right - ps.rcPaint.left,
562 ps.rcPaint.bottom - ps.rcPaint.top,
563 m_displayBuffer,
564 ps.rcPaint.left,
565 ps.rcPaint.top,
566 SRCCOPY
567 );
568 }
569 else
570 {
571 // bleh. There has to be a better way
572 SetStretchBltMode(hdc, HALFTONE);
573
574 StretchBlt
575 (
576 hdc,
577 0,
578 0,
579 m_consoleWidth,
580 m_consoleHeight,
581 m_displayBuffer,
582 0,
583 0,
584 m_displayBufferWidth,
585 m_displayBufferHeight,
586 SRCCOPY
587 );
588 }
589
590 EndPaint(m_displayWindow, &ps);
591 }
592
593 LeaveCriticalSection(&m_displayBufferMutex);
594 }
595
596 return 0;
597
598 default:
599 break;
600 }
601
602 return DefWindowProc(m_displayWindow, uMsg, wParam, lParam);
603 }
604
605 /* Screen repainting */
606 void Display_RepaintRect(const RECT * lprc)
607 {
608 if(m_smartSizing)
609 return Display_RepaintAll();
610
611 RECT rcDamage;
612 IntersectRect(&rcDamage, lprc, &m_displayBufferClip);
613 InvalidateRect(m_displayWindow, &rcDamage, FALSE);
614 }
615
616 void Display_RepaintArea(int x, int y, int cx, int cy)
617 {
618 if(m_smartSizing)
619 return Display_RepaintAll();
620
621 RECT rcDamage;
622 rcDamage.left = x;
623 rcDamage.top = y;
624 rcDamage.right = x + cx;
625 rcDamage.bottom = y + cy;
626 Display_RepaintRect(&rcDamage);
627 }
628
629 void Display_RepaintPolygon(POINT * point, int npoints, int linewidth)
630 {
631 if(m_smartSizing)
632 return Display_RepaintAll();
633
634 RECT rcDamage;
635
636 rcDamage.left = MAXLONG;
637 rcDamage.top = MAXLONG;
638 rcDamage.right = 0;
639 rcDamage.bottom = 0;
640
641 for(int i = 0; i < npoints; ++ i)
642 {
643 if(point[i].x < rcDamage.left)
644 rcDamage.left = point[i].x;
645
646 if(point[i].y < rcDamage.top)
647 rcDamage.top = point[i].y;
648
649 if(point[i].x > rcDamage.right)
650 rcDamage.right = point[i].x;
651
652 if(point[i].y > rcDamage.bottom)
653 rcDamage.bottom = point[i].y;
654 }
655
656 InflateRect(&rcDamage, linewidth, linewidth);
657 Display_RepaintRect(&rcDamage);
658 }
659
660 void Display_RepaintAll()
661 {
662 InvalidateRgn(m_displayWindow, NULL, FALSE);
663 }
664
665 public:
666 void Display_SetClip(int x, int y, int cx, int cy)
667 {
668 m_displayBufferClip.left = x;
669 m_displayBufferClip.top = y;
670 m_displayBufferClip.right = x + cx + 1;
671 m_displayBufferClip.bottom = y + cy + 1;
672
673 HRGN hrgn = CreateRectRgnIndirect(&m_displayBufferClip);
674 SelectClipRgn(m_displayBuffer, hrgn);
675 DeleteObject(hrgn);
676 }
677
678 void Display_ResetClip()
679 {
680 m_displayBufferClip.left = 0;
681 m_displayBufferClip.top = 0;
682 m_displayBufferClip.right = m_displayBufferWidth;
683 m_displayBufferClip.bottom = m_displayBufferHeight;
684 SelectClipRgn(m_displayBuffer, NULL);
685 }
686
687 void Display_PaintBitmap(int x, int y, int cx, int cy, int width, int height, uint8 * data)
688 {
689 GdiFlush();
690
691 int fromstride = alignup(width * m_displayBufferByteDepth, 4);
692 int sizex = cx * m_displayBufferByteDepth;
693
694 const uint8 * src = data;
695
696 uint8 * dst =
697 (uint8 *)m_displayBufferRaw +
698 (m_displayBufferHeight - y - cy) * m_displayBufferStride +
699 x * m_displayBufferByteDepth;
700
701 for(int i = 0; i < cy; ++ i)
702 {
703 memcpy(dst, src, sizex);
704 src += fromstride;
705 dst += m_displayBufferStride;
706 }
707
708 Display_RepaintArea(x, y, cx, cy);
709 }
710
711 void Display_DestBlt(uint8 opcode, int x, int y, int cx, int cy)
712 {
713 int dcsave = SaveDC(m_displayBuffer);
714 SelectObject(m_displayBuffer, GetStockObject(BLACK_BRUSH));
715 PatBlt(m_displayBuffer, x, y, cx, cy, MAKELONG(0, opcode));
716 RestoreDC(m_displayBuffer, dcsave);
717 Display_RepaintArea(x, y, cx, cy);
718 }
719
720 void Display_PatBlt(uint8 opcode, int x, int y, int cx, int cy, BRUSH * brush, int bgcolour, int fgcolour)
721 {
722 HBRUSH hbr = win32_create_brush(brush, fgcolour);
723
724 int dcsave = SaveDC(m_displayBuffer);
725
726 SetBkColor(m_displayBuffer, bgcolour);
727 SetTextColor(m_displayBuffer, fgcolour);
728 SetBrushOrgEx(m_displayBuffer, brush->xorigin, brush->yorigin, NULL);
729 SelectObject(m_displayBuffer, hbr);
730
731 PatBlt(m_displayBuffer, x, y, cx, cy, MAKELONG(0, opcode));
732
733 RestoreDC(m_displayBuffer, dcsave);
734
735 DeleteObject(hbr);
736
737 Display_RepaintArea(x, y, cx, cy);
738 }
739
740 void Display_ScreenBlt(uint8 opcode, int x, int y, int cx, int cy, int srcx, int srcy)
741 {
742 BitBlt(m_displayBuffer, x, y, cx, cy, m_displayBuffer, srcx, srcy, MAKELONG(0, opcode));
743 Display_RepaintArea(x, y, cx, cy);
744 }
745
746 void Display_MemBlt(uint8 opcode, int x, int y, int cx, int cy, HBITMAP src, int srcx, int srcy)
747 {
748 HDC hdcSrc = CreateCompatibleDC(m_displayBuffer);
749 HGDIOBJ hOld = SelectObject(hdcSrc, src);
750
751 BitBlt(m_displayBuffer, x, y, cx, cy, hdcSrc, srcx, srcy, MAKELONG(0, opcode));
752
753 SelectObject(hdcSrc, hOld);
754 DeleteDC(hdcSrc);
755
756 Display_RepaintArea(x, y, cx, cy);
757 }
758
759 void Display_TriBlt(uint8 opcode, int x, int y, int cx, int cy, HBITMAP src, int srcx, int srcy, BRUSH * brush, int bgcolour, int fgcolour)
760 {
761 // TODO
762 HDC hdcSrc = CreateCompatibleDC(m_displayBuffer);
763 HGDIOBJ hOld = SelectObject(hdcSrc, src);
764
765 //SELECT_BRUSH(brush, bgcolour, fgcolour);
766
767 BitBlt(m_displayBuffer, x, y, cx, cy, hdcSrc, srcx, srcy, MAKELONG(0, opcode));
768
769 //RESET_BRUSH();
770
771 SelectObject(hdcSrc, hOld);
772 DeleteDC(hdcSrc);
773
774 Display_RepaintArea(x, y, cx, cy);
775 }
776
777 void Display_Line(uint8 opcode, int startx, int starty, int endx, int endy, PEN * pen)
778 {
779 HPEN hpen = CreatePen(pen->style, pen->width, pen->colour);
780
781 int dcsave = SaveDC(m_displayBuffer);
782
783 SetROP2(m_displayBuffer, opcode);
784 SelectObject(m_displayBuffer, hpen);
785 MoveToEx(m_displayBuffer, startx, starty, NULL);
786
787 LineTo(m_displayBuffer, endx, endy);
788
789 RestoreDC(m_displayBuffer, dcsave);
790
791 DeleteObject(hpen);
792
793 RECT rcDamage;
794
795 if(startx < endx)
796 {
797 rcDamage.left = startx;
798 rcDamage.right = endx;
799 }
800 else
801 {
802 rcDamage.left = endx;
803 rcDamage.right = startx;
804 }
805
806 if(starty < endy)
807 {
808 rcDamage.top = starty;
809 rcDamage.bottom = endy;
810 }
811 else
812 {
813 rcDamage.top = endy;
814 rcDamage.bottom = starty;
815 }
816
817 InflateRect(&rcDamage, pen->width, pen->width);
818 Display_RepaintRect(&rcDamage);
819 }
820
821 void Display_Rect(int x, int y, int cx, int cy, int colour)
822 {
823 HBRUSH hbr = CreateSolidBrush(colour);
824
825 int dcsave = SaveDC(m_displayBuffer);
826
827 SelectObject(m_displayBuffer, hbr);
828 SelectObject(m_displayBuffer, GetStockObject(NULL_PEN));
829
830 Rectangle(m_displayBuffer, x, y, x + cx + 1, y + cy + 1);
831
832 RestoreDC(m_displayBuffer, dcsave);
833
834 DeleteObject(hbr);
835
836 Display_RepaintArea(x, y, cx, cy);
837 }
838
839 void Display_Polygon(uint8 opcode, uint8 fillmode, POINT * point, int npoints, BRUSH * brush, int bgcolour, int fgcolour)
840 {
841 HBRUSH hbr = win32_create_brush(brush, fgcolour);
842
843 int dcsave = SaveDC(m_displayBuffer);
844
845 SetBkColor(m_displayBuffer, bgcolour);
846 SetTextColor(m_displayBuffer, fgcolour);
847 SetPolyFillMode(m_displayBuffer, fillmode);
848 SelectObject(m_displayBuffer, hbr);
849
850 Polygon(m_displayBuffer, point, npoints);
851
852 RestoreDC(m_displayBuffer, dcsave);
853
854 Display_RepaintPolygon(point, npoints, 0);
855 }
856
857 void Display_Polyline(uint8 opcode, POINT * points, int npoints, PEN * pen)
858 {
859 POINT last = points[0];
860
861 for(int i = 1; i < npoints; ++ i)
862 {
863 points[i].x += last.x;
864 points[i].y += last.y;
865 last = points[i];
866 }
867
868 HPEN hpen = CreatePen(pen->style, pen->width, pen->colour);
869
870 int dcsave = SaveDC(m_displayBuffer);
871
872 SetROP2(m_displayBuffer, opcode);
873 SelectObject(m_displayBuffer, hpen);
874
875 Polyline(m_displayBuffer, points, npoints);
876
877 RestoreDC(m_displayBuffer, dcsave);
878
879 DeleteObject(hpen);
880
881 Display_RepaintPolygon(points, npoints, pen->width);
882 }
883
884 void Display_Ellypse(uint8 opcode, uint8 fillmode, int x, int y, int cx, int cy, BRUSH * brush, int bgcolour, int fgcolour)
885 {
886 // TODO
887
888 Display_RepaintArea(x, y, cx, cy);
889 }
890
891 // TBD: optimize text drawing
892 void Display_DrawGlyph(int mixmode, int x, int y, int cx, int cy, HGLYPH glyph, int srcx, int srcy, int bgcolour, int fgcolour)
893 {
894 HBITMAP hbmGlyph = (HBITMAP)glyph;
895 HDC hdcGlyph = CreateCompatibleDC(m_displayBuffer);
896 HGDIOBJ hOld = SelectObject(hdcGlyph, hbmGlyph);
897
898 int dcsave = SaveDC(m_displayBuffer);
899
900 switch(mixmode)
901 {
902 case MIX_TRANSPARENT:
903 {
904 /*
905 ROP is DSPDxax:
906 - where the glyph (S) is white, D is set to the foreground color (P)
907 - where the glyph (S) is black, D is left untouched
908
909 This paints a transparent glyph in the specified color
910 */
911 HBRUSH hbr = CreateSolidBrush(fgcolour);
912 SelectObject(m_displayBuffer, hbr);
913 BitBlt(m_displayBuffer, x, y, cx, cy, hdcGlyph, srcx, srcy, MAKELONG(0, 0xe2));
914 DeleteObject(hbr);
915 }
916
917 break;
918
919 case MIX_OPAQUE:
920 {
921 /* Curiously, glyphs are inverted (white-on-black) */
922 SetBkColor(m_displayBuffer, fgcolour);
923 SetTextColor(m_displayBuffer, bgcolour);
924 BitBlt(m_displayBuffer, x, y, cx, cy, hdcGlyph, srcx, srcy, SRCCOPY);
925 }
926
927 break;
928 }
929
930 RestoreDC(m_displayBuffer, dcsave);
931
932 SelectObject(hdcGlyph, hOld);
933 DeleteDC(hdcGlyph);
934
935 Display_RepaintArea(x, y, cx, cy);
936 }
937
938 void Display_DoGlyph(uint8 font, uint8 flags, int mixmode, int& x, int& y, int bgcolour, int fgcolour, const uint8 * ttext, int& idx)
939 {
940 FONTGLYPH * glyph;
941
942 glyph = cache_get_font(/*This*/NULL, font, ttext[idx]);
943
944 if(!(flags & TEXT2_IMPLICIT_X))
945 {
946 int xyoffset = ttext[++ idx];
947
948 if((xyoffset & 0x80))
949 {
950 if (flags & TEXT2_VERTICAL)
951 y += ttext[idx + 1] | (ttext[idx + 2] << 8);
952 else
953 x += ttext[idx + 1] | (ttext[idx + 2] << 8);
954
955 idx += 2;
956 }
957 else
958 {
959 if (flags & TEXT2_VERTICAL)
960 y += xyoffset;
961 else
962 x += xyoffset;
963 }
964 }
965
966 if(glyph)
967 {
968 Display_DrawGlyph
969 (
970 mixmode,
971 x + (short)glyph->offset,
972 y + (short)glyph->baseline,
973 glyph->width,
974 glyph->height,
975 glyph->pixmap,
976 0,
977 0,
978 bgcolour,
979 fgcolour
980 );
981
982 if(flags & TEXT2_IMPLICIT_X)
983 x += glyph->width;
984 }
985 }
986
987 void Display_DrawText
988 (
989 uint8 font,
990 uint8 flags,
991 uint8 opcode,
992 int mixmode,
993 int x,
994 int y,
995 int clipx,
996 int clipy,
997 int clipcx,
998 int clipcy,
999 int boxx,
1000 int boxy,
1001 int boxcx,
1002 int boxcy,
1003 BRUSH * brush,
1004 int bgcolour,
1005 int fgcolour,
1006 uint8 * text,
1007 uint8 length
1008 )
1009 {
1010 int i, j;
1011 DATABLOB *entry;
1012
1013 HBRUSH hbr = CreateSolidBrush(bgcolour);
1014 HGDIOBJ holdbrush = SelectObject(m_displayBuffer, hbr);
1015 HGDIOBJ holdpen = SelectObject(m_displayBuffer, GetStockObject(NULL_PEN));
1016
1017 if (boxcx > 1)
1018 Rectangle(m_displayBuffer, boxx, boxy, boxx + boxcx + 1, boxy + boxcy + 1);
1019 else if (mixmode == MIX_OPAQUE)
1020 Rectangle(m_displayBuffer, clipx, clipy, clipx + clipcx + 1, clipy + clipcy + 1);
1021
1022 SelectObject(m_displayBuffer, holdpen);
1023 SelectObject(m_displayBuffer, holdbrush);
1024
1025 DeleteObject(hbr);
1026
1027 if(boxcx > 1)
1028 Display_RepaintArea(boxx, boxy, boxcx, boxcy);
1029 else
1030 Display_RepaintArea(clipx, clipy, clipcx, clipcy);
1031
1032 /* Paint text, character by character */
1033 for (i = 0; i < length;)
1034 {
1035 switch (text[i])
1036 {
1037 case 0xff:
1038 /* At least two bytes needs to follow */
1039 if (i + 3 > length)
1040 {
1041 warning("Skipping short 0xff command:");
1042 for (j = 0; j < length; j++)
1043 fprintf(stderr, "%02x ", text[j]);
1044 fprintf(stderr, "\n");
1045 i = length = 0;
1046 break;
1047 }
1048 cache_put_text(NULL /* TODO */, text[i + 1], text, text[i + 2]);
1049 i += 3;
1050 length -= i;
1051 /* this will move pointer from start to first character after FF command */
1052 text = &(text[i]);
1053 i = 0;
1054 break;
1055
1056 case 0xfe:
1057 /* At least one byte needs to follow */
1058 if (i + 2 > length)
1059 {
1060 warning("Skipping short 0xfe command:");
1061 for (j = 0; j < length; j++)
1062 fprintf(stderr, "%02x ", text[j]);
1063 fprintf(stderr, "\n");
1064 i = length = 0;
1065 break;
1066 }
1067 entry = cache_get_text(/*This*/NULL, text[i + 1]);
1068 if (entry->data != NULL)
1069 {
1070 if ((((uint8 *) (entry->data))[1] == 0)
1071 && (!(flags & TEXT2_IMPLICIT_X)) && (i + 2 < length))
1072 {
1073 if (flags & TEXT2_VERTICAL)
1074 y += text[i + 2];
1075 else
1076 x += text[i + 2];
1077 }
1078 for (j = 0; j < entry->size; j++)
1079 Display_DoGlyph(font, flags, mixmode, x, y, bgcolour, fgcolour, ((uint8 *) (entry->data)), j);
1080 }
1081 if (i + 2 < length)
1082 i += 3;
1083 else
1084 i += 2;
1085 length -= i;
1086 /* this will move pointer from start to first character after FE command */
1087 text = &(text[i]);
1088 i = 0;
1089 break;
1090
1091 default:
1092 Display_DoGlyph(font, flags, mixmode, x, y, bgcolour, fgcolour, text, i);
1093 i++;
1094 break;
1095 }
1096 }
1097 }
1098
1099 void Display_SaveDesktop(uint32 offset, int x, int y, int cx, int cy)
1100 {
1101 GdiFlush();
1102
1103 uint8 * data =
1104 (uint8 *)m_displayBufferRaw +
1105 x * m_displayBufferByteDepth +
1106 (m_displayBufferHeight - y - cy) * m_displayBufferStride;
1107
1108 cache_put_desktop
1109 (
1110 /*This*/NULL,
1111 offset * m_displayBufferByteDepth,
1112 cx,
1113 cy,
1114 m_displayBufferStride,
1115 m_displayBufferByteDepth,
1116 data
1117 );
1118 }
1119
1120 void Display_RestoreDesktop(uint32 offset, int x, int y, int cx, int cy)
1121 {
1122 int fromstride = cx * m_displayBufferByteDepth;
1123
1124 const uint8 * src = cache_get_desktop(/*This*/NULL, offset, cx, cy, m_displayBufferByteDepth);
1125
1126 uint8 * dst =
1127 (uint8 *)m_displayBufferRaw +
1128 x * m_displayBufferByteDepth +
1129 (m_displayBufferHeight - y - cy) * m_displayBufferStride;
1130
1131 GdiFlush();
1132
1133 for(int i = 0; i < cy; ++ i)
1134 {
1135 memcpy(dst, src, fromstride);
1136 src += fromstride;
1137 dst += m_displayBufferStride;
1138 }
1139
1140 Display_RepaintArea(x, y, cx, cy);
1141 }
1142
1143
1144 void Display_BeginUpdate()
1145 {
1146 EnterCriticalSection(&m_displayBufferMutex);
1147 m_displayBufferSave = SaveDC(m_displayBuffer);
1148 }
1149
1150 void Display_EndUpdate()
1151 {
1152 RestoreDC(m_displayBuffer, m_displayBufferSave);
1153 LeaveCriticalSection(&m_displayBufferMutex);
1154 }
1155
1156 /*
1157 This is the input window. It receives the keyboard and mouse input from
1158 the user, and it's the only window that can receive the keyboard focus.
1159 It completely fills its parent, the console window, and it runs in its
1160 own thread for performance reasons and because of technical reasons
1161 involving keyboard hooks in full-screen mode
1162 */
1163 HWND m_inputWindow;
1164 HCURSOR m_inputCursor;
1165
1166 LRESULT InputWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
1167 {
1168 switch(uMsg)
1169 {
1170 case WM_DESTROY:
1171 PostQuitMessage(0);
1172 return 0;
1173
1174 /* Keyboard stuff */
1175 // TODO: we need a good way to post output cross-thread
1176 case WM_SYSKEYDOWN:
1177 case WM_KEYDOWN:
1178 //rdp_send_input(This, GetMessageTime(), RDP_INPUT_SCANCODE, RDP_KEYPRESS | (lparam & 0x1000000 ? KBD_FLAG_EXT : 0), LOBYTE(HIWORD(lparam)), 0);
1179 break;
1180
1181 case WM_SYSKEYUP:
1182 case WM_KEYUP:
1183 //rdp_send_input(This, GetMessageTime(), RDP_INPUT_SCANCODE, RDP_KEYRELEASE | (lparam & 0x1000000 ? KBD_FLAG_EXT : 0), LOBYTE(HIWORD(lparam)), 0);
1184 break;
1185
1186 /* Mouse stuff */
1187 // Cursor shape
1188 case WM_SETCURSOR:
1189 if(LOWORD(lParam) == HTCLIENT)
1190 {
1191 SetCursor(m_inputCursor);
1192 return TRUE;
1193 }
1194
1195 break;
1196
1197 // Movement
1198 case WM_MOUSEMOVE:
1199 //rdp_send_input(This, GetMessageTime(), RDP_INPUT_MOUSE, MOUSE_FLAG_MOVE, LOWORD(lparam), HIWORD(lparam));
1200 break;
1201
1202 // Buttons
1203 // TODO: X buttons
1204 case WM_LBUTTONDOWN:
1205 //rdp_send_input(This, GetMessageTime(), RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1 | MOUSE_FLAG_DOWN, LOWORD(lparam), HIWORD(lparam));
1206 break;
1207
1208 case WM_RBUTTONDOWN:
1209 //rdp_send_input(This, GetMessageTime(), RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON2 | MOUSE_FLAG_DOWN, LOWORD(lparam), HIWORD(lparam));
1210 break;
1211
1212 case WM_MBUTTONDOWN:
1213 //rdp_send_input(This, GetMessageTime(), RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON3 | MOUSE_FLAG_DOWN, LOWORD(lparam), HIWORD(lparam));
1214 break;
1215
1216 case WM_LBUTTONUP:
1217 //rdp_send_input(This, GetMessageTime(), RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON1, LOWORD(lparam), HIWORD(lparam));
1218 break;
1219
1220 case WM_RBUTTONUP:
1221 //rdp_send_input(This, GetMessageTime(), RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON2, LOWORD(lparam), HIWORD(lparam));
1222 break;
1223
1224 case WM_MBUTTONUP:
1225 //rdp_send_input(This, GetMessageTime(), RDP_INPUT_MOUSE, MOUSE_FLAG_BUTTON3, LOWORD(lparam), HIWORD(lparam));
1226 break;
1227
1228 // Wheel
1229 case WM_MOUSEWHEEL:
1230 //mstsc_mousewheel(This, (SHORT)HIWORD(wparam), lparam);
1231 break;
1232 }
1233
1234 return DefWindowProc(m_inputWindow, uMsg, wParam, lParam);
1235 }
1236
1237 public:
1238 };
1239
1240 #pragma warning(push)
1241 #pragma warning(disable: 4584)
1242
1243 /* The ActiveX control */
1244 class RdpClient SEALED_:
1245 /* COM basics */
1246 public IUnknown,
1247 public IDispatch,
1248
1249 /* ActiveX stuff */
1250 public IConnectionPointContainer,
1251 public IDataObject,
1252 public IObjectSafety,
1253 public IOleControl,
1254 public IOleInPlaceActiveObject,
1255 public IOleInPlaceObject,
1256 public IOleObject,
1257 public IOleWindow,
1258 public IPersist,
1259 public IPersistPropertyBag,
1260 public IPersistStorage,
1261 public IPersistStreamInit,
1262 public IProvideClassInfo,
1263 public IProvideClassInfo2,
1264 public IQuickActivate,
1265 public IViewObject,
1266 public IViewObject2,
1267
1268 // NOTE: the original has a vestigial, non-functional implementation of this, which we omit
1269 // ISpecifyPropertyPages
1270
1271 // Hidden interfaces, not available through QueryInterface
1272 public IConnectionPoint,
1273
1274 /* RDP client interface */
1275 public MSTSCLib::IMsRdpClient4,
1276 public MSTSCLib::IMsRdpClientNonScriptable2
1277
1278 // NOTE: implemented by inner classes due to requiring distinct IDispatch implementations
1279 // IMsRdpClientAdvancedSettings4
1280 // IMsRdpClientSecuredSettings
1281 {
1282 private:
1283 /* An endless amount of COM glue */
1284 // Reference counting
1285 LONG m_refCount;
1286
1287 #ifdef _DEBUG
1288 DWORD m_apartmentThreadId;
1289
1290 bool InsideApartment() const
1291 {
1292 return GetCurrentThreadId() == m_apartmentThreadId;
1293 }
1294 #endif
1295
1296 // Aggregation support
1297 IUnknown * m_punkOuter;
1298
1299 class RdpClientInner: public IUnknown
1300 {
1301 private:
1302 RdpClient * Outer()
1303 {
1304 return InnerToOuter(this);
1305 }
1306
1307 public:
1308 virtual STDMETHODIMP IUnknown::QueryInterface(REFIID riid, void ** ppvObject)
1309 {
1310 return Outer()->queryInterface(riid, ppvObject);
1311 }
1312
1313 virtual STDMETHODIMP_(ULONG) IUnknown::AddRef()
1314 {
1315 return Outer()->addRef();
1316 }
1317
1318 virtual STDMETHODIMP_(ULONG) IUnknown::Release()
1319 {
1320 return Outer()->release();
1321 }
1322
1323 }
1324 m_inner;
1325
1326 // Persistence support
1327 CLSID m_classId;
1328
1329 // Late binding support
1330 unsigned m_typeLibIndex;
1331 ITypeLib * m_typeLib;
1332 ITypeInfo * m_dispTypeInfo;
1333
1334 // Event sinks
1335 size_t m_EventSinksCount;
1336
1337 union
1338 {
1339 MSTSCLib::IMsTscAxEvents * m_EventSinksStatic[1];
1340 MSTSCLib::IMsTscAxEvents ** m_EventSinks;
1341 };
1342
1343 // OLE control glue
1344 HWND m_controlWindow;
1345 IOleClientSite * m_clientSite;
1346 IOleInPlaceSite * m_inPlaceSite;
1347 IOleAdviseHolder * m_adviseHolder;
1348 LONG m_freezeEvents;
1349 bool m_uiActive;
1350
1351 // UrlMon security
1352 DWORD m_SafetyOptions;
1353
1354 bool IsSafeForScripting() const
1355 {
1356 return m_SafetyOptions & INTERFACESAFE_FOR_UNTRUSTED_CALLER;
1357 }
1358
1359 /* Glue to interface to rdesktop-core */
1360 RdpClientUI * m_clientUI;
1361 RDPCLIENT m_protocolState;
1362 HANDLE m_protocolThread;
1363 HANDLE m_protocolThreadWaitingReconnection;
1364 bool m_reconnectAborted;
1365 bool m_actuallyConnected;
1366 bool m_loggedIn;
1367
1368 /* Properties */
1369 // Storage fields
1370 // NOTE: keep sorted by alignment (pointers and handles, integers, enumerations, booleans)
1371 BSTR m_Domain;
1372 BSTR m_UserName;
1373 BSTR m_DisconnectedText;
1374 BSTR m_ConnectingText;
1375 BSTR m_FullScreenTitle;
1376 BSTR m_StartProgram;
1377 BSTR m_WorkDir;
1378 BSTR m_ConnectedStatusText;
1379 BSTR m_ClearTextPassword; // FIXME! dangerous, shouldn't store in cleartext!
1380 BSTR m_RdpdrLocalPrintingDocName;
1381 BSTR m_RdpdrClipCleanTempDirString;
1382 BSTR m_RdpdrClipPasteInfoString;
1383 BSTR m_KeyboardLayoutString;
1384 LPSTR m_Server;
1385 LPSTR m_LoadBalanceInfo;
1386 // TODO: plugin DLLs
1387 HWND m_UIParentWindowHandle;
1388 long m_DesktopWidth;
1389 long m_DesktopHeight;
1390 long m_StartConnected;
1391 long m_ColorDepth;
1392 long m_KeyboardHookMode;
1393 long m_AudioRedirectionMode;
1394 long m_TransportType;
1395 long m_SasSequence;
1396 long m_RDPPort;
1397 long m_HotKeyFullScreen;
1398 long m_HotKeyAltEsc;
1399 long m_HotKeyAltShiftTab;
1400 long m_HotKeyAltSpace;
1401 long m_HotKeyAltTab;
1402 long m_HotKeyCtrlAltDel;
1403 long m_HotKeyCtrlEsc;
1404 long m_orderDrawThresold;
1405 long m_BitmapCacheSize;
1406 long m_BitmapVirtualCacheSize;
1407 long m_NumBitmapCaches;
1408 long m_brushSupportLevel;
1409 long m_minInputSendInterval;
1410 long m_InputEventsAtOnce;
1411 long m_maxEventCount;
1412 long m_keepAliveInternal;
1413 long m_shutdownTimeout;
1414 long m_overallConnectionTimeout;
1415 long m_singleConnectionTimeout;
1416 long m_MinutesToIdleTimeout;
1417 long m_BitmapVirtualCache16BppSize;
1418 long m_BitmapVirtualCache24BppSize;
1419 long m_PerformanceFlags;
1420 long m_MaxReconnectAttempts;
1421 unsigned int m_AuthenticationLevel;
1422
1423 MSTSCLib::ExtendedDisconnectReasonCode m_ExtendedDisconnectReason;
1424
1425 bool m_Connected;
1426 bool m_Compress;
1427 bool m_BitmapPersistence;
1428 bool m_allowBackgroundInput;
1429 bool m_ContainerHandledFullScreen;
1430 bool m_DisableRdpdr;
1431 bool m_SecuredSettingsEnabled;
1432 bool m_FullScreen;
1433 bool m_AcceleratorPassthrough;
1434 bool m_ShadowBitmap;
1435 bool m_EncryptionEnabled;
1436 bool m_DedicatedTerminal;
1437 bool m_DisableCtrlAltDel;
1438 bool m_EnableWindowsKey;
1439 bool m_DoubleClickDetect;
1440 bool m_MaximizeShell;
1441 bool m_ScaleBitmapCachesByBpp;
1442 bool m_CachePersistenceActive;
1443 bool m_ConnectToServerConsole;
1444 bool m_SmartSizing; // FIXME: this can be set while the control is connected
1445 bool m_DisplayConnectionBar;
1446 bool m_PinConnectionBar;
1447 bool m_GrabFocusOnConnect;
1448 bool m_RedirectDrives;
1449 bool m_RedirectPrinters;
1450 bool m_RedirectPorts;
1451 bool m_RedirectSmartCards;
1452 bool m_NotifyTSPublicKey;
1453 bool m_CanAutoReconnect;
1454 bool m_EnableAutoReconnect;
1455 bool m_ConnectionBarShowMinimizeButton;
1456 bool m_ConnectionBarShowRestoreButton;
1457
1458 // Generic getters/setters
1459 HRESULT GetProperty(BSTR& prop, BSTR * retVal) const
1460 {
1461 assert(InsideApartment());
1462
1463 if(retVal == NULL)
1464 return E_POINTER;
1465
1466 *retVal = SysAllocStringLen(prop, SysStringLen(prop));
1467
1468 if(*retVal == NULL)
1469 return E_OUTOFMEMORY;
1470
1471 return S_OK;
1472 }
1473
1474 HRESULT GetProperty(LPSTR& prop, BSTR * retVal) const
1475 {
1476 assert(InsideApartment());
1477
1478 if(retVal == NULL)
1479 return E_POINTER;
1480
1481 *retVal = LpszToBstr(prop);
1482
1483 if(*retVal == NULL)
1484 return E_OUTOFMEMORY;
1485
1486 return S_OK;
1487 }
1488
1489 HRESULT SetProperty(BSTR& prop, BSTR newValue)
1490 {
1491 assert(InsideApartment());
1492
1493 if(m_Connected)
1494 return E_FAIL;
1495
1496 SysFreeString(prop);
1497
1498 UINT len = SysStringLen(newValue);
1499
1500 if(len)
1501 {
1502 // no embedded NULs, please
1503 if(len != lstrlenW(newValue))
1504 return E_INVALIDARG;
1505
1506 prop = SysAllocStringLen(newValue, len);
1507
1508 if(prop == NULL)
1509 return E_OUTOFMEMORY;
1510 }
1511 else
1512 prop = NULL;
1513
1514 return S_OK;
1515 }
1516
1517 HRESULT ReplaceProperty(BSTR& prop, BSTR newValue)
1518 {
1519 assert(InsideApartment());
1520 assert((prop == NULL && newValue == NULL) || prop != newValue);
1521
1522 SysFreeString(prop);
1523 prop = newValue;
1524 return S_OK;
1525 }
1526
1527 HRESULT SetProperty(LPSTR& prop, BSTR newValue)
1528 {
1529 assert(InsideApartment());
1530
1531 if(m_Connected)
1532 return E_FAIL;
1533
1534 delete[] prop;
1535
1536 if(SysStringLen(newValue))
1537 {
1538 prop = BstrToLpsz(newValue);
1539
1540 if(prop == NULL)
1541 return E_OUTOFMEMORY;
1542 }
1543 else
1544 prop = NULL;
1545
1546 return S_OK;
1547 }
1548
1549 HRESULT ReplaceProperty(LPSTR& prop, LPSTR newValue)
1550 {
1551 assert(InsideApartment());
1552 assert((prop == NULL && newValue == NULL) || prop != newValue);
1553
1554 if(prop)
1555 delete[] prop;
1556
1557 prop = newValue;
1558 return S_OK;
1559 }
1560
1561 template<class Type> HRESULT SetProperty(bool& prop, const Type& newValue)
1562 {
1563 assert(InsideApartment());
1564
1565 if(m_Connected)
1566 return E_FAIL;
1567
1568 prop = !!newValue;
1569 return S_OK;
1570 }
1571
1572 template<class Type> HRESULT SetProperty(Type& prop, const Type& newValue)
1573 {
1574 assert(InsideApartment());
1575
1576 if(m_Connected)
1577 return E_FAIL;
1578
1579 prop = newValue;
1580 return S_OK;
1581 }
1582
1583 template<class Type> HRESULT GetProperty(const bool& prop, Type * retVal) const
1584 {
1585 assert(InsideApartment());
1586
1587 if(retVal == NULL)
1588 return E_POINTER;
1589
1590 *retVal = prop ? VARIANT_TRUE : VARIANT_FALSE;
1591 return S_OK;
1592 }
1593
1594 template<class Type> HRESULT GetProperty(const Type& prop, Type * retVal) const
1595 {
1596 assert(InsideApartment());
1597
1598 if(retVal == NULL)
1599 return E_POINTER;
1600
1601 *retVal = prop;
1602 return S_OK;
1603 }
1604
1605 /* Events */
1606 MSTSCLib::IMsTscAxEvents ** GetSinks() const
1607 {
1608 if(m_EventSinksCount > 1)
1609 return m_EventSinks;
1610 else
1611 return const_cast<MSTSCLib::IMsTscAxEvents **>(m_EventSinksStatic);
1612 }
1613
1614 // Event freezing
1615 void UnfreezeEvents()
1616 {
1617 // Just in case
1618 }
1619
1620 // Generic event riser & helpers
1621 void InvokeSinks(DISPID eventId, VARIANTARG rgvarg[], unsigned int cArgs, VARIANTARG * retval)
1622 {
1623 assert(InsideApartment());
1624
1625 DISPPARAMS params;
1626
1627 params.rgvarg = rgvarg;
1628 params.rgdispidNamedArgs = NULL;
1629 params.cArgs = cArgs;
1630 params.cNamedArgs = 0;
1631
1632 MSTSCLib::IMsTscAxEvents ** sinks = GetSinks();
1633
1634 for(size_t i = 0; i < m_EventSinksCount; ++ i)
1635 sinks[i]->Invoke(eventId, IID_NULL, 0, DISPATCH_METHOD, &params, retval, NULL, NULL);
1636 }
1637
1638 typedef void (RdpClient::* AsyncEventCallback)
1639 (
1640 DISPID eventId,
1641 VARIANTARG * rgvarg,
1642 unsigned int cArgs,
1643 VARIANTARG * retVal
1644 );
1645
1646 void CleanupEventArgumentsCallback
1647 (
1648 DISPID eventId,
1649 VARIANTARG * rgvarg,
1650 unsigned int cArgs,
1651 VARIANTARG * retVal
1652 )
1653 {
1654 assert((rgvarg == NULL) == (cArgs == 0));
1655
1656 for(unsigned int i = 0; i < cArgs; ++ i)
1657 VariantClear(&rgvarg[i]);
1658
1659 if(retVal)
1660 VariantClear(retVal);
1661 }
1662
1663 // synchronous call from inside the apartment that owns the object
1664 void FireEventInsideApartment
1665 (
1666 DISPID eventId,
1667 VARIANTARG * rgvarg = NULL,
1668 unsigned int cArgs = 0,
1669 VARIANTARG * retval = NULL,
1670 AsyncEventCallback callback = NULL
1671 )
1672 {
1673 assert(InsideApartment());
1674
1675 if(retval == NULL && callback)
1676 {
1677 VARIANTARG localRetval = { };
1678 retval = &localRetval;
1679 }
1680
1681 InvokeSinks(eventId, rgvarg, cArgs, retval);
1682
1683 if(callback)
1684 (this->*callback)(eventId, rgvarg, cArgs, retval);
1685 }
1686
1687 struct EventArguments
1688 {
1689 DISPID eventId;
1690 VARIANTARG * rgvarg;
1691 unsigned int cArgs;
1692 VARIANTARG * retval;
1693 AsyncEventCallback callback;
1694 };
1695
1696 struct RedirectArguments
1697 {
1698 uint32 flags;
1699 uint32 server_len;
1700 wchar_t * server;
1701 uint32 cookie_len;
1702 char * cookie;
1703 uint32 username_len;
1704 wchar_t * username;
1705 uint32 domain_len;
1706 wchar_t * domain;
1707 uint32 password_len;
1708 wchar_t * password;
1709 };
1710
1711 enum
1712 {
1713 RDPC_WM_ = WM_USER,
1714 RDPC_WM_SYNC_EVENT,
1715 RDPC_WM_ASYNC_EVENT,
1716 RDPC_WM_DISCONNECT,
1717 RDPC_WM_REQUEST_CLOSE,
1718 RDPC_WM_REDIRECT,
1719 };
1720
1721 static VOID CALLBACK DisconnectAPC(ULONG_PTR)
1722 {
1723 // no need to do anything. The interruption will be enough
1724 }
1725
1726 bool HandleEvent(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& result)
1727 {
1728 result = 0;
1729
1730 switch(uMsg)
1731 {
1732 /* Regular event to be dispatched to the container's sink */
1733 case RDPC_WM_SYNC_EVENT:
1734 assert(InSendMessage());
1735
1736 case RDPC_WM_ASYNC_EVENT:
1737 {
1738 const EventArguments * eventArgs = reinterpret_cast<EventArguments *>(lParam);
1739 assert(eventArgs);
1740
1741 FireEventInsideApartment
1742 (
1743 eventArgs->eventId,
1744 eventArgs->rgvarg,
1745 eventArgs->cArgs,
1746 eventArgs->retval,
1747 eventArgs->callback
1748 );
1749
1750 if(uMsg == RDPC_WM_ASYNC_EVENT)
1751 delete eventArgs;
1752 }
1753
1754 break;
1755
1756 /* The protocol thread is about to die: prepare for disconnection */
1757 case RDPC_WM_DISCONNECT:
1758 {
1759 assert(m_Connected);
1760 assert(InsideApartment());
1761 assert(InSendMessage());
1762
1763 // Unblock the protocol thread and wait for it to terminate
1764 ReplyMessage(0);
1765 JoinProtocolThread();
1766
1767 // Finish disconnecting
1768 PerformDisconnect(static_cast<long>(wParam));
1769 }
1770
1771 break;
1772
1773 case RDPC_WM_REDIRECT:
1774 {
1775 assert(InSendMessage());
1776 assert(lParam);
1777 assert(m_Connected);
1778 assert(m_protocolState.redirect);
1779
1780 RedirectArguments * redirectArgs = reinterpret_cast<RedirectArguments *>(lParam);
1781
1782 // BUGBUG: this is extremely messy and more prone to out-of-memory than it should be
1783 LPSTR lpszNewServer = NULL;
1784 LPSTR lpszNewCookie = NULL;
1785 BSTR strNewUsername = NULL;
1786 BSTR strNewDomain = NULL;
1787 BSTR strNewPassword = NULL;
1788 HRESULT hr = S_OK;
1789
1790 for(;;)
1791 {
1792 // Allocate the new properties
1793 hr = E_OUTOFMEMORY;
1794
1795 // FIXME: convert the hostname to Punycode, not the ANSI codepage
1796 lpszNewServer = AllocLpsz(redirectArgs->server, redirectArgs->server_len / sizeof(OLECHAR));
1797
1798 if(lpszNewServer == NULL && redirectArgs->server_len)
1799 break;
1800
1801 lpszNewCookie = AllocLpsz(redirectArgs->cookie, redirectArgs->cookie_len);
1802
1803 if(lpszNewCookie == NULL && redirectArgs->cookie_len)
1804 break;
1805
1806 strNewUsername = SysAllocStringLen(redirectArgs->username, redirectArgs->username_len / sizeof(OLECHAR));
1807
1808 if(strNewUsername == NULL && redirectArgs->username_len)
1809 break;
1810
1811 strNewDomain = SysAllocStringLen(redirectArgs->domain, redirectArgs->domain_len / sizeof(OLECHAR));
1812
1813 if(strNewDomain == NULL && redirectArgs->domain_len)
1814 break;
1815
1816 strNewPassword = SysAllocStringLen(redirectArgs->password, redirectArgs->password_len / sizeof(OLECHAR));
1817
1818 if(strNewPassword == NULL && redirectArgs->password_len)
1819 break;
1820
1821 hr = S_OK;
1822 break;
1823 }
1824
1825 // Success
1826 if(SUCCEEDED(hr))
1827 {
1828 // set the new properties
1829 ReplaceProperty(m_Server, lpszNewServer);
1830 ReplaceProperty(m_LoadBalanceInfo, lpszNewCookie);
1831 ReplaceProperty(m_UserName, strNewUsername);
1832 ReplaceProperty(m_Domain, strNewDomain);
1833 ReplaceProperty(m_ClearTextPassword, strNewPassword);
1834 }
1835 // Failure
1836 else
1837 {
1838 // free the buffers
1839 FreeLpsz(lpszNewServer);
1840 FreeLpsz(lpszNewCookie);
1841 SysFreeString(strNewUsername);
1842 SysFreeString(strNewDomain);
1843 SysFreeString(strNewPassword);
1844
1845 // signal the error
1846 m_protocolState.disconnect_reason = 262;
1847 m_protocolState.redirect = False;
1848 result = -1;
1849 }
1850 }
1851
1852 break;
1853
1854 // BUGBUG: this could potentially disconnect an unrelated connection established later...
1855 case RDPC_WM_REQUEST_CLOSE:
1856 {
1857 assert(!InSendMessage());
1858
1859 if(m_Connected)
1860 {
1861 // Ask confirmation to the container in case we are logged in
1862 if(m_loggedIn && !FireConfirmClose())
1863 break;
1864
1865 // For reentrancy (OnConfirmClose could deviously call Disconnect)
1866 if(m_protocolThread == NULL)
1867 break;
1868
1869 // Terminate the protocol thread. It will fire the Disconnected event on exit
1870 TerminateProtocolThread();
1871 }
1872 }
1873
1874 break;
1875
1876 default:
1877 return false;
1878 }
1879
1880 // If the calling thread is blocked, unblock it ASAP
1881 if(InSendMessage())
1882 ReplyMessage(result);
1883
1884 return true;
1885 }
1886
1887 // synchronous call from outside the apartment
1888 void FireEventOutsideApartment
1889 (
1890 DISPID eventId,
1891 VARIANTARG * rgvarg = NULL,
1892 unsigned int cArgs = 0,
1893 VARIANTARG * retval = NULL,
1894 AsyncEventCallback callback = NULL
1895 )
1896 {
1897 assert(!InsideApartment());
1898 EventArguments syncEvent = { eventId, rgvarg, cArgs, retval, callback };
1899 SendMessage(m_controlWindow, RDPC_WM_SYNC_EVENT, 0, reinterpret_cast<LPARAM>(&syncEvent));
1900 }
1901
1902 // asynchronous call from outside the apartment
1903 HRESULT FireEventOutsideApartmentAsync
1904 (
1905 DISPID eventId,
1906 VARIANTARG * rgvarg = NULL,
1907 unsigned int cArgs = 0,
1908 VARIANTARG * retval = NULL,
1909 AsyncEventCallback callback = NULL
1910 )
1911 {
1912 assert(!InsideApartment());
1913
1914 EventArguments * asyncEvent = new EventArguments();
1915
1916 if(asyncEvent == NULL)
1917 return E_OUTOFMEMORY;
1918
1919 asyncEvent->eventId = eventId;
1920 asyncEvent->rgvarg = rgvarg;
1921 asyncEvent->cArgs = cArgs;
1922 asyncEvent->retval = NULL;
1923
1924 if(!PostMessage(m_controlWindow, RDPC_WM_ASYNC_EVENT, 0, reinterpret_cast<LPARAM>(asyncEvent)))
1925 {
1926 delete asyncEvent;
1927 return HRESULT_FROM_WIN32(GetLastError());
1928 }
1929
1930 return S_OK;
1931 }
1932
1933 // Specific events
1934 void FireConnecting()
1935 {
1936 // Source: protocol
1937 FireEventOutsideApartment(1);
1938 }
1939
1940 void FireConnected()
1941 {
1942 // Source: protocol
1943 FireEventOutsideApartment(2);
1944 }
1945
1946 void FireLoginComplete()
1947 {
1948 // Source: protocol
1949 FireEventOutsideApartment(3);
1950 }
1951
1952 void FireDisconnected(long reason)
1953 {
1954 // Source: protocol. Special handling
1955 SendMessage(m_controlWindow, RDPC_WM_DISCONNECT, reason, 0);
1956 }
1957
1958 void FireEnterFullScreenMode()
1959 {
1960 // Source: UI window
1961 FireEventInsideApartment(5);
1962 }
1963
1964 void FireLeaveFullScreenMode()
1965 {
1966 // Source: UI window
1967 FireEventInsideApartment(6);
1968 }
1969
1970 HRESULT FireChannelReceivedData(char (& chanName)[CHANNEL_NAME_LEN + 1], void * chanData, unsigned int chanDataSize)
1971 {
1972 // BUGBUG: what to do when we run out of memory?
1973
1974 OLECHAR wchanName[ARRAYSIZE(chanName)];
1975 std::copy(chanName + 0, chanName + ARRAYSIZE(chanName), wchanName);
1976
1977 BSTR bstrChanName = SysAllocString(wchanName);
1978
1979 if(bstrChanName == NULL)
1980 return E_OUTOFMEMORY;
1981
1982 BSTR bstrChanData = SysAllocStringByteLen(NULL, chanDataSize);
1983
1984 if(bstrChanData == NULL)
1985 {
1986 SysFreeString(bstrChanName);
1987 return E_OUTOFMEMORY;
1988 }
1989
1990 CopyMemory(bstrChanData, chanData, chanDataSize);
1991
1992 VARIANTARG args[2] = { };
1993
1994 args[1].vt = VT_BSTR;
1995 args[1].bstrVal = bstrChanName;
1996
1997 args[0].vt = VT_BSTR;
1998 args[0].bstrVal = bstrChanData;
1999
2000 // Source: protocol
2001 HRESULT hr = FireEventOutsideApartmentAsync(7, args, ARRAYSIZE(args), NULL, &RdpClient::CleanupEventArgumentsCallback);
2002
2003 if(FAILED(hr))
2004 CleanupEventArgumentsCallback(7, args, ARRAYSIZE(args), NULL);
2005
2006 return hr;
2007 }
2008
2009 void FireRequestGoFullScreen()
2010 {
2011 // Source: UI window
2012 FireEventInsideApartment(8);
2013 }
2014
2015 void FireRequestLeaveFullScreen()
2016 {
2017 // Source: UI window
2018 FireEventInsideApartment(9);
2019 }
2020
2021 void FireFatalError(long errorCode)
2022 {
2023 VARIANTARG arg = { };
2024
2025 arg.vt = VT_I4;
2026 arg.lVal = errorCode;
2027
2028 // Source: protocol
2029 FireEventOutsideApartment(10, &arg, 1);
2030 }
2031
2032 void FireFatalErrorFromApartment(long errorCode)
2033 {
2034 VARIANTARG arg = { };
2035
2036 arg.vt = VT_I4;
2037 arg.lVal = errorCode;
2038
2039 // Source: control
2040 FireEventInsideApartment(10, &arg, 1);
2041 }
2042
2043 void FireWarning(long warningCode)
2044 {
2045 VARIANTARG arg = { };
2046
2047 arg.vt = VT_I4;
2048 arg.lVal = warningCode;
2049
2050 // Source: protocol
2051 FireEventOutsideApartment(11, &arg, 1);
2052 }
2053
2054 void FireRemoteDesktopSizeChange(long width, long height)
2055 {
2056 VARIANTARG args[2] = { };
2057
2058 args[1].vt = VT_I4;
2059 args[1].lVal = width;
2060
2061 args[0].vt = VT_I4;
2062 args[0].lVal = height;
2063
2064 // Source: UI window
2065 FireEventInsideApartment(12, args, ARRAYSIZE(args));
2066 }
2067
2068 void FireIdleTimeoutNotification()
2069 {
2070 // Source: input thread
2071 FireEventOutsideApartment(13);
2072 }
2073
2074 void FireRequestContainerMinimize()
2075 {
2076 // Source: UI window
2077 FireEventInsideApartment(14);
2078 }
2079
2080 bool FireConfirmClose()
2081 {
2082 VARIANTARG retval = { };
2083 VARIANT_BOOL allowClose = VARIANT_TRUE;
2084
2085 retval.vt = VT_BYREF | VT_BOOL;
2086 retval.pboolVal = &allowClose;
2087
2088 // Source: control
2089 FireEventInsideApartment(15, NULL, 0, &retval);
2090
2091 return allowClose != VARIANT_FALSE;
2092 }
2093
2094 HRESULT FireReceivedTSPublicKey(void * publicKey, unsigned int publicKeyLength)
2095 {
2096 assert(m_Connected);
2097
2098 if(!m_NotifyTSPublicKey)
2099 return S_OK;
2100
2101 BSTR bstrPublicKey = SysAllocStringByteLen(NULL, publicKeyLength);
2102
2103 if(bstrPublicKey == NULL)
2104 return E_OUTOFMEMORY;
2105
2106 CopyMemory(bstrPublicKey, publicKey, publicKeyLength);
2107
2108 VARIANT_BOOL continueLogon = VARIANT_TRUE;
2109 VARIANTARG arg = { };
2110 VARIANTARG retval = { };
2111
2112 arg.vt = VT_BSTR;
2113 arg.bstrVal = bstrPublicKey;
2114
2115 retval.vt = VT_BYREF | VT_BOOL;
2116 retval.pboolVal = &continueLogon;
2117
2118 // Source: protocol
2119 FireEventOutsideApartment(16, &arg, 1, &retval);
2120
2121 return continueLogon ? S_OK : S_FALSE;
2122 }
2123
2124 LONG FireAutoReconnecting(long disconnectReason, long attemptCount)
2125 {
2126 LONG continueStatus = MSTSCLib::autoReconnectContinueAutomatic;
2127 VARIANTARG args[2] = { };
2128 VARIANTARG retval = { };
2129
2130 args[1].vt = VT_I4;
2131 args[1].lVal = disconnectReason;
2132
2133 args[0].vt = VT_I4;
2134 args[0].lVal = attemptCount;
2135
2136 retval.vt = VT_BYREF | VT_I4;
2137 retval.plVal = &continueStatus;
2138
2139 // Source: protocol
2140 FireEventOutsideApartment(17, args, ARRAYSIZE(args), &retval);
2141
2142 return continueStatus;
2143 }
2144
2145 void FireAuthenticationWarningDisplayed()
2146 {
2147 // Source: protocol
2148 FireEventOutsideApartment(18);
2149 }
2150
2151 void FireAuthenticationWarningDismissed()
2152 {
2153 // Source: protocol
2154 FireEventOutsideApartment(19);
2155 }
2156
2157 /* Actual IUnknown implementation */
2158 HRESULT queryInterface(REFIID riid, void ** ppvObject)
2159 {
2160 IUnknown * pvObject = NULL;
2161
2162 using namespace MSTSCLib;
2163
2164 if(riid == IID_IUnknown)
2165 pvObject = static_cast<IUnknown *>(&m_inner);
2166 else if(riid == IID_IConnectionPointContainer)
2167 pvObject = static_cast<IConnectionPointContainer *>(this);
2168 else if(riid == IID_IDataObject)
2169 pvObject = static_cast<IDataObject *>(this);
2170 else if(riid == IID_IObjectSafety)
2171 pvObject = static_cast<IObjectSafety *>(this);
2172 else if(riid == IID_IOleControl)
2173 pvObject = static_cast<IOleControl *>(this);
2174 else if(riid == IID_IOleInPlaceActiveObject)
2175 pvObject = static_cast<IOleInPlaceActiveObject *>(this);
2176 else if(riid == IID_IOleInPlaceObject)
2177 pvObject = static_cast<IOleInPlaceObject *>(this);
2178 else if(riid == IID_IOleObject)
2179 pvObject = static_cast<IOleObject *>(this);
2180 else if(riid == IID_IOleWindow)
2181 pvObject = static_cast<IOleWindow *>(this);
2182 else if(riid == IID_IPersist)
2183 pvObject = static_cast<IPersist *>(this);
2184 else if(riid == IID_IPersistPropertyBag)
2185 pvObject = static_cast<IPersistPropertyBag *>(this);
2186 else if(riid == IID_IPersistStorage)
2187 pvObject = static_cast<IPersistStorage *>(this);
2188 else if(riid == IID_IPersistStreamInit)
2189 pvObject = static_cast<IPersistStreamInit *>(this);
2190 else if(riid == IID_IQuickActivate)
2191 pvObject = static_cast<IQuickActivate *>(this);
2192 else if(riid == IID_IViewObject)
2193 pvObject = static_cast<IViewObject *>(this);
2194 else if(riid == IID_IViewObject2)
2195 pvObject = static_cast<IViewObject2 *>(this);
2196 else if(riid == IID_IMsTscAx || riid == MSTSCLib_Redist::IID_IMsTscAx)
2197 pvObject = static_cast<IMsTscAx *>(this);
2198 else if(riid == IID_IMsRdpClient)
2199 pvObject = static_cast<IMsRdpClient *>(this);
2200 else if(riid == IID_IMsRdpClient2)
2201 pvObject = static_cast<IMsRdpClient2 *>(this);
2202 else if(riid == IID_IMsRdpClient3)
2203 pvObject = static_cast<IMsRdpClient3 *>(this);
2204 else if(riid == IID_IMsRdpClient4)
2205 pvObject = static_cast<IMsRdpClient4 *>(this);
2206 else if(riid == IID_IMsTscNonScriptable)
2207 pvObject = static_cast<IMsTscNonScriptable *>(this);
2208 else if(riid == IID_IMsRdpClientNonScriptable)
2209 pvObject = static_cast<IMsRdpClientNonScriptable *>(this);
2210 else if(riid == IID_IMsRdpClientNonScriptable2)
2211 pvObject = static_cast<IMsRdpClientNonScriptable2 *>(this);
2212
2213 *ppvObject = pvObject;
2214
2215 if(pvObject)
2216 {
2217 pvObject->AddRef();
2218 return S_OK;
2219 }
2220
2221 return E_NOINTERFACE;
2222 }
2223
2224 ULONG addRef()
2225 {
2226 return InterlockedIncrement(&m_refCount);
2227 }
2228
2229 ULONG release()
2230 {
2231 LONG n = InterlockedDecrement(&m_refCount);
2232
2233 if(n == 0)
2234 delete this;
2235
2236 return n;
2237 }
2238
2239 /* Constructor */
2240 RdpClient(REFCLSID classId, unsigned libIndex, IUnknown * punkOuter):
2241 // COM/OLE internals
2242 m_refCount(0),
2243 m_punkOuter(punkOuter),
2244 m_classId(classId),
2245 m_typeLibIndex(libIndex),
2246 m_typeLib(),
2247 m_dispTypeInfo(),
2248 m_controlWindow(NULL),
2249 m_clientSite(),
2250 m_inPlaceSite(),
2251 m_adviseHolder(),
2252 m_freezeEvents(0),
2253 m_uiActive(false),
2254 m_SafetyOptions(),
2255
2256 #ifdef _DEBUG
2257 m_apartmentThreadId(GetCurrentThreadId()),
2258 #endif
2259
2260 // rdesktop-core interface
2261 m_protocolState(),
2262 m_protocolThread(),
2263
2264 // Properties
2265 m_Server(),
2266 m_Domain(),
2267 m_UserName(),
2268 m_DisconnectedText(),
2269 m_ConnectingText(),
2270 m_FullScreenTitle(),
2271 m_StartProgram(),
2272 m_WorkDir(),
2273 m_LoadBalanceInfo(),
2274 m_ConnectedStatusText(),
2275 m_ClearTextPassword(),
2276 m_RdpdrLocalPrintingDocName(),
2277 m_RdpdrClipCleanTempDirString(),
2278 m_RdpdrClipPasteInfoString(),
2279 m_UIParentWindowHandle(),
2280 m_DesktopWidth(),
2281 m_DesktopHeight(),
2282 m_StartConnected(),
2283 m_ColorDepth(16),
2284 m_KeyboardHookMode(2),
2285 m_AudioRedirectionMode(0),
2286 m_TransportType(1), // BUGBUG: ??? what's this ???
2287 m_SasSequence(0xAA03), // BUGBUG: ??? what's this ???
2288 m_RDPPort(3389),
2289 m_HotKeyFullScreen(VK_CANCEL),
2290 m_HotKeyAltEsc(VK_INSERT),
2291 m_HotKeyAltShiftTab(VK_NEXT),
2292 m_HotKeyAltSpace(VK_DELETE),
2293 m_HotKeyAltTab(VK_PRIOR),
2294 m_HotKeyCtrlAltDel(VK_END),
2295 m_HotKeyCtrlEsc(VK_HOME),
2296 m_orderDrawThresold(0),
2297 m_BitmapCacheSize(1500),
2298 m_BitmapVirtualCacheSize(10),
2299 m_brushSupportLevel(),
2300 m_minInputSendInterval(),
2301 m_InputEventsAtOnce(),
2302 m_maxEventCount(),
2303 m_keepAliveInternal(0),
2304 m_shutdownTimeout(10),
2305 m_overallConnectionTimeout(120),
2306 m_singleConnectionTimeout(30),
2307 m_MinutesToIdleTimeout(0),
2308 m_BitmapVirtualCache16BppSize(20),
2309 m_BitmapVirtualCache24BppSize(30),
2310 m_PerformanceFlags(),
2311 m_MaxReconnectAttempts(20),
2312 m_AuthenticationLevel(0),
2313 m_ExtendedDisconnectReason(MSTSCLib::exDiscReasonNoInfo),
2314 m_Connected(false),
2315 m_Compress(true),
2316 m_BitmapPersistence(true),
2317 m_allowBackgroundInput(false),
2318 m_ContainerHandledFullScreen(false),
2319 m_DisableRdpdr(false),
2320 m_SecuredSettingsEnabled(true),
2321 m_FullScreen(false),
2322 m_AcceleratorPassthrough(true),
2323 m_ShadowBitmap(true),
2324 m_EncryptionEnabled(true),
2325 m_DedicatedTerminal(false),
2326 m_DisableCtrlAltDel(true),
2327 m_EnableWindowsKey(true),
2328 m_DoubleClickDetect(false),
2329 m_MaximizeShell(true),
2330 m_ScaleBitmapCachesByBpp(false),
2331 m_CachePersistenceActive(false),
2332 m_ConnectToServerConsole(false),
2333 m_SmartSizing(false),
2334 m_DisplayConnectionBar(true),
2335 m_PinConnectionBar(true),
2336 m_GrabFocusOnConnect(true),
2337 m_RedirectDrives(false),
2338 m_RedirectPrinters(false),
2339 m_RedirectPorts(false),
2340 m_RedirectSmartCards(false),
2341 m_NotifyTSPublicKey(false),
2342 m_CanAutoReconnect(false),
2343 m_EnableAutoReconnect(true),
2344 m_ConnectionBarShowMinimizeButton(true),
2345 m_ConnectionBarShowRestoreButton(true)
2346 {
2347 if(m_punkOuter == NULL)
2348 m_punkOuter = &m_inner;
2349 }
2350
2351 /* Destructor */
2352 ~RdpClient()
2353 {
2354 assert(m_refCount == 0);
2355
2356 if(m_Connected)
2357 {
2358 // Terminate the protocol thread
2359 TerminateProtocolThread();
2360
2361 // Dispatch the RDPC_WM_DISCONNECT message sent by the dying thread
2362 MSG msg;
2363 PeekMessage(&msg, m_controlWindow, 0, 0, PM_NOREMOVE);
2364
2365 assert(!m_Connected);
2366 }
2367
2368 DestroyControlWindow();
2369
2370 if(m_typeLib)
2371 m_typeLib->Release();
2372
2373 if(m_dispTypeInfo)
2374 m_dispTypeInfo->Release();
2375
2376 MSTSCLib::IMsTscAxEvents ** sinks = GetSinks();
2377
2378 for(size_t i = 0; i < m_EventSinksCount; ++ i)
2379 sinks[i]->Release();
2380
2381 if(m_EventSinksCount > 1)
2382 delete[] m_EventSinks;
2383
2384 if(m_clientSite)
2385 m_clientSite->Release();
2386
2387 if(m_inPlaceSite)
2388 m_inPlaceSite->Release();
2389
2390 if(m_adviseHolder)
2391 m_adviseHolder->Release();
2392
2393 SysFreeString(m_Domain);
2394 SysFreeString(m_UserName);
2395 SysFreeString(m_DisconnectedText);
2396 SysFreeString(m_DisconnectedText);
2397 SysFreeString(m_FullScreenTitle);
2398 SysFreeString(m_StartProgram);
2399 SysFreeString(m_WorkDir);
2400 SysFreeString(m_ConnectedStatusText);
2401 SysFreeString(m_ClearTextPassword);
2402 SysFreeString(m_RdpdrLocalPrintingDocName);
2403 SysFreeString(m_RdpdrClipCleanTempDirString);
2404 SysFreeString(m_RdpdrClipPasteInfoString);
2405
2406 FreeLpsz(m_LoadBalanceInfo);
2407 FreeLpsz(m_Server);
2408
2409 unlockServer();
2410 }
2411
2412 /* Advanced settings wrapper */
2413 friend class AdvancedSettings;
2414
2415 class AdvancedSettings SEALED_: public MSTSCLib::IMsRdpClientAdvancedSettings4
2416 {
2417 private:
2418 RdpClient * Outer()
2419 {
2420 return InnerToOuter(this);
2421 }
2422
2423 const RdpClient * Outer() const
2424 {
2425 return InnerToOuter(this);
2426 }
2427
2428 /* IDispatch type information */
2429 ITypeInfo * m_dispTypeInfo;
2430
2431 HRESULT LoadDispTypeInfo()
2432 {
2433 if(m_dispTypeInfo)
2434 return S_OK;
2435
2436 HRESULT hr = Outer()->LoadTypeLibrary();
2437
2438 if(FAILED(hr))
2439 return hr;
2440
2441 assert(MSTSCLib::IID_IMsRdpClientAdvancedSettings4 == MSTSCLib_Redist::IID_IMsRdpClientAdvancedSettings4);
2442
2443 hr = Outer()->m_typeLib->GetTypeInfoOfGuid(MSTSCLib::IID_IMsRdpClientAdvancedSettings4, &m_dispTypeInfo);
2444
2445 if(FAILED(hr))
2446 return hr;
2447
2448 assert(m_dispTypeInfo);
2449 return S_OK;
2450 }
2451
2452 HRESULT AcquireDispTypeInfo(ITypeInfo ** ppTI)
2453 {
2454 HRESULT hr = LoadDispTypeInfo();
2455
2456 if(FAILED(hr))
2457 return hr;
2458
2459 m_dispTypeInfo->AddRef();
2460 *ppTI = m_dispTypeInfo;
2461 return S_OK;
2462 }
2463
2464 public:
2465 ~AdvancedSettings()
2466 {
2467 if(m_dispTypeInfo)
2468 m_dispTypeInfo->Release();
2469 }
2470
2471 /* IUnknown */
2472 virtual STDMETHODIMP IUnknown::QueryInterface(REFIID riid, void ** ppvObject)
2473 {
2474 using namespace MSTSCLib;
2475
2476 if
2477 (
2478 riid == IID_IUnknown ||
2479 riid == IID_IDispatch ||
2480 riid == IID_IMsTscAdvancedSettings ||
2481 riid == IID_IMsRdpClientAdvancedSettings ||
2482 riid == IID_IMsRdpClientAdvancedSettings2 ||
2483 riid == IID_IMsRdpClientAdvancedSettings3 ||
2484 riid == IID_IMsRdpClientAdvancedSettings4
2485 )
2486 {
2487 *ppvObject = this;
2488 Outer()->addRef();
2489 return S_OK;
2490 }
2491 else
2492 {
2493 *ppvObject = NULL;
2494 return E_NOINTERFACE;
2495 }
2496 }
2497
2498 virtual STDMETHODIMP_(ULONG) IUnknown::AddRef()
2499 {
2500 return Outer()->addRef();
2501 }
2502
2503 virtual STDMETHODIMP_(ULONG) IUnknown::Release()
2504 {
2505 return Outer()->release();
2506 }
2507
2508 /* IDispatch */
2509 virtual STDMETHODIMP IDispatch::GetTypeInfoCount(UINT * pctinfo)
2510 {
2511 *pctinfo = 1;
2512 return S_OK;
2513 }
2514
2515 virtual STDMETHODIMP IDispatch::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo ** ppTInfo)
2516 {
2517 if(iTInfo != 0)
2518 return DISP_E_BADINDEX;
2519
2520 return AcquireDispTypeInfo(ppTInfo);
2521 }
2522
2523 virtual STDMETHODIMP IDispatch::GetIDsOfNames(REFIID riid, LPOLESTR * rgszNames, UINT cNames, LCID lcid, DISPID * rgDispId)
2524 {
2525 HRESULT hr = LoadDispTypeInfo();
2526
2527 if(FAILED(hr))
2528 return hr;
2529
2530 return m_dispTypeInfo->GetIDsOfNames(rgszNames, cNames, rgDispId);
2531 }
2532
2533 virtual STDMETHODIMP IDispatch::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult, EXCEPINFO * pExcepInfo, UINT * puArgErr)
2534 {
2535 return m_dispTypeInfo->Invoke
2536 (
2537 static_cast<MSTSCLib::IMsRdpClientAdvancedSettings4 *>(this),
2538 dispIdMember,
2539 wFlags,
2540 pDispParams,
2541 pVarResult,
2542 pExcepInfo,
2543 puArgErr
2544 );
2545 }
2546
2547 /* IMsTscAdvancedSettings */
2548 virtual STDMETHODIMP IMsTscAdvancedSettings::put_Compress(long pcompress)
2549 {
2550 return Outer()->SetProperty(Outer()->m_Compress, pcompress);
2551 }
2552
2553 virtual STDMETHODIMP IMsTscAdvancedSettings::get_Compress(long * pcompress) const
2554 {
2555 return Outer()->GetProperty(Outer()->m_Compress, pcompress);
2556 }
2557
2558 virtual STDMETHODIMP IMsTscAdvancedSettings::put_BitmapPeristence(long pbitmapPeristence)
2559 {
2560 return Outer()->SetProperty(Outer()->m_BitmapPersistence, pbitmapPeristence);
2561 }
2562
2563 virtual STDMETHODIMP IMsTscAdvancedSettings::get_BitmapPeristence(long * pbitmapPeristence) const
2564 {
2565 return Outer()->GetProperty(Outer()->m_BitmapPersistence, pbitmapPeristence);
2566 }
2567
2568 virtual STDMETHODIMP IMsTscAdvancedSettings::put_allowBackgroundInput(long pallowBackgroundInput)
2569 {
2570 if(Outer()->IsSafeForScripting())
2571 return S_FALSE;
2572
2573 return Outer()->SetProperty(Outer()->m_allowBackgroundInput, pallowBackgroundInput);
2574 }
2575
2576 virtual STDMETHODIMP IMsTscAdvancedSettings::get_allowBackgroundInput(long * pallowBackgroundInput) const
2577 {
2578 return Outer()->GetProperty(Outer()->m_allowBackgroundInput, pallowBackgroundInput);
2579 }
2580
2581 virtual STDMETHODIMP IMsTscAdvancedSettings::put_KeyBoardLayoutStr(BSTR rhs)
2582 {
2583 return Outer()->SetProperty(Outer()->m_KeyboardLayoutString, rhs);
2584 }
2585
2586 virtual STDMETHODIMP IMsTscAdvancedSettings::put_PluginDlls(BSTR rhs)
2587 {
2588 // TODO: split rhs into an array
2589
2590 // Control marked safe for scripting: only allow filenames
2591 if(Outer()->IsSafeForScripting())
2592 {
2593 // TODO: validate entries
2594 // TODO: replace each entry with a full path based on the Virtual Channel DLL path
2595 }
2596
2597 return E_NOTIMPL; // TODO
2598 }
2599
2600 virtual STDMETHODIMP IMsTscAdvancedSettings::put_IconFile(BSTR rhs)
2601 {
2602 return E_NOTIMPL;
2603 }
2604
2605 virtual STDMETHODIMP IMsTscAdvancedSettings::put_IconIndex(long rhs)
2606 {
2607 return E_NOTIMPL;
2608 }
2609
2610 virtual STDMETHODIMP IMsTscAdvancedSettings::put_ContainerHandledFullScreen(long pContainerHandledFullScreen)
2611 {
2612 if(Outer()->IsSafeForScripting())
2613 return S_FALSE;
2614
2615 return Outer()->SetProperty(Outer()->m_ContainerHandledFullScreen, pContainerHandledFullScreen);
2616 }
2617
2618 virtual STDMETHODIMP IMsTscAdvancedSettings::get_ContainerHandledFullScreen(long * pContainerHandledFullScreen) const
2619 {
2620 return Outer()->GetProperty(Outer()->m_ContainerHandledFullScreen, pContainerHandledFullScreen);
2621 }
2622
2623 virtual STDMETHODIMP IMsTscAdvancedSettings::put_DisableRdpdr(long pDisableRdpdr)
2624 {
2625 return Outer()->SetProperty(Outer()->m_DisableRdpdr, pDisableRdpdr);
2626 }
2627
2628 virtual STDMETHODIMP IMsTscAdvancedSettings::get_DisableRdpdr(long * pDisableRdpdr) const
2629 {
2630 return Outer()->GetProperty(Outer()->m_DisableRdpdr, pDisableRdpdr);
2631 }
2632
2633 /* IMsRdpClientAdvancedSettings */
2634 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_SmoothScroll(long psmoothScroll)
2635 {
2636 return S_FALSE;
2637 }
2638
2639 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_SmoothScroll(long * psmoothScroll) const
2640 {
2641 return S_FALSE;
2642 }
2643
2644 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_AcceleratorPassthrough(long pacceleratorPassthrough)
2645 {
2646 return Outer()->SetProperty(Outer()->m_AcceleratorPassthrough, pacceleratorPassthrough);
2647 }
2648
2649 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_AcceleratorPassthrough(long * pacceleratorPassthrough) const
2650 {
2651 return Outer()->GetProperty(Outer()->m_AcceleratorPassthrough, pacceleratorPassthrough);
2652 }
2653
2654 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_ShadowBitmap(long pshadowBitmap)
2655 {
2656 return Outer()->SetProperty(Outer()->m_ShadowBitmap, pshadowBitmap);
2657 }
2658
2659 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_ShadowBitmap(long * pshadowBitmap) const
2660 {
2661 return Outer()->GetProperty(Outer()->m_ShadowBitmap, pshadowBitmap);
2662 }
2663
2664 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_TransportType(long ptransportType)
2665 {
2666 // Reserved
2667 return Outer()->SetProperty(Outer()->m_TransportType, ptransportType);
2668 }
2669
2670 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_TransportType(long * ptransportType) const
2671 {
2672 // Reserved
2673 return Outer()->GetProperty(Outer()->m_TransportType, ptransportType);
2674 }
2675
2676 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_SasSequence(long psasSequence)
2677 {
2678 // Reserved
2679 return Outer()->SetProperty(Outer()->m_SasSequence, psasSequence);
2680 }
2681
2682 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_SasSequence(long * psasSequence) const
2683 {
2684 // Reserved
2685 return Outer()->GetProperty(Outer()->m_SasSequence, psasSequence);
2686 }
2687
2688 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_EncryptionEnabled(long pencryptionEnabled)
2689 {
2690 return Outer()->SetProperty(Outer()->m_EncryptionEnabled, pencryptionEnabled);
2691 }
2692
2693 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_EncryptionEnabled(long * pencryptionEnabled) const
2694 {
2695 return Outer()->GetProperty(Outer()->m_EncryptionEnabled, pencryptionEnabled);
2696 }
2697
2698 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_DedicatedTerminal(long pdedicatedTerminal)
2699 {
2700 return Outer()->SetProperty(Outer()->m_DedicatedTerminal, pdedicatedTerminal);
2701 }
2702
2703 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_DedicatedTerminal(long * pdedicatedTerminal) const
2704 {
2705 return Outer()->GetProperty(Outer()->m_DedicatedTerminal, pdedicatedTerminal);
2706 }
2707
2708 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_RDPPort(long prdpPort)
2709 {
2710 if(prdpPort == 0 || prdpPort > 65535)
2711 return E_INVALIDARG;
2712
2713 return Outer()->SetProperty(Outer()->m_RDPPort, prdpPort);
2714 }
2715
2716 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_RDPPort(long * prdpPort) const
2717 {
2718 return Outer()->GetProperty(Outer()->m_RDPPort, prdpPort);
2719 }
2720
2721 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_EnableMouse(long penableMouse)
2722 {
2723 return S_FALSE; // TBD? implement?
2724 }
2725
2726 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_EnableMouse(long * penableMouse) const
2727 {
2728 return S_FALSE; // TBD? implement?
2729 }
2730
2731 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_DisableCtrlAltDel(long pdisableCtrlAltDel)
2732 {
2733 return Outer()->SetProperty(Outer()->m_DisableCtrlAltDel, pdisableCtrlAltDel);
2734 }
2735
2736 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_DisableCtrlAltDel(long * pdisableCtrlAltDel) const
2737 {
2738 return Outer()->GetProperty(Outer()->m_DisableCtrlAltDel, pdisableCtrlAltDel);
2739 }
2740
2741 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_EnableWindowsKey(long penableWindowsKey)
2742 {
2743 return Outer()->SetProperty(Outer()->m_EnableWindowsKey, penableWindowsKey);
2744 }
2745
2746 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_EnableWindowsKey(long * penableWindowsKey) const
2747 {
2748 return Outer()->GetProperty(Outer()->m_EnableWindowsKey, penableWindowsKey);
2749 }
2750
2751 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_DoubleClickDetect(long pdoubleClickDetect)
2752 {
2753 return Outer()->SetProperty(Outer()->m_DoubleClickDetect, pdoubleClickDetect);
2754 }
2755
2756 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_DoubleClickDetect(long * pdoubleClickDetect) const
2757 {
2758 return Outer()->GetProperty(Outer()->m_DoubleClickDetect, pdoubleClickDetect);
2759 }
2760
2761 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_MaximizeShell(long pmaximizeShell)
2762 {
2763 return Outer()->SetProperty(Outer()->m_MaximizeShell, pmaximizeShell);
2764 }
2765
2766 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_MaximizeShell(long * pmaximizeShell) const
2767 {
2768 return Outer()->GetProperty(Outer()->m_MaximizeShell, pmaximizeShell);
2769 }
2770
2771 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_HotKeyFullScreen(long photKeyFullScreen)
2772 {
2773 return Outer()->SetProperty(Outer()->m_HotKeyFullScreen, photKeyFullScreen);
2774 }
2775
2776 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_HotKeyFullScreen(long * photKeyFullScreen) const
2777 {
2778 return Outer()->GetProperty(Outer()->m_HotKeyFullScreen, photKeyFullScreen);
2779 }
2780
2781 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_HotKeyCtrlEsc(long photKeyCtrlEsc)
2782 {
2783 return Outer()->SetProperty(Outer()->m_HotKeyCtrlEsc, photKeyCtrlEsc);
2784 }
2785
2786 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_HotKeyCtrlEsc(long * photKeyCtrlEsc) const
2787 {
2788 return Outer()->GetProperty(Outer()->m_HotKeyCtrlEsc, photKeyCtrlEsc);
2789 }
2790
2791 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_HotKeyAltEsc(long photKeyAltEsc)
2792 {
2793 return Outer()->SetProperty(Outer()->m_HotKeyAltEsc, photKeyAltEsc);
2794 }
2795
2796 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_HotKeyAltEsc(long * photKeyAltEsc) const
2797 {
2798 return Outer()->GetProperty(Outer()->m_HotKeyAltEsc, photKeyAltEsc);
2799 }
2800
2801 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_HotKeyAltTab(long photKeyAltTab)
2802 {
2803 return Outer()->SetProperty(Outer()->m_HotKeyAltTab, photKeyAltTab);
2804 }
2805
2806 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_HotKeyAltTab(long * photKeyAltTab) const
2807 {
2808 return Outer()->GetProperty(Outer()->m_HotKeyAltTab, photKeyAltTab);
2809 }
2810
2811 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_HotKeyAltShiftTab(long photKeyAltShiftTab)
2812 {
2813 return Outer()->SetProperty(Outer()->m_HotKeyAltShiftTab, photKeyAltShiftTab);
2814 }
2815
2816 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_HotKeyAltShiftTab(long * photKeyAltShiftTab) const
2817 {
2818 return Outer()->GetProperty(Outer()->m_HotKeyAltShiftTab, photKeyAltShiftTab);
2819 }
2820
2821 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_HotKeyAltSpace(long photKeyAltSpace)
2822 {
2823 return Outer()->SetProperty(Outer()->m_HotKeyAltSpace, photKeyAltSpace);
2824 }
2825
2826 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_HotKeyAltSpace(long * photKeyAltSpace) const
2827 {
2828 return Outer()->GetProperty(Outer()->m_HotKeyAltSpace, photKeyAltSpace);
2829 }
2830
2831 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_HotKeyCtrlAltDel(long photKeyCtrlAltDel)
2832 {
2833 return Outer()->SetProperty(Outer()->m_HotKeyCtrlAltDel, photKeyCtrlAltDel);
2834 }
2835
2836 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_HotKeyCtrlAltDel(long * photKeyCtrlAltDel) const
2837 {
2838 return Outer()->GetProperty(Outer()->m_HotKeyCtrlAltDel, photKeyCtrlAltDel);
2839 }
2840
2841 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_orderDrawThreshold(long porderDrawThreshold)
2842 {
2843 return S_FALSE;
2844 }
2845
2846 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_orderDrawThreshold(long * porderDrawThreshold) const
2847 {
2848 return S_FALSE;
2849 }
2850
2851 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_BitmapCacheSize(long pbitmapCacheSize)
2852 {
2853 // NOTE: the upper bound of "32" for a field with a default value of 1500 seems to be a bug
2854 if(pbitmapCacheSize < 0 || pbitmapCacheSize > 32)
2855 return E_INVALIDARG;
2856
2857 return Outer()->SetProperty(Outer()->m_BitmapCacheSize, pbitmapCacheSize);
2858 }
2859
2860 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_BitmapCacheSize(long * pbitmapCacheSize) const
2861 {
2862 return Outer()->GetProperty(Outer()->m_BitmapCacheSize, pbitmapCacheSize);
2863 }
2864
2865 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_BitmapVirtualCacheSize(long pbitmapVirtualCacheSize)
2866 {
2867 if(pbitmapVirtualCacheSize < 0 || pbitmapVirtualCacheSize > 32)
2868 return E_INVALIDARG;
2869
2870 return Outer()->SetProperty(Outer()->m_BitmapVirtualCacheSize, pbitmapVirtualCacheSize);
2871 }
2872
2873 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_BitmapVirtualCacheSize(long * pbitmapVirtualCacheSize) const
2874 {
2875 return Outer()->GetProperty(Outer()->m_BitmapVirtualCacheSize, pbitmapVirtualCacheSize);
2876 }
2877
2878 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_ScaleBitmapCachesByBPP(long pbScale)
2879 {
2880 return S_FALSE;
2881 }
2882
2883 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_ScaleBitmapCachesByBPP(long * pbScale) const
2884 {
2885 return S_FALSE;
2886 }
2887
2888 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_NumBitmapCaches(long pnumBitmapCaches)
2889 {
2890 return Outer()->SetProperty(Outer()->m_NumBitmapCaches, pnumBitmapCaches);
2891 }
2892
2893 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_NumBitmapCaches(long * pnumBitmapCaches) const
2894 {
2895 return Outer()->GetProperty(Outer()->m_NumBitmapCaches, pnumBitmapCaches);
2896 }
2897
2898 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_CachePersistenceActive(long pcachePersistenceActive)
2899 {
2900 return Outer()->SetProperty(Outer()->m_CachePersistenceActive, pcachePersistenceActive);
2901 }
2902
2903 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_CachePersistenceActive(long * pcachePersistenceActive) const
2904 {
2905 return Outer()->GetProperty(Outer()->m_CachePersistenceActive, pcachePersistenceActive);
2906 }
2907
2908 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_PersistCacheDirectory(BSTR rhs)
2909 {
2910 return S_FALSE;
2911 }
2912
2913 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_brushSupportLevel(long pbrushSupportLevel)
2914 {
2915 return Outer()->SetProperty(Outer()->m_brushSupportLevel, pbrushSupportLevel);
2916 }
2917
2918 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_brushSupportLevel(long * pbrushSupportLevel) const
2919 {
2920 return Outer()->GetProperty(Outer()->m_brushSupportLevel, pbrushSupportLevel);
2921 }
2922
2923 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_minInputSendInterval(long pminInputSendInterval)
2924 {
2925 // TODO
2926 return S_FALSE;
2927 }
2928
2929 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_minInputSendInterval(long * pminInputSendInterval) const
2930 {
2931 // TODO
2932 return S_FALSE;
2933 }
2934
2935 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_InputEventsAtOnce(long pinputEventsAtOnce)
2936 {
2937 // TODO
2938 return S_FALSE;
2939 }
2940
2941 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_InputEventsAtOnce(long * pinputEventsAtOnce) const
2942 {
2943 // TODO
2944 return S_FALSE;
2945 }
2946
2947 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_maxEventCount(long pmaxEventCount)
2948 {
2949 // TODO
2950 return S_FALSE;
2951 }
2952
2953 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_maxEventCount(long * pmaxEventCount) const
2954 {
2955 // TODO
2956 return S_FALSE;
2957 }
2958
2959 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_keepAliveInterval(long pkeepAliveInterval)
2960 {
2961 if(pkeepAliveInterval && pkeepAliveInterval < 10)
2962 return E_INVALIDARG;
2963
2964 return Outer()->SetProperty(Outer()->m_keepAliveInternal, pkeepAliveInterval);
2965 }
2966
2967 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_keepAliveInterval(long * pkeepAliveInterval) const
2968 {
2969 return Outer()->GetProperty(Outer()->m_keepAliveInternal, pkeepAliveInterval);
2970 }
2971
2972 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_shutdownTimeout(long pshutdownTimeout)
2973 {
2974 if(pshutdownTimeout >= 600)
2975 return E_INVALIDARG;
2976
2977 return Outer()->SetProperty(Outer()->m_shutdownTimeout, pshutdownTimeout);
2978 }
2979
2980 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_shutdownTimeout(long * pshutdownTimeout) const
2981 {
2982 return Outer()->GetProperty(Outer()->m_shutdownTimeout, pshutdownTimeout);
2983 }
2984
2985 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_overallConnectionTimeout(long poverallConnectionTimeout)
2986 {
2987 if(poverallConnectionTimeout < 0 || poverallConnectionTimeout >= 600)
2988 return E_INVALIDARG;
2989
2990 return Outer()->SetProperty(Outer()->m_overallConnectionTimeout, poverallConnectionTimeout);
2991 }
2992
2993 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_overallConnectionTimeout(long * poverallConnectionTimeout) const
2994 {
2995 return Outer()->GetProperty(Outer()->m_overallConnectionTimeout, poverallConnectionTimeout);
2996 }
2997
2998 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_singleConnectionTimeout(long psingleConnectionTimeout)
2999 {
3000 if(psingleConnectionTimeout >= 600)
3001 return E_INVALIDARG;
3002
3003 return Outer()->SetProperty(Outer()->m_singleConnectionTimeout, psingleConnectionTimeout);
3004 }
3005
3006 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_singleConnectionTimeout(long * psingleConnectionTimeout) const
3007 {
3008 return Outer()->GetProperty(Outer()->m_singleConnectionTimeout, psingleConnectionTimeout);
3009 }
3010
3011 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_KeyboardType(long pkeyboardType)
3012 {
3013 return E_NOTIMPL;
3014 }
3015
3016 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_KeyboardType(long * pkeyboardType) const
3017 {
3018 return E_NOTIMPL;
3019 }
3020
3021 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_KeyboardSubType(long pkeyboardSubType)
3022 {
3023 return E_NOTIMPL;
3024 }
3025
3026 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_KeyboardSubType(long * pkeyboardSubType) const
3027 {
3028 return E_NOTIMPL;
3029 }
3030
3031 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_KeyboardFunctionKey(long pkeyboardFunctionKey)
3032 {
3033 return E_NOTIMPL;
3034 }
3035
3036 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_KeyboardFunctionKey(long * pkeyboardFunctionKey) const
3037 {
3038 return E_NOTIMPL;
3039 }
3040
3041 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_WinceFixedPalette(long pwinceFixedPalette)
3042 {
3043 return E_NOTIMPL;
3044 }
3045
3046 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_WinceFixedPalette(long * pwinceFixedPalette) const
3047 {
3048 return E_NOTIMPL;
3049 }
3050
3051 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_ConnectToServerConsole(VARIANT_BOOL pConnectToConsole)
3052 {
3053 return Outer()->SetProperty(Outer()->m_ConnectToServerConsole, pConnectToConsole);
3054 }
3055
3056 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_ConnectToServerConsole(VARIANT_BOOL * pConnectToConsole) const
3057 {
3058 return Outer()->GetProperty(Outer()->m_ConnectToServerConsole, pConnectToConsole);
3059 }
3060
3061 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_BitmapPersistence(long pbitmapPersistence)
3062 {
3063 return put_BitmapPeristence(pbitmapPersistence);
3064 }
3065
3066 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_BitmapPersistence(long * pbitmapPersistence) const
3067 {
3068 return get_BitmapPeristence(pbitmapPersistence);
3069 }
3070
3071 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_MinutesToIdleTimeout(long pminutesToIdleTimeout)
3072 {
3073 if(pminutesToIdleTimeout > 240)
3074 return E_INVALIDARG;
3075
3076 return Outer()->SetProperty(Outer()->m_MinutesToIdleTimeout, pminutesToIdleTimeout);
3077 }
3078
3079 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_MinutesToIdleTimeout(long * pminutesToIdleTimeout) const
3080 {
3081 return Outer()->GetProperty(Outer()->m_MinutesToIdleTimeout, pminutesToIdleTimeout);
3082 }
3083
3084 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_SmartSizing(VARIANT_BOOL pfSmartSizing)
3085 {
3086 return Outer()->SetProperty(Outer()->m_SmartSizing, pfSmartSizing);
3087 }
3088
3089 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_SmartSizing(VARIANT_BOOL * pfSmartSizing) const
3090 {
3091 return Outer()->GetProperty(Outer()->m_SmartSizing, pfSmartSizing);
3092 }
3093
3094 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_RdpdrLocalPrintingDocName(BSTR pLocalPrintingDocName)
3095 {
3096 return Outer()->SetProperty(Outer()->m_RdpdrLocalPrintingDocName, pLocalPrintingDocName);
3097 }
3098
3099 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_RdpdrLocalPrintingDocName(BSTR * pLocalPrintingDocName) const
3100 {
3101 return Outer()->GetProperty(Outer()->m_RdpdrLocalPrintingDocName, pLocalPrintingDocName);
3102 }
3103
3104 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_RdpdrClipCleanTempDirString(BSTR clipCleanTempDirString)
3105 {
3106 return Outer()->SetProperty(Outer()->m_RdpdrClipCleanTempDirString, clipCleanTempDirString);
3107 }
3108
3109 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_RdpdrClipCleanTempDirString(BSTR * clipCleanTempDirString) const
3110 {
3111 return Outer()->GetProperty(Outer()->m_RdpdrClipCleanTempDirString, clipCleanTempDirString);
3112 }
3113
3114 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_RdpdrClipPasteInfoString(BSTR clipPasteInfoString)
3115 {
3116 return Outer()->SetProperty(Outer()->m_RdpdrClipPasteInfoString, clipPasteInfoString);
3117 }
3118
3119 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_RdpdrClipPasteInfoString(BSTR * clipPasteInfoString) const
3120 {
3121 return Outer()->GetProperty(Outer()->m_RdpdrClipPasteInfoString, clipPasteInfoString);
3122 }
3123
3124 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_ClearTextPassword(BSTR rhs)
3125 {
3126 return Outer()->put_ClearTextPassword(rhs);
3127 }
3128
3129 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_DisplayConnectionBar(VARIANT_BOOL pDisplayConnectionBar)
3130 {
3131 if(!pDisplayConnectionBar && Outer()->IsSafeForScripting())
3132 return E_FAIL;
3133
3134 return Outer()->SetProperty(Outer()->m_DisplayConnectionBar, pDisplayConnectionBar);
3135 }
3136
3137 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_DisplayConnectionBar(VARIANT_BOOL * pDisplayConnectionBar) const
3138 {
3139 return Outer()->GetProperty(Outer()->m_DisplayConnectionBar, pDisplayConnectionBar);
3140 }
3141
3142 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_PinConnectionBar(VARIANT_BOOL pPinConnectionBar)
3143 {
3144 if(Outer()->IsSafeForScripting())
3145 return E_NOTIMPL;
3146
3147 return Outer()->SetProperty(Outer()->m_PinConnectionBar, pPinConnectionBar);
3148 }
3149
3150 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_PinConnectionBar(VARIANT_BOOL * pPinConnectionBar) const
3151 {
3152 return Outer()->GetProperty(Outer()->m_PinConnectionBar, pPinConnectionBar);
3153 }
3154
3155 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_GrabFocusOnConnect(VARIANT_BOOL pfGrabFocusOnConnect)
3156 {
3157 return Outer()->SetProperty(Outer()->m_GrabFocusOnConnect, pfGrabFocusOnConnect);
3158 }
3159
3160 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_GrabFocusOnConnect(VARIANT_BOOL * pfGrabFocusOnConnect) const
3161 {
3162 return Outer()->GetProperty(Outer()->m_GrabFocusOnConnect, pfGrabFocusOnConnect);
3163 }
3164
3165 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_LoadBalanceInfo(BSTR pLBInfo)
3166 {
3167 return Outer()->SetProperty(Outer()->m_LoadBalanceInfo, pLBInfo);
3168 }
3169
3170 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_LoadBalanceInfo(BSTR * pLBInfo) const
3171 {
3172 return Outer()->GetProperty(Outer()->m_LoadBalanceInfo, pLBInfo);
3173 }
3174
3175 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_RedirectDrives(VARIANT_BOOL pRedirectDrives)
3176 {
3177 return Outer()->SetProperty(Outer()->m_RedirectDrives, pRedirectDrives);
3178 }
3179
3180 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_RedirectDrives(VARIANT_BOOL * pRedirectDrives) const
3181 {
3182 return Outer()->GetProperty(Outer()->m_RedirectDrives, pRedirectDrives);
3183 }
3184
3185 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_RedirectPrinters(VARIANT_BOOL pRedirectPrinters)
3186 {
3187 return Outer()->SetProperty(Outer()->m_RedirectPrinters, pRedirectPrinters);
3188 }
3189
3190 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_RedirectPrinters(VARIANT_BOOL * pRedirectPrinters) const
3191 {
3192 return Outer()->GetProperty(Outer()->m_RedirectPrinters, pRedirectPrinters);
3193 }
3194
3195 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_RedirectPorts(VARIANT_BOOL pRedirectPorts)
3196 {
3197 return Outer()->SetProperty(Outer()->m_RedirectPorts, pRedirectPorts);
3198 }
3199
3200 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_RedirectPorts(VARIANT_BOOL * pRedirectPorts) const
3201 {
3202 return Outer()->GetProperty(Outer()->m_RedirectPorts, pRedirectPorts);
3203 }
3204
3205 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_RedirectSmartCards(VARIANT_BOOL pRedirectSmartCards)
3206 {
3207 return Outer()->SetProperty(Outer()->m_RedirectSmartCards, pRedirectSmartCards);
3208 }
3209
3210 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_RedirectSmartCards(VARIANT_BOOL * pRedirectSmartCards) const
3211 {
3212 return Outer()->GetProperty(Outer()->m_RedirectSmartCards, pRedirectSmartCards);
3213 }
3214
3215 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_BitmapVirtualCache16BppSize(long pBitmapVirtualCache16BppSize)
3216 {
3217 if(pBitmapVirtualCache16BppSize < 0 || pBitmapVirtualCache16BppSize > 32)
3218 return E_INVALIDARG;
3219
3220 return Outer()->SetProperty(Outer()->m_BitmapVirtualCache16BppSize, pBitmapVirtualCache16BppSize);
3221 }
3222
3223 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_BitmapVirtualCache16BppSize(long * pBitmapVirtualCache16BppSize) const
3224 {
3225 return Outer()->GetProperty(Outer()->m_BitmapVirtualCache16BppSize, pBitmapVirtualCache16BppSize);
3226 }
3227
3228 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_BitmapVirtualCache24BppSize(long pBitmapVirtualCache24BppSize)
3229 {
3230 if(pBitmapVirtualCache24BppSize < 0 || pBitmapVirtualCache24BppSize > 32)
3231 return E_INVALIDARG;
3232
3233 return Outer()->SetProperty(Outer()->m_BitmapVirtualCache24BppSize, pBitmapVirtualCache24BppSize);
3234 }
3235
3236 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_BitmapVirtualCache24BppSize(long * pBitmapVirtualCache24BppSize) const
3237 {
3238 return Outer()->GetProperty(Outer()->m_BitmapVirtualCache24BppSize, pBitmapVirtualCache24BppSize);
3239 }
3240
3241 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_PerformanceFlags(long pDisableList)
3242 {
3243 return Outer()->SetProperty(Outer()->m_PerformanceFlags, pDisableList);
3244 }
3245
3246 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_PerformanceFlags(long * pDisableList) const
3247 {
3248 return Outer()->GetProperty(Outer()->m_PerformanceFlags, pDisableList);
3249 }
3250
3251 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_ConnectWithEndpoint(VARIANT * rhs)
3252 {
3253 // TBD? the Microsoft client implements this, but what does it mean?
3254 return E_NOTIMPL;
3255 }
3256
3257 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_NotifyTSPublicKey(VARIANT_BOOL pfNotify)
3258 {
3259 return Outer()->SetProperty(Outer()->m_NotifyTSPublicKey, pfNotify);
3260 }
3261
3262 virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_NotifyTSPublicKey(VARIANT_BOOL * pfNotify) const
3263 {
3264 return Outer()->GetProperty(Outer()->m_NotifyTSPublicKey, pfNotify);
3265 }
3266
3267 /* IMsRdpClientAdvancedSettings2 */
3268 virtual STDMETHODIMP IMsRdpClientAdvancedSettings2::get_CanAutoReconnect(VARIANT_BOOL * pfCanAutoReconnect) const
3269 {
3270 return E_NOTIMPL; // TODO
3271 }
3272
3273 virtual STDMETHODIMP IMsRdpClientAdvancedSettings2::put_EnableAutoReconnect(VARIANT_BOOL pfEnableAutoReconnect)
3274 {
3275 return Outer()->SetProperty(Outer()->m_EnableAutoReconnect, pfEnableAutoReconnect);
3276 }
3277
3278 virtual STDMETHODIMP IMsRdpClientAdvancedSettings2::get_EnableAutoReconnect(VARIANT_BOOL * pfEnableAutoReconnect) const
3279 {
3280 return Outer()->GetProperty(Outer()->m_EnableAutoReconnect, pfEnableAutoReconnect);
3281 }
3282
3283 virtual STDMETHODIMP IMsRdpClientAdvancedSettings2::put_MaxReconnectAttempts(long pMaxReconnectAttempts)
3284 {
3285 if(pMaxReconnectAttempts < 0 || pMaxReconnectAttempts > 200)
3286 return E_INVALIDARG;
3287
3288 return Outer()->SetProperty(Outer()->m_MaxReconnectAttempts, pMaxReconnectAttempts);
3289 }
3290
3291 virtual STDMETHODIMP IMsRdpClientAdvancedSettings2::get_MaxReconnectAttempts(long * pMaxReconnectAttempts) const
3292 {
3293 return Outer()->GetProperty(Outer()->m_MaxReconnectAttempts, pMaxReconnectAttempts);
3294 }
3295
3296 /* IMsRdpClientAdvancedSettings3 */
3297 virtual STDMETHODIMP IMsRdpClientAdvancedSettings3::put_ConnectionBarShowMinimizeButton(VARIANT_BOOL pfShowMinimize)
3298 {
3299 return Outer()->SetProperty(Outer()->m_ConnectionBarShowMinimizeButton, pfShowMinimize);
3300 }
3301
3302 virtual STDMETHODIMP IMsRdpClientAdvancedSettings3::get_ConnectionBarShowMinimizeButton(VARIANT_BOOL * pfShowMinimize) const
3303 {
3304 return Outer()->GetProperty(Outer()->m_ConnectionBarShowMinimizeButton, pfShowMinimize);
3305 }
3306
3307 virtual STDMETHODIMP IMsRdpClientAdvancedSettings3::put_ConnectionBarShowRestoreButton(VARIANT_BOOL pfShowRestore)
3308 {
3309 return Outer()->SetProperty(Outer()->m_ConnectionBarShowRestoreButton, pfShowRestore);
3310 }
3311
3312 virtual STDMETHODIMP IMsRdpClientAdvancedSettings3::get_ConnectionBarShowRestoreButton(VARIANT_BOOL * pfShowRestore) const
3313 {
3314 return Outer()->GetProperty(Outer()->m_ConnectionBarShowRestoreButton, pfShowRestore);
3315 }
3316
3317 /* IMsRdpClientAdvancedSettings4 */
3318 virtual STDMETHODIMP IMsRdpClientAdvancedSettings4::put_AuthenticationLevel(unsigned int puiAuthLevel)
3319 {
3320 // TODO: this isn't implemented in rdesktop yet...
3321 return Outer()->SetProperty(Outer()->m_AuthenticationLevel, puiAuthLevel);
3322 }
3323
3324 virtual STDMETHODIMP IMsRdpClientAdvancedSettings4::get_AuthenticationLevel(unsigned int * puiAuthLevel) const
3325 {
3326 return Outer()->GetProperty(Outer()->m_AuthenticationLevel, puiAuthLevel);
3327 }
3328 }
3329 m_advancedSettings;
3330
3331 template<class Interface> HRESULT GetAdvancedSettings(Interface ** ppAdvSettings)
3332 {
3333 addRef();
3334 *ppAdvSettings = &m_advancedSettings;
3335 return S_OK;
3336 }
3337
3338 /* Secured settings wrapper */
3339 friend class SecuredSettings;
3340
3341 class SecuredSettings SEALED_: public MSTSCLib::IMsRdpClientSecuredSettings
3342 {
3343 private:
3344 RdpClient * Outer()
3345 {
3346 return InnerToOuter(this);
3347 }
3348
3349 const RdpClient * Outer() const
3350 {
3351 return InnerToOuter(this);
3352 }
3353
3354 /* IDispatch type information */
3355 ITypeInfo * m_dispTypeInfo;
3356
3357 HRESULT LoadDispTypeInfo()
3358 {
3359 if(m_dispTypeInfo)
3360 return S_OK;
3361
3362 HRESULT hr = Outer()->LoadTypeLibrary();
3363
3364 if(FAILED(hr))
3365 return hr;
3366
3367 assert(MSTSCLib::IID_IMsRdpClientSecuredSettings == MSTSCLib_Redist::IID_IMsRdpClientSecuredSettings);
3368
3369 hr = Outer()->m_typeLib->GetTypeInfoOfGuid(MSTSCLib::IID_IMsRdpClientSecuredSettings, &m_dispTypeInfo);
3370
3371 if(FAILED(hr))
3372 return hr;
3373
3374 assert(m_dispTypeInfo);
3375 return S_OK;
3376 }
3377
3378 HRESULT AcquireDispTypeInfo(ITypeInfo ** ppTI)
3379 {
3380 HRESULT hr = LoadDispTypeInfo();
3381
3382 if(FAILED(hr))
3383 return hr;
3384
3385 m_dispTypeInfo->AddRef();
3386 *ppTI = m_dispTypeInfo;
3387 return S_OK;
3388 }
3389
3390 public:
3391 ~SecuredSettings()
3392 {
3393 if(m_dispTypeInfo)
3394 m_dispTypeInfo->Release();
3395 }
3396
3397 /* IUnknown */
3398 virtual STDMETHODIMP IUnknown::QueryInterface(REFIID riid, void ** ppvObject)
3399 {
3400 using namespace MSTSCLib;
3401
3402 if
3403 (
3404 riid == IID_IUnknown ||
3405 riid == IID_IDispatch ||
3406 riid == IID_IMsTscSecuredSettings ||
3407 riid == IID_IMsRdpClientSecuredSettings
3408 )
3409 {
3410 *ppvObject = this;
3411 Outer()->addRef();
3412 return S_OK;
3413 }
3414 else
3415 {
3416 *ppvObject = NULL;
3417 return E_NOINTERFACE;
3418 }
3419 }
3420
3421 virtual STDMETHODIMP_(ULONG) IUnknown::AddRef()
3422 {
3423 return Outer()->addRef();
3424 }
3425
3426 virtual STDMETHODIMP_(ULONG) IUnknown::Release()
3427 {
3428 return Outer()->release();
3429 }
3430
3431 /* IDispatch */
3432 virtual STDMETHODIMP IDispatch::GetTypeInfoCount(UINT * pctinfo)
3433 {
3434 *pctinfo = 1;
3435 return S_OK;
3436 }
3437
3438 virtual STDMETHODIMP IDispatch::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo ** ppTInfo)
3439 {
3440 if(iTInfo != 0)
3441 return DISP_E_BADINDEX;
3442
3443 return AcquireDispTypeInfo(ppTInfo);
3444 }
3445
3446 virtual STDMETHODIMP IDispatch::GetIDsOfNames(REFIID riid, LPOLESTR * rgszNames, UINT cNames, LCID lcid, DISPID * rgDispId)
3447 {
3448 HRESULT hr = LoadDispTypeInfo();
3449
3450 if(FAILED(hr))
3451 return hr;
3452
3453 return m_dispTypeInfo->GetIDsOfNames(rgszNames, cNames, rgDispId);
3454 }
3455
3456 virtual STDMETHODIMP IDispatch::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult, EXCEPINFO * pExcepInfo, UINT * puArgErr)
3457 {
3458 return m_dispTypeInfo->Invoke
3459 (
3460 static_cast<MSTSCLib::IMsRdpClientSecuredSettings *>(this),
3461 dispIdMember,
3462 wFlags,
3463 pDispParams,
3464 pVarResult,
3465 pExcepInfo,
3466 puArgErr
3467 );
3468 }
3469
3470 /* IMsTscSecuredSettings */
3471 virtual STDMETHODIMP IMsTscSecuredSettings::put_StartProgram(BSTR pStartProgram)
3472 {
3473 return Outer()->SetProperty(Outer()->m_StartProgram, pStartProgram);
3474 }
3475
3476 virtual STDMETHODIMP IMsTscSecuredSettings::get_StartProgram(BSTR * pStartProgram) const
3477 {
3478 return Outer()->GetProperty(Outer()->m_StartProgram, pStartProgram);
3479 }
3480
3481 virtual STDMETHODIMP IMsTscSecuredSettings::put_WorkDir(BSTR pWorkDir)
3482 {
3483 return Outer()->SetProperty(Outer()->m_WorkDir, pWorkDir);
3484 }
3485
3486 virtual STDMETHODIMP IMsTscSecuredSettings::get_WorkDir(BSTR * pWorkDir) const
3487 {
3488 return Outer()->GetProperty(Outer()->m_WorkDir, pWorkDir);
3489 }
3490
3491 virtual STDMETHODIMP IMsTscSecuredSettings::put_FullScreen(long pfFullScreen)
3492 {
3493 return Outer()->put_FullScreen(!!pfFullScreen);
3494 }
3495
3496 virtual STDMETHODIMP IMsTscSecuredSettings::get_FullScreen(long * pfFullScreen) const
3497 {
3498 return Outer()->GetProperty(Outer()->m_FullScreen, pfFullScreen);
3499 }
3500
3501 /* IMsRdpClientSecuredSettings */
3502 virtual STDMETHODIMP IMsRdpClientSecuredSettings::put_KeyboardHookMode(long pkeyboardHookMode)
3503 {
3504 if(pkeyboardHookMode < 0 || pkeyboardHookMode > 2)
3505 return E_INVALIDARG;
3506
3507 return Outer()->SetProperty(Outer()->m_KeyboardHookMode, pkeyboardHookMode);
3508 }
3509
3510 virtual STDMETHODIMP IMsRdpClientSecuredSettings::get_KeyboardHookMode(long * pkeyboardHookMode) const
3511 {
3512 return Outer()->GetProperty(Outer()->m_KeyboardHookMode, pkeyboardHookMode);
3513 }
3514
3515 virtual STDMETHODIMP IMsRdpClientSecuredSettings::put_AudioRedirectionMode(long pAudioRedirectionMode)
3516 {
3517 if(pAudioRedirectionMode < 0 || pAudioRedirectionMode > 2)
3518 return E_INVALIDARG;
3519
3520 return Outer()->SetProperty(Outer()->m_AudioRedirectionMode, pAudioRedirectionMode);
3521 }
3522
3523 virtual STDMETHODIMP IMsRdpClientSecuredSettings::get_AudioRedirectionMode(long * pAudioRedirectionMode) const
3524 {
3525 return Outer()->GetProperty(Outer()->m_AudioRedirectionMode, pAudioRedirectionMode);
3526 }
3527 }
3528 m_securedSettings;
3529
3530 template<class Interface> HRESULT GetSecuredSettings(Interface ** ppSecuredSettings)
3531 {
3532 if(!m_SecuredSettingsEnabled)
3533 return E_FAIL;
3534
3535 addRef();
3536 *ppSecuredSettings = &m_securedSettings;
3537 return S_OK;
3538 }
3539
3540 /* Type library loading */
3541 HRESULT LoadTypeLibrary()
3542 {
3543 if(m_typeLib)
3544 return S_OK;
3545
3546 // Get the DLL name of the ActiveX control
3547 WCHAR szPath[MAX_PATH + 1];
3548 DWORD cchPathLen = GetModuleFileNameW(GetCurrentModule(), szPath, ARRAYSIZE(szPath) - 1);
3549
3550 if(cchPathLen == 0)
3551 return HRESULT_FROM_WIN32(GetLastError());
3552
3553 if(cchPathLen > ((ARRAYSIZE(szPath) - 1) - 2))
3554 return E_FAIL;
3555
3556 // Append the resource id of the type library
3557 assert(m_typeLibIndex < 10);
3558
3559 szPath[cchPathLen + 0] = L'\\';
3560 szPath[cchPathLen + 1] = static_cast<WCHAR>(L'0' + m_typeLibIndex);
3561 szPath[cchPathLen + 2] = 0;
3562
3563 // Load the type library
3564 HRESULT hr = LoadTypeLibEx(szPath, REGKIND_NONE, &m_typeLib);
3565
3566 if(FAILED(hr))
3567 return hr;
3568
3569 assert(m_typeLib);
3570 return S_OK;
3571 }
3572
3573 /* IDispatch type information */
3574 HRESULT LoadDispTypeInfo()
3575 {
3576 if(m_dispTypeInfo)
3577 return S_OK;
3578
3579 HRESULT hr = LoadTypeLibrary();
3580
3581 if(FAILED(hr))
3582 return hr;
3583
3584 assert(MSTSCLib::IID_IMsRdpClient4 == MSTSCLib_Redist::IID_IMsRdpClient4);
3585
3586 hr = m_typeLib->GetTypeInfoOfGuid(MSTSCLib::IID_IMsRdpClient4, &m_dispTypeInfo);
3587
3588 if(FAILED(hr))
3589 return hr;
3590
3591 assert(m_dispTypeInfo);
3592 return S_OK;
3593 }
3594
3595 HRESULT AcquireDispTypeInfo(ITypeInfo ** ppTI)
3596 {
3597 HRESULT hr = LoadDispTypeInfo();
3598
3599 if(FAILED(hr))
3600 return hr;
3601
3602 m_dispTypeInfo->AddRef();
3603 *ppTI = m_dispTypeInfo;
3604 return S_OK;
3605 }
3606
3607 public:
3608 /* Helpers for our various embedded children */
3609 static RdpClient * InnerToOuter(RdpClientInner * innerThis)
3610 {
3611 return CONTAINING_RECORD(innerThis, RdpClient, m_inner);
3612 }
3613
3614 static RdpClient * InnerToOuter(AdvancedSettings * innerThis)
3615 {
3616 return CONTAINING_RECORD(innerThis, RdpClient, m_advancedSettings);
3617 }
3618
3619 static RdpClient * InnerToOuter(SecuredSettings * innerThis)
3620 {
3621 return CONTAINING_RECORD(innerThis, RdpClient, m_securedSettings);
3622 }
3623
3624 static RdpClient * InnerToOuter(RDPCLIENT * innerThis)
3625 {
3626 return CONTAINING_RECORD(innerThis, RdpClient, m_protocolState);
3627 }
3628
3629 static const RdpClient * InnerToOuter(const RdpClientInner * innerThis)
3630 {
3631 return CONTAINING_RECORD(innerThis, RdpClient, m_inner);
3632 }
3633
3634 static const RdpClient * InnerToOuter(const AdvancedSettings * innerThis)
3635 {
3636 return CONTAINING_RECORD(innerThis, RdpClient, m_advancedSettings);
3637 }
3638
3639 static const RdpClient * InnerToOuter(const SecuredSettings * innerThis)
3640 {
3641 return CONTAINING_RECORD(innerThis, RdpClient, m_securedSettings);
3642 }
3643
3644 static const RdpClient * InnerToOuter(const RDPCLIENT * innerThis)
3645 {
3646 return CONTAINING_RECORD(innerThis, RdpClient, m_protocolState);
3647 }
3648
3649 RdpClientUI * GetUI() const
3650 {
3651 assert(m_clientUI);
3652 return m_clientUI;
3653 }
3654
3655 /* Glue for rdesktop-core */
3656 public:
3657 static bool OnPublicKey(RDPCLIENT * This, unsigned char * key, unsigned int key_size)
3658 {
3659 return InnerToOuter(This)->OnPublicKey(key, key_size);
3660 }
3661
3662 static void OnLogon(RDPCLIENT * This)
3663 {
3664 return InnerToOuter(This)->OnLogon();
3665 }
3666
3667 static bool OnRedirect
3668 (
3669 RDPCLIENT * This,
3670 uint32 flags,
3671 uint32 server_len,
3672 wchar_t * server,
3673 uint32 cookie_len,
3674 char * cookie,
3675 uint32 username_len,
3676 wchar_t * username,
3677 uint32 domain_len,
3678 wchar_t * domain,
3679 uint32 password_len,
3680 wchar_t * password
3681 )
3682 {
3683 return InnerToOuter(This)->OnRedirect
3684 (
3685 flags,
3686 server_len,
3687 server,
3688 cookie_len,
3689 cookie,
3690 username_len,
3691 username,
3692 domain_len,
3693 domain,
3694 password_len,
3695 password
3696 );
3697 }
3698
3699 private:
3700 bool OnPublicKey(unsigned char * key, unsigned int key_size)
3701 {
3702 HRESULT hr = FireReceivedTSPublicKey(key, key_size);
3703
3704 if(FAILED(hr))
3705 {
3706 m_protocolState.disconnect_reason = 262;
3707 return false;
3708 }
3709
3710 return hr == S_OK;
3711 }
3712
3713 void OnLogon()
3714 {
3715 m_loggedIn = true;
3716 FireLoginComplete();
3717 }
3718
3719 bool OnRedirect
3720 (
3721 uint32 flags,
3722 uint32 server_len,
3723 wchar_t * server,
3724 uint32 cookie_len,
3725 char * cookie,
3726 uint32 username_len,
3727 wchar_t * username,
3728 uint32 domain_len,
3729 wchar_t * domain,
3730 uint32 password_len,
3731 wchar_t * password
3732 )
3733 {
3734 assert(m_Connected);
3735 assert(!InsideApartment());
3736 assert(IsWindow(m_controlWindow));
3737
3738 RedirectArguments redirectArgs =
3739 {
3740 flags,
3741 server_len,
3742 server,
3743 cookie_len,
3744 cookie,
3745 username_len,
3746 username,
3747 domain_len,
3748 domain,
3749 password_len,
3750 password
3751 };
3752
3753 return SendMessage(m_controlWindow, RDPC_WM_REDIRECT, 0, reinterpret_cast<LPARAM>(&redirectArgs)) == 0;
3754 }
3755
3756 private:
3757 static DWORD WINAPI ProtocolLoopThreadProc(LPVOID lpParam)
3758 {
3759 static_cast<RdpClient *>(lpParam)->ProtocolLoop();
3760 return 0;
3761 }
3762
3763 static VOID CALLBACK ConnectionTimerAPC(LPVOID, DWORD, DWORD)
3764 {
3765 }
3766
3767 // FIXME: various potential inconsistencies due to lack of detailed documentation of expected semantics
3768 void ProtocolLoop()
3769 {
3770 HANDLE waitingReconnection = NULL;
3771
3772 // Retrieve the local hostname to be passed to the server
3773 WCHAR hostname[MAX_COMPUTERNAME_LENGTH + 1];
3774 DWORD hostnameLen = ARRAYSIZE(hostname);
3775
3776 if(!GetComputerNameW(hostname, &hostnameLen))
3777 hostname[0] = 0;
3778
3779 // Set some connection flags
3780 uint32 flags = RDP_LOGON_NORMAL;
3781
3782 if(m_Compress)
3783 flags |= RDP_LOGON_COMPRESSION | RDP_LOGON_COMPRESSION2;
3784
3785 if(m_AudioRedirectionMode == 1)
3786 flags |= RDP_LOGON_LEAVE_AUDIO;
3787
3788 if(m_ClearTextPassword)
3789 flags |= RDP_LOGON_AUTO;
3790
3791 // Notify the container that the connection process is beginning now
3792 FireConnecting();
3793
3794 // Set the overall connection timer, if a timeout is set
3795 // BUGBUG: the timeout semantics are ambiguous and have been most probably misinterpreted
3796 HANDLE overallConnectionTimer = NULL;
3797 LARGE_INTEGER overallTimeout;
3798
3799 if(m_overallConnectionTimeout)
3800 {
3801 overallTimeout.QuadPart = - ((m_overallConnectionTimeout * 1000 * 1000 * 1000) / 100);
3802
3803 overallConnectionTimer = CreateWaitableTimer(NULL, FALSE, NULL);
3804
3805 if(overallConnectionTimer == NULL)
3806 goto l_Disconnect;
3807 }
3808
3809 if(overallConnectionTimer)
3810 SetWaitableTimer(overallConnectionTimer, &overallTimeout, 0, ConnectionTimerAPC, NULL, FALSE);
3811
3812 // Initial connection
3813 BOOL disconnected = rdp_connect
3814 (
3815 &m_protocolState,
3816 m_Server,
3817 flags,
3818 m_UserName,
3819 m_Domain,
3820 m_ClearTextPassword,
3821 m_StartProgram,
3822 m_WorkDir,
3823 hostname,
3824 m_LoadBalanceInfo
3825 );
3826
3827 if(overallConnectionTimer)
3828 CancelWaitableTimer(overallConnectionTimer);
3829
3830 if(disconnected)
3831 goto l_Disconnect;
3832
3833 // TODO: set the disconnect reason for every instance in which we abort the loop
3834 for(;;)
3835 {
3836 BOOL deactivated = False;
3837 uint32 extendedDisconnectReason = 0;
3838
3839 m_actuallyConnected = true;
3840
3841 // Notify the container of the successful connection
3842 FireConnected();
3843
3844 // Main protocol loop
3845 m_loggedIn = false;
3846 rdp_main_loop(&m_protocolState, &deactivated, &extendedDisconnectReason);
3847 rdp_disconnect(&m_protocolState);
3848
3849 m_actuallyConnected = false;
3850
3851 // Redirection
3852 // BUGBUG: redirection is very messy and probably this implementation is not "canonical"
3853 if(m_protocolState.redirect)
3854 {
3855 m_protocolState.redirect = False;
3856 rdp_reset_state(&m_protocolState);
3857
3858 // TODO: reset connection parameters
3859 // This has to be done in the main thread, so use SendMessage on the control window
3860
3861 flags |= RDP_LOGON_AUTO;
3862
3863 // retry
3864 continue;
3865 }
3866
3867 // Disconnection
3868 m_ExtendedDisconnectReason = static_cast<MSTSCLib::ExtendedDisconnectReasonCode>(extendedDisconnectReason);
3869
3870 // Clean disconnection
3871 if(deactivated)
3872 break;
3873
3874 BOOL success;
3875
3876 long autoReconnections = 0;
3877 long totalReconnections = 0;
3878
3879 // Reconnection
3880 // BUGBUG: reconnection semantics may not be entirely accurate
3881 do
3882 {
3883 ++ totalReconnections;
3884
3885 // ask the container whether we should reconnect
3886 long reconnectMode = FireAutoReconnecting(m_protocolState.disconnect_reason, totalReconnections);
3887
3888 // do not reconnect
3889 if(reconnectMode == MSTSCLib::autoReconnectContinueStop)
3890 goto l_Disconnect;
3891
3892 // the container will reconnect or abort manually
3893 if(reconnectMode == MSTSCLib::autoReconnectContinueManual)
3894 {
3895 assert(!m_reconnectAborted);
3896 assert(m_protocolThreadWaitingReconnection == NULL);
3897
3898 if(waitingReconnection == NULL)
3899 {
3900 waitingReconnection = CreateEvent(NULL, TRUE, FALSE, NULL);
3901
3902 if(waitingReconnection == NULL)
3903 // TODO: fatal error
3904 goto l_Disconnect;
3905 }
3906
3907 m_protocolThreadWaitingReconnection = waitingReconnection;
3908
3909 WaitForSingleObject(waitingReconnection, INFINITE);
3910
3911 m_protocolThreadWaitingReconnection = NULL;
3912
3913 if(m_reconnectAborted)
3914 {
3915 // FIXME? do we set the disconnection status here?
3916 goto l_Disconnect;
3917 }
3918 }
3919 // reconnect automatically
3920 else
3921 {
3922 // automatic reconnection is disabled
3923 if(m_EnableAutoReconnect)
3924 break;
3925
3926 // too many consecutive automatic reconnections
3927 if(autoReconnections == m_MaxReconnectAttempts)
3928 break;
3929
3930 ++ autoReconnections;
3931 }
3932
3933 if(overallConnectionTimer)
3934 SetWaitableTimer(overallConnectionTimer, &overallTimeout, 0, ConnectionTimerAPC, NULL, FALSE);
3935
3936 // Reconnection
3937 success = rdp_reconnect
3938 (
3939 &m_protocolState,
3940 m_Server,
3941 flags,
3942 m_UserName,
3943 m_Domain,
3944 m_ClearTextPassword,
3945 m_StartProgram,
3946 m_WorkDir,
3947 hostname,
3948 m_LoadBalanceInfo
3949 );
3950
3951 if(overallConnectionTimer)
3952 CancelWaitableTimer(overallConnectionTimer);
3953 }
3954 while(!success);
3955 }
3956
3957 l_Disconnect:
3958 // Disconnected
3959 FireDisconnected(m_protocolState.disconnect_reason);
3960
3961 if(overallConnectionTimer)
3962 CloseHandle(overallConnectionTimer);
3963 }
3964
3965 void JoinProtocolThread()
3966 {
3967 assert(m_protocolThread);
3968 WaitForSingleObject(m_protocolThread, INFINITE);
3969 CloseHandle(m_protocolThread);
3970 m_protocolThread = NULL;
3971 }
3972
3973 void TerminateProtocolThread()
3974 {
3975 assert(m_protocolThread);
3976
3977 // wake it up if it's waiting for a manual reconnection
3978 if(m_protocolThreadWaitingReconnection)
3979 {
3980 assert(!m_reconnectAborted);
3981 m_reconnectAborted = true;
3982 SetEvent(m_protocolThreadWaitingReconnection);
3983 }
3984 // otherwise, attempt to interrupt any current blocking operation
3985 else
3986 {
3987 // shutdown(m_protocolState.tcp.sock, SD_BOTH); // TBD: maybe in the future?
3988 QueueUserAPC(DisconnectAPC, m_protocolThread, 0);
3989 }
3990
3991 assert(m_protocolThreadWaitingReconnection == NULL);
3992 }
3993
3994 void PerformDisconnect(long reason)
3995 {
3996 assert(InsideApartment());
3997 assert(m_Connected);
3998
3999 // TODO: notify virtual channels
4000
4001 // TODO: do any other disconnection work here...
4002
4003 // Put the control in the disconnected state
4004 m_Connected = false;
4005 m_loggedIn = false;
4006
4007 // Notify the container
4008 VARIANTARG arg = { };
4009
4010 arg.vt = VT_I4;
4011 arg.lVal = reason;
4012
4013 FireEventInsideApartment(4, &arg, 1);
4014 }
4015
4016 public:
4017 /* Startup initialization */
4018 static BOOL Startup()
4019 {
4020 if(!RdpClientUI::Startup())
4021 return FALSE;
4022
4023 WNDCLASSEX wcex = { sizeof(wcex) };
4024
4025 wcex.style = CS_HREDRAW | CS_VREDRAW;
4026 wcex.lpfnWndProc = ControlWindowProc;
4027 wcex.hInstance = GetCurrentModule();
4028 wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
4029 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
4030 wcex.lpszClassName = TEXT("MissTosca_Control");
4031
4032 return RegisterClassEx(&wcex);;
4033 }
4034
4035 static void Shutdown()
4036 {
4037 UnregisterClass(TEXT("MissTosca_Control"), GetCurrentModule());
4038 }
4039
4040 /* Class factory */
4041 static HRESULT CreateInstance(REFCLSID rclsid, unsigned libIndex, IUnknown * punkOuter, REFIID riid, void ** ppObj)
4042 {
4043 RdpClient * obj = new RdpClient(rclsid, libIndex, punkOuter);
4044
4045 if(obj == NULL)
4046 return E_OUTOFMEMORY;
4047
4048 HRESULT hr = obj->m_inner.QueryInterface(riid, ppObj);
4049
4050 if(FAILED(hr))
4051 {
4052 delete obj;
4053 return hr;
4054 }
4055
4056 assert(obj->m_refCount == 1);
4057 assert(*ppObj != NULL);
4058
4059 return S_OK;
4060 }
4061
4062 private:
4063 /* Connection point enumerator */
4064 class CEnumConnectionPoints: public IEnumConnectionPoints
4065 {
4066 private:
4067 LONG m_refCount;
4068 IConnectionPoint * m_cp;
4069 bool m_done;
4070
4071 public:
4072 CEnumConnectionPoints(IConnectionPoint * cp): m_refCount(1), m_cp(cp), m_done(false)
4073 {
4074 assert(m_cp);
4075 m_cp->AddRef();
4076 }
4077
4078 CEnumConnectionPoints(const CEnumConnectionPoints& ecp): m_refCount(1), m_cp(ecp.m_cp), m_done(ecp.m_done)
4079 {
4080 assert(m_cp);
4081 m_cp->AddRef();
4082 }
4083
4084 ~CEnumConnectionPoints()
4085 {
4086 assert(m_cp);
4087 m_cp->Release();
4088 }
4089
4090 virtual STDMETHODIMP QueryInterface(REFIID riid, void ** ppvObject)
4091 {
4092 if(riid == IID_IUnknown || riid == IID_IEnumConnectionPoints)
4093 {
4094 *ppvObject = this;
4095 return S_OK;
4096 }
4097 else
4098 {
4099 *ppvObject = NULL;
4100 return E_NOINTERFACE;
4101 }
4102 }
4103
4104 virtual STDMETHODIMP_(ULONG) AddRef()
4105 {
4106 return InterlockedIncrement(&m_refCount);
4107 }
4108
4109 virtual STDMETHODIMP_(ULONG) Release()
4110 {
4111 LONG n = InterlockedDecrement(&m_refCount);
4112
4113 if(n == 0)
4114 delete this;
4115
4116 return n;
4117 }
4118
4119 virtual STDMETHODIMP Next(ULONG cConnections, LPCONNECTIONPOINT * ppCP, ULONG * pcFetched)
4120 {
4121 if(cConnections == 0 || m_done)
4122 return S_FALSE;
4123
4124 m_done = true;
4125 m_cp->AddRef();
4126 *ppCP = m_cp;
4127 *pcFetched = 1;
4128
4129 return S_OK;
4130 }
4131
4132 virtual STDMETHODIMP Skip(ULONG cConnections)
4133 {
4134 if(cConnections == 0)
4135 return S_OK;
4136
4137 if(cConnections == 1 && !m_done)
4138 {
4139 m_done = true;
4140 return S_OK;
4141 }
4142
4143 assert(cConnections > 1 || m_done);
4144
4145 return S_FALSE;
4146 }
4147
4148 virtual STDMETHODIMP Reset()
4149 {
4150 m_done = false;
4151 return S_OK;
4152 }
4153
4154 virtual STDMETHODIMP Clone(IEnumConnectionPoints ** ppEnum)
4155 {
4156 if(ppEnum == NULL)
4157 return E_POINTER;
4158
4159 *ppEnum = new CEnumConnectionPoints(*this);
4160
4161 if(*ppEnum == NULL)
4162 return E_OUTOFMEMORY;
4163
4164 return S_OK;
4165 }
4166 };
4167
4168 /* Pay no attention, ActiveX glue... */
4169 LRESULT ControlWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
4170 {
4171 switch(uMsg)
4172 {
4173 case WM_SIZE:
4174 {
4175 // TODO: resize UI
4176 }
4177
4178 return 0;
4179
4180 case WM_PAINT:
4181 {
4182 LPCWSTR text = NULL;
4183
4184 if(!m_Connected)
4185 text = m_DisconnectedText;
4186 else if(m_actuallyConnected)
4187 text = m_ConnectedStatusText;
4188 else
4189 text = m_ConnectingText;
4190
4191 RECT clientRect;
4192 GetClientRect(m_controlWindow, &clientRect);
4193
4194 PAINTSTRUCT ps;
4195 HDC hdc = BeginPaint(m_controlWindow, &ps);
4196
4197 SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
4198 SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
4199 SelectObject(hdc, GetStockObject(SYSTEM_FONT));
4200
4201 RECT textRect = clientRect;
4202
4203 DrawTextW
4204 (
4205 hdc,
4206 text,
4207 -1,
4208 &textRect,
4209 DT_CENTER | DT_EDITCONTROL | DT_END_ELLIPSIS | DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT
4210 );
4211
4212 if(textRect.right > clientRect.right)
4213 textRect.right = clientRect.right;
4214
4215 if(textRect.bottom > clientRect.bottom)
4216 textRect.bottom = clientRect.bottom;
4217
4218 textRect.left = (clientRect.right - textRect.right) / 2;
4219 textRect.right += textRect.left;
4220 textRect.top = (clientRect.bottom - textRect.bottom) / 2;
4221 textRect.bottom += textRect.top;
4222
4223 DrawTextW
4224 (
4225 hdc,
4226 text,
4227 -1,
4228 &textRect,
4229 DT_CENTER | DT_EDITCONTROL | DT_END_ELLIPSIS | DT_NOPREFIX | DT_WORDBREAK
4230 );
4231
4232 EndPaint(m_controlWindow, &ps);
4233 }
4234
4235 return 0;
4236
4237 default:
4238 {
4239 LRESULT result;
4240
4241 if(HandleEvent(uMsg, wParam, lParam, result))
4242 return result;
4243 }
4244
4245 break;
4246 }
4247
4248 return DefWindowProc(m_controlWindow, uMsg, wParam, lParam);
4249 }
4250
4251 static LRESULT CALLBACK ControlWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
4252 {
4253 if(uMsg == WM_CREATE)
4254 {
4255 SetWindowLongPtr
4256 (
4257 hwnd,
4258 GWLP_USERDATA,
4259 (LONG_PTR)reinterpret_cast<LPCREATESTRUCT>(lParam)->lpCreateParams
4260 );
4261 }
4262
4263 RdpClient * Self = reinterpret_cast<RdpClient *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
4264 assert(Self);
4265
4266 return Self->ControlWindowProc(uMsg, wParam, lParam);
4267 }
4268
4269 HRESULT CreateControlWindow(HWND hwndParent)
4270 {
4271 m_controlWindow = CreateWindow
4272 (
4273 TEXT("MissTosca_Control"),
4274 NULL,
4275 WS_CHILD | WS_CLIPCHILDREN,
4276 CW_USEDEFAULT,
4277 CW_USEDEFAULT,
4278 CW_USEDEFAULT,
4279 CW_USEDEFAULT,
4280 hwndParent,
4281 NULL,
4282 GetCurrentModule(),
4283 this
4284 );
4285
4286 if(m_controlWindow == NULL)
4287 return HRESULT_FROM_WIN32(GetLastError());
4288
4289 m_UIParentWindowHandle = m_controlWindow;
4290 return S_OK;
4291 }
4292
4293 HRESULT DestroyControlWindow()
4294 {
4295 if(m_controlWindow == NULL)
4296 return S_FALSE;
4297
4298 HWND controlWindow = NULL;
4299 std::swap(controlWindow, m_controlWindow);
4300 DestroyWindow(controlWindow);
4301 return S_OK;
4302 }
4303
4304 HRESULT Activate(LONG iVerb, IOleClientSite * pActiveSite, HWND hwndParent, LPCRECT lprcPosRect)
4305 {
4306 if(pActiveSite == NULL)
4307 pActiveSite = m_clientSite;
4308
4309 if(pActiveSite == NULL)
4310 return E_FAIL;
4311
4312 // TODO: store this until we are closed or deactivated
4313 IOleInPlaceSite * site;
4314
4315 HRESULT hr = pActiveSite->QueryInterface(&site);
4316
4317 if(FAILED(hr))
4318 return hr;
4319
4320 IOleInPlaceFrame * frame = NULL;
4321 IOleInPlaceUIWindow * uiWindow = NULL;
4322
4323 for(;;)
4324 {
4325 hr = site->CanInPlaceActivate();
4326
4327 if(hr == S_FALSE)
4328 hr = E_FAIL;
4329
4330 if(FAILED(hr))
4331 break;
4332
4333 site->OnInPlaceActivate();
4334
4335 if(hwndParent == NULL)
4336 {
4337 hr = site->GetWindow(&hwndParent);
4338
4339 if(FAILED(hr))
4340 break;
4341 }
4342
4343 RECT rcPos;
4344 RECT rcClip;
4345 OLEINPLACEFRAMEINFO frameInfo = { sizeof(frameInfo) };
4346
4347 site->GetWindowContext(&frame, &uiWindow, &rcPos, &rcClip, &frameInfo);
4348
4349 if(lprcPosRect == NULL)
4350 lprcPosRect = &rcPos;
4351
4352 if(m_controlWindow)
4353 ShowWindow(m_controlWindow, SW_SHOW);
4354 else
4355 {
4356 hr = CreateControlWindow(hwndParent);
4357
4358 if(FAILED(hr))
4359 break;
4360 }
4361
4362 SetObjectRects(lprcPosRect, &rcClip);
4363
4364 // UI activation
4365 if((iVerb == OLEIVERB_PRIMARY || iVerb == OLEIVERB_UIACTIVATE) && !m_uiActive)
4366 {
4367 m_uiActive = true;
4368
4369 hr = site->OnUIActivate();
4370
4371 if(FAILED(hr))
4372 break;
4373
4374 SetWindowPos
4375 (
4376 m_controlWindow,
4377 NULL,
4378 lprcPosRect->left,
4379 lprcPosRect->top,
4380 lprcPosRect->right - lprcPosRect->left,
4381 lprcPosRect->bottom - lprcPosRect->top,
4382 SWP_SHOWWINDOW
4383 );
4384
4385 if(frame)
4386 {
4387 frame->SetActiveObject(this, NULL);
4388 frame->SetBorderSpace(NULL);
4389 }
4390
4391 if(uiWindow)
4392 {
4393 uiWindow->SetActiveObject(this, NULL);
4394 uiWindow->SetBorderSpace(NULL);
4395 }
4396 }
4397
4398 break;
4399 }
4400
4401 if(uiWindow)
4402 uiWindow->Release();
4403
4404 if(frame)
4405 frame->Release();
4406
4407 site->Release();
4408
4409 if(SUCCEEDED(hr))
4410 pActiveSite->ShowObject();
4411
4412 return hr;
4413 }
4414
4415 public:
4416 /* IUnknown */
4417 /*
4418 NOTE: this is the delegating implementation, to support aggregation. The actual
4419 implementation is RdpClientInner, above
4420 */
4421 virtual STDMETHODIMP IUnknown::QueryInterface(REFIID riid, void ** ppvObject)
4422 {
4423 return m_punkOuter->QueryInterface(riid, ppvObject);
4424 }
4425
4426 virtual STDMETHODIMP_(ULONG) IUnknown::AddRef()
4427 {
4428 return m_punkOuter->AddRef();
4429 }
4430
4431 virtual STDMETHODIMP_(ULONG) IUnknown::Release()
4432 {
4433 return m_punkOuter->Release();
4434 }
4435
4436 /* IDispatch */
4437 virtual STDMETHODIMP IDispatch::GetTypeInfoCount(UINT * pctinfo)
4438 {
4439 *pctinfo = 1;
4440 return S_OK;
4441 }
4442
4443 virtual STDMETHODIMP IDispatch::GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo ** ppTInfo)
4444 {
4445 if(iTInfo != 0)
4446 return DISP_E_BADINDEX;
4447
4448 return AcquireDispTypeInfo(ppTInfo);
4449 }
4450
4451 virtual STDMETHODIMP IDispatch::GetIDsOfNames(REFIID riid, LPOLESTR * rgszNames, UINT cNames, LCID lcid, DISPID * rgDispId)
4452 {
4453 HRESULT hr = LoadDispTypeInfo();
4454
4455 if(FAILED(hr))
4456 return hr;
4457
4458 return m_dispTypeInfo->GetIDsOfNames(rgszNames, cNames, rgDispId);
4459 }
4460
4461 virtual STDMETHODIMP IDispatch::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult, EXCEPINFO * pExcepInfo, UINT * puArgErr)
4462 {
4463 HRESULT hr = LoadDispTypeInfo();
4464
4465 if(FAILED(hr))
4466 return hr;
4467
4468 return m_dispTypeInfo->Invoke
4469 (
4470 static_cast<MSTSCLib::IMsRdpClient4 *>(this),
4471 dispIdMember,
4472 wFlags,
4473 pDispParams,
4474 pVarResult,
4475 pExcepInfo,
4476 puArgErr
4477 );
4478 }
4479
4480 /* IConnectionPoint */
4481 virtual STDMETHODIMP GetConnectionInterface(IID * pIID)
4482 {
4483 if(pIID == NULL)
4484 return E_POINTER;
4485
4486 *pIID = MSTSCLib::DIID_IMsTscAxEvents;
4487 return S_OK;
4488 }
4489
4490 virtual STDMETHODIMP GetConnectionPointContainer(IConnectionPointContainer ** ppCPC)
4491 {
4492 if(ppCPC == NULL)
4493 return E_POINTER;
4494
4495 addRef();
4496 *ppCPC = this;
4497 return S_OK;
4498 }
4499
4500 virtual STDMETHODIMP Advise(IUnknown * pUnkSink, DWORD * pdwCookie)
4501 {
4502 MSTSCLib::IMsTscAxEvents * sink;
4503
4504 if(FAILED(pUnkSink->QueryInterface(&sink)))
4505 return CONNECT_E_CANNOTCONNECT;
4506
4507 MSTSCLib::IMsTscAxEvents ** sinks = GetSinks();
4508 DWORD cookie = 0;
4509
4510 if(m_EventSinksCount)
4511 {
4512 bool found = false;
4513
4514 for(size_t i = 0; i < m_EventSinksCount; ++ i)
4515 {
4516 found = (sinks[i] == NULL);
4517
4518 if(found)
4519 {
4520 cookie = static_cast<DWORD>(i);
4521 break;
4522 }
4523 }
4524
4525 if(!found)
4526 {
4527 MSTSCLib::IMsTscAxEvents ** newSinks = new MSTSCLib::IMsTscAxEvents *[m_EventSinksCount + 1];
4528
4529 if(newSinks == NULL)
4530 {
4531 sink->Release();
4532 return E_OUTOFMEMORY;
4533 }
4534
4535 std::copy(sinks, sinks + m_EventSinksCount, newSinks);
4536
4537 m_EventSinks = newSinks;
4538 sinks = newSinks;
4539
4540 cookie = static_cast<DWORD>(m_EventSinksCount);
4541 }
4542 }
4543
4544 sinks[cookie] = sink;
4545 *pdwCookie = cookie;
4546
4547 return S_OK;
4548 }
4549
4550 virtual STDMETHODIMP Unadvise(DWORD dwCookie)
4551 {
4552 MSTSCLib::IMsTscAxEvents ** sinks = GetSinks();
4553
4554 if(dwCookie >= m_EventSinksCount || sinks[dwCookie] == NULL)
4555 return CONNECT_E_NOCONNECTION;
4556
4557 sinks[dwCookie]->Release();
4558 sinks[dwCookie] = NULL;
4559
4560 // BUGBUG: the array currently grows forever. Trim it whenever possible
4561
4562 return S_OK;
4563 }
4564
4565 virtual STDMETHODIMP EnumConnections(IEnumConnections ** ppEnum)
4566 {
4567 // I see no real value in this
4568 return E_NOTIMPL;
4569 }
4570
4571 /* IConnectionPointContainer */
4572 virtual STDMETHODIMP IConnectionPointContainer::EnumConnectionPoints(IEnumConnectionPoints ** ppEnum)
4573 {
4574 *ppEnum = new CEnumConnectionPoints(this);
4575
4576 if(*ppEnum == NULL)
4577 return E_OUTOFMEMORY;
4578
4579 return S_OK;
4580 }
4581
4582 virtual STDMETHODIMP IConnectionPointContainer::FindConnectionPoint(REFIID riid, IConnectionPoint ** ppCP)
4583 {
4584 if(riid != MSTSCLib::DIID_IMsTscAxEvents)
4585 return CONNECT_E_NOCONNECTION;
4586
4587 addRef();
4588 *ppCP = this;
4589
4590 return S_OK;
4591 }
4592
4593 /* IDataObject */ // 0/9
4594 virtual STDMETHODIMP IDataObject::GetData(FORMATETC * pformatetcIn, STGMEDIUM * pmedium)
4595 {
4596 return E_NOTIMPL;
4597 }
4598
4599 virtual STDMETHODIMP IDataObject::GetDataHere(FORMATETC * pformatetc, STGMEDIUM * pmedium)
4600 {
4601 return E_NOTIMPL;
4602 }
4603
4604 virtual STDMETHODIMP IDataObject::QueryGetData(FORMATETC * pformatetc)
4605 {
4606 return E_NOTIMPL;
4607 }
4608
4609 virtual STDMETHODIMP IDataObject::GetCanonicalFormatEtc(FORMATETC * pformatectIn, FORMATETC * pformatetcOut)
4610 {
4611 return E_NOTIMPL;
4612 }
4613
4614 virtual STDMETHODIMP IDataObject::SetData(FORMATETC * pformatetc, STGMEDIUM * pmedium, BOOL fRelease)
4615 {
4616 return E_NOTIMPL;
4617 }
4618
4619 virtual STDMETHODIMP IDataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC ** ppenumFormatEtc)
4620 {
4621 return E_NOTIMPL;
4622 }
4623
4624 virtual STDMETHODIMP IDataObject::DAdvise(FORMATETC * pformatetc, DWORD advf, IAdviseSink * pAdvSink, DWORD * pdwConnection)
4625 {
4626 return E_NOTIMPL;
4627 }
4628
4629 virtual STDMETHODIMP IDataObject::DUnadvise(DWORD dwConnection)
4630 {
4631 return E_NOTIMPL;
4632 }
4633
4634 virtual STDMETHODIMP IDataObject::EnumDAdvise(IEnumSTATDATA ** ppenumAdvise)
4635 {
4636 return E_NOTIMPL;
4637 }
4638
4639 /* IObjectSafety */
4640 virtual STDMETHODIMP IObjectSafety::GetInterfaceSafetyOptions(REFIID riid, DWORD * pdwSupportedOptions, DWORD * pdwEnabledOptions)
4641 {
4642 if(pdwSupportedOptions == NULL || pdwEnabledOptions == NULL)
4643 return E_POINTER;
4644
4645 if(riid != IID_IDispatch)
4646 return E_NOINTERFACE;
4647
4648 *pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
4649 *pdwEnabledOptions = m_SafetyOptions;
4650 return S_OK;
4651 }
4652
4653 virtual STDMETHODIMP IObjectSafety::SetInterfaceSafetyOptions(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions)
4654 {
4655 if(riid != IID_IDispatch)
4656 return E_NOINTERFACE;
4657
4658 m_SafetyOptions = dwEnabledOptions & (dwOptionSetMask & INTERFACESAFE_FOR_UNTRUSTED_CALLER);
4659 return S_OK;
4660 }
4661
4662 /* IOleControl */ // 3/4
4663 virtual STDMETHODIMP IOleControl::GetControlInfo(CONTROLINFO * pCI)
4664 {
4665 return E_NOTIMPL;
4666 }
4667
4668 virtual STDMETHODIMP IOleControl::OnMnemonic(MSG * pMsg)
4669 {
4670 return E_NOTIMPL;
4671 }
4672
4673 virtual STDMETHODIMP IOleControl::OnAmbientPropertyChange(DISPID dispID)
4674 {
4675 return S_OK;
4676 }
4677
4678 virtual STDMETHODIMP IOleControl::FreezeEvents(BOOL bFreeze)
4679 {
4680 if(bFreeze)
4681 InterlockedIncrement(&m_freezeEvents);
4682 else if(InterlockedDecrement(&m_freezeEvents) == 0)
4683 UnfreezeEvents();
4684
4685 return S_OK;
4686 }
4687
4688 /* IOleInPlaceActiveObject */ // 3/5
4689 virtual STDMETHODIMP IOleInPlaceActiveObject::TranslateAccelerator(LPMSG lpmsg)
4690 {
4691 return E_NOTIMPL;
4692 }
4693
4694 virtual STDMETHODIMP IOleInPlaceActiveObject::OnFrameWindowActivate(BOOL fActivate)
4695 {
4696 // TODO
4697 return E_NOTIMPL;
4698 }
4699
4700 virtual STDMETHODIMP IOleInPlaceActiveObject::OnDocWindowActivate(BOOL fActivate)
4701 {
4702 // TODO
4703 return E_NOTIMPL;
4704 }
4705
4706 virtual STDMETHODIMP IOleInPlaceActiveObject::ResizeBorder(LPCRECT prcBorder, IOleInPlaceUIWindow * pUIWindow, BOOL fFrameWindow)
4707 {
4708 return S_OK;
4709 }
4710
4711 virtual STDMETHODIMP IOleInPlaceActiveObject::EnableModeless(BOOL fEnable)
4712 {
4713 return S_OK;
4714 }
4715
4716 /* IOleInPlaceObject */ // 1/4
4717 virtual STDMETHODIMP IOleInPlaceObject::InPlaceDeactivate()
4718 {
4719 // TODO: UIDeactivate, destroy window, inplacesite->OnInPlaceDeactivate
4720 return E_NOTIMPL;
4721 }
4722
4723 virtual STDMETHODIMP IOleInPlaceObject::UIDeactivate()
4724 {
4725 // TODO
4726 return E_NOTIMPL;
4727 }
4728
4729 virtual STDMETHODIMP IOleInPlaceObject::SetObjectRects(LPCRECT lprcPosRect, LPCRECT lprcClipRect)
4730 {
4731 if(m_controlWindow == NULL)
4732 return E_FAIL;
4733
4734 MoveWindow
4735 (
4736 m_controlWindow,
4737 lprcPosRect->left,
4738 lprcPosRect->top,
4739 lprcPosRect->right - lprcPosRect->left,
4740 lprcPosRect->bottom - lprcPosRect->top,
4741 TRUE
4742 );
4743
4744 SetWindowRgn(m_controlWindow, CreateRectRgnIndirect(lprcClipRect), TRUE);
4745
4746 return E_NOTIMPL;
4747 }
4748
4749 virtual STDMETHODIMP IOleInPlaceObject::ReactivateAndUndo()
4750 {
4751 return E_NOTIMPL;
4752 }
4753
4754 /* IOleObject */ // 18/21
4755 virtual STDMETHODIMP IOleObject::SetClientSite(IOleClientSite * pClientSite)
4756 {
4757 if(m_clientSite)
4758 m_clientSite->Release();
4759
4760 m_clientSite = pClientSite;
4761
4762 if(m_clientSite)
4763 m_clientSite->AddRef();
4764
4765 return S_OK;
4766 }
4767
4768 virtual STDMETHODIMP IOleObject::GetClientSite(IOleClientSite ** ppClientSite)
4769 {
4770 if(ppClientSite == NULL)
4771 return E_POINTER;
4772
4773 if(m_clientSite)
4774 m_clientSite->AddRef();
4775
4776 *ppClientSite = m_clientSite;
4777 return S_OK;
4778 }
4779
4780 virtual STDMETHODIMP IOleObject::SetHostNames(LPCOLESTR szContainerApp, LPCOLESTR szContainerObj)
4781 {
4782 return S_OK;
4783 }
4784
4785 virtual STDMETHODIMP IOleObject::Close(DWORD dwSaveOption)
4786 {
4787 // TODO: deactivate, destroy window, release in-place site, release advise sink
4788 return E_NOTIMPL; // TODO
4789 }
4790
4791 virtual STDMETHODIMP IOleObject::SetMoniker(DWORD dwWhichMoniker, IMoniker * pmk)
4792 {
4793 return E_NOTIMPL;
4794 }
4795
4796 virtual STDMETHODIMP IOleObject::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoniker ** ppmk)
4797 {
4798 return E_NOTIMPL;
4799 }
4800
4801 virtual STDMETHODIMP IOleObject::InitFromData(IDataObject * pDataObject, BOOL fCreation, DWORD dwReserved)
4802 {
4803 return E_NOTIMPL;
4804 }
4805
4806 virtual STDMETHODIMP IOleObject::GetClipboardData(DWORD dwReserved, IDataObject ** ppDataObject)
4807 {
4808 return E_NOTIMPL;
4809 }
4810
4811 virtual STDMETHODIMP IOleObject::DoVerb(LONG iVerb, LPMSG lpmsg, IOleClientSite * pActiveSite, LONG lindex, HWND hwndParent, LPCRECT lprcPosRect)
4812 {
4813 HRESULT hr;
4814
4815 switch(iVerb)
4816 {
4817 case OLEIVERB_PRIMARY:
4818 case OLEIVERB_SHOW:
4819 case OLEIVERB_UIACTIVATE:
4820 case OLEIVERB_INPLACEACTIVATE:
4821 hr = S_OK;
4822 break;
4823
4824 default:
4825 if(iVerb > 0)
4826 hr = OLEOBJ_S_INVALIDVERB;
4827 else
4828 hr = E_NOTIMPL;
4829 }
4830
4831 if(FAILED(hr))
4832 return hr;
4833
4834 HRESULT hrActivate = Activate(iVerb, pActiveSite, hwndParent, lprcPosRect);
4835
4836 if(FAILED(hrActivate))
4837 hr = hrActivate;
4838
4839 return hr;
4840 }
4841
4842 virtual STDMETHODIMP IOleObject::EnumVerbs(IEnumOLEVERB ** ppEnumOleVerb)
4843 {
4844 return OleRegEnumVerbs(m_classId, ppEnumOleVerb);
4845 }
4846
4847 virtual STDMETHODIMP IOleObject::Update()
4848 {
4849 return S_OK;
4850 }
4851
4852 virtual STDMETHODIMP IOleObject::IsUpToDate()
4853 {
4854 return S_OK;
4855 }
4856
4857 virtual STDMETHODIMP IOleObject::GetUserClassID(CLSID * pClsid)
4858 {
4859 *pClsid = m_classId;
4860 return S_OK;
4861 }
4862
4863 virtual STDMETHODIMP IOleObject::GetUserType(DWORD dwFormOfType, LPOLESTR * pszUserType)
4864 {
4865 return OleRegGetUserType(m_classId, dwFormOfType, pszUserType);
4866 }
4867
4868 virtual STDMETHODIMP IOleObject::SetExtent(DWORD dwDrawAspect, SIZEL * psizel)
4869 {
4870 // TODO: resize
4871 return E_NOTIMPL;
4872 }
4873
4874 virtual STDMETHODIMP IOleObject::GetExtent(DWORD dwDrawAspect, SIZEL * psizel)
4875 {
4876 // TODO: return size
4877 return E_NOTIMPL;
4878 }
4879
4880 HRESULT NeedAdviseHolder()
4881 {
4882 if(m_adviseHolder)
4883 return S_OK;
4884
4885 return CreateOleAdviseHolder(&m_adviseHolder);
4886 }
4887
4888 virtual STDMETHODIMP IOleObject::Advise(IAdviseSink * pAdvSink, DWORD * pdwConnection)
4889 {
4890 HRESULT hr = NeedAdviseHolder();
4891
4892 if(FAILED(hr))
4893 return hr;
4894
4895 return m_adviseHolder->Advise(pAdvSink, pdwConnection);
4896 }
4897
4898 virtual STDMETHODIMP IOleObject::Unadvise(DWORD dwConnection)
4899 {
4900 HRESULT hr = NeedAdviseHolder();
4901
4902 if(FAILED(hr))
4903 return hr;
4904
4905 return m_adviseHolder->Unadvise(dwConnection);
4906 }
4907
4908 virtual STDMETHODIMP IOleObject::EnumAdvise(IEnumSTATDATA ** ppenumAdvise)
4909 {
4910 HRESULT hr = NeedAdviseHolder();
4911
4912 if(FAILED(hr))
4913 return hr;
4914
4915 return m_adviseHolder->EnumAdvise(ppenumAdvise);
4916 }
4917
4918 virtual STDMETHODIMP IOleObject::GetMiscStatus(DWORD dwAspect, DWORD * pdwStatus)
4919 {
4920 return OleRegGetMiscStatus(m_classId, dwAspect, pdwStatus);
4921 }
4922
4923 virtual STDMETHODIMP IOleObject::SetColorScheme(LOGPALETTE * pLogpal)
4924 {
4925 return E_NOTIMPL;
4926 }
4927
4928 /* IOleWindow */
4929 virtual STDMETHODIMP IOleWindow::GetWindow(HWND * phwnd)
4930 {
4931 if(phwnd == NULL)
4932 return E_POINTER;
4933
4934 if(m_controlWindow == NULL)
4935 return E_FAIL;
4936
4937 *phwnd = m_controlWindow;
4938 return S_OK;
4939 }
4940
4941 virtual STDMETHODIMP IOleWindow::ContextSensitiveHelp(BOOL fEnterMode)
4942 {
4943 return E_NOTIMPL;
4944 }
4945
4946 /* IPersist */
4947 virtual STDMETHODIMP IPersist::GetClassID(CLSID * pClassID)
4948 {
4949 *pClassID = m_classId;
4950 return S_OK;
4951 }
4952
4953 /* IPersistPropertyBag */ // 0/3
4954 virtual STDMETHODIMP IPersistPropertyBag::InitNew()
4955 {
4956 return E_NOTIMPL;
4957 }
4958
4959 virtual STDMETHODIMP IPersistPropertyBag::Load(IPropertyBag * pPropBag, IErrorLog * pErrorLog)
4960 {
4961 return E_NOTIMPL;
4962 }
4963
4964 virtual STDMETHODIMP IPersistPropertyBag::Save(IPropertyBag * pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties)
4965 {
4966 return E_NOTIMPL;
4967 }
4968
4969 /* IPersistStorage */ // 0/6
4970 virtual STDMETHODIMP IPersistStorage::IsDirty()
4971 {
4972 return E_NOTIMPL;
4973 }
4974
4975 virtual STDMETHODIMP IPersistStorage::InitNew(IStorage * pStg)
4976 {
4977 return E_NOTIMPL;
4978 }
4979
4980 virtual STDMETHODIMP IPersistStorage::Load(IStorage * pStg)
4981 {
4982 return E_NOTIMPL;
4983 }
4984
4985 virtual STDMETHODIMP IPersistStorage::Save(IStorage * pStgSave, BOOL fSameAsLoad)
4986 {
4987 return E_NOTIMPL;
4988 }
4989
4990 virtual STDMETHODIMP IPersistStorage::SaveCompleted(IStorage * pStgNew)
4991 {
4992 return E_NOTIMPL;
4993 }
4994
4995 virtual STDMETHODIMP IPersistStorage::HandsOffStorage()
4996 {
4997 return E_NOTIMPL;
4998 }
4999
5000 /* IPersistStreamInit */ // 0/5
5001 virtual STDMETHODIMP IPersistStreamInit::IsDirty()
5002 {
5003 return E_NOTIMPL;
5004 }
5005
5006 virtual STDMETHODIMP IPersistStreamInit::Load(LPSTREAM pStm)
5007 {
5008 return E_NOTIMPL;
5009 }
5010
5011 virtual STDMETHODIMP IPersistStreamInit::Save(LPSTREAM pStm, BOOL fClearDirty)
5012 {
5013 return E_NOTIMPL;
5014 }
5015
5016 virtual STDMETHODIMP IPersistStreamInit::GetSizeMax(ULARGE_INTEGER * pCbSize)
5017 {
5018 return E_NOTIMPL;
5019 }
5020
5021 virtual STDMETHODIMP IPersistStreamInit::InitNew()
5022 {
5023 return E_NOTIMPL;
5024 }
5025
5026 /* IProvideClassInfo */
5027 virtual STDMETHODIMP IProvideClassInfo::GetClassInfo(ITypeInfo ** ppTI)
5028 {
5029 HRESULT hr = LoadTypeLibrary();
5030
5031 if(FAILED(hr))
5032 return hr;
5033
5034 return m_typeLib->GetTypeInfoOfGuid(m_classId, ppTI);
5035 }
5036
5037 /* IProvideClassInfo2 */
5038 virtual STDMETHODIMP IProvideClassInfo2::GetGUID(DWORD dwGuidKind, GUID * pGUID)
5039 {
5040 if(dwGuidKind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
5041 return E_INVALIDARG;
5042
5043 *pGUID = MSTSCLib::DIID_IMsTscAxEvents;
5044 return S_OK;
5045 }
5046
5047 /* IQuickActivate */
5048 virtual STDMETHODIMP IQuickActivate::QuickActivate(QACONTAINER * pQaContainer, QACONTROL * pQaControl)
5049 {
5050 if(pQaContainer == NULL || pQaControl == NULL)
5051 return E_POINTER;
5052
5053 if(pQaContainer->cbSize < sizeof(*pQaContainer) || pQaControl->cbSize < sizeof(*pQaControl))
5054 return E_INVALIDARG;
5055
5056 ULONG cb = pQaControl->cbSize;
5057 ZeroMemory(pQaControl, cb);
5058 pQaControl->cbSize = cb;
5059
5060 SetClientSite(pQaContainer->pClientSite);
5061
5062 if(pQaContainer->pAdviseSink)
5063 SetAdvise(DVASPECT_CONTENT, 0, pQaContainer->pAdviseSink);
5064
5065 if(pQaContainer->pUnkEventSink)
5066 Advise(pQaContainer->pUnkEventSink, &pQaControl->dwEventCookie);
5067
5068 GetMiscStatus(DVASPECT_CONTENT, &pQaControl->dwMiscStatus);
5069
5070 return E_NOTIMPL;
5071 }
5072
5073 virtual STDMETHODIMP IQuickActivate::SetContentExtent(LPSIZEL pSizel)
5074 {
5075 return SetExtent(DVASPECT_CONTENT, pSizel);
5076 }
5077
5078 virtual STDMETHODIMP IQuickActivate::GetContentExtent(LPSIZEL pSizel)
5079 {
5080 return GetExtent(DVASPECT_CONTENT, pSizel);
5081 }
5082
5083 /* IViewObject */ // 3/6
5084 virtual STDMETHODIMP IViewObject::Draw(DWORD dwDrawAspect, LONG lindex, void * pvAspect, DVTARGETDEVICE * ptd, HDC hdcTargetDev, HDC hdcDraw, LPCRECTL lprcBounds, LPCRECTL lprcWBounds, BOOL (STDMETHODCALLTYPE * pfnContinue)(ULONG_PTR dwContinue), ULONG_PTR dwContinue)
5085 {
5086 return E_NOTIMPL; // TODO
5087 }
5088
5089 virtual STDMETHODIMP IViewObject::GetColorSet(DWORD dwDrawAspect, LONG lindex, void * pvAspect, DVTARGETDEVICE * ptd, HDC hicTargetDev, LOGPALETTE ** ppColorSet)
5090 {
5091 return E_NOTIMPL;
5092 }
5093
5094 virtual STDMETHODIMP IViewObject::Freeze(DWORD dwDrawAspect, LONG lindex, void * pvAspect, DWORD * pdwFreeze)
5095 {
5096 return E_NOTIMPL;
5097 }
5098
5099 virtual STDMETHODIMP IViewObject::Unfreeze(DWORD dwFreeze)
5100 {
5101 return E_NOTIMPL;
5102 }
5103
5104 virtual STDMETHODIMP IViewObject::SetAdvise(DWORD aspects, DWORD advf, IAdviseSink * pAdvSink)
5105 {
5106 return E_NOTIMPL; // TODO
5107 }
5108
5109 virtual STDMETHODIMP IViewObject::GetAdvise(DWORD * pAspects, DWORD * pAdvf, IAdviseSink ** ppAdvSink)
5110 {
5111 return E_NOTIMPL; // TODO
5112 }
5113
5114 /* IViewObject2 */ // 0/1
5115 virtual STDMETHODIMP IViewObject2::GetExtent(DWORD dwDrawAspect, LONG lindex, DVTARGETDEVICE * ptd, LPSIZEL lpsizel)
5116 {
5117 return E_NOTIMPL; // TODO
5118 }
5119
5120 /* IMsTscAx */ // 23/30
5121 virtual STDMETHODIMP IMsTscAx::put_Server(BSTR pServer)
5122 {
5123 // FIXME: convert the hostname to Punycode, not the ANSI codepage
5124 return SetProperty(m_Server, pServer);
5125 }
5126
5127 virtual STDMETHODIMP IMsTscAx::get_Server(BSTR * pServer) const
5128 {
5129 return GetProperty(m_Server, pServer);
5130 }
5131
5132 virtual STDMETHODIMP IMsTscAx::put_Domain(BSTR pDomain)
5133 {
5134 return SetProperty(m_Domain, pDomain);
5135 }
5136
5137 virtual STDMETHODIMP IMsTscAx::get_Domain(BSTR * pDomain) const
5138 {
5139 return GetProperty(m_Domain, pDomain);
5140 }
5141
5142 virtual STDMETHODIMP IMsTscAx::put_UserName(BSTR pUserName)
5143 {
5144 return SetProperty(m_UserName, pUserName);
5145 }
5146
5147 virtual STDMETHODIMP IMsTscAx::get_UserName(BSTR * pUserName) const
5148 {
5149 return GetProperty(m_UserName, pUserName);
5150 }
5151
5152 virtual STDMETHODIMP IMsTscAx::put_DisconnectedText(BSTR pDisconnectedText)
5153 {
5154 return SetProperty(m_DisconnectedText, pDisconnectedText);
5155 }
5156
5157 virtual STDMETHODIMP IMsTscAx::get_DisconnectedText(BSTR * pDisconnectedText) const
5158 {
5159 return GetProperty(m_DisconnectedText, pDisconnectedText);
5160 }
5161
5162 virtual STDMETHODIMP IMsTscAx::put_ConnectingText(BSTR pConnectingText)
5163 {
5164 return SetProperty(m_ConnectingText, pConnectingText);
5165 }
5166
5167 virtual STDMETHODIMP IMsTscAx::get_ConnectingText(BSTR * pConnectingText) const
5168 {
5169 return GetProperty(m_ConnectingText, pConnectingText);
5170 }
5171
5172 virtual STDMETHODIMP IMsTscAx::get_Connected(short * pIsConnected) const
5173 {
5174 return GetProperty(m_Connected, pIsConnected);
5175 }
5176
5177 virtual STDMETHODIMP IMsTscAx::put_DesktopWidth(long pVal)
5178 {
5179 if(pVal < 200 || pVal > 1600)
5180 return E_INVALIDARG;
5181
5182 return SetProperty(m_DesktopWidth, pVal);
5183 }
5184
5185 virtual STDMETHODIMP IMsTscAx::get_DesktopWidth(long * pVal) const
5186 {
5187 return GetProperty(m_DesktopWidth, pVal);
5188 }
5189
5190 virtual STDMETHODIMP IMsTscAx::put_DesktopHeight(long pVal)
5191 {
5192 if(pVal < 200 || pVal > 1200)
5193 return E_INVALIDARG;
5194
5195 return SetProperty(m_DesktopHeight, pVal);
5196 }
5197
5198 virtual STDMETHODIMP IMsTscAx::get_DesktopHeight(long * pVal) const
5199 {
5200 return GetProperty(m_DesktopHeight, pVal);
5201 }
5202
5203 virtual STDMETHODIMP IMsTscAx::put_StartConnected(long pfStartConnected)
5204 {
5205 return SetProperty(m_StartConnected, pfStartConnected);
5206 }
5207
5208 virtual STDMETHODIMP IMsTscAx::get_StartConnected(long * pfStartConnected) const
5209 {
5210 return GetProperty(m_StartConnected, pfStartConnected);
5211 }
5212
5213 virtual STDMETHODIMP IMsTscAx::get_HorizontalScrollBarVisible(long * pfHScrollVisible) const
5214 {
5215 return E_NOTIMPL; // TODO
5216 }
5217
5218 virtual STDMETHODIMP IMsTscAx::get_VerticalScrollBarVisible(long * pfVScrollVisible) const
5219 {
5220 return E_NOTIMPL; // TODO
5221 }
5222
5223 virtual STDMETHODIMP IMsTscAx::put_FullScreenTitle(BSTR rhs)
5224 {
5225 // TODO
5226 return E_NOTIMPL;
5227 }
5228
5229 virtual STDMETHODIMP IMsTscAx::get_CipherStrength(long * pCipherStrength) const
5230 {
5231 if(pCipherStrength == NULL)
5232 return E_INVALIDARG;
5233
5234 *pCipherStrength = 128; // BUGBUG: a later version may change this. Use a compile-time constant
5235 return S_OK;
5236 }
5237
5238 virtual STDMETHODIMP IMsTscAx::get_Version(BSTR * pVersion) const
5239 {
5240 if(pVersion == NULL)
5241 return E_INVALIDARG;
5242
5243 BSTR version = SysAllocString(L"5.2.3790.1830"); // BUGBUG: don't use hardcoded string
5244
5245 if(version == NULL)
5246 return E_OUTOFMEMORY;
5247
5248 *pVersion = version;
5249 return S_OK;
5250 }
5251
5252 virtual STDMETHODIMP IMsTscAx::get_SecuredSettingsEnabled(long * pSecuredSettingsEnabled) const
5253 {
5254 // TODO: initialize m_SecuredSettingsEnabled as soon as we have an OLE client site
5255 return GetProperty(m_SecuredSettingsEnabled, pSecuredSettingsEnabled);
5256 }
5257
5258 virtual STDMETHODIMP IMsTscAx::get_SecuredSettings(MSTSCLib::IMsTscSecuredSettings ** ppSecuredSettings) const
5259 {
5260 return GetSecuredSettings(ppSecuredSettings);
5261 }
5262
5263 virtual STDMETHODIMP IMsTscAx::get_AdvancedSettings(MSTSCLib::IMsTscAdvancedSettings ** ppAdvSettings) const
5264 {
5265 return GetAdvancedSettings(ppAdvSettings);
5266 }
5267
5268 virtual STDMETHODIMP IMsTscAx::get_Debugger(MSTSCLib::IMsTscDebug ** ppDebugger) const
5269 {
5270 return E_NOTIMPL;
5271 }
5272
5273 virtual STDMETHODIMP IMsTscAx::Connect()
5274 {
5275 if(m_Connected)
5276 {
5277 // Protocol thread waiting for a manual reconnection: wake it up
5278 if(m_protocolThreadWaitingReconnection)
5279 {
5280 SetEvent(m_protocolThreadWaitingReconnection);
5281 return S_OK;
5282 }
5283
5284 return E_FAIL;
5285 }
5286
5287 m_Connected = true;
5288
5289 HRESULT hr;
5290
5291 if(m_controlWindow == NULL)
5292 {
5293 hr = CreateControlWindow(NULL);
5294
5295 if(FAILED(hr))
5296 return hr;
5297 }
5298
5299 for(;;)
5300 {
5301 // TODO: initialize plugin DLLs/channels
5302
5303 m_clientUI = new RdpClientUI();
5304
5305 if(m_clientUI == NULL)
5306 {
5307 hr = E_OUTOFMEMORY;
5308 break;
5309 }
5310
5311 m_clientUI->Initialize(m_controlWindow);
5312
5313 m_protocolState.licence_username = BstrToLpsz(m_UserName);
5314
5315 if(m_protocolState.licence_username == NULL)
5316 {
5317 hr = E_OUTOFMEMORY;
5318 break;
5319 }
5320
5321 DWORD dwSize = ARRAYSIZE(m_protocolState.licence_hostname);
5322
5323 if(!GetComputerNameA(m_protocolState.licence_hostname, &dwSize))
5324 {
5325 hr = HRESULT_FROM_WIN32(GetLastError());
5326 break;
5327 }
5328
5329 // Keyboard layout
5330 // BUGBUG: not too sure about the semantics
5331 long keyboardLayout = -1;
5332 WCHAR * endPtr = NULL;
5333
5334 if(m_KeyboardLayoutString)
5335 keyboardLayout = wcstol(m_KeyboardLayoutString, &endPtr, 0);
5336
5337 // no keyboard layout specified or invalid keyboard layout: use current keyboard layout
5338 if(endPtr == NULL || *endPtr == 0 || keyboardLayout == -1)
5339 keyboardLayout = PtrToLong(GetKeyboardLayout(0)); // FIXME? use LOWORD()?
5340
5341 m_protocolState.keylayout = keyboardLayout;
5342
5343 // in case of failure, assume English (US)
5344 if(m_protocolState.keylayout == 0)
5345 m_protocolState.keylayout = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
5346
5347 // Physical keyboard information
5348 m_protocolState.keyboard_type = GetKeyboardType(0);
5349 m_protocolState.keyboard_subtype = GetKeyboardType(1);
5350 m_protocolState.keyboard_functionkeys = GetKeyboardType(2);
5351
5352 // in case of failure, assume an IBM Enhanced keyboard with 12 function keys
5353 if(m_protocolState.keyboard_type == 0 || m_protocolState.keyboard_functionkeys == 0)
5354 {
5355 m_protocolState.keyboard_type = 4;
5356 m_protocolState.keyboard_subtype = 0;
5357 m_protocolState.keyboard_functionkeys = 12;
5358 }
5359
5360 // More initialization
5361 m_protocolState.width = m_DesktopWidth;
5362 m_protocolState.height = m_DesktopHeight;
5363 m_protocolState.server_depth = m_ColorDepth;
5364 m_protocolState.bitmap_compression = m_Compress ? TRUE : FALSE;
5365 m_protocolState.bitmap_cache = True; // TODO
5366 m_protocolState.bitmap_cache_persist_enable = False; // TODO
5367 m_protocolState.bitmap_cache_precache = True; // FIXME?
5368 m_protocolState.encryption = m_EncryptionEnabled ? TRUE : FALSE; // TBD: detect automatically
5369 m_protocolState.packet_encryption = m_EncryptionEnabled ? TRUE : FALSE;
5370 m_protocolState.desktop_save = True; // FIXME? tie to bitmap cache setting?
5371 m_protocolState.polygon_ellipse_orders = True;
5372 m_protocolState.use_rdp5 = True; // TBD: detect automatically
5373 m_protocolState.console_session = m_ConnectToServerConsole ? TRUE : FALSE;
5374 m_protocolState.rdp5_performanceflags = m_PerformanceFlags;
5375 m_protocolState.tcp_port_rdp = m_RDPPort;
5376 m_protocolState.rdp.current_status = 1;
5377
5378 // TODO: cache tuning based on the provided parameters
5379
5380 m_protocolState.cache.bmpcache_lru[0] = -1;
5381 m_protocolState.cache.bmpcache_lru[1] = -1;
5382 m_protocolState.cache.bmpcache_lru[2] = -1;
5383 m_protocolState.cache.bmpcache_mru[0] = -1;
5384 m_protocolState.cache.bmpcache_mru[1] = -1;
5385 m_protocolState.cache.bmpcache_mru[2] = -1;
5386
5387 DWORD dwIgnore;
5388 m_protocolThread = CreateThread(NULL, 0, ProtocolLoopThreadProc, this, 0, &dwIgnore);
5389
5390 hr = S_OK;
5391 break;
5392 }
5393
5394 if(FAILED(hr))
5395 m_Connected = false;
5396
5397 return hr;
5398 }
5399
5400 virtual STDMETHODIMP IMsTscAx::Disconnect()
5401 {
5402 if(!m_Connected)
5403 return E_FAIL;
5404
5405 // Terminate the protocol thread. On exit, it will fire the Disconnected event
5406 TerminateProtocolThread();
5407 return S_OK;
5408 }
5409
5410 virtual STDMETHODIMP IMsTscAx::CreateVirtualChannels(BSTR newVal)
5411 {
5412 UINT strLength = SysStringLen(newVal);
5413
5414 if(strLength < 1 || strLength > 300)
5415 return E_INVALIDARG;
5416
5417 return E_NOTIMPL; // TODO
5418 }
5419
5420 virtual STDMETHODIMP IMsTscAx::SendOnVirtualChannel(BSTR chanName, BSTR ChanData)
5421 {
5422 return E_NOTIMPL; // TODO
5423 }
5424
5425 /* IMsRdpClient */ // 6/10
5426 virtual STDMETHODIMP IMsRdpClient::put_ColorDepth(long pcolorDepth)
5427 {
5428 switch(pcolorDepth)
5429 {
5430 case 8:
5431 case 15:
5432 case 16:
5433 case 24:
5434 case 32:
5435 break;
5436
5437 default:
5438 return E_INVALIDARG;
5439 }
5440
5441 return SetProperty(m_ColorDepth, pcolorDepth);
5442 }
5443
5444 virtual STDMETHODIMP IMsRdpClient::get_ColorDepth(long * pcolorDepth) const
5445 {
5446 return GetProperty(m_ColorDepth, pcolorDepth);
5447 }
5448
5449 virtual STDMETHODIMP IMsRdpClient::get_AdvancedSettings2(MSTSCLib::IMsRdpClientAdvancedSettings ** ppAdvSettings) const
5450 {
5451 return GetAdvancedSettings(ppAdvSettings);
5452 }
5453
5454 virtual STDMETHODIMP IMsRdpClient::get_SecuredSettings2(MSTSCLib::IMsRdpClientSecuredSettings ** ppSecuredSettings) const
5455 {
5456 return GetSecuredSettings(ppSecuredSettings);
5457 }
5458
5459 virtual STDMETHODIMP IMsRdpClient::get_ExtendedDisconnectReason(MSTSCLib::ExtendedDisconnectReasonCode * pExtendedDisconnectReason) const
5460 {
5461 return GetProperty(m_ExtendedDisconnectReason, pExtendedDisconnectReason);
5462 }
5463
5464 virtual STDMETHODIMP IMsRdpClient::put_FullScreen(VARIANT_BOOL pfFullScreen)
5465 {
5466 if(!m_Connected)
5467 return E_FAIL;
5468
5469 if(pfFullScreen && !m_SecuredSettingsEnabled)
5470 return E_FAIL;
5471
5472 // TODO
5473 return E_NOTIMPL;
5474 }
5475
5476 virtual STDMETHODIMP IMsRdpClient::get_FullScreen(VARIANT_BOOL * pfFullScreen) const
5477 {
5478 return GetProperty(m_FullScreen, pfFullScreen);
5479 }
5480
5481 virtual STDMETHODIMP IMsRdpClient::SetVirtualChannelOptions(BSTR chanName, long chanOptions)
5482 {
5483 return E_NOTIMPL; // TODO
5484 }
5485
5486 virtual STDMETHODIMP IMsRdpClient::GetVirtualChannelOptions(BSTR chanName, long * pChanOptions)
5487 {
5488 return E_NOTIMPL; // TODO
5489 }
5490
5491 virtual STDMETHODIMP IMsRdpClient::RequestClose(MSTSCLib::ControlCloseStatus * pCloseStatus)
5492 {
5493 if(pCloseStatus == NULL)
5494 return E_POINTER;
5495
5496 if(!m_Connected)
5497 {
5498 *pCloseStatus = MSTSCLib::controlCloseCanProceed;
5499 return S_OK;
5500 }
5501
5502 *pCloseStatus = MSTSCLib::controlCloseWaitForEvents;
5503
5504 if(!PostMessage(m_controlWindow, RDPC_WM_REQUEST_CLOSE, 0, 0))
5505 return HRESULT_FROM_WIN32(GetLastError());
5506
5507 return S_OK;
5508 }
5509
5510 /* IMsRdpClient2 */
5511 virtual STDMETHODIMP IMsRdpClient2::get_AdvancedSettings3(MSTSCLib::IMsRdpClientAdvancedSettings2 ** ppAdvSettings) const
5512 {
5513 return GetAdvancedSettings(ppAdvSettings);
5514 }
5515
5516 virtual STDMETHODIMP IMsRdpClient2::put_ConnectedStatusText(BSTR pConnectedStatusText)
5517 {
5518 return SetProperty(m_ConnectedStatusText, pConnectedStatusText);
5519 }
5520
5521 virtual STDMETHODIMP IMsRdpClient2::get_ConnectedStatusText(BSTR * pConnectedStatusText) const
5522 {
5523 return GetProperty(m_ConnectedStatusText, pConnectedStatusText);
5524 }
5525
5526 /* IMsRdpClient3 */
5527 virtual STDMETHODIMP IMsRdpClient3::get_AdvancedSettings4(MSTSCLib::IMsRdpClientAdvancedSettings3 ** ppAdvSettings) const
5528 {
5529 return GetAdvancedSettings(ppAdvSettings);
5530 }
5531
5532 /* IMsRdpClient4 */
5533 virtual STDMETHODIMP IMsRdpClient4::get_AdvancedSettings5(MSTSCLib::IMsRdpClientAdvancedSettings4 ** ppAdvSettings5) const
5534 {
5535 return GetAdvancedSettings(ppAdvSettings5);
5536 }
5537
5538 /* IMsTscNonScriptable */
5539 virtual STDMETHODIMP IMsTscNonScriptable::put_ClearTextPassword(BSTR rhs)
5540 {
5541 return SetProperty(m_ClearTextPassword, rhs);
5542 }
5543
5544 virtual STDMETHODIMP IMsTscNonScriptable::put_PortablePassword(BSTR pPortablePass)
5545 {
5546 return E_NOTIMPL;
5547 }
5548
5549 virtual STDMETHODIMP IMsTscNonScriptable::get_PortablePassword(BSTR * pPortablePass) const
5550 {
5551 return E_NOTIMPL;
5552 }
5553
5554 virtual STDMETHODIMP IMsTscNonScriptable::put_PortableSalt(BSTR pPortableSalt)
5555 {
5556 return E_NOTIMPL;
5557 }
5558
5559 virtual STDMETHODIMP IMsTscNonScriptable::get_PortableSalt(BSTR * pPortableSalt) const
5560 {
5561 return E_NOTIMPL;
5562 }
5563
5564 virtual STDMETHODIMP IMsTscNonScriptable::put_BinaryPassword(BSTR pBinaryPassword)
5565 {
5566 return E_NOTIMPL;
5567 }
5568
5569 virtual STDMETHODIMP IMsTscNonScriptable::get_BinaryPassword(BSTR * pBinaryPassword) const
5570 {
5571 return E_NOTIMPL;
5572 }
5573
5574 virtual STDMETHODIMP IMsTscNonScriptable::put_BinarySalt(BSTR pSalt)
5575 {
5576 return E_NOTIMPL;
5577 }
5578
5579 virtual STDMETHODIMP IMsTscNonScriptable::get_BinarySalt(BSTR * pSalt) const
5580 {
5581 return E_NOTIMPL;
5582 }
5583
5584 virtual STDMETHODIMP IMsTscNonScriptable::ResetPassword()
5585 {
5586 return SetProperty(m_ClearTextPassword, NULL);
5587 }
5588
5589 /* IMsRdpClientNonScriptable */ // 0/2
5590 virtual STDMETHODIMP IMsRdpClientNonScriptable::NotifyRedirectDeviceChange(MSTSCLib::UINT_PTR wParam, MSTSCLib::LONG_PTR lParam)
5591 {
5592 return E_NOTIMPL; // TODO
5593 }
5594
5595 virtual STDMETHODIMP IMsRdpClientNonScriptable::SendKeys(long numKeys, VARIANT_BOOL * pbArrayKeyUp, long * plKeyData)
5596 {
5597 // NOTE: the keys must be sent in a single, atomic sequence
5598 // TODO: acquire the write lock
5599 return E_NOTIMPL; // TODO
5600 }
5601
5602 /* IMsRdpClientNonScriptable2 */
5603 virtual STDMETHODIMP IMsRdpClientNonScriptable2::put_UIParentWindowHandle(HWND phwndUIParentWindowHandle)
5604 {
5605 return SetProperty(m_UIParentWindowHandle, phwndUIParentWindowHandle);
5606 }
5607
5608 virtual STDMETHODIMP IMsRdpClientNonScriptable2::get_UIParentWindowHandle(HWND * phwndUIParentWindowHandle) const
5609 {
5610 return GetProperty(m_UIParentWindowHandle, phwndUIParentWindowHandle);
5611 }
5612 };
5613
5614 #pragma warning(pop)
5615
5616 /* More glue to interface to the rdesktop code */
5617 extern "C"
5618 {
5619
5620 /* Orders */
5621 /* support routines */
5622 void ui_begin_update(RDPCLIENT * This)
5623 {
5624 RdpClient::InnerToOuter(This)->GetUI()->Display_BeginUpdate();
5625 }
5626
5627 void ui_end_update(RDPCLIENT * This)
5628 {
5629 RdpClient::InnerToOuter(This)->GetUI()->Display_EndUpdate();
5630 }
5631
5632 void ui_set_clip(RDPCLIENT * This, int x, int y, int cx, int cy)
5633 {
5634 RdpClient::InnerToOuter(This)->GetUI()->Display_SetClip(x, y, cx, cy);
5635 }
5636
5637 void ui_reset_clip(RDPCLIENT * This)
5638 {
5639 RdpClient::InnerToOuter(This)->GetUI()->Display_ResetClip();
5640 }
5641
5642 /* blits */
5643 void ui_destblt(RDPCLIENT * This, uint8 opcode, int x, int y, int cx, int cy)
5644 {
5645 RdpClient::InnerToOuter(This)->GetUI()->Display_DestBlt(opcode, x, y, cx, cy);
5646 }
5647
5648 void ui_memblt(RDPCLIENT * This, uint8 opcode, int x, int y, int cx, int cy, HBITMAP src, int srcx, int srcy)
5649 {
5650 RdpClient::InnerToOuter(This)->GetUI()->Display_MemBlt(opcode, x, y, cx, cy, src, srcx, srcy);
5651 }
5652
5653 void ui_patblt(RDPCLIENT * This, uint8 opcode, int x, int y, int cx, int cy, BRUSH * brush, int bgcolour, int fgcolour)
5654 {
5655 RdpClient::InnerToOuter(This)->GetUI()->Display_PatBlt(opcode, x, y, cx, cy, brush, bgcolour, fgcolour);
5656 }
5657
5658 void ui_screenblt(RDPCLIENT * This, uint8 opcode, int x, int y, int cx, int cy, int srcx, int srcy)
5659 {
5660 RdpClient::InnerToOuter(This)->GetUI()->Display_ScreenBlt(opcode, x, y, cx, cy, srcx, srcy);
5661 }
5662
5663 void ui_triblt(RDPCLIENT * This, uint8 opcode, int x, int y, int cx, int cy, HBITMAP src, int srcx, int srcy, BRUSH * brush, int bgcolour, int fgcolour)
5664 {
5665 RdpClient::InnerToOuter(This)->GetUI()->Display_TriBlt(opcode, x, y, cx, cy, src, srcx, srcy, brush, bgcolour, fgcolour);
5666 }
5667
5668 void ui_paint_bitmap(RDPCLIENT * This, int x, int y, int cx, int cy, int width, int height, uint8 * data)
5669 {
5670 RdpClient::InnerToOuter(This)->GetUI()->Display_PaintBitmap(x, y, cx, cy, width, height, data);
5671 }
5672
5673 /* shapes */
5674 void ui_ellipse(RDPCLIENT * This, uint8 opcode, uint8 fillmode, int x, int y, int cx, int cy, BRUSH * brush, int bgcolour, int fgcolour)
5675 {
5676 // TODO
5677 // RdpClient::InnerToOuter(This)->GetUI()->Display_Ellipse(opcode, fillmode, x, y, cx, cy, brush, bgcolour, fgcolour);
5678 }
5679
5680 void ui_line(RDPCLIENT * This, uint8 opcode, int startx, int starty, int endx, int endy, PEN * pen)
5681 {
5682 RdpClient::InnerToOuter(This)->GetUI()->Display_Line(opcode, startx, starty, endx, endy, pen);
5683 }
5684
5685 void ui_polygon(RDPCLIENT * This, uint8 opcode, uint8 fillmode, POINT * point, int npoints, BRUSH * brush, int bgcolour, int fgcolour)
5686 {
5687 RdpClient::InnerToOuter(This)->GetUI()->Display_Polygon(opcode, fillmode, point, npoints, brush, bgcolour, fgcolour);
5688 }
5689
5690 void ui_polyline(RDPCLIENT * This, uint8 opcode, POINT * points, int npoints, PEN * pen)
5691 {
5692 RdpClient::InnerToOuter(This)->GetUI()->Display_Polyline(opcode, points, npoints, pen);
5693 }
5694
5695 void ui_rect(RDPCLIENT * This, int x, int y, int cx, int cy, int colour)
5696 {
5697 RdpClient::InnerToOuter(This)->GetUI()->Display_Rect(x, y, cx, cy, colour);
5698 }
5699
5700 /* text */
5701 void ui_draw_text
5702 (
5703 RDPCLIENT * This,
5704 uint8 font,
5705 uint8 flags,
5706 uint8 opcode,
5707 int mixmode,
5708 int x,
5709 int y,
5710 int clipx,
5711 int clipy,
5712 int clipcx,
5713 int clipcy,
5714 int boxx,
5715 int boxy,
5716 int boxcx,
5717 int boxcy,
5718 BRUSH * brush,
5719 int bgcolour,
5720 int fgcolour,
5721 uint8 * text,
5722 uint8 length
5723 )
5724 {
5725 RdpClient::InnerToOuter(This)->GetUI()->Display_DrawText
5726 (
5727 font,
5728 flags,
5729 opcode,
5730 mixmode,
5731 x,
5732 y,
5733 clipx,
5734 clipy,
5735 clipcx,
5736 clipcy,
5737 boxx,
5738 boxy,
5739 boxcx,
5740 boxcy,
5741 brush,
5742 bgcolour,
5743 fgcolour,
5744 text,
5745 length
5746 );
5747 }
5748
5749 /* desktop save/restore */
5750 void ui_desktop_save(RDPCLIENT * This, uint32 offset, int x, int y, int cx, int cy)
5751 {
5752 RdpClient::InnerToOuter(This)->GetUI()->Display_SaveDesktop(offset, x, y, cx, cy);
5753 }
5754
5755 void ui_desktop_restore(RDPCLIENT * This, uint32 offset, int x, int y, int cx, int cy)
5756 {
5757 RdpClient::InnerToOuter(This)->GetUI()->Display_RestoreDesktop(offset, x, y, cx, cy);
5758 }
5759
5760 /* Resources */
5761 /* bitmaps */
5762 HBITMAP ui_create_bitmap(RDPCLIENT * This, int width, int height, uint8 * data)
5763 {
5764 return win32_create_dib(width, height, This->server_depth, data);
5765 }
5766
5767 void ui_destroy_bitmap(RDPCLIENT *, HBITMAP bmp)
5768 {
5769 DeleteObject(bmp);
5770 }
5771
5772 /* palettes */
5773 HCOLOURMAP ui_create_colourmap(RDPCLIENT *, COLOURMAP * colours)
5774 {
5775 return NULL;
5776 }
5777
5778 void ui_set_colourmap(RDPCLIENT * This, HCOLOURMAP map)
5779 {
5780 // TODO
5781 }
5782
5783 /* cursors */
5784 HCURSOR ui_create_cursor(RDPCLIENT * This, unsigned int x, unsigned int y, int width, int height, uint8 * andmask, uint8 * xormask)
5785 {
5786 uint8 * andbuf = NULL;
5787 uint8 * xorbuf = NULL;
5788
5789 uint8 * andbits = win32_convert_scanlines(width, - height, 1, 2, 4, andmask, &andbuf);
5790 uint8 * xorbits = win32_convert_scanlines(width, height, 24, 2, 4, xormask, &xorbuf);
5791
5792 HBITMAP hbmMask = CreateBitmap(width, height, 1, 1, andbits);
5793 HBITMAP hbmColor = win32_create_dib(width, height, 24, xorbits);
5794
5795 ICONINFO iconinfo;
5796 iconinfo.fIcon = FALSE;
5797 iconinfo.xHotspot = x;
5798 iconinfo.yHotspot = y;
5799 iconinfo.hbmMask = hbmMask;
5800 iconinfo.hbmColor = hbmColor;
5801
5802 HICON icon = CreateIconIndirect(&iconinfo);
5803
5804 if(icon == NULL)
5805 error("CreateIconIndirect %dx%d failed\n", width, height);
5806
5807 if(andbuf)
5808 delete[] andbuf;
5809
5810 if(xorbuf)
5811 delete[] xorbuf;
5812
5813 DeleteObject(hbmMask);
5814 DeleteObject(hbmColor);
5815
5816 return icon;
5817 }
5818
5819 void ui_destroy_cursor(RDPCLIENT *, HCURSOR cursor)
5820 {
5821 DestroyIcon(cursor);
5822 }
5823
5824 /* glyphs */
5825 HGLYPH ui_create_glyph(RDPCLIENT * This, int width, int height, const uint8 * data)
5826 {
5827 uint8 * databuf = NULL;
5828 uint8 * databits = win32_convert_scanlines(width, height, 1, 1, 2, data, &databuf);
5829
5830 HBITMAP hbm = CreateBitmap(width, height, 1, 1, databits);
5831
5832 if(databuf)
5833 delete[] databuf;
5834
5835 const uint8 * p = data;
5836 int stride = alignup(alignup(width, 8) / 8, 1);
5837
5838 #ifdef _DEBUG
5839 printf("glyph %p\n", hbm);
5840
5841 for(int i = 0; i < height; ++ i, p += stride)
5842 {
5843 for(int j = 0; j < width; ++ j)
5844 {
5845 int B = p[j / 8];
5846 int b = 8 - j % 8 - 1;
5847
5848 if(B & (1 << b))
5849 fputs("##", stdout);
5850 else
5851 fputs("..", stdout);
5852 }
5853
5854 fputc('\n', stdout);
5855 }
5856
5857 fputc('\n', stdout);
5858 #endif
5859
5860 return hbm;
5861 }
5862
5863 void ui_destroy_glyph(RDPCLIENT *, HGLYPH glyph)
5864 {
5865 DeleteObject(glyph);
5866 }
5867
5868 /* Input window */
5869 void ui_move_pointer(RDPCLIENT * This, int x, int y)
5870 {
5871 // TODO
5872 }
5873
5874 void ui_set_cursor(RDPCLIENT * This, HCURSOR cursor)
5875 {
5876 // TODO
5877 }
5878
5879 void ui_set_null_cursor(RDPCLIENT * This)
5880 {
5881 // TODO
5882 }
5883
5884 /* Miscellaneous */
5885 void ui_resize_window(RDPCLIENT * This)
5886 {
5887 }
5888
5889 void ui_bell(RDPCLIENT *)
5890 {
5891 MessageBeep(0);
5892 }
5893
5894 int ui_select(RDPCLIENT * This, SOCKET rdp_socket)
5895 {
5896 return SleepEx(0, TRUE) == WAIT_IO_COMPLETION;
5897 }
5898
5899 /* Events */
5900 BOOL event_pubkey(RDPCLIENT * This, unsigned char * key, unsigned int key_size)
5901 {
5902 if(!RdpClient::OnPublicKey(This, key, key_size))
5903 return FALSE;
5904 else
5905 return TRUE;
5906 }
5907
5908 void event_logon(RDPCLIENT * This)
5909 {
5910 RdpClient::OnLogon(This);
5911 }
5912
5913 BOOL event_redirect(RDPCLIENT * This, uint32 flags, uint32 server_len, wchar_t * server, uint32 cookie_len, char * cookie, uint32 username_len, wchar_t * username, uint32 domain_len, wchar_t * domain, uint32 password_len, wchar_t * password)
5914 {
5915 if
5916 (
5917 !RdpClient::OnRedirect
5918 (
5919 This,
5920 flags,
5921 server_len,
5922 server,
5923 cookie_len,
5924 cookie,
5925 username_len,
5926 username,
5927 domain_len,
5928 domain,
5929 password_len,
5930 password
5931 )
5932 )
5933 return FALSE;
5934 else
5935 return TRUE;
5936 }
5937
5938 }
5939
5940 class ClassFactory: public IClassFactory
5941 {
5942 private:
5943 LONG m_refCount;
5944 CLSID m_classId;
5945 unsigned m_libIndex;
5946
5947 public:
5948 ClassFactory(REFCLSID rclsid, unsigned libIndex):
5949 m_refCount(1),
5950 m_classId(rclsid)
5951 {
5952 lockServer();
5953 }
5954
5955 ~ClassFactory()
5956 {
5957 unlockServer();
5958 }
5959
5960 virtual STDMETHODIMP QueryInterface(REFIID riid, void ** ppvObject)
5961 {
5962 if(riid == IID_IUnknown || riid == IID_IClassFactory)
5963 {
5964 *ppvObject = this;
5965 return S_OK;
5966 }
5967 else
5968 {
5969 *ppvObject = NULL;
5970 return E_NOINTERFACE;
5971 }
5972 }
5973
5974 virtual STDMETHODIMP_(ULONG) AddRef()
5975 {
5976 return InterlockedIncrement(&m_refCount);
5977 }
5978
5979 virtual STDMETHODIMP_(ULONG) Release()
5980 {
5981 LONG n = InterlockedDecrement(&m_refCount);
5982
5983 if(n == 0)
5984 delete this;
5985
5986 return n;
5987 }
5988
5989 virtual STDMETHODIMP CreateInstance(IUnknown * pUnkOuter, REFIID riid, void ** ppvObject)
5990 {
5991 if(pUnkOuter && riid != IID_IUnknown)
5992 return CLASS_E_NOAGGREGATION;
5993
5994 return RdpClient::CreateInstance(m_classId, m_libIndex, pUnkOuter, riid, ppvObject);
5995 }
5996
5997 virtual STDMETHODIMP LockServer(BOOL fLock)
5998 {
5999 if(fLock)
6000 lockServer();
6001 else
6002 unlockServer();
6003
6004 return S_OK;
6005 }
6006 };
6007
6008 extern "C"
6009 {
6010
6011 STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID * ppv)
6012 {
6013 unsigned libindex;
6014
6015 if
6016 (
6017 rclsid == MSTSCLib::CLSID_MsTscAx ||
6018 rclsid == MSTSCLib::CLSID_MsRdpClient ||
6019 rclsid == MSTSCLib::CLSID_MsRdpClient2 ||
6020 rclsid == MSTSCLib::CLSID_MsRdpClient3 ||
6021 rclsid == MSTSCLib::CLSID_MsRdpClient4
6022 )
6023 libindex = 1;
6024 else if
6025 (
6026 rclsid == MSTSCLib_Redist::CLSID_MsTscAx ||
6027 rclsid == MSTSCLib_Redist::CLSID_MsRdpClient ||
6028 rclsid == MSTSCLib_Redist::CLSID_MsRdpClient2 ||
6029 rclsid == MSTSCLib_Redist::CLSID_MsRdpClient3 // ||
6030 // rclsid != MSTSCLib::CLSID_MsRdpClient4
6031 )
6032 libindex = 2;
6033 else
6034 return CLASS_E_CLASSNOTAVAILABLE;
6035
6036 ClassFactory * p = new ClassFactory(rclsid, libindex);
6037
6038 if(p == NULL)
6039 return E_OUTOFMEMORY;
6040
6041 HRESULT hr = p->QueryInterface(riid, ppv);
6042
6043 p->Release();
6044
6045 if(FAILED(hr))
6046 return hr;
6047
6048 return S_OK;
6049 }
6050
6051 STDAPI DllCanUnloadNow(void)
6052 {
6053 return canUnloadServer() ? S_OK : S_FALSE;
6054 }
6055
6056 STDAPI_(ULONG) DllGetTscCtlVer(void)
6057 {
6058 // BUGBUG: don't hardcode this
6059 return 0x05020ECE; // 5.2.3790
6060 }
6061
6062 DWORD WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, LPVOID lpvReserved)
6063 {
6064 assert(hInstance == GetCurrentModule());
6065
6066 switch(fdwReason)
6067 {
6068 case DLL_PROCESS_ATTACH:
6069 {
6070 DisableThreadLibraryCalls(hInstance);
6071
6072 if(!RdpClient::Startup())
6073 return FALSE;
6074 }
6075
6076 break;
6077
6078 case DLL_PROCESS_DETACH:
6079 {
6080 // Process is terminating, no need to clean up
6081 if(lpvReserved)
6082 break;
6083
6084 RdpClient::Shutdown();
6085 }
6086
6087 break;
6088 }
6089
6090 return TRUE;
6091 }
6092
6093 }
6094
6095 // EOF