/**
 * WinPR: Windows Portable Runtime
 * Windows Terminal Services API
 *
 * Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
 * Copyright 2015 Copyright 2015 Thincast Technologies GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef WINPR_WTSAPI_H
#define WINPR_WTSAPI_H

#include <winpr/winpr.h>
#include <winpr/wtypes.h>

#include <winpr/file.h>

#define CHANNEL_CHUNK_MAX_LENGTH 16256

WINPR_PRAGMA_DIAG_PUSH
WINPR_PRAGMA_DIAG_IGNORED_RESERVED_IDENTIFIER

#ifdef _WIN32

#define CurrentTime _CurrentTime /* Workaround for X11 "CurrentTime" header conflict */

#endif

#if defined(_WIN32) && !defined(_UWP)

#include <pchannel.h>

#else

/**
 * Virtual Channel Protocol (pchannel.h)
 */

#define CHANNEL_CHUNK_LENGTH 1600

#define CHANNEL_PDU_LENGTH (CHANNEL_CHUNK_LENGTH + sizeof(CHANNEL_PDU_HEADER))

#define CHANNEL_FLAG_FIRST 0x01
#define CHANNEL_FLAG_LAST 0x02
#define CHANNEL_FLAG_ONLY (CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST)
#define CHANNEL_FLAG_MIDDLE 0
#define CHANNEL_FLAG_FAIL 0x100

#define CHANNEL_OPTION_INITIALIZED 0x80000000

#define CHANNEL_OPTION_ENCRYPT_RDP 0x40000000
#define CHANNEL_OPTION_ENCRYPT_SC 0x20000000
#define CHANNEL_OPTION_ENCRYPT_CS 0x10000000
#define CHANNEL_OPTION_PRI_HIGH 0x08000000
#define CHANNEL_OPTION_PRI_MED 0x04000000
#define CHANNEL_OPTION_PRI_LOW 0x02000000
#define CHANNEL_OPTION_COMPRESS_RDP 0x00800000
#define CHANNEL_OPTION_COMPRESS 0x00400000
#define CHANNEL_OPTION_SHOW_PROTOCOL 0x00200000
#define CHANNEL_OPTION_REMOTE_CONTROL_PERSISTENT 0x00100000

#define CHANNEL_MAX_COUNT 31
#define CHANNEL_NAME_LEN 7

typedef struct tagCHANNEL_DEF
{
	char name[CHANNEL_NAME_LEN + 1];
	ULONG options;
} CHANNEL_DEF;
typedef CHANNEL_DEF* PCHANNEL_DEF;
typedef PCHANNEL_DEF* PPCHANNEL_DEF;

typedef struct tagCHANNEL_PDU_HEADER
{
	UINT32 length;
	UINT32 flags;
} CHANNEL_PDU_HEADER, *PCHANNEL_PDU_HEADER;

#endif /* _WIN32 */

/**
 * These channel flags are defined in some versions of pchannel.h only
 */

#ifndef CHANNEL_FLAG_SHOW_PROTOCOL
#define CHANNEL_FLAG_SHOW_PROTOCOL 0x10
#endif
#ifndef CHANNEL_FLAG_SUSPEND
#define CHANNEL_FLAG_SUSPEND 0x20
#endif
#ifndef CHANNEL_FLAG_RESUME
#define CHANNEL_FLAG_RESUME 0x40
#endif
#ifndef CHANNEL_FLAG_SHADOW_PERSISTENT
#define CHANNEL_FLAG_SHADOW_PERSISTENT 0x80
#endif

#if !defined(_WIN32) || !defined(H_CCHANNEL)

/**
 * Virtual Channel Client API (cchannel.h)
 */

#ifdef _WIN32
#define VCAPITYPE __stdcall
#define VCEXPORT
#else
#define VCAPITYPE CALLBACK
#define VCEXPORT __export
#endif

typedef VOID VCAPITYPE CHANNEL_INIT_EVENT_FN(LPVOID pInitHandle, UINT event, LPVOID pData,
                                             UINT dataLength);

typedef CHANNEL_INIT_EVENT_FN* PCHANNEL_INIT_EVENT_FN;

typedef VOID VCAPITYPE CHANNEL_INIT_EVENT_EX_FN(LPVOID lpUserParam, LPVOID pInitHandle, UINT event,
                                                LPVOID pData, UINT dataLength);

typedef CHANNEL_INIT_EVENT_EX_FN* PCHANNEL_INIT_EVENT_EX_FN;

#define CHANNEL_EVENT_INITIALIZED 0
#define CHANNEL_EVENT_CONNECTED 1
#define CHANNEL_EVENT_V1_CONNECTED 2
#define CHANNEL_EVENT_DISCONNECTED 3
#define CHANNEL_EVENT_TERMINATED 4
#define CHANNEL_EVENT_REMOTE_CONTROL_START 5
#define CHANNEL_EVENT_REMOTE_CONTROL_STOP 6
#define CHANNEL_EVENT_ATTACHED 7
#define CHANNEL_EVENT_DETACHED 8
#define CHANNEL_EVENT_DATA_RECEIVED 10
#define CHANNEL_EVENT_WRITE_COMPLETE 11
#define CHANNEL_EVENT_WRITE_CANCELLED 12

typedef VOID VCAPITYPE CHANNEL_OPEN_EVENT_FN(DWORD openHandle, UINT event, LPVOID pData,
                                             UINT32 dataLength, UINT32 totalLength,
                                             UINT32 dataFlags);

typedef CHANNEL_OPEN_EVENT_FN* PCHANNEL_OPEN_EVENT_FN;

typedef VOID VCAPITYPE CHANNEL_OPEN_EVENT_EX_FN(LPVOID lpUserParam, DWORD openHandle, UINT event,
                                                LPVOID pData, UINT32 dataLength, UINT32 totalLength,
                                                UINT32 dataFlags);

typedef CHANNEL_OPEN_EVENT_EX_FN* PCHANNEL_OPEN_EVENT_EX_FN;

#define CHANNEL_RC_OK 0
#define CHANNEL_RC_ALREADY_INITIALIZED 1
#define CHANNEL_RC_NOT_INITIALIZED 2
#define CHANNEL_RC_ALREADY_CONNECTED 3
#define CHANNEL_RC_NOT_CONNECTED 4
#define CHANNEL_RC_TOO_MANY_CHANNELS 5
#define CHANNEL_RC_BAD_CHANNEL 6
#define CHANNEL_RC_BAD_CHANNEL_HANDLE 7
#define CHANNEL_RC_NO_BUFFER 8
#define CHANNEL_RC_BAD_INIT_HANDLE 9
#define CHANNEL_RC_NOT_OPEN 10
#define CHANNEL_RC_BAD_PROC 11
#define CHANNEL_RC_NO_MEMORY 12
#define CHANNEL_RC_UNKNOWN_CHANNEL_NAME 13
#define CHANNEL_RC_ALREADY_OPEN 14
#define CHANNEL_RC_NOT_IN_VIRTUALCHANNELENTRY 15
#define CHANNEL_RC_NULL_DATA 16
#define CHANNEL_RC_ZERO_LENGTH 17
#define CHANNEL_RC_INVALID_INSTANCE 18
#define CHANNEL_RC_UNSUPPORTED_VERSION 19
#define CHANNEL_RC_INITIALIZATION_ERROR 20

#define VIRTUAL_CHANNEL_VERSION_WIN2000 1

typedef UINT VCAPITYPE VIRTUALCHANNELINIT(LPVOID* ppInitHandle, PCHANNEL_DEF pChannel,
                                          INT channelCount, ULONG versionRequested,
                                          PCHANNEL_INIT_EVENT_FN pChannelInitEventProc);

typedef VIRTUALCHANNELINIT* PVIRTUALCHANNELINIT;

typedef UINT VCAPITYPE VIRTUALCHANNELINITEX(LPVOID lpUserParam, LPVOID clientContext,
                                            LPVOID pInitHandle, PCHANNEL_DEF pChannel,
                                            INT channelCount, ULONG versionRequested,
                                            PCHANNEL_INIT_EVENT_EX_FN pChannelInitEventProcEx);

typedef VIRTUALCHANNELINITEX* PVIRTUALCHANNELINITEX;

typedef UINT VCAPITYPE VIRTUALCHANNELOPEN(LPVOID pInitHandle, LPDWORD pOpenHandle,
                                          PCHAR pChannelName,
                                          PCHANNEL_OPEN_EVENT_FN pChannelOpenEventProc);

typedef VIRTUALCHANNELOPEN* PVIRTUALCHANNELOPEN;

typedef UINT VCAPITYPE VIRTUALCHANNELOPENEX(LPVOID pInitHandle, LPDWORD pOpenHandle,
                                            PCHAR pChannelName,
                                            PCHANNEL_OPEN_EVENT_EX_FN pChannelOpenEventProcEx);

typedef VIRTUALCHANNELOPENEX* PVIRTUALCHANNELOPENEX;

typedef UINT VCAPITYPE VIRTUALCHANNELCLOSE(DWORD openHandle);

typedef VIRTUALCHANNELCLOSE* PVIRTUALCHANNELCLOSE;

typedef UINT VCAPITYPE VIRTUALCHANNELCLOSEEX(LPVOID pInitHandle, DWORD openHandle);

typedef VIRTUALCHANNELCLOSEEX* PVIRTUALCHANNELCLOSEEX;

typedef UINT VCAPITYPE VIRTUALCHANNELWRITE(DWORD openHandle, LPVOID pData, ULONG dataLength,
                                           LPVOID pUserData);

typedef VIRTUALCHANNELWRITE* PVIRTUALCHANNELWRITE;

typedef UINT VCAPITYPE VIRTUALCHANNELWRITEEX(LPVOID pInitHandle, DWORD openHandle, LPVOID pData,
                                             ULONG dataLength, LPVOID pUserData);

typedef VIRTUALCHANNELWRITEEX* PVIRTUALCHANNELWRITEEX;

typedef struct tagCHANNEL_ENTRY_POINTS
{
	DWORD cbSize;
	DWORD protocolVersion;
	WINPR_ATTR_NODISCARD PVIRTUALCHANNELINIT pVirtualChannelInit;
	WINPR_ATTR_NODISCARD PVIRTUALCHANNELOPEN pVirtualChannelOpen;
	WINPR_ATTR_NODISCARD PVIRTUALCHANNELCLOSE pVirtualChannelClose;
	WINPR_ATTR_NODISCARD PVIRTUALCHANNELWRITE pVirtualChannelWrite;
} CHANNEL_ENTRY_POINTS, *PCHANNEL_ENTRY_POINTS;

