Signed-off-by: Aric Stewart aric@codeweavers.com
I have no information or opinion on the debate on initialization costs and such. I tend to be a person that says if it works and help then go for it. The code itself is just fine to me so it gets my sign-off.
-aric
On 1/30/19 3:25 AM, Nikolay Sivov wrote:
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com
dlls/imm32/Makefile.in | 2 +- dlls/imm32/imm.c | 129 ++++++++++++++++++- dlls/imm32/imm32.spec | 1 + dlls/imm32/tests/imm32.c | 252 ++++++++++++++++++++++++++++++++++++- dlls/user32/focus.c | 2 + dlls/user32/misc.c | 2 + dlls/user32/user_private.h | 1 + 7 files changed, 386 insertions(+), 3 deletions(-)
diff --git a/dlls/imm32/Makefile.in b/dlls/imm32/Makefile.in index b190888659..ad10fc2fa4 100644 --- a/dlls/imm32/Makefile.in +++ b/dlls/imm32/Makefile.in @@ -1,6 +1,6 @@ MODULE = imm32.dll IMPORTLIB = imm32 -IMPORTS = user32 gdi32 advapi32 +IMPORTS = user32 gdi32 advapi32 ole32
C_SRCS = \ imm.c diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 28eb00f355..129f7e8cb5 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -19,6 +19,8 @@
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#define COBJMACROS
- #include <stdarg.h> #include <stdio.h>
@@ -32,6 +34,8 @@ #include "ddk/imm.h" #include "winnls.h" #include "winreg.h" +#include "initguid.h" +#include "objbase.h" #include "wine/list.h" #include "wine/unicode.h"
@@ -95,8 +99,16 @@ typedef struct _tagIMMThreadData { HWND hwndDefault; BOOL disableIME; DWORD windowRefs;
- IInitializeSpy IInitializeSpy_iface;
- ULARGE_INTEGER spy_cookie;
- BOOL apt_initialized; } IMMThreadData;
+static inline IMMThreadData *impl_from_IInitializeSpy(IInitializeSpy *iface) +{
- return CONTAINING_RECORD(iface, IMMThreadData, IInitializeSpy_iface);
+}
- static struct list ImmHklList = LIST_INIT(ImmHklList); static struct list ImmThreadDataList = LIST_INIT(ImmThreadDataList);
@@ -227,6 +239,88 @@ static DWORD convert_candidatelist_AtoW( return ret; }
+static HRESULT WINAPI initializespy_QueryInterface(IInitializeSpy *iface, REFIID riid, void **obj) +{
- if (IsEqualIID(&IID_IInitializeSpy, riid) ||
IsEqualIID(&IID_IUnknown, riid))
- {
*obj = iface;
IInitializeSpy_AddRef(iface);
return S_OK;
- }
- *obj = NULL;
- return E_NOINTERFACE;
+}
+static ULONG WINAPI initializespy_AddRef(IInitializeSpy *iface) +{
- return 2;
+}
+static ULONG WINAPI initializespy_Release(IInitializeSpy *iface) +{
- return 1;
+}
+static void imm_couninit_thread(IMMThreadData *thread_data) +{
- if (!thread_data->apt_initialized)
return;
- thread_data->apt_initialized = FALSE;
- CoUninitialize();
+}
+static HRESULT WINAPI initializespy_PreInitialize(IInitializeSpy *iface, DWORD coinit, DWORD refs) +{
- IMMThreadData *thread_data = impl_from_IInitializeSpy(iface);
- /* Application requested initialization of different apartment type. */
- if (!(coinit & COINIT_APARTMENTTHREADED))
imm_couninit_thread(thread_data);
- return S_OK;
+}
+static HRESULT WINAPI initializespy_PostInitialize(IInitializeSpy *iface, HRESULT hr, DWORD coinit, DWORD refs) +{
- IMMThreadData *thread_data = impl_from_IInitializeSpy(iface);
- /* Explicit initialization call should return S_OK first time. */
- if (thread_data->apt_initialized && hr == S_FALSE && refs == 2)
hr = S_OK;
- return hr;
+}
+static HRESULT WINAPI initializespy_PreUninitialize(IInitializeSpy *iface, DWORD refs) +{
- IMMThreadData *thread_data = impl_from_IInitializeSpy(iface);
- /* Account for explicit uninitialization calls. */
- if (thread_data->apt_initialized && refs == 1)
thread_data->apt_initialized = FALSE;
- return S_OK;
+}
+static HRESULT WINAPI initializespy_PostUninitialize(IInitializeSpy *iface, DWORD refs) +{
- return S_OK;
+}
+static const IInitializeSpyVtbl initializespyvtbl = +{
- initializespy_QueryInterface,
- initializespy_AddRef,
- initializespy_Release,
- initializespy_PreInitialize,
- initializespy_PostInitialize,
- initializespy_PreUninitialize,
- initializespy_PostUninitialize,
+};
- static IMMThreadData *IMM_GetThreadData(HWND hwnd, DWORD thread) { IMMThreadData *data;
@@ -253,6 +347,7 @@ static IMMThreadData *IMM_GetThreadData(HWND hwnd, DWORD thread) if (data->threadID == thread) return data;
data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data));
- data->IInitializeSpy_iface.lpVtbl = &initializespyvtbl; data->threadID = thread; list_add_head(&ImmThreadDataList,&data->entry); TRACE("Thread Data Created (%x)\n",thread);
@@ -281,6 +376,7 @@ static void IMM_FreeThreadData(void) list_remove(&data->entry); LeaveCriticalSection(&threaddata_cs); IMM_DestroyContext(data->defaultContext);
imm_couninit_thread(data); HeapFree(GetProcessHeap(),0,data); TRACE("Thread Data Destroyed\n"); return;
@@ -1627,6 +1723,32 @@ static BOOL needs_ime_window(HWND hwnd) return TRUE; }
+void WINAPI __wine_activate_window(HWND hwnd) +{
- IMMThreadData *thread_data;
- TRACE("(%p)\n", hwnd);
- if (!needs_ime_window(hwnd))
return;
- thread_data = IMM_GetThreadData(hwnd, 0);
- if (!thread_data)
return;
- if (thread_data->disableIME || disable_ime)
- {
TRACE("IME for this thread is disabled\n");
LeaveCriticalSection(&threaddata_cs);
return;
- }
- if (!thread_data->apt_initialized)
thread_data->apt_initialized = SUCCEEDED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED));
- LeaveCriticalSection(&threaddata_cs);
+}
- /***********************************************************************
*/
__wine_register_window (IMM32.@)
@@ -1656,6 +1778,8 @@ BOOL WINAPI __wine_register_window(HWND hwnd) /* Create default IME window */ if (thread_data->windowRefs == 1) {
CoRegisterInitializeSpy(&thread_data->IInitializeSpy_iface, &thread_data->spy_cookie);
/* Do not create the window inside of a critical section */ LeaveCriticalSection(&threaddata_cs); new = CreateWindowExW( 0, szwIME, szwDefaultIME,
@@ -1697,8 +1821,11 @@ void WINAPI __wine_unregister_window(HWND hwnd) thread_data->windowRefs, thread_data->hwndDefault);
/* Destroy default IME window */
- if (thread_data->windowRefs == 0 && thread_data->hwndDefault)
- if (thread_data->windowRefs == 0) {
CoRevokeInitializeSpy(thread_data->spy_cookie);
thread_data->spy_cookie.QuadPart = 0;
imm_couninit_thread(thread_data); to_destroy = thread_data->hwndDefault; thread_data->hwndDefault = NULL; }
diff --git a/dlls/imm32/imm32.spec b/dlls/imm32/imm32.spec index 4197bb81e2..d9cdc794e9 100644 --- a/dlls/imm32/imm32.spec +++ b/dlls/imm32/imm32.spec @@ -117,3 +117,4 @@ @ stdcall __wine_get_ui_window(ptr) @ stdcall __wine_register_window(long) @ stdcall __wine_unregister_window(long) +@ stdcall __wine_activate_window(long) diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index ee1aeb3965..0d1632aa2f 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -18,6 +18,8 @@
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#define COBJMACROS
#include <stdio.h>
#include "wine/test.h"
@@ -25,10 +27,17 @@ #include "wingdi.h" #include "imm.h" #include "ddk/imm.h" +#include "initguid.h" +#include "objbase.h" +#include "urlmon.h"
static BOOL (WINAPI *pImmAssociateContextEx)(HWND,HIMC,DWORD); static BOOL (WINAPI *pImmIsUIMessageA)(HWND,UINT,WPARAM,LPARAM); static UINT (WINAPI *pSendInput) (UINT, INPUT*, size_t); +static HRESULT (WINAPI *pCoGetApartmentType)(APTTYPE *, APTTYPEQUALIFIER *); +static HRESULT (WINAPI *pCoInitializeEx)(void *, DWORD); +static void (WINAPI *pCoUninitialize)(void); +static HRESULT (WINAPI *pCoCreateInstance)(REFCLSID, IUnknown *, DWORD, REFIID, void **);
/*
- msgspy - record and analyse message traces sent to a certain window
@@ -1990,7 +1999,247 @@ static void test_InvalidIMC(void) ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); }
-START_TEST(imm32) { +static LRESULT CALLBACK com_init_test_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{
- return DefWindowProcA(hwnd, uMsg, wParam, lParam);
+}
+#define COM_INIT_TEST_APTTYPE(apttype) com_init_test_apttype(apttype, __LINE__) +static void com_init_test_apttype(APTTYPE expected_type, unsigned int line) +{
- APTTYPEQUALIFIER apttypequal;
- HRESULT hr, hr_expected;
- APTTYPE apttype;
- IUnknown *unk;
- if (expected_type == -1)
hr_expected = CO_E_NOTINITIALIZED;
- else
hr_expected = S_OK;
- hr = pCoCreateInstance(&CLSID_InternetZoneManager, NULL, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void **)&unk);
- ok_(__FILE__, line)(hr == hr_expected, "Unexpected hr %#x.\n", hr);
- if (SUCCEEDED(hr))
IUnknown_Release(unk);
- hr = pCoGetApartmentType(&apttype, &apttypequal);
- ok_(__FILE__, line)(hr == (expected_type == -1 ? CO_E_NOTINITIALIZED : S_OK),
"Failed to get apartment type, hr %#x.\n", hr);
- if (SUCCEEDED(hr))
ok_(__FILE__, line)(apttype == expected_type && apttypequal == APTTYPEQUALIFIER_NONE,
"Unexpected apartment type %u/%u.\n", apttype, apttypequal);
+}
+static HWND test_com_create_window(DWORD style) +{
- WNDCLASSA clsA;
- HWND hwnd;
- clsA.style = 0;
- clsA.lpfnWndProc = com_init_test_wndproc;
- clsA.cbClsExtra = 0;
- clsA.cbWndExtra = 0;
- clsA.hInstance = GetModuleHandleA(NULL);
- clsA.hIcon = 0;
- clsA.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
- clsA.hbrBackground = NULL;
- clsA.lpszMenuName = NULL;
- clsA.lpszClassName = "COMInitTest";
- RegisterClassA(&clsA);
- hwnd = CreateWindowExA(0, "COMInitTest", "Test window", WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
WS_MAXIMIZEBOX | style, 0, 0, 100, 100, GetDesktopWindow(), NULL, GetModuleHandleA(NULL), NULL);
- ok(hwnd != NULL, "Failed to create a test window.\n");
- return hwnd;
+}
+static void test_com_init(const char *testname) +{
- WNDCLASSA clsA;
- HMODULE hmod;
- HRESULT hr;
- HWND hwnd;
- clsA.style = 0;
- clsA.lpfnWndProc = com_init_test_wndproc;
- clsA.cbClsExtra = 0;
- clsA.cbWndExtra = 0;
- clsA.hInstance = GetModuleHandleA(NULL);
- clsA.hIcon = 0;
- clsA.hCursor = LoadCursorA(0, (LPCSTR)IDC_ARROW);
- clsA.hbrBackground = NULL;
- clsA.lpszMenuName = NULL;
- clsA.lpszClassName = "COMInitTest";
- RegisterClassA(&clsA);
- hmod = LoadLibraryA("ole32.dll");
- pCoGetApartmentType = (void *)GetProcAddress(hmod, "CoGetApartmentType");
- pCoInitializeEx = (void *)GetProcAddress(hmod, "CoInitializeEx");
- pCoUninitialize = (void *)GetProcAddress(hmod, "CoUninitialize");
- pCoCreateInstance = (void *)GetProcAddress(hmod, "CoCreateInstance");
- if (!strcmp(testname, "visible"))
- {
COM_INIT_TEST_APTTYPE(-1);
hwnd = test_com_create_window(WS_VISIBLE);
COM_INIT_TEST_APTTYPE(APTTYPE_MAINSTA);
hr = pCoInitializeEx(NULL, COINIT_MULTITHREADED);
ok(hr == S_OK, "Failed to re-initialize, hr %#x.\n", hr);
COM_INIT_TEST_APTTYPE(APTTYPE_MTA);
pCoUninitialize();
COM_INIT_TEST_APTTYPE(-1);
DestroyWindow(hwnd);
- }
- else if (!strcmp(testname, "invisible"))
- {
COM_INIT_TEST_APTTYPE(-1);
hwnd = test_com_create_window(0);
COM_INIT_TEST_APTTYPE(-1);
ShowWindow(hwnd, SW_SHOW);
COM_INIT_TEST_APTTYPE(APTTYPE_MAINSTA);
hr = pCoInitializeEx(NULL, COINIT_MULTITHREADED);
ok(hr == S_OK, "Failed to re-initialize, hr %#x.\n", hr);
COM_INIT_TEST_APTTYPE(APTTYPE_MTA);
pCoUninitialize();
COM_INIT_TEST_APTTYPE(-1);
DestroyWindow(hwnd);
- }
- else if (!strcmp(testname, "imedisabled"))
- {
COM_INIT_TEST_APTTYPE(-1);
ImmDisableIME(-1);
hwnd = test_com_create_window(WS_VISIBLE);
COM_INIT_TEST_APTTYPE(-1);
hr = pCoInitializeEx(NULL, COINIT_MULTITHREADED);
ok(hr == S_OK, "Failed to re-initialize, hr %#x.\n", hr);
COM_INIT_TEST_APTTYPE(APTTYPE_MTA);
pCoUninitialize();
COM_INIT_TEST_APTTYPE(-1);
DestroyWindow(hwnd);
- }
- else if (!strcmp(testname, "sta"))
- {
COM_INIT_TEST_APTTYPE(-1);
hwnd = test_com_create_window(WS_VISIBLE);
COM_INIT_TEST_APTTYPE(APTTYPE_MAINSTA);
/* Initialize for STA explicitly, S_OK is forced, with incremented counter. */
hr = pCoInitializeEx(0, COINIT_APARTMENTTHREADED);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
COM_INIT_TEST_APTTYPE(APTTYPE_MAINSTA);
pCoUninitialize();
COM_INIT_TEST_APTTYPE(APTTYPE_MAINSTA);
DestroyWindow(hwnd);
- }
- else if (!strcmp(testname, "uninit"))
- {
COM_INIT_TEST_APTTYPE(-1);
hwnd = test_com_create_window(WS_VISIBLE);
COM_INIT_TEST_APTTYPE(APTTYPE_MAINSTA);
pCoUninitialize();
COM_INIT_TEST_APTTYPE(-1);
DestroyWindow(hwnd);
hwnd = test_com_create_window(WS_VISIBLE);
COM_INIT_TEST_APTTYPE(APTTYPE_MAINSTA);
DestroyWindow(hwnd);
- }
- else
ok(0, "Unknown test name %s.\n", testname);
+}
+static void test_com_initialization(void) +{
- char path_name[MAX_PATH];
- PROCESS_INFORMATION info;
- STARTUPINFOA startup;
- HMODULE hmod;
- char **argv;
- int i;
- static const char *test_params[] =
- {
"imedisabled",
"visible",
"invisible",
"sta",
"uninit",
- };
- hmod = LoadLibraryA("ole32.dll");
- pCoGetApartmentType = (void *)GetProcAddress(hmod, "CoGetApartmentType");
- FreeLibrary(hmod);
- if (!pCoGetApartmentType)
- {
win_skip("Skipping COM initialization tests on older system.\n");
return;
- }
- winetest_get_mainargs( &argv );
- for (i = 0; i < ARRAY_SIZE(test_params); ++i)
- {
memset( &startup, 0, sizeof(startup) );
startup.cb = sizeof( startup );
sprintf( path_name, "%s imm32 %s", argv[0], test_params[i] );
ok( CreateProcessA( NULL, path_name, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info ),
"CreateProcess failed.\n" );
winetest_wait_child_process( info.hProcess );
CloseHandle( info.hProcess );
CloseHandle( info.hThread );
- }
+}
+START_TEST(imm32) +{
- char **argv;
- int argc = winetest_get_mainargs( &argv );
- if (argc >= 3)
- {
test_com_init( argv[2] );
return;
- }
if (init()) { test_ImmNotifyIME();
@@ -2017,6 +2266,7 @@ START_TEST(imm32) { if (pSendInput) test_ime_processkey(); else win_skip("SendInput is not available\n");
}test_com_initialization(); } cleanup();
diff --git a/dlls/user32/focus.c b/dlls/user32/focus.c index f1c883167e..50b3323ae9 100644 --- a/dlls/user32/focus.c +++ b/dlls/user32/focus.c @@ -156,6 +156,8 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) (LPARAM)previous ); if (GetAncestor( hwnd, GA_PARENT ) == GetDesktopWindow()) PostMessageW( GetDesktopWindow(), WM_PARENTNOTIFY, WM_NCACTIVATE, (LPARAM)hwnd );
imm_activate_window( hwnd ); } /* now change focus if necessary */
diff --git a/dlls/user32/misc.c b/dlls/user32/misc.c index d28cd9fd05..cfaa1b94db 100644 --- a/dlls/user32/misc.c +++ b/dlls/user32/misc.c @@ -43,6 +43,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(win); static HWND (WINAPI *imm_get_ui_window)(HKL); BOOL (WINAPI *imm_register_window)(HWND) = NULL; void (WINAPI *imm_unregister_window)(HWND) = NULL; +void (WINAPI *imm_activate_window)(HWND) = NULL;
/* MSIME messages */ static UINT WM_MSIME_SERVICE; @@ -480,6 +481,7 @@ BOOL WINAPI User32InitializeImmEntryTable(DWORD magic) imm_get_ui_window = (void*)GetProcAddress(imm32, "__wine_get_ui_window"); imm_register_window = (void*)GetProcAddress(imm32, "__wine_register_window"); imm_unregister_window = (void*)GetProcAddress(imm32, "__wine_unregister_window");
- imm_activate_window = (void*)GetProcAddress(imm32, "__wine_activate_window"); if (!imm_get_ui_window) FIXME("native imm32.dll not supported\n"); return TRUE;
diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h index 514cf6753f..b86831d7d9 100644 --- a/dlls/user32/user_private.h +++ b/dlls/user32/user_private.h @@ -197,6 +197,7 @@ C_ASSERT( sizeof(struct user_thread_info) <= sizeof(((TEB *)0)->Win32ClientInfo) extern INT global_key_state_counter DECLSPEC_HIDDEN; extern BOOL (WINAPI *imm_register_window)(HWND) DECLSPEC_HIDDEN; extern void (WINAPI *imm_unregister_window)(HWND) DECLSPEC_HIDDEN; +extern void (WINAPI *imm_activate_window)(HWND) DECLSPEC_HIDDEN;
struct user_key_state_info {