From: Patrick Hibbs hibbsncc1701@yahoo.com
Keeping track of window notification registrations is part of the defined API. A struct is required to do that.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47433 Signed-off-by: Patrick Hibbs hibbsncc1701@yahoo.com --- dlls/wtsapi32/wtsapi32.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/dlls/wtsapi32/wtsapi32.c b/dlls/wtsapi32/wtsapi32.c index 2f5e73d05a..3d944943b4 100644 --- a/dlls/wtsapi32/wtsapi32.c +++ b/dlls/wtsapi32/wtsapi32.c @@ -22,9 +22,24 @@ #include "wtsapi32.h" #include "wine/debug.h" #include "wine/heap.h" +#include "wine/list.h"
WINE_DEFAULT_DEBUG_CHANNEL(wtsapi);
+/* This linked list is an internal management structure + * mostly used to keep track of window event notification + * registrations so we can give proper return codes to + * callers. + */ +typedef struct tagWTSAPI32InternalRegMNGTStr +{ + struct list entry; + HANDLE hServer; /* The server we're monitoring. */ + HWND hWnd; /* The window to recieve notifications. */ + DWORD dwFlags; /* Types of notifications the window should get. */ +} WTSAPI32InternalRegMNGTStr; + +static struct list RegisteredWindowsToNotifiy = LIST_INIT( RegisteredWindowsToNotifiy );
/************************************************************ * WTSCloseServer (WTSAPI32.@)
From: Patrick Hibbs hibbsncc1701@yahoo.com
Callers expect valid status codes even from stubs. Keeping track of window registrations is required to do that.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47433 Signed-off-by: Patrick Hibbs hibbsncc1701@yahoo.com --- v2: Fix return status based on tests. --- dlls/wtsapi32/wtsapi32.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-)
diff --git a/dlls/wtsapi32/wtsapi32.c b/dlls/wtsapi32/wtsapi32.c index 3d944943b4..8ece1d2b37 100644 --- a/dlls/wtsapi32/wtsapi32.c +++ b/dlls/wtsapi32/wtsapi32.c @@ -316,8 +316,44 @@ BOOL WINAPI WTSRegisterSessionNotification(HWND hWnd, DWORD dwFlags) */ BOOL WINAPI WTSRegisterSessionNotificationEx(HANDLE hServer, HWND hWnd, DWORD dwFlags) { - FIXME("Stub %p %p 0x%08x\n", hServer, hWnd, dwFlags); - return FALSE; + BOOL ret = TRUE; + BOOL found = FALSE; + WTSAPI32InternalRegMNGTStr *mgntStr; + + FIXME("Simi-Stub %p %p 0x%08x\n", hServer, hWnd, dwFlags); + + /* Keep track of the registration attempts. + */ + LIST_FOR_EACH_ENTRY(mgntStr, &RegisteredWindowsToNotifiy, WTSAPI32InternalRegMNGTStr, entry) + { + /* MSDN says that if the window is already registered, + * the dwFlags value is ignored. + */ + if ((mgntStr != NULL) && (mgntStr->hServer == hServer) && (mgntStr->hWnd == hWnd)) + { + found = TRUE; + } + } + + /* Only create the registration if needed. */ + if (!found) + { + mgntStr = NULL; + mgntStr = HeapAlloc(GetProcessHeap(),0, sizeof(WTSAPI32InternalRegMNGTStr)); + if (mgntStr != NULL) + { + mgntStr->hServer = hServer; + mgntStr->hWnd = hWnd; + mgntStr->dwFlags = dwFlags; + list_add_head( &RegisteredWindowsToNotifiy, &mgntStr->entry ); + } + else + { + ret = FALSE; + } + } + + return ret; }
From: Patrick Hibbs hibbsncc1701@yahoo.com
Forward the calls from WTSRegisterSessionNotification() to WTSRegisterSessionNotificationEx().
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47433 Signed-off-by: Patrick Hibbs hibbsncc1701@yahoo.com --- dlls/wtsapi32/wtsapi32.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/dlls/wtsapi32/wtsapi32.c b/dlls/wtsapi32/wtsapi32.c index 8ece1d2b37..dccd5ec1a1 100644 --- a/dlls/wtsapi32/wtsapi32.c +++ b/dlls/wtsapi32/wtsapi32.c @@ -307,8 +307,9 @@ BOOL WINAPI WTSQueryUserConfigW(LPWSTR pServerName, LPWSTR pUserName, WTS_CONFIG */ BOOL WINAPI WTSRegisterSessionNotification(HWND hWnd, DWORD dwFlags) { - FIXME("Stub %p 0x%08x\n", hWnd, dwFlags); - return TRUE; + /* Forward to WTSRegisterSessionNotificationEx. + */ + return WTSRegisterSessionNotificationEx(WTS_CURRENT_SERVER_HANDLE, hWnd, dwFlags); }
/************************************************************
From: Patrick Hibbs hibbsncc1701@yahoo.com
Ensure the heap doesn't run out of space, and return the proper status codes.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47433 Signed-off-by: Patrick Hibbs hibbsncc1701@yahoo.com --- v2: Fix status code based on tests, make mismatched message a trace. --- dlls/wtsapi32/wtsapi32.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-)
diff --git a/dlls/wtsapi32/wtsapi32.c b/dlls/wtsapi32/wtsapi32.c index dccd5ec1a1..8bc7348fca 100644 --- a/dlls/wtsapi32/wtsapi32.c +++ b/dlls/wtsapi32/wtsapi32.c @@ -451,12 +451,35 @@ BOOL WINAPI WTSUnRegisterSessionNotification(HWND hWnd) }
/************************************************************ - * WTSUnRegisterSessionNotification (WTSAPI32.@) + * WTSUnRegisterSessionNotificationEx (WTSAPI32.@) */ BOOL WINAPI WTSUnRegisterSessionNotificationEx(HANDLE hServer, HWND hWnd) { - FIXME("Stub %p %p\n", hServer, hWnd); - return FALSE; + BOOL found = FALSE; + WTSAPI32InternalRegMNGTStr *mgntStr, *cursor2; + FIXME("Simi-Stub %p %p\n", hServer, hWnd); + + /* Only deregister a window if it was registered previously. + */ + LIST_FOR_EACH_ENTRY_SAFE(mgntStr, cursor2, &RegisteredWindowsToNotifiy, + WTSAPI32InternalRegMNGTStr, entry) + { + if ((mgntStr != NULL) && (mgntStr->hServer == hServer) && (mgntStr->hWnd == hWnd)) + { + found = TRUE; + list_remove(&mgntStr->entry); + HeapFree(GetProcessHeap(), 0, mgntStr); + } + } + + /* Log mismatched UnRegister calls. + */ + if (!found) + { + TRACE("Mismatched WTSUnRegisterSessionNotification\n"); + } + + return TRUE; }
From: Patrick Hibbs hibbsncc1701@yahoo.com
Forward calls from WTSUnRegisterSessionNotification() to WTSUnRegisterSessionNotificationEx().
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47433 Signed-off-by: Patrick Hibbs hibbsncc1701@yahoo.com --- dlls/wtsapi32/wtsapi32.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/dlls/wtsapi32/wtsapi32.c b/dlls/wtsapi32/wtsapi32.c index 8bc7348fca..00dfae0226 100644 --- a/dlls/wtsapi32/wtsapi32.c +++ b/dlls/wtsapi32/wtsapi32.c @@ -446,8 +446,9 @@ BOOL WINAPI WTSTerminateProcess(HANDLE hServer, DWORD ProcessId, DWORD ExitCode) */ BOOL WINAPI WTSUnRegisterSessionNotification(HWND hWnd) { - FIXME("Stub %p\n", hWnd); - return FALSE; + /* Forward to WTSUnRegisterSessionNotificationEx. + */ + return WTSUnRegisterSessionNotificationEx(WTS_CURRENT_SERVER_HANDLE, hWnd); }
/************************************************************
From: Patrick Hibbs hibbsncc1701@yahoo.com
Signed-off-by: Patrick Hibbs hibbsncc1701@gmail.com --- v2: Fix test for Windows XP. --- dlls/wtsapi32/tests/wtsapi.c | 87 ++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+)
diff --git a/dlls/wtsapi32/tests/wtsapi.c b/dlls/wtsapi32/tests/wtsapi.c index 67f56bbd7f..1686c077ea 100644 --- a/dlls/wtsapi32/tests/wtsapi.c +++ b/dlls/wtsapi32/tests/wtsapi.c @@ -22,9 +22,12 @@ #include <winbase.h> #include <winternl.h> #include <wtsapi32.h> +#include <windows.h>
#include "wine/test.h"
+static const CHAR testwindow_class[] = "testwindow"; + static void test_WTSEnumerateProcessesW(void) { BOOL found = FALSE, ret; @@ -115,9 +118,93 @@ static void test_WTSQueryUserToken(void) ok(GetLastError()==ERROR_INVALID_PARAMETER, "expected ERROR_INVALID_PARAMETER got: %d\n", GetLastError()); }
+static LRESULT CALLBACK testwindow_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + /* TODO: Actually check for WM_WTSSESSION_CHANGE messages. + */ + return DefWindowProcA(hwnd, msg, wparam, lparam); +} + +static void register_testwindow_class(void) +{ + WNDCLASSEXA cls; + + ZeroMemory(&cls, sizeof(cls)); + cls.cbSize = sizeof(cls); + cls.style = 0; + cls.lpfnWndProc = testwindow_wndproc; + cls.hInstance = NULL; + cls.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW); + cls.hbrBackground = (HBRUSH) COLOR_WINDOW; + cls.lpszClassName = testwindow_class; + + RegisterClassExA(&cls); +} + +typedef BOOL (WINAPI *RegFunc)(HWND, DWORD); +typedef BOOL (WINAPI *UnRegFunc)(HWND); + +static void test_WTSRegisterSessionNotification(void) +{ + BOOL ret; + HWND hwnd0; + HWND hwnd1; + HANDLE lib; + RegFunc regFunc; + UnRegFunc unRegFunc; + + register_testwindow_class(); + + hwnd0 = CreateWindowExA(WS_EX_TOOLWINDOW|WS_EX_TOPMOST, + testwindow_class, testwindow_class, WS_POPUP|WS_VISIBLE, 0, 0, 0, 0, + NULL, NULL, NULL, NULL); + ok(hwnd0 != NULL, "couldn't create window\n"); + + hwnd1 = CreateWindowExA(WS_EX_TOOLWINDOW|WS_EX_TOPMOST, + testwindow_class, testwindow_class, WS_POPUP|WS_VISIBLE, 0, 0, 0, 0, + NULL, NULL, NULL, NULL); + ok(hwnd1 != NULL, "couldn't create window\n"); + + lib = LoadLibraryA("WTSAPI32.DLL"); + if (lib != NULL) + { + regFunc = (RegFunc) GetProcAddress(lib, "WTSRegisterSessionNotification"); + unRegFunc = (UnRegFunc) GetProcAddress(lib, "WTSUnRegisterSessionNotification"); + if (regFunc && unRegFunc) + { + ret = regFunc(hwnd0, 0); + ok(ret, "WTSRegisterSessionNotification: Initial call, no registered windows.\n"); + ret = regFunc(hwnd0, 0); + ok(ret, "WTSRegisterSessionNotification: Re-register a window.\n"); + ret = regFunc(hwnd0, 1); + ok(ret, + "WTSRegisterSessionNotification: Re-register a window with diff flags.\n"); + ret = regFunc(hwnd1, 0); + ok(ret, "WTSRegisterSessionNotification: Register additional window.\n"); + ret = regFunc(hwnd1, 0); + ok(ret, "WTSRegisterSessionNotification: Re-register window2.\n"); + ret = regFunc(hwnd1, 1); + ok(ret, + "WTSRegisterSessionNotification: Re-register window2 with diff flags.\n"); + ret = unRegFunc(hwnd0); + ok(ret, "WTSUnRegisterSessionNotification: Initial call with first window.\n"); + ret = unRegFunc(hwnd0); + ok(ret, "WTSUnRegisterSessionNotification: Repeat call with first window.\n"); + ret = unRegFunc(hwnd1); + ok(ret, "WTSUnRegisterSessionNotification: Initial call with second window.\n"); + ret = unRegFunc(hwnd1); + ok(ret, "WTSUnRegisterSessionNotification: Repeat call with second window.\n"); + } + } + + DestroyWindow(hwnd0); + DestroyWindow(hwnd1); +} + START_TEST (wtsapi) { test_WTSEnumerateProcessesW(); test_WTSQuerySessionInformationW(); test_WTSQueryUserToken(); + test_WTSRegisterSessionNotification(); }