Coverage Report

Created: 2026-07-16 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/libfreerdp/core/window.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Windowing Alternate Secondary Orders
4
 *
5
 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 * Copyright 2011 Roman Barabanov <romanbarabanov@gmail.com>
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20
21
#include <freerdp/config.h>
22
23
#include "settings.h"
24
25
#include <winpr/crt.h>
26
#include <winpr/assert.h>
27
28
#include <freerdp/log.h>
29
30
#include "window.h"
31
32
#define TAG FREERDP_TAG("core.window")
33
34
static void update_free_window_icon_info(ICON_INFO* iconInfo);
35
36
BOOL rail_read_unicode_string(wStream* s, RAIL_UNICODE_STRING* unicode_string)
37
272
{
38
272
  WINPR_ASSERT(unicode_string);
39
40
272
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
41
2
    return FALSE;
42
43
270
  const UINT16 new_len = Stream_Get_UINT16(s); /* cbString (2 bytes) */
44
45
270
  if (!Stream_CheckAndLogRequiredLength(TAG, s, new_len))
46
57
    return FALSE;
47
48
213
  if ((new_len == 0) || ((new_len % sizeof(WCHAR)) != 0))
49
68
  {
50
68
    rail_unicode_string_free(unicode_string);
51
68
    return TRUE;
52
68
  }
53
54
145
  WCHAR* new_str = realloc(unicode_string->string, new_len);
55
145
  if (!new_str)
56
0
  {
57
0
    rail_unicode_string_free(unicode_string);
58
0
    return FALSE;
59
0
  }
60
61
145
  unicode_string->string = new_str;
62
145
  unicode_string->length = new_len;
63
145
  Stream_Read(s, unicode_string->string, unicode_string->length);
64
65
145
  const size_t charlen = unicode_string->length / sizeof(WCHAR);
66
145
  if (_wcsnlen(unicode_string->string, charlen) != charlen)
67
107
  {
68
107
    WLog_ERR(TAG, "Failed to read UNICODE_STRING, data contains \\0 characters!");
69
107
    return FALSE;
70
107
  }
71
38
  return TRUE;
72
145
}
73
74
UINT rail_write_unicode_string_value(wStream* s, const RAIL_UNICODE_STRING* unicode_string)
75
0
{
76
0
  if (!s || !unicode_string)
77
0
    return ERROR_INVALID_PARAMETER;
78
79
0
  const size_t length = unicode_string->length;
80
0
  WINPR_ASSERT((length % sizeof(WCHAR)) == 0);
81
0
  if (length > 0)
82
0
  {
83
0
    if (!Stream_EnsureRemainingCapacity(s, length))
84
0
    {
85
0
      WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
86
0
      return CHANNEL_RC_NO_MEMORY;
87
0
    }
88
89
0
    Stream_Write(s, unicode_string->string, length); /* string */
90
0
  }
91
92
0
  return CHANNEL_RC_OK;
93
0
}
94
95
UINT rail_write_unicode_string(wStream* s, const RAIL_UNICODE_STRING* unicode_string)
96
0
{
97
0
  if (!s || !unicode_string)
98
0
    return ERROR_INVALID_PARAMETER;
99
100
0
  if (!Stream_EnsureRemainingCapacity(s, 2 + unicode_string->length))
101
0
  {
102
0
    WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
103
0
    return CHANNEL_RC_NO_MEMORY;
104
0
  }
105
106
0
  Stream_Write_UINT16(s, unicode_string->length); /* cbString (2 bytes) */
107
0
  return rail_write_unicode_string_value(s, unicode_string);
108
0
}
109
110
void rail_unicode_string_free(RAIL_UNICODE_STRING* unicode_string)
111
601
{
112
601
  WINPR_ASSERT(unicode_string);
113
601
  free(unicode_string->string);
114
601
  unicode_string->string = nullptr;
115
601
  unicode_string->length = 0;
116
601
}
117
118
BOOL utf8_string_to_rail_string(const char* string, RAIL_UNICODE_STRING* unicode_string)
119
0
{
120
0
  WINPR_ASSERT(unicode_string);
121
122
0
  rail_unicode_string_free(unicode_string);
123
124
0
  if (!string || strlen(string) < 1)
125
0
    return TRUE;
126
127
0
  size_t len = 0;
128
0
  WCHAR* buffer = ConvertUtf8ToWCharAlloc(string, &len);
129
130
0
  const size_t wlen = len * sizeof(WCHAR);
131
0
  if (!buffer || (wlen > UINT16_MAX))
132
0
  {
133
0
    free(buffer);
134
0
    return FALSE;
135
0
  }
136
137
0
  unicode_string->string = buffer;
138
0
  unicode_string->length = WINPR_ASSERTING_INT_CAST(UINT16, len * sizeof(WCHAR));
139
0
  return TRUE;
140
0
}
141
142
char* rail_string_to_utf8_string(const RAIL_UNICODE_STRING* unicode_string)
143
0
{
144
0
  WINPR_ASSERT(unicode_string);
145
0
  WINPR_ASSERT((unicode_string->length % sizeof(WCHAR)) == 0);
146
0
  WINPR_ASSERT(((unicode_string->length > 0) && (unicode_string->string)) ||
147
0
               (unicode_string->length == 0));
148
149
0
  size_t outLen = 0;
150
0
  size_t inLen = unicode_string->length / sizeof(WCHAR);
151
0
  return ConvertWCharNToUtf8Alloc(unicode_string->string, inLen, &outLen);
152
0
}
153
154
/* See [MS-RDPERP] 2.2.1.2.3 Icon Info (TS_ICON_INFO) */
155
static BOOL update_read_icon_info(wStream* s, ICON_INFO* iconInfo)
156
0
{
157
0
  BYTE* newBitMask = nullptr;
158
159
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
160
0
    return FALSE;
161
162
0
  Stream_Read_UINT16(s, iconInfo->cacheEntry); /* cacheEntry (2 bytes) */
163
0
  Stream_Read_UINT8(s, iconInfo->cacheId);     /* cacheId (1 byte) */
164
0
  Stream_Read_UINT8(s, iconInfo->bpp);         /* bpp (1 byte) */
165
166
0
  if ((iconInfo->bpp < 1) || (iconInfo->bpp > 32))
167
0
  {
168
0
    WLog_ERR(TAG, "invalid bpp value %" PRIu32 "", iconInfo->bpp);
169
0
    return FALSE;
170
0
  }
171
172
0
  Stream_Read_UINT16(s, iconInfo->width);  /* width (2 bytes) */
173
0
  Stream_Read_UINT16(s, iconInfo->height); /* height (2 bytes) */
174
175
  /* cbColorTable is only present when bpp is 1, 4 or 8 */
176
0
  switch (iconInfo->bpp)
177
0
  {
178
0
    case 1:
179
0
    case 4:
180
0
    case 8:
181
0
      if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
182
0
        return FALSE;
183
184
0
      Stream_Read_UINT16(s, iconInfo->cbColorTable); /* cbColorTable (2 bytes) */
185
0
      break;
186
187
0
    default:
188
0
      iconInfo->cbColorTable = 0;
189
0
      break;
190
0
  }
191
192
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
193
0
    return FALSE;
194
195
0
  Stream_Read_UINT16(s, iconInfo->cbBitsMask);  /* cbBitsMask (2 bytes) */
196
0
  Stream_Read_UINT16(s, iconInfo->cbBitsColor); /* cbBitsColor (2 bytes) */
197
198
  /* bitsMask */
199
0
  if (iconInfo->cbBitsMask > 0)
200
0
  {
201
0
    newBitMask = (BYTE*)realloc(iconInfo->bitsMask, iconInfo->cbBitsMask);
202
203
0
    if (!newBitMask)
204
0
    {
205
0
      free(iconInfo->bitsMask);
206
0
      iconInfo->bitsMask = nullptr;
207
0
      return FALSE;
208
0
    }
209
210
0
    iconInfo->bitsMask = newBitMask;
211
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, iconInfo->cbBitsMask))
212
0
      return FALSE;
