From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 21 ++++++++++++++++++--- dlls/imm32/tests/imm32.c | 7 ++++--- 2 files changed, 22 insertions(+), 6 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 682fb748f2f..28344b909d6 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -3033,10 +3033,25 @@ BOOL WINAPI ImmDisableTextFrameService(DWORD idThread) * ImmEnumInputContext(IMM32.@) */
-BOOL WINAPI ImmEnumInputContext(DWORD idThread, IMCENUMPROC lpfn, LPARAM lParam) +BOOL WINAPI ImmEnumInputContext( DWORD thread, IMCENUMPROC callback, LPARAM lparam ) { - FIXME("Stub\n"); - return FALSE; + HIMC buffer[256]; + NTSTATUS status; + UINT i, size; + + TRACE( "thread %lu, callback %p, lparam %#Ix\n", thread, callback, lparam ); + + if ((status = NtUserBuildHimcList( thread, ARRAY_SIZE(buffer), buffer, &size ))) + { + RtlSetLastWin32Error( RtlNtStatusToDosError( status ) ); + WARN( "NtUserBuildHimcList returned %#lx\n", status ); + return FALSE; + } + + if (size == ARRAY_SIZE(buffer)) FIXME( "NtUserBuildHimcList returned %u handles\n", size ); + for (i = 0; i < size; i++) if (!callback( buffer[i], lparam )) return FALSE; + + return TRUE; }
/*********************************************************************** diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c index 6f98fb4f645..31068ca2d20 100644 --- a/dlls/imm32/tests/imm32.c +++ b/dlls/imm32/tests/imm32.c @@ -2930,18 +2930,19 @@ static void test_ImmEnumInputContext(void) { HIMC himc;
- todo_wine ok_ret( 1, ImmEnumInputContext( 0, enum_get_context, (LPARAM)&default_himc ) ); + ok_ret( 1, ImmEnumInputContext( -1, enum_find_context, 0 ) ); + ok_ret( 1, ImmEnumInputContext( GetCurrentThreadId(), enum_find_context, 0 ) ); + + todo_wine ok_ret( 0, ImmEnumInputContext( 1, enum_find_context, 0 ) ); todo_wine - ok_ret( 1, ImmEnumInputContext( GetCurrentThreadId(), enum_find_context, 0 ) ); ok_ret( 0, ImmEnumInputContext( GetCurrentProcessId(), enum_find_context, 0 ) );
himc = ImmCreateContext(); ok_ne( NULL, himc, HIMC, "%p" ); ok_ret( 0, ImmEnumInputContext( GetCurrentThreadId(), enum_find_context, (LPARAM)himc ) ); ok_ret( 1, ImmDestroyContext( himc ) ); - todo_wine ok_ret( 1, ImmEnumInputContext( GetCurrentThreadId(), enum_find_context, (LPARAM)himc ) ); }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 28344b909d6..1a0f0579c0b 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -623,28 +623,27 @@ static void IMM_FreeAllImmHkl(void) } }
-BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpReserved) +BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved ) { - TRACE("%p, %lx, %p\n",hInstDLL,fdwReason,lpReserved); - switch (fdwReason) + TRACE( "instance %p, reason %lx, reserved %p\n", instance, reason, reserved ); + + switch (reason) { - case DLL_PROCESS_ATTACH: - if (!User32InitializeImmEntryTable(IMM_INIT_MAGIC)) - { - return FALSE; - } - break; - case DLL_THREAD_ATTACH: - break; - case DLL_THREAD_DETACH: - IMM_FreeThreadData(); - break; - case DLL_PROCESS_DETACH: - if (lpReserved) break; - IMM_FreeThreadData(); - IMM_FreeAllImmHkl(); - break; + case DLL_PROCESS_ATTACH: + if (!User32InitializeImmEntryTable( IMM_INIT_MAGIC )) return FALSE; + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + IMM_FreeThreadData(); + break; + case DLL_PROCESS_DETACH: + if (reserved) break; + IMM_FreeThreadData(); + IMM_FreeAllImmHkl(); + break; } + return TRUE; }
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 1 + dlls/win32u/tests/win32u.c | 6 ------ 2 files changed, 1 insertion(+), 6 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 1a0f0579c0b..6d22516dbf0 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -633,6 +633,7 @@ BOOL WINAPI DllMain( HINSTANCE instance, DWORD reason, void *reserved ) if (!User32InitializeImmEntryTable( IMM_INIT_MAGIC )) return FALSE; break; case DLL_THREAD_ATTACH: + NtUserGetThreadInfo()->default_imc = (UINT_PTR)NtUserCreateInputContext( 0 ); break; case DLL_THREAD_DETACH: IMM_FreeThreadData(); diff --git a/dlls/win32u/tests/win32u.c b/dlls/win32u/tests/win32u.c index 04e5a2e7932..b309b51ddd4 100644 --- a/dlls/win32u/tests/win32u.c +++ b/dlls/win32u/tests/win32u.c @@ -333,7 +333,6 @@ static DWORD CALLBACK test_NtUserBuildHimcList_thread( void *arg ) memset( buf, 0xcd, sizeof(buf) ); status = NtUserBuildHimcList( GetCurrentThreadId(), ARRAYSIZE( buf ), buf, &size ); ok( !status, "NtUserBuildHimcList failed: %#lx\n", status ); - todo_wine ok( size == 1, "size = %u\n", size ); ok( !!buf[0], "buf[0] = %p\n", buf[0] );
@@ -346,16 +345,11 @@ static DWORD CALLBACK test_NtUserBuildHimcList_thread( void *arg ) memset( buf, 0xcd, sizeof(buf) ); status = NtUserBuildHimcList( -1, ARRAYSIZE( buf ), buf, &size ); ok( !status, "NtUserBuildHimcList failed: %#lx\n", status ); - todo_wine ok( size == 3, "size = %u\n", size );
qsort( buf, size, sizeof(*buf), himc_compare ); - /* FIXME: Wine only lazily creates a default thread IMC */ - todo_wine ok( buf[0] == himc[0], "buf[0] = %p\n", buf[0] ); - todo_wine ok( buf[1] == himc[1], "buf[1] = %p\n", buf[1] ); - todo_wine ok( buf[2] == himc[2], "buf[2] = %p\n", buf[2] );
return 0;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index 6d22516dbf0..ddf16c418cd 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -94,7 +94,6 @@ typedef struct tagInputContextData
struct ime *ime; UINT lastVK; - BOOL threadDefault; } InputContextData;
#define WINE_IMC_VALID_MAGIC 0x56434D49 @@ -404,16 +403,6 @@ static void imm_coinit_thread(void) InitOnceExecuteOnce(&init_ole32_once, init_ole32_funcs, NULL, NULL); }
-static BOOL IMM_IsDefaultContext(HIMC imc) -{ - InputContextData *data = get_imc_data(imc); - - if (!data) - return FALSE; - - return data->threadDefault; -} - static InputContextData *query_imc_data(HIMC handle) { InputContextData *ret; @@ -868,7 +857,6 @@ static InputContextData *create_input_context(HIMC default_imc) new_context = calloc( 1, sizeof(InputContextData) );
/* Load the IME */ - new_context->threadDefault = !!default_imc; if (!(new_context->ime = ime_acquire( GetKeyboardLayout( 0 ) ))) { TRACE("IME dll could not be loaded\n"); @@ -953,7 +941,8 @@ static BOOL IMM_DestroyContext(HIMC hIMC) */ BOOL WINAPI ImmDestroyContext(HIMC hIMC) { - if (!IMM_IsDefaultContext(hIMC) && !IMM_IsCrossThreadAccess(NULL, hIMC)) + if ((UINT_PTR)hIMC == NtUserGetThreadInfo()->default_imc) return FALSE; + if (!IMM_IsCrossThreadAccess(NULL, hIMC)) return IMM_DestroyContext(hIMC); else return FALSE;
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/imm32/imm.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-)
diff --git a/dlls/imm32/imm.c b/dlls/imm32/imm.c index ddf16c418cd..1e621832bba 100644 --- a/dlls/imm32/imm.c +++ b/dlls/imm32/imm.c @@ -682,15 +682,10 @@ static HIMCC ImmCreateBlankCompStr(void) return rc; }
-static BOOL IMM_IsCrossThreadAccess(HWND hWnd, HIMC hIMC) +static BOOL IMM_IsCrossThreadAccess(HIMC hIMC) { InputContextData *data;
- if (hWnd) - { - DWORD thread = GetWindowThreadProcessId(hWnd, NULL); - if (thread != GetCurrentThreadId()) return TRUE; - } data = get_imc_data(hIMC); if (data && data->threadID != GetCurrentThreadId()) return TRUE; @@ -942,7 +937,7 @@ static BOOL IMM_DestroyContext(HIMC hIMC) BOOL WINAPI ImmDestroyContext(HIMC hIMC) { if ((UINT_PTR)hIMC == NtUserGetThreadInfo()->default_imc) return FALSE; - if (!IMM_IsCrossThreadAccess(NULL, hIMC)) + if (!IMM_IsCrossThreadAccess(hIMC)) return IMM_DestroyContext(hIMC); else return FALSE; @@ -2244,7 +2239,7 @@ BOOL WINAPI ImmSetCandidateWindow( if (!data || !lpCandidate) return FALSE;
- if (IMM_IsCrossThreadAccess(NULL, hIMC)) + if (IMM_IsCrossThreadAccess(hIMC)) return FALSE;
TRACE("\t%lx, %lx, %s, %s\n", @@ -2276,7 +2271,7 @@ BOOL WINAPI ImmSetCompositionFontA(HIMC hIMC, LPLOGFONTA lplf) return FALSE; }
- if (IMM_IsCrossThreadAccess(NULL, hIMC)) + if (IMM_IsCrossThreadAccess(hIMC)) return FALSE;
memcpy(&data->IMC.lfFont.W,lplf,sizeof(LOGFONTA)); @@ -2302,7 +2297,7 @@ BOOL WINAPI ImmSetCompositionFontW(HIMC hIMC, LPLOGFONTW lplf) return FALSE; }
- if (IMM_IsCrossThreadAccess(NULL, hIMC)) + if (IMM_IsCrossThreadAccess(hIMC)) return FALSE;
data->IMC.lfFont.W = *lplf; @@ -2333,7 +2328,7 @@ BOOL WINAPI ImmSetCompositionStringA( if (!data) return FALSE;
- if (IMM_IsCrossThreadAccess(NULL, hIMC)) + if (IMM_IsCrossThreadAccess(hIMC)) return FALSE;
if (!(dwIndex == SCS_SETSTR || @@ -2390,7 +2385,7 @@ BOOL WINAPI ImmSetCompositionStringW( if (!data) return FALSE;
- if (IMM_IsCrossThreadAccess(NULL, hIMC)) + if (IMM_IsCrossThreadAccess(hIMC)) return FALSE;
if (!(dwIndex == SCS_SETSTR || @@ -2451,7 +2446,7 @@ BOOL WINAPI ImmSetCompositionWindow( return FALSE; }
- if (IMM_IsCrossThreadAccess(NULL, hIMC)) + if (IMM_IsCrossThreadAccess(hIMC)) return FALSE;
data->IMC.cfCompForm = *lpCompForm; @@ -2487,7 +2482,7 @@ BOOL WINAPI ImmSetConversionStatus( return FALSE; }
- if (IMM_IsCrossThreadAccess(NULL, hIMC)) + if (IMM_IsCrossThreadAccess(hIMC)) return FALSE;
if ( fdwConversion != data->IMC.fdwConversion ) @@ -2523,7 +2518,7 @@ BOOL WINAPI ImmSetOpenStatus(HIMC hIMC, BOOL fOpen) return FALSE; }
- if (IMM_IsCrossThreadAccess(NULL, hIMC)) + if (IMM_IsCrossThreadAccess(hIMC)) return FALSE;
if (data->ime->ui_hwnd == NULL) @@ -2560,7 +2555,7 @@ BOOL WINAPI ImmSetStatusWindowPos(HIMC hIMC, LPPOINT lpptPos) return FALSE; }
- if (IMM_IsCrossThreadAccess(NULL, hIMC)) + if (IMM_IsCrossThreadAccess(hIMC)) return FALSE;
TRACE("\t%s\n", wine_dbgstr_point(lpptPos));
Jacek Caban (@jacek) commented about dlls/imm32/imm.c:
if (!User32InitializeImmEntryTable( IMM_INIT_MAGIC )) return FALSE; break; case DLL_THREAD_ATTACH:
NtUserGetThreadInfo()->default_imc = (UINT_PTR)NtUserCreateInputContext( 0 );
Another solution would be to call get_default_input_context from NtUserBuildHimcList to make sure it's initialized. It would save an extra server call for each new thread. Lazy initialization would not be enough for non-current threads, so we may need something like this if it's important.
On Tue Mar 21 15:12:22 2023 +0000, Jacek Caban wrote:
Another solution would be to call get_default_input_context from NtUserBuildHimcList to make sure it's initialized. It would save an extra server call for each new thread. Lazy initialization would not be enough for non-current threads, so we may need something like this if it's important.
Well, it's not really important and we can probably keep the lazy init, but I'm also not sure that an additional server call is so bad here, is it?
On Tue Mar 21 16:08:46 2023 +0000, Rémi Bernon wrote:
Well, it's not really important and we can probably keep the lazy init, but I'm also not sure that an additional server call is so bad here, is it?
No, I don't think it's a blocker, it just feels like win32u's responsibility. Note that DLL_THREAD_ATTACH is also not a complete solution: it will not handle threads that were created before loading imm32.dll (so triggering lazy initialization in NtUserBuildHimcList may be interesting even if we take this patch).
Note that DLL_THREAD_ATTACH is also not a complete solution: it will not handle threads that were created before loading imm32.dll (so triggering lazy initialization in NtUserBuildHimcList may be interesting even if we take this patch).
Good point. I'll do something else then.