typedef struct tagCHANNEL_ENTRY_POINTS_EX
{
	DWORD cbSize;
	DWORD protocolVersion;
	WINPR_ATTR_NODISCARD PVIRTUALCHANNELINITEX pVirtualChannelInitEx;
	WINPR_ATTR_NODISCARD PVIRTUALCHANNELOPENEX pVirtualChannelOpenEx;
	WINPR_ATTR_NODISCARD PVIRTUALCHANNELCLOSEEX pVirtualChannelCloseEx;
	WINPR_ATTR_NODISCARD PVIRTUALCHANNELWRITEEX pVirtualChannelWriteEx;
} CHANNEL_ENTRY_POINTS_EX, *PCHANNEL_ENTRY_POINTS_EX;

typedef BOOL VCAPITYPE VIRTUALCHANNELENTRY(PCHANNEL_ENTRY_POINTS pEntryPoints);

typedef VIRTUALCHANNELENTRY* PVIRTUALCHANNELENTRY;

typedef BOOL VCAPITYPE VIRTUALCHANNELENTRYEX(PCHANNEL_ENTRY_POINTS_EX pEntryPointsEx,
                                             PVOID pInitHandle);

typedef VIRTUALCHANNELENTRYEX* PVIRTUALCHANNELENTRYEX;

typedef HRESULT(VCAPITYPE* PFNVCAPIGETINSTANCE)(REFIID refiid, PULONG pNumObjs, PVOID* ppObjArray);

#endif

#if !defined(_WIN32) || !defined(_INC_WTSAPI)

/**
 * Windows Terminal Services API (wtsapi32.h)
 */

#define WTS_CURRENT_SERVER ((HANDLE) nullptr)
#define WTS_CURRENT_SERVER_HANDLE ((HANDLE) nullptr)
#define WTS_CURRENT_SERVER_NAME (nullptr)

#define WTS_CURRENT_SESSION ((DWORD)-1)

#define WTS_ANY_SESSION ((DWORD)-2)

#define IDTIMEOUT 32000
#define IDASYNC 32001

#define USERNAME_LENGTH 20
#define CLIENTNAME_LENGTH 20
#define CLIENTADDRESS_LENGTH 30

#define WTS_WSD_LOGOFF 0x00000001
#define WTS_WSD_SHUTDOWN 0x00000002
#define WTS_WSD_REBOOT 0x00000004
#define WTS_WSD_POWEROFF 0x00000008
#define WTS_WSD_FASTREBOOT 0x00000010

#define MAX_ELAPSED_TIME_LENGTH 15
#define MAX_DATE_TIME_LENGTH 56
#define WINSTATIONNAME_LENGTH 32
#define DOMAIN_LENGTH 17

#define WTS_DRIVE_LENGTH 3
#define WTS_LISTENER_NAME_LENGTH 32
#define WTS_COMMENT_LENGTH 60

#define WTS_LISTENER_CREATE 0x00000001
#define WTS_LISTENER_UPDATE 0x00000010

#define WTS_SECURITY_QUERY_INFORMATION 0x00000001
#define WTS_SECURITY_SET_INFORMATION 0x00000002
#define WTS_SECURITY_RESET 0x00000004
#define WTS_SECURITY_VIRTUAL_CHANNELS 0x00000008
#define WTS_SECURITY_REMOTE_CONTROL 0x00000010
#define WTS_SECURITY_LOGON 0x00000020
#define WTS_SECURITY_LOGOFF 0x00000040
#define WTS_SECURITY_MESSAGE 0x00000080
#define WTS_SECURITY_CONNECT 0x00000100
#define WTS_SECURITY_DISCONNECT 0x00000200

#define WTS_SECURITY_GUEST_ACCESS (WTS_SECURITY_LOGON)

#define WTS_SECURITY_CURRENT_GUEST_ACCESS (WTS_SECURITY_VIRTUAL_CHANNELS | WTS_SECURITY_LOGOFF)

#define WTS_SECURITY_USER_ACCESS \
	(WTS_SECURITY_CURRENT_GUEST_ACCESS | WTS_SECURITY_QUERY_INFORMATION | WTS_SECURITY_CONNECT)

#define WTS_SECURITY_CURRENT_USER_ACCESS                                               \
	(WTS_SECURITY_SET_INFORMATION | WTS_SECURITY_RESET WTS_SECURITY_VIRTUAL_CHANNELS | \
	 WTS_SECURITY_LOGOFF WTS_SECURITY_DISCONNECT)

#define WTS_SECURITY_ALL_ACCESS                                                                 \
	(STANDARD_RIGHTS_REQUIRED | WTS_SECURITY_QUERY_INFORMATION | WTS_SECURITY_SET_INFORMATION | \
	 WTS_SECURITY_RESET | WTS_SECURITY_VIRTUAL_CHANNELS | WTS_SECURITY_REMOTE_CONTROL |         \
	 WTS_SECURITY_LOGON | WTS_SECURITY_MESSAGE | WTS_SECURITY_CONNECT | WTS_SECURITY_DISCONNECT)

typedef enum
{
	WTSActive,
	WTSConnected,
	WTSConnectQuery,
	WTSShadow,
	WTSDisconnected,
	WTSIdle,
	WTSListen,
	WTSReset,
	WTSDown,
	WTSInit
} WTS_CONNECTSTATE_CLASS;

typedef struct
{
	LPWSTR pServerName;
} WTS_SERVER_INFOW, *PWTS_SERVER_INFOW;

typedef struct
{
	LPSTR pServerName;
} WTS_SERVER_INFOA, *PWTS_SERVER_INFOA;

typedef struct
{
	DWORD SessionId;
	LPWSTR pWinStationName;
	WTS_CONNECTSTATE_CLASS State;
} WTS_SESSION_INFOW, *PWTS_SESSION_INFOW;

typedef struct
{
	DWORD SessionId;
	LPSTR pWinStationName;
	WTS_CONNECTSTATE_CLASS State;
} WTS_SESSION_INFOA, *PWTS_SESSION_INFOA;

typedef struct
{
	DWORD ExecEnvId;
	WTS_CONNECTSTATE_CLASS State;
	DWORD SessionId;
	LPWSTR pSessionName;
	LPWSTR pHostName;
	LPWSTR pUserName;
	LPWSTR pDomainName;
	LPWSTR pFarmName;
} WTS_SESSION_INFO_1W, *PWTS_SESSION_INFO_1W;

typedef struct
{
	DWORD ExecEnvId;
	WTS_CONNECTSTATE_CLASS State;
	DWORD SessionId;
	LPSTR pSessionName;
	LPSTR pHostName;
	LPSTR pUserName;
	LPSTR pDomainName;
	LPSTR pFarmName;
} WTS_SESSION_INFO_1A, *PWTS_SESSION_INFO_1A;

typedef struct
{
	DWORD SessionId;
	DWORD ProcessId;
	LPWSTR pProcessName;
	PSID pUserSid;
} WTS_PROCESS_INFOW, *PWTS_PROCESS_INFOW;

typedef struct
{
	DWORD SessionId;
	DWORD ProcessId;
	LPSTR pProcessName;
	PSID pUserSid;
} WTS_PROCESS_INFOA, *PWTS_PROCESS_INFOA;

#define WTS_PROTOCOL_TYPE_CONSOLE 0
#define WTS_PROTOCOL_TYPE_ICA 1
#define WTS_PROTOCOL_TYPE_RDP 2

typedef enum
{
	WTSInitialProgram,
	WTSApplicationName,
	WTSWorkingDirectory,
	WTSOEMId,
	WTSSessionId,
	WTSUserName,
	WTSWinStationName,
	WTSDomainName,
	WTSConnectState,
	WTSClientBuildNumber,
	WTSClientName,
	WTSClientDirectory,
	WTSClientProductId,
	WTSClientHardwareId,
	WTSClientAddress,
	WTSClientDisplay,
	WTSClientProtocolType,
	WTSIdleTime,
	WTSLogonTime,
	WTSIncomingBytes,
	WTSOutgoingBytes,
	WTSIncomingFrames,
	WTSOutgoingFrames,
	WTSClientInfo,
	WTSSessionInfo,
	WTSSessionInfoEx,
	WTSConfigInfo,
	WTSValidationInfo,
	WTSSessionAddressV4,
	WTSIsRemoteSession
} WTS_INFO_CLASS;

typedef struct
{
	ULONG version;
	ULONG fConnectClientDrivesAtLogon;
	ULONG fConnectPrinterAtLogon;
	ULONG fDisablePrinterRedirection;
	ULONG fDisableDefaultMainClientPrinter;
	ULONG ShadowSettings;
	WCHAR LogonUserName[USERNAME_LENGTH + 1];
	WCHAR LogonDomain[DOMAIN_LENGTH + 1];
	WCHAR WorkDirectory[MAX_PATH + 1];
	WCHAR InitialProgram[MAX_PATH + 1];
	WCHAR ApplicationName[MAX_PATH + 1];
} WTSCONFIGINFOW, *PWTSCONFIGINFOW;

typedef struct
{
	ULONG version;
	ULONG fConnectClientDrivesAtLogon;
	ULONG fConnectPrinterAtLogon;
	ULONG fDisablePrinterRedirection;
	ULONG fDisableDefaultMainClientPrinter;
	ULONG ShadowSettings;
	CHAR LogonUserName[USERNAME_LENGTH + 1];
	CHAR LogonDomain[DOMAIN_LENGTH + 1];
	CHAR WorkDirectory[MAX_PATH + 1];
	CHAR InitialProgram[MAX_PATH + 1];
	CHAR ApplicationName[MAX_PATH + 1];
} WTSCONFIGINFOA, *PWTSCONFIGINFOA;