213
0
    Stream_Read(s, iconInfo->bitsMask, iconInfo->cbBitsMask);
214
0
  }
215
0
  else
216
0
  {
217
0
    free(iconInfo->bitsMask);
218
0
    iconInfo->bitsMask = nullptr;
219
0
    iconInfo->cbBitsMask = 0;
220
0
  }
221
222
  /* colorTable */
223
0
  if (iconInfo->cbColorTable > 0)
224
0
  {
225
0
    BYTE* new_tab = nullptr;
226
0
    new_tab = (BYTE*)realloc(iconInfo->colorTable, iconInfo->cbColorTable);
227
228
0
    if (!new_tab)
229
0
    {
230
0
      free(iconInfo->colorTable);
231
0
      iconInfo->colorTable = nullptr;
232
0
      return FALSE;
233
0
    }
234
235
0
    iconInfo->colorTable = new_tab;
236
0
  }
237
0
  else
238
0
  {
239
0
    free(iconInfo->colorTable);
240
0
    iconInfo->colorTable = nullptr;
241
0
  }
242
243
0
  if (iconInfo->colorTable)
244
0
  {
245
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, iconInfo->cbColorTable))
246
0
      return FALSE;
247
0
    Stream_Read(s, iconInfo->colorTable, iconInfo->cbColorTable);
248
0
  }
249
250
  /* bitsColor */
251
0
  if (iconInfo->cbBitsColor > 0)
252
0
  {
253
0
    newBitMask = (BYTE*)realloc(iconInfo->bitsColor, iconInfo->cbBitsColor);
254
255
0
    if (!newBitMask)
256
0
    {
257
0
      free(iconInfo->bitsColor);
258
0
      iconInfo->bitsColor = nullptr;
259
0
      return FALSE;
260
0
    }
261
262
0
    iconInfo->bitsColor = newBitMask;
263
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, iconInfo->cbBitsColor))
264
0
      return FALSE;
265
0
    Stream_Read(s, iconInfo->bitsColor, iconInfo->cbBitsColor);
266
0
  }
267
0
  else
268
0
  {
269
0
    free(iconInfo->bitsColor);
270
0
    iconInfo->bitsColor = nullptr;
271
0
    iconInfo->cbBitsColor = 0;
272
0
  }
273
0
  return TRUE;
274
0
}
275
276
static BOOL update_read_cached_icon_info(wStream* s, CACHED_ICON_INFO* cachedIconInfo)
277
0
{
278
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 3))
279
0
    return FALSE;
280
281
0
  Stream_Read_UINT16(s, cachedIconInfo->cacheEntry); /* cacheEntry (2 bytes) */
282
0
  Stream_Read_UINT8(s, cachedIconInfo->cacheId);     /* cacheId (1 byte) */
283
0
  return TRUE;
284
0
}
285
286
static BOOL update_read_notify_icon_infotip(wStream* s, NOTIFY_ICON_INFOTIP* notifyIconInfoTip)
287
0
{
288
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
289
0
    return FALSE;
290
291
0
  Stream_Read_UINT32(s, notifyIconInfoTip->timeout);              /* timeout (4 bytes) */
292
0
  Stream_Read_UINT32(s, notifyIconInfoTip->flags);                /* infoFlags (4 bytes) */
293
0
  return rail_read_unicode_string(s, &notifyIconInfoTip->text) && /* infoTipText */
294
0
         rail_read_unicode_string(s, &notifyIconInfoTip->title);  /* title */
295
0
}
296
297
static BOOL update_read_window_state_order(wStream* s, WINDOW_ORDER_INFO* orderInfo,
298
                                           WINDOW_STATE_ORDER* windowState)
299
0
{
300
0
  size_t size = 0;
301
0
  RECTANGLE_16* newRect = nullptr;
302
303
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_OWNER)
304
0
  {
305
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
306
0
      return FALSE;
307
308
0
    Stream_Read_UINT32(s, windowState->ownerWindowId); /* ownerWindowId (4 bytes) */
309
0
  }
310
311
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_STYLE)
312
0
  {
313
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
314
0
      return FALSE;
315
316
0
    Stream_Read_UINT32(s, windowState->style);         /* style (4 bytes) */
317
0
    Stream_Read_UINT32(s, windowState->extendedStyle); /* extendedStyle (4 bytes) */
318
0
  }
319
320
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_SHOW)
321
0
  {
322
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
323
0
      return FALSE;
324
325
0
    Stream_Read_UINT8(s, windowState->showState); /* showState (1 byte) */
326
0
  }
327
328
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_TITLE)
329
0
  {
330
0
    if (!rail_read_unicode_string(s, &windowState->titleInfo)) /* titleInfo */
331
0
      return FALSE;
332
0
  }
333
334
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET)
335
0
  {
336
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
337
0
      return FALSE;
338
339
0
    Stream_Read_INT32(s, windowState->clientOffsetX); /* clientOffsetX (4 bytes) */
340
0
    Stream_Read_INT32(s, windowState->clientOffsetY); /* clientOffsetY (4 bytes) */
341
0
  }
342
343
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE)
344
0
  {
345
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
346
0
      return FALSE;
347
348
0
    Stream_Read_UINT32(s, windowState->clientAreaWidth);  /* clientAreaWidth (4 bytes) */
349
0
    Stream_Read_UINT32(s, windowState->clientAreaHeight); /* clientAreaHeight (4 bytes) */
350
0
  }
351
352
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_RESIZE_MARGIN_X)
353
0
  {
354
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
355
0
      return FALSE;
356
357
0
    Stream_Read_UINT32(s, windowState->resizeMarginLeft);
358
0
    Stream_Read_UINT32(s, windowState->resizeMarginRight);
359
0
  }
360
361
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_RESIZE_MARGIN_Y)
362
0
  {
363
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
364
0
      return FALSE;
365
366
0
    Stream_Read_UINT32(s, windowState->resizeMarginTop);
367
0
    Stream_Read_UINT32(s, windowState->resizeMarginBottom);
368
0
  }
