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
75static BOOL 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
119static 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
173static 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
248static HANDLE WINAPI Win32_WTSVirtualChannelOpen(HANDLE hServer, DWORD SessionId,
249 LPSTR pVirtualName)
250{
251 return Win32_WTSVirtualChannelOpen_Internal(hServer, SessionId, pVirtualName, 0);
252}
253
254static HANDLE WINAPI Win32_WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualName, DWORD flags)
255{
256 return Win32_WTSVirtualChannelOpen_Internal(0, SessionId, pVirtualName, flags);
257}
258
259static BOOL WINAPI Win32_WTSVirtualChannelClose(HANDLE hChannel)
260{
261 BOOL status = TRUE;
262 WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannel;
263
264 if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
265 {
266 SetLastError(ERROR_INVALID_PARAMETER);
267 return FALSE;
268 }
269
270 if (pChannel->hFile)
271 {
272 if (pChannel->readAsync)
273 {
274 CancelIo(pChannel->hFile);
275 pChannel->readAsync = FALSE;
276 }
277
278 status = CloseHandle(pChannel->hFile);
279 pChannel->hFile = NULL;
280 }
281
282 if (pChannel->hEvent)
283 {
284 (void)CloseHandle(pChannel->hEvent);
285 pChannel->hEvent = NULL;
286 }
287
288 if (pChannel->VirtualName)
289 {
290 _wts_free(pChannel->VirtualName);
291 pChannel->VirtualName = NULL;
292 }
293
294 if (pChannel->readBuffer)
295 {
296 _wts_free(pChannel->readBuffer);
297 pChannel->readBuffer = NULL;
298 }
299
300 pChannel->magic = 0;
301 _wts_free(pChannel);
302
303 return status;
304}
305
306static BOOL WINAPI Win32_WTSVirtualChannelRead_Static(WTSAPI_CHANNEL* pChannel,
307 DWORD dwMilliseconds, LPVOID lpBuffer,
308 DWORD nNumberOfBytesToRead,
309 LPDWORD lpNumberOfBytesTransferred)
310{
311 if (pChannel->readDone)
312 {
313 DWORD numBytesRead = 0;
314 DWORD numBytesToRead = 0;
315
316 *lpNumberOfBytesTransferred = 0;
317
318 numBytesToRead = nNumberOfBytesToRead;
319
320 if (numBytesToRead > (pChannel->header->length - pChannel->readOffset))
321 numBytesToRead = (pChannel->header->length - pChannel->readOffset);
322
323 CopyMemory(lpBuffer, &(pChannel->chunk[pChannel->readOffset]), numBytesToRead);
324 *lpNumberOfBytesTransferred += numBytesToRead;
325 pChannel->readOffset += numBytesToRead;
326
327 if (pChannel->readOffset != pChannel->header->length)
328 {
329 SetLastError(ERROR_MORE_DATA);
330 return FALSE;
331 }
332 else
333 {
334 pChannel->readDone = FALSE;
335 Win32_WTSVirtualChannelReadAsync(pChannel);
336 }
337
338 return TRUE;
339 }
340 else if (pChannel->readSync)
341 {
342 BOOL bSuccess;
343 OVERLAPPED overlapped = { 0 };
344 DWORD numBytesRead = 0;
345 DWORD numBytesToRead = 0;
346
347 *lpNumberOfBytesTransferred = 0;
348
349 numBytesToRead = nNumberOfBytesToRead;
350
351 if (numBytesToRead > (pChannel->header->length - pChannel->readOffset))
352 numBytesToRead = (pChannel->header->length - pChannel->readOffset);
353
354 if (ReadFile(pChannel->hFile, lpBuffer, numBytesToRead, &numBytesRead, &overlapped))
355 {
356 *lpNumberOfBytesTransferred += numBytesRead;
357 pChannel->readOffset += numBytesRead;
358
359 if (pChannel->readOffset != pChannel->header->length)
360 {
361 SetLastError(ERROR_MORE_DATA);
362 return FALSE;
363 }
364
365 pChannel->readSync = FALSE;
366 Win32_WTSVirtualChannelReadAsync(pChannel);
367
368 return TRUE;
369 }
370
371 if (GetLastError() != ERROR_IO_PENDING)
372 return FALSE;
373
374 bSuccess = GetOverlappedResult(pChannel->hFile, &overlapped, &numBytesRead, TRUE);
375
376 if (!bSuccess)
377 return FALSE;
378
379 *lpNumberOfBytesTransferred += numBytesRead;
380 pChannel->readOffset += numBytesRead;
381
382 if (pChannel->readOffset != pChannel->header->length)
383 {
384 SetLastError(ERROR_MORE_DATA);
385 return FALSE;
386 }
387
388 pChannel->readSync = FALSE;
389 Win32_WTSVirtualChannelReadAsync(pChannel);
390
391 return TRUE;
392 }
393 else if (pChannel->readAsync)
394 {
395 BOOL bSuccess;
396 DWORD numBytesRead = 0;
397 DWORD numBytesToRead = 0;
398
399 *lpNumberOfBytesTransferred = 0;
400
401 if (WaitForSingleObject(pChannel->hEvent, dwMilliseconds) != WAIT_TIMEOUT)
402 {
403 bSuccess =
404 GetOverlappedResult(pChannel->hFile, &(pChannel->overlapped), &numBytesRead, TRUE);
405
406 pChannel->readOffset = 0;
407 pChannel->header->length = numBytesRead;
408
409 if (!bSuccess && (GetLastError() != ERROR_MORE_DATA))
410 return FALSE;
411
412 numBytesToRead = nNumberOfBytesToRead;
413
414 if (numBytesRead < numBytesToRead)
415 {
416 numBytesToRead = numBytesRead;
417 nNumberOfBytesToRead = numBytesRead;
418 }
419
420 CopyMemory(lpBuffer, pChannel->chunk, numBytesToRead);
421 *lpNumberOfBytesTransferred += numBytesToRead;
422 lpBuffer = (BYTE*)lpBuffer + numBytesToRead;
423 nNumberOfBytesToRead -= numBytesToRead;
424 pChannel->readOffset += numBytesToRead;
425
426 pChannel->readAsync = FALSE;
427
428 if (!nNumberOfBytesToRead)
429 {
430 Win32_WTSVirtualChannelReadAsync(pChannel);
431 return TRUE;
432 }
433
434 pChannel->readSync = TRUE;
435
436 numBytesRead = 0;
437
438 bSuccess = Win32_WTSVirtualChannelRead_Static(pChannel, dwMilliseconds, lpBuffer,
439 nNumberOfBytesToRead, &numBytesRead);
440
441 *lpNumberOfBytesTransferred += numBytesRead;
442 return bSuccess;
443 }
444 else
445 {
446 SetLastError(ERROR_IO_INCOMPLETE);
447 return FALSE;
448 }
449 }
450
451 return FALSE;
452}
453
454static BOOL WINAPI Win32_WTSVirtualChannelRead_Dynamic(WTSAPI_CHANNEL* pChannel,
455 DWORD dwMilliseconds, LPVOID lpBuffer,
456 DWORD nNumberOfBytesToRead,
457 LPDWORD lpNumberOfBytesTransferred)
458{
459 if (pChannel->readSync)
460 {
461 BOOL bSuccess;
462 OVERLAPPED overlapped = { 0 };
463 DWORD numBytesRead = 0;
464 DWORD numBytesToRead = 0;
465
466 *lpNumberOfBytesTransferred = 0;
467
468 numBytesToRead = nNumberOfBytesToRead;
469
470 if (numBytesToRead > (pChannel->header->length - pChannel->readOffset))
471 numBytesToRead = (pChannel->header->length - pChannel->readOffset);
472
473 if (ReadFile(pChannel->hFile, lpBuffer, numBytesToRead, &numBytesRead, &overlapped))
474 {
475 *lpNumberOfBytesTransferred += numBytesRead;
476 pChannel->readOffset += numBytesRead;
477
478 if (pChannel->readOffset != pChannel->header->length)
479 {
480 SetLastError(ERROR_MORE_DATA);
481 return FALSE;
482 }
483
484 pChannel->readSync = FALSE;
485 Win32_WTSVirtualChannelReadAsync(pChannel);
486
487 return TRUE;
488 }
489
490 if (GetLastError() != ERROR_IO_PENDING)
491 return FALSE;
492
493 bSuccess = GetOverlappedResult(pChannel->hFile, &overlapped, &numBytesRead, TRUE);
494
495 if (!bSuccess)
496 return FALSE;
497
498 *lpNumberOfBytesTransferred += numBytesRead;
499 pChannel->readOffset += numBytesRead;
500
501 if (pChannel->readOffset != pChannel->header->length)
502 {
503 SetLastError(ERROR_MORE_DATA);
504 return FALSE;
505 }
506
507 pChannel->readSync = FALSE;
508 Win32_WTSVirtualChannelReadAsync(pChannel);
509
510 return TRUE;
511 }
512 else if (pChannel->readAsync)
513 {
514 BOOL bSuccess;
515 DWORD numBytesRead = 0;
516
517 *lpNumberOfBytesTransferred = 0;
518
519 if (WaitForSingleObject(pChannel->hEvent, dwMilliseconds) != WAIT_TIMEOUT)
520 {
521 bSuccess =
522 GetOverlappedResult(pChannel->hFile, &(pChannel->overlapped), &numBytesRead, TRUE);
523
524 if (pChannel->showProtocol)
525 {
526 if (numBytesRead != sizeof(CHANNEL_PDU_HEADER))
527 return FALSE;
528
529 if (!bSuccess && (GetLastError() != ERROR_MORE_DATA))
530 return FALSE;
531
532 CopyMemory(lpBuffer, pChannel->header, numBytesRead);
533 *lpNumberOfBytesTransferred += numBytesRead;
534 lpBuffer = (BYTE*)lpBuffer + numBytesRead;
535 nNumberOfBytesToRead -= numBytesRead;
536 }
537
538 pChannel->readAsync = FALSE;
539
540 if (!pChannel->header->length)
541 {
542 Win32_WTSVirtualChannelReadAsync(pChannel);
543 return TRUE;
544 }
545
546 pChannel->readSync = TRUE;
547 pChannel->readOffset = 0;
548
549 if (!nNumberOfBytesToRead)
550 {
551 SetLastError(ERROR_MORE_DATA);
552 return FALSE;
553 }
554
555 numBytesRead = 0;
556
557 bSuccess = Win32_WTSVirtualChannelRead_Dynamic(pChannel, dwMilliseconds, lpBuffer,
558 nNumberOfBytesToRead, &numBytesRead);
559
560 *lpNumberOfBytesTransferred += numBytesRead;
561 return bSuccess;
562 }
563 else
564 {
565 SetLastError(ERROR_IO_INCOMPLETE);
566 return FALSE;
567 }
568 }
569
570 return FALSE;
571}
572
573static BOOL WINAPI Win32_WTSVirtualChannelRead(HANDLE hChannel, DWORD dwMilliseconds,
574 PCHAR lpBuffer, DWORD nNumberOfBytesToRead,
575 LPDWORD lpNumberOfBytesTransferred)
576{
577 WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannel;
578
579 if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
580 {
581 SetLastError(ERROR_INVALID_PARAMETER);
582 return FALSE;
583 }
584
585 if (!pChannel->waitObjectMode)
586 {
587 OVERLAPPED overlapped = { 0 };
588
589 if (ReadFile(pChannel->hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesTransferred,
590 &overlapped))
591 return TRUE;
592
593 if (GetLastError() != ERROR_IO_PENDING)
594 return FALSE;
595
596 if (!dwMilliseconds)
597 {
598 CancelIo(pChannel->hFile);
599 *lpNumberOfBytesTransferred = 0;
600 return TRUE;
601 }
602
603 if (WaitForSingleObject(pChannel->hFile, dwMilliseconds) != WAIT_TIMEOUT)
604 return GetOverlappedResult(pChannel->hFile, &overlapped, lpNumberOfBytesTransferred,
605 FALSE);
606
607 CancelIo(pChannel->hFile);
608 SetLastError(ERROR_IO_INCOMPLETE);
609
610 return FALSE;
611 }
612 else
613 {
614 if (pChannel->dynamic)
615 {
616 return Win32_WTSVirtualChannelRead_Dynamic(pChannel, dwMilliseconds, lpBuffer,
617 nNumberOfBytesToRead,
618 lpNumberOfBytesTransferred);
619 }
620 else
621 {
622 return Win32_WTSVirtualChannelRead_Static(pChannel, dwMilliseconds, lpBuffer,
623 nNumberOfBytesToRead,
624 lpNumberOfBytesTransferred);
625 }
626 }
627
628 return FALSE;
629}
630
631static BOOL WINAPI Win32_WTSVirtualChannelWrite(HANDLE hChannel, PCHAR lpBuffer,
632 DWORD nNumberOfBytesToWrite,
633 LPDWORD lpNumberOfBytesTransferred)
634{
635 OVERLAPPED overlapped = { 0 };
636 WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannel;
637
638 if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
639 {
640 SetLastError(ERROR_INVALID_PARAMETER);
641 return FALSE;
642 }
643
644 if (WriteFile(pChannel->hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesTransferred,
645 &overlapped))
646 return TRUE;
647
648 if (GetLastError() == ERROR_IO_PENDING)
649 return GetOverlappedResult(pChannel->hFile, &overlapped, lpNumberOfBytesTransferred, TRUE);
650
651 return FALSE;
652}
653
654#ifndef FILE_DEVICE_TERMSRV
655#define FILE_DEVICE_TERMSRV 0x00000038
656#endif
657
658static BOOL Win32_WTSVirtualChannelPurge_Internal(HANDLE hChannelHandle, ULONG IoControlCode)
659{
660 IO_STATUS_BLOCK ioStatusBlock = { 0 };
661 WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannelHandle;
662
663 if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
664 {
665 SetLastError(ERROR_INVALID_PARAMETER);
666 return FALSE;
667 }
668
669 NTSTATUS ntstatus =
670 NtDeviceIoControlFile(pChannel->hFile, 0, 0, 0, &ioStatusBlock, IoControlCode, 0, 0, 0, 0);
671
672 if (ntstatus == STATUS_PENDING)
673 {
674 ntstatus = NtWaitForSingleObject(pChannel->hFile, 0, 0);
675
676 if (ntstatus >= 0)
677 {
678#if defined(NONAMELESSUNION) && !defined(__MINGW32__)
679 ntstatus = ioStatusBlock.DUMMYUNIONNAME.Status;
680#else
681 ntstatus = ioStatusBlock.Status;
682#endif
683 }
684 }
685
686 if (ntstatus == STATUS_BUFFER_OVERFLOW)
687 {
688 ntstatus = STATUS_BUFFER_TOO_SMALL;
689 const DWORD error = RtlNtStatusToDosError(ntstatus);
690 SetLastError(error);
691 return FALSE;
692 }
693
694 if (ntstatus < 0)
695 {
696 const DWORD error = RtlNtStatusToDosError(ntstatus);
697 SetLastError(error);
698 return FALSE;
699 }
700
701 return TRUE;
702}
703
704static BOOL WINAPI Win32_WTSVirtualChannelPurgeInput(HANDLE hChannelHandle)
705{
706 return Win32_WTSVirtualChannelPurge_Internal(hChannelHandle,
707 (FILE_DEVICE_TERMSRV << 16) | 0x0107);
708}
709
710static BOOL WINAPI Win32_WTSVirtualChannelPurgeOutput(HANDLE hChannelHandle)
711{
712 return Win32_WTSVirtualChannelPurge_Internal(hChannelHandle,
713 (FILE_DEVICE_TERMSRV << 16) | 0x010B);
714}
715
716static BOOL WINAPI Win32_WTSVirtualChannelQuery(HANDLE hChannelHandle,
717 WTS_VIRTUAL_CLASS WtsVirtualClass, PVOID* ppBuffer,
718 DWORD* pBytesReturned)
719{
720 WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannelHandle;
721
722 if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
723 {
724 SetLastError(ERROR_INVALID_PARAMETER);
725 return FALSE;
726 }
727
728 if (WtsVirtualClass == WTSVirtualClientData)
729 {
730 SetLastError(ERROR_INVALID_PARAMETER);
731 return FALSE;
732 }
733 else if (WtsVirtualClass == WTSVirtualFileHandle)
734 {
735 *pBytesReturned = sizeof(HANDLE);
736 *ppBuffer = _wts_calloc(1, *pBytesReturned);
737
738 if (*ppBuffer == NULL)
739 {
740 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
741 return FALSE;
742 }
743
744 CopyMemory(*ppBuffer, &(pChannel->hFile), *pBytesReturned);
745 }
746 else if (WtsVirtualClass == WTSVirtualEventHandle)
747 {
748 *pBytesReturned = sizeof(HANDLE);
749 *ppBuffer = _wts_calloc(1, *pBytesReturned);
750
751 if (*ppBuffer == NULL)
752 {
753 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
754 return FALSE;
755 }
756
757 CopyMemory(*ppBuffer, &(pChannel->hEvent), *pBytesReturned);
758
759 Win32_WTSVirtualChannelReadAsync(pChannel);
760 pChannel->waitObjectMode = TRUE;
761 }
762 else
763 {
764 SetLastError(ERROR_INVALID_PARAMETER);
765 return FALSE;
766 }
767
768 return TRUE;
769}
770
771static VOID WINAPI Win32_WTSFreeMemory(PVOID pMemory)
772{
773 _wts_free(pMemory);
774}
775
776static BOOL WINAPI Win32_WTSFreeMemoryExW(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory,
777 ULONG NumberOfEntries)
778{
779 return FALSE;
780}
781
782static BOOL WINAPI Win32_WTSFreeMemoryExA(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory,
783 ULONG NumberOfEntries)
784{
785 return WTSFreeMemoryExW(WTSTypeClass, pMemory, NumberOfEntries);
786}
787
788BOOL Win32_InitializeWinSta(PWtsApiFunctionTable pWtsApi)
789{
790 g_WinStaModule = LoadLibraryA("winsta.dll");
791
792 if (!g_WinStaModule)
793 return FALSE;
794
795 pfnWinStationVirtualOpen =
796 GetProcAddressAs(g_WinStaModule, "WinStationVirtualOpen", fnWinStationVirtualOpen);
797 pfnWinStationVirtualOpenEx =
798 GetProcAddressAs(g_WinStaModule, "WinStationVirtualOpenEx", fnWinStationVirtualOpenEx);
799
800 if (!pfnWinStationVirtualOpen | !pfnWinStationVirtualOpenEx)
801 return FALSE;
802
803 pWtsApi->pVirtualChannelOpen = Win32_WTSVirtualChannelOpen;
804 pWtsApi->pVirtualChannelOpenEx = Win32_WTSVirtualChannelOpenEx;
805 pWtsApi->pVirtualChannelClose = Win32_WTSVirtualChannelClose;
806 pWtsApi->pVirtualChannelRead = Win32_WTSVirtualChannelRead;
807 pWtsApi->pVirtualChannelWrite = Win32_WTSVirtualChannelWrite;
808 pWtsApi->pVirtualChannelPurgeInput = Win32_WTSVirtualChannelPurgeInput;
809 pWtsApi->pVirtualChannelPurgeOutput = Win32_WTSVirtualChannelPurgeOutput;
810 pWtsApi->pVirtualChannelQuery = Win32_WTSVirtualChannelQuery;
811 pWtsApi->pFreeMemory = Win32_WTSFreeMemory;
812 // pWtsApi->pFreeMemoryExW = Win32_WTSFreeMemoryExW;
813 // pWtsApi->pFreeMemoryExA = Win32_WTSFreeMemoryExA;
814
815 return TRUE;
816}