typedef struct
{
	WTS_CONNECTSTATE_CLASS State;
	DWORD SessionId;
	DWORD IncomingBytes;
	DWORD OutgoingBytes;
	DWORD IncomingFrames;
	DWORD OutgoingFrames;
	DWORD IncomingCompressedBytes;
	DWORD OutgoingCompressedBytes;
	WCHAR WinStationName[WINSTATIONNAME_LENGTH];
	WCHAR Domain[DOMAIN_LENGTH];
	WCHAR UserName[USERNAME_LENGTH + 1];
	LARGE_INTEGER ConnectTime;
	LARGE_INTEGER DisconnectTime;
	LARGE_INTEGER LastInputTime;
	LARGE_INTEGER LogonTime;
	// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
	LARGE_INTEGER _CurrentTime; /* Conflicts with X11 headers */
} WTSINFOW, *PWTSINFOW;

typedef struct
{
	WTS_CONNECTSTATE_CLASS State;
	DWORD SessionId;
	DWORD IncomingBytes;
	DWORD OutgoingBytes;
	DWORD IncomingFrames;
	DWORD OutgoingFrames;
	DWORD IncomingCompressedBytes;
	DWORD OutgoingCompressedBy;
	CHAR WinStationName[WINSTATIONNAME_LENGTH];
	CHAR Domain[DOMAIN_LENGTH];
	CHAR UserName[USERNAME_LENGTH + 1];
	LARGE_INTEGER ConnectTime;
	LARGE_INTEGER DisconnectTime;
	LARGE_INTEGER LastInputTime;
	LARGE_INTEGER LogonTime;
	// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
	LARGE_INTEGER _CurrentTime; /* Conflicts with X11 headers */
} WTSINFOA, *PWTSINFOA;

#define WTS_SESSIONSTATE_UNKNOWN 0xFFFFFFFF
#define WTS_SESSIONSTATE_LOCK 0x00000000
#define WTS_SESSIONSTATE_UNLOCK 0x00000001

typedef struct
{
	ULONG SessionId;
	WTS_CONNECTSTATE_CLASS SessionState;
	LONG SessionFlags;
	WCHAR WinStationName[WINSTATIONNAME_LENGTH + 1];
	WCHAR UserName[USERNAME_LENGTH + 1];
	WCHAR DomainName[DOMAIN_LENGTH + 1];
	LARGE_INTEGER LogonTime;
	LARGE_INTEGER ConnectTime;
	LARGE_INTEGER DisconnectTime;
	LARGE_INTEGER LastInputTime;
	// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
	LARGE_INTEGER _CurrentTime; /* Conflicts with X11 headers */
	DWORD IncomingBytes;
	DWORD OutgoingBytes;
	DWORD IncomingFrames;
	DWORD OutgoingFrames;
	DWORD IncomingCompressedBytes;
	DWORD OutgoingCompressedBytes;
} WTSINFOEX_LEVEL1_W, *PWTSINFOEX_LEVEL1_W;

typedef struct
{
	ULONG SessionId;
	WTS_CONNECTSTATE_CLASS SessionState;
	LONG SessionFlags;
	CHAR WinStationName[WINSTATIONNAME_LENGTH + 1];
	CHAR UserName[USERNAME_LENGTH + 1];
	CHAR DomainName[DOMAIN_LENGTH + 1];
	LARGE_INTEGER LogonTime;
	LARGE_INTEGER ConnectTime;
	LARGE_INTEGER DisconnectTime;
	LARGE_INTEGER LastInputTime;
	// NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
	LARGE_INTEGER _CurrentTime; /* Conflicts with X11 headers */
	DWORD IncomingBytes;
	DWORD OutgoingBytes;
	DWORD IncomingFrames;
	DWORD OutgoingFrames;
	DWORD IncomingCompressedBytes;
	DWORD OutgoingCompressedBytes;
} WTSINFOEX_LEVEL1_A, *PWTSINFOEX_LEVEL1_A;

typedef union
{
	WTSINFOEX_LEVEL1_W WTSInfoExLevel1;
} WTSINFOEX_LEVEL_W, *PWTSINFOEX_LEVEL_W;

typedef union
{
	WTSINFOEX_LEVEL1_A WTSInfoExLevel1;
} WTSINFOEX_LEVEL_A, *PWTSINFOEX_LEVEL_A;

typedef struct
{
	DWORD Level;
	WTSINFOEX_LEVEL_W Data;
} WTSINFOEXW, *PWTSINFOEXW;

typedef struct
{
	DWORD Level;
	WTSINFOEX_LEVEL_A Data;
} WTSINFOEXA, *PWTSINFOEXA;

typedef struct
{
	WCHAR ClientName[CLIENTNAME_LENGTH + 1];
	WCHAR Domain[DOMAIN_LENGTH + 1];
	WCHAR UserName[USERNAME_LENGTH + 1];
	WCHAR WorkDirectory[MAX_PATH + 1];
	WCHAR InitialProgram[MAX_PATH + 1];
	BYTE EncryptionLevel;
	ULONG ClientAddressFamily;
	USHORT ClientAddress[CLIENTADDRESS_LENGTH + 1];
	USHORT HRes;
	USHORT VRes;
	USHORT ColorDepth;
	WCHAR ClientDirectory[MAX_PATH + 1];
	ULONG ClientBuildNumber;
	ULONG ClientHardwareId;
	USHORT ClientProductId;
	USHORT OutBufCountHost;
	USHORT OutBufCountClient;
	USHORT OutBufLength;
	WCHAR DeviceId[MAX_PATH + 1];
} WTSCLIENTW, *PWTSCLIENTW;

typedef struct
{
	CHAR ClientName[CLIENTNAME_LENGTH + 1];
	CHAR Domain[DOMAIN_LENGTH + 1];
	CHAR UserName[USERNAME_LENGTH + 1];
	CHAR WorkDirectory[MAX_PATH + 1];
	CHAR InitialProgram[MAX_PATH + 1];
	BYTE EncryptionLevel;
	ULONG ClientAddressFamily;
	USHORT ClientAddress[CLIENTADDRESS_LENGTH + 1];
	USHORT HRes;
	USHORT VRes;
	USHORT ColorDepth;
	CHAR ClientDirectory[MAX_PATH + 1];
	ULONG ClientBuildNumber;
	ULONG ClientHardwareId;
	USHORT ClientProductId;
	USHORT OutBufCountHost;
	USHORT OutBufCountClient;
	USHORT OutBufLength;
	CHAR DeviceId[MAX_PATH + 1];
} WTSCLIENTA, *PWTSCLIENTA;

#define PRODUCTINFO_COMPANYNAME_LENGTH 256
#define PRODUCTINFO_PRODUCTID_LENGTH 4

typedef struct
{
	CHAR CompanyName[PRODUCTINFO_COMPANYNAME_LENGTH];
	CHAR ProductID[PRODUCTINFO_PRODUCTID_LENGTH];
} PRODUCT_INFOA;

typedef struct
{
	WCHAR CompanyName[PRODUCTINFO_COMPANYNAME_LENGTH];
	WCHAR ProductID[PRODUCTINFO_PRODUCTID_LENGTH];
} PRODUCT_INFOW;

#define VALIDATIONINFORMATION_LICENSE_LENGTH 16384
#define VALIDATIONINFORMATION_HARDWAREID_LENGTH 20

typedef struct
{
	PRODUCT_INFOA ProductInfo;
	BYTE License[VALIDATIONINFORMATION_LICENSE_LENGTH];
	DWORD LicenseLength;
	BYTE HardwareID[VALIDATIONINFORMATION_HARDWAREID_LENGTH];
	DWORD HardwareIDLength;
} WTS_VALIDATION_INFORMATIONA, *PWTS_VALIDATION_INFORMATIONA;

typedef struct
{
	PRODUCT_INFOW ProductInfo;
	BYTE License[VALIDATIONINFORMATION_LICENSE_LENGTH];
	DWORD LicenseLength;
	BYTE HardwareID[VALIDATIONINFORMATION_HARDWAREID_LENGTH];
	DWORD HardwareIDLength;
} WTS_VALIDATION_INFORMATIONW, *PWTS_VALIDATION_INFORMATIONW;

typedef struct
{
	DWORD AddressFamily;
	BYTE Address[20];
} WTS_CLIENT_ADDRESS, *PWTS_CLIENT_ADDRESS;

typedef struct
{
	DWORD HorizontalResolution;
	DWORD VerticalResolution;
	DWORD ColorDepth;
} WTS_CLIENT_DISPLAY, *PWTS_CLIENT_DISPLAY;

typedef enum
{
	WTSUserConfigInitialProgram,
	WTSUserConfigWorkingDirectory,
	WTSUserConfigfInheritInitialProgram,
	WTSUserConfigfAllowLogonTerminalServer,
	WTSUserConfigTimeoutSettingsConnections,
	WTSUserConfigTimeoutSettingsDisconnections,
	WTSUserConfigTimeoutSettingsIdle,
	WTSUserConfigfDeviceClientDrives,
	WTSUserConfigfDeviceClientPrinters,
	WTSUserConfigfDeviceClientDefaultPrinter,
	WTSUserConfigBrokenTimeoutSettings,
	WTSUserConfigReconnectSettings,
	WTSUserConfigModemCallbackSettings,
	WTSUserConfigModemCallbackPhoneNumber,
	WTSUserConfigShadowingSettings,
	WTSUserConfigTerminalServerProfilePath,
	WTSUserConfigTerminalServerHomeDir,
	WTSUserConfigTerminalServerHomeDirDrive,
	WTSUserConfigfTerminalServerRemoteHomeDir,
	WTSUserConfigUser
} WTS_CONFIG_CLASS;

typedef enum
{
	WTSUserConfigSourceSAM
} WTS_CONFIG_SOURCE;

typedef struct
{
	DWORD Source;
	DWORD InheritInitialProgram;
	DWORD AllowLogonTerminalServer;
	DWORD TimeoutSettingsConnections;
	DWORD TimeoutSettingsDisconnections;
	DWORD TimeoutSettingsIdle;
	DWORD DeviceClientDrives;
	DWORD DeviceClientPrinters;
	DWORD ClientDefaultPrinter;
	DWORD BrokenTimeoutSettings;
	DWORD ReconnectSettings;
	DWORD ShadowingSettings;
	DWORD TerminalServerRemoteHomeDir;
	CHAR InitialProgram[MAX_PATH + 1];
	CHAR WorkDirectory[MAX_PATH + 1];
	CHAR TerminalServerProfilePath[MAX_PATH + 1];
	CHAR TerminalServerHomeDir[MAX_PATH + 1];
	CHAR TerminalServerHomeDirDrive[WTS_DRIVE_LENGTH + 1];
} WTSUSERCONFIGA, *PWTSUSERCONFIGA;

