FreeRDP
mouse_cursor_main.c
1 
20 #include <freerdp/config.h>
21 
22 #include <freerdp/freerdp.h>
23 #include <freerdp/channels/log.h>
24 #include <freerdp/server/rdpemsc.h>
25 
26 #define TAG CHANNELS_TAG("rdpemsc.server")
27 
28 typedef enum
29 {
30  MOUSE_CURSOR_INITIAL,
31  MOUSE_CURSOR_OPENED,
32 } eMouseCursorChannelState;
33 
34 typedef struct
35 {
36  MouseCursorServerContext context;
37 
38  HANDLE stopEvent;
39 
40  HANDLE thread;
41  void* mouse_cursor_channel;
42 
43  DWORD SessionId;
44 
45  BOOL isOpened;
46  BOOL externalThread;
47 
48  /* Channel state */
49  eMouseCursorChannelState state;
50 
51  wStream* buffer;
52 } mouse_cursor_server;
53 
54 static UINT mouse_cursor_server_initialize(MouseCursorServerContext* context, BOOL externalThread)
55 {
56  UINT error = CHANNEL_RC_OK;
57  mouse_cursor_server* mouse_cursor = (mouse_cursor_server*)context;
58 
59  WINPR_ASSERT(mouse_cursor);
60 
61  if (mouse_cursor->isOpened)
62  {
63  WLog_WARN(TAG, "Application error: Mouse Cursor channel already initialized, "
64  "calling in this state is not possible!");
65  return ERROR_INVALID_STATE;
66  }
67 
68  mouse_cursor->externalThread = externalThread;
69 
70  return error;
71 }
72 
73 static UINT mouse_cursor_server_open_channel(mouse_cursor_server* mouse_cursor)
74 {
75  MouseCursorServerContext* context = NULL;
76  DWORD Error = ERROR_SUCCESS;
77  DWORD BytesReturned = 0;
78  PULONG pSessionId = NULL;
79  UINT32 channelId = 0;
80  BOOL status = TRUE;
81 
82  WINPR_ASSERT(mouse_cursor);
83  context = &mouse_cursor->context;
84  WINPR_ASSERT(context);
85 
86  if (WTSQuerySessionInformationA(mouse_cursor->context.vcm, WTS_CURRENT_SESSION, WTSSessionId,
87  (LPSTR*)&pSessionId, &BytesReturned) == FALSE)
88  {
89  WLog_ERR(TAG, "WTSQuerySessionInformationA failed!");
90  return ERROR_INTERNAL_ERROR;
91  }
92 
93  mouse_cursor->SessionId = (DWORD)*pSessionId;
94  WTSFreeMemory(pSessionId);
95 
96  mouse_cursor->mouse_cursor_channel = WTSVirtualChannelOpenEx(
97  mouse_cursor->SessionId, RDPEMSC_DVC_CHANNEL_NAME, WTS_CHANNEL_OPTION_DYNAMIC);
98  if (!mouse_cursor->mouse_cursor_channel)
99  {
100  Error = GetLastError();
101  WLog_ERR(TAG, "WTSVirtualChannelOpenEx failed with error %" PRIu32 "!", Error);
102  return Error;
103  }
104 
105  channelId = WTSChannelGetIdByHandle(mouse_cursor->mouse_cursor_channel);
106 
107  IFCALLRET(context->ChannelIdAssigned, status, context, channelId);
108  if (!status)
109  {
110  WLog_ERR(TAG, "context->ChannelIdAssigned failed!");
111  return ERROR_INTERNAL_ERROR;
112  }
113 
114  return Error;
115 }
116 
117 static BOOL read_cap_set(wStream* s, wArrayList* capsSets)
118 {
119  RDP_MOUSE_CURSOR_CAPSET* capsSet = NULL;
120  UINT32 signature = 0;
121  RDP_MOUSE_CURSOR_CAPVERSION version = RDP_MOUSE_CURSOR_CAPVERSION_INVALID;
122  UINT32 size = 0;
123  size_t capsDataSize = 0;
124 
125  if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
126  return FALSE;
127 
128  Stream_Read_UINT32(s, signature);
129  Stream_Read_UINT32(s, version);
130  Stream_Read_UINT32(s, size);
131 
132  if (size < 12)
133  {
134  WLog_ERR(TAG, "Size of caps set is invalid: %u", size);
135  return FALSE;
136  }
137 
138  capsDataSize = size - 12;
139  if (!Stream_CheckAndLogRequiredLength(TAG, s, capsDataSize))
140  return FALSE;
141 
142  switch (version)
143  {
145  {
146  RDP_MOUSE_CURSOR_CAPSET_VERSION1* capsSetV1 = NULL;
147 
148  capsSetV1 = calloc(1, sizeof(RDP_MOUSE_CURSOR_CAPSET_VERSION1));
149  if (!capsSetV1)
150  return FALSE;
151 
152  capsSet = (RDP_MOUSE_CURSOR_CAPSET*)capsSetV1;
153  break;
154  }
155  default:
156  WLog_WARN(TAG, "Received caps set with unknown version %u", version);
157  Stream_Seek(s, capsDataSize);
158  return TRUE;
159  }
160  WINPR_ASSERT(capsSet);
161 
162  capsSet->signature = signature;
163  capsSet->version = version;
164  capsSet->size = size;
165 
166  if (!ArrayList_Append(capsSets, capsSet))
167  {
168  WLog_ERR(TAG, "Failed to append caps set to arraylist");
169  free(capsSet);
170  return FALSE;
171  }
172 
173  // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): ArrayList_Append owns capsSet
174  return TRUE;
175 }
176 
177 static UINT mouse_cursor_server_recv_cs_caps_advertise(MouseCursorServerContext* context,
178  wStream* s,
179  const RDP_MOUSE_CURSOR_HEADER* header)
180 {
182  UINT error = CHANNEL_RC_OK;
183 
184  WINPR_ASSERT(context);
185  WINPR_ASSERT(s);
186  WINPR_ASSERT(header);
187 
188  pdu.header = *header;
189 
190  /* There must be at least one capability set present */
191  if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
192  return ERROR_NO_DATA;
193 
194  pdu.capsSets = ArrayList_New(FALSE);
195  if (!pdu.capsSets)
196  {
197  WLog_ERR(TAG, "Failed to allocate arraylist");
198  return ERROR_NOT_ENOUGH_MEMORY;
199  }
200 
201  wObject* aobj = ArrayList_Object(pdu.capsSets);
202  WINPR_ASSERT(aobj);
203  aobj->fnObjectFree = free;
204 
205  while (Stream_GetRemainingLength(s) > 0)
206  {
207  if (!read_cap_set(s, pdu.capsSets))
208  {
209  ArrayList_Free(pdu.capsSets);
210  return ERROR_INVALID_DATA;
211  }
212  }
213 
214  IFCALLRET(context->CapsAdvertise, error, context, &pdu);
215  if (error)
216  WLog_ERR(TAG, "context->CapsAdvertise failed with error %" PRIu32 "", error);
217 
218  ArrayList_Free(pdu.capsSets);
219 
220  return error;
221 }
222 
223 static UINT mouse_cursor_process_message(mouse_cursor_server* mouse_cursor)
224 {
225  BOOL rc = 0;
226  UINT error = ERROR_INTERNAL_ERROR;
227  ULONG BytesReturned = 0;
228  RDP_MOUSE_CURSOR_HEADER header = { 0 };
229  wStream* s = NULL;
230 
231  WINPR_ASSERT(mouse_cursor);
232  WINPR_ASSERT(mouse_cursor->mouse_cursor_channel);
233 
234  s = mouse_cursor->buffer;
235  WINPR_ASSERT(s);
236 
237  Stream_SetPosition(s, 0);
238  rc = WTSVirtualChannelRead(mouse_cursor->mouse_cursor_channel, 0, NULL, 0, &BytesReturned);
239  if (!rc)
240  goto out;
241 
242  if (BytesReturned < 1)
243  {
244  error = CHANNEL_RC_OK;
245  goto out;
246  }
247 
248  if (!Stream_EnsureRemainingCapacity(s, BytesReturned))
249  {
250  WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
251  error = CHANNEL_RC_NO_MEMORY;
252  goto out;
253  }
254 
255  if (WTSVirtualChannelRead(mouse_cursor->mouse_cursor_channel, 0, Stream_BufferAs(s, char),
256  (ULONG)Stream_Capacity(s), &BytesReturned) == FALSE)
257  {
258  WLog_ERR(TAG, "WTSVirtualChannelRead failed!");
259  goto out;
260  }
261 
262  Stream_SetLength(s, BytesReturned);
263  if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPEMSC_HEADER_SIZE))
264  return ERROR_NO_DATA;
265 
266  Stream_Read_UINT8(s, header.pduType);
267  Stream_Read_UINT8(s, header.updateType);
268  Stream_Read_UINT16(s, header.reserved);
269 
270  switch (header.pduType)
271  {
272  case PDUTYPE_CS_CAPS_ADVERTISE:
273  error = mouse_cursor_server_recv_cs_caps_advertise(&mouse_cursor->context, s, &header);
274  break;
275  default:
276  WLog_ERR(TAG, "mouse_cursor_process_message: unknown or invalid pduType %" PRIu8 "",
277  header.pduType);
278  break;
279  }
280 
281 out:
282  if (error)
283  WLog_ERR(TAG, "Response failed with error %" PRIu32 "!", error);
284 
285  return error;
286 }
287 
288 static UINT mouse_cursor_server_context_poll_int(MouseCursorServerContext* context)
289 {
290  mouse_cursor_server* mouse_cursor = (mouse_cursor_server*)context;
291  UINT error = ERROR_INTERNAL_ERROR;
292 
293  WINPR_ASSERT(mouse_cursor);
294 
295  switch (mouse_cursor->state)
296  {
297  case MOUSE_CURSOR_INITIAL:
298  error = mouse_cursor_server_open_channel(mouse_cursor);
299  if (error)
300  WLog_ERR(TAG, "mouse_cursor_server_open_channel failed with error %" PRIu32 "!",
301  error);
302  else
303  mouse_cursor->state = MOUSE_CURSOR_OPENED;
304  break;
305  case MOUSE_CURSOR_OPENED:
306  error = mouse_cursor_process_message(mouse_cursor);
307  break;
308  default:
309  break;
310  }
311 
312  return error;
313 }
314 
315 static HANDLE mouse_cursor_server_get_channel_handle(mouse_cursor_server* mouse_cursor)
316 {
317  void* buffer = NULL;
318  DWORD BytesReturned = 0;
319  HANDLE ChannelEvent = NULL;
320 
321  WINPR_ASSERT(mouse_cursor);
322 
323  if (WTSVirtualChannelQuery(mouse_cursor->mouse_cursor_channel, WTSVirtualEventHandle, &buffer,
324  &BytesReturned) == TRUE)
325  {
326  if (BytesReturned == sizeof(HANDLE))
327  CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE));
328 
329  WTSFreeMemory(buffer);
330  }
331 
332  return ChannelEvent;
333 }
334 
335 static DWORD WINAPI mouse_cursor_server_thread_func(LPVOID arg)
336 {
337  DWORD nCount = 0;
338  HANDLE events[2] = { 0 };
339  mouse_cursor_server* mouse_cursor = (mouse_cursor_server*)arg;
340  UINT error = CHANNEL_RC_OK;
341  DWORD status = 0;
342 
343  WINPR_ASSERT(mouse_cursor);
344 
345  nCount = 0;
346  events[nCount++] = mouse_cursor->stopEvent;
347 
348  while ((error == CHANNEL_RC_OK) && (WaitForSingleObject(events[0], 0) != WAIT_OBJECT_0))
349  {
350  switch (mouse_cursor->state)
351  {
352  case MOUSE_CURSOR_INITIAL:
353  error = mouse_cursor_server_context_poll_int(&mouse_cursor->context);
354  if (error == CHANNEL_RC_OK)
355  {
356  events[1] = mouse_cursor_server_get_channel_handle(mouse_cursor);
357  nCount = 2;
358  }
359  break;
360  case MOUSE_CURSOR_OPENED:
361  status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
362  switch (status)
363  {
364  case WAIT_OBJECT_0:
365  break;
366  case WAIT_OBJECT_0 + 1:
367  case WAIT_TIMEOUT:
368  error = mouse_cursor_server_context_poll_int(&mouse_cursor->context);
369  break;
370 
371  case WAIT_FAILED:
372  default:
373  error = ERROR_INTERNAL_ERROR;
374  break;
375  }
376  break;
377  default:
378  break;
379  }
380  }
381 
382  (void)WTSVirtualChannelClose(mouse_cursor->mouse_cursor_channel);
383  mouse_cursor->mouse_cursor_channel = NULL;
384 
385  if (error && mouse_cursor->context.rdpcontext)
386  setChannelError(mouse_cursor->context.rdpcontext, error,
387  "mouse_cursor_server_thread_func reported an error");
388 
389  ExitThread(error);
390  return error;
391 }
392 
393 static UINT mouse_cursor_server_open(MouseCursorServerContext* context)
394 {
395  mouse_cursor_server* mouse_cursor = (mouse_cursor_server*)context;
396 
397  WINPR_ASSERT(mouse_cursor);
398 
399  if (!mouse_cursor->externalThread && (mouse_cursor->thread == NULL))
400  {
401  mouse_cursor->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
402  if (!mouse_cursor->stopEvent)
403  {
404  WLog_ERR(TAG, "CreateEvent failed!");
405  return ERROR_INTERNAL_ERROR;
406  }
407 
408  mouse_cursor->thread =
409  CreateThread(NULL, 0, mouse_cursor_server_thread_func, mouse_cursor, 0, NULL);
410  if (!mouse_cursor->thread)
411  {
412  WLog_ERR(TAG, "CreateThread failed!");
413  (void)CloseHandle(mouse_cursor->stopEvent);
414  mouse_cursor->stopEvent = NULL;
415  return ERROR_INTERNAL_ERROR;
416  }
417  }
418  mouse_cursor->isOpened = TRUE;
419 
420  return CHANNEL_RC_OK;
421 }
422 
423 static UINT mouse_cursor_server_close(MouseCursorServerContext* context)
424 {
425  UINT error = CHANNEL_RC_OK;
426  mouse_cursor_server* mouse_cursor = (mouse_cursor_server*)context;
427 
428  WINPR_ASSERT(mouse_cursor);
429 
430  if (!mouse_cursor->externalThread && mouse_cursor->thread)
431  {
432  (void)SetEvent(mouse_cursor->stopEvent);
433 
434  if (WaitForSingleObject(mouse_cursor->thread, INFINITE) == WAIT_FAILED)
435  {
436  error = GetLastError();
437  WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
438  return error;
439  }
440 
441  (void)CloseHandle(mouse_cursor->thread);
442  (void)CloseHandle(mouse_cursor->stopEvent);
443  mouse_cursor->thread = NULL;
444  mouse_cursor->stopEvent = NULL;
445  }
446  if (mouse_cursor->externalThread)
447  {
448  if (mouse_cursor->state != MOUSE_CURSOR_INITIAL)
449  {
450  (void)WTSVirtualChannelClose(mouse_cursor->mouse_cursor_channel);
451  mouse_cursor->mouse_cursor_channel = NULL;
452  mouse_cursor->state = MOUSE_CURSOR_INITIAL;
453  }
454  }
455  mouse_cursor->isOpened = FALSE;
456 
457  return error;
458 }
459 
460 static UINT mouse_cursor_server_context_poll(MouseCursorServerContext* context)
461 {
462  mouse_cursor_server* mouse_cursor = (mouse_cursor_server*)context;
463 
464  WINPR_ASSERT(mouse_cursor);
465 
466  if (!mouse_cursor->externalThread)
467  return ERROR_INTERNAL_ERROR;
468 
469  return mouse_cursor_server_context_poll_int(context);
470 }
471 
472 static BOOL mouse_cursor_server_context_handle(MouseCursorServerContext* context, HANDLE* handle)
473 {
474  mouse_cursor_server* mouse_cursor = (mouse_cursor_server*)context;
475 
476  WINPR_ASSERT(mouse_cursor);
477  WINPR_ASSERT(handle);
478 
479  if (!mouse_cursor->externalThread)
480  return FALSE;
481  if (mouse_cursor->state == MOUSE_CURSOR_INITIAL)
482  return FALSE;
483 
484  *handle = mouse_cursor_server_get_channel_handle(mouse_cursor);
485 
486  return TRUE;
487 }
488 
489 static wStream* mouse_cursor_server_packet_new(size_t size, RDP_MOUSE_CURSOR_PDUTYPE pduType,
490  const RDP_MOUSE_CURSOR_HEADER* header)
491 {
492  wStream* s = NULL;
493 
494  /* Allocate what we need plus header bytes */
495  s = Stream_New(NULL, size + RDPEMSC_HEADER_SIZE);
496  if (!s)
497  {
498  WLog_ERR(TAG, "Stream_New failed!");
499  return NULL;
500  }
501 
502  WINPR_ASSERT(pduType <= UINT8_MAX);
503  Stream_Write_UINT8(s, (BYTE)pduType);
504 
505  WINPR_ASSERT(header->updateType <= UINT8_MAX);
506  Stream_Write_UINT8(s, (BYTE)header->updateType);
507  Stream_Write_UINT16(s, header->reserved);
508 
509  return s;
510 }
511 
512 static UINT mouse_cursor_server_packet_send(MouseCursorServerContext* context, wStream* s)
513 {
514  mouse_cursor_server* mouse_cursor = (mouse_cursor_server*)context;
515  UINT error = CHANNEL_RC_OK;
516  ULONG written = 0;
517 
518  WINPR_ASSERT(mouse_cursor);
519  WINPR_ASSERT(s);
520 
521  const size_t pos = Stream_GetPosition(s);
522 
523  WINPR_ASSERT(pos <= UINT32_MAX);
524  if (!WTSVirtualChannelWrite(mouse_cursor->mouse_cursor_channel, Stream_BufferAs(s, char),
525  (ULONG)pos, &written))
526  {
527  WLog_ERR(TAG, "WTSVirtualChannelWrite failed!");
528  error = ERROR_INTERNAL_ERROR;
529  goto out;
530  }
531 
532  if (written < Stream_GetPosition(s))
533  {
534  WLog_WARN(TAG, "Unexpected bytes written: %" PRIu32 "/%" PRIuz "", written,
535  Stream_GetPosition(s));
536  }
537 
538 out:
539  Stream_Free(s, TRUE);
540  return error;
541 }
542 
543 static UINT
544 mouse_cursor_server_send_sc_caps_confirm(MouseCursorServerContext* context,
545  const RDP_MOUSE_CURSOR_CAPS_CONFIRM_PDU* capsConfirm)
546 {
547  RDP_MOUSE_CURSOR_CAPSET* capsetHeader = NULL;
548  RDP_MOUSE_CURSOR_PDUTYPE pduType = PDUTYPE_EMSC_RESERVED;
549  size_t caps_size = 0;
550  wStream* s = NULL;
551 
552  WINPR_ASSERT(context);
553  WINPR_ASSERT(capsConfirm);
554 
555  capsetHeader = capsConfirm->capsSet;
556  WINPR_ASSERT(capsetHeader);
557 
558  caps_size = 12;
559  switch (capsetHeader->version)
560  {
562  break;
563  default:
564  WINPR_ASSERT(FALSE);
565  break;
566  }
567 
568  pduType = PDUTYPE_SC_CAPS_CONFIRM;
569  s = mouse_cursor_server_packet_new(caps_size, pduType, &capsConfirm->header);
570  if (!s)
571  return ERROR_NOT_ENOUGH_MEMORY;
572 
573  Stream_Write_UINT32(s, capsetHeader->signature);
574  Stream_Write_UINT32(s, capsetHeader->version);
575  Stream_Write_UINT32(s, capsetHeader->size);
576 
577  /* Write capsData */
578  switch (capsetHeader->version)
579  {
581  break;
582  default:
583  WINPR_ASSERT(FALSE);
584  break;
585  }
586 
587  return mouse_cursor_server_packet_send(context, s);
588 }
589 
590 static void write_point16(wStream* s, const TS_POINT16* point16)
591 {
592  WINPR_ASSERT(s);
593  WINPR_ASSERT(point16);
594 
595  Stream_Write_UINT16(s, point16->xPos);
596  Stream_Write_UINT16(s, point16->yPos);
597 }
598 
599 static UINT mouse_cursor_server_send_sc_mouseptr_update(
600  MouseCursorServerContext* context, const RDP_MOUSE_CURSOR_MOUSEPTR_UPDATE_PDU* mouseptrUpdate)
601 {
602  TS_POINT16* position = NULL;
603  TS_POINTERATTRIBUTE* pointerAttribute = NULL;
604  TS_LARGEPOINTERATTRIBUTE* largePointerAttribute = NULL;
605  RDP_MOUSE_CURSOR_PDUTYPE pduType = PDUTYPE_EMSC_RESERVED;
606  size_t update_size = 0;
607  wStream* s = NULL;
608 
609  WINPR_ASSERT(context);
610  WINPR_ASSERT(mouseptrUpdate);
611 
612  position = mouseptrUpdate->position;
613  pointerAttribute = mouseptrUpdate->pointerAttribute;
614  largePointerAttribute = mouseptrUpdate->largePointerAttribute;
615 
616  switch (mouseptrUpdate->header.updateType)
617  {
618  case TS_UPDATETYPE_MOUSEPTR_SYSTEM_NULL:
619  case TS_UPDATETYPE_MOUSEPTR_SYSTEM_DEFAULT:
620  update_size = 0;
621  break;
622  case TS_UPDATETYPE_MOUSEPTR_POSITION:
623  WINPR_ASSERT(position);
624  update_size = 4;
625  break;
626  case TS_UPDATETYPE_MOUSEPTR_CACHED:
627  WINPR_ASSERT(mouseptrUpdate->cachedPointerIndex);
628  update_size = 2;
629  break;
630  case TS_UPDATETYPE_MOUSEPTR_POINTER:
631  WINPR_ASSERT(pointerAttribute);
632  update_size = 2 + 2 + 4 + 2 + 2 + 2 + 2;
633  update_size += pointerAttribute->lengthAndMask;
634  update_size += pointerAttribute->lengthXorMask;
635  break;
636  case TS_UPDATETYPE_MOUSEPTR_LARGE_POINTER:
637  WINPR_ASSERT(largePointerAttribute);
638  update_size = 2 + 2 + 4 + 2 + 2 + 4 + 4;
639  update_size += largePointerAttribute->lengthAndMask;
640  update_size += largePointerAttribute->lengthXorMask;
641  break;
642  default:
643  WINPR_ASSERT(FALSE);
644  break;
645  }
646 
647  pduType = PDUTYPE_SC_MOUSEPTR_UPDATE;
648  s = mouse_cursor_server_packet_new(update_size, pduType, &mouseptrUpdate->header);
649  if (!s)
650  return ERROR_NOT_ENOUGH_MEMORY;
651 
652  switch (mouseptrUpdate->header.updateType)
653  {
654  case TS_UPDATETYPE_MOUSEPTR_SYSTEM_NULL:
655  case TS_UPDATETYPE_MOUSEPTR_SYSTEM_DEFAULT:
656  break;
657  case TS_UPDATETYPE_MOUSEPTR_POSITION:
658  write_point16(s, position);
659  break;
660  case TS_UPDATETYPE_MOUSEPTR_CACHED:
661  Stream_Write_UINT16(s, *mouseptrUpdate->cachedPointerIndex);
662  break;
663  case TS_UPDATETYPE_MOUSEPTR_POINTER:
664  Stream_Write_UINT16(s, pointerAttribute->xorBpp);
665  Stream_Write_UINT16(s, pointerAttribute->cacheIndex);
666  write_point16(s, &pointerAttribute->hotSpot);
667  Stream_Write_UINT16(s, pointerAttribute->width);
668  Stream_Write_UINT16(s, pointerAttribute->height);
669  Stream_Write_UINT16(s, pointerAttribute->lengthAndMask);
670  Stream_Write_UINT16(s, pointerAttribute->lengthXorMask);
671  Stream_Write(s, pointerAttribute->xorMaskData, pointerAttribute->lengthXorMask);
672  Stream_Write(s, pointerAttribute->andMaskData, pointerAttribute->lengthAndMask);
673  break;
674  case TS_UPDATETYPE_MOUSEPTR_LARGE_POINTER:
675  Stream_Write_UINT16(s, largePointerAttribute->xorBpp);
676  Stream_Write_UINT16(s, largePointerAttribute->cacheIndex);
677  write_point16(s, &largePointerAttribute->hotSpot);
678  Stream_Write_UINT16(s, largePointerAttribute->width);
679  Stream_Write_UINT16(s, largePointerAttribute->height);
680  Stream_Write_UINT32(s, largePointerAttribute->lengthAndMask);
681  Stream_Write_UINT32(s, largePointerAttribute->lengthXorMask);
682  Stream_Write(s, largePointerAttribute->xorMaskData,
683  largePointerAttribute->lengthXorMask);
684  Stream_Write(s, largePointerAttribute->andMaskData,
685  largePointerAttribute->lengthAndMask);
686  break;
687  default:
688  WINPR_ASSERT(FALSE);
689  break;
690  }
691 
692  return mouse_cursor_server_packet_send(context, s);
693 }
694 
695 MouseCursorServerContext* mouse_cursor_server_context_new(HANDLE vcm)
696 {
697  mouse_cursor_server* mouse_cursor =
698  (mouse_cursor_server*)calloc(1, sizeof(mouse_cursor_server));
699 
700  if (!mouse_cursor)
701  return NULL;
702 
703  mouse_cursor->context.vcm = vcm;
704  mouse_cursor->context.Initialize = mouse_cursor_server_initialize;
705  mouse_cursor->context.Open = mouse_cursor_server_open;
706  mouse_cursor->context.Close = mouse_cursor_server_close;
707  mouse_cursor->context.Poll = mouse_cursor_server_context_poll;
708  mouse_cursor->context.ChannelHandle = mouse_cursor_server_context_handle;
709 
710  mouse_cursor->context.CapsConfirm = mouse_cursor_server_send_sc_caps_confirm;
711  mouse_cursor->context.MouseptrUpdate = mouse_cursor_server_send_sc_mouseptr_update;
712 
713  mouse_cursor->buffer = Stream_New(NULL, 4096);
714  if (!mouse_cursor->buffer)
715  goto fail;
716 
717  return &mouse_cursor->context;
718 fail:
719  WINPR_PRAGMA_DIAG_PUSH
720  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
721  mouse_cursor_server_context_free(&mouse_cursor->context);
722  WINPR_PRAGMA_DIAG_POP
723  return NULL;
724 }
725 
726 void mouse_cursor_server_context_free(MouseCursorServerContext* context)
727 {
728  mouse_cursor_server* mouse_cursor = (mouse_cursor_server*)context;
729 
730  if (mouse_cursor)
731  {
732  mouse_cursor_server_close(context);
733  Stream_Free(mouse_cursor->buffer, TRUE);
734  }
735 
736  free(mouse_cursor);
737 }
RDP_MOUSE_CURSOR_CAPVERSION
@ RDP_MOUSE_CURSOR_CAPVERSION_1
This struct contains function pointer to initialize/free objects.
Definition: collections.h:57