369
370
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_RP_CONTENT)
371
0
  {
372
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
373
0
      return FALSE;
374
375
0
    Stream_Read_UINT8(s, windowState->RPContent); /* RPContent (1 byte) */
376
0
  }
377
378
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_ROOT_PARENT)
379
0
  {
380
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
381
0
      return FALSE;
382
383
0
    Stream_Read_UINT32(s, windowState->rootParentHandle); /* rootParentHandle (4 bytes) */
384
0
  }
385
386
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET)
387
0
  {
388
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
389
0
      return FALSE;
390
391
0
    Stream_Read_INT32(s, windowState->windowOffsetX); /* windowOffsetX (4 bytes) */
392
0
    Stream_Read_INT32(s, windowState->windowOffsetY); /* windowOffsetY (4 bytes) */
393
0
  }
394
395
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA)
396
0
  {
397
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
398
0
      return FALSE;
399
400
0
    Stream_Read_INT32(s, windowState->windowClientDeltaX); /* windowClientDeltaX (4 bytes) */
401
0
    Stream_Read_INT32(s, windowState->windowClientDeltaY); /* windowClientDeltaY (4 bytes) */
402
0
  }
403
404
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE)
405
0
  {
406
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
407
0
      return FALSE;
408
409
0
    Stream_Read_UINT32(s, windowState->windowWidth);  /* windowWidth (4 bytes) */
410
0
    Stream_Read_UINT32(s, windowState->windowHeight); /* windowHeight (4 bytes) */
411
0
  }
412
413
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS)
414
0
  {
415
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
416
0
      return FALSE;
417
418
0
    Stream_Read_UINT16(s, windowState->numWindowRects); /* numWindowRects (2 bytes) */
419
420
0
    if (windowState->numWindowRects > 0)
421
0
    {
422
0
      size = sizeof(RECTANGLE_16) * windowState->numWindowRects;
423
0
      newRect = (RECTANGLE_16*)realloc(windowState->windowRects, size);
424
425
0
      if (!newRect)
426
0
      {
427
0
        free(windowState->windowRects);
428
0
        windowState->windowRects = nullptr;
429
0
        return FALSE;
430
0
      }
431
432
0
      windowState->windowRects = newRect;
433
434
0
      if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, windowState->numWindowRects, 8ull))
435
0
        return FALSE;
436
437
      /* windowRects */
438
0
      for (UINT32 i = 0; i < windowState->numWindowRects; i++)
439
0
      {
440
0
        Stream_Read_UINT16(s, windowState->windowRects[i].left);   /* left (2 bytes) */
441
0
        Stream_Read_UINT16(s, windowState->windowRects[i].top);    /* top (2 bytes) */
442
0
        Stream_Read_UINT16(s, windowState->windowRects[i].right);  /* right (2 bytes) */
443
0
        Stream_Read_UINT16(s, windowState->windowRects[i].bottom); /* bottom (2 bytes) */
444
0
      }
445
0
    }
446
0
  }
447
448
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET)
449
0
  {
450
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
451
0
      return FALSE;
452
453
0
    Stream_Read_INT32(s, windowState->visibleOffsetX); /* visibleOffsetX (4 bytes) */
454
0
    Stream_Read_INT32(s, windowState->visibleOffsetY); /* visibleOffsetY (4 bytes) */
455
0
  }
456
457
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY)
458
0
  {
459
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 2))
460
0
      return FALSE;
461
462
0
    Stream_Read_UINT16(s, windowState->numVisibilityRects); /* numVisibilityRects (2 bytes) */
463
464
0
    if (windowState->numVisibilityRects != 0)
465
0
    {
466
0
      size = sizeof(RECTANGLE_16) * windowState->numVisibilityRects;
467
0
      newRect = (RECTANGLE_16*)realloc(windowState->visibilityRects, size);
468
469
0
      if (!newRect)
470
0
      {
471
0
        free(windowState->visibilityRects);
472
0
        windowState->visibilityRects = nullptr;
473
0
        return FALSE;
474
0
      }
475
476
0
      windowState->visibilityRects = newRect;
477
478
0
      if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, windowState->numVisibilityRects,
479
0
                                                  8ull))
480
0
        return FALSE;
481
482
      /* visibilityRects */
483
0
      for (UINT32 i = 0; i < windowState->numVisibilityRects; i++)
484
0
      {
485
0
        Stream_Read_UINT16(s, windowState->visibilityRects[i].left);  /* left (2 bytes) */
486
0
        Stream_Read_UINT16(s, windowState->visibilityRects[i].top);   /* top (2 bytes) */
487
0
        Stream_Read_UINT16(s, windowState->visibilityRects[i].right); /* right (2 bytes) */
488
0
        Stream_Read_UINT16(s,
489
0
                           windowState->visibilityRects[i].bottom); /* bottom (2 bytes) */
490
0
      }
491
0
    }
492
0
  }
493
494
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_OVERLAY_DESCRIPTION)
495
0
  {
496
0
    if (!rail_read_unicode_string(s, &windowState->OverlayDescription))
497
0
      return FALSE;
498
0
  }
499
500
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_ICON_OVERLAY_NULL)
501
0
  {
502
    /* no data to be read here */
503
0
  }
504
505
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_TASKBAR_BUTTON)
506
0
  {
507
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
508
0
      return FALSE;
509
510
0
    Stream_Read_UINT8(s, windowState->TaskbarButton);
511
0
  }
512
513
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_ENFORCE_SERVER_ZORDER)
514
0
  {
515
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
516
0
      return FALSE;
517
518
0
    Stream_Read_UINT8(s, windowState->EnforceServerZOrder);
519
0
  }
520
521
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_APPBAR_STATE)
522
0
  {
523
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
524
0
      return FALSE;
525
526
0
    Stream_Read_UINT8(s, windowState->AppBarState);
527
0
  }
528
529
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_APPBAR_EDGE)
530
0
  {
531
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
532
0
      return FALSE;
533
534
0
    Stream_Read_UINT8(s, windowState->AppBarEdge);
535
0
  }
536
537
0
  return TRUE;
538
0
}
539
540
static BOOL update_read_window_icon_order(wStream* s, WINDOW_ORDER_INFO* orderInfo,
541
                                          WINDOW_ICON_ORDER* window_icon)
542
0
{
543
0
  WINPR_UNUSED(orderInfo);
544
0
  window_icon->iconInfo = (ICON_INFO*)calloc(1, sizeof(ICON_INFO));
545
546
0
  if (!window_icon->iconInfo)
547
0
    return FALSE;
548
549
0
  return update_read_icon_info(s, window_icon->iconInfo); /* iconInfo (ICON_INFO) */
550
0
}
551
552
static BOOL update_read_window_cached_icon_order(wStream* s, WINDOW_ORDER_INFO* orderInfo,
553
                                                 WINDOW_CACHED_ICON_ORDER* window_cached_icon)
554
0
{
555
0
  WINPR_UNUSED(orderInfo);
556
0
  return update_read_cached_icon_info(
557
0
      s, &window_cached_icon->cachedIcon); /* cachedIcon (CACHED_ICON_INFO) */
558
0
}
559
560
static void update_read_window_delete_order(WINPR_ATTR_UNUSED wStream* s,
561
                                            WINPR_ATTR_UNUSED WINDOW_ORDER_INFO* orderInfo)