typedef struct
{
	DWORD Source;
	DWORD InheritInitialProgram;
	DWORD AllowLogonTerminalServer;
	DWORD TimeoutSettingsConnections;
	DWORD TimeoutSettingsDisconnections;
	DWORD TimeoutSettingsIdle;
	DWORD DeviceClientDrives;
	DWORD DeviceClientPrinters;
	DWORD ClientDefaultPrinter;
	DWORD BrokenTimeoutSettings;
	DWORD ReconnectSettings;
	DWORD ShadowingSettings;
	DWORD TerminalServerRemoteHomeDir;
	WCHAR InitialProgram[MAX_PATH + 1];
	WCHAR WorkDirectory[MAX_PATH + 1];
	WCHAR TerminalServerProfilePath[MAX_PATH + 1];
	WCHAR TerminalServerHomeDir[MAX_PATH + 1];
	WCHAR TerminalServerHomeDirDrive[WTS_DRIVE_LENGTH + 1];
} WTSUSERCONFIGW, *PWTSUSERCONFIGW;

#define WTS_EVENT_NONE 0x00000000
#define WTS_EVENT_CREATE 0x00000001
#define WTS_EVENT_DELETE 0x00000002
#define WTS_EVENT_RENAME 0x00000004
#define WTS_EVENT_CONNECT 0x00000008
#define WTS_EVENT_DISCONNECT 0x00000010
#define WTS_EVENT_LOGON 0x00000020
#define WTS_EVENT_LOGOFF 0x00000040
#define WTS_EVENT_STATECHANGE 0x00000080
#define WTS_EVENT_LICENSE 0x00000100
#define WTS_EVENT_ALL 0x7FFFFFFF
#define WTS_EVENT_FLUSH 0x80000000

#define REMOTECONTROL_KBDSHIFT_HOTKEY 0x1
#define REMOTECONTROL_KBDCTRL_HOTKEY 0x2
#define REMOTECONTROL_KBDALT_HOTKEY 0x4

typedef enum
{
	WTSVirtualClientData,
	WTSVirtualFileHandle,
	WTSVirtualEventHandle,      /* Extended */
	WTSVirtualChannelReady,     /* Extended */
	WTSVirtualChannelOpenStatus /* Extended */
} WTS_VIRTUAL_CLASS;

typedef struct
{
	DWORD AddressFamily;
	BYTE Address[20];
} WTS_SESSION_ADDRESS, *PWTS_SESSION_ADDRESS;

#define WTS_CHANNEL_OPTION_DYNAMIC 0x00000001
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_LOW 0x00000000
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_MED 0x00000002
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_HIGH 0x00000004
#define WTS_CHANNEL_OPTION_DYNAMIC_PRI_REAL 0x00000006
#define WTS_CHANNEL_OPTION_DYNAMIC_NO_COMPRESS 0x00000008

#define NOTIFY_FOR_ALL_SESSIONS 1
#define NOTIFY_FOR_THIS_SESSION 0

#define WTS_PROCESS_INFO_LEVEL_0 0
#define WTS_PROCESS_INFO_LEVEL_1 1

typedef struct
{
	DWORD SessionId;
	DWORD ProcessId;
	LPWSTR pProcessName;
	PSID pUserSid;
	DWORD NumberOfThreads;
	DWORD HandleCount;
	DWORD PagefileUsage;
	DWORD PeakPagefileUsage;
	DWORD WorkingSetSize;
	DWORD PeakWorkingSetSize;
	LARGE_INTEGER UserTime;
	LARGE_INTEGER KernelTime;
} WTS_PROCESS_INFO_EXW, *PWTS_PROCESS_INFO_EXW;

typedef struct
{
	DWORD SessionId;
	DWORD ProcessId;
	LPSTR pProcessName;
	PSID pUserSid;
	DWORD NumberOfThreads;
	DWORD HandleCount;
	DWORD PagefileUsage;
	DWORD PeakPagefileUsage;
	DWORD WorkingSetSize;
	DWORD PeakWorkingSetSize;
	LARGE_INTEGER UserTime;
	LARGE_INTEGER KernelTime;
} WTS_PROCESS_INFO_EXA, *PWTS_PROCESS_INFO_EXA;

typedef enum
{
	WTSTypeProcessInfoLevel0,
	WTSTypeProcessInfoLevel1,
	WTSTypeSessionInfoLevel1
} WTS_TYPE_CLASS;

typedef WCHAR WTSLISTENERNAMEW[WTS_LISTENER_NAME_LENGTH + 1];
typedef WTSLISTENERNAMEW* PWTSLISTENERNAMEW;
typedef CHAR WTSLISTENERNAMEA[WTS_LISTENER_NAME_LENGTH + 1];
typedef WTSLISTENERNAMEA* PWTSLISTENERNAMEA;

typedef struct
{
	ULONG version;
	ULONG fEnableListener;
	ULONG MaxConnectionCount;
	ULONG fPromptForPassword;
	ULONG fInheritColorDepth;
	ULONG ColorDepth;
	ULONG fInheritBrokenTimeoutSettings;
	ULONG BrokenTimeoutSettings;
	ULONG fDisablePrinterRedirection;
	ULONG fDisableDriveRedirection;
	ULONG fDisableComPortRedirection;
	ULONG fDisableLPTPortRedirection;
	ULONG fDisableClipboardRedirection;
	ULONG fDisableAudioRedirection;
	ULONG fDisablePNPRedirection;
	ULONG fDisableDefaultMainClientPrinter;
	ULONG LanAdapter;
	ULONG PortNumber;
	ULONG fInheritShadowSettings;
	ULONG ShadowSettings;
	ULONG TimeoutSettingsConnection;
	ULONG TimeoutSettingsDisconnection;
	ULONG TimeoutSettingsIdle;
	ULONG SecurityLayer;
	ULONG MinEncryptionLevel;
	ULONG UserAuthentication;
	WCHAR Comment[WTS_COMMENT_LENGTH + 1];
	WCHAR LogonUserName[USERNAME_LENGTH + 1];
	WCHAR LogonDomain[DOMAIN_LENGTH + 1];
	WCHAR WorkDirectory[MAX_PATH + 1];
	WCHAR InitialProgram[MAX_PATH + 1];
} WTSLISTENERCONFIGW, *PWTSLISTENERCONFIGW;

typedef struct
{
	ULONG version;
	ULONG fEnableListener;
	ULONG MaxConnectionCount;
	ULONG fPromptForPassword;
	ULONG fInheritColorDepth;
	ULONG ColorDepth;
	ULONG fInheritBrokenTimeoutSettings;
	ULONG BrokenTimeoutSettings;
	ULONG fDisablePrinterRedirection;
	ULONG fDisableDriveRedirection;
	ULONG fDisableComPortRedirection;
	ULONG fDisableLPTPortRedirection;
	ULONG fDisableClipboardRedirection;
	ULONG fDisableAudioRedirection;
	ULONG fDisablePNPRedirection;
	ULONG fDisableDefaultMainClientPrinter;
	ULONG LanAdapter;
	ULONG PortNumber;
	ULONG fInheritShadowSettings;
	ULONG ShadowSettings;
	ULONG TimeoutSettingsConnection;
	ULONG TimeoutSettingsDisconnection;
	ULONG TimeoutSettingsIdle;
	ULONG SecurityLayer;
	ULONG MinEncryptionLevel;
	ULONG UserAuthentication;
	CHAR Comment[WTS_COMMENT_LENGTH + 1];
	CHAR LogonUserName[USERNAME_LENGTH + 1];
	CHAR LogonDomain[DOMAIN_LENGTH + 1];
	CHAR WorkDirectory[MAX_PATH + 1];
	CHAR InitialProgram[MAX_PATH + 1];
} WTSLISTENERCONFIGA, *PWTSLISTENERCONFIGA;

#ifdef UNICODE
#define WTS_SERVER_INFO WTS_SERVER_INFOW
#define PWTS_SERVER_INFO PWTS_SERVER_INFOW
#define WTS_SESSION_INFO WTS_SESSION_INFOW
#define PWTS_SESSION_INFO PWTS_SESSION_INFOW
#define WTS_SESSION_INFO_1 WTS_SESSION_INFO_1W
#define PWTS_SESSION_INFO_1 PWTS_SESSION_INFO_1W
#define WTS_PROCESS_INFO WTS_PROCESS_INFOW
#define PWTS_PROCESS_INFO PWTS_PROCESS_INFOW
#define WTSCONFIGINFO WTSCONFIGINFOW
#define PWTSCONFIGINFO PWTSCONFIGINFOW
#define WTSINFO WTSINFOW
#define PWTSINFO PWTSINFOW
#define WTSINFOEX WTSINFOEXW
#define PWTSINFOEX PWTSINFOEXW
#define WTSINFOEX_LEVEL WTSINFOEX_LEVEL_W
#define PWTSINFOEX_LEVEL PWTSINFOEX_LEVEL_W
#define WTSINFOEX_LEVEL1 WTSINFOEX_LEVEL1_W
#define PWTSINFOEX_LEVEL1 PWTSINFOEX_LEVEL1_W
#define WTSCLIENT WTSCLIENTW
#define PWTSCLIENT PWTSCLIENTW
#define PRODUCT_INFO PRODUCT_INFOW
#define WTS_VALIDATION_INFORMATION WTS_VALIDATION_INFORMATIONW
#define PWTS_VALIDATION_INFORMATION PWTS_VALIDATION_INFORMATIONW
#define WTSUSERCONFIG WTSUSERCONFIGW
#define PWTSUSERCONFIG PWTSUSERCONFIGW
#define WTS_PROCESS_INFO_EX WTS_PROCESS_INFO_EXW
#define PWTS_PROCESS_INFO_EX PWTS_PROCESS_INFO_EXW
#define WTSLISTENERNAME WTSLISTENERNAMEW
#define PWTSLISTENERNAME PWTSLISTENERNAMEW
#define WTSLISTENERCONFIG WTSLISTENERCONFIGW
#define PWTSLISTENERCONFIG PWTSLISTENERCONFIGW
#else
#define WTS_SERVER_INFO WTS_SERVER_INFOA
#define PWTS_SERVER_INFO PWTS_SERVER_INFOA
#define WTS_SESSION_INFO WTS_SESSION_INFOA
#define PWTS_SESSION_INFO PWTS_SESSION_INFOA
#define WTS_SESSION_INFO_1 WTS_SESSION_INFO_1A
#define PWTS_SESSION_INFO_1 PWTS_SESSION_INFO_1A
#define WTS_PROCESS_INFO WTS_PROCESS_INFOA
#define PWTS_PROCESS_INFO PWTS_PROCESS_INFOA
#define WTSCONFIGINFO WTSCONFIGINFOA
#define PWTSCONFIGINFO PWTSCONFIGINFOA
#define WTSINFO WTSINFOA
#define PWTSINFO PWTSINFOA
#define WTSINFOEX WTSINFOEXA
#define PWTSINFOEX PWTSINFOEXA
#define WTSINFOEX_LEVEL WTSINFOEX_LEVEL_A
#define PWTSINFOEX_LEVEL PWTSINFOEX_LEVEL_A
#define WTSINFOEX_LEVEL1 WTSINFOEX_LEVEL1_A
#define PWTSINFOEX_LEVEL1 PWTSINFOEX_LEVEL1_A
#define WTSCLIENT WTSCLIENTA
#define PWTSCLIENT PWTSCLIENTA
#define PRODUCT_INFO PRODUCT_INFOA
#define WTS_VALIDATION_INFORMATION WTS_VALIDATION_INFORMATIONA
#define PWTS_VALIDATION_INFORMATION PWTS_VALIDATION_INFORMATIONA
#define WTSUSERCONFIG WTSUSERCONFIGA
#define PWTSUSERCONFIG PWTSUSERCONFIGA
#define WTS_PROCESS_INFO_EX WTS_PROCESS_INFO_EXA
#define PWTS_PROCESS_INFO_EX PWTS_PROCESS_INFO_EXA
#define WTSLISTENERNAME WTSLISTENERNAMEA
#define PWTSLISTENERNAME PWTSLISTENERNAMEA
#define WTSLISTENERCONFIG WTSLISTENERCONFIGA
#define PWTSLISTENERCONFIG PWTSLISTENERCONFIGA
#endif

