FreeRDP
wtsapi_win32.c
1 
20 #include <winpr/config.h>
21 
22 #include <winpr/crt.h>
23 #include <winpr/io.h>
24 #include <winpr/nt.h>
25 #include <winpr/library.h>
26 
27 #include <winpr/wtsapi.h>
28 
29 #include "wtsapi_win32.h"
30 
31 #include "../log.h"
32 
33 #include <winternl.h>
34 
35 #pragma comment(lib, "ntdll.lib")
36 
37 #define WTSAPI_CHANNEL_MAGIC 0x44484356
38 #define TAG WINPR_TAG("wtsapi")
39 
40 typedef struct
41 {
42  UINT32 magic;
43  HANDLE hServer;
44  DWORD SessionId;
45  HANDLE hFile;
46  HANDLE hEvent;
47  char* VirtualName;
48 
49  DWORD flags;
50  BYTE* chunk;
51  BOOL dynamic;
52  BOOL readSync;
53  BOOL readAsync;
54  BOOL readDone;
55  UINT32 readSize;
56  UINT32 readOffset;
57  BYTE* readBuffer;
58  BOOL showProtocol;
59  BOOL waitObjectMode;
60  OVERLAPPED overlapped;
61  CHANNEL_PDU_HEADER* header;
62 } WTSAPI_CHANNEL;
63 
64 static BOOL g_Initialized = FALSE;
65 static HMODULE g_WinStaModule = NULL;
66 
67 typedef HANDLE(WINAPI* fnWinStationVirtualOpen)(HANDLE hServer, DWORD SessionId,
68  LPSTR pVirtualName);
69 typedef HANDLE(WINAPI* fnWinStationVirtualOpenEx)(HANDLE hServer, DWORD SessionId,
70  LPSTR pVirtualName, DWORD flags);
71 
72 static fnWinStationVirtualOpen pfnWinStationVirtualOpen = NULL;
73 static fnWinStationVirtualOpenEx pfnWinStationVirtualOpenEx = NULL;
74 
75 BOOL WINAPI Win32_WTSVirtualChannelClose(HANDLE hChannel);
76 
92 static void* _wts_malloc(size_t size)
93 {
94 #ifdef _UWP
95  return malloc(size);
96 #else
97  return (PVOID)LocalAlloc(LMEM_FIXED, size);
98 #endif
99 }
100 
101 static void* _wts_calloc(size_t nmemb, size_t size)
102 {
103 #ifdef _UWP
104  return calloc(nmemb, size);
105 #else
106  return (PVOID)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, nmemb * size);
107 #endif
108 }
109 
110 static void _wts_free(void* ptr)
111 {
112 #ifdef _UWP
113  free(ptr);
114 #else
115  LocalFree((HLOCAL)ptr);
116 #endif
117 }
118 
119 BOOL Win32_WTSVirtualChannelReadAsync(WTSAPI_CHANNEL* pChannel)
120 {
121  BOOL status = TRUE;
122  DWORD numBytes = 0;
123 
124  if (pChannel->readAsync)
125  return TRUE;
126 
127  ZeroMemory(&(pChannel->overlapped), sizeof(OVERLAPPED));
128  pChannel->overlapped.hEvent = pChannel->hEvent;
129  (void)ResetEvent(pChannel->hEvent);
130 
131  if (pChannel->showProtocol)
132  {
133  ZeroMemory(pChannel->header, sizeof(CHANNEL_PDU_HEADER));
134 
135  status = ReadFile(pChannel->hFile, pChannel->header, sizeof(CHANNEL_PDU_HEADER), &numBytes,
136  &(pChannel->overlapped));
137  }
138  else
139  {
140  status = ReadFile(pChannel->hFile, pChannel->chunk, CHANNEL_CHUNK_LENGTH, &numBytes,
141  &(pChannel->overlapped));
142 
143  if (status)
144  {
145  pChannel->readOffset = 0;
146  pChannel->header->length = numBytes;
147 
148  pChannel->readDone = TRUE;
149  (void)SetEvent(pChannel->hEvent);
150 
151  return TRUE;
152  }
153  }
154 
155  if (status)
156  {
157  WLog_ERR(TAG, "Unexpected ReadFile status: %" PRId32 " numBytes: %" PRIu32 "", status,
158  numBytes);
159  return FALSE; /* ReadFile should return FALSE and set ERROR_IO_PENDING */
160  }
161 
162  if (GetLastError() != ERROR_IO_PENDING)
163  {
164  WLog_ERR(TAG, "ReadFile: GetLastError() = %" PRIu32 "", GetLastError());
165  return FALSE;
166  }
167 
168  pChannel->readAsync = TRUE;
169 
170  return TRUE;
171 }
172 
173 HANDLE WINAPI Win32_WTSVirtualChannelOpen_Internal(HANDLE hServer, DWORD SessionId,
174  LPSTR pVirtualName, DWORD flags)
175 {
176  HANDLE hFile;
177  HANDLE hChannel;
178  WTSAPI_CHANNEL* pChannel;
179  size_t virtualNameLen;
180 
181  virtualNameLen = pVirtualName ? strlen(pVirtualName) : 0;
182 
183  if (!virtualNameLen)
184  {
185  SetLastError(ERROR_INVALID_PARAMETER);
186  return NULL;
187  }
188 
189  if (!pfnWinStationVirtualOpenEx)
190  {
191  SetLastError(ERROR_INVALID_FUNCTION);
192  return NULL;
193  }
194 
195  hFile = pfnWinStationVirtualOpenEx(hServer, SessionId, pVirtualName, flags);
196 
197  if (!hFile)
198  return NULL;
199 
200  pChannel = (WTSAPI_CHANNEL*)_wts_calloc(1, sizeof(WTSAPI_CHANNEL));
201 
202  if (!pChannel)
203  {
204  (void)CloseHandle(hFile);
205  SetLastError(ERROR_NOT_ENOUGH_MEMORY);
206  return NULL;
207  }
208 
209  hChannel = (HANDLE)pChannel;
210  pChannel->magic = WTSAPI_CHANNEL_MAGIC;
211  pChannel->hServer = hServer;
212  pChannel->SessionId = SessionId;
213  pChannel->hFile = hFile;
214  pChannel->VirtualName = _wts_calloc(1, virtualNameLen + 1);
215  if (!pChannel->VirtualName)
216  {
217  (void)CloseHandle(hFile);
218  SetLastError(ERROR_NOT_ENOUGH_MEMORY);
219  _wts_free(pChannel);
220  return NULL;
221  }
222  memcpy(pChannel->VirtualName, pVirtualName, virtualNameLen);
223 
224  pChannel->flags = flags;
225  pChannel->dynamic = (flags & WTS_CHANNEL_OPTION_DYNAMIC) ? TRUE : FALSE;
226 
227  pChannel->showProtocol = pChannel->dynamic;
228 
229  pChannel->readSize = CHANNEL_PDU_LENGTH;
230  pChannel->readBuffer = (BYTE*)_wts_malloc(pChannel->readSize);
231 
232  pChannel->header = (CHANNEL_PDU_HEADER*)pChannel->readBuffer;
233  pChannel->chunk = &(pChannel->readBuffer[sizeof(CHANNEL_PDU_HEADER)]);
234 
235  pChannel->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
236  pChannel->overlapped.hEvent = pChannel->hEvent;
237 
238  if (!pChannel->hEvent || !pChannel->VirtualName || !pChannel->readBuffer)
239  {
240  Win32_WTSVirtualChannelClose(hChannel);
241  SetLastError(ERROR_NOT_ENOUGH_MEMORY);
242  return NULL;
243  }
244 
245  return hChannel;
246 }
247 
248 HANDLE WINAPI Win32_WTSVirtualChannelOpen(HANDLE hServer, DWORD SessionId, LPSTR pVirtualName)
249 {
250  return Win32_WTSVirtualChannelOpen_Internal(hServer, SessionId, pVirtualName, 0);
251 }
252 
253 HANDLE WINAPI Win32_WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualName, DWORD flags)
254 {
255  return Win32_WTSVirtualChannelOpen_Internal(0, SessionId, pVirtualName, flags);
256 }
257 
258 BOOL WINAPI Win32_WTSVirtualChannelClose(HANDLE hChannel)
259 {
260  BOOL status = TRUE;
261  WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannel;
262 
263  if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
264  {
265  SetLastError(ERROR_INVALID_PARAMETER);
266  return FALSE;
267  }
268 
269  if (pChannel->hFile)
270  {
271  if (pChannel->readAsync)
272  {
273  CancelIo(pChannel->hFile);
274  pChannel->readAsync = FALSE;
275  }
276 
277  status = CloseHandle(pChannel->hFile);
278  pChannel->hFile = NULL;
279  }
280 
281  if (pChannel->hEvent)
282  {
283  (void)CloseHandle(pChannel->hEvent);
284  pChannel->hEvent = NULL;
285  }
286 
287  if (pChannel->VirtualName)
288  {
289  _wts_free(pChannel->VirtualName);
290  pChannel->VirtualName = NULL;
291  }
292 
293  if (pChannel->readBuffer)
294  {
295  _wts_free(pChannel->readBuffer);
296  pChannel->readBuffer = NULL;
297  }
298 
299  pChannel->magic = 0;
300  _wts_free(pChannel);
301 
302  return status;
303 }
304 
305 BOOL WINAPI Win32_WTSVirtualChannelRead_Static(WTSAPI_CHANNEL* pChannel, DWORD dwMilliseconds,
306  LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
307  LPDWORD lpNumberOfBytesTransferred)
308 {
309  if (pChannel->readDone)
310  {
311  DWORD numBytesRead = 0;
312  DWORD numBytesToRead = 0;
313 
314  *lpNumberOfBytesTransferred = 0;
315 
316  numBytesToRead = nNumberOfBytesToRead;
317 
318  if (numBytesToRead > (pChannel->header->length - pChannel->readOffset))
319  numBytesToRead = (pChannel->header->length - pChannel->readOffset);
320 
321  CopyMemory(lpBuffer, &(pChannel->chunk[pChannel->readOffset]), numBytesToRead);
322  *lpNumberOfBytesTransferred += numBytesToRead;
323  pChannel->readOffset += numBytesToRead;
324 
325  if (pChannel->readOffset != pChannel->header->length)
326  {
327  SetLastError(ERROR_MORE_DATA);
328  return FALSE;
329  }
330  else
331  {
332  pChannel->readDone = FALSE;
333  Win32_WTSVirtualChannelReadAsync(pChannel);
334  }
335 
336  return TRUE;
337  }
338  else if (pChannel->readSync)
339  {
340  BOOL bSuccess;
341  OVERLAPPED overlapped = { 0 };
342  DWORD numBytesRead = 0;
343  DWORD numBytesToRead = 0;
344 
345  *lpNumberOfBytesTransferred = 0;
346 
347  numBytesToRead = nNumberOfBytesToRead;
348 
349  if (numBytesToRead > (pChannel->header->length - pChannel->readOffset))
350  numBytesToRead = (pChannel->header->length - pChannel->readOffset);
351 
352  if (ReadFile(pChannel->hFile, lpBuffer, numBytesToRead, &numBytesRead, &overlapped))
353  {
354  *lpNumberOfBytesTransferred += numBytesRead;
355  pChannel->readOffset += numBytesRead;
356 
357  if (pChannel->readOffset != pChannel->header->length)
358  {
359  SetLastError(ERROR_MORE_DATA);
360  return FALSE;
361  }
362 
363  pChannel->readSync = FALSE;
364  Win32_WTSVirtualChannelReadAsync(pChannel);
365 
366  return TRUE;
367  }
368 
369  if (GetLastError() != ERROR_IO_PENDING)
370  return FALSE;
371 
372  bSuccess = GetOverlappedResult(pChannel->hFile, &overlapped, &numBytesRead, TRUE);
373 
374  if (!bSuccess)
375  return FALSE;
376 
377  *lpNumberOfBytesTransferred += numBytesRead;
378  pChannel->readOffset += numBytesRead;
379 
380  if (pChannel->readOffset != pChannel->header->length)
381  {
382  SetLastError(ERROR_MORE_DATA);
383  return FALSE;
384  }
385 
386  pChannel->readSync = FALSE;
387  Win32_WTSVirtualChannelReadAsync(pChannel);
388 
389  return TRUE;
390  }
391  else if (pChannel->readAsync)
392  {
393  BOOL bSuccess;
394  DWORD numBytesRead = 0;
395  DWORD numBytesToRead = 0;
396 
397  *lpNumberOfBytesTransferred = 0;
398 
399  if (WaitForSingleObject(pChannel->hEvent, dwMilliseconds) != WAIT_TIMEOUT)
400  {
401  bSuccess =
402  GetOverlappedResult(pChannel->hFile, &(pChannel->overlapped), &numBytesRead, TRUE);
403 
404  pChannel->readOffset = 0;
405  pChannel->header->length = numBytesRead;
406 
407  if (!bSuccess && (GetLastError() != ERROR_MORE_DATA))
408  return FALSE;
409 
410  numBytesToRead = nNumberOfBytesToRead;
411 
412  if (numBytesRead < numBytesToRead)
413  {
414  numBytesToRead = numBytesRead;
415  nNumberOfBytesToRead = numBytesRead;
416  }
417 
418  CopyMemory(lpBuffer, pChannel->chunk, numBytesToRead);
419  *lpNumberOfBytesTransferred += numBytesToRead;
420  lpBuffer = (BYTE*)lpBuffer + numBytesToRead;
421  nNumberOfBytesToRead -= numBytesToRead;
422  pChannel->readOffset += numBytesToRead;
423 
424  pChannel->readAsync = FALSE;
425 
426  if (!nNumberOfBytesToRead)
427  {
428  Win32_WTSVirtualChannelReadAsync(pChannel);
429  return TRUE;
430  }
431 
432  pChannel->readSync = TRUE;
433 
434  numBytesRead = 0;
435 
436  bSuccess = Win32_WTSVirtualChannelRead_Static(pChannel, dwMilliseconds, lpBuffer,
437  nNumberOfBytesToRead, &numBytesRead);
438 
439  *lpNumberOfBytesTransferred += numBytesRead;
440  return bSuccess;
441  }
442  else
443  {
444  SetLastError(ERROR_IO_INCOMPLETE);
445  return FALSE;
446  }
447  }
448 
449  return FALSE;
450 }
451 
452 BOOL WINAPI Win32_WTSVirtualChannelRead_Dynamic(WTSAPI_CHANNEL* pChannel, DWORD dwMilliseconds,
453  LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
454  LPDWORD lpNumberOfBytesTransferred)
455 {
456  if (pChannel->readSync)
457  {
458  BOOL bSuccess;
459  OVERLAPPED overlapped = { 0 };
460  DWORD numBytesRead = 0;
461  DWORD numBytesToRead = 0;
462 
463  *lpNumberOfBytesTransferred = 0;
464 
465  numBytesToRead = nNumberOfBytesToRead;
466 
467  if (numBytesToRead > (pChannel->header->length - pChannel->readOffset))
468  numBytesToRead = (pChannel->header->length - pChannel->readOffset);
469 
470  if (ReadFile(pChannel->hFile, lpBuffer, numBytesToRead, &numBytesRead, &overlapped))
471  {
472  *lpNumberOfBytesTransferred += numBytesRead;
473  pChannel->readOffset += numBytesRead;
474 
475  if (pChannel->readOffset != pChannel->header->length)
476  {
477  SetLastError(ERROR_MORE_DATA);
478  return FALSE;
479  }
480 
481  pChannel->readSync = FALSE;
482  Win32_WTSVirtualChannelReadAsync(pChannel);
483 
484  return TRUE;
485  }
486 
487  if (GetLastError() != ERROR_IO_PENDING)
488  return FALSE;
489 
490  bSuccess = GetOverlappedResult(pChannel->hFile, &overlapped, &numBytesRead, TRUE);
491 
492  if (!bSuccess)
493  return FALSE;
494 
495  *lpNumberOfBytesTransferred += numBytesRead;
496  pChannel->readOffset += numBytesRead;
497 
498  if (pChannel->readOffset != pChannel->header->length)
499  {
500  SetLastError(ERROR_MORE_DATA);
501  return FALSE;
502  }
503 
504  pChannel->readSync = FALSE;
505  Win32_WTSVirtualChannelReadAsync(pChannel);
506 
507  return TRUE;
508  }
509  else if (pChannel->readAsync)
510  {
511  BOOL bSuccess;
512  DWORD numBytesRead = 0;
513 
514  *lpNumberOfBytesTransferred = 0;
515 
516  if (WaitForSingleObject(pChannel->hEvent, dwMilliseconds) != WAIT_TIMEOUT)
517  {
518  bSuccess =
519  GetOverlappedResult(pChannel->hFile, &(pChannel->overlapped), &numBytesRead, TRUE);
520 
521  if (pChannel->showProtocol)
522  {
523  if (numBytesRead != sizeof(CHANNEL_PDU_HEADER))
524  return FALSE;
525 
526  if (!bSuccess && (GetLastError() != ERROR_MORE_DATA))
527  return FALSE;
528 
529  CopyMemory(lpBuffer, pChannel->header, numBytesRead);
530  *lpNumberOfBytesTransferred += numBytesRead;
531  lpBuffer = (BYTE*)lpBuffer + numBytesRead;
532  nNumberOfBytesToRead -= numBytesRead;
533  }
534 
535  pChannel->readAsync = FALSE;
536 
537  if (!pChannel->header->length)
538  {
539  Win32_WTSVirtualChannelReadAsync(pChannel);
540  return TRUE;
541  }
542 
543  pChannel->readSync = TRUE;
544  pChannel->readOffset = 0;
545 
546  if (!nNumberOfBytesToRead)
547  {
548  SetLastError(ERROR_MORE_DATA);
549  return FALSE;
550  }
551 
552  numBytesRead = 0;
553 
554  bSuccess = Win32_WTSVirtualChannelRead_Dynamic(pChannel, dwMilliseconds, lpBuffer,
555  nNumberOfBytesToRead, &numBytesRead);
556 
557  *lpNumberOfBytesTransferred += numBytesRead;
558  return bSuccess;
559  }
560  else
561  {
562  SetLastError(ERROR_IO_INCOMPLETE);
563  return FALSE;
564  }
565  }
566 
567  return FALSE;
568 }
569 
570 BOOL WINAPI Win32_WTSVirtualChannelRead(HANDLE hChannel, DWORD dwMilliseconds, LPVOID lpBuffer,
571  DWORD nNumberOfBytesToRead,
572  LPDWORD lpNumberOfBytesTransferred)
573 {
574  WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannel;
575 
576  if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
577  {
578  SetLastError(ERROR_INVALID_PARAMETER);
579  return FALSE;
580  }
581 
582  if (!pChannel->waitObjectMode)
583  {
584  OVERLAPPED overlapped = { 0 };
585 
586  if (ReadFile(pChannel->hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesTransferred,
587  &overlapped))
588  return TRUE;
589 
590  if (GetLastError() != ERROR_IO_PENDING)
591  return FALSE;
592 
593  if (!dwMilliseconds)
594  {
595  CancelIo(pChannel->hFile);
596  *lpNumberOfBytesTransferred = 0;
597  return TRUE;
598  }
599 
600  if (WaitForSingleObject(pChannel->hFile, dwMilliseconds) != WAIT_TIMEOUT)
601  return GetOverlappedResult(pChannel->hFile, &overlapped, lpNumberOfBytesTransferred,
602  FALSE);
603 
604  CancelIo(pChannel->hFile);
605  SetLastError(ERROR_IO_INCOMPLETE);
606 
607  return FALSE;
608  }
609  else
610  {
611  if (pChannel->dynamic)
612  {
613  return Win32_WTSVirtualChannelRead_Dynamic(pChannel, dwMilliseconds, lpBuffer,
614  nNumberOfBytesToRead,
615  lpNumberOfBytesTransferred);
616  }
617  else
618  {
619  return Win32_WTSVirtualChannelRead_Static(pChannel, dwMilliseconds, lpBuffer,
620  nNumberOfBytesToRead,
621  lpNumberOfBytesTransferred);
622  }
623  }
624 
625  return FALSE;
626 }
627 
628 BOOL WINAPI Win32_WTSVirtualChannelWrite(HANDLE hChannel, LPCVOID lpBuffer,
629  DWORD nNumberOfBytesToWrite,
630  LPDWORD lpNumberOfBytesTransferred)
631 {
632  OVERLAPPED overlapped = { 0 };
633  WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannel;
634 
635  if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
636  {
637  SetLastError(ERROR_INVALID_PARAMETER);
638  return FALSE;
639  }
640 
641  if (WriteFile(pChannel->hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesTransferred,
642  &overlapped))
643  return TRUE;
644 
645  if (GetLastError() == ERROR_IO_PENDING)
646  return GetOverlappedResult(pChannel->hFile, &overlapped, lpNumberOfBytesTransferred, TRUE);
647 
648  return FALSE;
649 }
650 
651 #ifndef FILE_DEVICE_TERMSRV
652 #define FILE_DEVICE_TERMSRV 0x00000038
653 #endif
654 
655 BOOL Win32_WTSVirtualChannelPurge_Internal(HANDLE hChannelHandle, ULONG IoControlCode)
656 {
657  DWORD error;
658  NTSTATUS ntstatus;
659  IO_STATUS_BLOCK ioStatusBlock;
660  WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannelHandle;
661 
662  if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
663  {
664  SetLastError(ERROR_INVALID_PARAMETER);
665  return FALSE;
666  }
667 
668  ntstatus =
669  NtDeviceIoControlFile(pChannel->hFile, 0, 0, 0, &ioStatusBlock, IoControlCode, 0, 0, 0, 0);
670 
671  if (ntstatus == STATUS_PENDING)
672  {
673  ntstatus = NtWaitForSingleObject(pChannel->hFile, 0, 0);
674 
675  if (ntstatus >= 0)
676  ntstatus = ioStatusBlock.Status;
677  }
678 
679  if (ntstatus == STATUS_BUFFER_OVERFLOW)
680  {
681  ntstatus = STATUS_BUFFER_TOO_SMALL;
682  error = RtlNtStatusToDosError(ntstatus);
683  SetLastError(error);
684  return FALSE;
685  }
686 
687  if (ntstatus < 0)
688  {
689  error = RtlNtStatusToDosError(ntstatus);
690  SetLastError(error);
691  return FALSE;
692  }
693 
694  return TRUE;
695 }
696 
697 BOOL WINAPI Win32_WTSVirtualChannelPurgeInput(HANDLE hChannelHandle)
698 {
699  return Win32_WTSVirtualChannelPurge_Internal(hChannelHandle,
700  (FILE_DEVICE_TERMSRV << 16) | 0x0107);
701 }
702 
703 BOOL WINAPI Win32_WTSVirtualChannelPurgeOutput(HANDLE hChannelHandle)
704 {
705  return Win32_WTSVirtualChannelPurge_Internal(hChannelHandle,
706  (FILE_DEVICE_TERMSRV << 16) | 0x010B);
707 }
708 
709 BOOL WINAPI Win32_WTSVirtualChannelQuery(HANDLE hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass,
710  PVOID* ppBuffer, DWORD* pBytesReturned)
711 {
712  WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannelHandle;
713 
714  if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
715  {
716  SetLastError(ERROR_INVALID_PARAMETER);
717  return FALSE;
718  }
719 
720  if (WtsVirtualClass == WTSVirtualClientData)
721  {
722  SetLastError(ERROR_INVALID_PARAMETER);
723  return FALSE;
724  }
725  else if (WtsVirtualClass == WTSVirtualFileHandle)
726  {
727  *pBytesReturned = sizeof(HANDLE);
728  *ppBuffer = _wts_calloc(1, *pBytesReturned);
729 
730  if (*ppBuffer == NULL)
731  {
732  SetLastError(ERROR_NOT_ENOUGH_MEMORY);
733  return FALSE;
734  }
735 
736  CopyMemory(*ppBuffer, &(pChannel->hFile), *pBytesReturned);
737  }
738  else if (WtsVirtualClass == WTSVirtualEventHandle)
739  {
740  *pBytesReturned = sizeof(HANDLE);
741  *ppBuffer = _wts_calloc(1, *pBytesReturned);
742 
743  if (*ppBuffer == NULL)
744  {
745  SetLastError(ERROR_NOT_ENOUGH_MEMORY);
746  return FALSE;
747  }
748 
749  CopyMemory(*ppBuffer, &(pChannel->hEvent), *pBytesReturned);
750 
751  Win32_WTSVirtualChannelReadAsync(pChannel);
752  pChannel->waitObjectMode = TRUE;
753  }
754  else
755  {
756  SetLastError(ERROR_INVALID_PARAMETER);
757  return FALSE;
758  }
759 
760  return TRUE;
761 }
762 
763 VOID WINAPI Win32_WTSFreeMemory(PVOID pMemory)
764 {
765  _wts_free(pMemory);
766 }
767 
768 BOOL WINAPI Win32_WTSFreeMemoryExW(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory,
769  ULONG NumberOfEntries)
770 {
771  return FALSE;
772 }
773 
774 BOOL WINAPI Win32_WTSFreeMemoryExA(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory,
775  ULONG NumberOfEntries)
776 {
777  return WTSFreeMemoryExW(WTSTypeClass, pMemory, NumberOfEntries);
778 }
779 
780 BOOL Win32_InitializeWinSta(PWtsApiFunctionTable pWtsApi)
781 {
782  g_WinStaModule = LoadLibraryA("winsta.dll");
783 
784  if (!g_WinStaModule)
785  return FALSE;
786 
787  pfnWinStationVirtualOpen =
788  GetProcAddressAs(g_WinStaModule, "WinStationVirtualOpen", fnWinStationVirtualOpen);
789  pfnWinStationVirtualOpenEx =
790  GetProcAddressAs(g_WinStaModule, "WinStationVirtualOpenEx", fnWinStationVirtualOpenEx);
791 
792  if (!pfnWinStationVirtualOpen | !pfnWinStationVirtualOpenEx)
793  return FALSE;
794 
795  pWtsApi->pVirtualChannelOpen = Win32_WTSVirtualChannelOpen;
796  pWtsApi->pVirtualChannelOpenEx = Win32_WTSVirtualChannelOpenEx;
797  pWtsApi->pVirtualChannelClose = Win32_WTSVirtualChannelClose;
798  pWtsApi->pVirtualChannelRead = Win32_WTSVirtualChannelRead;
799  pWtsApi->pVirtualChannelWrite = Win32_WTSVirtualChannelWrite;
800  pWtsApi->pVirtualChannelPurgeInput = Win32_WTSVirtualChannelPurgeInput;
801  pWtsApi->pVirtualChannelPurgeOutput = Win32_WTSVirtualChannelPurgeOutput;
802  pWtsApi->pVirtualChannelQuery = Win32_WTSVirtualChannelQuery;
803  pWtsApi->pFreeMemory = Win32_WTSFreeMemory;
804  // pWtsApi->pFreeMemoryExW = Win32_WTSFreeMemoryExW;
805  // pWtsApi->pFreeMemoryExA = Win32_WTSFreeMemoryExA;
806 
807  return TRUE;
808 }