562
0
{
563
  /* window deletion event */
564
0
}
565
566
static BOOL window_order_supported(const rdpSettings* settings, UINT32 fieldFlags)
567
4.49k
{
568
4.49k
  const UINT32 mask = (WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE | WINDOW_ORDER_FIELD_RP_CONTENT |
569
4.49k
                       WINDOW_ORDER_FIELD_ROOT_PARENT);
570
571
4.49k
  if (!settings)
572
0
    return FALSE;
573
574
  /* See [MS-RDPERP] 2.2.1.1.2 Window List Capability Set */
575
4.49k
  const BOOL dresult =
576
4.49k
      freerdp_settings_get_bool(settings, FreeRDP_AllowUnanouncedOrdersFromServer);
577
578
4.49k
  switch (freerdp_settings_get_uint32(settings, FreeRDP_RemoteWndSupportLevel))
579
4.49k
  {
580
0
    case WINDOW_LEVEL_SUPPORTED_EX:
581
0
      return TRUE;
582
583
0
    case WINDOW_LEVEL_SUPPORTED:
584
0
      return ((fieldFlags & mask) == 0) || dresult;
585
586
0
    case WINDOW_LEVEL_NOT_SUPPORTED:
587
0
      return dresult;
588
589
4.49k
    default:
590
4.49k
      return dresult;
591
4.49k
  }
592
4.49k
}
593
594
#define DUMP_APPEND(buffer, size, ...)                  \
595
0
  do                                                  \
596
0
  {                                                   \
597
0
    char* b = (buffer);                             \
598
0
    size_t s = (size);                              \
599
0
    size_t pos = strnlen(b, s);                     \
600
0
    (void)_snprintf(&b[pos], s - pos, __VA_ARGS__); \
601
0
  } while (0)
602
603
static void dump_window_style(char* buffer, size_t bufferSize, UINT32 style)
604
0
{
605
0
  DUMP_APPEND(buffer, bufferSize, " style=<0x%" PRIx32 ": ", style);
606
0
  if (style & WS_BORDER)
607
0
    DUMP_APPEND(buffer, bufferSize, " border");
608
0
  if (style & WS_CAPTION)
609
0
    DUMP_APPEND(buffer, bufferSize, " caption");
610
0
  if (style & WS_CHILD)
611
0
    DUMP_APPEND(buffer, bufferSize, " child");
612
0
  if (style & WS_CHILDWINDOW)
613
0
    DUMP_APPEND(buffer, bufferSize, " childwindow");
614
0
  if (style & WS_CLIPCHILDREN)
615
0
    DUMP_APPEND(buffer, bufferSize, " clipchildren");
616
0
  if (style & WS_CLIPSIBLINGS)
617
0
    DUMP_APPEND(buffer, bufferSize, " clipsiblings");
618
0
  if (style & WS_DISABLED)
619
0
    DUMP_APPEND(buffer, bufferSize, " disabled");
620
0
  if (style & WS_DLGFRAME)
621
0
    DUMP_APPEND(buffer, bufferSize, " dlgframe");
622
0
  if (style & WS_GROUP)
623
0
    DUMP_APPEND(buffer, bufferSize, " group");
624
0
  if (style & WS_HSCROLL)
625
0
    DUMP_APPEND(buffer, bufferSize, " hscroll");
626
0
  if (style & WS_ICONIC)
627
0
    DUMP_APPEND(buffer, bufferSize, " iconic");
628
0
  if (style & WS_MAXIMIZE)
629
0
    DUMP_APPEND(buffer, bufferSize, " maximize");
630
0
  if (style & WS_MAXIMIZEBOX)
631
0
    DUMP_APPEND(buffer, bufferSize, " maximizebox");
632
0
  if (style & WS_MINIMIZE)
633
0
    DUMP_APPEND(buffer, bufferSize, " minimize");
634
0
  if (style & WS_MINIMIZEBOX)
635
0
    DUMP_APPEND(buffer, bufferSize, " minimizebox");
636
0
  if (style & WS_POPUP)
637
0
    DUMP_APPEND(buffer, bufferSize, " popup");
638
0
  if (style & WS_SIZEBOX)
639
0
    DUMP_APPEND(buffer, bufferSize, " sizebox");
640
0
  if (style & WS_SYSMENU)
641
0
    DUMP_APPEND(buffer, bufferSize, " sysmenu");
642
0
  if (style & WS_TABSTOP)
643
0
    DUMP_APPEND(buffer, bufferSize, " tabstop");
644
0
  if (style & WS_THICKFRAME)
645
0
    DUMP_APPEND(buffer, bufferSize, " thickframe");
646
0
  if (style & WS_VISIBLE)
647
0
    DUMP_APPEND(buffer, bufferSize, " visible");
648
0
  if (style & WS_VSCROLL)
649
0
    DUMP_APPEND(buffer, bufferSize, " vscroll");
650
0
  DUMP_APPEND(buffer, bufferSize, ">");
651
0
}
652
653
static void dump_window_style_ex(char* buffer, size_t bufferSize, UINT32 extendedStyle)
654
0
{
655
0
  DUMP_APPEND(buffer, bufferSize, " styleEx=<0x%" PRIx32 ": ", extendedStyle);
656
0
  if (extendedStyle & WS_EX_ACCEPTFILES)
657
0
    DUMP_APPEND(buffer, bufferSize, " acceptfiles");
658
0
  if (extendedStyle & WS_EX_APPWINDOW)
659
0
    DUMP_APPEND(buffer, bufferSize, " appwindow");
660
0
  if (extendedStyle & WS_EX_CLIENTEDGE)
661
0
    DUMP_APPEND(buffer, bufferSize, " clientedge");
662
0
  if (extendedStyle & WS_EX_COMPOSITED)
663
0
    DUMP_APPEND(buffer, bufferSize, " composited");
664
0
  if (extendedStyle & WS_EX_CONTEXTHELP)
665
0
    DUMP_APPEND(buffer, bufferSize, " contexthelp");
666
0
  if (extendedStyle & WS_EX_CONTROLPARENT)
667
0
    DUMP_APPEND(buffer, bufferSize, " controlparent");
668
0
  if (extendedStyle & WS_EX_DLGMODALFRAME)
669
0
    DUMP_APPEND(buffer, bufferSize, " dlgmodalframe");
670
0
  if (extendedStyle & WS_EX_LAYERED)
671
0
    DUMP_APPEND(buffer, bufferSize, " layered");
672
0
  if (extendedStyle & WS_EX_LAYOUTRTL)
673
0
    DUMP_APPEND(buffer, bufferSize, " layoutrtl");
674
0
  if (extendedStyle & WS_EX_LEFT)
675
0
    DUMP_APPEND(buffer, bufferSize, " left");
676
0
  if (extendedStyle & WS_EX_LEFTSCROLLBAR)
677
0
    DUMP_APPEND(buffer, bufferSize, " leftscrollbar");
678
0
  if (extendedStyle & WS_EX_LTRREADING)
679
0
    DUMP_APPEND(buffer, bufferSize, " ltrreading");
680
0
  if (extendedStyle & WS_EX_MDICHILD)
681
0
    DUMP_APPEND(buffer, bufferSize, " mdichild");
682
0
  if (extendedStyle & WS_EX_NOACTIVATE)
683
0
    DUMP_APPEND(buffer, bufferSize, " noactivate");
684
0
  if (extendedStyle & WS_EX_NOINHERITLAYOUT)
685
0
    DUMP_APPEND(buffer, bufferSize, " noinheritlayout");
686
0
#if defined(WS_EX_NOREDIRECTIONBITMAP)
687
0
  if (extendedStyle & WS_EX_NOREDIRECTIONBITMAP)
688
0
    DUMP_APPEND(buffer, bufferSize, " noredirectionbitmap");
689
0
#endif
690
0
  if (extendedStyle & WS_EX_RIGHT)
691
0
    DUMP_APPEND(buffer, bufferSize, " right");
692
0
  if (extendedStyle & WS_EX_RIGHTSCROLLBAR)
693
0
    DUMP_APPEND(buffer, bufferSize, " rightscrollbar");
694
0
  if (extendedStyle & WS_EX_RTLREADING)
695
0
    DUMP_APPEND(buffer, bufferSize, " rtlreading");
696
0
  if (extendedStyle & WS_EX_STATICEDGE)
697
0
    DUMP_APPEND(buffer, bufferSize, " staticedge");
698
0
  if (extendedStyle & WS_EX_TOOLWINDOW)
699
0
    DUMP_APPEND(buffer, bufferSize, " toolWindow");
700
0
  if (extendedStyle & WS_EX_TOPMOST)
701
0
    DUMP_APPEND(buffer, bufferSize, " topMost");
702
0
  if (extendedStyle & WS_EX_TRANSPARENT)
703
0
    DUMP_APPEND(buffer, bufferSize, " transparent");
704
0
  if (extendedStyle & WS_EX_WINDOWEDGE)
705
0
    DUMP_APPEND(buffer, bufferSize, " windowedge");
706
0
  DUMP_APPEND(buffer, bufferSize, ">");
707
0
}
708
709
static void dump_window_state_order(wLog* log, const char* msg, const WINDOW_ORDER_INFO* order,
710
                                    const WINDOW_STATE_ORDER* state)