#define REMOTECONTROL_FLAG_DISABLE_KEYBOARD 0x00000001
#define REMOTECONTROL_FLAG_DISABLE_MOUSE 0x00000002
#define REMOTECONTROL_FLAG_DISABLE_INPUT \
	REMOTECONTROL_FLAG_DISABLE_KEYBOARD | REMOTECONTROL_FLAG_DISABLE_MOUSE

#ifdef __cplusplus
extern "C"
{
#endif

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSStopRemoteControlSession(ULONG LogonId);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSStartRemoteControlSessionW(LPWSTR pTargetServerName,
	                                                    ULONG TargetLogonId, BYTE HotkeyVk,
	                                                    USHORT HotkeyModifiers);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSStartRemoteControlSessionA(LPSTR pTargetServerName,
	                                                    ULONG TargetLogonId, BYTE HotkeyVk,
	                                                    USHORT HotkeyModifiers);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSStartRemoteControlSessionExW(LPWSTR pTargetServerName,
	                                                      ULONG TargetLogonId, BYTE HotkeyVk,
	                                                      USHORT HotkeyModifiers, DWORD flags);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSStartRemoteControlSessionExA(LPSTR pTargetServerName,
	                                                      ULONG TargetLogonId, BYTE HotkeyVk,
	                                                      USHORT HotkeyModifiers, DWORD flags);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSConnectSessionW(ULONG LogonId, ULONG TargetLogonId, PWSTR pPassword,
	                                         BOOL bWait);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSConnectSessionA(ULONG LogonId, ULONG TargetLogonId, PSTR pPassword,
	                                         BOOL bWait);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSEnumerateServersW(LPWSTR pDomainName, DWORD Reserved, DWORD Version,
	                                           PWTS_SERVER_INFOW* ppServerInfo, DWORD* pCount);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSEnumerateServersA(LPSTR pDomainName, DWORD Reserved, DWORD Version,
	                                           PWTS_SERVER_INFOA* ppServerInfo, DWORD* pCount);

	WINPR_API VOID WINAPI WTSCloseServer(HANDLE hServer);

	WINPR_ATTR_MALLOC(WTSCloseServer, 1)
	WINPR_API HANDLE WINAPI WTSOpenServerW(LPWSTR pServerName);

	WINPR_ATTR_MALLOC(WTSCloseServer, 1)
	WINPR_API HANDLE WINAPI WTSOpenServerA(LPSTR pServerName);

	WINPR_ATTR_MALLOC(WTSCloseServer, 1)
	WINPR_API HANDLE WINAPI WTSOpenServerExW(LPWSTR pServerName);

	WINPR_ATTR_MALLOC(WTSCloseServer, 1)
	WINPR_API HANDLE WINAPI WTSOpenServerExA(LPSTR pServerName);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSEnumerateSessionsW(HANDLE hServer, DWORD Reserved, DWORD Version,
	                                            PWTS_SESSION_INFOW* ppSessionInfo, DWORD* pCount);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSEnumerateSessionsA(HANDLE hServer, DWORD Reserved, DWORD Version,
	                                            PWTS_SESSION_INFOA* ppSessionInfo, DWORD* pCount);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSEnumerateSessionsExW(HANDLE hServer, DWORD* pLevel, DWORD Filter,
	                                              PWTS_SESSION_INFO_1W* ppSessionInfo,
	                                              DWORD* pCount);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSEnumerateSessionsExA(HANDLE hServer, DWORD* pLevel, DWORD Filter,
	                                              PWTS_SESSION_INFO_1A* ppSessionInfo,
	                                              DWORD* pCount);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSEnumerateProcessesW(HANDLE hServer, DWORD Reserved, DWORD Version,
	                                             PWTS_PROCESS_INFOW* ppProcessInfo, DWORD* pCount);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSEnumerateProcessesA(HANDLE hServer, DWORD Reserved, DWORD Version,
	                                             PWTS_PROCESS_INFOA* ppProcessInfo, DWORD* pCount);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSTerminateProcess(HANDLE hServer, DWORD ProcessId, DWORD ExitCode);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSQuerySessionInformationW(HANDLE hServer, DWORD SessionId,
	                                                  WTS_INFO_CLASS WTSInfoClass, LPWSTR* ppBuffer,
	                                                  DWORD* pBytesReturned);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSQuerySessionInformationA(HANDLE hServer, DWORD SessionId,
	                                                  WTS_INFO_CLASS WTSInfoClass, LPSTR* ppBuffer,
	                                                  DWORD* pBytesReturned);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSQueryUserConfigW(LPWSTR pServerName, LPWSTR pUserName,
	                                          WTS_CONFIG_CLASS WTSConfigClass, LPWSTR* ppBuffer,
	                                          DWORD* pBytesReturned);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSQueryUserConfigA(LPSTR pServerName, LPSTR pUserName,
	                                          WTS_CONFIG_CLASS WTSConfigClass, LPSTR* ppBuffer,
	                                          DWORD* pBytesReturned);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSSetUserConfigW(LPWSTR pServerName, LPWSTR pUserName,
	                                        WTS_CONFIG_CLASS WTSConfigClass, LPWSTR pBuffer,
	                                        DWORD DataLength);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSSetUserConfigA(LPSTR pServerName, LPSTR pUserName,
	                                        WTS_CONFIG_CLASS WTSConfigClass, LPSTR pBuffer,
	                                        DWORD DataLength);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSSendMessageW(HANDLE hServer, DWORD SessionId, LPWSTR pTitle,
	                                      DWORD TitleLength, LPWSTR pMessage, DWORD MessageLength,
	                                      DWORD Style, DWORD Timeout, DWORD* pResponse, BOOL bWait);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSSendMessageA(HANDLE hServer, DWORD SessionId, LPSTR pTitle,
	                                      DWORD TitleLength, LPSTR pMessage, DWORD MessageLength,
	                                      DWORD Style, DWORD Timeout, DWORD* pResponse, BOOL bWait);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSDisconnectSession(HANDLE hServer, DWORD SessionId, BOOL bWait);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSLogoffSession(HANDLE hServer, DWORD SessionId, BOOL bWait);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSShutdownSystem(HANDLE hServer, DWORD ShutdownFlag);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSWaitSystemEvent(HANDLE hServer, DWORD EventMask, DWORD* pEventFlags);

	WINPR_API BOOL WINAPI WTSVirtualChannelClose(HANDLE hChannelHandle);

	WINPR_ATTR_MALLOC(WTSVirtualChannelClose, 1)
	WINPR_API HANDLE WINAPI WTSVirtualChannelOpen(HANDLE hServer, DWORD SessionId,
	                                              LPSTR pVirtualName);

	WINPR_ATTR_MALLOC(WTSVirtualChannelClose, 1)
	WINPR_API HANDLE WINAPI WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualName,
	                                                DWORD flags);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSVirtualChannelRead(HANDLE hChannelHandle, ULONG TimeOut, PCHAR Buffer,
	                                            ULONG BufferSize, PULONG pBytesRead);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSVirtualChannelWrite(HANDLE hChannelHandle, PCHAR Buffer, ULONG Length,
	                                             PULONG pBytesWritten);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSVirtualChannelPurgeInput(HANDLE hChannelHandle);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSVirtualChannelPurgeOutput(HANDLE hChannelHandle);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSVirtualChannelQuery(HANDLE hChannelHandle,
	                                             WTS_VIRTUAL_CLASS WtsVirtualClass, PVOID* ppBuffer,
	                                             DWORD* pBytesReturned);

	WINPR_API VOID WINAPI WTSFreeMemory(PVOID pMemory);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSRegisterSessionNotification(HWND hWnd, DWORD dwFlags);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSUnRegisterSessionNotification(HWND hWnd);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSRegisterSessionNotificationEx(HANDLE hServer, HWND hWnd,
	                                                       DWORD dwFlags);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSUnRegisterSessionNotificationEx(HANDLE hServer, HWND hWnd);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSQueryUserToken(ULONG SessionId, PHANDLE phToken);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSFreeMemoryExW(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory,
	                                       ULONG NumberOfEntries);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSFreeMemoryExA(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory,
	                                       ULONG NumberOfEntries);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSEnumerateProcessesExW(HANDLE hServer, DWORD* pLevel, DWORD SessionId,
	                                               LPWSTR* ppProcessInfo, DWORD* pCount);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSEnumerateProcessesExA(HANDLE hServer, DWORD* pLevel, DWORD SessionId,
	                                               LPSTR* ppProcessInfo, DWORD* pCount);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSEnumerateListenersW(HANDLE hServer, PVOID pReserved, DWORD Reserved,
	                                             PWTSLISTENERNAMEW pListeners, DWORD* pCount);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSEnumerateListenersA(HANDLE hServer, PVOID pReserved, DWORD Reserved,
	                                             PWTSLISTENERNAMEA pListeners, DWORD* pCount);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSQueryListenerConfigW(HANDLE hServer, PVOID pReserved, DWORD Reserved,
	                                              LPWSTR pListenerName,
	                                              PWTSLISTENERCONFIGW pBuffer);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSQueryListenerConfigA(HANDLE hServer, PVOID pReserved, DWORD Reserved,
	                                              LPSTR pListenerName, PWTSLISTENERCONFIGA pBuffer);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSCreateListenerW(HANDLE hServer, PVOID pReserved, DWORD Reserved,
	                                         LPWSTR pListenerName, PWTSLISTENERCONFIGW pBuffer,
	                                         DWORD flag);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSCreateListenerA(HANDLE hServer, PVOID pReserved, DWORD Reserved,
	                                         LPSTR pListenerName, PWTSLISTENERCONFIGA pBuffer,
	                                         DWORD flag);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSSetListenerSecurityW(HANDLE hServer, PVOID pReserved, DWORD Reserved,
	                                              LPWSTR pListenerName,
	                                              SECURITY_INFORMATION SecurityInformation,
	                                              PSECURITY_DESCRIPTOR pSecurityDescriptor);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSSetListenerSecurityA(HANDLE hServer, PVOID pReserved, DWORD Reserved,
	                                              LPSTR pListenerName,
	                                              SECURITY_INFORMATION SecurityInformation,
	                                              PSECURITY_DESCRIPTOR pSecurityDescriptor);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSGetListenerSecurityW(HANDLE hServer, PVOID pReserved, DWORD Reserved,
	                                              LPWSTR pListenerName,
	                                              SECURITY_INFORMATION SecurityInformation,
	                                              PSECURITY_DESCRIPTOR pSecurityDescriptor,
	                                              DWORD nLength, LPDWORD lpnLengthNeeded);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WINAPI WTSGetListenerSecurityA(HANDLE hServer, PVOID pReserved, DWORD Reserved,
	                                              LPSTR pListenerName,
	                                              SECURITY_INFORMATION SecurityInformation,
	                                              PSECURITY_DESCRIPTOR pSecurityDescriptor,
	                                              DWORD nLength, LPDWORD lpnLengthNeeded);

	/**
	 * WTSEnableChildSessions, WTSIsChildSessionsEnabled and WTSGetChildSessionId
	 * are not explicitly declared as WINAPI like other WTSAPI functions.
	 * Since they are declared as extern "C", we explicitly declare them as CDECL.
	 */

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL CDECL WTSEnableChildSessions(BOOL bEnable);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL CDECL WTSIsChildSessionsEnabled(PBOOL pbEnabled);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL CDECL WTSGetChildSessionId(PULONG pSessionId);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL CDECL WTSLogonUser(HANDLE hServer, LPCSTR username, LPCSTR password,
	                                  LPCSTR domain);

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL CDECL WTSLogoffUser(HANDLE hServer);

