ReactOS  0.4.13-dev-249-gcba1a2f
activex.cpp
Go to the documentation of this file.
1 #include "stdafx.h"
2 
3 namespace MSTSCLib
4 {
5 #include "mstsclib_h.h"
6 };
7 
8 namespace MSTSCLib_Redist
9 {
10 // extremely ew, but actually the cleanest way to import the alternate UUIDs
11 #include "mstsclib_redist_i.c"
12 };
13 
14 #include "rdesktop/rdesktop.h"
15 #include "rdesktop/proto.h"
16 
17 namespace
18 {
19 #ifdef _MSC_VER
20 extern "C" char __ImageBase;
21 #endif
22 
24 {
25  return reinterpret_cast<HMODULE>(&__ImageBase);
26 }
27 
28 }
29 
30 namespace
31 {
32 
34 
35 void lockServer()
36 {
38 }
39 
41 {
43 }
44 
46 {
47  return g_moduleRefCount == 0;
48 }
49 
50 }
51 
52 namespace
53 {
54 
55 void FreeLpsz(LPSTR lpsz)
56 {
57  if(lpsz)
58  delete[] lpsz;
59 }
60 
61 LPSTR AllocLpsz(const CHAR * lpsz, size_t cb)
62 {
63  LPSTR lpszNew = new CHAR[cb + 1];
64 
65  if(lpszNew == NULL)
66  return NULL;
67 
68  CopyMemory(lpszNew, lpsz, cb);
69  lpszNew[cb] = 0;
70 
71  return lpszNew;
72 }
73 
74 LPSTR AllocLpsz(const WCHAR * lpwsz, int cchIn)
75 {
76  int cch = WideCharToMultiByte(CP_ACP, 0, lpwsz, cchIn, NULL, 0, NULL, NULL);
77 
78  if(cch <= 0)
79  return NULL;
80 
81  LPSTR lpsz = new CHAR[cch];
82 
83  if(lpsz == NULL)
84  return NULL;
85 
86  cch = WideCharToMultiByte(CP_ACP, 0, lpwsz, cchIn, lpsz, cch, NULL, NULL);
87 
88  if(cch <= 0)
89  {
90  FreeLpsz(lpsz);
91  return NULL;
92  }
93 
94  return lpsz;
95 }
96 
98 {
99  return AllocLpsz(bstr, SysStringLen(bstr));
100 }
103 {
104  int cch = MultiByteToWideChar(CP_ACP, 0, lpsz, -1, NULL, 0);
105 
106  if(cch <= 0)
107  return NULL;
108 
109  BSTR bstr = SysAllocStringLen(NULL, cch);
110 
111  if(bstr == NULL)
112  return NULL;
114  cch = MultiByteToWideChar(CP_ACP, 0, lpsz, -1, bstr, cch);
115 
116  if(cch <= 0)
117  {
118  SysFreeString(bstr);
119  return NULL;
120  }
121 
122  return bstr;
123 }
124 
125 }
126 
127 namespace
128 {
129 
130 template<class T, class U> T aligndown(const T& X, const U& align)
131 {
132  return X & ~(T(align) - 1);
133 }
134 
135 template<class T, class U> T alignup(const T& X, const U& align)
136 {
137  return aligndown(X + (align - 1), align);
138 }
139 
140 /* Convert between bitmap formats */
141 uint8 * win32_convert_scanlines(int width, int height, int bitcount, int fromalign, int toalign, const uint8 * data, uint8 ** buffer)
142 {
143  // TBD: profile & optimize the most common cases
144  assert(width > 0);
145  assert(height);
146  assert(bitcount && bitcount <= 32);
147  assert(fromalign <= toalign);
148  assert(data);
149  assert(buffer);
150 
151  bool flipped = height < 0;
152 
153  if(flipped)
154  height = - height;
155 
156  int bytesperrow = alignup(width * bitcount, 8) / 8;
157  int fromstride = alignup(bytesperrow, fromalign);
158  int tostride = alignup(bytesperrow, toalign);
159  assert(fromstride <= tostride);
160 
161  int datasize = tostride * height;
162 
163  uint8 * dibits = new uint8[datasize];
164 
165  const uint8 * src = data;
166  uint8 * dest = dibits;
167 
168  const int pad = tostride - fromstride;
169 
170  assert(pad < 4);
171  __assume(pad < 4);
172 
173  if(flipped)
174  {
175  dest += (height - 1) * tostride;
176  tostride = - tostride;
177  }
178 
179  for(int i = 0; i < height; ++ i)
180  {
181  memcpy(dest, src, fromstride);
182  memset(dest + fromstride, 0, pad);
183  src += fromstride;
184  dest += tostride;
185  }
186 
187  *buffer = dibits;
188  return dibits;
189 }
190 
191 /* Creates bitmaps */
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 }
239 /* Creates brushes */
240 HBRUSH win32_create_brush(BRUSH * brush, COLORREF fgcolour)
241 {
242  if(brush == NULL)
243  return (HBRUSH)GetStockObject(NULL_BRUSH);
245  switch(brush->style)
246  {
247  case BS_SOLID:
248  case BS_NULL:
252  break;
254  default:
255  return NULL;
256  }
258  switch(brush->style)
259  {
260  case BS_SOLID:
261  return CreateSolidBrush(fgcolour);
264  return CreateHatchBrush(brush->pattern[0], fgcolour);
266  case BS_NULL:
267  return (HBRUSH)GetStockObject(NULL_BRUSH);
268 
269  case BS_PATTERN:
271  {
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 {
302 public:
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 
312 public:
313  static BOOL Startup()
314  {
315  WNDCLASSEX wcexUI = { sizeof(wcexUI) };
316  WNDCLASSEX wcexConsole = { sizeof(wcexConsole) };
317  WNDCLASSEX wcexDisplay = { sizeof(wcexDisplay) };
318  WNDCLASSEX wcexInput = { sizeof(wcexInput) };
319 
320  HBRUSH nullBrush = (HBRUSH)GetStockObject(HOLLOW_BRUSH);
321 
322  wcexUI.lpfnWndProc = NULL; // TODO
323  wcexUI.hInstance = GetCurrentModule();
324  wcexUI.hCursor = LoadCursor(NULL, IDC_ARROW);
325  wcexUI.hbrBackground = nullBrush;
326  wcexUI.lpszClassName = TEXT("MissTosca_UI");
327 
328  wcexConsole.style = CS_VREDRAW | CS_HREDRAW;
329  wcexConsole.lpfnWndProc = NULL; // TODO
330  wcexConsole.hInstance = GetCurrentModule();
331  wcexConsole.hCursor = LoadCursor(NULL, IDC_ARROW);
332  wcexConsole.hbrBackground = nullBrush;
333  wcexConsole.lpszClassName = TEXT("MissTosca_Console");
334 
335  wcexDisplay.style = CS_VREDRAW | CS_HREDRAW;
336  wcexDisplay.lpfnWndProc = NULL; // TODO
337  wcexDisplay.hInstance = GetCurrentModule();
338  wcexDisplay.hCursor = LoadCursor(NULL, IDC_ARROW);
339  wcexDisplay.hbrBackground = nullBrush;
340  wcexDisplay.lpszClassName = TEXT("MissTosca_Display");
341 
342  wcexInput.style = CS_VREDRAW | CS_HREDRAW;
343  wcexInput.lpfnWndProc = NULL; // TODO
344  wcexInput.hInstance = GetCurrentModule();
345  wcexInput.hCursor = NULL;
346  wcexInput.hbrBackground = nullBrush;
347  wcexInput.lpszClassName = TEXT("MissTosca_Input");
348 
349  return
350  RegisterClassEx(&wcexUI) &&
351  RegisterClassEx(&wcexConsole) &&
352  RegisterClassEx(&wcexDisplay) &&
353  RegisterClassEx(&wcexInput);
354  }
355 
356  static void Shutdown()
357  {
358  // TODO
359  }
360 
361  /*
362  This is the main UI window. It's the direct child of the control
363  window, it fills its whole extent and it contains the scrollbars.
364  When activated, it will move keyboard focus to the input window
365  */
366 private:
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  {
393  if(IsIconic(m_uiWindow))
394  break;
395 
396  RECT rcClient;
397  GetWindowRect(m_uiWindow, &rcClient);
398 
399  if(m_smartSizing)
400  {
401  // we are not supposed to maintain aspect ratio. Container has to do that
402  m_consoleX = 0;
403  m_consoleY = 0;
404  m_consoleWidth = rcClient.right;
405  m_consoleHeight = rcClient.bottom;
406  }
407  else
408  {
409  // center horizontally, no horizontal scrollbar
410  if(rcClient.right >= m_consoleWidth)
411  m_consoleX = (m_consoleWidth - rcClient.right) / 2;
412 
413  // center vertically, no vertical scrollbar
414  if(rcClient.bottom >= m_consoleHeight)
415  m_consoleY = (m_consoleHeight - rcClient.right) / 2;
416  }
417 
418  SCROLLINFO scroll = { sizeof(scroll), SIF_ALL, 0 };
419 
420  // update the horizontal scrollbar
421  scroll.nMax = m_consoleWidth;
422  scroll.nPage = rcClient.right;
423  scroll.nPos = 0 - m_consoleX;
424  SetScrollInfo(m_uiWindow, SB_HORZ, &scroll, TRUE);
425 
426  // update the vertical scrollbar
427  scroll.nMax = m_consoleHeight;
428  scroll.nPage = rcClient.bottom;
429  scroll.nPos = 0 - m_consoleY;
430  SetScrollInfo(m_uiWindow, SB_VERT, &scroll, TRUE);
431 
432  // move/resize the console window
434  }
435 
436  return 0;
437 
438  case WM_HSCROLL:
439  {
440  SCROLLINFO scroll = { sizeof(scroll), SIF_TRACKPOS };
441  GetScrollInfo(m_uiWindow, SB_HORZ, &scroll);
442  m_consoleX = - scroll.nTrackPos;
444  }
445 
446  return 0;
447 
448  case WM_VSCROLL:
449  {
450  SCROLLINFO scroll = { sizeof(scroll), SIF_TRACKPOS };
451  GetScrollInfo(m_uiWindow, SB_VERT, &scroll);
452  m_consoleY = - scroll.nTrackPos;
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  */
477 private:
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  }
498  return 0;
499 
500  default:
501  break;
502  }
504  return DefWindowProc(m_consoleWindow, uMsg, wParam, lParam);
505  }
506 
507  /*
508  This is the display window. It represents the virtual display of the
509  remote computer. It completely fills its parent, the console window,
510  and it runs in its own thread for performance reasons
511  */
512 private:
524 
526  {
527  switch(uMsg)
528  {
529  case WM_DESTROY:
530  PostQuitMessage(0);
531  return 0;
532 
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  {
557  (
558  hdc,
559  ps.rcPaint.left,
561  ps.rcPaint.right - ps.rcPaint.left,
562  ps.rcPaint.bottom - ps.rcPaint.top,
565  ps.rcPaint.top,
566  SRCCOPY
567  );
568  }
569  else
570  {
571  // bleh. There has to be a better way
573 
574  StretchBlt
575  (
577  0,
578  0,
582  0,
583  0,
586  SRCCOPY
587  );
588  }
589 
591  }
594  }
595 
596  return 0;
597 
598  default:
599  break;
600  }
601 
602  return DefWindowProc(m_displayWindow, uMsg, wParam, lParam);
603  }
605  /* Screen repainting */
607  {
609  return Display_RepaintAll();
610 
611  RECT rcDamage;
613  InvalidateRect(m_displayWindow, &rcDamage, FALSE);
614  }
615 
616  void Display_RepaintArea(int x, int y, int cx, int cy)
617  {
618  if(m_smartSizing)
619  return Display_RepaintAll();
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  }
629  void Display_RepaintPolygon(POINT * point, int npoints, int linewidth)
630  {
631  if(m_smartSizing)
633 
634  RECT rcDamage;
635 
636  rcDamage.left = MAXLONG;
637  rcDamage.top = MAXLONG;
638  rcDamage.right = 0;
639  rcDamage.bottom = 0;
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 
665 public:
666  void Display_SetClip(int x, int y, int cx, int cy)
667  {
670  m_displayBufferClip.right = x + cx + 1;
671  m_displayBufferClip.bottom = y + cy + 1;
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  {
749  HGDIOBJ hOld = SelectObject(hdcSrc, src);
750 
751  BitBlt(m_displayBuffer, x, y, cx, cy, hdcSrc, srcx, srcy, MAKELONG(0, opcode));
752 
753  SelectObject(hdcSrc, hOld);
754  DeleteDC(hdcSrc);
755 
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
763  HGDIOBJ hOld = SelectObject(hdcSrc, src);
764 
765  //SELECT_BRUSH(brush, bgcolour, fgcolour);
766 
767  BitBlt(m_displayBuffer, x, y, cx, cy, hdcSrc, srcx, srcy, MAKELONG(0, opcode));
768 
769  //RESET_BRUSH();
770 
771  SelectObject(hdcSrc, hOld);
772  DeleteDC(hdcSrc);
773 
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  }
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);
847  SetPolyFillMode(m_displayBuffer, fillmode);
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  }
868  HPEN hpen = CreatePen(pen->style, pen->width, pen->colour);
869 
870  int dcsave = SaveDC(m_displayBuffer);
872  SetROP2(m_displayBuffer, opcode);
874 
875  Polyline(m_displayBuffer, points, npoints);
876 
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
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  }
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 
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 
982  if(flags & TEXT2_IMPLICIT_X)
983  x += glyph->width;
984  }
985  }
986 
987  void Display_DrawText
988  (
989  uint8 font,
990  uint8 flags,
991  uint8 opcode,
992  int mixmode,
993  int x,
994  int y,
995  int clipx,
996  int clipy,
997  int clipcx,
998  int clipcy,
999  int boxx,
1000  int boxy,
1001  int boxcx,
1002  int boxcy,
1003  BRUSH * brush,
1004  int bgcolour,
1005  int fgcolour,
1007  uint8 length
1008  )
1009  {
1010  int i, j;
1011  DATABLOB *entry;
1012 
1013  HBRUSH hbr = CreateSolidBrush(bgcolour);
1014  HGDIOBJ holdbrush = SelectObject(m_displayBuffer, hbr);
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);
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);
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 
1140  Display_RepaintArea(x, y, cx, cy);
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 
1237 public:
1238 };
1239 
1240 #pragma warning(push)
1241 #pragma warning(disable: 4584)
1242 
1243 /* The ActiveX control */
1244 class RdpClient SEALED_:
1245  /* COM basics */
1246  public IUnknown,
1247  public IDispatch,
1248 
1249  /* ActiveX stuff */
1251  public IDataObject,
1252  public IObjectSafety,
1253  public IOleControl,
1254  public IOleInPlaceActiveObject,
1255  public IOleInPlaceObject,
1256  public IOleObject,
1257  public IOleWindow,
1258  public IPersist,
1259  public IPersistPropertyBag,
1260  public IPersistStorage,
1261  public IPersistStreamInit,
1262  public IProvideClassInfo,
1263  public IProvideClassInfo2,
1264  public IQuickActivate,
1265  public IViewObject,
1266  public IViewObject2,
1267 
1268  // NOTE: the original has a vestigial, non-functional implementation of this, which we omit
1269  // ISpecifyPropertyPages
1270 
1271  // Hidden interfaces, not available through QueryInterface
1272  public IConnectionPoint,
1274  /* RDP client interface */
1275  public MSTSCLib::IMsRdpClient4,
1277 
1278  // NOTE: implemented by inner classes due to requiring distinct IDispatch implementations
1279  // IMsRdpClientAdvancedSettings4
1280  // IMsRdpClientSecuredSettings
1281 {
1282 private:
1283  /* An endless amount of COM glue */
1284  // Reference counting
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
1299  class RdpClientInner: public IUnknown
1300  {
1301  private:
1302  RdpClient * Outer()
1303  {
1304  return InnerToOuter(this);
1305  }
1307  public:
1309  {
1310  return Outer()->queryInterface(riid, ppvObject);
1311  }
1312 
1314  {
1315  return Outer()->addRef();
1316  }
1317 
1319  {
1320  return Outer()->release();
1321  }
1323  }
1324  m_inner;
1325 
1326  // Persistence support
1328 
1329  // Late binding support
1330  unsigned m_typeLibIndex;
1333 
1334  // Event sinks
1336 
1337  union
1338  {
1339  MSTSCLib::IMsTscAxEvents * m_EventSinksStatic[1];
1341  };
1343  // OLE control glue
1346  IOleInPlaceSite * m_inPlaceSite;
1350 
1351  // UrlMon security
1353 
1354  bool IsSafeForScripting() const
1355  {
1356  return m_SafetyOptions & INTERFACESAFE_FOR_UNTRUSTED_CALLER;
1357  }
1359  /* Glue to interface to rdesktop-core */
1362  HANDLE m_protocolThread;
1366  bool m_loggedIn;
1367 
1368  /* Properties */
1369  // Storage fields
1370  // NOTE: keep sorted by alignment (pointers and handles, integers, enumerations, booleans)
1374  BSTR m_ConnectingText;
1378  BSTR m_ConnectedStatusText;
1379  BSTR m_ClearTextPassword; // FIXME! dangerous, shouldn't store in cleartext!
1382  BSTR m_RdpdrClipPasteInfoString;
1386  // TODO: plugin DLLs
1390  long m_StartConnected;
1394  long m_TransportType;
1398  long m_HotKeyAltEsc;
1408  long m_brushSupportLevel;
1417  long m_BitmapVirtualCache16BppSize;
1421  unsigned int m_AuthenticationLevel;
1422 
1424 
1425  bool m_Connected;
1429  bool m_ContainerHandledFullScreen;
1433  bool m_AcceleratorPassthrough;
1437  bool m_DisableCtrlAltDel;
1441  bool m_ScaleBitmapCachesByBpp;
1444  bool m_SmartSizing; // FIXME: this can be set while the control is connected
1450  bool m_RedirectPorts;
1455  bool m_ConnectionBarShowMinimizeButton;
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));
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 
1527  HRESULT SetProperty(LPSTR& prop, BSTR newValue)
1528  {
1529  assert(InsideApartment());
1530 
1531  if(m_Connected)
1532  return E_FAIL;
1533 
1534  delete[] prop;
1535 
1536  if(SysStringLen(newValue))
1537  {
1538  prop = BstrToLpsz(newValue);
1539 
1540  if(prop == NULL)
1541  return E_OUTOFMEMORY;
1542  }
1543  else
1544  prop = NULL;
1545 
1546  return S_OK;
1547  }
1548 
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 
1626 
1627  params.rgvarg = rgvarg;
1628  params.rgdispidNamedArgs = NULL;
1629  params.cArgs = cArgs;
1630  params.cNamedArgs = 0;
1631 
1632  MSTSCLib::IMsTscAxEvents ** sinks = GetSinks();
1633 
1634  for(size_t i = 0; i < m_EventSinksCount; ++ i)
1635  sinks[i]->Invoke(eventId, IID_NULL, 0, DISPATCH_METHOD, &params, retval, NULL, NULL);
1636  }
1637 
1638  typedef void (RdpClient::* AsyncEventCallback)
1639  (
1640  DISPID eventId,
1641  VARIANTARG * rgvarg,
1642  unsigned int cArgs,
1643  VARIANTARG * retVal
1644  );
1645 
1646  void CleanupEventArgumentsCallback
1647  (
1648  DISPID eventId,
1649  VARIANTARG * rgvarg,
1650  unsigned int cArgs,
1651  VARIANTARG * retVal
1652  )
1653  {
1654  assert((rgvarg == NULL) == (cArgs == 0));
1655 
1656  for(unsigned int i = 0; i < cArgs; ++ i)
1657  VariantClear(&rgvarg[i]);
1658 
1659  if(retVal)
1660  VariantClear(retVal);
1661  }
1662 
1663  // synchronous call from inside the apartment that owns the object
1664  void FireEventInsideApartment
1665  (
1666  DISPID eventId,
1667  VARIANTARG * rgvarg = NULL,
1668  unsigned int cArgs = 0,
1669  VARIANTARG * retval = NULL,
1670  AsyncEventCallback callback = NULL
1671  )
1672  {
1673  assert(InsideApartment());
1674 
1675  if(retval == NULL && callback)
1676  {
1677  VARIANTARG localRetval = { };
1678  retval = &localRetval;
1679  }
1680 
1681  InvokeSinks(eventId, rgvarg, cArgs, retval);
1682 
1683  if(callback)
1684  (this->*callback)(eventId, rgvarg, cArgs, retval);
1685  }
1686 
1687  struct EventArguments
1688  {
1691  unsigned int cArgs;
1693  AsyncEventCallback callback;
1694  };
1695 
1697  {
1700  wchar_t * server;
1702  char * cookie;
1704  wchar_t * username;
1705  uint32 domain_len;
1706  wchar_t * domain;
1708  wchar_t * password;
1709  };
1710 
1711  enum
1712  {
1713  RDPC_WM_ = WM_USER,
1719  };
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:
1734  assert(InSendMessage());
1735 
1736  case RDPC_WM_ASYNC_EVENT:
1737  {
1738  const EventArguments * eventArgs = reinterpret_cast<EventArguments *>(lParam);
1739  assert(eventArgs);
1741  FireEventInsideApartment
1742  (
1743  eventArgs->eventId,
1744  eventArgs->rgvarg,
1745  eventArgs->cArgs,
1746  eventArgs->retval,
1747  eventArgs->callback
1748  );
1749 
1750  if(uMsg == RDPC_WM_ASYNC_EVENT)
1751  delete eventArgs;
1752  }
1753 
1754  break;
1755 
1756  /* The protocol thread is about to die: prepare for disconnection */
1757  case RDPC_WM_DISCONNECT:
1758  {
1759  assert(m_Connected);
1760  assert(InsideApartment());
1761  assert(InSendMessage());
1762 
1763  // Unblock the protocol thread and wait for it to terminate
1765  JoinProtocolThread();
1766 
1767  // Finish disconnecting
1768  PerformDisconnect(static_cast<long>(wParam));
1769  }
1770 
1771  break;
1772 
1773  case RDPC_WM_REDIRECT:
1774  {
1775  assert(InSendMessage());
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;
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;
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));
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
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  }
1852  break;
1853 
1854  // BUGBUG: this could potentially disconnect an unrelated connection established later...
1855  case RDPC_WM_REQUEST_CLOSE:
1856  {
1857  assert(!InSendMessage());
1858 
1859  if(m_Connected)
1860  {
1861  // Ask confirmation to the container in case we are logged in
1862  if(m_loggedIn && !FireConfirmClose())
1863  break;
1864 
1865  // For reentrancy (OnConfirmClose could deviously call Disconnect)
1866  if(m_protocolThread == NULL)
1867  break;
1869  // Terminate the protocol thread. It will fire the Disconnected event on exit
1870  TerminateProtocolThread();
1871  }
1872  }
1874  break;
1875 
1876  default:
1877  return false;
1878  }
1879 
1880  // If the calling thread is blocked, unblock it ASAP
1883 
1884  return true;
1885  }
1886 
1887  // synchronous call from outside the apartment
1888  void FireEventOutsideApartment
1889  (
1890  DISPID eventId,
1891  VARIANTARG * rgvarg = NULL,
1892  unsigned int cArgs = 0,
1893  VARIANTARG * retval = NULL,
1894  AsyncEventCallback callback = NULL
1895  )
1896  {
1897  assert(!InsideApartment());
1898  EventArguments syncEvent = { eventId, rgvarg, cArgs, retval, callback };
1899  SendMessage(m_controlWindow, RDPC_WM_SYNC_EVENT, 0, reinterpret_cast<LPARAM>(&syncEvent));
1900  }
1901 
1902  // asynchronous call from outside the apartment
1903  HRESULT FireEventOutsideApartmentAsync
1904  (
1905  DISPID eventId,
1906  VARIANTARG * rgvarg = NULL,
1907  unsigned int cArgs = 0,
1908  VARIANTARG * retval = NULL,
1909  AsyncEventCallback callback = NULL
1910  )
1911  {
1912  assert(!InsideApartment());
1913 
1914  EventArguments * asyncEvent = new EventArguments();
1915 
1916  if(asyncEvent == NULL)
1917  return E_OUTOFMEMORY;
1918 
1919  asyncEvent->eventId = eventId;
1920  asyncEvent->rgvarg = rgvarg;
1921  asyncEvent->cArgs = cArgs;
1922  asyncEvent->retval = NULL;
1923 
1924  if(!PostMessage(m_controlWindow, RDPC_WM_ASYNC_EVENT, 0, reinterpret_cast<LPARAM>(asyncEvent)))
1925  {
1926  delete asyncEvent;
1927  return HRESULT_FROM_WIN32(GetLastError());
1928  }
1929 
1930  return S_OK;
1931  }
1932 
1933  // Specific events
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 
2080  bool FireConfirmClose()
2081  {
2082  VARIANTARG retval = { };
2083  VARIANT_BOOL allowClose = VARIANT_TRUE;
2084 
2085  retval.vt = VT_BYREF | VT_BOOL;
2086  retval.pboolVal = &allowClose;
2087 
2088  // Source: control
2089  FireEventInsideApartment(15, NULL, 0, &retval);
2090 
2091  return allowClose != VARIANT_FALSE;
2092  }
2093 
2094  HRESULT FireReceivedTSPublicKey(void * publicKey, unsigned int publicKeyLength)
2095  {
2096  assert(m_Connected);
2097 
2098  if(!m_NotifyTSPublicKey)
2099  return S_OK;
2100 
2101  BSTR bstrPublicKey = SysAllocStringByteLen(NULL, publicKeyLength);
2102 
2103  if(bstrPublicKey == NULL)
2104  return E_OUTOFMEMORY;
2105 
2106  CopyMemory(bstrPublicKey, publicKey, publicKeyLength);
2107 
2108  VARIANT_BOOL continueLogon = VARIANT_TRUE;
2109  VARIANTARG arg = { };
2110  VARIANTARG retval = { };
2111 
2112  arg.vt = VT_BSTR;
2113  arg.bstrVal = bstrPublicKey;
2114 
2115  retval.vt = VT_BYREF | VT_BOOL;
2116  retval.pboolVal = &continueLogon;
2118  // Source: protocol
2119  FireEventOutsideApartment(16, &arg, 1, &retval);
2120 
2121  return continueLogon ? S_OK : S_FALSE;
2122  }
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  }
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);
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);
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);
2203  pvObject = static_cast<IMsRdpClient3 *>(this);
2204  else if(riid == IID_IMsRdpClient4)
2205  pvObject = static_cast<IMsRdpClient4 *>(this);
2207  pvObject = static_cast<IMsTscNonScriptable *>(this);
2209  pvObject = static_cast<IMsRdpClientNonScriptable *>(this);
2211  pvObject = static_cast<IMsRdpClientNonScriptable2 *>(this);
2212 
2213  *ppvObject = pvObject;
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  }
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 
2415  class AdvancedSettings SEALED_: public MSTSCLib::IMsRdpClientAdvancedSettings4
2416  {
2417  private:
2418  RdpClient * Outer()
2419  {
2420  return InnerToOuter(this);
2421  }
2422 
2423  const RdpClient * Outer() const
2424  {
2425  return InnerToOuter(this);
2426  }
2427 
2428  /* IDispatch type information */
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 
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  }
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  }
2586  virtual STDMETHODIMP IMsTscAdvancedSettings::put_PluginDlls(BSTR rhs)
2587  {
2588  // TODO: split rhs into an array
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  }
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  }
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  }
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  }
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  }
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  }
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  }
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  }
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  }
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  }
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  }
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  }
3165  virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_LoadBalanceInfo(BSTR pLBInfo)
3166  {
3167  return Outer()->SetProperty(Outer()->m_LoadBalanceInfo, pLBInfo);
3168  }
3169 
3170  virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_LoadBalanceInfo(BSTR * pLBInfo) const
3171  {
3172  return Outer()->GetProperty(Outer()->m_LoadBalanceInfo, pLBInfo);
3173  }
3174 
3175  virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_RedirectDrives(VARIANT_BOOL pRedirectDrives)
3176  {
3177  return Outer()->SetProperty(Outer()->m_RedirectDrives, pRedirectDrives);
3178  }
3179 
3180  virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_RedirectDrives(VARIANT_BOOL * pRedirectDrives) const
3181  {
3182  return Outer()->GetProperty(Outer()->m_RedirectDrives, pRedirectDrives);
3183  }
3184 
3185  virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_RedirectPrinters(VARIANT_BOOL pRedirectPrinters)
3186  {
3187  return Outer()->SetProperty(Outer()->m_RedirectPrinters, pRedirectPrinters);
3188  }
3189 
3190  virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_RedirectPrinters(VARIANT_BOOL * pRedirectPrinters) const
3191  {
3192  return Outer()->GetProperty(Outer()->m_RedirectPrinters, pRedirectPrinters);
3193  }
3194 
3195  virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_RedirectPorts(VARIANT_BOOL pRedirectPorts)
3196  {
3197  return Outer()->SetProperty(Outer()->m_RedirectPorts, pRedirectPorts);
3198  }
3199 
3200  virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_RedirectPorts(VARIANT_BOOL * pRedirectPorts) const
3201  {
3202  return Outer()->GetProperty(Outer()->m_RedirectPorts, pRedirectPorts);
3203  }
3204 
3205  virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_RedirectSmartCards(VARIANT_BOOL pRedirectSmartCards)
3206  {
3207  return Outer()->SetProperty(Outer()->m_RedirectSmartCards, pRedirectSmartCards);
3208  }
3209 
3210  virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_RedirectSmartCards(VARIANT_BOOL * pRedirectSmartCards) const
3211  {
3212  return Outer()->GetProperty(Outer()->m_RedirectSmartCards, pRedirectSmartCards);
3213  }
3214 
3215  virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_BitmapVirtualCache16BppSize(long pBitmapVirtualCache16BppSize)
3216  {
3217  if(pBitmapVirtualCache16BppSize < 0 || pBitmapVirtualCache16BppSize > 32)
3218  return E_INVALIDARG;
3219 
3220  return Outer()->SetProperty(Outer()->m_BitmapVirtualCache16BppSize, pBitmapVirtualCache16BppSize);
3221  }
3222 
3223  virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_BitmapVirtualCache16BppSize(long * pBitmapVirtualCache16BppSize) const
3224  {
3225  return Outer()->GetProperty(Outer()->m_BitmapVirtualCache16BppSize, pBitmapVirtualCache16BppSize);
3226  }
3227 
3228  virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_BitmapVirtualCache24BppSize(long pBitmapVirtualCache24BppSize)
3229  {
3230  if(pBitmapVirtualCache24BppSize < 0 || pBitmapVirtualCache24BppSize > 32)
3231  return E_INVALIDARG;
3232 
3233  return Outer()->SetProperty(Outer()->m_BitmapVirtualCache24BppSize, pBitmapVirtualCache24BppSize);
3234  }
3235 
3236  virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_BitmapVirtualCache24BppSize(long * pBitmapVirtualCache24BppSize) const
3237  {
3238  return Outer()->GetProperty(Outer()->m_BitmapVirtualCache24BppSize, pBitmapVirtualCache24BppSize);
3239  }
3240 
3241  virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_PerformanceFlags(long pDisableList)
3242  {
3243  return Outer()->SetProperty(Outer()->m_PerformanceFlags, pDisableList);
3244  }
3245 
3246  virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_PerformanceFlags(long * pDisableList) const
3247  {
3248  return Outer()->GetProperty(Outer()->m_PerformanceFlags, pDisableList);
3249  }
3250 
3251  virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_ConnectWithEndpoint(VARIANT * rhs)
3252  {
3253  // TBD? the Microsoft client implements this, but what does it mean?
3254  return E_NOTIMPL;
3255  }
3256 
3257  virtual STDMETHODIMP IMsRdpClientAdvancedSettings::put_NotifyTSPublicKey(VARIANT_BOOL pfNotify)
3258  {
3259  return Outer()->SetProperty(Outer()->m_NotifyTSPublicKey, pfNotify);
3260  }
3261 
3262  virtual STDMETHODIMP IMsRdpClientAdvancedSettings::get_NotifyTSPublicKey(VARIANT_BOOL * pfNotify) const
3263  {
3264  return Outer()->GetProperty(Outer()->m_NotifyTSPublicKey, pfNotify);
3265  }
3266 
3267  /* IMsRdpClientAdvancedSettings2 */
3268  virtual STDMETHODIMP IMsRdpClientAdvancedSettings2::get_CanAutoReconnect(VARIANT_BOOL * pfCanAutoReconnect) const
3269  {
3270  return E_NOTIMPL; // TODO
3271  }
3272 
3273  virtual STDMETHODIMP IMsRdpClientAdvancedSettings2::put_EnableAutoReconnect(VARIANT_BOOL pfEnableAutoReconnect)
3274  {
3275  return Outer()->SetProperty(Outer()->m_EnableAutoReconnect, pfEnableAutoReconnect);
3276  }
3277 
3278  virtual STDMETHODIMP IMsRdpClientAdvancedSettings2::get_EnableAutoReconnect(VARIANT_BOOL * pfEnableAutoReconnect) const
3279  {
3280  return Outer()->GetProperty(Outer()->m_EnableAutoReconnect, pfEnableAutoReconnect);
3281  }
3282 
3283  virtual STDMETHODIMP IMsRdpClientAdvancedSettings2::put_MaxReconnectAttempts(long pMaxReconnectAttempts)
3284  {
3285  if(pMaxReconnectAttempts < 0 || pMaxReconnectAttempts > 200)
3286  return E_INVALIDARG;
3287 
3288  return Outer()->SetProperty(Outer()->m_MaxReconnectAttempts, pMaxReconnectAttempts);
3289  }
3290 
3291  virtual STDMETHODIMP IMsRdpClientAdvancedSettings2::get_MaxReconnectAttempts(long * pMaxReconnectAttempts) const
3292  {
3293  return Outer()->GetProperty(Outer()->m_MaxReconnectAttempts, pMaxReconnectAttempts);
3294  }
3295 
3296  /* IMsRdpClientAdvancedSettings3 */
3297  virtual STDMETHODIMP IMsRdpClientAdvancedSettings3::put_ConnectionBarShowMinimizeButton(VARIANT_BOOL pfShowMinimize)
3298  {
3299  return Outer()->SetProperty(Outer()->m_ConnectionBarShowMinimizeButton, pfShowMinimize);
3300  }
3301 
3302  virtual STDMETHODIMP IMsRdpClientAdvancedSettings3::get_ConnectionBarShowMinimizeButton(VARIANT_BOOL * pfShowMinimize) const
3303  {
3304  return Outer()->GetProperty(Outer()->m_ConnectionBarShowMinimizeButton, pfShowMinimize);
3305  }
3306 
3307  virtual STDMETHODIMP IMsRdpClientAdvancedSettings3::put_ConnectionBarShowRestoreButton(VARIANT_BOOL pfShowRestore)
3308  {
3309  return Outer()->SetProperty(Outer()->m_ConnectionBarShowRestoreButton, pfShowRestore);
3310  }
3311 
3312  virtual STDMETHODIMP IMsRdpClientAdvancedSettings3::get_ConnectionBarShowRestoreButton(VARIANT_BOOL * pfShowRestore) const
3313  {
3314  return Outer()->GetProperty(Outer()->m_ConnectionBarShowRestoreButton, pfShowRestore);
3315  }
3316 
3317  /* IMsRdpClientAdvancedSettings4 */
3318  virtual STDMETHODIMP IMsRdpClientAdvancedSettings4::put_AuthenticationLevel(unsigned int puiAuthLevel)
3319  {
3320  // TODO: this isn't implemented in rdesktop yet...
3321  return Outer()->SetProperty(Outer()->m_AuthenticationLevel, puiAuthLevel);
3322  }
3323 
3324  virtual STDMETHODIMP IMsRdpClientAdvancedSettings4::get_AuthenticationLevel(unsigned int * puiAuthLevel) const
3325  {
3326  return Outer()->GetProperty(Outer()->m_AuthenticationLevel, puiAuthLevel);
3327  }
3328  }
3329  m_advancedSettings;
3330 
3331  template<class Interface> HRESULT GetAdvancedSettings(Interface ** ppAdvSettings)
3332  {
3333  addRef();
3334  *ppAdvSettings = &m_advancedSettings;
3335  return S_OK;
3336  }
3337 
3338  /* Secured settings wrapper */
3339  friend class SecuredSettings;
3340 
3341  class SecuredSettings SEALED_: public MSTSCLib::IMsRdpClientSecuredSettings
3342  {
3343  private:
3344  RdpClient * Outer()
3345  {
3346  return InnerToOuter(this);
3347  }
3348 
3349  const RdpClient * Outer() const
3350  {
3351  return InnerToOuter(this);
3352  }
3353 
3354  /* IDispatch type information */
3355  ITypeInfo * m_dispTypeInfo;
3356 
3358  {
3359  if(m_dispTypeInfo)
3360  return S_OK;
3361 
3362  HRESULT hr = Outer()->LoadTypeLibrary();
3363 
3364  if(FAILED(hr))
3365  return hr;
3366 
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  }
3528  m_securedSettings;
3529 
3530  template<class Interface> HRESULT GetSecuredSettings(Interface ** ppSecuredSettings)
3531  {
3532  if(!m_SecuredSettingsEnabled)
3533  return E_FAIL;
3534 
3535  addRef();
3536  *ppSecuredSettings = &m_securedSettings;
3537  return S_OK;
3538  }
3539 
3540  /* Type library loading */
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)
3551  return HRESULT_FROM_WIN32(GetLastError());
3552 
3553  if(cchPathLen > ((ARRAYSIZE(szPath) - 1) - 2))
3554  return E_FAIL;
3555 
3556  // Append the resource id of the type library
3557  assert(m_typeLibIndex < 10);
3558 
3559  szPath[cchPathLen + 0] = L'\\';
3560  szPath[cchPathLen + 1] = static_cast<WCHAR>(L'0' + m_typeLibIndex);
3561  szPath[cchPathLen + 2] = 0;
3562 
3563  // Load the type library
3564  HRESULT hr = LoadTypeLibEx(szPath, REGKIND_NONE, &m_typeLib);
3565 
3566  if(FAILED(hr))
3567  return hr;
3568 
3569  assert(m_typeLib);
3570  return S_OK;
3571  }
3572 
3573  /* IDispatch type information */
3575  {
3576  if(m_dispTypeInfo)
3577  return S_OK;
3578 
3579  HRESULT hr = LoadTypeLibrary();
3580 
3581  if(FAILED(hr))
3582  return hr;
3583 
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 
3607 public:
3608  /* Helpers for our various embedded children */
3609  static RdpClient * InnerToOuter(RdpClientInner * innerThis)
3610  {
3611  return CONTAINING_RECORD(innerThis, RdpClient, m_inner);
3612  }
3613 
3614  static RdpClient * InnerToOuter(AdvancedSettings * innerThis)
3615  {
3616  return CONTAINING_RECORD(innerThis, RdpClient, m_advancedSettings);
3617  }
3618 
3619  static RdpClient * InnerToOuter(SecuredSettings * innerThis)
3620  {
3621  return CONTAINING_RECORD(innerThis, RdpClient, m_securedSettings);
3622  }
3623 
3624  static RdpClient * InnerToOuter(RDPCLIENT * innerThis)
3625  {
3626  return CONTAINING_RECORD(innerThis, RdpClient, m_protocolState);
3627  }
3628 
3629  static const RdpClient * InnerToOuter(const RdpClientInner * innerThis)
3630  {
3631  return CONTAINING_RECORD(innerThis, RdpClient, m_inner);
3632  }
3633 
3634  static const RdpClient * InnerToOuter(const AdvancedSettings * innerThis)
3635  {
3636  return CONTAINING_RECORD(innerThis, RdpClient, m_advancedSettings);
3637  }
3638 
3639  static const RdpClient * InnerToOuter(const SecuredSettings * innerThis)
3640  {
3641  return CONTAINING_RECORD(innerThis, RdpClient, m_securedSettings);
3642  }
3644  static const RdpClient * InnerToOuter(const RDPCLIENT * innerThis)
3645  {
3646  return CONTAINING_RECORD(innerThis, RdpClient, m_protocolState);
3647  }
3648 
3649  RdpClientUI * GetUI() const
3650  {
3651  assert(m_clientUI);
3652  return m_clientUI;
3653  }
3654 
3655  /* Glue for rdesktop-core */
3656 public:
3657  static bool OnPublicKey(RDPCLIENT * This, unsigned char * key, unsigned int key_size)
3658  {
3659  return InnerToOuter(This)->OnPublicKey(key, key_size);
3660  }
3661 
3662  static void OnLogon(RDPCLIENT * This)
3663  {
3664  return InnerToOuter(This)->OnLogon();
3665  }
3666 
3667  static bool OnRedirect
3668  (
3669  RDPCLIENT * This,
3670  uint32 flags,
3671  uint32 server_len,
3672  wchar_t * server,
3673  uint32 cookie_len,
3674  char * cookie,
3675  uint32 username_len,
3676  wchar_t * username,
3677  uint32 domain_len,
3678  wchar_t * domain,
3679  uint32 password_len,
3680  wchar_t * password
3681  )
3682  {
3683  return InnerToOuter(This)->OnRedirect
3684  (
3685  flags,
3686  server_len,
3687  server,
3688  cookie_len,
3689  cookie,
3690  username_len,
3691  username,
3692  domain_len,
3693  domain,
3694  password_len,
3695  password
3696  );
3697  }
3698 
3699 private:
3700  bool OnPublicKey(unsigned char * key, unsigned int key_size)
3701  {
3702  HRESULT hr = FireReceivedTSPublicKey(key, key_size);
3703 
3704  if(FAILED(hr))
3705  {
3706  m_protocolState.disconnect_reason = 262;
3707  return false;
3708  }
3709 
3710  return hr == S_OK;
3711  }
3712 
3713  void OnLogon()
3714  {
3715  m_loggedIn = true;
3716  FireLoginComplete();
3717  }
3718 
3719  bool OnRedirect
3720  (
3721  uint32 flags,
3722  uint32 server_len,
3723  wchar_t * server,
3724  uint32 cookie_len,
3725  char * cookie,
3726  uint32 username_len,
3727  wchar_t * username,
3728  uint32 domain_len,
3729  wchar_t * domain,
3730  uint32 password_len,
3731  wchar_t * password
3732  )
3733  {
3734  assert(m_Connected);
3735  assert(!InsideApartment());
3736  assert(IsWindow(m_controlWindow));
3737 
3738  RedirectArguments redirectArgs =
3739  {
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  };
3753  return SendMessage(m_controlWindow, RDPC_WM_REDIRECT, 0, reinterpret_cast<LPARAM>(&redirectArgs)) == 0;
3754  }
3755 
3756 private:
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
3768  void ProtocolLoop()
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)
3785  if(m_AudioRedirectionMode == 1)
3787 
3788  if(m_ClearTextPassword)
3789  flags |= RDP_LOGON_AUTO;
3790 
3791  // Notify the container that the connection process is beginning now
3792  FireConnecting();
3793 
3794  // Set the overall connection timer, if a timeout is set
3795  // BUGBUG: the timeout semantics are ambiguous and have been most probably misinterpreted
3796  HANDLE overallConnectionTimer = NULL;
3797  LARGE_INTEGER overallTimeout;
3798 
3799  if(m_overallConnectionTimeout)
3800  {
3801  overallTimeout.QuadPart = - ((m_overallConnectionTimeout * 1000 * 1000 * 1000) / 100);
3802 
3803  overallConnectionTimer = CreateWaitableTimer(NULL, FALSE, NULL);
3805  if(overallConnectionTimer == NULL)
3806  goto l_Disconnect;
3807  }
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;
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;
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);
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
3861  flags |= RDP_LOGON_AUTO;
3862 
3863  // retry
3864  continue;
3865  }
3866 
3867  // Disconnection
3868  m_ExtendedDisconnectReason = static_cast<MSTSCLib::ExtendedDisconnectReasonCode>(extendedDisconnectReason);
3869 
3870  // Clean disconnection
3871  if(deactivated)
3872  break;
3873 
3874  BOOL success;
3875 
3876  long autoReconnections = 0;
3877  long totalReconnections = 0;
3878 
3879  // Reconnection
3880  // BUGBUG: reconnection semantics may not be entirely accurate
3881  do
3882  {
3883  ++ totalReconnections;
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;
3909  WaitForSingleObject(waitingReconnection, INFINITE);
3910 
3911  m_protocolThreadWaitingReconnection = NULL;
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  }
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  }
3957 l_Disconnect:
3958  // Disconnected
3959  FireDisconnected(m_protocolState.disconnect_reason);
3961  if(overallConnectionTimer)
3962  CloseHandle(overallConnectionTimer);
3963  }
3966  {
3967  assert(m_protocolThread);
3968  WaitForSingleObject(m_protocolThread, INFINITE);
3969  CloseHandle(m_protocolThread);
3970  m_protocolThread = NULL;
3971  }
3974  {
3975  assert(m_protocolThread);
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
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
4009 
4010  arg.vt = VT_I4;
4011  arg.lVal = reason;
4013  FireEventInsideApartment(4, &arg, 1);
4014  }
4015 
4016 public:
4017  /* Startup initialization */
4018  static BOOL Startup()
4019  {
4021  return FALSE;
4022 
4023  WNDCLASSEX wcex = { sizeof(wcex) };
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);
4045  if(obj == NULL)
4046  return E_OUTOFMEMORY;
4047 
4048  HRESULT hr = obj->m_inner.QueryInterface(riid, ppObj);
4049 
4050  if(FAILED(hr))
4051  {
4052  delete obj;
4053  return hr;
4054  }
4055 
4056  assert(obj->m_refCount == 1);
4057  assert(*ppObj != NULL);
4058 
4059  return S_OK;
4060  }
4061 
4062 private:
4063  /* Connection point enumerator */
4064  class CEnumConnectionPoints: public IEnumConnectionPoints
4065  {
4066  private:
4069  bool m_done;
4070 
4071  public:
4072  CEnumConnectionPoints(IConnectionPoint * cp): m_refCount(1), m_cp(cp), m_done(false)
4073  {
4074  assert(m_cp);
4075  m_cp->AddRef();
4076  }
4077 
4078  CEnumConnectionPoints(const CEnumConnectionPoints& ecp): m_refCount(1), m_cp(ecp.m_cp), m_done(ecp.m_done)
4079  {
4080  assert(m_cp);
4081  m_cp->AddRef();
4082  }
4083 
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;
4101  }
4102  }
4103 
4105  {
4106  return InterlockedIncrement(&m_refCount);
4107  }
4110  {
4111  LONG n = InterlockedDecrement(&m_refCount);
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;
4129  return S_OK;
4130  }
4131 
4132  virtual STDMETHODIMP Skip(ULONG cConnections)
4133  {
4134  if(cConnections == 0)
4135  return S_OK;
4137  if(cConnections == 1 && !m_done)
4138  {
4139  m_done = true;
4140  return S_OK;
4141  }
4142 
4143  assert(cConnections > 1 || m_done);
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);
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);
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  {
4239  LRESULT result;
4240 
4241  if(HandleEvent(uMsg, wParam, lParam, result))
4242  return result;
4243  }
4244 
4245  break;
4246  }
4247 
4248  return DefWindowProc(m_controlWindow, uMsg, wParam, lParam);
4249  }
4250 
4252  {
4253  if(uMsg == WM_CREATE)
4254  {
4256  (
4257  hwnd,
4258  GWLP_USERDATA,
4259  (LONG_PTR)reinterpret_cast<LPCREATESTRUCT>(lParam)->lpCreateParams
4260  );
4261  }
4262 
4263  RdpClient * Self = reinterpret_cast<RdpClient *>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
4264  assert(Self);
4265 
4266  return Self->ControlWindowProc(uMsg, wParam, lParam);
4267  }
4268 
4270  {
4271  m_controlWindow = CreateWindow
4272  (
4273  TEXT("MissTosca_Control"),
4274  NULL,
4276  CW_USEDEFAULT,
4277  CW_USEDEFAULT,
4278  CW_USEDEFAULT,
4279  CW_USEDEFAULT,
4280  hwndParent,
4281  NULL,
4282  GetCurrentModule(),
4283  this
4284  );
4285 
4286  if(m_controlWindow == NULL)
4287  return HRESULT_FROM_WIN32(GetLastError());
4288 
4289  m_UIParentWindowHandle = m_controlWindow;
4290  return S_OK;
4291  }
4292 
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 
4374  SetWindowPos
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 
4415 public:
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 
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)))
4505  return CONNECT_E_CANNOTCONNECT;
4506 
4507  MSTSCLib::IMsTscAxEvents ** sinks = GetSinks();
4508  DWORD cookie = 0;
4509 
4510  if(m_EventSinksCount)
4511  {
4512  bool found = false;
4513 
4514  for(size_t i = 0; i < m_EventSinksCount; ++ i)
4515  {
4516  found = (sinks[i] == NULL);
4517 
4518  if(found)
4519  {
4520  cookie = static_cast<DWORD>(i);
4521  break;
4522  }
4523  }
4524 
4525  if(!found)
4526  {
4527  MSTSCLib::IMsTscAxEvents ** newSinks = new MSTSCLib::IMsTscAxEvents *[m_EventSinksCount + 1];
4528 
4529  if(newSinks == NULL)
4530  {
4531  sink->Release();
4532  return E_OUTOFMEMORY;
4533  }
4534 
4535  std::copy(sinks, sinks + m_EventSinksCount, newSinks);
4536 
4537  m_EventSinks = newSinks;
4538  sinks = newSinks;
4539 
4540  cookie = static_cast<DWORD>(m_EventSinksCount);
4541  }
4542  }
4543 
4544  sinks[cookie] = sink;
4545  *pdwCookie = cookie;
4546 
4547  return S_OK;
4548  }
4549 
4550  virtual STDMETHODIMP Unadvise(DWORD dwCookie)
4551  {
4552  MSTSCLib::IMsTscAxEvents ** sinks = GetSinks();
4553 
4554  if(dwCookie >= m_EventSinksCount || sinks[dwCookie] == NULL)
4555  return CONNECT_E_NOCONNECTION;
4556 
4557  sinks[dwCookie]->Release();
4558  sinks[dwCookie] = NULL;
4559 
4560  // BUGBUG: the array currently grows forever. Trim it whenever possible
4561 
4562  return S_OK;
4563  }
4564 
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  {
4585  return CONNECT_E_NOCONNECTION;
4586 
4587  addRef();
4588  *ppCP = this;
4589 
4590  return S_OK;
4591  }
4592 
4593  /* IDataObject */ // 0/9
4594  virtual STDMETHODIMP IDataObject::GetData(FORMATETC * pformatetcIn, STGMEDIUM * pmedium)
4595  {
4596  return E_NOTIMPL;
4597  }
4598 
4599  virtual STDMETHODIMP IDataObject::GetDataHere(FORMATETC * pformatetc, STGMEDIUM * pmedium)
4600  {
4601  return E_NOTIMPL;
4602  }
4603 
4604  virtual STDMETHODIMP IDataObject::QueryGetData(FORMATETC * pformatetc)
4605  {
4606  return E_NOTIMPL;
4607  }
4608 
4609  virtual STDMETHODIMP IDataObject::GetCanonicalFormatEtc(FORMATETC * pformatectIn, FORMATETC * pformatetcOut)
4610  {
4611  return E_NOTIMPL;
4612  }
4613 
4614  virtual STDMETHODIMP IDataObject::SetData(FORMATETC * pformatetc, STGMEDIUM * pmedium, BOOL fRelease)
4615  {
4616  return E_NOTIMPL;
4617  }
4618 
4619  virtual STDMETHODIMP IDataObject::EnumFormatEtc(DWORD dwDirection, IEnumFORMATETC ** ppenumFormatEtc)
4620  {
4621  return E_NOTIMPL;
4622  }
4623 
4624  virtual STDMETHODIMP IDataObject::DAdvise(FORMATETC * pformatetc, DWORD advf, IAdviseSink * pAdvSink, DWORD * pdwConnection)
4625  {
4626  return E_NOTIMPL;
4627  }
4628 
4630  {
4631  return E_NOTIMPL;
4632  }
4633 
4635  {
4636  return E_NOTIMPL;
4637  }
4638 
4639  /* IObjectSafety */
4640  virtual STDMETHODIMP IObjectSafety::GetInterfaceSafetyOptions(REFIID riid, DWORD * pdwSupportedOptions, DWORD * pdwEnabledOptions)
4641  {
4642  if(pdwSupportedOptions == NULL || pdwEnabledOptions == NULL)
4643  return E_POINTER;
4644 
4645  if(riid != IID_IDispatch)
4646  return E_NOINTERFACE;
4647 
4648  *pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
4649  *pdwEnabledOptions = m_SafetyOptions;
4650  return S_OK;
4651  }
4652 
4653  virtual STDMETHODIMP IObjectSafety::SetInterfaceSafetyOptions(REFIID riid, DWORD dwOptionSetMask, DWORD dwEnabledOptions)
4654  {
4655  if(riid != IID_IDispatch)
4656  return E_NOINTERFACE;
4657 
4658  m_SafetyOptions = dwEnabledOptions & (dwOptionSetMask & INTERFACESAFE_FOR_UNTRUSTED_CALLER);
4659  return S_OK;
4660  }
4661 
4662  /* IOleControl */ // 3/4
4664  {
4665  return E_NOTIMPL;
4666  }
4667 
4669  {
4670  return E_NOTIMPL;
4671  }
4672 
4674  {
4675  return S_OK;
4676  }
4677 
4679  {
4680  if(bFreeze)
4681  InterlockedIncrement(&m_freezeEvents);
4682  else if(InterlockedDecrement(&m_freezeEvents) == 0)
4683  UnfreezeEvents();
4684 
4685  return S_OK;
4686  }
4687 
4688  /* IOleInPlaceActiveObject */ // 3/5
4690  {
4691  return E_NOTIMPL;
4692  }
4693 
4695  {
4696  // TODO
4697  return E_NOTIMPL;
4698  }
4699 
4701  {
4702  // TODO
4703  return E_NOTIMPL;
4704  }
4705 
4707  {
4708  return S_OK;
4709  }
4710 
4712  {
4713  return S_OK;
4714  }
4715 
4716  /* IOleInPlaceObject */ // 1/4
4718  {
4719  // TODO: UIDeactivate, destroy window, inplacesite->OnInPlaceDeactivate
4720  return E_NOTIMPL;
4721  }
4722 
4724  {
4725  // TODO
4726  return E_NOTIMPL;
4727  }
4728 
4730  {
4731  if(m_controlWindow == NULL)
4732  return E_FAIL;
4733 
4734  MoveWindow
4735  (
4736  m_controlWindow,
4737  lprcPosRect->left,
4738  lprcPosRect->top,
4739  lprcPosRect->right - lprcPosRect->left,
4740  lprcPosRect->bottom - lprcPosRect->top,
4741  TRUE
4742  );
4743 
4744  SetWindowRgn(m_controlWindow, CreateRectRgnIndirect(lprcClipRect), TRUE);
4745 
4746  return E_NOTIMPL;
4747  }
4748 
4750  {
4751  return E_NOTIMPL;
4752  }
4753 
4754  /* IOleObject */ // 18/21
4756  {
4757  if(m_clientSite)
4758  m_clientSite->Release();
4759 
4760  m_clientSite = pClientSite;
4761 
4762  if(m_clientSite)
4763  m_clientSite->AddRef();
4764 
4765  return S_OK;
4766  }
4767 
4769  {
4770  if(ppClientSite == NULL)
4771  return E_POINTER;
4772 
4773  if(m_clientSite)
4774  m_clientSite->AddRef();
4775 
4776  *ppClientSite = m_clientSite;
4777  return S_OK;
4778  }
4779 
4780  virtual STDMETHODIMP IOleObject::SetHostNames(LPCOLESTR szContainerApp, LPCOLESTR szContainerObj)
4781  {
4782  return S_OK;
4783  }
4784 
4785  virtual STDMETHODIMP IOleObject::Close(DWORD dwSaveOption)
4786  {
4787  // TODO: deactivate, destroy window, release in-place site, release advise sink
4788  return E_NOTIMPL; // TODO
4789  }
4790 
4791  virtual STDMETHODIMP IOleObject::SetMoniker(DWORD dwWhichMoniker, IMoniker * pmk)
4792  {
4793  return E_NOTIMPL;
4794  }
4795 
4796  virtual STDMETHODIMP IOleObject::GetMoniker(DWORD dwAssign, DWORD dwWhichMoniker, IMoni