Commit ea0c992f authored by Piotr Caban's avatar Piotr Caban Committed by Alexandre Julliard

imm32: Initialize COM in ImmSetActiveContext.

Loosely based on a patch by Nikolay. Signed-off-by: 's avatarPiotr Caban <piotr@codeweavers.com> Signed-off-by: 's avatarAlexandre Julliard <julliard@winehq.org>
parent 01e072bb
MODULE = imm32.dll MODULE = imm32.dll
IMPORTLIB = imm32 IMPORTLIB = imm32
IMPORTS = user32 gdi32 advapi32 IMPORTS = user32 gdi32 advapi32 ole32
C_SRCS = \ C_SRCS = \
imm.c imm.c
......
...@@ -19,9 +19,13 @@ ...@@ -19,9 +19,13 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
#define COBJMACROS
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
#include "initguid.h"
#include "objbase.h"
#include "windef.h" #include "windef.h"
#include "winbase.h" #include "winbase.h"
#include "wingdi.h" #include "wingdi.h"
...@@ -94,6 +98,15 @@ typedef struct _tagIMMThreadData { ...@@ -94,6 +98,15 @@ typedef struct _tagIMMThreadData {
HWND hwndDefault; HWND hwndDefault;
BOOL disableIME; BOOL disableIME;
DWORD windowRefs; DWORD windowRefs;
IInitializeSpy IInitializeSpy_iface;
ULARGE_INTEGER spy_cookie;
enum
{
IMM_APT_INIT = 0x1,
IMM_APT_CREATED = 0x2,
IMM_APT_CAN_FREE = 0x4,
IMM_APT_BROKEN = 0x8
} apt_flags;
} IMMThreadData; } IMMThreadData;
static struct list ImmHklList = LIST_INIT(ImmHklList); static struct list ImmHklList = LIST_INIT(ImmHklList);
...@@ -227,6 +240,141 @@ static DWORD convert_candidatelist_AtoW( ...@@ -227,6 +240,141 @@ static DWORD convert_candidatelist_AtoW(
return ret; return ret;
} }
static void imm_coinit_thread(IMMThreadData *thread_data)
{
HRESULT hr;
TRACE("implicit COM initialization\n");
if (thread_data->threadID != GetCurrentThreadId())
return;
if (thread_data->apt_flags & (IMM_APT_INIT | IMM_APT_BROKEN))
return;
thread_data->apt_flags |= IMM_APT_INIT;
if(!thread_data->spy_cookie.QuadPart)
{
hr = CoRegisterInitializeSpy(&thread_data->IInitializeSpy_iface,
&thread_data->spy_cookie);
if (FAILED(hr))
return;
}
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
if (SUCCEEDED(hr))
thread_data->apt_flags |= IMM_APT_CREATED;
}
static void imm_couninit_thread(IMMThreadData *thread_data, BOOL cleanup)
{
TRACE("implicit COM deinitialization\n");
if (thread_data->apt_flags & IMM_APT_BROKEN)
return;
if (cleanup && thread_data->spy_cookie.QuadPart)
{
CoRevokeInitializeSpy(thread_data->spy_cookie);
thread_data->spy_cookie.QuadPart = 0;
}
if (!(thread_data->apt_flags & IMM_APT_INIT))
return;
thread_data->apt_flags &= ~IMM_APT_INIT;
if (thread_data->apt_flags & IMM_APT_CREATED)
{
thread_data->apt_flags &= ~IMM_APT_CREATED;
if (thread_data->apt_flags & IMM_APT_CAN_FREE)
CoUninitialize();
}
if (cleanup)
thread_data->apt_flags = 0;
}
static inline IMMThreadData *impl_from_IInitializeSpy(IInitializeSpy *iface)
{
return CONTAINING_RECORD(iface, IMMThreadData, IInitializeSpy_iface);
}
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 HRESULT WINAPI InitializeSpy_PreInitialize(IInitializeSpy *iface,
DWORD coinit, DWORD refs)
{
IMMThreadData *thread_data = impl_from_IInitializeSpy(iface);
if ((thread_data->apt_flags & IMM_APT_CREATED) &&
!(coinit & COINIT_APARTMENTTHREADED) && refs == 1)
{
imm_couninit_thread(thread_data, TRUE);
thread_data->apt_flags |= IMM_APT_BROKEN;
}
return S_OK;
}
static HRESULT WINAPI InitializeSpy_PostInitialize(IInitializeSpy *iface,
HRESULT hr, DWORD coinit, DWORD refs)
{
IMMThreadData *thread_data = impl_from_IInitializeSpy(iface);
if ((thread_data->apt_flags & IMM_APT_CREATED) && hr == S_FALSE && refs == 2)
hr = S_OK;
if (SUCCEEDED(hr))
thread_data->apt_flags |= IMM_APT_CAN_FREE;
return hr;
}
static HRESULT WINAPI InitializeSpy_PreUninitialize(IInitializeSpy *iface, DWORD refs)
{
return S_OK;
}
static HRESULT WINAPI InitializeSpy_PostUninitialize(IInitializeSpy *iface, DWORD refs)
{
IMMThreadData *thread_data = impl_from_IInitializeSpy(iface);
if (refs == 1 && !thread_data->windowRefs)
imm_couninit_thread(thread_data, FALSE);
else if (!refs)
thread_data->apt_flags &= ~IMM_APT_CAN_FREE;
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) static IMMThreadData *IMM_GetThreadData(HWND hwnd, DWORD thread)
{ {
IMMThreadData *data; IMMThreadData *data;
...@@ -253,6 +401,7 @@ static IMMThreadData *IMM_GetThreadData(HWND hwnd, DWORD thread) ...@@ -253,6 +401,7 @@ static IMMThreadData *IMM_GetThreadData(HWND hwnd, DWORD thread)
if (data->threadID == thread) return data; if (data->threadID == thread) return data;
data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data)); data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data));
data->IInitializeSpy_iface.lpVtbl = &InitializeSpyVtbl;
data->threadID = thread; data->threadID = thread;
list_add_head(&ImmThreadDataList,&data->entry); list_add_head(&ImmThreadDataList,&data->entry);
TRACE("Thread Data Created (%x)\n",thread); TRACE("Thread Data Created (%x)\n",thread);
...@@ -281,6 +430,7 @@ static void IMM_FreeThreadData(void) ...@@ -281,6 +430,7 @@ static void IMM_FreeThreadData(void)
list_remove(&data->entry); list_remove(&data->entry);
LeaveCriticalSection(&threaddata_cs); LeaveCriticalSection(&threaddata_cs);
IMM_DestroyContext(data->defaultContext); IMM_DestroyContext(data->defaultContext);
imm_couninit_thread(data, TRUE);
HeapFree(GetProcessHeap(),0,data); HeapFree(GetProcessHeap(),0,data);
TRACE("Thread Data Destroyed\n"); TRACE("Thread Data Destroyed\n");
return; return;
...@@ -556,12 +706,20 @@ static BOOL IMM_IsCrossThreadAccess(HWND hWnd, HIMC hIMC) ...@@ -556,12 +706,20 @@ static BOOL IMM_IsCrossThreadAccess(HWND hWnd, HIMC hIMC)
BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC himc, BOOL activate) BOOL WINAPI ImmSetActiveContext(HWND hwnd, HIMC himc, BOOL activate)
{ {
InputContextData *data = get_imc_data(himc); InputContextData *data = get_imc_data(himc);
IMMThreadData *thread_data;
TRACE("(%p, %p, %x)\n", hwnd, himc, activate); TRACE("(%p, %p, %x)\n", hwnd, himc, activate);
if (himc && !data && activate) if (himc && !data && activate)
return FALSE; return FALSE;
thread_data = IMM_GetThreadData(hwnd, 0);
if (thread_data)
{
imm_coinit_thread(thread_data);
LeaveCriticalSection(&threaddata_cs);
}
if (data) if (data)
{ {
data->IMC.hWnd = activate ? hwnd : NULL; data->IMC.hWnd = activate ? hwnd : NULL;
...@@ -1719,8 +1877,9 @@ void WINAPI __wine_unregister_window(HWND hwnd) ...@@ -1719,8 +1877,9 @@ void WINAPI __wine_unregister_window(HWND hwnd)
thread_data->windowRefs, thread_data->hwndDefault); thread_data->windowRefs, thread_data->hwndDefault);
/* Destroy default IME window */ /* Destroy default IME window */
if (thread_data->windowRefs == 0 && thread_data->hwndDefault) if (thread_data->windowRefs == 0)
{ {
imm_couninit_thread(thread_data, TRUE);
to_destroy = thread_data->hwndDefault; to_destroy = thread_data->hwndDefault;
thread_data->hwndDefault = NULL; thread_data->hwndDefault = NULL;
} }
......
TESTDLL = imm32.dll TESTDLL = imm32.dll
IMPORTS = imm32 user32 IMPORTS = imm32 ole32 user32
C_SRCS = \ C_SRCS = \
imm32.c imm32.c
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <stdio.h> #include <stdio.h>
#include "wine/test.h" #include "wine/test.h"
#include "objbase.h"
#include "winuser.h" #include "winuser.h"
#include "wingdi.h" #include "wingdi.h"
#include "imm.h" #include "imm.h"
...@@ -273,9 +274,28 @@ static LRESULT WINAPI wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) ...@@ -273,9 +274,28 @@ static LRESULT WINAPI wndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
return DefWindowProcA(hWnd,msg,wParam,lParam); return DefWindowProcA(hWnd,msg,wParam,lParam);
} }
static BOOL is_ime_enabled(void)
{
HIMC himc;
HWND wnd;
wnd = CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0);
ok(wnd != NULL, "CreateWindow failed\n");
himc = ImmGetContext(wnd);
if (!himc)
{
DestroyWindow(wnd);
return FALSE;
}
ImmReleaseContext(wnd, himc);
DestroyWindow(wnd);
return TRUE;
}
static BOOL init(void) { static BOOL init(void) {
WNDCLASSEXA wc; WNDCLASSEXA wc;
HIMC imc;
HMODULE hmod,huser; HMODULE hmod,huser;
hmod = GetModuleHandleA("imm32.dll"); hmod = GetModuleHandleA("imm32.dll");
...@@ -306,14 +326,6 @@ static BOOL init(void) { ...@@ -306,14 +326,6 @@ static BOOL init(void) {
if (!hwnd) if (!hwnd)
return FALSE; return FALSE;
imc = ImmGetContext(hwnd);
if (!imc)
{
win_skip("IME support not implemented\n");
return FALSE;
}
ImmReleaseContext(hwnd, imc);
ShowWindow(hwnd, SW_SHOWNORMAL); ShowWindow(hwnd, SW_SHOWNORMAL);
UpdateWindow(hwnd); UpdateWindow(hwnd);
...@@ -2122,7 +2134,122 @@ static void test_InvalidIMC(void) ...@@ -2122,7 +2134,122 @@ static void test_InvalidIMC(void)
ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret); ok(ret == ERROR_INVALID_HANDLE, "wrong last error %08x!\n", ret);
} }
#define test_apttype(apttype) _test_apttype(apttype, __LINE__)
static void _test_apttype(APTTYPE apttype, unsigned int line)
{
APTTYPEQUALIFIER qualifier;
HRESULT hr, hr_expected;
APTTYPE type;
hr = CoGetApartmentType(&type, &qualifier);
hr_expected = (apttype == -1 ? CO_E_NOTINITIALIZED : S_OK);
ok_(__FILE__, line)(hr == hr_expected, "CoGetApartmentType returned %x\n", hr);
if (FAILED(hr))
return;
ok_(__FILE__, line)(type == apttype, "type %x\n", type);
ok_(__FILE__, line)(!qualifier, "qualifier %x\n", qualifier);
}
static DWORD WINAPI com_initialization_thread(void *arg)
{
HRESULT hr;
BOOL r;
test_apttype(-1);
ImmDisableIME(GetCurrentThreadId());
r = ImmSetActiveContext(NULL, NULL, TRUE);
ok(r, "ImmSetActiveContext failed\n");
test_apttype(APTTYPE_MAINSTA);
hr = CoInitialize(NULL);
ok(hr == S_OK, "CoInitialize returned %x\n", hr);
CoUninitialize();
test_apttype(-1);
/* Changes IMM behavior so it no longer initialized COM */
r = ImmSetActiveContext(NULL, NULL, TRUE);
ok(r, "ImmSetActiveContext failed\n");
test_apttype(APTTYPE_MAINSTA);
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
ok(hr == S_OK, "CoInitialize returned %x\n", hr);
test_apttype(APTTYPE_MTA);
CoUninitialize();
test_apttype(-1);
r = ImmSetActiveContext(NULL, NULL, TRUE);
ok(r, "ImmSetActiveContext failed\n");
test_apttype(-1);
return 0;
}
static void test_com_initialization(void)
{
HANDLE thread;
HRESULT hr;
HWND wnd;
BOOL r;
thread = CreateThread(NULL, 0, com_initialization_thread, NULL, 0, NULL);
ok(thread != NULL, "CreateThread failed\n");
WaitForSingleObject(thread, INFINITE);
CloseHandle(thread);
test_apttype(-1);
r = ImmSetActiveContext(NULL, (HIMC)0xdeadbeef, TRUE);
ok(!r, "ImmSetActiveContext succeeded\n");
test_apttype(-1);
r = ImmSetActiveContext(NULL, NULL, TRUE);
ok(r, "ImmSetActiveContext failed\n");
test_apttype(APTTYPE_MAINSTA);
/* Force default IME window destruction */
wnd = CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0);
ok(wnd != NULL, "CreateWindow failed\n");
DestroyWindow(wnd);
test_apttype(-1);
r = ImmSetActiveContext(NULL, NULL, TRUE);
ok(r, "ImmSetActiveContext failed\n");
test_apttype(APTTYPE_MAINSTA);
hr = CoInitialize(NULL);
ok(hr == S_OK, "CoInitialize returned %x\n", hr);
CoUninitialize();
test_apttype(-1);
/* Test with default IME window created */
wnd = CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0);
ok(wnd != NULL, "CreateWindow failed\n");
test_apttype(-1);
r = ImmSetActiveContext(NULL, NULL, TRUE);
ok(r, "ImmSetActiveContext failed\n");
test_apttype(APTTYPE_MAINSTA);
hr = CoInitialize(NULL);
ok(hr == S_OK, "CoInitialize returned %x\n", hr);
CoUninitialize();
test_apttype(APTTYPE_MAINSTA);
DestroyWindow(wnd);
test_apttype(-1);
wnd = CreateWindowA("static", "static", 0, 0, 0, 0, 0, 0, 0, 0, 0);
ok(wnd != NULL, "CreateWindow failed\n");
r = ImmSetActiveContext(NULL, NULL, TRUE);
CoUninitialize();
hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
ok(hr == S_OK, "CoInitialize returned %x\n", hr);
test_apttype(APTTYPE_MTA);
DestroyWindow(wnd);
test_apttype(-1);
}
START_TEST(imm32) { START_TEST(imm32) {
if (!is_ime_enabled())
{
win_skip("IME support not implemented\n");
return;
}
test_com_initialization();
if (init()) if (init())
{ {
test_ImmNotifyIME(); test_ImmNotifyIME();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment