ReactOS 0.4.15-dev-8348-gc1b9bb5
activex.cpp
Go to the documentation of this file.
1#include "stdafx.h"
2
3namespace MSTSCLib
4{
5#include "mstsclib_h.h"
6};
7
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
17namespace
18{
19#ifdef _MSC_VER
20extern "C" char __ImageBase;
21#endif
22
24{
25 return reinterpret_cast<HMODULE>(&__ImageBase);
26}
27
28}
29
30namespace
31{
32
34
36{
38}
39
41{
43}
44
46{
47 return g_moduleRefCount == 0;
48}
49
50}
51
52namespace
53{
54
55void FreeLpsz(LPSTR lpsz)
56{
57 if(lpsz)
58 delete[] lpsz;
59}
60
61LPSTR 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
74LPSTR 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
98{
99 return AllocLpsz(bstr, SysStringLen(bstr));
100}
101
103{
104 int cch = MultiByteToWideChar(CP_ACP, 0, lpsz, -1, NULL, 0);
105
106 if(cch <= 0)
107 return NULL;
108
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
127namespace
128{
129
130template<class T, class U> T aligndown(const T& X, const U& align)
131{
132 return X & ~(T(align) - 1);
133}
134
135template<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 */
141uint8 * 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 */
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
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 */
240HBRUSH 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
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 */
301{
302public:
303 // TODO: pass the client settings relevant to the GUI here
305 {
306 // TODO: create the various windows
307 // TODO: create display window thread
308 // TODO: create input thread
309 return E_FAIL;
310 }
311
312public:
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 */
366private:
370
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))
386 }
387
388 return 0;
389
390 // Resized: rearrange children windows, adjust scrollbars
391 case WM_SIZE:
392 {
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;
425
426 // update the vertical scrollbar
427 scroll.nMax = m_consoleHeight;
428 scroll.nPage = rcClient.bottom;
429 scroll.nPos = 0 - m_consoleY;
431
432 // move/resize the console window
434 }
435
436 return 0;
437
438 case WM_HSCROLL:
439 {
440 SCROLLINFO scroll = { sizeof(scroll), SIF_TRACKPOS };
442 m_consoleX = - scroll.nTrackPos;
444 }
445
446 return 0;
447
448 case WM_VSCROLL:
449 {
450 SCROLLINFO scroll = { sizeof(scroll), SIF_TRACKPOS };
452 m_consoleY = - scroll.nTrackPos;
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 */
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 */
477private:
484
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
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 */
512private:
524
526 {
527 switch(uMsg)
528 {
529 case WM_DESTROY:
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
542
543 if(hdc)
544 {
545 RECT rc;
547 BitBlt(hdc, 0, 0, rc.right, rc.bottom, m_displayBuffer, 0, 0, SRCCOPY);
548 }
549 else
550 {
551 PAINTSTRUCT 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,
564 ps.rcPaint.left,
565 ps.rcPaint.top,
566 SRCCOPY
567 );
568 }
569 else
570 {
571 // bleh. There has to be a better way
573
575 (
576 hdc,
577 0,
578 0,
582 0,
583 0,
586 SRCCOPY
587 );
588 }
589
591 }
592
594 }
595
596 return 0;
597
598 default:
599 break;
600 }
601
603 }
604
605 /* Screen repainting */
607 {
608 if(m_smartSizing)
609 return Display_RepaintAll();
610
611 RECT rcDamage;
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
661 {
663 }
664
665public:
666 void Display_SetClip(int x, int y, int cx, int cy)
667 {
672
676 }
677
679 {
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 =
700
701 for(int i = 0; i < cy; ++ i)
702 {
703 memcpy(dst, src, sizex);
704 src += fromstride;
706 }
707
709 }
710
711 void Display_DestBlt(uint8 opcode, int x, int y, int cx, int cy)
712 {
713 int dcsave = SaveDC(m_displayBuffer);
715 PatBlt(m_displayBuffer, x, y, cx, cy, MAKELONG(0, opcode));
716 RestoreDC(m_displayBuffer, dcsave);
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);
730
731 PatBlt(m_displayBuffer, x, y, cx, cy, MAKELONG(0, opcode));
732
733 RestoreDC(m_displayBuffer, dcsave);
734
735 DeleteObject(hbr);
736
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));
744 }
745
746 void Display_MemBlt(uint8 opcode, int x, int y, int cx, int cy, HBITMAP src, int srcx, int srcy)
747 {
750
751 BitBlt(m_displayBuffer, x, y, cx, cy, hdcSrc, srcx, srcy, MAKELONG(0, opcode));
752
753 SelectObject(hdcSrc, hOld);
755
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
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);
773
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);
785 MoveToEx(m_displayBuffer, startx, starty, NULL);
786
787 LineTo(m_displayBuffer, endx, endy);
788
789 RestoreDC(m_displayBuffer, dcsave);
790
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
829
830 Rectangle(m_displayBuffer, x, y, x + cx + 1, y + cy + 1);
831
832 RestoreDC(m_displayBuffer, dcsave);
833
834 DeleteObject(hbr);
835
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);
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);
874
876
877 RestoreDC(m_displayBuffer, dcsave);
878
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
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;
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);
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
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 {
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
983 x += glyph->width;
984 }
985 }
986
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,
1008 )
1009 {
1010 int i, j;
1011 DATABLOB *entry;
1012
1013 HBRUSH hbr = CreateSolidBrush(bgcolour);
1014 HGDIOBJ holdbrush = SelectObject(m_displayBuffer, hbr);
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 =
1107
1109 (
1110 /*This*/NULL,
1112 cx,
1113 cy,
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
1125
1126 uint8 * dst =
1130
1131 GdiFlush();
1132
1133 for(int i = 0; i < cy; ++ i)
1134 {
1135 memcpy(dst, src, fromstride);
1136 src += fromstride;
1138 }
1139
1141 }
1142
1143
1145 {
1148 }
1149
1151 {
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 */
1165
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 {
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
1237public:
1238};
1239
1240#pragma warning(push)
1241#pragma warning(disable: 4584)
1242
1243/* The ActiveX control */
1244class RdpClient SEALED_:
1245 /* COM basics */
1246 public IUnknown,
1247 public IDispatch,
1248
1249 /* ActiveX stuff */
1251 public IDataObject,
1252 public IObjectSafety,
1253 public IOleControl,
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 */
1277
1278 // NOTE: implemented by inner classes due to requiring distinct IDispatch implementations
1279 // IMsRdpClientAdvancedSettings4
1280 // IMsRdpClientSecuredSettings
1281{
1282private:
1283 /* An endless amount of COM glue */
1284 // Reference counting
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
1298
1300 {
1301 private:
1302 RdpClient * Outer()
1303 {
1304 return InnerToOuter(this);
1305 }
1306
1307 public:
1309 {
1310 return Outer()->queryInterface(riid, ppvObject);
1311 }
1312
1314 {
1315 return Outer()->addRef();
1316 }
1317
1319 {
1320 return Outer()->release();
1321 }
1322
1323 }
1325
1326 // Persistence support
1328
1329 // Late binding support
1333
1334 // Event sinks
1336
1337 union
1338 {
1339 MSTSCLib::IMsTscAxEvents * m_EventSinksStatic[1];
1341 };
1342
1343 // OLE control glue
1350
1351 // UrlMon security
1353
1355 {
1356 return m_SafetyOptions & INTERFACESAFE_FOR_UNTRUSTED_CALLER;
1357 }
1358
1359 /* Glue to interface to rdesktop-core */
1367
1368 /* Properties */
1369 // Storage fields
1370 // NOTE: keep sorted by alignment (pointers and handles, integers, enumerations, booleans)
1379 BSTR m_ClearTextPassword; // FIXME! dangerous, shouldn't store in cleartext!
1386 // TODO: plugin DLLs
1422
1424
1444 bool m_SmartSizing; // FIXME: this can be set while the control is connected
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
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
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
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 */
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
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
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
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
1688 {
1691 unsigned int cArgs;
1693 AsyncEventCallback callback;
1694 };
1695
1697 {
1700 wchar_t * server;
1702 char * cookie;
1704 wchar_t * username;
1706 wchar_t * domain;
1708 wchar_t * password;
1709 };
1710
1711 enum
1712 {
1713 RDPC_WM_ = WM_USER,
1719 };
1720
1722 {
1723 // no need to do anything. The interruption will be enough
1724 }
1725
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:
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());
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 {
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 {
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())
1883
1884 return true;
1885 }
1886
1887 // synchronous call from outside the apartment
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
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;
1928 }
1929
1930 return S_OK;
1931 }
1932
1933 // Specific events
1935 {
1936 // Source: protocol
1937 FireEventOutsideApartment(1);
1938 }
1939
1941 {
1942 // Source: protocol
1943 FireEventOutsideApartment(2);
1944 }
1945
1947 {
1948 // Source: protocol
1949 FireEventOutsideApartment(3);
1950 }
1951
1953 {
1954 // Source: protocol. Special handling
1955 SendMessage(m_controlWindow, RDPC_WM_DISCONNECT, reason, 0);
1956 }
1957
1959 {
1960 // Source: UI window
1961 FireEventInsideApartment(5);
1962 }
1963
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
2010 {
2011 // Source: UI window
2012 FireEventInsideApartment(8);
2013 }
2014
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
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
2069 {
2070 // Source: input thread
2071 FireEventOutsideApartment(13);
2072 }
2073
2075 {
2076 // Source: UI window
2077 FireEventInsideApartment(14);
2078 }
2079
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 {
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
2146 {
2147 // Source: protocol
2148 FireEventOutsideApartment(18);
2149 }
2150
2152 {
2153 // Source: protocol
2154 FireEventOutsideApartment(19);
2155 }
2156
2157 /* Actual IUnknown implementation */
2159 {
2160 IUnknown * pvObject = NULL;
2161
2162 using namespace MSTSCLib;
2163
2164 if(riid == IID_IUnknown)
2165 pvObject = static_cast<IUnknown *>(&m_inner);
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);
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);
2209 pvObject = static_cast<IMsRdpClientNonScriptable *>(this);
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
2225 {
2226 return InterlockedIncrement(&m_refCount);
2227 }
2228
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 */
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
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 */
2430
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
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:
2466 {
2467 if(m_dispTypeInfo)
2468 m_dispTypeInfo->Release();
2469 }
2470
2471 /* IUnknown */
2473 {
2474 using namespace MSTSCLib;
2475
2476 if
2477 (
2478 riid == IID_IUnknown ||
2479 riid == IID_IDispatch ||
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
2499 {
2500 return Outer()->addRef();
2501 }
2502
2504 {
2505 return Outer()->release();
2506 }
2507
2508 /* IDispatch */
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 }
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
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
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:
3392 {
3393 if(m_dispTypeInfo)
3394 m_dispTypeInfo->Release();
3395 }
3396
3397 /* IUnknown */
3399 {
3400 using namespace MSTSCLib;
3401
3402 if
3403 (
3404 riid == IID_IUnknown ||
3405 riid == IID_IDispatch ||
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
3422 {
3423 return Outer()->addRef();
3424 }
3425
3427 {
3428 return Outer()->release();
3429 }
3430
3431 /* IDispatch */
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 }
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 */
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];
3549
3550 if(cchPathLen == 0)
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 */
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
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
3607public:
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
3650 {
3651 assert(m_clientUI);
3652 return m_clientUI;
3653 }
3654
3655 /* Glue for rdesktop-core */
3656public:
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
3699private:
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
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
3756private:
3758 {
3759 static_cast<RdpClient *>(lpParam)->ProtocolLoop();
3760 return 0;
3761 }
3762
3764 {
3765 }
3766
3767 // FIXME: various potential inconsistencies due to lack of detailed documentation of expected semantics
3769 {
3770 HANDLE waitingReconnection = NULL;
3771
3772 // Retrieve the local hostname to be passed to the server
3774 DWORD hostnameLen = ARRAYSIZE(hostname);
3775
3776 if(!GetComputerNameW(hostname, &hostnameLen))
3777 hostname[0] = 0;
3778
3779 // Set some connection flags
3781
3782 if(m_Compress)
3784
3785 if(m_AudioRedirectionMode == 1)
3787
3788 if(m_ClearTextPassword)
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 {
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
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
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
3957l_Disconnect:
3958 // Disconnected
3959 FireDisconnected(m_protocolState.disconnect_reason);
3960
3961 if(overallConnectionTimer)
3962 CloseHandle(overallConnectionTimer);
3963 }
3964
3966 {
3967 assert(m_protocolThread);
3968 WaitForSingleObject(m_protocolThread, INFINITE);
3969 CloseHandle(m_protocolThread);
3970 m_protocolThread = NULL;
3971 }
3972
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
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
4016public:
4017 /* Startup initialization */
4018 static BOOL Startup()
4019 {
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();
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
4062private:
4063 /* Connection point enumerator */
4065 {
4066 private:
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
4085 {
4086 assert(m_cp);
4087 m_cp->Release();
4088 }
4089
4091 {
4093 {
4094 *ppvObject = this;
4095 return S_OK;
4096 }
4097 else
4098 {
4099 *ppvObject = NULL;
4100 return E_NOINTERFACE;
4101 }
4102 }
4103
4105 {
4106 return InterlockedIncrement(&m_refCount);
4107 }
4108
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
4149 {
4150 m_done = false;
4151 return S_OK;
4152 }
4153
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... */
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
4200
4201 RECT textRect = clientRect;
4202
4203 DrawTextW
4204 (
4205 hdc,
4206 text,
4207 -1,
4208 &textRect,
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;
4220 textRect.top = (clientRect.bottom - textRect.bottom) / 2;
4222
4223 DrawTextW
4224 (
4225 hdc,
4226 text,
4227 -1,
4228 &textRect,
4230 );
4231
4232 EndPaint(m_controlWindow, &ps);
4233 }
4234
4235 return 0;
4236
4237 default:
4238 {
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
4252 {
4253 if(uMsg == WM_CREATE)
4254 {
4256 (
4257 hwnd,
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
4270 {
4271 m_controlWindow = CreateWindow
4272 (
4273 TEXT("MissTosca_Control"),
4274 NULL,
4280 hwndParent,
4281 NULL,
4283 this
4284 );
4285
4286 if(m_controlWindow == NULL)
4288
4289 m_UIParentWindowHandle = m_controlWindow;
4290 return S_OK;
4291 }
4292
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
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
4375 (
4376 m_controlWindow,
4377 NULL,
4378 lprcPosRect->left,
4379 lprcPosRect->top,
4380 lprcPosRect->right - lprcPosRect->left,
4381 lprcPosRect->bottom - lprcPosRect->top,
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
4415public:
4416 /* IUnknown */
4417 /*
4418 NOTE: this is the delegating implementation, to support aggregation. The actual
4419 implementation is RdpClientInner, above
4420 */
4422 {
4423 return m_punkOuter->QueryInterface(riid, ppvObject);
4424 }
4425
4427 {
4428 return m_punkOuter->AddRef();
4429 }
4430
4432 {
4433 return m_punkOuter->Release();
4434 }
4435
4436 /* IDispatch */
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 */
4482 {
4483 if(pIID == NULL)
4484 return E_POINTER;
4485
4486 *pIID = MSTSCLib::DIID_IMsTscAxEvents;
4487 return S_OK;
4488 }
4489
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 {
4503
4504 if(FAILED(pUnkSink->QueryInterface(&sink)))
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)
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
4566 {
4567 // I see no real value in this
4568 return E_NOTIMPL;
4569 }
4570
4571 /* IConnectionPointContainer */
4573 {
4574 *ppEnum = new CEnumConnectionPoints(this);
4575
4576 if(*ppEnum == NULL)
4577 return E_OUTOFMEMORY;
4578
4579 return S_OK;
4580 }
4581
4583 {
4584 if(riid != MSTSCLib::DIID_IMsTscAxEvents)
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
4630 {
4631 return E_NOTIMPL;