FreeRDP
Loading...
Searching...
No Matches
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
40typedef 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
64static BOOL g_Initialized = FALSE;
65static HMODULE g_WinStaModule = NULL;
66
67typedef HANDLE(WINAPI* fnWinStationVirtualOpen)(HANDLE hServer, DWORD SessionId,
68 LPSTR pVirtualName);
69typedef HANDLE(WINAPI* fnWinStationVirtualOpenEx)(HANDLE hServer, DWORD SessionId,
70 LPSTR pVirtualName, DWORD flags);
71
72static fnWinStationVirtualOpen pfnWinStationVirtualOpen = NULL;
73static fnWinStationVirtualOpenEx pfnWinStationVirtualOpenEx = NULL;
74
75BOOL WINAPI Win32_WTSVirtualChannelClose(HANDLE hChannel);
76
92static 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
101static 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
110static void _wts_free(void* ptr)
111{
112#ifdef _UWP
113 free(ptr);
114#else
115 LocalFree((HLOCAL)ptr);
116#endif
117}
118
119BOOL 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
173HANDLE 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
248HANDLE WINAPI Win32_WTSVirtualChannelOpen(HANDLE hServer, DWORD SessionId, LPSTR pVirtualName)
249{
250 return Win32_WTSVirtualChannelOpen_Internal(hServer, SessionId, pVirtualName, 0);
251}
252
253HANDLE WINAPI Win32_WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualName, DWORD flags)
254{
255 return Win32_WTSVirtualChannelOpen_Internal(0, SessionId, pVirtualName, flags);
256}
257
258BOOL 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
305BOOL 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
452BOOL 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
570BOOL 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
628BOOL 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
655BOOL 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
701BOOL WINAPI Win32_WTSVirtualChannelPurgeInput(HANDLE hChannelHandle)
702{
703 return Win32_WTSVirtualChannelPurge_Internal(hChannelHandle,
704 (FILE_DEVICE_TERMSRV << 16) | 0x0107);
705}
706
707BOOL WINAPI Win32_WTSVirtualChannelPurgeOutput(HANDLE hChannelHandle)
708{
709 return Win32_WTSVirtualChannelPurge_Internal(hChannelHandle,
710 (FILE_DEVICE_TERMSRV << 16) | 0x010B);
711}
712
713BOOL 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
767VOID WINAPI Win32_WTSFreeMemory(PVOID pMemory)
768{
769 _wts_free(pMemory);
770}
771
772BOOL WINAPI Win32_WTSFreeMemoryExW(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory,
773 ULONG NumberOfEntries)
774{
775 return FALSE;
776}
777
778BOOL WINAPI Win32_WTSFreeMemoryExA(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory,
779 ULONG NumberOfEntries)
780{
781 return WTSFreeMemoryExW(WTSTypeClass, pMemory, NumberOfEntries);
782}
783
784BOOL 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}