xref: /reactos/dll/win32/wtsapi32/wtsapi32.c (revision 1ac9e484)
1 /* Copyright 2005 Ulrich Czekalla
2  *
3  * This library is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Lesser General Public
5  * License as published by the Free Software Foundation; either
6  * version 2.1 of the License, or (at your option) any later version.
7  *
8  * This library is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with this library; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
16  */
17 
18 #include "config.h"
19 #include <stdarg.h>
20 #include <stdlib.h>
21 #include "ntstatus.h"
22 #define WIN32_NO_STATUS
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wine/winternl.h"
26 #include "wtsapi32.h"
27 #include "wine/debug.h"
28 #include "wine/heap.h"
29 
30 WINE_DEFAULT_DEBUG_CHANNEL(wtsapi);
31 
32 #ifdef __REACTOS__ /* FIXME: Inspect */
33 #define GetCurrentProcessToken() ((HANDLE)~(ULONG_PTR)3)
34 #endif
35 
36 /************************************************************
37  *                WTSCloseServer  (WTSAPI32.@)
38  */
39 void WINAPI WTSCloseServer(HANDLE hServer)
40 {
41     FIXME("Stub %p\n", hServer);
42 }
43 
44 /************************************************************
45  *                WTSConnectSessionA  (WTSAPI32.@)
46  */
47 BOOL WINAPI WTSConnectSessionA(ULONG LogonId, ULONG TargetLogonId, PSTR pPassword, BOOL bWait)
48 {
49    FIXME("Stub %d %d (%s) %d\n", LogonId, TargetLogonId, debugstr_a(pPassword), bWait);
50    return TRUE;
51 }
52 
53 /************************************************************
54  *                WTSConnectSessionW  (WTSAPI32.@)
55  */
56 BOOL WINAPI WTSConnectSessionW(ULONG LogonId, ULONG TargetLogonId, PWSTR pPassword, BOOL bWait)
57 {
58    FIXME("Stub %d %d (%s) %d\n", LogonId, TargetLogonId, debugstr_w(pPassword), bWait);
59    return TRUE;
60 }
61 
62 /************************************************************
63  *                WTSDisconnectSession  (WTSAPI32.@)
64  */
65 BOOL WINAPI WTSDisconnectSession(HANDLE hServer, DWORD SessionId, BOOL bWait)
66 {
67     FIXME("Stub %p 0x%08x %d\n", hServer, SessionId, bWait);
68     return TRUE;
69 }
70 
71 /************************************************************
72  *                WTSEnableChildSessions  (WTSAPI32.@)
73  */
74 BOOL WINAPI WTSEnableChildSessions(BOOL enable)
75 {
76     FIXME("Stub %d\n", enable);
77     return TRUE;
78 }
79 
80 /************************************************************
81  *                WTSEnumerateProcessesA  (WTSAPI32.@)
82  */
83 BOOL WINAPI WTSEnumerateProcessesA(HANDLE hServer, DWORD Reserved, DWORD Version,
84     PWTS_PROCESS_INFOA* ppProcessInfo, DWORD* pCount)
85 {
86     FIXME("Stub %p 0x%08x 0x%08x %p %p\n", hServer, Reserved, Version,
87           ppProcessInfo, pCount);
88 
89     if (!ppProcessInfo || !pCount) return FALSE;
90 
91     *pCount = 0;
92     *ppProcessInfo = NULL;
93 
94     return TRUE;
95 }
96 
97 /************************************************************
98  *                WTSEnumerateProcessesW  (WTSAPI32.@)
99  */
100 BOOL WINAPI WTSEnumerateProcessesW(HANDLE hServer, DWORD Reserved, DWORD Version,
101     PWTS_PROCESS_INFOW* ppProcessInfo, DWORD* pCount)
102 {
103     WTS_PROCESS_INFOW *processInfo;
104     SYSTEM_PROCESS_INFORMATION *spi;
105     ULONG size = 0x4000;
106     void *buf = NULL;
107     NTSTATUS status;
108     DWORD count;
109     WCHAR *name;
110 
111     if (!ppProcessInfo || !pCount || Reserved != 0 || Version != 1)
112     {
113         SetLastError(ERROR_INVALID_PARAMETER);
114         return FALSE;
115     }
116 
117     if (hServer != WTS_CURRENT_SERVER_HANDLE)
118     {
119         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
120         return FALSE;
121     }
122 
123     do
124     {
125         size *= 2;
126         HeapFree(GetProcessHeap(), 0, buf);
127         buf = HeapAlloc(GetProcessHeap(), 0, size);
128         if (!buf)
129         {
130             SetLastError(ERROR_OUTOFMEMORY);
131             return FALSE;
132         }
133         status = NtQuerySystemInformation(SystemProcessInformation, buf, size, NULL);
134     }
135     while (status == STATUS_INFO_LENGTH_MISMATCH);
136 
137     if (status != STATUS_SUCCESS)
138     {
139         HeapFree(GetProcessHeap(), 0, buf);
140         SetLastError(RtlNtStatusToDosError(status));
141         return FALSE;
142     }
143 
144     spi = buf;
145     count = size = 0;
146     for (;;)
147     {
148         size += sizeof(WTS_PROCESS_INFOW) + spi->ProcessName.Length + sizeof(WCHAR);
149         count++;
150         if (spi->NextEntryOffset == 0) break;
151         spi = (SYSTEM_PROCESS_INFORMATION *)(((PCHAR)spi) + spi->NextEntryOffset);
152     }
153 
154     processInfo = HeapAlloc(GetProcessHeap(), 0, size);
155     if (!processInfo)
156     {
157         HeapFree(GetProcessHeap(), 0, buf);
158         SetLastError(ERROR_OUTOFMEMORY);
159         return FALSE;
160     }
161     name = (WCHAR *)&processInfo[count];
162 
163     *ppProcessInfo = processInfo;
164     *pCount = count;
165 
166     spi = buf;
167     while (count--)
168     {
169         processInfo->SessionId = 0;
170         processInfo->ProcessId = HandleToUlong(spi->UniqueProcessId);
171         processInfo->pProcessName = name;
172         processInfo->pUserSid = NULL;
173         memcpy( name, spi->ProcessName.Buffer, spi->ProcessName.Length );
174         name[ spi->ProcessName.Length/sizeof(WCHAR) ] = 0;
175 
176         processInfo++;
177         name += (spi->ProcessName.Length + sizeof(WCHAR))/sizeof(WCHAR);
178         spi = (SYSTEM_PROCESS_INFORMATION *)(((PCHAR)spi) + spi->NextEntryOffset);
179     }
180 
181     HeapFree(GetProcessHeap(), 0, buf);
182     return TRUE;
183 }
184 
185 /************************************************************
186  *                WTSEnumerateServersA  (WTSAPI32.@)
187  */
188 BOOL WINAPI WTSEnumerateServersA(LPSTR pDomainName, DWORD Reserved, DWORD Version, PWTS_SERVER_INFOA *ppServerInfo, DWORD *pCount)
189 {
190     FIXME("Stub %s 0x%08x 0x%08x %p %p\n", debugstr_a(pDomainName), Reserved, Version, ppServerInfo, pCount);
191     return FALSE;
192 }
193 
194 /************************************************************
195  *                WTSEnumerateServersW  (WTSAPI32.@)
196  */
197 BOOL WINAPI WTSEnumerateServersW(LPWSTR pDomainName, DWORD Reserved, DWORD Version, PWTS_SERVER_INFOW *ppServerInfo, DWORD *pCount)
198 {
199     FIXME("Stub %s 0x%08x 0x%08x %p %p\n", debugstr_w(pDomainName), Reserved, Version, ppServerInfo, pCount);
200     return FALSE;
201 }
202 
203 
204 /************************************************************
205  *                WTSEnumerateEnumerateSessionsA  (WTSAPI32.@)
206  */
207 BOOL WINAPI WTSEnumerateSessionsA(HANDLE hServer, DWORD Reserved, DWORD Version,
208     PWTS_SESSION_INFOA* ppSessionInfo, DWORD* pCount)
209 {
210     static int once;
211 
212     if (!once++) FIXME("Stub %p 0x%08x 0x%08x %p %p\n", hServer, Reserved, Version,
213           ppSessionInfo, pCount);
214 
215     if (!ppSessionInfo || !pCount) return FALSE;
216 
217     *pCount = 0;
218     *ppSessionInfo = NULL;
219 
220     return TRUE;
221 }
222 
223 /************************************************************
224  *                WTSEnumerateEnumerateSessionsW  (WTSAPI32.@)
225  */
226 BOOL WINAPI WTSEnumerateSessionsW(HANDLE hServer, DWORD Reserved, DWORD Version,
227     PWTS_SESSION_INFOW* ppSessionInfo, DWORD* pCount)
228 {
229     FIXME("Stub %p 0x%08x 0x%08x %p %p\n", hServer, Reserved, Version,
230           ppSessionInfo, pCount);
231 
232     if (!ppSessionInfo || !pCount) return FALSE;
233 
234     *pCount = 0;
235     *ppSessionInfo = NULL;
236 
237     return TRUE;
238 }
239 
240 /************************************************************
241  *                WTSFreeMemory (WTSAPI32.@)
242  */
243 void WINAPI WTSFreeMemory(PVOID pMemory)
244 {
245     heap_free(pMemory);
246 }
247 
248 /************************************************************
249  *                WTSLogoffSession (WTSAPI32.@)
250  */
251 BOOL WINAPI WTSLogoffSession(HANDLE hserver, DWORD session_id, BOOL bwait)
252 {
253     FIXME("(%p, 0x%x, %d): stub\n", hserver, session_id, bwait);
254     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
255     return FALSE;
256 }
257 
258 /************************************************************
259  *                WTSOpenServerA (WTSAPI32.@)
260  */
261 HANDLE WINAPI WTSOpenServerA(LPSTR pServerName)
262 {
263     FIXME("(%s) stub\n", debugstr_a(pServerName));
264     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
265     return NULL;
266 }
267 
268 /************************************************************
269  *                WTSOpenServerW (WTSAPI32.@)
270  */
271 HANDLE WINAPI WTSOpenServerW(LPWSTR pServerName)
272 {
273     FIXME("(%s) stub\n", debugstr_w(pServerName));
274     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
275     return NULL;
276 }
277 
278 /************************************************************
279  *                WTSQuerySessionInformationA  (WTSAPI32.@)
280  */
281 BOOL WINAPI WTSQuerySessionInformationA(
282     HANDLE hServer,
283     DWORD SessionId,
284     WTS_INFO_CLASS WTSInfoClass,
285     LPSTR* Buffer,
286     DWORD* BytesReturned)
287 {
288 #ifdef __REACTOS__
289     const size_t wcsErrorCode = -1;
290     LPWSTR buffer = NULL;
291     LPSTR ansiBuffer = NULL;
292     DWORD bytesReturned = 0;
293     BOOL result = FALSE;
294     size_t len;
295 
296     if (!BytesReturned || !Buffer)
297     {
298         SetLastError(ERROR_INVALID_USER_BUFFER);
299         return FALSE;
300     }
301 
302     if (!WTSQuerySessionInformationW(hServer, SessionId, WTSInfoClass, &buffer, &bytesReturned))
303     {
304         ansiBuffer = (LPSTR)buffer;
305         *Buffer = ansiBuffer;
306         *BytesReturned = bytesReturned;
307         return FALSE;
308     }
309 
310     switch (WTSInfoClass)
311     {
312         case WTSInitialProgram:
313         case WTSApplicationName:
314         case WTSWorkingDirectory:
315         case WTSOEMId:
316         case WTSUserName:
317         case WTSWinStationName:
318         case WTSDomainName:
319         case WTSClientName:
320         case WTSClientDirectory:
321         {
322             len = wcstombs(NULL, buffer, 0);
323             if (len != wcsErrorCode)
324             {
325                 len++;
326                 ansiBuffer = heap_alloc_zero(len);
327                 if (ansiBuffer && (wcstombs(ansiBuffer, buffer, len) != wcsErrorCode))
328                 {
329                     result = TRUE;
330                     bytesReturned = len;
331                 }
332             }
333             WTSFreeMemory(buffer);
334             break;
335         }
336 
337         default:
338         {
339             result = TRUE;
340             ansiBuffer = (LPSTR)buffer;
341             break;
342         }
343     }
344 
345     *Buffer = ansiBuffer;
346     *BytesReturned = bytesReturned;
347 
348     return result;
349 #else
350     /* FIXME: Forward request to winsta.dll::WinStationQueryInformationA */
351     FIXME("Stub %p 0x%08x %d %p %p\n", hServer, SessionId, WTSInfoClass,
352         Buffer, BytesReturned);
353 
354     return FALSE;
355 #endif
356 }
357 
358 /************************************************************
359  *                WTSQuerySessionInformationW  (WTSAPI32.@)
360  */
361 BOOL WINAPI WTSQuerySessionInformationW(
362     HANDLE hServer,
363     DWORD SessionId,
364     WTS_INFO_CLASS WTSInfoClass,
365     LPWSTR* Buffer,
366     DWORD* BytesReturned)
367 {
368 #ifdef __REACTOS__
369     if (!BytesReturned || !Buffer)
370     {
371         SetLastError(ERROR_INVALID_USER_BUFFER);
372         return FALSE;
373     }
374 
375 #if (NTDDI_VERSION >= NTDDI_WS08)
376     if (WTSInfoClass > WTSIsRemoteSession)
377 #else
378     if (WTSInfoClass > WTSClientProtocolType)
379 #endif
380     {
381         SetLastError(ERROR_INVALID_PARAMETER);
382         return FALSE;
383     }
384 
385     switch (WTSInfoClass)
386     {
387         case WTSSessionId:
388         {
389             const DWORD size = sizeof(ULONG);
390             ULONG* output = heap_alloc_zero(size);
391             if (!output)
392             {
393                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
394                 return FALSE;
395             }
396 
397             *output = NtCurrentTeb()->Peb->SessionId;
398             *Buffer = (LPWSTR)output;
399             *BytesReturned = size;
400             return TRUE;
401         }
402 
403         case WTSUserName:
404         {
405             WCHAR* username;
406             DWORD count = 0;
407 
408             GetUserNameW(NULL, &count);
409             if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
410                 return FALSE;
411             username = heap_alloc(count * sizeof(WCHAR));
412             if (!username)
413             {
414                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
415                 return FALSE;
416             }
417 
418             GetUserNameW(username, &count);
419             *Buffer = username;
420             *BytesReturned = count * sizeof(WCHAR);
421             return TRUE;
422         }
423 
424         case WTSConnectState:
425         {
426             const DWORD size = sizeof(DWORD);
427             WCHAR* output = heap_alloc_zero(size);
428             if (!output)
429             {
430                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
431                 return FALSE;
432             }
433 
434             *Buffer = output;
435             *BytesReturned = size;
436             return TRUE;
437         }
438 
439         case WTSClientProtocolType:
440         {
441             const DWORD size = sizeof(WORD);
442             WCHAR* output = heap_alloc_zero(size);
443             if (!output)
444             {
445                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
446                 return FALSE;
447             }
448 
449             *Buffer = output;
450             *BytesReturned = size;
451             return TRUE;
452         }
453 
454 #if (NTDDI_VERSION >= NTDDI_WS08)
455         case WTSIdleTime:
456         case WTSLogonTime:
457         case WTSIncomingBytes:
458         case WTSOutgoingBytes:
459         case WTSIncomingFrames:
460         case WTSOutgoingFrames:
461         {
462             SetLastError(ERROR_NOT_SUPPORTED);
463             return FALSE;
464         }
465 #endif /* (NTDDI_VERSION >= NTDDI_WS08) */
466 
467         default:
468         {
469             if (BytesReturned)
470                 *BytesReturned = 0;
471 
472             break;
473         }
474     }
475 
476     /* FIXME: Forward request to winsta.dll::WinStationQueryInformationW */
477     FIXME("Stub %p 0x%08x %d %p %p\n", hServer, SessionId, WTSInfoClass,
478         Buffer, BytesReturned);
479 
480     return FALSE;
481 #else
482     /* FIXME: Forward request to winsta.dll::WinStationQueryInformationW */
483     FIXME("Stub %p 0x%08x %d %p %p\n", hServer, SessionId, WTSInfoClass,
484         Buffer, BytesReturned);
485 
486     if (WTSInfoClass == WTSUserName)
487     {
488         WCHAR *username;
489         DWORD count = 0;
490 
491         GetUserNameW(NULL, &count);
492         if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return FALSE;
493         if (!(username = heap_alloc(count * sizeof(WCHAR)))) return FALSE;
494         GetUserNameW(username, &count);
495         *Buffer = username;
496         *BytesReturned = count * sizeof(WCHAR);
497         return TRUE;
498     }
499     return FALSE;
500 #endif
501 }
502 
503 /************************************************************
504  *                WTSQueryUserToken (WTSAPI32.@)
505  */
506 BOOL WINAPI WTSQueryUserToken(ULONG session_id, PHANDLE token)
507 {
508     FIXME("%u %p\n", session_id, token);
509 
510     if (!token)
511     {
512         SetLastError(ERROR_INVALID_PARAMETER);
513         return FALSE;
514     }
515 
516     return DuplicateHandle(GetCurrentProcess(), GetCurrentProcessToken(),
517                            GetCurrentProcess(), token,
518                            0, FALSE, DUPLICATE_SAME_ACCESS);
519 }
520 
521 /************************************************************
522  *                WTSQueryUserConfigA (WTSAPI32.@)
523  */
524 BOOL WINAPI WTSQueryUserConfigA(LPSTR pServerName, LPSTR pUserName, WTS_CONFIG_CLASS WTSConfigClass, LPSTR *ppBuffer, DWORD *pBytesReturned)
525 {
526    FIXME("Stub (%s) (%s) 0x%08x %p %p\n", debugstr_a(pServerName), debugstr_a(pUserName), WTSConfigClass,
527         ppBuffer, pBytesReturned);
528    return FALSE;
529 }
530 
531 /************************************************************
532  *                WTSQueryUserConfigW (WTSAPI32.@)
533  */
534 BOOL WINAPI WTSQueryUserConfigW(LPWSTR pServerName, LPWSTR pUserName, WTS_CONFIG_CLASS WTSConfigClass, LPWSTR *ppBuffer, DWORD *pBytesReturned)
535 {
536    FIXME("Stub (%s) (%s) 0x%08x %p %p\n", debugstr_w(pServerName), debugstr_w(pUserName), WTSConfigClass,
537         ppBuffer, pBytesReturned);
538    return FALSE;
539 }
540 
541 
542 /************************************************************
543  *                WTSRegisterSessionNotification (WTSAPI32.@)
544  */
545 BOOL WINAPI WTSRegisterSessionNotification(HWND hWnd, DWORD dwFlags)
546 {
547     FIXME("Stub %p 0x%08x\n", hWnd, dwFlags);
548     return TRUE;
549 }
550 
551 /************************************************************
552  *                WTSRegisterSessionNotificationEx (WTSAPI32.@)
553  */
554 BOOL WINAPI WTSRegisterSessionNotificationEx(HANDLE hServer, HWND hWnd, DWORD dwFlags)
555 {
556     FIXME("Stub %p %p 0x%08x\n", hServer, hWnd, dwFlags);
557     return FALSE;
558 }
559 
560 
561 /************************************************************
562  *                WTSSendMessageA (WTSAPI32.@)
563  */
564 BOOL WINAPI WTSSendMessageA(HANDLE hServer, DWORD SessionId, LPSTR pTitle, DWORD TitleLength, LPSTR pMessage,
565    DWORD MessageLength, DWORD Style, DWORD Timeout, DWORD *pResponse, BOOL bWait)
566 {
567    FIXME("Stub %p 0x%08x (%s) %d (%s) %d 0x%08x %d %p %d\n", hServer, SessionId, debugstr_a(pTitle), TitleLength, debugstr_a(pMessage), MessageLength, Style, Timeout, pResponse, bWait);
568    return FALSE;
569 }
570 
571 /************************************************************
572  *                WTSSendMessageW (WTSAPI32.@)
573  */
574 BOOL WINAPI WTSSendMessageW(HANDLE hServer, DWORD SessionId, LPWSTR pTitle, DWORD TitleLength, LPWSTR pMessage,
575    DWORD MessageLength, DWORD Style, DWORD Timeout, DWORD *pResponse, BOOL bWait)
576 {
577    FIXME("Stub %p 0x%08x (%s) %d (%s) %d 0x%08x %d %p %d\n", hServer, SessionId, debugstr_w(pTitle), TitleLength, debugstr_w(pMessage), MessageLength, Style, Timeout, pResponse, bWait);
578    return FALSE;
579 }
580 
581 /************************************************************
582  *                WTSSetUserConfigA (WTSAPI32.@)
583  */
584 BOOL WINAPI WTSSetUserConfigA(LPSTR pServerName, LPSTR pUserName, WTS_CONFIG_CLASS WTSConfigClass, LPSTR pBuffer, DWORD DataLength)
585 {
586    FIXME("Stub (%s) (%s) 0x%08x %p %d\n", debugstr_a(pServerName), debugstr_a(pUserName), WTSConfigClass,pBuffer, DataLength);
587    return FALSE;
588 }
589 
590 /************************************************************
591  *                WTSSetUserConfigW (WTSAPI32.@)
592  */
593 BOOL WINAPI WTSSetUserConfigW(LPWSTR pServerName, LPWSTR pUserName, WTS_CONFIG_CLASS WTSConfigClass, LPWSTR pBuffer, DWORD DataLength)
594 {
595    FIXME("Stub (%s) (%s) 0x%08x %p %d\n", debugstr_w(pServerName), debugstr_w(pUserName), WTSConfigClass,pBuffer, DataLength);
596    return FALSE;
597 }
598 
599 /************************************************************
600  *                WTSShutdownSystem (WTSAPI32.@)
601  */
602 BOOL WINAPI WTSShutdownSystem(HANDLE hServer, DWORD ShutdownFlag)
603 {
604    FIXME("Stub %p 0x%08x\n", hServer,ShutdownFlag);
605    return FALSE;
606 }
607 
608 /************************************************************
609  *                WTSStartRemoteControlSessionA (WTSAPI32.@)
610  */
611 BOOL WINAPI WTSStartRemoteControlSessionA(LPSTR pTargetServerName, ULONG TargetLogonId, BYTE HotkeyVk, USHORT HotkeyModifiers)
612 {
613    FIXME("Stub (%s) %d %d %d\n", debugstr_a(pTargetServerName), TargetLogonId, HotkeyVk, HotkeyModifiers);
614    return FALSE;
615 }
616 
617 /************************************************************
618  *                WTSStartRemoteControlSessionW (WTSAPI32.@)
619  */
620 BOOL WINAPI WTSStartRemoteControlSessionW(LPWSTR pTargetServerName, ULONG TargetLogonId, BYTE HotkeyVk, USHORT HotkeyModifiers)
621 {
622    FIXME("Stub (%s) %d %d %d\n", debugstr_w(pTargetServerName), TargetLogonId, HotkeyVk, HotkeyModifiers);
623    return FALSE;
624 }
625 
626 /************************************************************
627  *                WTSStopRemoteControlSession (WTSAPI32.@)
628  */
629 BOOL WINAPI WTSStopRemoteControlSession(ULONG LogonId)
630 {
631    FIXME("Stub %d\n",  LogonId);
632    return FALSE;
633 }
634 
635 /************************************************************
636  *                WTSTerminateProcess (WTSAPI32.@)
637  */
638 BOOL WINAPI WTSTerminateProcess(HANDLE hServer, DWORD ProcessId, DWORD ExitCode)
639 {
640    FIXME("Stub %p %d %d\n", hServer, ProcessId, ExitCode);
641    return FALSE;
642 }
643 
644 /************************************************************
645  *                WTSUnRegisterSessionNotification (WTSAPI32.@)
646  */
647 BOOL WINAPI WTSUnRegisterSessionNotification(HWND hWnd)
648 {
649     FIXME("Stub %p\n", hWnd);
650     return FALSE;
651 }
652 
653 /************************************************************
654  *                WTSUnRegisterSessionNotification (WTSAPI32.@)
655  */
656 BOOL WINAPI WTSUnRegisterSessionNotificationEx(HANDLE hServer, HWND hWnd)
657 {
658     FIXME("Stub %p %p\n", hServer, hWnd);
659     return FALSE;
660 }
661 
662 
663 /************************************************************
664  *                WTSVirtualChannelClose (WTSAPI32.@)
665  */
666 BOOL WINAPI WTSVirtualChannelClose(HANDLE hChannelHandle)
667 {
668    FIXME("Stub %p\n", hChannelHandle);
669    return FALSE;
670 }
671 
672 /************************************************************
673  *                WTSVirtualChannelOpen (WTSAPI32.@)
674  */
675 HANDLE WINAPI WTSVirtualChannelOpen(HANDLE hServer, DWORD SessionId, LPSTR pVirtualName)
676 {
677    FIXME("Stub %p %d (%s)\n", hServer, SessionId, debugstr_a(pVirtualName));
678    return NULL;
679 }
680 
681 /************************************************************
682  *                WTSVirtualChannelOpen (WTSAPI32.@)
683  */
684 HANDLE WINAPI WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualName, DWORD flags)
685 {
686    FIXME("Stub %d (%s) %d\n",  SessionId, debugstr_a(pVirtualName), flags);
687    return NULL;
688 }
689 
690 /************************************************************
691  *                WTSVirtualChannelPurgeInput (WTSAPI32.@)
692  */
693 BOOL WINAPI WTSVirtualChannelPurgeInput(HANDLE hChannelHandle)
694 {
695    FIXME("Stub %p\n", hChannelHandle);
696    return FALSE;
697 }
698 
699 /************************************************************
700  *                WTSVirtualChannelPurgeOutput (WTSAPI32.@)
701  */
702 BOOL WINAPI WTSVirtualChannelPurgeOutput(HANDLE hChannelHandle)
703 {
704    FIXME("Stub %p\n", hChannelHandle);
705    return FALSE;
706 }
707 
708 
709 /************************************************************
710  *                WTSVirtualChannelQuery (WTSAPI32.@)
711  */
712 BOOL WINAPI WTSVirtualChannelQuery(HANDLE hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass, PVOID *ppBuffer, DWORD *pBytesReturned)
713 {
714    FIXME("Stub %p %d %p %p\n", hChannelHandle, WtsVirtualClass, ppBuffer, pBytesReturned);
715    return FALSE;
716 }
717 
718 /************************************************************
719  *                WTSVirtualChannelRead (WTSAPI32.@)
720  */
721 BOOL WINAPI WTSVirtualChannelRead(HANDLE hChannelHandle, ULONG TimeOut, PCHAR Buffer, ULONG BufferSize, PULONG pBytesRead)
722 {
723    FIXME("Stub %p %d %p %d %p\n", hChannelHandle, TimeOut, Buffer, BufferSize, pBytesRead);
724    return FALSE;
725 }
726 
727 /************************************************************
728  *                WTSVirtualChannelWrite (WTSAPI32.@)
729  */
730 BOOL WINAPI WTSVirtualChannelWrite(HANDLE hChannelHandle, PCHAR Buffer, ULONG Length, PULONG pBytesWritten)
731 {
732    FIXME("Stub %p %p %d %p\n", hChannelHandle, Buffer, Length, pBytesWritten);
733    return FALSE;
734 }
735 
736 /************************************************************
737  *                WTSWaitSystemEvent (WTSAPI32.@)
738  */
739 BOOL WINAPI WTSWaitSystemEvent(HANDLE hServer, DWORD Mask, DWORD* Flags)
740 {
741     /* FIXME: Forward request to winsta.dll::WinStationWaitSystemEvent */
742     FIXME("Stub %p 0x%08x %p\n", hServer, Mask, Flags);
743     return FALSE;
744 }
745