#ifdef __cplusplus
}
#endif

#ifdef UNICODE
#define WTSStartRemoteControlSession WTSStartRemoteControlSessionW
#define WTSStartRemoteControlSessionEx WTSStartRemoteControlSessionExW
#define WTSConnectSession WTSConnectSessionW
#define WTSEnumerateServers WTSEnumerateServersW
#define WTSOpenServer WTSOpenServerW
#define WTSOpenServerEx WTSOpenServerExW
#define WTSEnumerateSessions WTSEnumerateSessionsW
#define WTSEnumerateSessionsEx WTSEnumerateSessionsExW
#define WTSEnumerateProcesses WTSEnumerateProcessesW
#define WTSQuerySessionInformation WTSQuerySessionInformationW
#define WTSQueryUserConfig WTSQueryUserConfigW
#define WTSSetUserConfig WTSSetUserConfigW
#define WTSSendMessage WTSSendMessageW
#define WTSFreeMemoryEx WTSFreeMemoryExW
#define WTSEnumerateProcessesEx WTSEnumerateProcessesExW
#define WTSEnumerateListeners WTSEnumerateListenersW
#define WTSQueryListenerConfig WTSQueryListenerConfigW
#define WTSCreateListener WTSCreateListenerW
#define WTSSetListenerSecurity WTSSetListenerSecurityW
#define WTSGetListenerSecurity WTSGetListenerSecurityW
#else
#define WTSStartRemoteControlSession WTSStartRemoteControlSessionA
#define WTSStartRemoteControlSessionEx WTSStartRemoteControlSessionExA
#define WTSConnectSession WTSConnectSessionA
#define WTSEnumerateServers WTSEnumerateServersA
#define WTSOpenServer WTSOpenServerA
#define WTSOpenServerEx WTSOpenServerExA
#define WTSEnumerateSessions WTSEnumerateSessionsA
#define WTSEnumerateSessionsEx WTSEnumerateSessionsExA
#define WTSEnumerateProcesses WTSEnumerateProcessesA
#define WTSQuerySessionInformation WTSQuerySessionInformationA
#define WTSQueryUserConfig WTSQueryUserConfigA
#define WTSSetUserConfig WTSSetUserConfigA
#define WTSSendMessage WTSSendMessageA
#define WTSFreeMemoryEx WTSFreeMemoryExA
#define WTSEnumerateProcessesEx WTSEnumerateProcessesExA
#define WTSEnumerateListeners WTSEnumerateListenersA
#define WTSQueryListenerConfig WTSQueryListenerConfigA
#define WTSCreateListener WTSCreateListenerA
#define WTSSetListenerSecurity WTSSetListenerSecurityA
#define WTSGetListenerSecurity WTSGetListenerSecurityA
#endif

#endif

#ifndef _WIN32

/**
 * WTSGetActiveConsoleSessionId is declared in WinBase.h
 * and exported by kernel32.dll, so we have to treat it separately.
 */

WINPR_ATTR_NODISCARD
WINPR_API DWORD WINAPI WTSGetActiveConsoleSessionId(void);

#endif

typedef BOOL(WINAPI* WTS_STOP_REMOTE_CONTROL_SESSION_FN)(ULONG LogonId);

typedef BOOL(WINAPI* WTS_START_REMOTE_CONTROL_SESSION_FN_W)(LPWSTR pTargetServerName,
                                                            ULONG TargetLogonId, BYTE HotkeyVk,
                                                            USHORT HotkeyModifiers);
typedef BOOL(WINAPI* WTS_START_REMOTE_CONTROL_SESSION_FN_A)(LPSTR pTargetServerName,
                                                            ULONG TargetLogonId, BYTE HotkeyVk,
                                                            USHORT HotkeyModifiers);

typedef BOOL(WINAPI* WTS_START_REMOTE_CONTROL_SESSION_EX_FN_W)(LPWSTR pTargetServerName,
                                                               ULONG TargetLogonId, BYTE HotkeyVk,
                                                               USHORT HotkeyModifiers, DWORD flags);
typedef BOOL(WINAPI* WTS_START_REMOTE_CONTROL_SESSION_EX_FN_A)(LPSTR pTargetServerName,
                                                               ULONG TargetLogonId, BYTE HotkeyVk,
                                                               USHORT HotkeyModifiers, DWORD flags);

typedef BOOL(WINAPI* WTS_CONNECT_SESSION_FN_W)(ULONG LogonId, ULONG TargetLogonId, PWSTR pPassword,
                                               BOOL bWait);
typedef BOOL(WINAPI* WTS_CONNECT_SESSION_FN_A)(ULONG LogonId, ULONG TargetLogonId, PSTR pPassword,
                                               BOOL bWait);

typedef BOOL(WINAPI* WTS_ENUMERATE_SERVERS_FN_W)(LPWSTR pDomainName, DWORD Reserved, DWORD Version,
                                                 PWTS_SERVER_INFOW* ppServerInfo, DWORD* pCount);
typedef BOOL(WINAPI* WTS_ENUMERATE_SERVERS_FN_A)(LPSTR pDomainName, DWORD Reserved, DWORD Version,
                                                 PWTS_SERVER_INFOA* ppServerInfo, DWORD* pCount);

typedef HANDLE(WINAPI* WTS_OPEN_SERVER_FN_W)(LPWSTR pServerName);
typedef HANDLE(WINAPI* WTS_OPEN_SERVER_FN_A)(LPSTR pServerName);

typedef HANDLE(WINAPI* WTS_OPEN_SERVER_EX_FN_W)(LPWSTR pServerName);
typedef HANDLE(WINAPI* WTS_OPEN_SERVER_EX_FN_A)(LPSTR pServerName);

typedef VOID(WINAPI* WTS_CLOSE_SERVER_FN)(HANDLE hServer);

typedef BOOL(WINAPI* WTS_ENUMERATE_SESSIONS_FN_W)(HANDLE hServer, DWORD Reserved, DWORD Version,
                                                  PWTS_SESSION_INFOW* ppSessionInfo, DWORD* pCount);
typedef BOOL(WINAPI* WTS_ENUMERATE_SESSIONS_FN_A)(HANDLE hServer, DWORD Reserved, DWORD Version,
                                                  PWTS_SESSION_INFOA* ppSessionInfo, DWORD* pCount);

typedef BOOL(WINAPI* WTS_ENUMERATE_SESSIONS_EX_FN_W)(HANDLE hServer, DWORD* pLevel, DWORD Filter,
                                                     PWTS_SESSION_INFO_1W* ppSessionInfo,
                                                     DWORD* pCount);
typedef BOOL(WINAPI* WTS_ENUMERATE_SESSIONS_EX_FN_A)(HANDLE hServer, DWORD* pLevel, DWORD Filter,
                                                     PWTS_SESSION_INFO_1A* ppSessionInfo,
                                                     DWORD* pCount);