711
0
{
712
0
  char buffer[3000] = WINPR_C_ARRAY_INIT;
713
0
  const size_t bufferSize = sizeof(buffer) - 1;
714
715
0
  (void)_snprintf(buffer, bufferSize, "%s windowId=%" PRIu32 "", msg, order->windowId);
716
717
0
  if (order->fieldFlags & WINDOW_ORDER_FIELD_OWNER)
718
0
    DUMP_APPEND(buffer, bufferSize, " owner=%" PRIu32 "", state->ownerWindowId);
719
0
  if (order->fieldFlags & WINDOW_ORDER_FIELD_STYLE)
720
0
  {
721
0
    dump_window_style(buffer, bufferSize, state->style);
722
0
    dump_window_style_ex(buffer, bufferSize, state->extendedStyle);
723
0
  }
724
725
0
  if (order->fieldFlags & WINDOW_ORDER_FIELD_SHOW)
726
0
  {
727
0
    const char* showStr = nullptr;
728
0
    switch (state->showState)
729
0
    {
730
0
      case 0:
731
0
        showStr = "hidden";
732
0
        break;
733
0
      case 2:
734
0
        showStr = "minimized";
735
0
        break;
736
0
      case 3:
737
0
        showStr = "maximized";
738
0
        break;
739
0
      case 5:
740
0
        showStr = "show";
741
0
        break;
742
0
      default:
743
0
        showStr = "<unknown>";
744
0
        break;
745
0
    }
746
0
    DUMP_APPEND(buffer, bufferSize, " show=%s", showStr);
747
0
  }
748
749
0
  if (order->fieldFlags & WINDOW_ORDER_FIELD_TITLE)
750
0
  {
751
0
    char* title = rail_string_to_utf8_string(&state->titleInfo);
752
0
    if (title)
753
0
    {
754
0
      DUMP_APPEND(buffer, bufferSize, " title=\"%s\"", title);
755
0
      free(title);
756
0
    }
757
0
    else
758
0
      DUMP_APPEND(buffer, bufferSize, " title=<decode failed>");
759
0
  }
760
0
  if (order->fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_OFFSET)
761
0
    DUMP_APPEND(buffer, bufferSize, " clientOffset=(%" PRId32 ",%" PRId32 ")",
762
0
                state->clientOffsetX, state->clientOffsetY);
763
0
  if (order->fieldFlags & WINDOW_ORDER_FIELD_CLIENT_AREA_SIZE)
764
0
    DUMP_APPEND(buffer, bufferSize, " clientAreaWidth=%" PRIu32 " clientAreaHeight=%" PRIu32 "",
765
0
                state->clientAreaWidth, state->clientAreaHeight);
766
0
  if (order->fieldFlags & WINDOW_ORDER_FIELD_RESIZE_MARGIN_X)
767
0
    DUMP_APPEND(buffer, bufferSize,
768
0
                " resizeMarginLeft=%" PRIu32 " resizeMarginRight=%" PRIu32 "",
769
0
                state->resizeMarginLeft, state->resizeMarginRight);
770
0
  if (order->fieldFlags & WINDOW_ORDER_FIELD_RESIZE_MARGIN_Y)
771
0
    DUMP_APPEND(buffer, bufferSize,
772
0
                " resizeMarginTop=%" PRIu32 " resizeMarginBottom=%" PRIu32 "",
773
0
                state->resizeMarginTop, state->resizeMarginBottom);
774
0
  if (order->fieldFlags & WINDOW_ORDER_FIELD_RP_CONTENT)
775
0
    DUMP_APPEND(buffer, bufferSize, " rpContent=0x%" PRIx32 "", state->RPContent);
776
0
  if (order->fieldFlags & WINDOW_ORDER_FIELD_ROOT_PARENT)
777
0
    DUMP_APPEND(buffer, bufferSize, " rootParent=0x%" PRIx32 "", state->rootParentHandle);
778
0
  if (order->fieldFlags & WINDOW_ORDER_FIELD_WND_OFFSET)
779
0
    DUMP_APPEND(buffer, bufferSize, " windowOffset=(%" PRId32 ",%" PRId32 ")",
780
0
                state->windowOffsetX, state->windowOffsetY);
781
0
  if (order->fieldFlags & WINDOW_ORDER_FIELD_WND_CLIENT_DELTA)
782
0
    DUMP_APPEND(buffer, bufferSize, " windowClientDelta=(%" PRId32 ",%" PRId32 ")",
783
0
                state->windowClientDeltaX, state->windowClientDeltaY);
784
0
  if (order->fieldFlags & WINDOW_ORDER_FIELD_WND_SIZE)
785
0
    DUMP_APPEND(buffer, bufferSize, " windowWidth=%" PRIu32 " windowHeight=%" PRIu32 "",
786
0
                state->windowWidth, state->windowHeight);
787
788
0
  if (order->fieldFlags & WINDOW_ORDER_FIELD_WND_RECTS)
789
0
  {
790
0
    DUMP_APPEND(buffer, bufferSize, " windowRects=(");
791
0
    for (UINT32 i = 0; i < state->numWindowRects; i++)
792
0
    {
793
0
      DUMP_APPEND(buffer, bufferSize, "(%" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16 ")",
794
0
                  state->windowRects[i].left, state->windowRects[i].top,
795
0
                  state->windowRects[i].right, state->windowRects[i].bottom);
796
0
    }
797
0
    DUMP_APPEND(buffer, bufferSize, ")");
798
0
  }
799
800
0
  if (order->fieldFlags & WINDOW_ORDER_FIELD_VIS_OFFSET)
801
0
    DUMP_APPEND(buffer, bufferSize, " visibleOffset=(%" PRId32 ",%" PRId32 ")",
802
0
                state->visibleOffsetX, state->visibleOffsetY);
803
804
0
  if (order->fieldFlags & WINDOW_ORDER_FIELD_VISIBILITY)
805
0
  {
806
0
    DUMP_APPEND(buffer, bufferSize, " visibilityRects=(");
807
0
    for (UINT32 i = 0; i < state->numVisibilityRects; i++)
808
0
    {
809
0
      DUMP_APPEND(buffer, bufferSize, "(%" PRIu16 ",%" PRIu16 ",%" PRIu16 ",%" PRIu16 ")",
810
0
                  state->visibilityRects[i].left, state->visibilityRects[i].top,
811
0
                  state->visibilityRects[i].right, state->visibilityRects[i].bottom);
812
0
    }
813
0
    DUMP_APPEND(buffer, bufferSize, ")");
814
0
  }
815
816
0
  if (order->fieldFlags & WINDOW_ORDER_FIELD_OVERLAY_DESCRIPTION)
817
0
    DUMP_APPEND(buffer, bufferSize, " overlayDescr");
818
819
0
  if (order->fieldFlags & WINDOW_ORDER_FIELD_ICON_OVERLAY_NULL)
820
0
    DUMP_APPEND(buffer, bufferSize, " iconOverlayNull");
821
822
0
  if (order->fieldFlags & WINDOW_ORDER_FIELD_TASKBAR_BUTTON)
823
0
    DUMP_APPEND(buffer, bufferSize, " taskBarButton=0x%" PRIx8 "", state->TaskbarButton);
824
825
0
  if (order->fieldFlags & WINDOW_ORDER_FIELD_ENFORCE_SERVER_ZORDER)
826
0
    DUMP_APPEND(buffer, bufferSize, " enforceServerZOrder=0x%" PRIx8 "",
827
0
                state->EnforceServerZOrder);
828
0
  if (order->fieldFlags & WINDOW_ORDER_FIELD_APPBAR_STATE)
829
0
    DUMP_APPEND(buffer, bufferSize, " appBarState=0x%" PRIx8 "", state->AppBarState);
830
0
  if (order->fieldFlags & WINDOW_ORDER_FIELD_APPBAR_EDGE)
831
0
  {
832
0
    const char* appBarEdgeStr = nullptr;
833
0
    switch (state->AppBarEdge)
834
0
    {
835
0
      case 0:
836
0
        appBarEdgeStr = "left";
837
0
        break;
838
0
      case 1:
839
0
        appBarEdgeStr = "top";
840
0
        break;
841
0
      case 2:
842
0
        appBarEdgeStr = "right";
843
0
        break;
844
0
      case 3:
845
0
        appBarEdgeStr = "bottom";
846
0
        break;
847
0
      default:
848
0
        appBarEdgeStr = "<unknown>";
849
0
        break;
850
0
    }
851
0
    DUMP_APPEND(buffer, bufferSize, " appBarEdge=%s", appBarEdgeStr);
852
0
  }
853
854
0
  WLog_Print(log, WLOG_DEBUG, "%s", buffer);
855
0
}
856
857
static BOOL update_recv_window_info_order(rdpUpdate* update, wStream* s,
858
                                          WINDOW_ORDER_INFO* orderInfo)
