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  IO_STATUS_BLOCK ioStatusBlock = { 0 };
658  WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannelHandle;
659 
660  if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
661  {
662  SetLastError(ERROR_INVALID_PARAMETER);
663  return FALSE;
664  }
665 
666  NTSTATUS ntstatus =
667  NtDeviceIoControlFile(pChannel->hFile, 0, 0, 0, &ioStatusBlock, IoControlCode, 0, 0, 0, 0);
668 
669  if (ntstatus == STATUS_PENDING)
670  {
671  ntstatus = NtWaitForSingleObject(pChannel->hFile, 0, 0);
672 
673  if (ntstatus >= 0)
674  {
675 #if defined(NONAMELESSUNION) && !defined(__MINGW32__)
676  ntstatus = ioStatusBlock.DUMMYUNIONNAME.Status;
677 #else
678  ntstatus = ioStatusBlock.Status;
679 #endif
680  }
681  }
682 
683  if (ntstatus == STATUS_BUFFER_OVERFLOW)
684  {
685  ntstatus = STATUS_BUFFER_TOO_SMALL;
686  const DWORD error = RtlNtStatusToDosError(ntstatus);
687  SetLastError(error);
688  return FALSE;
689  }
690 
691  if (ntstatus < 0)
692  {
693  const DWORD error = RtlNtStatusToDosError(ntstatus);
694  SetLastError(error);
695  return FALSE;
696  }
697 
698  return TRUE;
699 }
700 
701 BOOL WINAPI Win32_WTSVirtualChannelPurgeInput(HANDLE hChannelHandle)
702 {
703  return Win32_WTSVirtualChannelPurge_Internal(hChannelHandle,
704  (FILE_DEVICE_TERMSRV << 16) | 0x0107);
705 }
706 
707 BOOL WINAPI Win32_WTSVirtualChannelPurgeOutput(HANDLE hChannelHandle)
708 {
709  return Win32_WTSVirtualChannelPurge_Internal(hChannelHandle,
710  (FILE_DEVICE_TERMSRV << 16) | 0x010B);
711 }
712 
713 BOOL WINAPI Win32_WTSVirtualChannelQuery(HANDLE hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass,
714  PVOID* ppBuffer, DWORD* pBytesReturned)
715 {
716  WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannelHandle;
717 
718  if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
719  {
720  SetLastError(ERROR_INVALID_PARAMETER);
721  return FALSE;
722  }
723 
724  if (WtsVirtualClass == WTSVirtualClientData)
725  {
726  SetLastError(ERROR_INVALID_PARAMETER);
727  return FALSE;
728  }
729  else if (WtsVirtualClass == WTSVirtualFileHandle)
730  {
731  *pBytesReturned = sizeof(HANDLE);
732  *ppBuffer = _wts_calloc(1, *pBytesReturned);
733 
734  if (*ppBuffer == NULL)
735  {
736  SetLastError(ERROR_NOT_ENOUGH_MEMORY);
737  return FALSE;
738  }
739 
740  CopyMemory(*ppBuffer, &(pChannel->hFile), *pBytesReturned);
741  }
742  else if (WtsVirtualClass == WTSVirtualEventHandle)
743  {
744  *pBytesReturned = sizeof(HANDLE);
745  *ppBuffer = _wts_calloc(1, *pBytesReturned);
746 
747  if (*ppBuffer == NULL)
748  {
749  SetLastError(ERROR_NOT_ENOUGH_MEMORY);
750  return FALSE;
751  }
752 
753  CopyMemory(*ppBuffer, &(pChannel->hEvent), *pBytesReturned);
754 
755  Win32_WTSVirtualChannelReadAsync(pChannel);
756  pChannel->waitObjectMode = TRUE;
757  }
758  else
759  {
760  SetLastError(ERROR_INVALID_PARAMETER);
761  return FALSE;
762  }
763 
764  return TRUE;
765 }
766 
767 VOID WINAPI Win32_WTSFreeMemory(PVOID pMemory)
768 {
769  _wts_free(pMemory);
770 }
771 
772 BOOL WINAPI Win32_WTSFreeMemoryExW(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory,
773  ULONG NumberOfEntries)
774 {
775  return FALSE;
776 }
777 
778 BOOL WINAPI Win32_WTSFreeMemoryExA(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory,
779  ULONG NumberOfEntries)
780 {
781  return WTSFreeMemoryExW(WTSTypeClass, pMemory, NumberOfEntries);
782 }
783 
784 BOOL Win32_InitializeWinSta(PWtsApiFunctionTable pWtsApi)
785 {
786  g_WinStaModule = LoadLibraryA("winsta.dll");
787 
788  if (!g_WinStaModule)
789  return FALSE;
790 
791  pfnWinStationVirtualOpen =
792  GetProcAddressAs(g_WinStaModule, "WinStationVirtualOpen", fnWinStationVirtualOpen);
793  pfnWinStationVirtualOpenEx =
794  GetProcAddressAs(g_WinStaModule, "WinStationVirtualOpenEx", fnWinStationVirtualOpenEx);
795 
796  if (!pfnWinStationVirtualOpen | !pfnWinStationVirtualOpenEx)
797  return FALSE;
798 
799  pWtsApi->pVirtualChannelOpen = Win32_WTSVirtualChannelOpen;
800  pWtsApi->pVirtualChannelOpenEx = Win32_WTSVirtualChannelOpenEx;
801  pWtsApi->pVirtualChannelClose = Win32_WTSVirtualChannelClose;
802  pWtsApi->pVirtualChannelRead = Win32_WTSVirtualChannelRead;
803  pWtsApi->pVirtualChannelWrite = Win32_WTSVirtualChannelWrite;
804  pWtsApi->pVirtualChannelPurgeInput = Win32_WTSVirtualChannelPurgeInput;
805  pWtsApi->pVirtualChannelPurgeOutput = Win32_WTSVirtualChannelPurgeOutput;
806  pWtsApi->pVirtualChannelQuery = Win32_WTSVirtualChannelQuery;
807  pWtsApi->pFreeMemory = Win32_WTSFreeMemory;
808  // pWtsApi->pFreeMemoryExW = Win32_WTSFreeMemoryExW;
809  // pWtsApi->pFreeMemoryExA = Win32_WTSFreeMemoryExA;
810 
811  return TRUE;
812 }