typedef BOOL(WINAPI* WTS_ENUMERATE_PROCESSES_FN_W)(HANDLE hServer, DWORD Reserved, DWORD Version,
                                                   PWTS_PROCESS_INFOW* ppProcessInfo,
                                                   DWORD* pCount);
typedef BOOL(WINAPI* WTS_ENUMERATE_PROCESSES_FN_A)(HANDLE hServer, DWORD Reserved, DWORD Version,
                                                   PWTS_PROCESS_INFOA* ppProcessInfo,
                                                   DWORD* pCount);

typedef BOOL(WINAPI* WTS_TERMINATE_PROCESS_FN)(HANDLE hServer, DWORD ProcessId, DWORD ExitCode);

typedef BOOL(WINAPI* WTS_QUERY_SESSION_INFORMATION_FN_W)(HANDLE hServer, DWORD SessionId,
                                                         WTS_INFO_CLASS WTSInfoClass,
                                                         LPWSTR* ppBuffer, DWORD* pBytesReturned);
typedef BOOL(WINAPI* WTS_QUERY_SESSION_INFORMATION_FN_A)(HANDLE hServer, DWORD SessionId,
                                                         WTS_INFO_CLASS WTSInfoClass,
                                                         LPSTR* ppBuffer, DWORD* pBytesReturned);

typedef BOOL(WINAPI* WTS_QUERY_USER_CONFIG_FN_W)(LPWSTR pServerName, LPWSTR pUserName,
                                                 WTS_CONFIG_CLASS WTSConfigClass, LPWSTR* ppBuffer,
                                                 DWORD* pBytesReturned);
typedef BOOL(WINAPI* WTS_QUERY_USER_CONFIG_FN_A)(LPSTR pServerName, LPSTR pUserName,
                                                 WTS_CONFIG_CLASS WTSConfigClass, LPSTR* ppBuffer,
                                                 DWORD* pBytesReturned);

typedef BOOL(WINAPI* WTS_SET_USER_CONFIG_FN_W)(LPWSTR pServerName, LPWSTR pUserName,
                                               WTS_CONFIG_CLASS WTSConfigClass, LPWSTR pBuffer,
                                               DWORD DataLength);
typedef BOOL(WINAPI* WTS_SET_USER_CONFIG_FN_A)(LPSTR pServerName, LPSTR pUserName,
                                               WTS_CONFIG_CLASS WTSConfigClass, LPSTR pBuffer,
                                               DWORD DataLength);

typedef BOOL(WINAPI* WTS_SEND_MESSAGE_FN_W)(HANDLE hServer, DWORD SessionId, LPWSTR pTitle,
                                            DWORD TitleLength, LPWSTR pMessage, DWORD MessageLength,
                                            DWORD Style, DWORD Timeout, DWORD* pResponse,
                                            BOOL bWait);
typedef BOOL(WINAPI* WTS_SEND_MESSAGE_FN_A)(HANDLE hServer, DWORD SessionId, LPSTR pTitle,
                                            DWORD TitleLength, LPSTR pMessage, DWORD MessageLength,
                                            DWORD Style, DWORD Timeout, DWORD* pResponse,
                                            BOOL bWait);

typedef BOOL(WINAPI* WTS_DISCONNECT_SESSION_FN)(HANDLE hServer, DWORD SessionId, BOOL bWait);

typedef BOOL(WINAPI* WTS_LOGOFF_SESSION_FN)(HANDLE hServer, DWORD SessionId, BOOL bWait);

typedef BOOL(WINAPI* WTS_SHUTDOWN_SYSTEM_FN)(HANDLE hServer, DWORD ShutdownFlag);

typedef BOOL(WINAPI* WTS_WAIT_SYSTEM_EVENT_FN)(HANDLE hServer, DWORD EventMask, DWORD* pEventFlags);

typedef HANDLE(WINAPI* WTS_VIRTUAL_CHANNEL_OPEN_FN)(HANDLE hServer, DWORD SessionId,
                                                    LPSTR pVirtualName);

typedef HANDLE(WINAPI* WTS_VIRTUAL_CHANNEL_OPEN_EX_FN)(DWORD SessionId, LPSTR pVirtualName,
                                                       DWORD flags);

typedef BOOL(WINAPI* WTS_VIRTUAL_CHANNEL_CLOSE_FN)(HANDLE hChannelHandle);

typedef BOOL(WINAPI* WTS_VIRTUAL_CHANNEL_READ_FN)(HANDLE hChannelHandle, ULONG TimeOut,
                                                  PCHAR Buffer, ULONG BufferSize,
                                                  PULONG pBytesRead);

typedef BOOL(WINAPI* WTS_VIRTUAL_CHANNEL_WRITE_FN)(HANDLE hChannelHandle, PCHAR Buffer,
                                                   ULONG Length, PULONG pBytesWritten);

typedef BOOL(WINAPI* WTS_VIRTUAL_CHANNEL_PURGE_INPUT_FN)(HANDLE hChannelHandle);

typedef BOOL(WINAPI* WTS_VIRTUAL_CHANNEL_PURGE_OUTPUT_FN)(HANDLE hChannelHandle);

typedef BOOL(WINAPI* WTS_VIRTUAL_CHANNEL_QUERY_FN)(HANDLE hChannelHandle,
                                                   WTS_VIRTUAL_CLASS WtsVirtualClass,
                                                   PVOID* ppBuffer, DWORD* pBytesReturned);

typedef VOID(WINAPI* WTS_FREE_MEMORY_FN)(PVOID pMemory);

typedef BOOL(WINAPI* WTS_REGISTER_SESSION_NOTIFICATION_FN)(HWND hWnd, DWORD dwFlags);

typedef BOOL(WINAPI* WTS_UNREGISTER_SESSION_NOTIFICATION_FN)(HWND hWnd);

typedef BOOL(WINAPI* WTS_REGISTER_SESSION_NOTIFICATION_EX_FN)(HANDLE hServer, HWND hWnd,
                                                              DWORD dwFlags);

typedef BOOL(WINAPI* WTS_UNREGISTER_SESSION_NOTIFICATION_EX_FN)(HANDLE hServer, HWND hWnd);

typedef BOOL(WINAPI* WTS_QUERY_USER_TOKEN_FN)(ULONG SessionId, PHANDLE phToken);

typedef BOOL(WINAPI* WTS_FREE_MEMORY_EX_FN_W)(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory,
                                              ULONG NumberOfEntries);
typedef BOOL(WINAPI* WTS_FREE_MEMORY_EX_FN_A)(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory,
                                              ULONG NumberOfEntries);

typedef BOOL(WINAPI* WTS_ENUMERATE_PROCESSES_EX_FN_W)(HANDLE hServer, DWORD* pLevel,
                                                      DWORD SessionId, LPWSTR* ppProcessInfo,
                                                      DWORD* pCount);
typedef BOOL(WINAPI* WTS_ENUMERATE_PROCESSES_EX_FN_A)(HANDLE hServer, DWORD* pLevel,
                                                      DWORD SessionId, LPSTR* ppProcessInfo,
                                                      DWORD* pCount);

typedef BOOL(WINAPI* WTS_ENUMERATE_LISTENERS_FN_W)(HANDLE hServer, PVOID pReserved, DWORD Reserved,
                                                   PWTSLISTENERNAMEW pListeners, DWORD* pCount);
typedef BOOL(WINAPI* WTS_ENUMERATE_LISTENERS_FN_A)(HANDLE hServer, PVOID pReserved, DWORD Reserved,
                                                   PWTSLISTENERNAMEA pListeners, DWORD* pCount);

typedef BOOL(WINAPI* WTS_QUERY_LISTENER_CONFIG_FN_W)(HANDLE hServer, PVOID pReserved,
                                                     DWORD Reserved, LPWSTR pListenerName,
                                                     PWTSLISTENERCONFIGW pBuffer);
typedef BOOL(WINAPI* WTS_QUERY_LISTENER_CONFIG_FN_A)(HANDLE hServer, PVOID pReserved,
                                                     DWORD Reserved, LPSTR pListenerName,
                                                     PWTSLISTENERCONFIGA pBuffer);

typedef BOOL(WINAPI* WTS_CREATE_LISTENER_FN_W)(HANDLE hServer, PVOID pReserved, DWORD Reserved,
                                               LPWSTR pListenerName, PWTSLISTENERCONFIGW pBuffer,
                                               DWORD flag);
typedef BOOL(WINAPI* WTS_CREATE_LISTENER_FN_A)(HANDLE hServer, PVOID pReserved, DWORD Reserved,
                                               LPSTR pListenerName, PWTSLISTENERCONFIGA pBuffer,
                                               DWORD flag);

typedef BOOL(WINAPI* WTS_SET_LISTENER_SECURITY_FN_W)(HANDLE hServer, PVOID pReserved,
                                                     DWORD Reserved, LPWSTR pListenerName,
                                                     SECURITY_INFORMATION SecurityInformation,
                                                     PSECURITY_DESCRIPTOR pSecurityDescriptor);
typedef BOOL(WINAPI* WTS_SET_LISTENER_SECURITY_FN_A)(HANDLE hServer, PVOID pReserved,
                                                     DWORD Reserved, LPSTR pListenerName,
                                                     SECURITY_INFORMATION SecurityInformation,
                                                     PSECURITY_DESCRIPTOR pSecurityDescriptor);

typedef BOOL(WINAPI* WTS_GET_LISTENER_SECURITY_FN_W)(HANDLE hServer, PVOID pReserved,
                                                     DWORD Reserved, LPWSTR pListenerName,
                                                     SECURITY_INFORMATION SecurityInformation,
                                                     PSECURITY_DESCRIPTOR pSecurityDescriptor,
                                                     DWORD nLength, LPDWORD lpnLengthNeeded);
typedef BOOL(WINAPI* WTS_GET_LISTENER_SECURITY_FN_A)(HANDLE hServer, PVOID pReserved,
                                                     DWORD Reserved, LPSTR pListenerName,
                                                     SECURITY_INFORMATION SecurityInformation,
                                                     PSECURITY_DESCRIPTOR pSecurityDescriptor,
                                                     DWORD nLength, LPDWORD lpnLengthNeeded);