859
0
{
860
0
  rdp_update_internal* up = update_cast(update);
861
0
  rdpContext* context = update->context;
862
0
  rdpWindowUpdate* window = update->window;
863
864
0
  BOOL result = TRUE;
865
866
0
  WINPR_ASSERT(s);
867
0
  WINPR_ASSERT(context);
868
0
  WINPR_ASSERT(window);
869
0
  WINPR_ASSERT(orderInfo);
870
871
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
872
0
    return FALSE;
873
874
0
  Stream_Read_UINT32(s, orderInfo->windowId); /* windowId (4 bytes) */
875
876
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_ICON)
877
0
  {
878
0
    WINDOW_ICON_ORDER window_icon = WINPR_C_ARRAY_INIT;
879
0
    result = update_read_window_icon_order(s, orderInfo, &window_icon);
880
881
0
    if (result)
882
0
    {
883
0
      WLog_Print(up->log, WLOG_DEBUG, "WindowIcon windowId=0x%" PRIx32 "",
884
0
                 orderInfo->windowId);
885
0
      IFCALLRET(window->WindowIcon, result, context, orderInfo, &window_icon);
886
0
    }
887
888
0
    update_free_window_icon_info(window_icon.iconInfo);
889
0
    free(window_icon.iconInfo);
890
0
  }
891
0
  else if (orderInfo->fieldFlags & WINDOW_ORDER_CACHED_ICON)
892
0
  {
893
0
    WINDOW_CACHED_ICON_ORDER window_cached_icon = WINPR_C_ARRAY_INIT;
894
0
    result = update_read_window_cached_icon_order(s, orderInfo, &window_cached_icon);
895
896
0
    if (result)
897
0
    {
898
0
      WLog_Print(up->log, WLOG_DEBUG, "WindowCachedIcon windowId=0x%" PRIx32 "",
899
0
                 orderInfo->windowId);
900
0
      IFCALLRET(window->WindowCachedIcon, result, context, orderInfo, &window_cached_icon);
901
0
    }
902
0
  }
903
0
  else if (orderInfo->fieldFlags & WINDOW_ORDER_STATE_DELETED)
904
0
  {
905
0
    update_read_window_delete_order(s, orderInfo);
906
0
    WLog_Print(up->log, WLOG_DEBUG, "WindowDelete windowId=0x%" PRIx32 "", orderInfo->windowId);
907
0
    IFCALLRET(window->WindowDelete, result, context, orderInfo);
908
0
  }
909
0
  else
