EA Desktop depends on that when tries to run the game with elevated privileges (which is performed from a process started by a service and running in a service session on Windows).
The improved stub only returns interactive ("Console") session, while Windows at least starting from Win Vista also always have "Services" session. While we could probably return "Sevices" as well, I think it is safer not to while we don't really have services running in "Services" session (along with all the winstation, token etc. info).
From: Paul Gofman pgofman@codeweavers.com
--- dlls/wtsapi32/tests/wtsapi.c | 33 +++++++++++++++++++++++++++++++++ dlls/wtsapi32/wtsapi32.c | 27 ++++++++++++++++++++------- 2 files changed, 53 insertions(+), 7 deletions(-)
diff --git a/dlls/wtsapi32/tests/wtsapi.c b/dlls/wtsapi32/tests/wtsapi.c index 5be1764b6b3..39634985dae 100644 --- a/dlls/wtsapi32/tests/wtsapi.c +++ b/dlls/wtsapi32/tests/wtsapi.c @@ -306,6 +306,38 @@ static void test_WTSQueryUserToken(void) ok(GetLastError()==ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got: %ld\n", GetLastError()); }
+static void test_WTSEnumerateSessions(void) +{ + BOOL console_found = FALSE, services_found = FALSE; + WTS_SESSION_INFOW *info; + unsigned int i; + DWORD count; + BOOL bret; + + bret = WTSEnumerateSessionsW(WTS_CURRENT_SERVER_HANDLE, 0, 1, &info, &count); + ok(bret, "got error %lu.\n", GetLastError()); + todo_wine_if(count == 1) ok(count >= 2, "got %lu.\n", count); + + for (i = 0; i < count; ++i) + { + trace("SessionId %lu, name %s, State %d.\n", info[i].SessionId, debugstr_w(info[i].pWinStationName), info[i].State); + if (!wcscmp(info[i].pWinStationName, L"Console")) + { + console_found = TRUE; + ok(info[i].State == WTSActive, "got State %d.\n", info[i].State); + } + else if (!wcscmp(info[i].pWinStationName, L"Services")) + { + services_found = TRUE; + ok(info[i].State == WTSDisconnected, "got State %d.\n", info[i].State); + } + } + ok(console_found, "Console session not found.\n"); + todo_wine ok(services_found, "Services session not found.\n"); + + WTSFreeMemory(info); +} + START_TEST (wtsapi) { pWTSEnumerateProcessesExW = (void *)GetProcAddress(GetModuleHandleA("wtsapi32"), "WTSEnumerateProcessesExW"); @@ -314,4 +346,5 @@ START_TEST (wtsapi) test_WTSEnumerateProcessesW(); test_WTSQuerySessionInformation(); test_WTSQueryUserToken(); + test_WTSEnumerateSessions(); } diff --git a/dlls/wtsapi32/wtsapi32.c b/dlls/wtsapi32/wtsapi32.c index 7de1b8124ea..0071922d866 100644 --- a/dlls/wtsapi32/wtsapi32.c +++ b/dlls/wtsapi32/wtsapi32.c @@ -309,16 +309,29 @@ BOOL WINAPI WTSEnumerateSessionsA(HANDLE hServer, DWORD Reserved, DWORD Version, /************************************************************ * WTSEnumerateEnumerateSessionsW (WTSAPI32.@) */ -BOOL WINAPI WTSEnumerateSessionsW(HANDLE hServer, DWORD Reserved, DWORD Version, - PWTS_SESSION_INFOW* ppSessionInfo, DWORD* pCount) +BOOL WINAPI WTSEnumerateSessionsW(HANDLE server, DWORD reserved, DWORD version, + PWTS_SESSION_INFOW *session_info, DWORD *count) { - FIXME("Stub %p 0x%08lx 0x%08lx %p %p\n", hServer, Reserved, Version, - ppSessionInfo, pCount); + static const WCHAR session_name[] = L"Console";
- if (!ppSessionInfo || !pCount) return FALSE; + FIXME("%p 0x%08lx 0x%08lx %p %p semi-stub.\n", server, reserved, version, session_info, count);
- *pCount = 0; - *ppSessionInfo = NULL; + if (!session_info || !count) return FALSE; + + if (!(*session_info = heap_alloc(sizeof(**session_info) + sizeof(session_name)))) + { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + if (!ProcessIdToSessionId( GetCurrentProcessId(), &(*session_info)->SessionId)) + { + WTSFreeMemory(*session_info); + return FALSE; + } + *count = 1; + (*session_info)->State = WTSActive; + (*session_info)->pWinStationName = (WCHAR *)((char *)*session_info + sizeof(**session_info)); + memcpy((*session_info)->pWinStationName, session_name, sizeof(session_name));
return TRUE; }
From: Paul Gofman pgofman@codeweavers.com
--- dlls/wtsapi32/tests/wtsapi.c | 10 ++++++- dlls/wtsapi32/wtsapi32.c | 55 ++++++++++++++++++++++++++++++------ 2 files changed, 55 insertions(+), 10 deletions(-)
diff --git a/dlls/wtsapi32/tests/wtsapi.c b/dlls/wtsapi32/tests/wtsapi.c index 39634985dae..cac5da94e77 100644 --- a/dlls/wtsapi32/tests/wtsapi.c +++ b/dlls/wtsapi32/tests/wtsapi.c @@ -310,14 +310,19 @@ static void test_WTSEnumerateSessions(void) { BOOL console_found = FALSE, services_found = FALSE; WTS_SESSION_INFOW *info; + WTS_SESSION_INFOA *infoA; + DWORD count, count2; unsigned int i; - DWORD count; BOOL bret;
bret = WTSEnumerateSessionsW(WTS_CURRENT_SERVER_HANDLE, 0, 1, &info, &count); ok(bret, "got error %lu.\n", GetLastError()); todo_wine_if(count == 1) ok(count >= 2, "got %lu.\n", count);
+ bret = WTSEnumerateSessionsA(WTS_CURRENT_SERVER_HANDLE, 0, 1, &infoA, &count2); + ok(bret, "got error %lu.\n", GetLastError()); + ok(count2 == count, "got %lu.\n", count2); + for (i = 0; i < count; ++i) { trace("SessionId %lu, name %s, State %d.\n", info[i].SessionId, debugstr_w(info[i].pWinStationName), info[i].State); @@ -325,17 +330,20 @@ static void test_WTSEnumerateSessions(void) { console_found = TRUE; ok(info[i].State == WTSActive, "got State %d.\n", info[i].State); + ok(!strcmp(infoA[i].pWinStationName, "Console"), "got %s.\n", debugstr_a(infoA[i].pWinStationName)); } else if (!wcscmp(info[i].pWinStationName, L"Services")) { services_found = TRUE; ok(info[i].State == WTSDisconnected, "got State %d.\n", info[i].State); + ok(!strcmp(infoA[i].pWinStationName, "Services"), "got %s.\n", debugstr_a(infoA[i].pWinStationName)); } } ok(console_found, "Console session not found.\n"); todo_wine ok(services_found, "Services session not found.\n");
WTSFreeMemory(info); + WTSFreeMemory(infoA); }
START_TEST (wtsapi) diff --git a/dlls/wtsapi32/wtsapi32.c b/dlls/wtsapi32/wtsapi32.c index 0071922d866..6eaea8d3c6f 100644 --- a/dlls/wtsapi32/wtsapi32.c +++ b/dlls/wtsapi32/wtsapi32.c @@ -266,7 +266,6 @@ BOOL WINAPI WTSEnumerateServersW(LPWSTR pDomainName, DWORD Reserved, DWORD Versi return FALSE; }
- /************************************************************ * WTSEnumerateEnumerateSessionsExW (WTSAPI32.@) */ @@ -290,19 +289,57 @@ BOOL WINAPI WTSEnumerateSessionsExA(HANDLE server, DWORD *level, DWORD filter, W /************************************************************ * WTSEnumerateEnumerateSessionsA (WTSAPI32.@) */ -BOOL WINAPI WTSEnumerateSessionsA(HANDLE hServer, DWORD Reserved, DWORD Version, - PWTS_SESSION_INFOA* ppSessionInfo, DWORD* pCount) +BOOL WINAPI WTSEnumerateSessionsA(HANDLE server, DWORD reserved, DWORD version, + PWTS_SESSION_INFOA *session_info, DWORD *count) { - static int once; + PWTS_SESSION_INFOW infoW; + DWORD size, offset; + unsigned int i; + int len;
- if (!once++) FIXME("Stub %p 0x%08lx 0x%08lx %p %p\n", hServer, Reserved, Version, - ppSessionInfo, pCount); + TRACE("%p 0x%08lx 0x%08lx %p %p.\n", server, reserved, version, session_info, count);
- if (!ppSessionInfo || !pCount) return FALSE; + if (!session_info || !count) return FALSE;
- *pCount = 0; - *ppSessionInfo = NULL; + if (!WTSEnumerateSessionsW(server, reserved, version, &infoW, count)) return FALSE; + + size = 0; + for (i = 0; i < *count; ++i) + { + if (!(len = WideCharToMultiByte(CP_ACP, 0, infoW[i].pWinStationName, -1, NULL, 0, NULL, NULL))) + { + ERR("WideCharToMultiByte failed.\n"); + WTSFreeMemory(infoW); + return FALSE; + } + size += sizeof(**session_info) + len; + } + + if (!(*session_info = heap_alloc(size))) + { + WTSFreeMemory(infoW); + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + + offset = *count * sizeof(**session_info); + for (i = 0; i < *count; ++i) + { + (*session_info)[i].State = infoW[i].State; + (*session_info)[i].SessionId = infoW[i].SessionId; + (*session_info)[i].pWinStationName = (char *)(*session_info) + offset; + len = WideCharToMultiByte(CP_ACP, 0, infoW[i].pWinStationName, -1, (*session_info)[i].pWinStationName, + size - offset, NULL, NULL); + if (!len) + { + ERR("WideCharToMultiByte failed.\n"); + WTSFreeMemory(*session_info); + WTSFreeMemory(infoW); + } + offset += len; + }
+ WTSFreeMemory(infoW); return TRUE; }
From: Paul Gofman pgofman@codeweavers.com
--- dlls/wtsapi32/tests/wtsapi.c | 15 +++++++++++++++ dlls/wtsapi32/wtsapi32.c | 24 +++++++++++++----------- 2 files changed, 28 insertions(+), 11 deletions(-)
diff --git a/dlls/wtsapi32/tests/wtsapi.c b/dlls/wtsapi32/tests/wtsapi.c index cac5da94e77..d45d5776f39 100644 --- a/dlls/wtsapi32/tests/wtsapi.c +++ b/dlls/wtsapi32/tests/wtsapi.c @@ -192,10 +192,25 @@ static void test_WTSQuerySessionInformation(void) { WCHAR *buf1, usernameW[UNLEN + 1], computernameW[MAX_COMPUTERNAME_LENGTH + 1]; char *buf2, username[UNLEN + 1], computername[MAX_COMPUTERNAME_LENGTH + 1]; + WTS_CONNECTSTATE_CLASS *state; DWORD count, tempsize; USHORT *protocol; BOOL ret;
+ count = 0; + ret = WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSConnectState, (WCHAR **)&state, &count); + ok(ret, "got error %lu\n", GetLastError()); + ok(count == sizeof(*state), "got %lu\n", count); + ok(*state == WTSActive, "got %d.\n", *state); + WTSFreeMemory(state); + + count = 0; + ret = WTSQuerySessionInformationA(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSConnectState, (char **)&state, &count); + ok(ret, "got error %lu\n", GetLastError()); + ok(count == sizeof(*state), "got %lu\n", count); + ok(*state == WTSActive, "got %d.\n", *state); + WTSFreeMemory(state); + SetLastError(0xdeadbeef); count = 0; ret = WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION, WTSUserName, NULL, &count); diff --git a/dlls/wtsapi32/wtsapi32.c b/dlls/wtsapi32/wtsapi32.c index 6eaea8d3c6f..f4072e7090b 100644 --- a/dlls/wtsapi32/wtsapi32.c +++ b/dlls/wtsapi32/wtsapi32.c @@ -468,17 +468,8 @@ BOOL WINAPI WTSQuerySessionInformationA(HANDLE server, DWORD session_id, WTS_INF return FALSE; }
- if (class == WTSClientProtocolType) - { - USHORT *protocol; - - if (!(protocol = heap_alloc(sizeof(*protocol)))) return FALSE; - FIXME("returning 0 protocol type\n"); - *protocol = 0; - *buffer = (char *)protocol; - *count = sizeof(*protocol); - return TRUE; - } + if (class == WTSClientProtocolType || class == WTSConnectState) + return WTSQuerySessionInformationW(server, session_id, class, (WCHAR **)buffer, count);
if (!WTSQuerySessionInformationW(server, session_id, class, &bufferW, count)) return FALSE; @@ -520,6 +511,17 @@ BOOL WINAPI WTSQuerySessionInformationW(HANDLE server, DWORD session_id, WTS_INF return FALSE; }
+ if (class == WTSConnectState) + { + WTS_CONNECTSTATE_CLASS *state; + + if (!(state = heap_alloc(sizeof(*state)))) return FALSE; + *state = WTSActive; + *buffer = (WCHAR *)state; + *count = sizeof(*state); + return TRUE; + } + if (class == WTSClientProtocolType) { USHORT *protocol;