typedef BOOL(CDECL* WTS_ENABLE_CHILD_SESSIONS_FN)(BOOL bEnable);

typedef BOOL(CDECL* WTS_IS_CHILD_SESSIONS_ENABLED_FN)(PBOOL pbEnabled);

typedef BOOL(CDECL* WTS_GET_CHILD_SESSION_ID_FN)(PULONG pSessionId);

typedef DWORD(WINAPI* WTS_GET_ACTIVE_CONSOLE_SESSION_ID_FN)(void);

typedef BOOL(WINAPI* WTS_LOGON_USER_FN)(HANDLE hServer, LPCSTR username, LPCSTR password,
                                        LPCSTR domain);

typedef BOOL(WINAPI* WTS_LOGOFF_USER_FN)(HANDLE hServer);

typedef struct
{
	DWORD dwVersion;
	DWORD dwFlags;

	WINPR_ATTR_NODISCARD WTS_STOP_REMOTE_CONTROL_SESSION_FN pStopRemoteControlSession;
	WINPR_ATTR_NODISCARD WTS_START_REMOTE_CONTROL_SESSION_FN_W pStartRemoteControlSessionW;
	WINPR_ATTR_NODISCARD WTS_START_REMOTE_CONTROL_SESSION_FN_A pStartRemoteControlSessionA;
	WINPR_ATTR_NODISCARD WTS_CONNECT_SESSION_FN_W pConnectSessionW;
	WINPR_ATTR_NODISCARD WTS_CONNECT_SESSION_FN_A pConnectSessionA;
	WINPR_ATTR_NODISCARD WTS_ENUMERATE_SERVERS_FN_W pEnumerateServersW;
	WINPR_ATTR_NODISCARD WTS_ENUMERATE_SERVERS_FN_A pEnumerateServersA;
	WINPR_ATTR_NODISCARD WTS_OPEN_SERVER_FN_W pOpenServerW;
	WINPR_ATTR_NODISCARD WTS_OPEN_SERVER_FN_A pOpenServerA;
	WINPR_ATTR_NODISCARD WTS_OPEN_SERVER_EX_FN_W pOpenServerExW;
	WINPR_ATTR_NODISCARD WTS_OPEN_SERVER_EX_FN_A pOpenServerExA;
	WTS_CLOSE_SERVER_FN pCloseServer;
	WINPR_ATTR_NODISCARD WTS_ENUMERATE_SESSIONS_FN_W pEnumerateSessionsW;
	WINPR_ATTR_NODISCARD WTS_ENUMERATE_SESSIONS_FN_A pEnumerateSessionsA;
	WINPR_ATTR_NODISCARD WTS_ENUMERATE_SESSIONS_EX_FN_W pEnumerateSessionsExW;
	WINPR_ATTR_NODISCARD WTS_ENUMERATE_SESSIONS_EX_FN_A pEnumerateSessionsExA;
	WINPR_ATTR_NODISCARD WTS_ENUMERATE_PROCESSES_FN_W pEnumerateProcessesW;
	WINPR_ATTR_NODISCARD WTS_ENUMERATE_PROCESSES_FN_A pEnumerateProcessesA;
	WINPR_ATTR_NODISCARD WTS_TERMINATE_PROCESS_FN pTerminateProcess;
	WINPR_ATTR_NODISCARD WTS_QUERY_SESSION_INFORMATION_FN_W pQuerySessionInformationW;
	WINPR_ATTR_NODISCARD WTS_QUERY_SESSION_INFORMATION_FN_A pQuerySessionInformationA;
	WINPR_ATTR_NODISCARD WTS_QUERY_USER_CONFIG_FN_W pQueryUserConfigW;
	WINPR_ATTR_NODISCARD WTS_QUERY_USER_CONFIG_FN_A pQueryUserConfigA;
	WINPR_ATTR_NODISCARD WTS_SET_USER_CONFIG_FN_W pSetUserConfigW;
	WINPR_ATTR_NODISCARD WTS_SET_USER_CONFIG_FN_A pSetUserConfigA;
	WINPR_ATTR_NODISCARD WTS_SEND_MESSAGE_FN_W pSendMessageW;
	WINPR_ATTR_NODISCARD WTS_SEND_MESSAGE_FN_A pSendMessageA;
	WINPR_ATTR_NODISCARD WTS_DISCONNECT_SESSION_FN pDisconnectSession;
	WINPR_ATTR_NODISCARD WTS_LOGOFF_SESSION_FN pLogoffSession;
	WINPR_ATTR_NODISCARD WTS_SHUTDOWN_SYSTEM_FN pShutdownSystem;
	WINPR_ATTR_NODISCARD WTS_WAIT_SYSTEM_EVENT_FN pWaitSystemEvent;
	WINPR_ATTR_NODISCARD WTS_VIRTUAL_CHANNEL_OPEN_FN pVirtualChannelOpen;
	WINPR_ATTR_NODISCARD WTS_VIRTUAL_CHANNEL_OPEN_EX_FN pVirtualChannelOpenEx;
	WINPR_ATTR_NODISCARD WTS_VIRTUAL_CHANNEL_CLOSE_FN pVirtualChannelClose;
	WINPR_ATTR_NODISCARD WTS_VIRTUAL_CHANNEL_READ_FN pVirtualChannelRead;
	WINPR_ATTR_NODISCARD WTS_VIRTUAL_CHANNEL_WRITE_FN pVirtualChannelWrite;
	WINPR_ATTR_NODISCARD WTS_VIRTUAL_CHANNEL_PURGE_INPUT_FN pVirtualChannelPurgeInput;
	WINPR_ATTR_NODISCARD WTS_VIRTUAL_CHANNEL_PURGE_OUTPUT_FN pVirtualChannelPurgeOutput;
	WINPR_ATTR_NODISCARD WTS_VIRTUAL_CHANNEL_QUERY_FN pVirtualChannelQuery;
	WTS_FREE_MEMORY_FN pFreeMemory;
	WINPR_ATTR_NODISCARD WTS_REGISTER_SESSION_NOTIFICATION_FN pRegisterSessionNotification;
	WINPR_ATTR_NODISCARD WTS_UNREGISTER_SESSION_NOTIFICATION_FN pUnRegisterSessionNotification;
	WINPR_ATTR_NODISCARD WTS_REGISTER_SESSION_NOTIFICATION_EX_FN pRegisterSessionNotificationEx;
	WINPR_ATTR_NODISCARD WTS_UNREGISTER_SESSION_NOTIFICATION_EX_FN pUnRegisterSessionNotificationEx;
	WINPR_ATTR_NODISCARD WTS_QUERY_USER_TOKEN_FN pQueryUserToken;
	WINPR_ATTR_NODISCARD WTS_FREE_MEMORY_EX_FN_W pFreeMemoryExW;
	WINPR_ATTR_NODISCARD WTS_FREE_MEMORY_EX_FN_A pFreeMemoryExA;
	WINPR_ATTR_NODISCARD WTS_ENUMERATE_PROCESSES_EX_FN_W pEnumerateProcessesExW;
	WINPR_ATTR_NODISCARD WTS_ENUMERATE_PROCESSES_EX_FN_A pEnumerateProcessesExA;
	WINPR_ATTR_NODISCARD WTS_ENUMERATE_LISTENERS_FN_W pEnumerateListenersW;
	WINPR_ATTR_NODISCARD WTS_ENUMERATE_LISTENERS_FN_A pEnumerateListenersA;
	WINPR_ATTR_NODISCARD WTS_QUERY_LISTENER_CONFIG_FN_W pQueryListenerConfigW;
	WINPR_ATTR_NODISCARD WTS_QUERY_LISTENER_CONFIG_FN_A pQueryListenerConfigA;
	WINPR_ATTR_NODISCARD WTS_CREATE_LISTENER_FN_W pCreateListenerW;
	WINPR_ATTR_NODISCARD WTS_CREATE_LISTENER_FN_A pCreateListenerA;
	WINPR_ATTR_NODISCARD WTS_SET_LISTENER_SECURITY_FN_W pSetListenerSecurityW;
	WINPR_ATTR_NODISCARD WTS_SET_LISTENER_SECURITY_FN_A pSetListenerSecurityA;
	WINPR_ATTR_NODISCARD WTS_GET_LISTENER_SECURITY_FN_W pGetListenerSecurityW;
	WINPR_ATTR_NODISCARD WTS_GET_LISTENER_SECURITY_FN_A pGetListenerSecurityA;
	WINPR_ATTR_NODISCARD WTS_ENABLE_CHILD_SESSIONS_FN pEnableChildSessions;
	WINPR_ATTR_NODISCARD WTS_IS_CHILD_SESSIONS_ENABLED_FN pIsChildSessionsEnabled;
	WINPR_ATTR_NODISCARD WTS_GET_CHILD_SESSION_ID_FN pGetChildSessionId;
	WINPR_ATTR_NODISCARD WTS_GET_ACTIVE_CONSOLE_SESSION_ID_FN pGetActiveConsoleSessionId;
	WINPR_ATTR_NODISCARD WTS_LOGON_USER_FN pLogonUser;
	WINPR_ATTR_NODISCARD WTS_LOGOFF_USER_FN pLogoffUser;
	WINPR_ATTR_NODISCARD WTS_START_REMOTE_CONTROL_SESSION_EX_FN_W pStartRemoteControlSessionExW;
	WINPR_ATTR_NODISCARD WTS_START_REMOTE_CONTROL_SESSION_EX_FN_A pStartRemoteControlSessionExA;
} WtsApiFunctionTable;
typedef WtsApiFunctionTable* PWtsApiFunctionTable;

typedef const WtsApiFunctionTable*(CDECL* INIT_WTSAPI_FN)(void);

#ifdef __cplusplus
extern "C"
{
#endif

	WINPR_ATTR_NODISCARD
	WINPR_API BOOL WTSRegisterWtsApiFunctionTable(const WtsApiFunctionTable* table);

	WINPR_ATTR_NODISCARD
	WINPR_API const CHAR* WTSErrorToString(UINT error);

	WINPR_ATTR_NODISCARD
	WINPR_API const CHAR* WTSSessionStateToString(WTS_CONNECTSTATE_CLASS state);

#ifdef __cplusplus
}
#endif

WINPR_PRAGMA_DIAG_POP

#endif /* WINPR_WTSAPI_H */