910
0
  {
911
0
    WINDOW_STATE_ORDER windowState = WINPR_C_ARRAY_INIT;
912
0
    result = update_read_window_state_order(s, orderInfo, &windowState);
913
914
0
    if (result)
915
0
    {
916
0
      if (orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW)
917
0
      {
918
0
        dump_window_state_order(up->log, "WindowCreate", orderInfo, &windowState);
919
0
        IFCALLRET(window->WindowCreate, result, context, orderInfo, &windowState);
920
0
      }
921
0
      else
922
0
      {
923
0
        dump_window_state_order(up->log, "WindowUpdate", orderInfo, &windowState);
924
0
        IFCALLRET(window->WindowUpdate, result, context, orderInfo, &windowState);
925
0
      }
926
927
0
      update_free_window_state(&windowState);
928
0
    }
929
0
  }
930
931
0
  return result;
932
0
}
933
934
static void update_notify_icon_state_order_free(NOTIFY_ICON_STATE_ORDER* notify)
935
0
{
936
0
  WINPR_ASSERT(notify);
937
0
  rail_unicode_string_free(&notify->toolTip);
938
0
  rail_unicode_string_free(&notify->infoTip.text);
939
0
  rail_unicode_string_free(&notify->infoTip.title);
940
0
  update_free_window_icon_info(&notify->icon);
941
0
  memset(notify, 0, sizeof(NOTIFY_ICON_STATE_ORDER));
942
0
}
943
944
static BOOL update_read_notification_icon_state_order(wStream* s, WINDOW_ORDER_INFO* orderInfo,
945
                                                      NOTIFY_ICON_STATE_ORDER* notify_icon_state)
946
0
{
947
0
  WINPR_ASSERT(orderInfo);
948
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_VERSION)
949
0
  {
950
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
951
0
      return FALSE;
952
953
0
    Stream_Read_UINT32(s, notify_icon_state->version); /* version (4 bytes) */
954
0
  }
955
956
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_TIP)
957
0
  {
958
0
    if (!rail_read_unicode_string(s,
959
0
                                  &notify_icon_state->toolTip)) /* toolTip (UNICODE_STRING) */
960
0
      return FALSE;
961
0
  }
962
963
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_INFO_TIP)
964
0
  {
965
0
    if (!update_read_notify_icon_infotip(
966
0
            s, &notify_icon_state->infoTip)) /* infoTip (NOTIFY_ICON_INFOTIP) */
967
0
      return FALSE;
968
0
  }
969
970
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_NOTIFY_STATE)
971
0
  {
972
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
973
0
      return FALSE;
974
975
0
    Stream_Read_UINT32(s, notify_icon_state->state); /* state (4 bytes) */
976
0
  }
977
978
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_ICON)
979
0
  {
980
0
    if (!update_read_icon_info(s, &notify_icon_state->icon)) /* icon (ICON_INFO) */
981
0
      return FALSE;
982
0
  }
983
984
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_CACHED_ICON)
985
0
  {
986
0
    if (!update_read_cached_icon_info(
987
0
            s, &notify_icon_state->cachedIcon)) /* cachedIcon (CACHED_ICON_INFO) */
988
0
      return FALSE;
989
0
  }
990
991
0
  return TRUE;
992
0
}
993
994
static void
995
update_read_notification_icon_delete_order(WINPR_ATTR_UNUSED wStream* s,
996
                                           WINPR_ATTR_UNUSED WINDOW_ORDER_INFO* orderInfo)
997
0
{
998
  /* notification icon deletion event */
999
0
}
1000
1001
static BOOL update_recv_notification_icon_info_order(rdpUpdate* update, wStream* s,
1002
                                                     WINDOW_ORDER_INFO* orderInfo)
1003
0
{
1004
0
  rdp_update_internal* up = update_cast(update);
1005
0
  rdpContext* context = update->context;
1006
0
  rdpWindowUpdate* window = update->window;
1007
0
  BOOL result = TRUE;
1008
1009
0
  WINPR_ASSERT(s);
1010
0
  WINPR_ASSERT(orderInfo);
1011
0
  WINPR_ASSERT(context);
1012
0
  WINPR_ASSERT(window);
1013
1014
0
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
1015
0
    return FALSE;
1016
1017
0
  Stream_Read_UINT32(s, orderInfo->windowId);     /* windowId (4 bytes) */
1018
0
  Stream_Read_UINT32(s, orderInfo->notifyIconId); /* notifyIconId (4 bytes) */
1019
1020
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_STATE_DELETED)
1021
0
  {
1022
0
    update_read_notification_icon_delete_order(s, orderInfo);
1023
0
    WLog_Print(up->log, WLOG_DEBUG, "NotifyIconDelete");
1024
0
    IFCALLRET(window->NotifyIconDelete, result, context, orderInfo);
1025
0
  }
1026
0
  else
1027
0
  {
1028
0
    NOTIFY_ICON_STATE_ORDER notify_icon_state = WINPR_C_ARRAY_INIT;
1029
0
    result = update_read_notification_icon_state_order(s, orderInfo, &notify_icon_state);
1030
1031
0
    if (!result)
1032
0
      goto fail;
1033
1034
0
    if (orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW)
1035
0
    {
1036
0
      WLog_Print(up->log, WLOG_DEBUG, "NotifyIconCreate");
1037
0
      IFCALLRET(window->NotifyIconCreate, result, context, orderInfo, &notify_icon_state);
1038
0
    }
1039
0
    else
1040
0
    {
1041
0
      WLog_Print(up->log, WLOG_DEBUG, "NotifyIconUpdate");
1042
0
      IFCALLRET(window->NotifyIconUpdate, result, context, orderInfo, &notify_icon_state);
1043
0
    }
1044
0
  fail:
1045
0
    update_notify_icon_state_order_free(&notify_icon_state);
1046
0
  }
1047
1048
0
  return result;
1049
0
}
1050
1051
static BOOL update_read_desktop_actively_monitored_order(wStream* s,
1052
                                                         const WINDOW_ORDER_INFO* orderInfo,
1053
                                                         MONITORED_DESKTOP_ORDER* monitored_desktop)
1054
0
{
1055
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_ACTIVE_WND)
1056
0
  {
1057
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
1058
0
      return FALSE;
1059
1060
0
    Stream_Read_UINT32(s, monitored_desktop->activeWindowId); /* activeWindowId (4 bytes) */
1061
0
  }
1062
1063
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_ZORDER)
1064
0
  {
1065
0
    if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
1066
0
      return FALSE;
1067
1068
0
    Stream_Read_UINT8(s, monitored_desktop->numWindowIds); /* numWindowIds (1 byte) */
1069
1070
0
    if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, monitored_desktop->numWindowIds, 4ull))
1071
0
    {
1072
0
      monitored_desktop->numWindowIds = 0;
1073
0
      return FALSE;
1074
0
    }
1075
1076
0
    if (monitored_desktop->numWindowIds > 0)
1077
0
    {
1078
0
      const size_t size = sizeof(UINT32) * monitored_desktop->numWindowIds;
1079
0
      UINT32* newid = (UINT32*)realloc(monitored_desktop->windowIds, size);
1080
1081
0
      if (!newid)
1082
0
      {
1083
0
        free(monitored_desktop->windowIds);
1084
0
        monitored_desktop->windowIds = nullptr;
1085
0
        monitored_desktop->numWindowIds = 0;
1086
0
        return FALSE;
1087
0
      }
1088
1089
0
      monitored_desktop->windowIds = newid;
1090
1091
      /* windowIds */
1092
0
      for (UINT32 i = 0; i < monitored_desktop->numWindowIds; i++)
1093
0
      {
1094
0
        Stream_Read_UINT32(s, monitored_desktop->windowIds[i]);
1095
0
      }
1096
0
    }
