Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
30
third_party/FreeRDP/winpr/libwinpr/wtsapi/CMakeLists.txt
vendored
Normal file
30
third_party/FreeRDP/winpr/libwinpr/wtsapi/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
# WinPR: Windows Portable Runtime
|
||||
# libwinpr-wtsapi cmake build script
|
||||
#
|
||||
# Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
#
|
||||
# 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.
|
||||
|
||||
winpr_module_add(wtsapi.c)
|
||||
|
||||
if(WIN32)
|
||||
winpr_module_add(wtsapi_win32.c wtsapi_win32.h)
|
||||
|
||||
if(MINGW)
|
||||
winpr_library_add_private(ntdll.lib) # Only required with MINGW
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
9
third_party/FreeRDP/winpr/libwinpr/wtsapi/ModuleOptions.cmake
vendored
Normal file
9
third_party/FreeRDP/winpr/libwinpr/wtsapi/ModuleOptions.cmake
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
set(MINWIN_LAYER "0")
|
||||
set(MINWIN_GROUP "none")
|
||||
set(MINWIN_MAJOR_VERSION "0")
|
||||
set(MINWIN_MINOR_VERSION "0")
|
||||
set(MINWIN_SHORT_NAME "wtsapi")
|
||||
set(MINWIN_LONG_NAME "Windows Terminal Services API")
|
||||
set(MODULE_LIBRARY_NAME
|
||||
"api-ms-win-${MINWIN_GROUP}-${MINWIN_SHORT_NAME}-l${MINWIN_LAYER}-${MINWIN_MAJOR_VERSION}-${MINWIN_MINOR_VERSION}"
|
||||
)
|
||||
60
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/CMakeLists.txt
vendored
Normal file
60
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
set(MODULE_NAME "TestWtsApi")
|
||||
set(MODULE_PREFIX "TEST_WTSAPI")
|
||||
|
||||
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
|
||||
|
||||
set(UNIX_ONLY TestWtsApiShutdownSystem.c TestWtsApiWaitSystemEvent.c)
|
||||
|
||||
set(${MODULE_PREFIX}_TESTS TestWtsApiEnumerateProcesses.c TestWtsApiEnumerateSessions.c
|
||||
TestWtsApiQuerySessionInformation.c TestWtsApiSessionNotification.c
|
||||
)
|
||||
|
||||
if(NOT WIN32)
|
||||
set(${MODULE_PREFIX}_TESTS ${${MODULE_PREFIX}_TESTS} ${UNIX_ONLY})
|
||||
endif()
|
||||
|
||||
create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} ${${MODULE_PREFIX}_TESTS})
|
||||
|
||||
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
|
||||
|
||||
target_link_libraries(${MODULE_NAME} winpr)
|
||||
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
|
||||
|
||||
foreach(test ${${MODULE_PREFIX}_TESTS})
|
||||
get_filename_component(TestName ${test} NAME_WE)
|
||||
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
|
||||
endforeach()
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")
|
||||
|
||||
if(TESTS_WTSAPI_EXTRA)
|
||||
|
||||
set(MODULE_NAME "TestWtsApiExtra")
|
||||
set(MODULE_PREFIX "TEST_WTSAPI_EXTRA")
|
||||
|
||||
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
|
||||
|
||||
set(${MODULE_PREFIX}_TESTS
|
||||
TestWtsApiExtraDisconnectSession.c TestWtsApiExtraDynamicVirtualChannel.c TestWtsApiExtraLogoffSession.c
|
||||
TestWtsApiExtraSendMessage.c TestWtsApiExtraVirtualChannel.c TestWtsApiExtraStartRemoteSessionEx.c
|
||||
)
|
||||
|
||||
create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} ${${MODULE_PREFIX}_TESTS})
|
||||
|
||||
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
|
||||
|
||||
target_link_libraries(${MODULE_NAME} winpr)
|
||||
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
|
||||
|
||||
foreach(test ${${MODULE_PREFIX}_TESTS})
|
||||
get_filename_component(TestName ${test} NAME_WE)
|
||||
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
|
||||
set_tests_properties(${TestName} PROPERTIES LABELS "WTSAPI_EXTRA")
|
||||
endforeach()
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")
|
||||
endif()
|
||||
53
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/TestWtsApiEnumerateProcesses.c
vendored
Normal file
53
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/TestWtsApiEnumerateProcesses.c
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/error.h>
|
||||
#include <winpr/wtsapi.h>
|
||||
#include <winpr/environment.h>
|
||||
|
||||
int TestWtsApiEnumerateProcesses(int argc, char* argv[])
|
||||
{
|
||||
DWORD count = 0;
|
||||
BOOL bSuccess = 0;
|
||||
HANDLE hServer = nullptr;
|
||||
PWTS_PROCESS_INFOA pProcessInfo = nullptr;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
#ifndef _WIN32
|
||||
if (!GetEnvironmentVariableA("WTSAPI_LIBRARY", nullptr, 0))
|
||||
{
|
||||
printf("%s: No RDS environment detected, skipping test\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
hServer = WTS_CURRENT_SERVER_HANDLE;
|
||||
|
||||
count = 0;
|
||||
pProcessInfo = nullptr;
|
||||
|
||||
bSuccess = WTSEnumerateProcessesA(hServer, 0, 1, &pProcessInfo, &count);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("WTSEnumerateProcesses failed: %" PRIu32 "\n", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
int rc = 0;
|
||||
{
|
||||
printf("WTSEnumerateProcesses enumerated %"PRIu32" process:\n", count);
|
||||
for (DWORD i = 0; i < count; i++)
|
||||
{
|
||||
const WTS_PROCESS_INFOA* cur = &pProcessInfo[i];
|
||||
if (!cur->pProcessName)
|
||||
rc = -1;
|
||||
printf("\t[%" PRIu32 "]: %s (%" PRIu32 ")\n", i, cur->pProcessName, cur->ProcessId);
|
||||
}
|
||||
}
|
||||
|
||||
WTSFreeMemory(pProcessInfo);
|
||||
|
||||
return rc;
|
||||
}
|
||||
50
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/TestWtsApiEnumerateSessions.c
vendored
Normal file
50
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/TestWtsApiEnumerateSessions.c
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/error.h>
|
||||
#include <winpr/wtsapi.h>
|
||||
#include <winpr/environment.h>
|
||||
|
||||
int TestWtsApiEnumerateSessions(int argc, char* argv[])
|
||||
{
|
||||
DWORD count = 0;
|
||||
BOOL bSuccess = 0;
|
||||
HANDLE hServer = nullptr;
|
||||
PWTS_SESSION_INFOA pSessionInfo = nullptr;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
#ifndef _WIN32
|
||||
if (!GetEnvironmentVariableA("WTSAPI_LIBRARY", nullptr, 0))
|
||||
{
|
||||
printf("%s: No RDS environment detected, skipping test\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
hServer = WTS_CURRENT_SERVER_HANDLE;
|
||||
|
||||
count = 0;
|
||||
pSessionInfo = nullptr;
|
||||
|
||||
bSuccess = WTSEnumerateSessionsA(hServer, 0, 1, &pSessionInfo, &count);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("WTSEnumerateSessions failed: %" PRIu32 "\n", GetLastError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("WTSEnumerateSessions count: %" PRIu32 "\n", count);
|
||||
|
||||
for (DWORD index = 0; index < count; index++)
|
||||
{
|
||||
printf("[%" PRIu32 "] SessionId: %" PRIu32 " WinstationName: '%s' State: %s (%u)\n", index,
|
||||
pSessionInfo[index].SessionId, pSessionInfo[index].pWinStationName,
|
||||
WTSSessionStateToString(pSessionInfo[index].State), pSessionInfo[index].State);
|
||||
}
|
||||
|
||||
WTSFreeMemory(pSessionInfo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
21
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/TestWtsApiExtraDisconnectSession.c
vendored
Normal file
21
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/TestWtsApiExtraDisconnectSession.c
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/error.h>
|
||||
#include <winpr/wtsapi.h>
|
||||
|
||||
int TestWtsApiExtraDisconnectSession(int argc, char* argv[])
|
||||
{
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
HANDLE hServer = WTS_CURRENT_SERVER_HANDLE;
|
||||
BOOL bSuccess = WTSDisconnectSession(hServer, WTS_CURRENT_SESSION, FALSE);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("WTSDisconnectSession failed: %" PRIu32 "\n", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
49
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/TestWtsApiExtraDynamicVirtualChannel.c
vendored
Normal file
49
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/TestWtsApiExtraDynamicVirtualChannel.c
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/error.h>
|
||||
#include <winpr/wtsapi.h>
|
||||
|
||||
int TestWtsApiExtraDynamicVirtualChannel(int argc, char* argv[])
|
||||
{
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
HANDLE hVirtualChannel =
|
||||
WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, "ECHO", WTS_CHANNEL_OPTION_DYNAMIC);
|
||||
|
||||
if (hVirtualChannel == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
printf("WTSVirtualChannelOpen failed: %" PRIu32 "\n", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
printf("WTSVirtualChannelOpen opend");
|
||||
ULONG bytesWritten = 0;
|
||||
char buffer[1024] = WINPR_C_ARRAY_INIT;
|
||||
size_t length = sizeof(buffer);
|
||||
BOOL bSuccess = WTSVirtualChannelWrite(hVirtualChannel, buffer, length, &bytesWritten);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("WTSVirtualChannelWrite failed: %" PRIu32 "\n", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
printf("WTSVirtualChannelWrite written");
|
||||
|
||||
ULONG bytesRead = 0;
|
||||
bSuccess = WTSVirtualChannelRead(hVirtualChannel, 5000, (PCHAR)buffer, length, &bytesRead);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("WTSVirtualChannelRead failed: %" PRIu32 "\n", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
printf("WTSVirtualChannelRead read");
|
||||
|
||||
if (!WTSVirtualChannelClose(hVirtualChannel))
|
||||
{
|
||||
printf("WTSVirtualChannelClose failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
22
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/TestWtsApiExtraLogoffSession.c
vendored
Normal file
22
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/TestWtsApiExtraLogoffSession.c
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/error.h>
|
||||
#include <winpr/wtsapi.h>
|
||||
|
||||
int TestWtsApiExtraLogoffSession(int argc, char* argv[])
|
||||
{
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
HANDLE hServer = WTS_CURRENT_SERVER_HANDLE;
|
||||
BOOL bSuccess = WTSLogoffSession(hServer, WTS_CURRENT_SESSION, FALSE);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("WTSLogoffSession failed: %" PRIu32 "\n", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
29
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/TestWtsApiExtraSendMessage.c
vendored
Normal file
29
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/TestWtsApiExtraSendMessage.c
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/error.h>
|
||||
#include <winpr/wtsapi.h>
|
||||
#include <winpr/user.h>
|
||||
|
||||
#define TITLE "thats the title"
|
||||
#define MESSAGE "thats the message"
|
||||
|
||||
int TestWtsApiExtraSendMessage(int argc, char* argv[])
|
||||
{
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
HANDLE hServer = WTS_CURRENT_SERVER_HANDLE;
|
||||
DWORD result = 0;
|
||||
BOOL bSuccess = WTSSendMessageA(hServer, WTS_CURRENT_SESSION, TITLE, strlen(TITLE) + 1, MESSAGE,
|
||||
strlen(MESSAGE) + 1, MB_CANCELTRYCONTINUE, 3, &result, TRUE);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("WTSSendMessage failed: %" PRIu32 "\n", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf("WTSSendMessage got result: %" PRIu32 "\n", result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
36
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/TestWtsApiExtraStartRemoteSessionEx.c
vendored
Normal file
36
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/TestWtsApiExtraStartRemoteSessionEx.c
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/error.h>
|
||||
#include <winpr/wtsapi.h>
|
||||
#include <winpr/input.h>
|
||||
#include <winpr/environment.h>
|
||||
|
||||
int TestWtsApiExtraStartRemoteSessionEx(int argc, char* argv[])
|
||||
{
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
ULONG logonId = 0;
|
||||
char logonIdStr[10] = WINPR_C_ARRAY_INIT;
|
||||
|
||||
DWORD bSuccess = GetEnvironmentVariableA("TEST_SESSION_LOGON_ID", logonIdStr, 10);
|
||||
if (bSuccess > 0)
|
||||
{
|
||||
errno = 0;
|
||||
logonId = strtoul(logonIdStr, nullptr, 0);
|
||||
if (errno != 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
bSuccess = WTSStartRemoteControlSessionEx(
|
||||
nullptr, logonId, VK_F10, REMOTECONTROL_KBDSHIFT_HOTKEY | REMOTECONTROL_KBDCTRL_HOTKEY,
|
||||
REMOTECONTROL_FLAG_DISABLE_INPUT);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("WTSStartRemoteControlSessionEx failed: %" PRIu32 "\n", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
51
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/TestWtsApiExtraVirtualChannel.c
vendored
Normal file
51
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/TestWtsApiExtraVirtualChannel.c
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/error.h>
|
||||
#include <winpr/wtsapi.h>
|
||||
|
||||
int TestWtsApiExtraVirtualChannel(int argc, char* argv[])
|
||||
{
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
char buffer[1024] = WINPR_C_ARRAY_INIT;
|
||||
const size_t length = sizeof(buffer);
|
||||
|
||||
HANDLE hVirtualChannel =
|
||||
WTSVirtualChannelOpen(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, "sample");
|
||||
|
||||
if (hVirtualChannel == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
printf("WTSVirtualChannelOpen failed: %" PRIu32 "\n", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
printf("WTSVirtualChannelOpen opend");
|
||||
ULONG bytesWritten = 0;
|
||||
BOOL bSuccess = WTSVirtualChannelWrite(hVirtualChannel, buffer, length, &bytesWritten);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("WTSVirtualChannelWrite failed: %" PRIu32 "\n", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
printf("WTSVirtualChannelWrite written");
|
||||
|
||||
ULONG bytesRead = 0;
|
||||
bSuccess = WTSVirtualChannelRead(hVirtualChannel, 5000, buffer, length, &bytesRead);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("WTSVirtualChannelRead failed: %" PRIu32 "\n", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
printf("WTSVirtualChannelRead read");
|
||||
|
||||
if (!WTSVirtualChannelClose(hVirtualChannel))
|
||||
{
|
||||
printf("WTSVirtualChannelClose failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
225
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/TestWtsApiQuerySessionInformation.c
vendored
Normal file
225
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/TestWtsApiQuerySessionInformation.c
vendored
Normal file
@@ -0,0 +1,225 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/error.h>
|
||||
#include <winpr/wtsapi.h>
|
||||
#include <winpr/environment.h>
|
||||
|
||||
int TestWtsApiQuerySessionInformation(int argc, char* argv[])
|
||||
{
|
||||
DWORD count = 0;
|
||||
BOOL bSuccess = 0;
|
||||
HANDLE hServer = nullptr;
|
||||
LPSTR pBuffer = nullptr;
|
||||
DWORD sessionId = 0;
|
||||
DWORD bytesReturned = 0;
|
||||
PWTS_SESSION_INFOA pSessionInfo = nullptr;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
#ifndef _WIN32
|
||||
if (!GetEnvironmentVariableA("WTSAPI_LIBRARY", nullptr, 0))
|
||||
{
|
||||
printf("%s: No RDS environment detected, skipping test\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
hServer = WTS_CURRENT_SERVER_HANDLE;
|
||||
|
||||
count = 0;
|
||||
pSessionInfo = nullptr;
|
||||
|
||||
bSuccess = WTSEnumerateSessionsA(hServer, 0, 1, &pSessionInfo, &count);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("WTSEnumerateSessions failed: %" PRIu32 "\n", GetLastError());
|
||||
return 0;
|
||||
}
|
||||
|
||||
printf("WTSEnumerateSessions count: %" PRIu32 "\n", count);
|
||||
|
||||
for (DWORD index = 0; index < count; index++)
|
||||
{
|
||||
char* Username = nullptr;
|
||||
char* Domain = nullptr;
|
||||
char* ClientName = nullptr;
|
||||
ULONG ClientBuildNumber = 0;
|
||||
USHORT ClientProductId = 0;
|
||||
ULONG ClientHardwareId = 0;
|
||||
USHORT ClientProtocolType = 0;
|
||||
PWTS_CLIENT_DISPLAY ClientDisplay = nullptr;
|
||||
PWTS_CLIENT_ADDRESS ClientAddress = nullptr;
|
||||
WTS_CONNECTSTATE_CLASS ConnectState = WTSInit;
|
||||
|
||||
pBuffer = nullptr;
|
||||
bytesReturned = 0;
|
||||
|
||||
sessionId = pSessionInfo[index].SessionId;
|
||||
|
||||
printf("[%" PRIu32 "] SessionId: %" PRIu32 " State: %s (%u) WinstationName: '%s'\n", index,
|
||||
pSessionInfo[index].SessionId, WTSSessionStateToString(pSessionInfo[index].State),
|
||||
pSessionInfo[index].State, pSessionInfo[index].pWinStationName);
|
||||
|
||||
/* WTSUserName */
|
||||
|
||||
bSuccess =
|
||||
WTSQuerySessionInformationA(hServer, sessionId, WTSUserName, &pBuffer, &bytesReturned);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("WTSQuerySessionInformation WTSUserName failed: %" PRIu32 "\n", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
Username = (char*)pBuffer;
|
||||
printf("\tWTSUserName: '%s'\n", Username);
|
||||
|
||||
/* WTSDomainName */
|
||||
|
||||
bSuccess = WTSQuerySessionInformationA(hServer, sessionId, WTSDomainName, &pBuffer,
|
||||
&bytesReturned);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("WTSQuerySessionInformation WTSDomainName failed: %" PRIu32 "\n",
|
||||
GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
Domain = (char*)pBuffer;
|
||||
printf("\tWTSDomainName: '%s'\n", Domain);
|
||||
|
||||
/* WTSConnectState */
|
||||
|
||||
bSuccess = WTSQuerySessionInformationA(hServer, sessionId, WTSConnectState, &pBuffer,
|
||||
&bytesReturned);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("WTSQuerySessionInformation WTSConnectState failed: %" PRIu32 "\n",
|
||||
GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
ConnectState = *((WTS_CONNECTSTATE_CLASS*)pBuffer);
|
||||
printf("\tWTSConnectState: %u (%s)\n", ConnectState, WTSSessionStateToString(ConnectState));
|
||||
|
||||
/* WTSClientBuildNumber */
|
||||
|
||||
bSuccess = WTSQuerySessionInformationA(hServer, sessionId, WTSClientBuildNumber, &pBuffer,
|
||||
&bytesReturned);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("WTSQuerySessionInformation WTSClientBuildNumber failed: %" PRIu32 "\n",
|
||||
GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
ClientBuildNumber = *((ULONG*)pBuffer);
|
||||
printf("\tWTSClientBuildNumber: %" PRIu32 "\n", ClientBuildNumber);
|
||||
|
||||
/* WTSClientName */
|
||||
|
||||
bSuccess = WTSQuerySessionInformationA(hServer, sessionId, WTSClientName, &pBuffer,
|
||||
&bytesReturned);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("WTSQuerySessionInformation WTSClientName failed: %" PRIu32 "\n",
|
||||
GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
ClientName = (char*)pBuffer;
|
||||
printf("\tWTSClientName: '%s'\n", ClientName);
|
||||
|
||||
/* WTSClientProductId */
|
||||
|
||||
bSuccess = WTSQuerySessionInformationA(hServer, sessionId, WTSClientProductId, &pBuffer,
|
||||
&bytesReturned);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("WTSQuerySessionInformation WTSClientProductId failed: %" PRIu32 "\n",
|
||||
GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
ClientProductId = *((USHORT*)pBuffer);
|
||||
printf("\tWTSClientProductId: %" PRIu16 "\n", ClientProductId);
|
||||
|
||||
/* WTSClientHardwareId */
|
||||
|
||||
bSuccess = WTSQuerySessionInformationA(hServer, sessionId, WTSClientHardwareId, &pBuffer,
|
||||
&bytesReturned);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("WTSQuerySessionInformation WTSClientHardwareId failed: %" PRIu32 "\n",
|
||||
GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
ClientHardwareId = *((ULONG*)pBuffer);
|
||||
printf("\tWTSClientHardwareId: %" PRIu32 "\n", ClientHardwareId);
|
||||
|
||||
/* WTSClientAddress */
|
||||
|
||||
bSuccess = WTSQuerySessionInformationA(hServer, sessionId, WTSClientAddress, &pBuffer,
|
||||
&bytesReturned);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("WTSQuerySessionInformation WTSClientAddress failed: %" PRIu32 "\n",
|
||||
GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
ClientAddress = (PWTS_CLIENT_ADDRESS)pBuffer;
|
||||
printf("\tWTSClientAddress: AddressFamily: %" PRIu32 " Address: ",
|
||||
ClientAddress->AddressFamily);
|
||||
for (DWORD i = 0; i < sizeof(ClientAddress->Address); i++)
|
||||
printf("%02" PRIX8 "", ClientAddress->Address[i]);
|
||||
printf("\n");
|
||||
|
||||
/* WTSClientDisplay */
|
||||
|
||||
bSuccess = WTSQuerySessionInformationA(hServer, sessionId, WTSClientDisplay, &pBuffer,
|
||||
&bytesReturned);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("WTSQuerySessionInformation WTSClientDisplay failed: %" PRIu32 "\n",
|
||||
GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
ClientDisplay = (PWTS_CLIENT_DISPLAY)pBuffer;
|
||||
printf("\tWTSClientDisplay: HorizontalResolution: %" PRIu32 " VerticalResolution: %" PRIu32
|
||||
" ColorDepth: %" PRIu32 "\n",
|
||||
ClientDisplay->HorizontalResolution, ClientDisplay->VerticalResolution,
|
||||
ClientDisplay->ColorDepth);
|
||||
|
||||
/* WTSClientProtocolType */
|
||||
|
||||
bSuccess = WTSQuerySessionInformationA(hServer, sessionId, WTSClientProtocolType, &pBuffer,
|
||||
&bytesReturned);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("WTSQuerySessionInformation WTSClientProtocolType failed: %" PRIu32 "\n",
|
||||
GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
ClientProtocolType = *((USHORT*)pBuffer);
|
||||
printf("\tWTSClientProtocolType: %" PRIu16 "\n", ClientProtocolType);
|
||||
}
|
||||
|
||||
WTSFreeMemory(pSessionInfo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
62
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/TestWtsApiSessionNotification.c
vendored
Normal file
62
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/TestWtsApiSessionNotification.c
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/error.h>
|
||||
#include <winpr/wtsapi.h>
|
||||
#include <winpr/environment.h>
|
||||
|
||||
int TestWtsApiSessionNotification(int argc, char* argv[])
|
||||
{
|
||||
HWND hWnd = nullptr;
|
||||
BOOL bSuccess = 0;
|
||||
DWORD dwFlags = 0;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
#ifndef _WIN32
|
||||
if (!GetEnvironmentVariableA("WTSAPI_LIBRARY", nullptr, 0))
|
||||
{
|
||||
printf("%s: No RDS environment detected, skipping test\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
/* We create a message-only window and use the predefined class name "STATIC" for simplicity */
|
||||
hWnd = CreateWindowA("STATIC", "TestWtsApiSessionNotification", 0, 0, 0, 0, 0, HWND_MESSAGE,
|
||||
nullptr, nullptr, nullptr);
|
||||
if (!hWnd)
|
||||
{
|
||||
printf("%s: error creating message-only window: %" PRIu32 "\n", __func__, GetLastError());
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
dwFlags = NOTIFY_FOR_ALL_SESSIONS;
|
||||
|
||||
bSuccess = WTSRegisterSessionNotification(hWnd, dwFlags);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("%s: WTSRegisterSessionNotification failed: %" PRIu32 "\n", __func__,
|
||||
GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
bSuccess = WTSUnRegisterSessionNotification(hWnd);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (hWnd)
|
||||
{
|
||||
DestroyWindow(hWnd);
|
||||
hWnd = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("%s: WTSUnRegisterSessionNotification failed: %" PRIu32 "\n", __func__,
|
||||
GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
35
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/TestWtsApiShutdownSystem.c
vendored
Normal file
35
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/TestWtsApiShutdownSystem.c
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/error.h>
|
||||
#include <winpr/wtsapi.h>
|
||||
#include <winpr/environment.h>
|
||||
|
||||
int TestWtsApiShutdownSystem(int argc, char* argv[])
|
||||
{
|
||||
BOOL bSuccess = 0;
|
||||
HANDLE hServer = nullptr;
|
||||
DWORD ShutdownFlag = 0;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
#ifndef _WIN32
|
||||
if (!GetEnvironmentVariableA("WTSAPI_LIBRARY", nullptr, 0))
|
||||
{
|
||||
printf("%s: No RDS environment detected, skipping test\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
hServer = WTS_CURRENT_SERVER_HANDLE;
|
||||
ShutdownFlag = WTS_WSD_SHUTDOWN;
|
||||
|
||||
bSuccess = WTSShutdownSystem(hServer, ShutdownFlag);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("WTSShutdownSystem failed: %" PRIu32 "\n", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
39
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/TestWtsApiWaitSystemEvent.c
vendored
Normal file
39
third_party/FreeRDP/winpr/libwinpr/wtsapi/test/TestWtsApiWaitSystemEvent.c
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/error.h>
|
||||
#include <winpr/wtsapi.h>
|
||||
#include <winpr/environment.h>
|
||||
|
||||
int TestWtsApiWaitSystemEvent(int argc, char* argv[])
|
||||
{
|
||||
BOOL bSuccess = 0;
|
||||
HANDLE hServer = nullptr;
|
||||
DWORD eventMask = 0;
|
||||
DWORD eventFlags = 0;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
#ifndef _WIN32
|
||||
if (!GetEnvironmentVariableA("WTSAPI_LIBRARY", nullptr, 0))
|
||||
{
|
||||
printf("%s: No RDS environment detected, skipping test\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
hServer = WTS_CURRENT_SERVER_HANDLE;
|
||||
|
||||
eventMask = WTS_EVENT_ALL;
|
||||
eventFlags = 0;
|
||||
|
||||
bSuccess = WTSWaitSystemEvent(hServer, eventMask, &eventFlags);
|
||||
|
||||
if (!bSuccess)
|
||||
{
|
||||
printf("WTSWaitSystemEvent failed: %" PRIu32 "\n", GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
804
third_party/FreeRDP/winpr/libwinpr/wtsapi/wtsapi.c
vendored
Normal file
804
third_party/FreeRDP/winpr/libwinpr/wtsapi/wtsapi.c
vendored
Normal file
@@ -0,0 +1,804 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/ini.h>
|
||||
#include <winpr/path.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/library.h>
|
||||
#include <winpr/environment.h>
|
||||
|
||||
#include <winpr/wtsapi.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "wtsapi_win32.h"
|
||||
#endif
|
||||
|
||||
#include "../log.h"
|
||||
#define TAG WINPR_TAG("wtsapi")
|
||||
|
||||
/**
|
||||
* Remote Desktop Services API Functions:
|
||||
* http://msdn.microsoft.com/en-us/library/windows/desktop/aa383464/
|
||||
*/
|
||||
|
||||
static HMODULE g_WtsApiModule = nullptr;
|
||||
|
||||
static const WtsApiFunctionTable* g_WtsApi = nullptr;
|
||||
|
||||
#if defined(_WIN32)
|
||||
static HMODULE g_WtsApi32Module = nullptr;
|
||||
static WtsApiFunctionTable WtsApi32_WtsApiFunctionTable = WINPR_C_ARRAY_INIT;
|
||||
|
||||
#ifdef __MINGW32__
|
||||
#define WTSAPI32_LOAD_PROC(NAME, TYPE) \
|
||||
WtsApi32_WtsApiFunctionTable.p##NAME = GetProcAddressAs(g_WtsApi32Module, "WTS" #NAME, TYPE);
|
||||
#else
|
||||
#define WTSAPI32_LOAD_PROC(NAME, TYPE) \
|
||||
WtsApi32_WtsApiFunctionTable.p##NAME = GetProcAddressAs(g_WtsApi32Module, "WTS" #NAME, ##TYPE);
|
||||
#endif
|
||||
|
||||
static BOOL WtsApi32_InitializeWtsApi(void)
|
||||
{
|
||||
g_WtsApi32Module = LoadLibraryA("wtsapi32.dll");
|
||||
|
||||
if (!g_WtsApi32Module)
|
||||
return FALSE;
|
||||
|
||||
WTSAPI32_LOAD_PROC(StopRemoteControlSession, WTS_STOP_REMOTE_CONTROL_SESSION_FN);
|
||||
WTSAPI32_LOAD_PROC(StartRemoteControlSessionW, WTS_START_REMOTE_CONTROL_SESSION_FN_W);
|
||||
WTSAPI32_LOAD_PROC(StartRemoteControlSessionA, WTS_START_REMOTE_CONTROL_SESSION_FN_A);
|
||||
WTSAPI32_LOAD_PROC(ConnectSessionW, WTS_CONNECT_SESSION_FN_W);
|
||||
WTSAPI32_LOAD_PROC(ConnectSessionA, WTS_CONNECT_SESSION_FN_A);
|
||||
WTSAPI32_LOAD_PROC(EnumerateServersW, WTS_ENUMERATE_SERVERS_FN_W);
|
||||
WTSAPI32_LOAD_PROC(EnumerateServersA, WTS_ENUMERATE_SERVERS_FN_A);
|
||||
WTSAPI32_LOAD_PROC(OpenServerW, WTS_OPEN_SERVER_FN_W);
|
||||
WTSAPI32_LOAD_PROC(OpenServerA, WTS_OPEN_SERVER_FN_A);
|
||||
WTSAPI32_LOAD_PROC(OpenServerExW, WTS_OPEN_SERVER_EX_FN_W);
|
||||
WTSAPI32_LOAD_PROC(OpenServerExA, WTS_OPEN_SERVER_EX_FN_A);
|
||||
WTSAPI32_LOAD_PROC(CloseServer, WTS_CLOSE_SERVER_FN);
|
||||
WTSAPI32_LOAD_PROC(EnumerateSessionsW, WTS_ENUMERATE_SESSIONS_FN_W);
|
||||
WTSAPI32_LOAD_PROC(EnumerateSessionsA, WTS_ENUMERATE_SESSIONS_FN_A);
|
||||
WTSAPI32_LOAD_PROC(EnumerateSessionsExW, WTS_ENUMERATE_SESSIONS_EX_FN_W);
|
||||
WTSAPI32_LOAD_PROC(EnumerateSessionsExA, WTS_ENUMERATE_SESSIONS_EX_FN_A);
|
||||
WTSAPI32_LOAD_PROC(EnumerateProcessesW, WTS_ENUMERATE_PROCESSES_FN_W);
|
||||
WTSAPI32_LOAD_PROC(EnumerateProcessesA, WTS_ENUMERATE_PROCESSES_FN_A);
|
||||
WTSAPI32_LOAD_PROC(TerminateProcess, WTS_TERMINATE_PROCESS_FN);
|
||||
WTSAPI32_LOAD_PROC(QuerySessionInformationW, WTS_QUERY_SESSION_INFORMATION_FN_W);
|
||||
WTSAPI32_LOAD_PROC(QuerySessionInformationA, WTS_QUERY_SESSION_INFORMATION_FN_A);
|
||||
WTSAPI32_LOAD_PROC(QueryUserConfigW, WTS_QUERY_USER_CONFIG_FN_W);
|
||||
WTSAPI32_LOAD_PROC(QueryUserConfigA, WTS_QUERY_USER_CONFIG_FN_A);
|
||||
WTSAPI32_LOAD_PROC(SetUserConfigW, WTS_SET_USER_CONFIG_FN_W);
|
||||
WTSAPI32_LOAD_PROC(SetUserConfigA, WTS_SET_USER_CONFIG_FN_A);
|
||||
WTSAPI32_LOAD_PROC(SendMessageW, WTS_SEND_MESSAGE_FN_W);
|
||||
WTSAPI32_LOAD_PROC(SendMessageA, WTS_SEND_MESSAGE_FN_A);
|
||||
WTSAPI32_LOAD_PROC(DisconnectSession, WTS_DISCONNECT_SESSION_FN);
|
||||
WTSAPI32_LOAD_PROC(LogoffSession, WTS_LOGOFF_SESSION_FN);
|
||||
WTSAPI32_LOAD_PROC(ShutdownSystem, WTS_SHUTDOWN_SYSTEM_FN);
|
||||
WTSAPI32_LOAD_PROC(WaitSystemEvent, WTS_WAIT_SYSTEM_EVENT_FN);
|
||||
WTSAPI32_LOAD_PROC(VirtualChannelOpen, WTS_VIRTUAL_CHANNEL_OPEN_FN);
|
||||
WTSAPI32_LOAD_PROC(VirtualChannelOpenEx, WTS_VIRTUAL_CHANNEL_OPEN_EX_FN);
|
||||
WTSAPI32_LOAD_PROC(VirtualChannelClose, WTS_VIRTUAL_CHANNEL_CLOSE_FN);
|
||||
WTSAPI32_LOAD_PROC(VirtualChannelRead, WTS_VIRTUAL_CHANNEL_READ_FN);
|
||||
WTSAPI32_LOAD_PROC(VirtualChannelWrite, WTS_VIRTUAL_CHANNEL_WRITE_FN);
|
||||
WTSAPI32_LOAD_PROC(VirtualChannelPurgeInput, WTS_VIRTUAL_CHANNEL_PURGE_INPUT_FN);
|
||||
WTSAPI32_LOAD_PROC(VirtualChannelPurgeOutput, WTS_VIRTUAL_CHANNEL_PURGE_OUTPUT_FN);
|
||||
WTSAPI32_LOAD_PROC(VirtualChannelQuery, WTS_VIRTUAL_CHANNEL_QUERY_FN);
|
||||
WTSAPI32_LOAD_PROC(FreeMemory, WTS_FREE_MEMORY_FN);
|
||||
WTSAPI32_LOAD_PROC(RegisterSessionNotification, WTS_REGISTER_SESSION_NOTIFICATION_FN);
|
||||
WTSAPI32_LOAD_PROC(UnRegisterSessionNotification, WTS_UNREGISTER_SESSION_NOTIFICATION_FN);
|
||||
WTSAPI32_LOAD_PROC(RegisterSessionNotificationEx, WTS_REGISTER_SESSION_NOTIFICATION_EX_FN);
|
||||
WTSAPI32_LOAD_PROC(UnRegisterSessionNotificationEx, WTS_UNREGISTER_SESSION_NOTIFICATION_EX_FN);
|
||||
WTSAPI32_LOAD_PROC(QueryUserToken, WTS_QUERY_USER_TOKEN_FN);
|
||||
WTSAPI32_LOAD_PROC(FreeMemoryExW, WTS_FREE_MEMORY_EX_FN_W);
|
||||
WTSAPI32_LOAD_PROC(FreeMemoryExA, WTS_FREE_MEMORY_EX_FN_A);
|
||||
WTSAPI32_LOAD_PROC(EnumerateProcessesExW, WTS_ENUMERATE_PROCESSES_EX_FN_W);
|
||||
WTSAPI32_LOAD_PROC(EnumerateProcessesExA, WTS_ENUMERATE_PROCESSES_EX_FN_A);
|
||||
WTSAPI32_LOAD_PROC(EnumerateListenersW, WTS_ENUMERATE_LISTENERS_FN_W);
|
||||
WTSAPI32_LOAD_PROC(EnumerateListenersA, WTS_ENUMERATE_LISTENERS_FN_A);
|
||||
WTSAPI32_LOAD_PROC(QueryListenerConfigW, WTS_QUERY_LISTENER_CONFIG_FN_W);
|
||||
WTSAPI32_LOAD_PROC(QueryListenerConfigA, WTS_QUERY_LISTENER_CONFIG_FN_A);
|
||||
WTSAPI32_LOAD_PROC(CreateListenerW, WTS_CREATE_LISTENER_FN_W);
|
||||
WTSAPI32_LOAD_PROC(CreateListenerA, WTS_CREATE_LISTENER_FN_A);
|
||||
WTSAPI32_LOAD_PROC(SetListenerSecurityW, WTS_SET_LISTENER_SECURITY_FN_W);
|
||||
WTSAPI32_LOAD_PROC(SetListenerSecurityA, WTS_SET_LISTENER_SECURITY_FN_A);
|
||||
WTSAPI32_LOAD_PROC(GetListenerSecurityW, WTS_GET_LISTENER_SECURITY_FN_W);
|
||||
WTSAPI32_LOAD_PROC(GetListenerSecurityA, WTS_GET_LISTENER_SECURITY_FN_A);
|
||||
WTSAPI32_LOAD_PROC(EnableChildSessions, WTS_ENABLE_CHILD_SESSIONS_FN);
|
||||
WTSAPI32_LOAD_PROC(IsChildSessionsEnabled, WTS_IS_CHILD_SESSIONS_ENABLED_FN);
|
||||
WTSAPI32_LOAD_PROC(GetChildSessionId, WTS_GET_CHILD_SESSION_ID_FN);
|
||||
WTSAPI32_LOAD_PROC(GetActiveConsoleSessionId, WTS_GET_ACTIVE_CONSOLE_SESSION_ID_FN);
|
||||
|
||||
Win32_InitializeWinSta(&WtsApi32_WtsApiFunctionTable);
|
||||
|
||||
g_WtsApi = &WtsApi32_WtsApiFunctionTable;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* WtsApi Functions */
|
||||
|
||||
static BOOL CALLBACK InitializeWtsApiStubs(PINIT_ONCE once, PVOID param, PVOID* context);
|
||||
static INIT_ONCE wtsapiInitOnce = INIT_ONCE_STATIC_INIT;
|
||||
|
||||
#define WTSAPI_STUB_CALL_VOID(_name, ...) \
|
||||
if (!InitOnceExecuteOnce(&wtsapiInitOnce, InitializeWtsApiStubs, nullptr, nullptr)) \
|
||||
return; \
|
||||
if (!g_WtsApi || !g_WtsApi->p##_name) \
|
||||
return; \
|
||||
g_WtsApi->p##_name(__VA_ARGS__)
|
||||
|
||||
#define WTSAPI_STUB_CALL_BOOL(_name, ...) \
|
||||
if (!InitOnceExecuteOnce(&wtsapiInitOnce, InitializeWtsApiStubs, nullptr, nullptr)) \
|
||||
return FALSE; \
|
||||
if (!g_WtsApi || !g_WtsApi->p##_name) \
|
||||
return FALSE; \
|
||||
return g_WtsApi->p##_name(__VA_ARGS__)
|
||||
|
||||
#define WTSAPI_STUB_CALL_HANDLE(_name, ...) \
|
||||
if (!InitOnceExecuteOnce(&wtsapiInitOnce, InitializeWtsApiStubs, nullptr, nullptr)) \
|
||||
return nullptr; \
|
||||
if (!g_WtsApi || !g_WtsApi->p##_name) \
|
||||
return nullptr; \
|
||||
return g_WtsApi->p##_name(__VA_ARGS__)
|
||||
|
||||
BOOL WINAPI WTSStartRemoteControlSessionW(LPWSTR pTargetServerName, ULONG TargetLogonId,
|
||||
BYTE HotkeyVk, USHORT HotkeyModifiers)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(StartRemoteControlSessionW, pTargetServerName, TargetLogonId, HotkeyVk,
|
||||
HotkeyModifiers);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSStartRemoteControlSessionA(LPSTR pTargetServerName, ULONG TargetLogonId,
|
||||
BYTE HotkeyVk, USHORT HotkeyModifiers)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(StartRemoteControlSessionA, pTargetServerName, TargetLogonId, HotkeyVk,
|
||||
HotkeyModifiers);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSStartRemoteControlSessionExW(LPWSTR pTargetServerName, ULONG TargetLogonId,
|
||||
BYTE HotkeyVk, USHORT HotkeyModifiers, DWORD flags)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(StartRemoteControlSessionExW, pTargetServerName, TargetLogonId, HotkeyVk,
|
||||
HotkeyModifiers, flags);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSStartRemoteControlSessionExA(LPSTR pTargetServerName, ULONG TargetLogonId,
|
||||
BYTE HotkeyVk, USHORT HotkeyModifiers, DWORD flags)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(StartRemoteControlSessionExA, pTargetServerName, TargetLogonId, HotkeyVk,
|
||||
HotkeyModifiers, flags);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSStopRemoteControlSession(ULONG LogonId)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(StopRemoteControlSession, LogonId);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSConnectSessionW(ULONG LogonId, ULONG TargetLogonId, PWSTR pPassword, BOOL bWait)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(ConnectSessionW, LogonId, TargetLogonId, pPassword, bWait);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSConnectSessionA(ULONG LogonId, ULONG TargetLogonId, PSTR pPassword, BOOL bWait)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(ConnectSessionA, LogonId, TargetLogonId, pPassword, bWait);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSEnumerateServersW(LPWSTR pDomainName, DWORD Reserved, DWORD Version,
|
||||
PWTS_SERVER_INFOW* ppServerInfo, DWORD* pCount)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(EnumerateServersW, pDomainName, Reserved, Version, ppServerInfo, pCount);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSEnumerateServersA(LPSTR pDomainName, DWORD Reserved, DWORD Version,
|
||||
PWTS_SERVER_INFOA* ppServerInfo, DWORD* pCount)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(EnumerateServersA, pDomainName, Reserved, Version, ppServerInfo, pCount);
|
||||
}
|
||||
|
||||
HANDLE WINAPI WTSOpenServerW(LPWSTR pServerName)
|
||||
{
|
||||
WTSAPI_STUB_CALL_HANDLE(OpenServerW, pServerName);
|
||||
}
|
||||
|
||||
HANDLE WINAPI WTSOpenServerA(LPSTR pServerName)
|
||||
{
|
||||
WTSAPI_STUB_CALL_HANDLE(OpenServerA, pServerName);
|
||||
}
|
||||
|
||||
HANDLE WINAPI WTSOpenServerExW(LPWSTR pServerName)
|
||||
{
|
||||
WTSAPI_STUB_CALL_HANDLE(OpenServerExW, pServerName);
|
||||
}
|
||||
|
||||
HANDLE WINAPI WTSOpenServerExA(LPSTR pServerName)
|
||||
{
|
||||
WTSAPI_STUB_CALL_HANDLE(OpenServerExA, pServerName);
|
||||
}
|
||||
|
||||
VOID WINAPI WTSCloseServer(HANDLE hServer)
|
||||
{
|
||||
WTSAPI_STUB_CALL_VOID(CloseServer, hServer);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSEnumerateSessionsW(HANDLE hServer, DWORD Reserved, DWORD Version,
|
||||
PWTS_SESSION_INFOW* ppSessionInfo, DWORD* pCount)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(EnumerateSessionsW, hServer, Reserved, Version, ppSessionInfo, pCount);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSEnumerateSessionsA(HANDLE hServer, DWORD Reserved, DWORD Version,
|
||||
PWTS_SESSION_INFOA* ppSessionInfo, DWORD* pCount)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(EnumerateSessionsA, hServer, Reserved, Version, ppSessionInfo, pCount);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSEnumerateSessionsExW(HANDLE hServer, DWORD* pLevel, DWORD Filter,
|
||||
PWTS_SESSION_INFO_1W* ppSessionInfo, DWORD* pCount)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(EnumerateSessionsExW, hServer, pLevel, Filter, ppSessionInfo, pCount);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSEnumerateSessionsExA(HANDLE hServer, DWORD* pLevel, DWORD Filter,
|
||||
PWTS_SESSION_INFO_1A* ppSessionInfo, DWORD* pCount)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(EnumerateSessionsExA, hServer, pLevel, Filter, ppSessionInfo, pCount);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSEnumerateProcessesW(HANDLE hServer, DWORD Reserved, DWORD Version,
|
||||
PWTS_PROCESS_INFOW* ppProcessInfo, DWORD* pCount)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(EnumerateProcessesW, hServer, Reserved, Version, ppProcessInfo, pCount);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSEnumerateProcessesA(HANDLE hServer, DWORD Reserved, DWORD Version,
|
||||
PWTS_PROCESS_INFOA* ppProcessInfo, DWORD* pCount)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(EnumerateProcessesA, hServer, Reserved, Version, ppProcessInfo, pCount);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSTerminateProcess(HANDLE hServer, DWORD ProcessId, DWORD ExitCode)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(TerminateProcess, hServer, ProcessId, ExitCode);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSQuerySessionInformationW(HANDLE hServer, DWORD SessionId,
|
||||
WTS_INFO_CLASS WTSInfoClass, LPWSTR* ppBuffer,
|
||||
DWORD* pBytesReturned)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(QuerySessionInformationW, hServer, SessionId, WTSInfoClass, ppBuffer,
|
||||
pBytesReturned);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSQuerySessionInformationA(HANDLE hServer, DWORD SessionId,
|
||||
WTS_INFO_CLASS WTSInfoClass, LPSTR* ppBuffer,
|
||||
DWORD* pBytesReturned)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(QuerySessionInformationA, hServer, SessionId, WTSInfoClass, ppBuffer,
|
||||
pBytesReturned);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSQueryUserConfigW(LPWSTR pServerName, LPWSTR pUserName,
|
||||
WTS_CONFIG_CLASS WTSConfigClass, LPWSTR* ppBuffer,
|
||||
DWORD* pBytesReturned)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(QueryUserConfigW, pServerName, pUserName, WTSConfigClass, ppBuffer,
|
||||
pBytesReturned);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSQueryUserConfigA(LPSTR pServerName, LPSTR pUserName, WTS_CONFIG_CLASS WTSConfigClass,
|
||||
LPSTR* ppBuffer, DWORD* pBytesReturned)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(QueryUserConfigA, pServerName, pUserName, WTSConfigClass, ppBuffer,
|
||||
pBytesReturned);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSSetUserConfigW(LPWSTR pServerName, LPWSTR pUserName, WTS_CONFIG_CLASS WTSConfigClass,
|
||||
LPWSTR pBuffer, DWORD DataLength)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(SetUserConfigW, pServerName, pUserName, WTSConfigClass, pBuffer,
|
||||
DataLength);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSSetUserConfigA(LPSTR pServerName, LPSTR pUserName, WTS_CONFIG_CLASS WTSConfigClass,
|
||||
LPSTR pBuffer, DWORD DataLength)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(SetUserConfigA, pServerName, pUserName, WTSConfigClass, pBuffer,
|
||||
DataLength);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSSendMessageW(HANDLE hServer, DWORD SessionId, LPWSTR pTitle, DWORD TitleLength,
|
||||
LPWSTR pMessage, DWORD MessageLength, DWORD Style, DWORD Timeout,
|
||||
DWORD* pResponse, BOOL bWait)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(SendMessageW, hServer, SessionId, pTitle, TitleLength, pMessage,
|
||||
MessageLength, Style, Timeout, pResponse, bWait);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSSendMessageA(HANDLE hServer, DWORD SessionId, LPSTR pTitle, DWORD TitleLength,
|
||||
LPSTR pMessage, DWORD MessageLength, DWORD Style, DWORD Timeout,
|
||||
DWORD* pResponse, BOOL bWait)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(SendMessageA, hServer, SessionId, pTitle, TitleLength, pMessage,
|
||||
MessageLength, Style, Timeout, pResponse, bWait);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSDisconnectSession(HANDLE hServer, DWORD SessionId, BOOL bWait)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(DisconnectSession, hServer, SessionId, bWait);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSLogoffSession(HANDLE hServer, DWORD SessionId, BOOL bWait)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(LogoffSession, hServer, SessionId, bWait);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSShutdownSystem(HANDLE hServer, DWORD ShutdownFlag)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(ShutdownSystem, hServer, ShutdownFlag);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSWaitSystemEvent(HANDLE hServer, DWORD EventMask, DWORD* pEventFlags)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(WaitSystemEvent, hServer, EventMask, pEventFlags);
|
||||
}
|
||||
|
||||
HANDLE WINAPI WTSVirtualChannelOpen(HANDLE hServer, DWORD SessionId, LPSTR pVirtualName)
|
||||
{
|
||||
WTSAPI_STUB_CALL_HANDLE(VirtualChannelOpen, hServer, SessionId, pVirtualName);
|
||||
}
|
||||
|
||||
HANDLE WINAPI WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualName, DWORD flags)
|
||||
{
|
||||
WTSAPI_STUB_CALL_HANDLE(VirtualChannelOpenEx, SessionId, pVirtualName, flags);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSVirtualChannelClose(HANDLE hChannelHandle)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(VirtualChannelClose, hChannelHandle);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSVirtualChannelRead(HANDLE hChannelHandle, ULONG TimeOut, PCHAR Buffer,
|
||||
ULONG BufferSize, PULONG pBytesRead)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(VirtualChannelRead, hChannelHandle, TimeOut, Buffer, BufferSize,
|
||||
pBytesRead);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSVirtualChannelWrite(HANDLE hChannelHandle, PCHAR Buffer, ULONG Length,
|
||||
PULONG pBytesWritten)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(VirtualChannelWrite, hChannelHandle, Buffer, Length, pBytesWritten);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSVirtualChannelPurgeInput(HANDLE hChannelHandle)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(VirtualChannelPurgeInput, hChannelHandle);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSVirtualChannelPurgeOutput(HANDLE hChannelHandle)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(VirtualChannelPurgeOutput, hChannelHandle);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSVirtualChannelQuery(HANDLE hChannelHandle, WTS_VIRTUAL_CLASS WtsVirtualClass,
|
||||
PVOID* ppBuffer, DWORD* pBytesReturned)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(VirtualChannelQuery, hChannelHandle, WtsVirtualClass, ppBuffer,
|
||||
pBytesReturned);
|
||||
}
|
||||
|
||||
VOID WINAPI WTSFreeMemory(PVOID pMemory)
|
||||
{
|
||||
WTSAPI_STUB_CALL_VOID(FreeMemory, pMemory);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSFreeMemoryExW(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory, ULONG NumberOfEntries)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(FreeMemoryExW, WTSTypeClass, pMemory, NumberOfEntries);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSFreeMemoryExA(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory, ULONG NumberOfEntries)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(FreeMemoryExA, WTSTypeClass, pMemory, NumberOfEntries);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSRegisterSessionNotification(HWND hWnd, DWORD dwFlags)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(RegisterSessionNotification, hWnd, dwFlags);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSUnRegisterSessionNotification(HWND hWnd)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(UnRegisterSessionNotification, hWnd);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSRegisterSessionNotificationEx(HANDLE hServer, HWND hWnd, DWORD dwFlags)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(RegisterSessionNotificationEx, hServer, hWnd, dwFlags);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSUnRegisterSessionNotificationEx(HANDLE hServer, HWND hWnd)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(UnRegisterSessionNotificationEx, hServer, hWnd);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSQueryUserToken(ULONG SessionId, PHANDLE phToken)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(QueryUserToken, SessionId, phToken);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSEnumerateProcessesExW(HANDLE hServer, DWORD* pLevel, DWORD SessionId,
|
||||
LPWSTR* ppProcessInfo, DWORD* pCount)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(EnumerateProcessesExW, hServer, pLevel, SessionId, ppProcessInfo, pCount);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSEnumerateProcessesExA(HANDLE hServer, DWORD* pLevel, DWORD SessionId,
|
||||
LPSTR* ppProcessInfo, DWORD* pCount)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(EnumerateProcessesExA, hServer, pLevel, SessionId, ppProcessInfo, pCount);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSEnumerateListenersW(HANDLE hServer, PVOID pReserved, DWORD Reserved,
|
||||
PWTSLISTENERNAMEW pListeners, DWORD* pCount)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(EnumerateListenersW, hServer, pReserved, Reserved, pListeners, pCount);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSEnumerateListenersA(HANDLE hServer, PVOID pReserved, DWORD Reserved,
|
||||
PWTSLISTENERNAMEA pListeners, DWORD* pCount)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(EnumerateListenersA, hServer, pReserved, Reserved, pListeners, pCount);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSQueryListenerConfigW(HANDLE hServer, PVOID pReserved, DWORD Reserved,
|
||||
LPWSTR pListenerName, PWTSLISTENERCONFIGW pBuffer)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(QueryListenerConfigW, hServer, pReserved, Reserved, pListenerName,
|
||||
pBuffer);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSQueryListenerConfigA(HANDLE hServer, PVOID pReserved, DWORD Reserved,
|
||||
LPSTR pListenerName, PWTSLISTENERCONFIGA pBuffer)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(QueryListenerConfigA, hServer, pReserved, Reserved, pListenerName,
|
||||
pBuffer);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSCreateListenerW(HANDLE hServer, PVOID pReserved, DWORD Reserved,
|
||||
LPWSTR pListenerName, PWTSLISTENERCONFIGW pBuffer, DWORD flag)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(CreateListenerW, hServer, pReserved, Reserved, pListenerName, pBuffer,
|
||||
flag);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSCreateListenerA(HANDLE hServer, PVOID pReserved, DWORD Reserved, LPSTR pListenerName,
|
||||
PWTSLISTENERCONFIGA pBuffer, DWORD flag)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(CreateListenerA, hServer, pReserved, Reserved, pListenerName, pBuffer,
|
||||
flag);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSSetListenerSecurityW(HANDLE hServer, PVOID pReserved, DWORD Reserved,
|
||||
LPWSTR pListenerName, SECURITY_INFORMATION SecurityInformation,
|
||||
PSECURITY_DESCRIPTOR pSecurityDescriptor)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(SetListenerSecurityW, hServer, pReserved, Reserved, pListenerName,
|
||||
SecurityInformation, pSecurityDescriptor);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSSetListenerSecurityA(HANDLE hServer, PVOID pReserved, DWORD Reserved,
|
||||
LPSTR pListenerName, SECURITY_INFORMATION SecurityInformation,
|
||||
PSECURITY_DESCRIPTOR pSecurityDescriptor)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(SetListenerSecurityA, hServer, pReserved, Reserved, pListenerName,
|
||||
SecurityInformation, pSecurityDescriptor);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSGetListenerSecurityW(HANDLE hServer, PVOID pReserved, DWORD Reserved,
|
||||
LPWSTR pListenerName, SECURITY_INFORMATION SecurityInformation,
|
||||
PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength,
|
||||
LPDWORD lpnLengthNeeded)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(GetListenerSecurityW, hServer, pReserved, Reserved, pListenerName,
|
||||
SecurityInformation, pSecurityDescriptor, nLength, lpnLengthNeeded);
|
||||
}
|
||||
|
||||
BOOL WINAPI WTSGetListenerSecurityA(HANDLE hServer, PVOID pReserved, DWORD Reserved,
|
||||
LPSTR pListenerName, SECURITY_INFORMATION SecurityInformation,
|
||||
PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength,
|
||||
LPDWORD lpnLengthNeeded)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(GetListenerSecurityA, hServer, pReserved, Reserved, pListenerName,
|
||||
SecurityInformation, pSecurityDescriptor, nLength, lpnLengthNeeded);
|
||||
}
|
||||
|
||||
BOOL CDECL WTSEnableChildSessions(BOOL bEnable)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(EnableChildSessions, bEnable);
|
||||
}
|
||||
|
||||
BOOL CDECL WTSIsChildSessionsEnabled(PBOOL pbEnabled)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(IsChildSessionsEnabled, pbEnabled);
|
||||
}
|
||||
|
||||
BOOL CDECL WTSGetChildSessionId(PULONG pSessionId)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(GetChildSessionId, pSessionId);
|
||||
}
|
||||
|
||||
BOOL CDECL WTSLogonUser(HANDLE hServer, LPCSTR username, LPCSTR password, LPCSTR domain)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(LogonUser, hServer, username, password, domain);
|
||||
}
|
||||
|
||||
BOOL CDECL WTSLogoffUser(HANDLE hServer)
|
||||
{
|
||||
WTSAPI_STUB_CALL_BOOL(LogoffUser, hServer);
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
/**
|
||||
* WTSGetActiveConsoleSessionId is declared in WinBase.h and exported by kernel32.dll
|
||||
*/
|
||||
|
||||
DWORD WINAPI WTSGetActiveConsoleSessionId(void)
|
||||
{
|
||||
if (!InitOnceExecuteOnce(&wtsapiInitOnce, InitializeWtsApiStubs, nullptr, nullptr))
|
||||
return UINT32_MAX;
|
||||
|
||||
if (!g_WtsApi || !g_WtsApi->pGetActiveConsoleSessionId)
|
||||
return UINT32_MAX;
|
||||
|
||||
return g_WtsApi->pGetActiveConsoleSessionId();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
const CHAR* WTSErrorToString(UINT error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case CHANNEL_RC_OK:
|
||||
return "CHANNEL_RC_OK";
|
||||
|
||||
case CHANNEL_RC_ALREADY_INITIALIZED:
|
||||
return "CHANNEL_RC_ALREADY_INITIALIZED";
|
||||
|
||||
case CHANNEL_RC_NOT_INITIALIZED:
|
||||
return "CHANNEL_RC_NOT_INITIALIZED";
|
||||
|
||||
case CHANNEL_RC_ALREADY_CONNECTED:
|
||||
return "CHANNEL_RC_ALREADY_CONNECTED";
|
||||
|
||||
case CHANNEL_RC_NOT_CONNECTED:
|
||||
return "CHANNEL_RC_NOT_CONNECTED";
|
||||
|
||||
case CHANNEL_RC_TOO_MANY_CHANNELS:
|
||||
return "CHANNEL_RC_TOO_MANY_CHANNELS";
|
||||
|
||||
case CHANNEL_RC_BAD_CHANNEL:
|
||||
return "CHANNEL_RC_BAD_CHANNEL";
|
||||
|
||||
case CHANNEL_RC_BAD_CHANNEL_HANDLE:
|
||||
return "CHANNEL_RC_BAD_CHANNEL_HANDLE";
|
||||
|
||||
case CHANNEL_RC_NO_BUFFER:
|
||||
return "CHANNEL_RC_NO_BUFFER";
|
||||
|
||||
case CHANNEL_RC_BAD_INIT_HANDLE:
|
||||
return "CHANNEL_RC_BAD_INIT_HANDLE";
|
||||
|
||||
case CHANNEL_RC_NOT_OPEN:
|
||||
return "CHANNEL_RC_NOT_OPEN";
|
||||
|
||||
case CHANNEL_RC_BAD_PROC:
|
||||
return "CHANNEL_RC_BAD_PROC";
|
||||
|
||||
case CHANNEL_RC_NO_MEMORY:
|
||||
return "CHANNEL_RC_NO_MEMORY";
|
||||
|
||||
case CHANNEL_RC_UNKNOWN_CHANNEL_NAME:
|
||||
return "CHANNEL_RC_UNKNOWN_CHANNEL_NAME";
|
||||
|
||||
case CHANNEL_RC_ALREADY_OPEN:
|
||||
return "CHANNEL_RC_ALREADY_OPEN";
|
||||
|
||||
case CHANNEL_RC_NOT_IN_VIRTUALCHANNELENTRY:
|
||||
return "CHANNEL_RC_NOT_IN_VIRTUALCHANNELENTRY";
|
||||
|
||||
case CHANNEL_RC_NULL_DATA:
|
||||
return "CHANNEL_RC_NULL_DATA";
|
||||
|
||||
case CHANNEL_RC_ZERO_LENGTH:
|
||||
return "CHANNEL_RC_ZERO_LENGTH";
|
||||
|
||||
case CHANNEL_RC_INVALID_INSTANCE:
|
||||
return "CHANNEL_RC_INVALID_INSTANCE";
|
||||
|
||||
case CHANNEL_RC_UNSUPPORTED_VERSION:
|
||||
return "CHANNEL_RC_UNSUPPORTED_VERSION";
|
||||
|
||||
case CHANNEL_RC_INITIALIZATION_ERROR:
|
||||
return "CHANNEL_RC_INITIALIZATION_ERROR";
|
||||
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
const CHAR* WTSSessionStateToString(WTS_CONNECTSTATE_CLASS state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case WTSActive:
|
||||
return "WTSActive";
|
||||
case WTSConnected:
|
||||
return "WTSConnected";
|
||||
case WTSConnectQuery:
|
||||
return "WTSConnectQuery";
|
||||
case WTSShadow:
|
||||
return "WTSShadow";
|
||||
case WTSDisconnected:
|
||||
return "WTSDisconnected";
|
||||
case WTSIdle:
|
||||
return "WTSIdle";
|
||||
case WTSListen:
|
||||
return "WTSListen";
|
||||
case WTSReset:
|
||||
return "WTSReset";
|
||||
case WTSDown:
|
||||
return "WTSDown";
|
||||
case WTSInit:
|
||||
return "WTSInit";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "INVALID_STATE";
|
||||
}
|
||||
|
||||
BOOL WTSRegisterWtsApiFunctionTable(const WtsApiFunctionTable* table)
|
||||
{
|
||||
/* Use InitOnceExecuteOnce here as well - otherwise a table set with this
|
||||
function is overridden on the first use of a WTS* API call (due to
|
||||
wtsapiInitOnce not being set). */
|
||||
union
|
||||
{
|
||||
const void* cpv;
|
||||
void* pv;
|
||||
} cnv;
|
||||
cnv.cpv = table;
|
||||
if (!InitOnceExecuteOnce(&wtsapiInitOnce, InitializeWtsApiStubs, cnv.pv, nullptr))
|
||||
return FALSE;
|
||||
return g_WtsApi != nullptr;
|
||||
}
|
||||
|
||||
static BOOL LoadAndInitialize(char* library)
|
||||
{
|
||||
g_WtsApiModule = LoadLibraryX(library);
|
||||
|
||||
if (!g_WtsApiModule)
|
||||
return FALSE;
|
||||
|
||||
INIT_WTSAPI_FN pInitWtsApi = GetProcAddressAs(g_WtsApiModule, "InitWtsApi", INIT_WTSAPI_FN);
|
||||
|
||||
if (!pInitWtsApi)
|
||||
return FALSE;
|
||||
|
||||
g_WtsApi = pInitWtsApi();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void InitializeWtsApiStubs_Env(void)
|
||||
{
|
||||
DWORD nSize = 0;
|
||||
char* env = nullptr;
|
||||
LPCSTR wts = "WTSAPI_LIBRARY";
|
||||
|
||||
if (g_WtsApi)
|
||||
return;
|
||||
|
||||
nSize = GetEnvironmentVariableA(wts, nullptr, 0);
|
||||
|
||||
if (!nSize)
|
||||
return;
|
||||
|
||||
env = (LPSTR)malloc(nSize);
|
||||
if (env)
|
||||
{
|
||||
if (GetEnvironmentVariableA(wts, env, nSize) == nSize - 1)
|
||||
LoadAndInitialize(env);
|
||||
free(env);
|
||||
}
|
||||
}
|
||||
|
||||
#define FREERDS_LIBRARY_NAME "libfreerds-fdsapi.so"
|
||||
|
||||
static void InitializeWtsApiStubs_FreeRDS(void)
|
||||
{
|
||||
wIniFile* ini = nullptr;
|
||||
const char* prefix = nullptr;
|
||||
const char* libdir = nullptr;
|
||||
|
||||
if (g_WtsApi)
|
||||
return;
|
||||
|
||||
ini = IniFile_New();
|
||||
|
||||
if (IniFile_ReadFile(ini, "/var/run/freerds.instance") < 0)
|
||||
{
|
||||
IniFile_Free(ini);
|
||||
WLog_ERR(TAG, "failed to parse freerds.instance");
|
||||
LoadAndInitialize(FREERDS_LIBRARY_NAME);
|
||||
return;
|
||||
}
|
||||
|
||||
prefix = IniFile_GetKeyValueString(ini, "FreeRDS", "prefix");
|
||||
libdir = IniFile_GetKeyValueString(ini, "FreeRDS", "libdir");
|
||||
WLog_INFO(TAG, "FreeRDS (prefix / libdir): %s / %s", prefix, libdir);
|
||||
|
||||
if (prefix && libdir)
|
||||
{
|
||||
char* prefix_libdir = nullptr;
|
||||
char* wtsapi_library = nullptr;
|
||||
prefix_libdir = GetCombinedPath(prefix, libdir);
|
||||
wtsapi_library = GetCombinedPath(prefix_libdir, FREERDS_LIBRARY_NAME);
|
||||
|
||||
if (wtsapi_library)
|
||||
{
|
||||
LoadAndInitialize(wtsapi_library);
|
||||
}
|
||||
|
||||
free(prefix_libdir);
|
||||
free(wtsapi_library);
|
||||
}
|
||||
|
||||
IniFile_Free(ini);
|
||||
}
|
||||
|
||||
static BOOL CALLBACK InitializeWtsApiStubs(PINIT_ONCE once, PVOID param, PVOID* context)
|
||||
{
|
||||
WINPR_UNUSED(once);
|
||||
WINPR_UNUSED(context);
|
||||
if (param)
|
||||
{
|
||||
g_WtsApi = (const WtsApiFunctionTable*)param;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
InitializeWtsApiStubs_Env();
|
||||
|
||||
#ifdef _WIN32
|
||||
WtsApi32_InitializeWtsApi();
|
||||
#endif
|
||||
|
||||
if (!g_WtsApi)
|
||||
InitializeWtsApiStubs_FreeRDS();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
816
third_party/FreeRDP/winpr/libwinpr/wtsapi/wtsapi_win32.c
vendored
Normal file
816
third_party/FreeRDP/winpr/libwinpr/wtsapi/wtsapi_win32.c
vendored
Normal file
@@ -0,0 +1,816 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Windows Terminal Services API
|
||||
*
|
||||
* Copyright 2013-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/io.h>
|
||||
#include <winpr/nt.h>
|
||||
#include <winpr/library.h>
|
||||
|
||||
#include <winpr/wtsapi.h>
|
||||
|
||||
#include "wtsapi_win32.h"
|
||||
|
||||
#include "../log.h"
|
||||
|
||||
#include <winternl.h>
|
||||
|
||||
#pragma comment(lib, "ntdll.lib")
|
||||
|
||||
#define WTSAPI_CHANNEL_MAGIC 0x44484356
|
||||
#define TAG WINPR_TAG("wtsapi")
|
||||
|
||||
typedef struct
|
||||
{
|
||||
UINT32 magic;
|
||||
HANDLE hServer;
|
||||
DWORD SessionId;
|
||||
HANDLE hFile;
|
||||
HANDLE hEvent;
|
||||
char* VirtualName;
|
||||
|
||||
DWORD flags;
|
||||
BYTE* chunk;
|
||||
BOOL dynamic;
|
||||
BOOL readSync;
|
||||
BOOL readAsync;
|
||||
BOOL readDone;
|
||||
UINT32 readSize;
|
||||
UINT32 readOffset;
|
||||
BYTE* readBuffer;
|
||||
BOOL showProtocol;
|
||||
BOOL waitObjectMode;
|
||||
OVERLAPPED overlapped;
|
||||
CHANNEL_PDU_HEADER* header;
|
||||
} WTSAPI_CHANNEL;
|
||||
|
||||
static BOOL g_Initialized = FALSE;
|
||||
static HMODULE g_WinStaModule = nullptr;
|
||||
|
||||
typedef HANDLE(WINAPI* fnWinStationVirtualOpen)(HANDLE hServer, DWORD SessionId,
|
||||
LPSTR pVirtualName);
|
||||
typedef HANDLE(WINAPI* fnWinStationVirtualOpenEx)(HANDLE hServer, DWORD SessionId,
|
||||
LPSTR pVirtualName, DWORD flags);
|
||||
|
||||
static fnWinStationVirtualOpen pfnWinStationVirtualOpen = nullptr;
|
||||
static fnWinStationVirtualOpenEx pfnWinStationVirtualOpenEx = nullptr;
|
||||
|
||||
static BOOL WINAPI Win32_WTSVirtualChannelClose(HANDLE hChannel);
|
||||
|
||||
/**
|
||||
* NOTE !!
|
||||
* An application using the WinPR wtsapi frees memory via WTSFreeMemory, which
|
||||
* might be mapped to Win32_WTSFreeMemory. Latter does not know if the passed
|
||||
* pointer was allocated by a function in wtsapi32.dll or in some internal
|
||||
* code below. The WTSFreeMemory implementation in all Windows wtsapi32.dll
|
||||
* versions up to Windows 10 uses LocalFree since all its allocating functions
|
||||
* use LocalAlloc() internally.
|
||||
* For that reason we also have to use LocalAlloc() for any memory returned by
|
||||
* our WinPR wtsapi functions.
|
||||
*
|
||||
* To be safe we only use the _wts_malloc, _wts_calloc, _wts_free wrappers
|
||||
* for memory management the code below.
|
||||
*/
|
||||
|
||||
static void* _wts_malloc(size_t size)
|
||||
{
|
||||
#ifdef _UWP
|
||||
return malloc(size);
|
||||
#else
|
||||
return (PVOID)LocalAlloc(LMEM_FIXED, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void* _wts_calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
#ifdef _UWP
|
||||
return calloc(nmemb, size);
|
||||
#else
|
||||
return (PVOID)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, nmemb * size);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void _wts_free(void* ptr)
|
||||
{
|
||||
#ifdef _UWP
|
||||
free(ptr);
|
||||
#else
|
||||
LocalFree((HLOCAL)ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
static BOOL Win32_WTSVirtualChannelReadAsync(WTSAPI_CHANNEL* pChannel)
|
||||
{
|
||||
BOOL status = TRUE;
|
||||
DWORD numBytes = 0;
|
||||
|
||||
if (pChannel->readAsync)
|
||||
return TRUE;
|
||||
|
||||
ZeroMemory(&(pChannel->overlapped), sizeof(OVERLAPPED));
|
||||
pChannel->overlapped.hEvent = pChannel->hEvent;
|
||||
(void)ResetEvent(pChannel->hEvent);
|
||||
|
||||
if (pChannel->showProtocol)
|
||||
{
|
||||
ZeroMemory(pChannel->header, sizeof(CHANNEL_PDU_HEADER));
|
||||
|
||||
status = ReadFile(pChannel->hFile, pChannel->header, sizeof(CHANNEL_PDU_HEADER), &numBytes,
|
||||
&(pChannel->overlapped));
|
||||
}
|
||||
else
|
||||
{
|
||||
status = ReadFile(pChannel->hFile, pChannel->chunk, CHANNEL_CHUNK_LENGTH, &numBytes,
|
||||
&(pChannel->overlapped));
|
||||
|
||||
if (status)
|
||||
{
|
||||
pChannel->readOffset = 0;
|
||||
pChannel->header->length = numBytes;
|
||||
|
||||
pChannel->readDone = TRUE;
|
||||
(void)SetEvent(pChannel->hEvent);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (status)
|
||||
{
|
||||
WLog_ERR(TAG, "Unexpected ReadFile status: %" PRId32 " numBytes: %" PRIu32 "", status,
|
||||
numBytes);
|
||||
return FALSE; /* ReadFile should return FALSE and set ERROR_IO_PENDING */
|
||||
}
|
||||
|
||||
if (GetLastError() != ERROR_IO_PENDING)
|
||||
{
|
||||
WLog_ERR(TAG, "ReadFile: GetLastError() = %" PRIu32 "", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pChannel->readAsync = TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static HANDLE WINAPI Win32_WTSVirtualChannelOpen_Internal(HANDLE hServer, DWORD SessionId,
|
||||
LPSTR pVirtualName, DWORD flags)
|
||||
{
|
||||
HANDLE hFile;
|
||||
HANDLE hChannel;
|
||||
WTSAPI_CHANNEL* pChannel;
|
||||
size_t virtualNameLen;
|
||||
|
||||
virtualNameLen = pVirtualName ? strlen(pVirtualName) : 0;
|
||||
|
||||
if (!virtualNameLen)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!pfnWinStationVirtualOpenEx)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_FUNCTION);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
hFile = pfnWinStationVirtualOpenEx(hServer, SessionId, pVirtualName, flags);
|
||||
|
||||
if (!hFile)
|
||||
return nullptr;
|
||||
|
||||
pChannel = (WTSAPI_CHANNEL*)_wts_calloc(1, sizeof(WTSAPI_CHANNEL));
|
||||
|
||||
if (!pChannel)
|
||||
{
|
||||
(void)CloseHandle(hFile);
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
hChannel = (HANDLE)pChannel;
|
||||
pChannel->magic = WTSAPI_CHANNEL_MAGIC;
|
||||
pChannel->hServer = hServer;
|
||||
pChannel->SessionId = SessionId;
|
||||
pChannel->hFile = hFile;
|
||||
pChannel->VirtualName = _wts_calloc(1, virtualNameLen + 1);
|
||||
if (!pChannel->VirtualName)
|
||||
{
|
||||
(void)CloseHandle(hFile);
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
_wts_free(pChannel);
|
||||
return nullptr;
|
||||
}
|
||||
memcpy(pChannel->VirtualName, pVirtualName, virtualNameLen);
|
||||
|
||||
pChannel->flags = flags;
|
||||
pChannel->dynamic = (flags & WTS_CHANNEL_OPTION_DYNAMIC) ? TRUE : FALSE;
|
||||
|
||||
pChannel->showProtocol = pChannel->dynamic;
|
||||
|
||||
pChannel->readSize = CHANNEL_PDU_LENGTH;
|
||||
pChannel->readBuffer = (BYTE*)_wts_malloc(pChannel->readSize);
|
||||
|
||||
pChannel->header = (CHANNEL_PDU_HEADER*)pChannel->readBuffer;
|
||||
pChannel->chunk = &(pChannel->readBuffer[sizeof(CHANNEL_PDU_HEADER)]);
|
||||
|
||||
pChannel->hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
|
||||
pChannel->overlapped.hEvent = pChannel->hEvent;
|
||||
|
||||
if (!pChannel->hEvent || !pChannel->VirtualName || !pChannel->readBuffer)
|
||||
{
|
||||
Win32_WTSVirtualChannelClose(hChannel);
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return hChannel;
|
||||
}
|
||||
|
||||
static HANDLE WINAPI Win32_WTSVirtualChannelOpen(HANDLE hServer, DWORD SessionId,
|
||||
LPSTR pVirtualName)
|
||||
{
|
||||
return Win32_WTSVirtualChannelOpen_Internal(hServer, SessionId, pVirtualName, 0);
|
||||
}
|
||||
|
||||
static HANDLE WINAPI Win32_WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualName, DWORD flags)
|
||||
{
|
||||
return Win32_WTSVirtualChannelOpen_Internal(0, SessionId, pVirtualName, flags);
|
||||
}
|
||||
|
||||
static BOOL WINAPI Win32_WTSVirtualChannelClose(HANDLE hChannel)
|
||||
{
|
||||
BOOL status = TRUE;
|
||||
WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannel;
|
||||
|
||||
if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (pChannel->hFile)
|
||||
{
|
||||
if (pChannel->readAsync)
|
||||
{
|
||||
CancelIo(pChannel->hFile);
|
||||
pChannel->readAsync = FALSE;
|
||||
}
|
||||
|
||||
status = CloseHandle(pChannel->hFile);
|
||||
pChannel->hFile = nullptr;
|
||||
}
|
||||
|
||||
if (pChannel->hEvent)
|
||||
{
|
||||
(void)CloseHandle(pChannel->hEvent);
|
||||
pChannel->hEvent = nullptr;
|
||||
}
|
||||
|
||||
if (pChannel->VirtualName)
|
||||
{
|
||||
_wts_free(pChannel->VirtualName);
|
||||
pChannel->VirtualName = nullptr;
|
||||
}
|
||||
|
||||
if (pChannel->readBuffer)
|
||||
{
|
||||
_wts_free(pChannel->readBuffer);
|
||||
pChannel->readBuffer = nullptr;
|
||||
}
|
||||
|
||||
pChannel->magic = 0;
|
||||
_wts_free(pChannel);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static BOOL WINAPI Win32_WTSVirtualChannelRead_Static(WTSAPI_CHANNEL* pChannel,
|
||||
DWORD dwMilliseconds, LPVOID lpBuffer,
|
||||
DWORD nNumberOfBytesToRead,
|
||||
LPDWORD lpNumberOfBytesTransferred)
|
||||
{
|
||||
if (pChannel->readDone)
|
||||
{
|
||||
DWORD numBytesRead = 0;
|
||||
DWORD numBytesToRead = 0;
|
||||
|
||||
*lpNumberOfBytesTransferred = 0;
|
||||
|
||||
numBytesToRead = nNumberOfBytesToRead;
|
||||
|
||||
if (numBytesToRead > (pChannel->header->length - pChannel->readOffset))
|
||||
numBytesToRead = (pChannel->header->length - pChannel->readOffset);
|
||||
|
||||
CopyMemory(lpBuffer, &(pChannel->chunk[pChannel->readOffset]), numBytesToRead);
|
||||
*lpNumberOfBytesTransferred += numBytesToRead;
|
||||
pChannel->readOffset += numBytesToRead;
|
||||
|
||||
if (pChannel->readOffset != pChannel->header->length)
|
||||
{
|
||||
SetLastError(ERROR_MORE_DATA);
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
pChannel->readDone = FALSE;
|
||||
Win32_WTSVirtualChannelReadAsync(pChannel);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else if (pChannel->readSync)
|
||||
{
|
||||
BOOL bSuccess;
|
||||
OVERLAPPED overlapped = WINPR_C_ARRAY_INIT;
|
||||
DWORD numBytesRead = 0;
|
||||
DWORD numBytesToRead = 0;
|
||||
|
||||
*lpNumberOfBytesTransferred = 0;
|
||||
|
||||
numBytesToRead = nNumberOfBytesToRead;
|
||||
|
||||
if (numBytesToRead > (pChannel->header->length - pChannel->readOffset))
|
||||
numBytesToRead = (pChannel->header->length - pChannel->readOffset);
|
||||
|
||||
if (ReadFile(pChannel->hFile, lpBuffer, numBytesToRead, &numBytesRead, &overlapped))
|
||||
{
|
||||
*lpNumberOfBytesTransferred += numBytesRead;
|
||||
pChannel->readOffset += numBytesRead;
|
||||
|
||||
if (pChannel->readOffset != pChannel->header->length)
|
||||
{
|
||||
SetLastError(ERROR_MORE_DATA);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pChannel->readSync = FALSE;
|
||||
Win32_WTSVirtualChannelReadAsync(pChannel);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (GetLastError() != ERROR_IO_PENDING)
|
||||
return FALSE;
|
||||
|
||||
bSuccess = GetOverlappedResult(pChannel->hFile, &overlapped, &numBytesRead, TRUE);
|
||||
|
||||
if (!bSuccess)
|
||||
return FALSE;
|
||||
|
||||
*lpNumberOfBytesTransferred += numBytesRead;
|
||||
pChannel->readOffset += numBytesRead;
|
||||
|
||||
if (pChannel->readOffset != pChannel->header->length)
|
||||
{
|
||||
SetLastError(ERROR_MORE_DATA);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pChannel->readSync = FALSE;
|
||||
Win32_WTSVirtualChannelReadAsync(pChannel);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else if (pChannel->readAsync)
|
||||
{
|
||||
BOOL bSuccess;
|
||||
DWORD numBytesRead = 0;
|
||||
DWORD numBytesToRead = 0;
|
||||
|
||||
*lpNumberOfBytesTransferred = 0;
|
||||
|
||||
if (WaitForSingleObject(pChannel->hEvent, dwMilliseconds) != WAIT_TIMEOUT)
|
||||
{
|
||||
bSuccess =
|
||||
GetOverlappedResult(pChannel->hFile, &(pChannel->overlapped), &numBytesRead, TRUE);
|
||||
|
||||
pChannel->readOffset = 0;
|
||||
pChannel->header->length = numBytesRead;
|
||||
|
||||
if (!bSuccess && (GetLastError() != ERROR_MORE_DATA))
|
||||
return FALSE;
|
||||
|
||||
numBytesToRead = nNumberOfBytesToRead;
|
||||
|
||||
if (numBytesRead < numBytesToRead)
|
||||
{
|
||||
numBytesToRead = numBytesRead;
|
||||
nNumberOfBytesToRead = numBytesRead;
|
||||
}
|
||||
|
||||
CopyMemory(lpBuffer, pChannel->chunk, numBytesToRead);
|
||||
*lpNumberOfBytesTransferred += numBytesToRead;
|
||||
lpBuffer = (BYTE*)lpBuffer + numBytesToRead;
|
||||
nNumberOfBytesToRead -= numBytesToRead;
|
||||
pChannel->readOffset += numBytesToRead;
|
||||
|
||||
pChannel->readAsync = FALSE;
|
||||
|
||||
if (!nNumberOfBytesToRead)
|
||||
{
|
||||
Win32_WTSVirtualChannelReadAsync(pChannel);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
pChannel->readSync = TRUE;
|
||||
|
||||
numBytesRead = 0;
|
||||
|
||||
bSuccess = Win32_WTSVirtualChannelRead_Static(pChannel, dwMilliseconds, lpBuffer,
|
||||
nNumberOfBytesToRead, &numBytesRead);
|
||||
|
||||
*lpNumberOfBytesTransferred += numBytesRead;
|
||||
return bSuccess;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetLastError(ERROR_IO_INCOMPLETE);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL WINAPI Win32_WTSVirtualChannelRead_Dynamic(WTSAPI_CHANNEL* pChannel,
|
||||
DWORD dwMilliseconds, LPVOID lpBuffer,
|
||||
DWORD nNumberOfBytesToRead,
|
||||
LPDWORD lpNumberOfBytesTransferred)
|
||||
{
|
||||
if (pChannel->readSync)
|
||||
{
|
||||
BOOL bSuccess;
|
||||
OVERLAPPED overlapped = WINPR_C_ARRAY_INIT;
|
||||
DWORD numBytesRead = 0;
|
||||
DWORD numBytesToRead = 0;
|
||||
|
||||
*lpNumberOfBytesTransferred = 0;
|
||||
|
||||
numBytesToRead = nNumberOfBytesToRead;
|
||||
|
||||
if (numBytesToRead > (pChannel->header->length - pChannel->readOffset))
|
||||
numBytesToRead = (pChannel->header->length - pChannel->readOffset);
|
||||
|
||||
if (ReadFile(pChannel->hFile, lpBuffer, numBytesToRead, &numBytesRead, &overlapped))
|
||||
{
|
||||
*lpNumberOfBytesTransferred += numBytesRead;
|
||||
pChannel->readOffset += numBytesRead;
|
||||
|
||||
if (pChannel->readOffset != pChannel->header->length)
|
||||
{
|
||||
SetLastError(ERROR_MORE_DATA);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pChannel->readSync = FALSE;
|
||||
Win32_WTSVirtualChannelReadAsync(pChannel);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (GetLastError() != ERROR_IO_PENDING)
|
||||
return FALSE;
|
||||
|
||||
bSuccess = GetOverlappedResult(pChannel->hFile, &overlapped, &numBytesRead, TRUE);
|
||||
|
||||
if (!bSuccess)
|
||||
return FALSE;
|
||||
|
||||
*lpNumberOfBytesTransferred += numBytesRead;
|
||||
pChannel->readOffset += numBytesRead;
|
||||
|
||||
if (pChannel->readOffset != pChannel->header->length)
|
||||
{
|
||||
SetLastError(ERROR_MORE_DATA);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pChannel->readSync = FALSE;
|
||||
Win32_WTSVirtualChannelReadAsync(pChannel);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else if (pChannel->readAsync)
|
||||
{
|
||||
BOOL bSuccess;
|
||||
DWORD numBytesRead = 0;
|
||||
|
||||
*lpNumberOfBytesTransferred = 0;
|
||||
|
||||
if (WaitForSingleObject(pChannel->hEvent, dwMilliseconds) != WAIT_TIMEOUT)
|
||||
{
|
||||
bSuccess =
|
||||
GetOverlappedResult(pChannel->hFile, &(pChannel->overlapped), &numBytesRead, TRUE);
|
||||
|
||||
if (pChannel->showProtocol)
|
||||
{
|
||||
if (numBytesRead != sizeof(CHANNEL_PDU_HEADER))
|
||||
return FALSE;
|
||||
|
||||
if (!bSuccess && (GetLastError() != ERROR_MORE_DATA))
|
||||
return FALSE;
|
||||
|
||||
CopyMemory(lpBuffer, pChannel->header, numBytesRead);
|
||||
*lpNumberOfBytesTransferred += numBytesRead;
|
||||
lpBuffer = (BYTE*)lpBuffer + numBytesRead;
|
||||
nNumberOfBytesToRead -= numBytesRead;
|
||||
}
|
||||
|
||||
pChannel->readAsync = FALSE;
|
||||
|
||||
if (!pChannel->header->length)
|
||||
{
|
||||
Win32_WTSVirtualChannelReadAsync(pChannel);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
pChannel->readSync = TRUE;
|
||||
pChannel->readOffset = 0;
|
||||
|
||||
if (!nNumberOfBytesToRead)
|
||||
{
|
||||
SetLastError(ERROR_MORE_DATA);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
numBytesRead = 0;
|
||||
|
||||
bSuccess = Win32_WTSVirtualChannelRead_Dynamic(pChannel, dwMilliseconds, lpBuffer,
|
||||
nNumberOfBytesToRead, &numBytesRead);
|
||||
|
||||
*lpNumberOfBytesTransferred += numBytesRead;
|
||||
return bSuccess;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetLastError(ERROR_IO_INCOMPLETE);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL WINAPI Win32_WTSVirtualChannelRead(HANDLE hChannel, DWORD dwMilliseconds,
|
||||
PCHAR lpBuffer, DWORD nNumberOfBytesToRead,
|
||||
LPDWORD lpNumberOfBytesTransferred)
|
||||
{
|
||||
WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannel;
|
||||
|
||||
if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!pChannel->waitObjectMode)
|
||||
{
|
||||
OVERLAPPED overlapped = WINPR_C_ARRAY_INIT;
|
||||
|
||||
if (ReadFile(pChannel->hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesTransferred,
|
||||
&overlapped))
|
||||
return TRUE;
|
||||
|
||||
if (GetLastError() != ERROR_IO_PENDING)
|
||||
return FALSE;
|
||||
|
||||
if (!dwMilliseconds)
|
||||
{
|
||||
CancelIo(pChannel->hFile);
|
||||
*lpNumberOfBytesTransferred = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (WaitForSingleObject(pChannel->hFile, dwMilliseconds) != WAIT_TIMEOUT)
|
||||
return GetOverlappedResult(pChannel->hFile, &overlapped, lpNumberOfBytesTransferred,
|
||||
FALSE);
|
||||
|
||||
CancelIo(pChannel->hFile);
|
||||
SetLastError(ERROR_IO_INCOMPLETE);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pChannel->dynamic)
|
||||
{
|
||||
return Win32_WTSVirtualChannelRead_Dynamic(pChannel, dwMilliseconds, lpBuffer,
|
||||
nNumberOfBytesToRead,
|
||||
lpNumberOfBytesTransferred);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Win32_WTSVirtualChannelRead_Static(pChannel, dwMilliseconds, lpBuffer,
|
||||
nNumberOfBytesToRead,
|
||||
lpNumberOfBytesTransferred);
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL WINAPI Win32_WTSVirtualChannelWrite(HANDLE hChannel, PCHAR lpBuffer,
|
||||
DWORD nNumberOfBytesToWrite,
|
||||
LPDWORD lpNumberOfBytesTransferred)
|
||||
{
|
||||
OVERLAPPED overlapped = WINPR_C_ARRAY_INIT;
|
||||
WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannel;
|
||||
|
||||
if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (WriteFile(pChannel->hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesTransferred,
|
||||
&overlapped))
|
||||
return TRUE;
|
||||
|
||||
if (GetLastError() == ERROR_IO_PENDING)
|
||||
return GetOverlappedResult(pChannel->hFile, &overlapped, lpNumberOfBytesTransferred, TRUE);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#ifndef FILE_DEVICE_TERMSRV
|
||||
#define FILE_DEVICE_TERMSRV 0x00000038
|
||||
#endif
|
||||
|
||||
static BOOL Win32_WTSVirtualChannelPurge_Internal(HANDLE hChannelHandle, ULONG IoControlCode)
|
||||
{
|
||||
IO_STATUS_BLOCK ioStatusBlock = WINPR_C_ARRAY_INIT;
|
||||
WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannelHandle;
|
||||
|
||||
if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
NTSTATUS ntstatus =
|
||||
NtDeviceIoControlFile(pChannel->hFile, 0, 0, 0, &ioStatusBlock, IoControlCode, 0, 0, 0, 0);
|
||||
|
||||
if (ntstatus == STATUS_PENDING)
|
||||
{
|
||||
ntstatus = NtWaitForSingleObject(pChannel->hFile, 0, 0);
|
||||
|
||||
if (ntstatus >= 0)
|
||||
{
|
||||
#if defined(NONAMELESSUNION) && !defined(__MINGW32__)
|
||||
ntstatus = ioStatusBlock.DUMMYUNIONNAME.Status;
|
||||
#else
|
||||
ntstatus = ioStatusBlock.Status;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (ntstatus == STATUS_BUFFER_OVERFLOW)
|
||||
{
|
||||
ntstatus = STATUS_BUFFER_TOO_SMALL;
|
||||
const DWORD error = RtlNtStatusToDosError(ntstatus);
|
||||
SetLastError(error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (ntstatus < 0)
|
||||
{
|
||||
const DWORD error = RtlNtStatusToDosError(ntstatus);
|
||||
SetLastError(error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL WINAPI Win32_WTSVirtualChannelPurgeInput(HANDLE hChannelHandle)
|
||||
{
|
||||
return Win32_WTSVirtualChannelPurge_Internal(hChannelHandle,
|
||||
(FILE_DEVICE_TERMSRV << 16) | 0x0107);
|
||||
}
|
||||
|
||||
static BOOL WINAPI Win32_WTSVirtualChannelPurgeOutput(HANDLE hChannelHandle)
|
||||
{
|
||||
return Win32_WTSVirtualChannelPurge_Internal(hChannelHandle,
|
||||
(FILE_DEVICE_TERMSRV << 16) | 0x010B);
|
||||
}
|
||||
|
||||
static BOOL WINAPI Win32_WTSVirtualChannelQuery(HANDLE hChannelHandle,
|
||||
WTS_VIRTUAL_CLASS WtsVirtualClass, PVOID* ppBuffer,
|
||||
DWORD* pBytesReturned)
|
||||
{
|
||||
WTSAPI_CHANNEL* pChannel = (WTSAPI_CHANNEL*)hChannelHandle;
|
||||
|
||||
if (!pChannel || (pChannel->magic != WTSAPI_CHANNEL_MAGIC))
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (WtsVirtualClass == WTSVirtualClientData)
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
else if (WtsVirtualClass == WTSVirtualFileHandle)
|
||||
{
|
||||
*pBytesReturned = sizeof(HANDLE);
|
||||
*ppBuffer = _wts_calloc(1, *pBytesReturned);
|
||||
|
||||
if (*ppBuffer == nullptr)
|
||||
{
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CopyMemory(*ppBuffer, &(pChannel->hFile), *pBytesReturned);
|
||||
}
|
||||
else if (WtsVirtualClass == WTSVirtualEventHandle)
|
||||
{
|
||||
*pBytesReturned = sizeof(HANDLE);
|
||||
*ppBuffer = _wts_calloc(1, *pBytesReturned);
|
||||
|
||||
if (*ppBuffer == nullptr)
|
||||
{
|
||||
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CopyMemory(*ppBuffer, &(pChannel->hEvent), *pBytesReturned);
|
||||
|
||||
Win32_WTSVirtualChannelReadAsync(pChannel);
|
||||
pChannel->waitObjectMode = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static VOID WINAPI Win32_WTSFreeMemory(PVOID pMemory)
|
||||
{
|
||||
_wts_free(pMemory);
|
||||
}
|
||||
|
||||
static BOOL WINAPI Win32_WTSFreeMemoryExW(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory,
|
||||
ULONG NumberOfEntries)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL WINAPI Win32_WTSFreeMemoryExA(WTS_TYPE_CLASS WTSTypeClass, PVOID pMemory,
|
||||
ULONG NumberOfEntries)
|
||||
{
|
||||
return WTSFreeMemoryExW(WTSTypeClass, pMemory, NumberOfEntries);
|
||||
}
|
||||
|
||||
BOOL Win32_InitializeWinSta(PWtsApiFunctionTable pWtsApi)
|
||||
{
|
||||
g_WinStaModule = LoadLibraryA("winsta.dll");
|
||||
|
||||
if (!g_WinStaModule)
|
||||
return FALSE;
|
||||
|
||||
pfnWinStationVirtualOpen =
|
||||
GetProcAddressAs(g_WinStaModule, "WinStationVirtualOpen", fnWinStationVirtualOpen);
|
||||
pfnWinStationVirtualOpenEx =
|
||||
GetProcAddressAs(g_WinStaModule, "WinStationVirtualOpenEx", fnWinStationVirtualOpenEx);
|
||||
|
||||
if (!pfnWinStationVirtualOpen | !pfnWinStationVirtualOpenEx)
|
||||
return FALSE;
|
||||
|
||||
pWtsApi->pVirtualChannelOpen = Win32_WTSVirtualChannelOpen;
|
||||
pWtsApi->pVirtualChannelOpenEx = Win32_WTSVirtualChannelOpenEx;
|
||||
pWtsApi->pVirtualChannelClose = Win32_WTSVirtualChannelClose;
|
||||
pWtsApi->pVirtualChannelRead = Win32_WTSVirtualChannelRead;
|
||||
pWtsApi->pVirtualChannelWrite = Win32_WTSVirtualChannelWrite;
|
||||
pWtsApi->pVirtualChannelPurgeInput = Win32_WTSVirtualChannelPurgeInput;
|
||||
pWtsApi->pVirtualChannelPurgeOutput = Win32_WTSVirtualChannelPurgeOutput;
|
||||
pWtsApi->pVirtualChannelQuery = Win32_WTSVirtualChannelQuery;
|
||||
pWtsApi->pFreeMemory = Win32_WTSFreeMemory;
|
||||
// pWtsApi->pFreeMemoryExW = Win32_WTSFreeMemoryExW;
|
||||
// pWtsApi->pFreeMemoryExA = Win32_WTSFreeMemoryExA;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
27
third_party/FreeRDP/winpr/libwinpr/wtsapi/wtsapi_win32.h
vendored
Normal file
27
third_party/FreeRDP/winpr/libwinpr/wtsapi/wtsapi_win32.h
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Windows Terminal Services API
|
||||
*
|
||||
* Copyright 2013-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* 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_WIN32_PRIVATE_H
|
||||
#define WINPR_WTSAPI_WIN32_PRIVATE_H
|
||||
|
||||
#include <winpr/wtsapi.h>
|
||||
|
||||
BOOL Win32_InitializeWinSta(PWtsApiFunctionTable pWtsApi);
|
||||
|
||||
#endif /* WINPR_WTSAPI_WIN32_PRIVATE_H */
|
||||
Reference in New Issue
Block a user