FreeRDP
wf_rail.c
1 
19 #include <freerdp/config.h>
20 
21 #include <winpr/crt.h>
22 #include <freerdp/log.h>
23 #include <freerdp/client/rail.h>
24 #include <winpr/tchar.h>
25 #include <winpr/print.h>
26 
27 #include "wf_rail.h"
28 
29 #define TAG CLIENT_TAG("windows")
30 
31 #define GET_X_LPARAM(lParam) ((UINT16)(lParam & 0xFFFF))
32 #define GET_Y_LPARAM(lParam) ((UINT16)((lParam >> 16) & 0xFFFF))
33 
34 struct wf_rail_window
35 {
36  wfContext* wfc;
37 
38  HWND hWnd;
39 
40  DWORD dwStyle;
41  DWORD dwExStyle;
42 
43  int x;
44  int y;
45  int width;
46  int height;
47  char* title;
48 };
49 
50 /* RemoteApp Core Protocol Extension */
51 
52 typedef struct
53 {
54  UINT32 style;
55  const char* name;
56  BOOL multi;
57 } WINDOW_STYLE;
58 
59 static const WINDOW_STYLE WINDOW_STYLES[] = { { WS_BORDER, "WS_BORDER", FALSE },
60  { WS_CAPTION, "WS_CAPTION", FALSE },
61  { WS_CHILD, "WS_CHILD", FALSE },
62  { WS_CLIPCHILDREN, "WS_CLIPCHILDREN", FALSE },
63  { WS_CLIPSIBLINGS, "WS_CLIPSIBLINGS", FALSE },
64  { WS_DISABLED, "WS_DISABLED", FALSE },
65  { WS_DLGFRAME, "WS_DLGFRAME", FALSE },
66  { WS_GROUP, "WS_GROUP", FALSE },
67  { WS_HSCROLL, "WS_HSCROLL", FALSE },
68  { WS_ICONIC, "WS_ICONIC", FALSE },
69  { WS_MAXIMIZE, "WS_MAXIMIZE", FALSE },
70  { WS_MAXIMIZEBOX, "WS_MAXIMIZEBOX", FALSE },
71  { WS_MINIMIZE, "WS_MINIMIZE", FALSE },
72  { WS_MINIMIZEBOX, "WS_MINIMIZEBOX", FALSE },
73  { WS_OVERLAPPED, "WS_OVERLAPPED", FALSE },
74  { WS_OVERLAPPEDWINDOW, "WS_OVERLAPPEDWINDOW", TRUE },
75  { WS_POPUP, "WS_POPUP", FALSE },
76  { WS_POPUPWINDOW, "WS_POPUPWINDOW", TRUE },
77  { WS_SIZEBOX, "WS_SIZEBOX", FALSE },
78  { WS_SYSMENU, "WS_SYSMENU", FALSE },
79  { WS_TABSTOP, "WS_TABSTOP", FALSE },
80  { WS_THICKFRAME, "WS_THICKFRAME", FALSE },
81  { WS_VISIBLE, "WS_VISIBLE", FALSE } };
82 
83 static const WINDOW_STYLE EXTENDED_WINDOW_STYLES[] = {
84  { WS_EX_ACCEPTFILES, "WS_EX_ACCEPTFILES", FALSE },
85  { WS_EX_APPWINDOW, "WS_EX_APPWINDOW", FALSE },
86  { WS_EX_CLIENTEDGE, "WS_EX_CLIENTEDGE", FALSE },
87  { WS_EX_COMPOSITED, "WS_EX_COMPOSITED", FALSE },
88  { WS_EX_CONTEXTHELP, "WS_EX_CONTEXTHELP", FALSE },
89  { WS_EX_CONTROLPARENT, "WS_EX_CONTROLPARENT", FALSE },
90  { WS_EX_DLGMODALFRAME, "WS_EX_DLGMODALFRAME", FALSE },
91  { WS_EX_LAYERED, "WS_EX_LAYERED", FALSE },
92  { WS_EX_LAYOUTRTL, "WS_EX_LAYOUTRTL", FALSE },
93  { WS_EX_LEFT, "WS_EX_LEFT", FALSE },
94  { WS_EX_LEFTSCROLLBAR, "WS_EX_LEFTSCROLLBAR", FALSE },
95  { WS_EX_LTRREADING, "WS_EX_LTRREADING", FALSE },
96  { WS_EX_MDICHILD, "WS_EX_MDICHILD", FALSE },
97  { WS_EX_NOACTIVATE, "WS_EX_NOACTIVATE", FALSE },
98  { WS_EX_NOINHERITLAYOUT, "WS_EX_NOINHERITLAYOUT", FALSE },
99  { WS_EX_NOPARENTNOTIFY, "WS_EX_NOPARENTNOTIFY", FALSE },
100  { WS_EX_OVERLAPPEDWINDOW, "WS_EX_OVERLAPPEDWINDOW", TRUE },
101  { WS_EX_PALETTEWINDOW, "WS_EX_PALETTEWINDOW", TRUE },
102  { WS_EX_RIGHT, "WS_EX_RIGHT", FALSE },
103  { WS_EX_RIGHTSCROLLBAR, "WS_EX_RIGHTSCROLLBAR", FALSE },
104  { WS_EX_RTLREADING, "WS_EX_RTLREADING", FALSE },
105  { WS_EX_STATICEDGE, "WS_EX_STATICEDGE", FALSE },
106  { WS_EX_TOOLWINDOW, "WS_EX_TOOLWINDOW", FALSE },
107  { WS_EX_TOPMOST, "WS_EX_TOPMOST", FALSE },
108  { WS_EX_TRANSPARENT, "WS_EX_TRANSPARENT", FALSE },
109  { WS_EX_WINDOWEDGE, "WS_EX_WINDOWEDGE", FALSE }
110 };
111 
112 static void PrintWindowStyles(UINT32 style)
113 {
114  WLog_INFO(TAG, "\tWindow Styles:\t{");
115 
116  for (size_t i = 0; i < ARRAYSIZE(WINDOW_STYLES); i++)
117  {
118  if (style & WINDOW_STYLES[i].style)
119  {
120  if (WINDOW_STYLES[i].multi)
121  {
122  if ((style & WINDOW_STYLES[i].style) != WINDOW_STYLES[i].style)
123  continue;
124  }
125 
126  WLog_INFO(TAG, "\t\t%s", WINDOW_STYLES[i].name);
127  }
128  }
129 }
130 
131 static void PrintExtendedWindowStyles(UINT32 style)
132 {
133  WLog_INFO(TAG, "\tExtended Window Styles:\t{");
134 
135  for (size_t i = 0; i < ARRAYSIZE(EXTENDED_WINDOW_STYLES); i++)
136  {
137  if (style & EXTENDED_WINDOW_STYLES[i].style)
138  {
139  if (EXTENDED_WINDOW_STYLES[i].multi)
140  {
141  if ((style & EXTENDED_WINDOW_STYLES[i].style) != EXTENDED_WINDOW_STYLES[i].style)
142  continue;
143  }
144 
145  WLog_INFO(TAG, "\t\t%s", EXTENDED_WINDOW_STYLES[i].name);
146  }
147  }
148 }
149 
150 static void PrintRailWindowState(const WINDOW_ORDER_INFO* orderInfo,
151  const WINDOW_STATE_ORDER* windowState)
152 {
153  if (orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW)
154  WLog_INFO(TAG, "WindowCreate: WindowId: 0x%08X", orderInfo->windowId);
155  else
156  WLog_INFO(TAG, "WindowUpdate: WindowId: 0x%08X", orderInfo->windowId);
157 
158  WLog_INFO(TAG, "{");
159 
160  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_OWNER)
161  {
162  WLog_INFO(TAG, "\tOwnerWindowId: 0x%08X", windowState->ownerWindowId);
163  }
164 
165  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_STYLE)
166  {
167  WLog_INFO(TAG, "\tStyle: 0x%08X ExtendedStyle: 0x%08X", windowState->style,
168  windowState->extendedStyle);
169  PrintWindowStyles(windowState->style);
170  PrintExtendedWindowStyles(windowState->extendedStyle);
171  }
172 
173  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_SHOW)
174  {
175  WLog_INFO(TAG, "\tShowState: %u", windowState->showState);
176  }
177 
178  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_TITLE)
179  {
180  const WCHAR* str = (const WCHAR*)windowState->titleInfo.string;
181  char* title =
182  ConvertWCharNToUtf8Alloc(str, windowState->titleInfo.length / sizeof(WCHAR), NULL);
183  WLog_INFO(TAG, "\tTitleInfo: %s (length = %hu)", title, windowState->titleInfo.length);
184  free(title);
185  }
186 
187  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET)
188  {
189  WLog_INFO(TAG, "\tClientOffsetX: %d ClientOffsetY: %d", windowState->clientOffsetX,
190  windowState->clientOffsetY);
191  }
192 
193  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE)
194  {
195  WLog_INFO(TAG, "\tClientAreaWidth: %u ClientAreaHeight: %u", windowState->clientAreaWidth,
196  windowState->clientAreaHeight);
197  }
198 
199  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_RP_CONTENT)
200  {
201  WLog_INFO(TAG, "\tRPContent: %u", windowState->RPContent);
202  }
203 
204  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_ROOT_PARENT)
205  {
206  WLog_INFO(TAG, "\tRootParentHandle: 0x%08X", windowState->rootParentHandle);
207  }
208 
209  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET)
210  {
211  WLog_INFO(TAG, "\tWindowOffsetX: %d WindowOffsetY: %d", windowState->windowOffsetX,
212  windowState->windowOffsetY);
213  }
214 
215  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA)
216  {
217  WLog_INFO(TAG, "\tWindowClientDeltaX: %d WindowClientDeltaY: %d",
218  windowState->windowClientDeltaX, windowState->windowClientDeltaY);
219  }
220 
221  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE)
222  {
223  WLog_INFO(TAG, "\tWindowWidth: %u WindowHeight: %u", windowState->windowWidth,
224  windowState->windowHeight);
225  }
226 
227  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS)
228  {
229  RECTANGLE_16* rect;
230  WLog_INFO(TAG, "\tnumWindowRects: %u", windowState->numWindowRects);
231 
232  for (UINT32 index = 0; index < windowState->numWindowRects; index++)
233  {
234  rect = &windowState->windowRects[index];
235  WLog_INFO(TAG, "\twindowRect[%u]: left: %hu top: %hu right: %hu bottom: %hu", index,
236  rect->left, rect->top, rect->right, rect->bottom);
237  }
238  }
239 
240  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET)
241  {
242  WLog_INFO(TAG, "\tvisibileOffsetX: %d visibleOffsetY: %d", windowState->visibleOffsetX,
243  windowState->visibleOffsetY);
244  }
245 
246  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY)
247  {
248  RECTANGLE_16* rect;
249  WLog_INFO(TAG, "\tnumVisibilityRects: %u", windowState->numVisibilityRects);
250 
251  for (UINT32 index = 0; index < windowState->numVisibilityRects; index++)
252  {
253  rect = &windowState->visibilityRects[index];
254  WLog_INFO(TAG, "\tvisibilityRect[%u]: left: %hu top: %hu right: %hu bottom: %hu", index,
255  rect->left, rect->top, rect->right, rect->bottom);
256  }
257  }
258 
259  WLog_INFO(TAG, "}");
260 }
261 
262 static void PrintRailIconInfo(const WINDOW_ORDER_INFO* orderInfo, const ICON_INFO* iconInfo)
263 {
264  WLog_INFO(TAG, "ICON_INFO");
265  WLog_INFO(TAG, "{");
266  WLog_INFO(TAG, "\tbigIcon: %s",
267  (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_ICON_BIG) ? "true" : "false");
268  WLog_INFO(TAG, "\tcacheEntry; 0x%08X", iconInfo->cacheEntry);
269  WLog_INFO(TAG, "\tcacheId: 0x%08X", iconInfo->cacheId);
270  WLog_INFO(TAG, "\tbpp: %u", iconInfo->bpp);
271  WLog_INFO(TAG, "\twidth: %u", iconInfo->width);
272  WLog_INFO(TAG, "\theight: %u", iconInfo->height);
273  WLog_INFO(TAG, "\tcbColorTable: %u", iconInfo->cbColorTable);
274  WLog_INFO(TAG, "\tcbBitsMask: %u", iconInfo->cbBitsMask);
275  WLog_INFO(TAG, "\tcbBitsColor: %u", iconInfo->cbBitsColor);
276  WLog_INFO(TAG, "\tcolorTable: %p", (void*)iconInfo->colorTable);
277  WLog_INFO(TAG, "\tbitsMask: %p", (void*)iconInfo->bitsMask);
278  WLog_INFO(TAG, "\tbitsColor: %p", (void*)iconInfo->bitsColor);
279  WLog_INFO(TAG, "}");
280 }
281 
282 LRESULT CALLBACK wf_RailWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
283 {
284  HDC hDC;
285  int x, y;
286  int width;
287  int height;
288  UINT32 xPos;
289  UINT32 yPos;
290  PAINTSTRUCT ps;
291  UINT32 inputFlags;
292  wfContext* wfc = NULL;
293  rdpInput* input = NULL;
294  rdpContext* context = NULL;
295  wfRailWindow* railWindow;
296  railWindow = (wfRailWindow*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
297 
298  if (railWindow)
299  wfc = railWindow->wfc;
300 
301  if (wfc)
302  context = (rdpContext*)wfc;
303 
304  if (context)
305  input = context->input;
306 
307  switch (msg)
308  {
309  case WM_PAINT:
310  {
311  if (!wfc)
312  return 0;
313 
314  hDC = BeginPaint(hWnd, &ps);
315  x = ps.rcPaint.left;
316  y = ps.rcPaint.top;
317  width = ps.rcPaint.right - ps.rcPaint.left + 1;
318  height = ps.rcPaint.bottom - ps.rcPaint.top + 1;
319  BitBlt(hDC, x, y, width, height, wfc->primary->hdc, railWindow->x + x,
320  railWindow->y + y, SRCCOPY);
321  EndPaint(hWnd, &ps);
322  }
323  break;
324 
325  case WM_LBUTTONDOWN:
326  {
327  if (!railWindow || !input)
328  return 0;
329 
330  xPos = GET_X_LPARAM(lParam) + railWindow->x;
331  yPos = GET_Y_LPARAM(lParam) + railWindow->y;
332  inputFlags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON1;
333 
334  if (input)
335  input->MouseEvent(input, inputFlags, xPos, yPos);
336  }
337  break;
338 
339  case WM_LBUTTONUP:
340  {
341  if (!railWindow || !input)
342  return 0;
343 
344  xPos = GET_X_LPARAM(lParam) + railWindow->x;
345  yPos = GET_Y_LPARAM(lParam) + railWindow->y;
346  inputFlags = PTR_FLAGS_BUTTON1;
347 
348  if (input)
349  input->MouseEvent(input, inputFlags, xPos, yPos);
350  }
351  break;
352 
353  case WM_RBUTTONDOWN:
354  {
355  if (!railWindow || !input)
356  return 0;
357 
358  xPos = GET_X_LPARAM(lParam) + railWindow->x;
359  yPos = GET_Y_LPARAM(lParam) + railWindow->y;
360  inputFlags = PTR_FLAGS_DOWN | PTR_FLAGS_BUTTON2;
361 
362  if (input)
363  input->MouseEvent(input, inputFlags, xPos, yPos);
364  }
365  break;
366 
367  case WM_RBUTTONUP:
368  {
369  if (!railWindow || !input)
370  return 0;
371 
372  xPos = GET_X_LPARAM(lParam) + railWindow->x;
373  yPos = GET_Y_LPARAM(lParam) + railWindow->y;
374  inputFlags = PTR_FLAGS_BUTTON2;
375 
376  if (input)
377  input->MouseEvent(input, inputFlags, xPos, yPos);
378  }
379  break;
380 
381  case WM_MOUSEMOVE:
382  {
383  if (!railWindow || !input)
384  return 0;
385 
386  xPos = GET_X_LPARAM(lParam) + railWindow->x;
387  yPos = GET_Y_LPARAM(lParam) + railWindow->y;
388  inputFlags = PTR_FLAGS_MOVE;
389 
390  if (input)
391  input->MouseEvent(input, inputFlags, xPos, yPos);
392  }
393  break;
394 
395  case WM_MOUSEWHEEL:
396  break;
397 
398  case WM_CLOSE:
399  DestroyWindow(hWnd);
400  break;
401 
402  case WM_DESTROY:
403  PostQuitMessage(0);
404  break;
405 
406  default:
407  return DefWindowProc(hWnd, msg, wParam, lParam);
408  }
409 
410  return 0;
411 }
412 
413 #define RAIL_DISABLED_WINDOW_STYLES \
414  (WS_BORDER | WS_THICKFRAME | WS_DLGFRAME | WS_CAPTION | WS_OVERLAPPED | WS_VSCROLL | \
415  WS_HSCROLL | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX)
416 #define RAIL_DISABLED_EXTENDED_WINDOW_STYLES \
417  (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE | WS_EX_WINDOWEDGE)
418 
419 static BOOL wf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
420  const WINDOW_STATE_ORDER* windowState)
421 {
422  wfRailWindow* railWindow = NULL;
423  wfContext* wfc = (wfContext*)context;
424  RailClientContext* rail = wfc->rail;
425  UINT32 fieldFlags = orderInfo->fieldFlags;
426  PrintRailWindowState(orderInfo, windowState);
427 
428  if (fieldFlags & WINDOW_ORDER_STATE_NEW)
429  {
430  BOOL rc;
431  HANDLE hInstance;
432  WCHAR* titleW = NULL;
433  WNDCLASSEX wndClassEx = { 0 };
434  railWindow = (wfRailWindow*)calloc(1, sizeof(wfRailWindow));
435 
436  if (!railWindow)
437  return FALSE;
438 
439  railWindow->wfc = wfc;
440  railWindow->dwStyle = windowState->style;
441  railWindow->dwStyle &= ~RAIL_DISABLED_WINDOW_STYLES;
442  railWindow->dwExStyle = windowState->extendedStyle;
443  railWindow->dwExStyle &= ~RAIL_DISABLED_EXTENDED_WINDOW_STYLES;
444  railWindow->x = windowState->windowOffsetX;
445  railWindow->y = windowState->windowOffsetY;
446  railWindow->width = windowState->windowWidth;
447  railWindow->height = windowState->windowHeight;
448 
449  if (fieldFlags & WINDOW_ORDER_FIELD_TITLE)
450  {
451  const WCHAR* str = (const WCHAR*)windowState->titleInfo.string;
452  char* title = NULL;
453 
454  if (windowState->titleInfo.length == 0)
455  {
456  if (!(title = _strdup("")))
457  {
458  WLog_ERR(TAG, "failed to duplicate empty window title string");
459  /* error handled below */
460  }
461  }
462  else if (!(title = ConvertWCharNToUtf8Alloc(
463  str, windowState->titleInfo.length / sizeof(WCHAR), NULL)))
464  {
465  WLog_ERR(TAG, "failed to convert window title");
466  /* error handled below */
467  }
468 
469  railWindow->title = title;
470  }
471  else
472  {
473  if (!(railWindow->title = _strdup("RdpRailWindow")))
474  WLog_ERR(TAG, "failed to duplicate default window title string");
475  }
476 
477  if (!railWindow->title)
478  {
479  free(railWindow);
480  return FALSE;
481  }
482 
483  titleW = ConvertUtf8ToWCharAlloc(railWindow->title, NULL);
484  hInstance = GetModuleHandle(NULL);
485 
486  wndClassEx.cbSize = sizeof(WNDCLASSEX);
487  wndClassEx.style = 0;
488  wndClassEx.lpfnWndProc = wf_RailWndProc;
489  wndClassEx.cbClsExtra = 0;
490  wndClassEx.cbWndExtra = 0;
491  wndClassEx.hIcon = NULL;
492  wndClassEx.hCursor = NULL;
493  wndClassEx.hbrBackground = NULL;
494  wndClassEx.lpszMenuName = NULL;
495  wndClassEx.lpszClassName = _T("RdpRailWindow");
496  wndClassEx.hInstance = hInstance;
497  wndClassEx.hIconSm = NULL;
498  RegisterClassEx(&wndClassEx);
499  railWindow->hWnd = CreateWindowExW(railWindow->dwExStyle, /* dwExStyle */
500  _T("RdpRailWindow"), /* lpClassName */
501  titleW, /* lpWindowName */
502  railWindow->dwStyle, /* dwStyle */
503  railWindow->x, /* x */
504  railWindow->y, /* y */
505  railWindow->width, /* nWidth */
506  railWindow->height, /* nHeight */
507  NULL, /* hWndParent */
508  NULL, /* hMenu */
509  hInstance, /* hInstance */
510  NULL /* lpParam */
511  );
512 
513  if (!railWindow->hWnd)
514  {
515  free(titleW);
516  free(railWindow->title);
517  free(railWindow);
518  WLog_ERR(TAG, "CreateWindowExW failed with error %" PRIu32 "", GetLastError());
519  return FALSE;
520  }
521 
522  SetWindowLongPtr(railWindow->hWnd, GWLP_USERDATA, (LONG_PTR)railWindow);
523  rc = HashTable_Insert(wfc->railWindows, (void*)(UINT_PTR)orderInfo->windowId,
524  (void*)railWindow);
525  free(titleW);
526  UpdateWindow(railWindow->hWnd);
527  return rc;
528  }
529  else
530  {
531  railWindow = (wfRailWindow*)HashTable_GetItemValue(wfc->railWindows,
532  (void*)(UINT_PTR)orderInfo->windowId);
533  }
534 
535  if (!railWindow)
536  return TRUE;
537 
538  if ((fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET) || (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE))
539  {
540  if (fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET)
541  {
542  railWindow->x = windowState->windowOffsetX;
543  railWindow->y = windowState->windowOffsetY;
544  }
545 
546  if (fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE)
547  {
548  railWindow->width = windowState->windowWidth;
549  railWindow->height = windowState->windowHeight;
550  }
551 
552  SetWindowPos(railWindow->hWnd, NULL, railWindow->x, railWindow->y, railWindow->width,
553  railWindow->height, 0);
554  }
555 
556  if (fieldFlags & WINDOW_ORDER_FIELD_OWNER)
557  {
558  }
559 
560  if (fieldFlags & WINDOW_ORDER_FIELD_STYLE)
561  {
562  railWindow->dwStyle = windowState->style;
563  railWindow->dwStyle &= ~RAIL_DISABLED_WINDOW_STYLES;
564  railWindow->dwExStyle = windowState->extendedStyle;
565  railWindow->dwExStyle &= ~RAIL_DISABLED_EXTENDED_WINDOW_STYLES;
566  SetWindowLongPtr(railWindow->hWnd, GWL_STYLE, (LONG)railWindow->dwStyle);
567  SetWindowLongPtr(railWindow->hWnd, GWL_EXSTYLE, (LONG)railWindow->dwExStyle);
568  }
569 
570  if (fieldFlags & WINDOW_ORDER_FIELD_SHOW)
571  {
572  ShowWindow(railWindow->hWnd, windowState->showState);
573  }
574 
575  if (fieldFlags & WINDOW_ORDER_FIELD_TITLE)
576  {
577  const WCHAR* str = (const WCHAR*)windowState->titleInfo.string;
578  char* title = NULL;
579 
580  if (windowState->titleInfo.length == 0)
581  {
582  if (!(title = _strdup("")))
583  {
584  WLog_ERR(TAG, "failed to duplicate empty window title string");
585  return FALSE;
586  }
587  }
588  else if (!(title = ConvertWCharNToUtf8Alloc(
589  str, windowState->titleInfo.length / sizeof(WCHAR), NULL)))
590  {
591  WLog_ERR(TAG, "failed to convert window title");
592  return FALSE;
593  }
594 
595  free(railWindow->title);
596  railWindow->title = title;
597  SetWindowTextW(railWindow->hWnd, str);
598  }
599 
600  if (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET)
601  {
602  }
603 
604  if (fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE)
605  {
606  }
607 
608  if (fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA)
609  {
610  }
611 
612  if (fieldFlags & WINDOW_ORDER_FIELD_RP_CONTENT)
613  {
614  }
615 
616  if (fieldFlags & WINDOW_ORDER_FIELD_ROOT_PARENT)
617  {
618  }
619 
620  if (fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS)
621  {
622  HRGN hWndRect;
623  HRGN hWndRects;
624  RECTANGLE_16* rect;
625 
626  if (windowState->numWindowRects > 0)
627  {
628  rect = &(windowState->windowRects[0]);
629  hWndRects = CreateRectRgn(rect->left, rect->top, rect->right, rect->bottom);
630 
631  for (UINT32 index = 1; index < windowState->numWindowRects; index++)
632  {
633  rect = &(windowState->windowRects[index]);
634  hWndRect = CreateRectRgn(rect->left, rect->top, rect->right, rect->bottom);
635  CombineRgn(hWndRects, hWndRects, hWndRect, RGN_OR);
636  DeleteObject(hWndRect);
637  }
638 
639  SetWindowRgn(railWindow->hWnd, hWndRects, TRUE);
640  DeleteObject(hWndRects);
641  }
642  }
643 
644  if (fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET)
645  {
646  }
647 
648  if (fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY)
649  {
650  }
651 
652  UpdateWindow(railWindow->hWnd);
653  return TRUE;
654 }
655 
656 static BOOL wf_rail_window_delete(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo)
657 {
658  wfRailWindow* railWindow = NULL;
659  wfContext* wfc = (wfContext*)context;
660  RailClientContext* rail = wfc->rail;
661  WLog_DBG(TAG, "RailWindowDelete");
662  railWindow = (wfRailWindow*)HashTable_GetItemValue(wfc->railWindows,
663  (void*)(UINT_PTR)orderInfo->windowId);
664 
665  if (!railWindow)
666  return TRUE;
667 
668  HashTable_Remove(wfc->railWindows, (void*)(UINT_PTR)orderInfo->windowId);
669  DestroyWindow(railWindow->hWnd);
670  free(railWindow);
671  return TRUE;
672 }
673 
674 static BOOL wf_rail_window_icon(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
675  const WINDOW_ICON_ORDER* windowIcon)
676 {
677  HDC hDC;
678  int bpp;
679  int width;
680  int height;
681  HICON hIcon;
682  BOOL bigIcon;
683  ICONINFO iconInfo = { 0 };
684  BITMAPINFO bitmapInfo = { 0 };
685  wfRailWindow* railWindow;
686  BITMAPINFOHEADER* bitmapInfoHeader;
687  wfContext* wfc = (wfContext*)context;
688  RailClientContext* rail = wfc->rail;
689  WLog_DBG(TAG, "RailWindowIcon");
690  PrintRailIconInfo(orderInfo, windowIcon->iconInfo);
691  railWindow = (wfRailWindow*)HashTable_GetItemValue(wfc->railWindows,
692  (void*)(UINT_PTR)orderInfo->windowId);
693 
694  if (!railWindow)
695  return TRUE;
696 
697  bigIcon = (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_ICON_BIG) ? TRUE : FALSE;
698  hDC = GetDC(railWindow->hWnd);
699  iconInfo.fIcon = TRUE;
700  iconInfo.xHotspot = 0;
701  iconInfo.yHotspot = 0;
702 
703  bitmapInfoHeader = &(bitmapInfo.bmiHeader);
704  bpp = windowIcon->iconInfo->bpp;
705  width = windowIcon->iconInfo->width;
706  height = windowIcon->iconInfo->height;
707  bitmapInfoHeader->biSize = sizeof(BITMAPINFOHEADER);
708  bitmapInfoHeader->biWidth = width;
709  bitmapInfoHeader->biHeight = height;
710  bitmapInfoHeader->biPlanes = 1;
711  bitmapInfoHeader->biBitCount = bpp;
712  bitmapInfoHeader->biCompression = 0;
713  bitmapInfoHeader->biSizeImage = height * width * ((bpp + 7) / 8);
714  bitmapInfoHeader->biXPelsPerMeter = width;
715  bitmapInfoHeader->biYPelsPerMeter = height;
716  bitmapInfoHeader->biClrUsed = 0;
717  bitmapInfoHeader->biClrImportant = 0;
718  iconInfo.hbmMask = CreateDIBitmap(hDC, bitmapInfoHeader, CBM_INIT,
719  windowIcon->iconInfo->bitsMask, &bitmapInfo, DIB_RGB_COLORS);
720  iconInfo.hbmColor =
721  CreateDIBitmap(hDC, bitmapInfoHeader, CBM_INIT, windowIcon->iconInfo->bitsColor,
722  &bitmapInfo, DIB_RGB_COLORS);
723  hIcon = CreateIconIndirect(&iconInfo);
724 
725  if (hIcon)
726  {
727  WPARAM wParam;
728  LPARAM lParam;
729  wParam = (WPARAM)bigIcon ? ICON_BIG : ICON_SMALL;
730  lParam = (LPARAM)hIcon;
731  SendMessage(railWindow->hWnd, WM_SETICON, wParam, lParam);
732  }
733 
734  ReleaseDC(NULL, hDC);
735 
736  if (windowIcon->iconInfo->cacheEntry != 0xFFFF)
737  {
738  /* icon should be cached */
739  }
740 
741  return TRUE;
742 }
743 
744 static BOOL wf_rail_window_cached_icon(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
745  const WINDOW_CACHED_ICON_ORDER* windowCachedIcon)
746 {
747  WLog_DBG(TAG, "RailWindowCachedIcon");
748  return TRUE;
749 }
750 
751 static void wf_rail_notify_icon_common(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
752  const NOTIFY_ICON_STATE_ORDER* notifyIconState)
753 {
754  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_VERSION)
755  {
756  }
757 
758  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_TIP)
759  {
760  }
761 
762  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_INFO_TIP)
763  {
764  }
765 
766  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_STATE)
767  {
768  }
769 
770  if (orderInfo->fieldFlags & WINDOW_ORDER_ICON)
771  {
772  const ICON_INFO* iconInfo = &(notifyIconState->icon);
773  PrintRailIconInfo(orderInfo, iconInfo);
774  }
775 
776  if (orderInfo->fieldFlags & WINDOW_ORDER_CACHED_ICON)
777  {
778  }
779 }
780 
781 static BOOL wf_rail_notify_icon_create(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
782  const NOTIFY_ICON_STATE_ORDER* notifyIconState)
783 {
784  wfContext* wfc = (wfContext*)context;
785  RailClientContext* rail = wfc->rail;
786  WLog_DBG(TAG, "RailNotifyIconCreate");
787  wf_rail_notify_icon_common(context, orderInfo, notifyIconState);
788  return TRUE;
789 }
790 
791 static BOOL wf_rail_notify_icon_update(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
792  const NOTIFY_ICON_STATE_ORDER* notifyIconState)
793 {
794  wfContext* wfc = (wfContext*)context;
795  RailClientContext* rail = wfc->rail;
796  WLog_DBG(TAG, "RailNotifyIconUpdate");
797  wf_rail_notify_icon_common(context, orderInfo, notifyIconState);
798  return TRUE;
799 }
800 
801 static BOOL wf_rail_notify_icon_delete(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo)
802 {
803  wfContext* wfc = (wfContext*)context;
804  RailClientContext* rail = wfc->rail;
805  WLog_DBG(TAG, "RailNotifyIconDelete");
806  return TRUE;
807 }
808 
809 static BOOL wf_rail_monitored_desktop(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
810  const MONITORED_DESKTOP_ORDER* monitoredDesktop)
811 {
812  wfContext* wfc = (wfContext*)context;
813  RailClientContext* rail = wfc->rail;
814  WLog_DBG(TAG, "RailMonitorDesktop");
815  return TRUE;
816 }
817 
818 static BOOL wf_rail_non_monitored_desktop(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo)
819 {
820  wfContext* wfc = (wfContext*)context;
821  RailClientContext* rail = wfc->rail;
822  WLog_DBG(TAG, "RailNonMonitorDesktop");
823  return TRUE;
824 }
825 
826 void wf_rail_register_update_callbacks(rdpUpdate* update)
827 {
828  rdpWindowUpdate* window = update->window;
829  window->WindowCreate = wf_rail_window_common;
830  window->WindowUpdate = wf_rail_window_common;
831  window->WindowDelete = wf_rail_window_delete;
832  window->WindowIcon = wf_rail_window_icon;
833  window->WindowCachedIcon = wf_rail_window_cached_icon;
834  window->NotifyIconCreate = wf_rail_notify_icon_create;
835  window->NotifyIconUpdate = wf_rail_notify_icon_update;
836  window->NotifyIconDelete = wf_rail_notify_icon_delete;
837  window->MonitoredDesktop = wf_rail_monitored_desktop;
838  window->NonMonitoredDesktop = wf_rail_non_monitored_desktop;
839 }
840 
841 /* RemoteApp Virtual Channel Extension */
842 
848 static UINT wf_rail_server_execute_result(RailClientContext* context,
849  const RAIL_EXEC_RESULT_ORDER* execResult)
850 {
851  WLog_DBG(TAG, "RailServerExecuteResult: 0x%08X", execResult->rawResult);
852  return CHANNEL_RC_OK;
853 }
854 
860 static UINT wf_rail_server_system_param(RailClientContext* context,
861  const RAIL_SYSPARAM_ORDER* sysparam)
862 {
863  return CHANNEL_RC_OK;
864 }
865 
871 static UINT wf_rail_server_handshake(RailClientContext* context,
872  const RAIL_HANDSHAKE_ORDER* handshake)
873 {
874  return client_rail_server_start_cmd(context);
875 }
876 
882 static UINT wf_rail_server_handshake_ex(RailClientContext* context,
883  const RAIL_HANDSHAKE_EX_ORDER* handshakeEx)
884 {
885  return client_rail_server_start_cmd(context);
886 }
887 
893 static UINT wf_rail_server_local_move_size(RailClientContext* context,
894  const RAIL_LOCALMOVESIZE_ORDER* localMoveSize)
895 {
896  return CHANNEL_RC_OK;
897 }
898 
904 static UINT wf_rail_server_min_max_info(RailClientContext* context,
905  const RAIL_MINMAXINFO_ORDER* minMaxInfo)
906 {
907  return CHANNEL_RC_OK;
908 }
909 
915 static UINT wf_rail_server_language_bar_info(RailClientContext* context,
916  const RAIL_LANGBAR_INFO_ORDER* langBarInfo)
917 {
918  return CHANNEL_RC_OK;
919 }
920 
926 static UINT wf_rail_server_get_appid_response(RailClientContext* context,
927  const RAIL_GET_APPID_RESP_ORDER* getAppIdResp)
928 {
929  return CHANNEL_RC_OK;
930 }
931 
932 void wf_rail_invalidate_region(wfContext* wfc, REGION16* invalidRegion)
933 {
934  RECT updateRect;
935  RECTANGLE_16 windowRect;
936  ULONG_PTR* pKeys = NULL;
937  wfRailWindow* railWindow;
938  const RECTANGLE_16* extents;
939  REGION16 windowInvalidRegion;
940  region16_init(&windowInvalidRegion);
941  size_t count = HashTable_GetKeys(wfc->railWindows, &pKeys);
942 
943  for (size_t index = 0; index < count; index++)
944  {
945  railWindow = (wfRailWindow*)HashTable_GetItemValue(wfc->railWindows, (void*)pKeys[index]);
946 
947  if (railWindow)
948  {
949  windowRect.left = railWindow->x;
950  windowRect.top = railWindow->y;
951  windowRect.right = railWindow->x + railWindow->width;
952  windowRect.bottom = railWindow->y + railWindow->height;
953  region16_clear(&windowInvalidRegion);
954  region16_intersect_rect(&windowInvalidRegion, invalidRegion, &windowRect);
955 
956  if (!region16_is_empty(&windowInvalidRegion))
957  {
958  extents = region16_extents(&windowInvalidRegion);
959  updateRect.left = extents->left - railWindow->x;
960  updateRect.top = extents->top - railWindow->y;
961  updateRect.right = extents->right - railWindow->x;
962  updateRect.bottom = extents->bottom - railWindow->y;
963  InvalidateRect(railWindow->hWnd, &updateRect, FALSE);
964  }
965  }
966  }
967 
968  region16_uninit(&windowInvalidRegion);
969 }
970 
971 BOOL wf_rail_init(wfContext* wfc, RailClientContext* rail)
972 {
973  rdpContext* context = (rdpContext*)wfc;
974  wfc->rail = rail;
975  rail->custom = (void*)wfc;
976  rail->ServerExecuteResult = wf_rail_server_execute_result;
977  rail->ServerSystemParam = wf_rail_server_system_param;
978  rail->ServerHandshake = wf_rail_server_handshake;
979  rail->ServerHandshakeEx = wf_rail_server_handshake_ex;
980  rail->ServerLocalMoveSize = wf_rail_server_local_move_size;
981  rail->ServerMinMaxInfo = wf_rail_server_min_max_info;
982  rail->ServerLanguageBarInfo = wf_rail_server_language_bar_info;
983  rail->ServerGetAppIdResponse = wf_rail_server_get_appid_response;
984  wf_rail_register_update_callbacks(context->update);
985  wfc->railWindows = HashTable_New(TRUE);
986  return (wfc->railWindows != NULL);
987 }
988 
989 void wf_rail_uninit(wfContext* wfc, RailClientContext* rail)
990 {
991  wfc->rail = NULL;
992  rail->custom = NULL;
993  HashTable_Free(wfc->railWindows);
994 }