1097
0
    else
1098
0
    {
1099
0
      free(monitored_desktop->windowIds);
1100
0
      monitored_desktop->windowIds = nullptr;
1101
0
    }
1102
0
  }
1103
1104
0
  return TRUE;
1105
0
}
1106
1107
static void update_read_desktop_non_monitored_order(WINPR_ATTR_UNUSED wStream* s,
1108
                                                    WINPR_ATTR_UNUSED WINDOW_ORDER_INFO* orderInfo)
1109
0
{
1110
  /* non-monitored desktop notification event */
1111
0
}
1112
1113
static void dump_monitored_desktop(wLog* log, const char* msg, const WINDOW_ORDER_INFO* orderInfo,
1114
                                   const MONITORED_DESKTOP_ORDER* monitored)
1115
0
{
1116
0
  char buffer[1000] = WINPR_C_ARRAY_INIT;
1117
0
  const size_t bufferSize = sizeof(buffer) - 1;
1118
1119
0
  DUMP_APPEND(buffer, bufferSize, "%s", msg);
1120
1121
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_ACTIVE_WND)
1122
0
    DUMP_APPEND(buffer, bufferSize, " activeWindowId=0x%" PRIx32 "", monitored->activeWindowId);
1123
1124
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_ZORDER)
1125
0
  {
1126
0
    DUMP_APPEND(buffer, bufferSize, " windows=(");
1127
0
    for (UINT32 i = 0; i < monitored->numWindowIds; i++)
1128
0
    {
1129
0
      WINPR_ASSERT(monitored->windowIds);
1130
0
      DUMP_APPEND(buffer, bufferSize, "0x%" PRIx32 ",", monitored->windowIds[i]);
1131
0
    }
1132
0
    DUMP_APPEND(buffer, bufferSize, ")");
1133
0
  }
1134
0
  WLog_Print(log, WLOG_DEBUG, "%s", buffer);
1135
0
}
1136
1137
static BOOL update_recv_desktop_info_order(rdpUpdate* update, wStream* s,
1138
                                           WINDOW_ORDER_INFO* orderInfo)
1139
0
{
1140
0
  rdp_update_internal* up = update_cast(update);
1141
0
  rdpContext* context = update->context;
1142
0
  rdpWindowUpdate* window = update->window;
1143
0
  BOOL result = TRUE;
1144
1145
0
  WINPR_ASSERT(s);
1146
0
  WINPR_ASSERT(orderInfo);
1147
0
  WINPR_ASSERT(context);
1148
0
  WINPR_ASSERT(window);
1149
1150
0
  if (orderInfo->fieldFlags & WINDOW_ORDER_FIELD_DESKTOP_NONE)
1151
0
  {
1152
0
    update_read_desktop_non_monitored_order(s, orderInfo);
1153
0
    WLog_Print(up->log, WLOG_DEBUG, "NonMonitoredDesktop, windowId=0x%" PRIx32 "",
1154
0
               orderInfo->windowId);
1155
0
    IFCALLRET(window->NonMonitoredDesktop, result, context, orderInfo);
1156
0
  }
1157
0
  else
1158
0
  {
1159
0
    MONITORED_DESKTOP_ORDER monitored_desktop = WINPR_C_ARRAY_INIT;
1160
0
    result = update_read_desktop_actively_monitored_order(s, orderInfo, &monitored_desktop);
1161
1162
0
    if (result)
1163
0
    {
1164
0
      dump_monitored_desktop(up->log, "ActivelyMonitoredDesktop", orderInfo,
1165
0
                             &monitored_desktop);
1166
0
      IFCALLRET(window->MonitoredDesktop, result, context, orderInfo, &monitored_desktop);
1167
0
    }
1168
1169
0
    free(monitored_desktop.windowIds);
1170
0
  }
1171
1172
0
  return result;
1173
0
}
1174
1175
void update_free_window_icon_info(ICON_INFO* iconInfo)
1176
0
{
1177
0
  if (!iconInfo)
1178
0
    return;
1179
1180
0
  free(iconInfo->bitsColor);
1181
0
  iconInfo->bitsColor = nullptr;
1182
0
  free(iconInfo->bitsMask);
1183
0
  iconInfo->bitsMask = nullptr;
1184
0
  free(iconInfo->colorTable);
1185
0
  iconInfo->colorTable = nullptr;
1186
0
}
1187
1188
BOOL update_recv_altsec_window_order(rdpUpdate* update, wStream* s)
1189
16.5k
{
1190
16.5k
  BOOL rc = TRUE;
1191
16.5k
  size_t remaining = 0;
1192
16.5k
  UINT16 orderSize = 0;
1193
16.5k
  WINDOW_ORDER_INFO orderInfo = WINPR_C_ARRAY_INIT;
1194
16.5k
  rdp_update_internal* up = update_cast(update);
1195
1196
16.5k
  remaining = Stream_GetRemainingLength(s);
1197
1198
16.5k
  if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
1199
7.56k
    return FALSE;
1200
1201
8.98k
  Stream_Read_UINT16(s, orderSize);            /* orderSize (2 bytes) */
1202
8.98k
  Stream_Read_UINT32(s, orderInfo.fieldFlags); /* FieldsPresentFlags (4 bytes) */
1203
1204
8.98k
  if (remaining + 1 < orderSize)
1205
4.49k
  {
1206
4.49k
    WLog_Print(up->log, WLOG_ERROR, "Stream short orderSize");
1207
4.49k
    return FALSE;
1208
4.49k
  }
1209
1210
4.49k
  if (!window_order_supported(update->context->settings, orderInfo.fieldFlags))
1211
4.49k
  {
1212
4.49k
    WLog_INFO(TAG, "Window order %08" PRIx32 " not supported!", orderInfo.fieldFlags);
1213
4.49k
    return FALSE;
1214
4.49k
  }
1215
1216
0
  if (orderInfo.fieldFlags & WINDOW_ORDER_TYPE_WINDOW)
1217
0
    rc = update_recv_window_info_order(update, s, &orderInfo);
1218
0
  else if (orderInfo.fieldFlags & WINDOW_ORDER_TYPE_NOTIFY)
1219
0
    rc = update_recv_notification_icon_info_order(update, s, &orderInfo);
1220
0
  else if (orderInfo.fieldFlags & WINDOW_ORDER_TYPE_DESKTOP)
1221
0
    rc = update_recv_desktop_info_order(update, s, &orderInfo);
1222
1223
0
  if (!rc)
1224
0
    WLog_Print(up->log, WLOG_ERROR, "windoworder flags %08" PRIx32 " failed",
1225
0
               orderInfo.fieldFlags);
1226
1227
0
  return rc;
1228
4.49k
}