1 /*
2 * PROJECT: ReactOS IMM32
3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4 * PURPOSE: Implementing IMM32 helper functions
5 * COPYRIGHT: Copyright 1998 Patrik Stridvall
6 * Copyright 2002, 2003, 2007 CodeWeavers, Aric Stewart
7 * Copyright 2017 James Tabor <james.tabor@reactos.org>
8 * Copyright 2018 Amine Khaldi <amine.khaldi@reactos.org>
9 * Copyright 2020-2021 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
10 */
11
12 #include "precomp.h"
13
14 WINE_DEFAULT_DEBUG_CHANNEL(imm);
15
16 HANDLE ghImmHeap = NULL; // Win: pImmHeap
17
18 /* Win: PtiCurrent */
Imm32CurrentPti(VOID)19 PTHREADINFO FASTCALL Imm32CurrentPti(VOID)
20 {
21 if (NtCurrentTeb()->Win32ThreadInfo == NULL)
22 NtUserGetThreadState(THREADSTATE_GETTHREADINFO);
23 return NtCurrentTeb()->Win32ThreadInfo;
24 }
25
Imm32IsCrossThreadAccess(HIMC hIMC)26 BOOL APIENTRY Imm32IsCrossThreadAccess(HIMC hIMC)
27 {
28 DWORD_PTR dwImeThreadId = NtUserQueryInputContext(hIMC, QIC_INPUTTHREADID);
29 DWORD_PTR dwCurrentThreadId = GetCurrentThreadId();
30 return dwImeThreadId != dwCurrentThreadId;
31 }
32
33 // Win: TestWindowProcess
Imm32IsCrossProcessAccess(HWND hWnd)34 BOOL APIENTRY Imm32IsCrossProcessAccess(HWND hWnd)
35 {
36 DWORD_PTR WndPID = NtUserQueryWindow(hWnd, QUERY_WINDOW_UNIQUE_PROCESS_ID);
37 DWORD_PTR CurrentPID = (DWORD_PTR)NtCurrentTeb()->ClientId.UniqueProcess;
38 return WndPID != CurrentPID;
39 }
40
41 // Win: StrToUInt
42 HRESULT APIENTRY
Imm32StrToUInt(LPCWSTR pszText,LPDWORD pdwValue,ULONG nBase)43 Imm32StrToUInt(LPCWSTR pszText, LPDWORD pdwValue, ULONG nBase)
44 {
45 NTSTATUS Status;
46 UNICODE_STRING UnicodeString;
47 RtlInitUnicodeString(&UnicodeString, pszText);
48 Status = RtlUnicodeStringToInteger(&UnicodeString, nBase, pdwValue);
49 if (!NT_SUCCESS(Status))
50 return E_FAIL;
51 return S_OK;
52 }
53
54 // Win: UIntToStr
55 HRESULT APIENTRY
Imm32UIntToStr(DWORD dwValue,ULONG nBase,LPWSTR pszBuff,USHORT cchBuff)56 Imm32UIntToStr(DWORD dwValue, ULONG nBase, LPWSTR pszBuff, USHORT cchBuff)
57 {
58 NTSTATUS Status;
59 UNICODE_STRING UnicodeString;
60 UnicodeString.Buffer = pszBuff;
61 UnicodeString.MaximumLength = cchBuff * sizeof(WCHAR);
62 Status = RtlIntegerToUnicodeString(dwValue, nBase, &UnicodeString);
63 if (!NT_SUCCESS(Status))
64 return E_FAIL;
65 return S_OK;
66 }
67
68 /* Win: CheckCountry */
Imm32IsSystemJapaneseOrKorean(VOID)69 BOOL APIENTRY Imm32IsSystemJapaneseOrKorean(VOID)
70 {
71 LCID lcid = GetSystemDefaultLCID();
72 LANGID LangID = LANGIDFROMLCID(lcid);
73 WORD wPrimary = PRIMARYLANGID(LangID);
74 if (wPrimary != LANG_JAPANESE || wPrimary != LANG_KOREAN)
75 {
76 TRACE("The country has no special IME support\n");
77 return FALSE;
78 }
79 return TRUE;
80 }
81
82 typedef struct tagBITMAPCOREINFO256
83 {
84 BITMAPCOREHEADER bmciHeader;
85 RGBTRIPLE bmciColors[256];
86 } BITMAPCOREINFO256, *PBITMAPCOREINFO256;
87
Imm32LoadBitmapFromBytes(const BYTE * pb)88 HBITMAP Imm32LoadBitmapFromBytes(const BYTE *pb)
89 {
90 HBITMAP hbm = NULL;
91 const BITMAPCOREINFO256 *pbmci;
92 LPVOID pvBits;
93 DWORD ib, cbBytes, cColors;
94 BITMAP bm;
95
96 cbBytes = *(const DWORD *)pb;
97 if (cbBytes == 0)
98 return NULL;
99
100 pb += sizeof(DWORD);
101 ib = sizeof(DWORD);
102
103 pbmci = (const BITMAPCOREINFO256 *)pb;
104 hbm = CreateDIBSection(NULL, (LPBITMAPINFO)pbmci, DIB_RGB_COLORS, &pvBits, NULL, 0);
105 if (!hbm || !GetObject(hbm, sizeof(BITMAP), &bm))
106 {
107 ERR("Invalid bitmap\n");
108 return NULL;
109 }
110
111 switch (pbmci->bmciHeader.bcBitCount)
112 {
113 case 1: cColors = 2; break;
114 case 4: cColors = 16; break;
115 case 8: cColors = 256; break;
116 case 24: case 32:
117 cColors = 0;
118 break;
119 default:
120 ERR("Invalid bitmap\n");
121 DeleteObject(hbm);
122 return NULL;
123 }
124
125 ib += sizeof(BITMAPCOREHEADER);
126 pb += sizeof(BITMAPCOREHEADER);
127
128 ib += cColors * sizeof(RGBTRIPLE);
129 pb += cColors * sizeof(RGBTRIPLE);
130
131 ib += bm.bmWidthBytes * bm.bmHeight;
132 if (ib > cbBytes)
133 {
134 ERR("Invalid bitmap\n");
135 DeleteObject(hbm);
136 return NULL;
137 }
138 RtlCopyMemory(pvBits, pb, bm.bmWidthBytes * bm.bmHeight);
139
140 return hbm;
141 }
142
Imm32StoreBitmapToBytes(HBITMAP hbm,LPBYTE pbData,DWORD cbDataMax)143 BOOL Imm32StoreBitmapToBytes(HBITMAP hbm, LPBYTE pbData, DWORD cbDataMax)
144 {
145 HDC hDC;
146 BITMAP bm;
147 DWORD cbBytes, cColors;
148 BITMAPCOREINFO256 bmci;
149 BOOL ret;
150 LPBYTE pb = pbData;
151
152 *(LPDWORD)pb = 0;
153
154 if (!GetObject(hbm, sizeof(BITMAP), &bm))
155 {
156 ERR("Invalid bitmap\n");
157 return FALSE;
158 }
159
160 ZeroMemory(&bmci, sizeof(bmci));
161 bmci.bmciHeader.bcSize = sizeof(BITMAPCOREHEADER);
162 bmci.bmciHeader.bcWidth = bm.bmWidth;
163 bmci.bmciHeader.bcHeight = bm.bmHeight;
164 bmci.bmciHeader.bcPlanes = 1;
165 bmci.bmciHeader.bcBitCount = bm.bmBitsPixel;
166
167 switch (bm.bmBitsPixel)
168 {
169 case 1: cColors = 2; break;
170 case 4: cColors = 16; break;
171 case 8: cColors = 256; break;
172 case 24: case 32:
173 cColors = 0;
174 break;
175 default:
176 ERR("Invalid bitmap\n");
177 return FALSE;
178 }
179
180 cbBytes = sizeof(DWORD);
181 cbBytes += sizeof(BITMAPCOREHEADER);
182 cbBytes += cColors * sizeof(RGBTRIPLE);
183 cbBytes += bm.bmWidthBytes * bm.bmHeight;
184 if (cbBytes > cbDataMax)
185 {
186 ERR("Too small\n");
187 return FALSE;
188 }
189
190 hDC = CreateCompatibleDC(NULL);
191
192 ret = GetDIBits(hDC, hbm, 0, bm.bmHeight, NULL, (LPBITMAPINFO)&bmci, DIB_RGB_COLORS);
193
194 if (ret)
195 {
196 *(LPDWORD)pb = cbBytes;
197 pb += sizeof(DWORD);
198
199 RtlCopyMemory(pb, &bmci.bmciHeader, sizeof(BITMAPCOREHEADER));
200 pb += sizeof(BITMAPCOREHEADER);
201
202 RtlCopyMemory(pb, &bmci.bmciColors, cColors * sizeof(RGBTRIPLE));
203 pb += cColors * sizeof(RGBTRIPLE);
204
205 ret = GetDIBits(hDC, hbm, 0, bm.bmHeight, pb, (LPBITMAPINFO)&bmci, DIB_RGB_COLORS);
206 if (!ret)
207 *(LPDWORD)pbData = 0;
208 }
209
210 DeleteDC(hDC);
211
212 return ret;
213 }
214
215 // Win: IsAnsiIMC
Imm32IsImcAnsi(HIMC hIMC)216 BOOL WINAPI Imm32IsImcAnsi(HIMC hIMC)
217 {
218 BOOL ret;
219 PCLIENTIMC pClientImc = ImmLockClientImc(hIMC);
220 if (IS_NULL_UNEXPECTEDLY(pClientImc))
221 return -1;
222 ret = !(pClientImc->dwFlags & CLIENTIMC_WIDE);
223 ImmUnlockClientImc(pClientImc);
224 return ret;
225 }
226
Imm32WideFromAnsi(UINT uCodePage,LPCSTR pszA)227 LPWSTR APIENTRY Imm32WideFromAnsi(UINT uCodePage, LPCSTR pszA)
228 {
229 INT cch = lstrlenA(pszA);
230 LPWSTR pszW = ImmLocalAlloc(0, (cch + 1) * sizeof(WCHAR));
231 if (IS_NULL_UNEXPECTEDLY(pszW))
232 return NULL;
233 cch = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, pszA, cch, pszW, cch + 1);
234 pszW[cch] = 0;
235 return pszW;
236 }
237
Imm32AnsiFromWide(UINT uCodePage,LPCWSTR pszW)238 LPSTR APIENTRY Imm32AnsiFromWide(UINT uCodePage, LPCWSTR pszW)
239 {
240 INT cchW = lstrlenW(pszW);
241 INT cchA = (cchW + 1) * sizeof(WCHAR);
242 LPSTR pszA = ImmLocalAlloc(0, cchA);
243 if (IS_NULL_UNEXPECTEDLY(pszA))
244 return NULL;
245 cchA = WideCharToMultiByte(uCodePage, 0, pszW, cchW, pszA, cchA, NULL, NULL);
246 pszA[cchA] = 0;
247 return pszA;
248 }
249
250 /* Converts the character index */
251 /* Win: CalcCharacterPositionAtoW */
IchWideFromAnsi(LONG cchAnsi,LPCSTR pchAnsi,UINT uCodePage)252 LONG APIENTRY IchWideFromAnsi(LONG cchAnsi, LPCSTR pchAnsi, UINT uCodePage)
253 {
254 LONG cchWide;
255 for (cchWide = 0; cchAnsi > 0; ++cchWide)
256 {
257 if (IsDBCSLeadByteEx(uCodePage, *pchAnsi) && pchAnsi[1])
258 {
259 cchAnsi -= 2;
260 pchAnsi += 2;
261 }
262 else
263 {
264 --cchAnsi;
265 ++pchAnsi;
266 }
267 }
268 return cchWide;
269 }
270
271 /* Converts the character index */
272 /* Win: CalcCharacterPositionWtoA */
IchAnsiFromWide(LONG cchWide,LPCWSTR pchWide,UINT uCodePage)273 LONG APIENTRY IchAnsiFromWide(LONG cchWide, LPCWSTR pchWide, UINT uCodePage)
274 {
275 LONG cb, cchAnsi;
276 for (cchAnsi = 0; cchWide > 0; ++cchAnsi, ++pchWide, --cchWide)
277 {
278 cb = WideCharToMultiByte(uCodePage, 0, pchWide, 1, NULL, 0, NULL, NULL);
279 if (cb > 1)
280 ++cchAnsi;
281 }
282 return cchAnsi;
283 }
284
285 // Win: InternalGetSystemPathName
Imm32GetSystemLibraryPath(LPWSTR pszPath,DWORD cchPath,LPCWSTR pszFileName)286 BOOL Imm32GetSystemLibraryPath(LPWSTR pszPath, DWORD cchPath, LPCWSTR pszFileName)
287 {
288 if (!pszFileName[0] || !GetSystemDirectoryW(pszPath, cchPath))
289 {
290 ERR("Invalid filename\n");
291 return FALSE;
292 }
293 StringCchCatW(pszPath, cchPath, L"\\");
294 StringCchCatW(pszPath, cchPath, pszFileName);
295 return TRUE;
296 }
297
298 // Win: LFontAtoLFontW
LogFontAnsiToWide(const LOGFONTA * plfA,LPLOGFONTW plfW)299 VOID APIENTRY LogFontAnsiToWide(const LOGFONTA *plfA, LPLOGFONTW plfW)
300 {
301 size_t cch;
302 RtlCopyMemory(plfW, plfA, offsetof(LOGFONTA, lfFaceName));
303 StringCchLengthA(plfA->lfFaceName, _countof(plfA->lfFaceName), &cch);
304 cch = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, plfA->lfFaceName, (INT)cch,
305 plfW->lfFaceName, _countof(plfW->lfFaceName));
306 if (cch > _countof(plfW->lfFaceName) - 1)
307 cch = _countof(plfW->lfFaceName) - 1;
308 plfW->lfFaceName[cch] = 0;
309 }
310
311 // Win: LFontWtoLFontA
LogFontWideToAnsi(const LOGFONTW * plfW,LPLOGFONTA plfA)312 VOID APIENTRY LogFontWideToAnsi(const LOGFONTW *plfW, LPLOGFONTA plfA)
313 {
314 size_t cch;
315 RtlCopyMemory(plfA, plfW, offsetof(LOGFONTW, lfFaceName));
316 StringCchLengthW(plfW->lfFaceName, _countof(plfW->lfFaceName), &cch);
317 cch = WideCharToMultiByte(CP_ACP, 0, plfW->lfFaceName, (INT)cch,
318 plfA->lfFaceName, _countof(plfA->lfFaceName), NULL, NULL);
319 if (cch > _countof(plfA->lfFaceName) - 1)
320 cch = _countof(plfA->lfFaceName) - 1;
321 plfA->lfFaceName[cch] = 0;
322 }
323
DesktopPtrToUser(PVOID ptr)324 static PVOID FASTCALL DesktopPtrToUser(PVOID ptr)
325 {
326 PCLIENTINFO pci = GetWin32ClientInfo();
327 PDESKTOPINFO pdi = pci->pDeskInfo;
328
329 ASSERT(ptr != NULL);
330 ASSERT(pdi != NULL);
331 if (pdi->pvDesktopBase <= ptr && ptr < pdi->pvDesktopLimit)
332 return (PVOID)((ULONG_PTR)ptr - pci->ulClientDelta);
333 else
334 return (PVOID)NtUserCallOneParam((DWORD_PTR)ptr, ONEPARAM_ROUTINE_GETDESKTOPMAPPING);
335 }
336
337 // Win: HMValidateHandleNoRip
ValidateHandleNoErr(HANDLE hObject,UINT uType)338 LPVOID FASTCALL ValidateHandleNoErr(HANDLE hObject, UINT uType)
339 {
340 UINT index;
341 PUSER_HANDLE_TABLE ht;
342 PUSER_HANDLE_ENTRY he;
343 WORD generation;
344 LPVOID ptr;
345
346 if (!NtUserValidateHandleSecure(hObject))
347 {
348 WARN("Not a handle\n");
349 return NULL;
350 }
351
352 ht = gSharedInfo.aheList; /* handle table */
353 ASSERT(ht);
354 /* ReactOS-Specific! */
355 ASSERT(gSharedInfo.ulSharedDelta != 0);
356 he = (PUSER_HANDLE_ENTRY)((ULONG_PTR)ht->handles - gSharedInfo.ulSharedDelta);
357
358 index = (LOWORD(hObject) - FIRST_USER_HANDLE) >> 1;
359 if ((INT)index < 0 || ht->nb_handles <= index || he[index].type != uType)
360 return NULL;
361
362 if (he[index].flags & HANDLEENTRY_DESTROY)
363 return NULL;
364
365 generation = HIWORD(hObject);
366 if (generation != he[index].generation && generation && generation != 0xFFFF)
367 return NULL;
368
369 ptr = he[index].ptr;
370 if (ptr)
371 ptr = DesktopPtrToUser(ptr);
372
373 return ptr;
374 }
375
376 // Win: HMValidateHandle
ValidateHandle(HANDLE hObject,UINT uType)377 LPVOID FASTCALL ValidateHandle(HANDLE hObject, UINT uType)
378 {
379 LPVOID pvObj = ValidateHandleNoErr(hObject, uType);
380 if (pvObj)
381 return pvObj;
382
383 if (uType == TYPE_WINDOW)
384 SetLastError(ERROR_INVALID_WINDOW_HANDLE);
385 else
386 SetLastError(ERROR_INVALID_HANDLE);
387 return NULL;
388 }
389
390 // Win: TestInputContextProcess
Imm32CheckImcProcess(PIMC pIMC)391 BOOL APIENTRY Imm32CheckImcProcess(PIMC pIMC)
392 {
393 HIMC hIMC;
394 DWORD_PTR dwPID1, dwPID2;
395
396 if (IS_NULL_UNEXPECTEDLY(pIMC))
397 return FALSE;
398
399 if (pIMC->head.pti == Imm32CurrentPti())
400 return TRUE;
401
402 hIMC = pIMC->head.h;
403 dwPID1 = (DWORD)NtUserQueryInputContext(hIMC, QIC_INPUTPROCESSID);
404 dwPID2 = (DWORD_PTR)NtCurrentTeb()->ClientId.UniqueProcess;
405 if (dwPID1 != dwPID2)
406 {
407 WARN("PID 0x%X != 0x%X\n", dwPID1, dwPID2);
408 return FALSE;
409 }
410
411 return TRUE;
412 }
413
414 // Win: ImmLocalAlloc
ImmLocalAlloc(DWORD dwFlags,DWORD dwBytes)415 LPVOID APIENTRY ImmLocalAlloc(DWORD dwFlags, DWORD dwBytes)
416 {
417 if (!ghImmHeap)
418 {
419 ghImmHeap = RtlGetProcessHeap();
420 if (IS_NULL_UNEXPECTEDLY(ghImmHeap))
421 return NULL;
422 }
423 return HeapAlloc(ghImmHeap, dwFlags, dwBytes);
424 }
425
426 // Win: MakeIMENotify
427 BOOL APIENTRY
Imm32MakeIMENotify(HIMC hIMC,HWND hwnd,DWORD dwAction,DWORD_PTR dwIndex,DWORD_PTR dwValue,DWORD_PTR dwCommand,DWORD_PTR dwData)428 Imm32MakeIMENotify(HIMC hIMC, HWND hwnd, DWORD dwAction, DWORD_PTR dwIndex, DWORD_PTR dwValue,
429 DWORD_PTR dwCommand, DWORD_PTR dwData)
430 {
431 DWORD dwThreadId;
432 HKL hKL;
433 PIMEDPI pImeDpi;
434
435 if (dwAction != 0)
436 {
437 dwThreadId = (DWORD)NtUserQueryInputContext(hIMC, QIC_INPUTTHREADID);
438 if (dwThreadId)
439 {
440 /* find keyboard layout and lock it */
441 hKL = GetKeyboardLayout(dwThreadId);
442 pImeDpi = ImmLockImeDpi(hKL);
443 if (pImeDpi)
444 {
445 /* do notify */
446 pImeDpi->NotifyIME(hIMC, dwAction, dwIndex, dwValue);
447
448 ImmUnlockImeDpi(pImeDpi); /* unlock */
449 }
450 }
451 }
452
453 if (hwnd && dwCommand)
454 SendMessageW(hwnd, WM_IME_NOTIFY, dwCommand, dwData);
455
456 return TRUE;
457 }
458
459 // Win: BuildHimcList
Imm32BuildHimcList(DWORD dwThreadId,HIMC ** pphList)460 DWORD APIENTRY Imm32BuildHimcList(DWORD dwThreadId, HIMC **pphList)
461 {
462 #define INITIAL_COUNT 0x40
463 #define MAX_RETRY 10
464 NTSTATUS Status;
465 DWORD dwCount = INITIAL_COUNT, cRetry = 0;
466 HIMC *phNewList;
467
468 phNewList = ImmLocalAlloc(0, dwCount * sizeof(HIMC));
469 if (IS_NULL_UNEXPECTEDLY(phNewList))
470 return 0;
471
472 Status = NtUserBuildHimcList(dwThreadId, dwCount, phNewList, &dwCount);
473 while (Status == STATUS_BUFFER_TOO_SMALL)
474 {
475 ImmLocalFree(phNewList);
476 if (cRetry++ >= MAX_RETRY)
477 return 0;
478
479 phNewList = ImmLocalAlloc(0, dwCount * sizeof(HIMC));
480 if (IS_NULL_UNEXPECTEDLY(phNewList))
481 return 0;
482
483 Status = NtUserBuildHimcList(dwThreadId, dwCount, phNewList, &dwCount);
484 }
485
486 if (NT_ERROR(Status) || !dwCount)
487 {
488 ERR("Abnormal status\n");
489 ImmLocalFree(phNewList);
490 return 0;
491 }
492
493 *pphList = phNewList;
494 return dwCount;
495 #undef INITIAL_COUNT
496 #undef MAX_RETRY
497 }
498
499 // Win: ConvertImeMenuItemInfoAtoW
500 INT APIENTRY
Imm32ImeMenuAnsiToWide(const IMEMENUITEMINFOA * pItemA,LPIMEMENUITEMINFOW pItemW,UINT uCodePage,BOOL bBitmap)501 Imm32ImeMenuAnsiToWide(const IMEMENUITEMINFOA *pItemA, LPIMEMENUITEMINFOW pItemW,
502 UINT uCodePage, BOOL bBitmap)
503 {
504 INT ret;
505 pItemW->cbSize = pItemA->cbSize;
506 pItemW->fType = pItemA->fType;
507 pItemW->fState = pItemA->fState;
508 pItemW->wID = pItemA->wID;
509 if (bBitmap)
510 {
511 pItemW->hbmpChecked = pItemA->hbmpChecked;
512 pItemW->hbmpUnchecked = pItemA->hbmpUnchecked;
513 pItemW->hbmpItem = pItemA->hbmpItem;
514 }
515 pItemW->dwItemData = pItemA->dwItemData;
516 ret = MultiByteToWideChar(uCodePage, 0, pItemA->szString, -1,
517 pItemW->szString, _countof(pItemW->szString));
518 if (ret >= _countof(pItemW->szString))
519 {
520 ret = 0;
521 pItemW->szString[0] = 0;
522 }
523 return ret;
524 }
525
526 // Win: ConvertImeMenuItemInfoWtoA
527 INT APIENTRY
Imm32ImeMenuWideToAnsi(const IMEMENUITEMINFOW * pItemW,LPIMEMENUITEMINFOA pItemA,UINT uCodePage)528 Imm32ImeMenuWideToAnsi(const IMEMENUITEMINFOW *pItemW, LPIMEMENUITEMINFOA pItemA,
529 UINT uCodePage)
530 {
531 INT ret;
532 pItemA->cbSize = pItemW->cbSize;
533 pItemA->fType = pItemW->fType;
534 pItemA->fState = pItemW->fState;
535 pItemA->wID = pItemW->wID;
536 pItemA->hbmpChecked = pItemW->hbmpChecked;
537 pItemA->hbmpUnchecked = pItemW->hbmpUnchecked;
538 pItemA->dwItemData = pItemW->dwItemData;
539 pItemA->hbmpItem = pItemW->hbmpItem;
540 ret = WideCharToMultiByte(uCodePage, 0, pItemW->szString, -1,
541 pItemA->szString, _countof(pItemA->szString), NULL, NULL);
542 if (ret >= _countof(pItemA->szString))
543 {
544 ret = 0;
545 pItemA->szString[0] = 0;
546 }
547 return ret;
548 }
549
550 // Win: GetImeModeSaver
551 PIME_STATE APIENTRY
Imm32FetchImeState(LPINPUTCONTEXTDX pIC,HKL hKL)552 Imm32FetchImeState(LPINPUTCONTEXTDX pIC, HKL hKL)
553 {
554 PIME_STATE pState;
555 WORD Lang = PRIMARYLANGID(LOWORD(hKL));
556 for (pState = pIC->pState; pState; pState = pState->pNext)
557 {
558 if (pState->wLang == Lang)
559 break;
560 }
561 if (!pState)
562 {
563 pState = ImmLocalAlloc(HEAP_ZERO_MEMORY, sizeof(IME_STATE));
564 if (pState)
565 {
566 pState->wLang = Lang;
567 pState->pNext = pIC->pState;
568 pIC->pState = pState;
569 }
570 }
571 return pState;
572 }
573
574 // Win: GetImePrivateModeSaver
575 PIME_SUBSTATE APIENTRY
Imm32FetchImeSubState(PIME_STATE pState,HKL hKL)576 Imm32FetchImeSubState(PIME_STATE pState, HKL hKL)
577 {
578 PIME_SUBSTATE pSubState;
579 for (pSubState = pState->pSubState; pSubState; pSubState = pSubState->pNext)
580 {
581 if (pSubState->hKL == hKL)
582 return pSubState;
583 }
584 pSubState = ImmLocalAlloc(0, sizeof(IME_SUBSTATE));
585 if (!pSubState)
586 return NULL;
587 pSubState->dwValue = 0;
588 pSubState->hKL = hKL;
589 pSubState->pNext = pState->pSubState;
590 pState->pSubState = pSubState;
591 return pSubState;
592 }
593
594 // Win: RestorePrivateMode
595 BOOL APIENTRY
Imm32LoadImeStateSentence(LPINPUTCONTEXTDX pIC,PIME_STATE pState,HKL hKL)596 Imm32LoadImeStateSentence(LPINPUTCONTEXTDX pIC, PIME_STATE pState, HKL hKL)
597 {
598 PIME_SUBSTATE pSubState = Imm32FetchImeSubState(pState, hKL);
599 if (IS_NULL_UNEXPECTEDLY(pSubState))
600 return FALSE;
601
602 pIC->fdwSentence |= pSubState->dwValue;
603 return TRUE;
604 }
605
606 // Win: SavePrivateMode
607 BOOL APIENTRY
Imm32SaveImeStateSentence(LPINPUTCONTEXTDX pIC,PIME_STATE pState,HKL hKL)608 Imm32SaveImeStateSentence(LPINPUTCONTEXTDX pIC, PIME_STATE pState, HKL hKL)
609 {
610 PIME_SUBSTATE pSubState = Imm32FetchImeSubState(pState, hKL);
611 if (IS_NULL_UNEXPECTEDLY(pSubState))
612 return FALSE;
613
614 pSubState->dwValue = (pIC->fdwSentence & 0xffff0000);
615 return TRUE;
616 }
617
618 /*
619 * See RECONVERTSTRING structure:
620 * https://katahiromz.web.fc2.com/colony3rd/imehackerz/en/RECONVERTSTRING.html
621 *
622 * The dwCompStrOffset and dwTargetOffset members are the relative position of dwStrOffset.
623 * dwStrLen, dwCompStrLen, and dwTargetStrLen are the TCHAR count. dwStrOffset,
624 * dwCompStrOffset, and dwTargetStrOffset are the byte offset.
625 */
626
627 DWORD APIENTRY
Imm32ReconvertWideFromAnsi(LPRECONVERTSTRING pDest,const RECONVERTSTRING * pSrc,UINT uCodePage)628 Imm32ReconvertWideFromAnsi(LPRECONVERTSTRING pDest, const RECONVERTSTRING *pSrc, UINT uCodePage)
629 {
630 DWORD cch0, cchDest, cbDest;
631 LPCSTR pchSrc = (LPCSTR)pSrc + pSrc->dwStrOffset;
632 LPWSTR pchDest;
633
634 if (pSrc->dwVersion != 0)
635 {
636 ERR("\n");
637 return 0;
638 }
639
640 cchDest = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, pchSrc, pSrc->dwStrLen,
641 NULL, 0);
642 cbDest = sizeof(RECONVERTSTRING) + (cchDest + 1) * sizeof(WCHAR);
643 if (!pDest)
644 return cbDest;
645
646 if (pDest->dwSize < cbDest)
647 {
648 ERR("Too small\n");
649 return 0;
650 }
651
652 /* dwSize */
653 pDest->dwSize = cbDest;
654
655 /* dwVersion */
656 pDest->dwVersion = 0;
657
658 /* dwStrOffset */
659 pDest->dwStrOffset = sizeof(RECONVERTSTRING);
660
661 /* dwCompStrOffset */
662 cch0 = IchWideFromAnsi(pSrc->dwCompStrOffset, pchSrc, uCodePage);
663 pDest->dwCompStrOffset = cch0 * sizeof(WCHAR);
664
665 /* dwCompStrLen */
666 cch0 = IchWideFromAnsi(pSrc->dwCompStrOffset + pSrc->dwCompStrLen, pchSrc, uCodePage);
667 pDest->dwCompStrLen = (cch0 * sizeof(WCHAR) - pDest->dwCompStrOffset) / sizeof(WCHAR);
668
669 /* dwTargetStrOffset */
670 cch0 = IchWideFromAnsi(pSrc->dwTargetStrOffset, pchSrc, uCodePage);
671 pDest->dwTargetStrOffset = cch0 * sizeof(WCHAR);
672
673 /* dwTargetStrLen */
674 cch0 = IchWideFromAnsi(pSrc->dwTargetStrOffset + pSrc->dwTargetStrLen, pchSrc, uCodePage);
675 pDest->dwTargetStrLen = (cch0 * sizeof(WCHAR) - pSrc->dwTargetStrOffset) / sizeof(WCHAR);
676
677 /* dwStrLen */
678 pDest->dwStrLen = cchDest;
679
680 /* the string */
681 pchDest = (LPWSTR)((LPBYTE)pDest + pDest->dwStrOffset);
682 cchDest = MultiByteToWideChar(uCodePage, MB_PRECOMPOSED, pchSrc, pSrc->dwStrLen,
683 pchDest, cchDest);
684 pchDest[cchDest] = 0;
685
686 TRACE("cbDest: 0x%X\n", cbDest);
687 return cbDest;
688 }
689
690 DWORD APIENTRY
Imm32ReconvertAnsiFromWide(LPRECONVERTSTRING pDest,const RECONVERTSTRING * pSrc,UINT uCodePage)691 Imm32ReconvertAnsiFromWide(LPRECONVERTSTRING pDest, const RECONVERTSTRING *pSrc, UINT uCodePage)
692 {
693 DWORD cch0, cch1, cchDest, cbDest;
694 LPCWSTR pchSrc = (LPCWSTR)((LPCSTR)pSrc + pSrc->dwStrOffset);
695 LPSTR pchDest;
696
697 if (pSrc->dwVersion != 0)
698 {
699 ERR("\n");
700 return 0;
701 }
702
703 cchDest = WideCharToMultiByte(uCodePage, 0, pchSrc, pSrc->dwStrLen,
704 NULL, 0, NULL, NULL);
705 cbDest = sizeof(RECONVERTSTRING) + (cchDest + 1) * sizeof(CHAR);
706 if (!pDest)
707 return cbDest;
708
709 if (pDest->dwSize < cbDest)
710 {
711 ERR("Too small\n");
712 return 0;
713 }
714
715 /* dwSize */
716 pDest->dwSize = cbDest;
717
718 /* dwVersion */
719 pDest->dwVersion = 0;
720
721 /* dwStrOffset */
722 pDest->dwStrOffset = sizeof(RECONVERTSTRING);
723
724 /* dwCompStrOffset */
725 cch1 = pSrc->dwCompStrOffset / sizeof(WCHAR);
726 cch0 = IchAnsiFromWide(cch1, pchSrc, uCodePage);
727 pDest->dwCompStrOffset = cch0 * sizeof(CHAR);
728
729 /* dwCompStrLen */
730 cch0 = IchAnsiFromWide(cch1 + pSrc->dwCompStrLen, pchSrc, uCodePage);
731 pDest->dwCompStrLen = cch0 * sizeof(CHAR) - pDest->dwCompStrOffset;
732
733 /* dwTargetStrOffset */
734 cch1 = pSrc->dwTargetStrOffset / sizeof(WCHAR);
735 cch0 = IchAnsiFromWide(cch1, pchSrc, uCodePage);
736 pDest->dwTargetStrOffset = cch0 * sizeof(CHAR);
737
738 /* dwTargetStrLen */
739 cch0 = IchAnsiFromWide(cch1 + pSrc->dwTargetStrLen, pchSrc, uCodePage);
740 pDest->dwTargetStrLen = cch0 * sizeof(CHAR) - pDest->dwTargetStrOffset;
741
742 /* dwStrLen */
743 pDest->dwStrLen = cchDest;
744
745 /* the string */
746 pchDest = (LPSTR)pDest + pDest->dwStrOffset;
747 cchDest = WideCharToMultiByte(uCodePage, 0, pchSrc, pSrc->dwStrLen,
748 pchDest, cchDest, NULL, NULL);
749 pchDest[cchDest] = 0;
750
751 TRACE("cchDest: 0x%X\n", cchDest);
752 return cbDest;
753 }
754
755 typedef BOOL (WINAPI *FN_GetFileVersionInfoW)(LPCWSTR, DWORD, DWORD, LPVOID);
756 typedef DWORD (WINAPI *FN_GetFileVersionInfoSizeW)(LPCWSTR, LPDWORD);
757 typedef BOOL (WINAPI *FN_VerQueryValueW)(LPCVOID, LPCWSTR, LPVOID*, PUINT);
758
759 static FN_GetFileVersionInfoW s_fnGetFileVersionInfoW = NULL;
760 static FN_GetFileVersionInfoSizeW s_fnGetFileVersionInfoSizeW = NULL;
761 static FN_VerQueryValueW s_fnVerQueryValueW = NULL;
762
763 // Win: LoadFixVersionInfo
Imm32LoadImeFixedInfo(PIMEINFOEX pInfoEx,LPCVOID pVerInfo)764 static BOOL APIENTRY Imm32LoadImeFixedInfo(PIMEINFOEX pInfoEx, LPCVOID pVerInfo)
765 {
766 UINT cbFixed = 0;
767 VS_FIXEDFILEINFO *pFixed;
768 if (!s_fnVerQueryValueW(pVerInfo, L"\\", (LPVOID*)&pFixed, &cbFixed) || !cbFixed)
769 {
770 ERR("Fixed version info not available\n");
771 return FALSE;
772 }
773
774 /* NOTE: The IME module must contain a version info of input method driver. */
775 if (pFixed->dwFileType != VFT_DRV || pFixed->dwFileSubtype != VFT2_DRV_INPUTMETHOD)
776 {
777 ERR("DLL %S is not an IME\n", pInfoEx->wszImeFile);
778 return FALSE;
779 }
780
781 pInfoEx->dwProdVersion = pFixed->dwProductVersionMS;
782 pInfoEx->dwImeWinVersion = 0x40000;
783 return TRUE;
784 }
785
786 // Win: GetVersionDatum
787 static LPWSTR APIENTRY
Imm32GetVerInfoValue(LPCVOID pVerInfo,LPWSTR pszKey,DWORD cchKey,LPCWSTR pszName)788 Imm32GetVerInfoValue(LPCVOID pVerInfo, LPWSTR pszKey, DWORD cchKey, LPCWSTR pszName)
789 {
790 size_t cchExtra;
791 LPWSTR pszValue;
792 UINT cbValue = 0;
793
794 StringCchLengthW(pszKey, cchKey, &cchExtra);
795
796 StringCchCatW(pszKey, cchKey, pszName);
797 s_fnVerQueryValueW(pVerInfo, pszKey, (LPVOID*)&pszValue, &cbValue);
798 pszKey[cchExtra] = 0;
799
800 return (cbValue ? pszValue : NULL);
801 }
802
803 // Win: LoadVarVersionInfo
Imm32LoadImeLangAndDesc(PIMEINFOEX pInfoEx,LPCVOID pVerInfo)804 BOOL APIENTRY Imm32LoadImeLangAndDesc(PIMEINFOEX pInfoEx, LPCVOID pVerInfo)
805 {
806 BOOL ret;
807 WCHAR szKey[80];
808 LPWSTR pszDesc;
809 LPWORD pw;
810 UINT cbData;
811 LANGID LangID;
812
813 /* Getting the version info. See VerQueryValue */
814 ret = s_fnVerQueryValueW(pVerInfo, L"\\VarFileInfo\\Translation", (LPVOID*)&pw, &cbData);
815 if (!ret || !cbData)
816 {
817 ERR("Translation not available\n");
818 return FALSE;
819 }
820
821 if (pInfoEx->hkl == NULL)
822 pInfoEx->hkl = UlongToHandle(*pw);
823
824 /* Try the current language and the Unicode codepage (0x04B0) */
825 LangID = LANGIDFROMLCID(GetThreadLocale());
826 StringCchPrintfW(szKey, _countof(szKey), L"\\StringFileInfo\\%04X04B0\\", LangID);
827 pszDesc = Imm32GetVerInfoValue(pVerInfo, szKey, _countof(szKey), L"FileDescription");
828 if (!pszDesc)
829 {
830 /* Retry the language and codepage of the IME module */
831 StringCchPrintfW(szKey, _countof(szKey), L"\\StringFileInfo\\%04X%04X\\", pw[0], pw[1]);
832 pszDesc = Imm32GetVerInfoValue(pVerInfo, szKey, _countof(szKey), L"FileDescription");
833 }
834
835 /* The description */
836 if (pszDesc)
837 StringCchCopyW(pInfoEx->wszImeDescription, _countof(pInfoEx->wszImeDescription), pszDesc);
838 else
839 pInfoEx->wszImeDescription[0] = 0;
840
841 return TRUE;
842 }
843
844 // Win: LoadVersionInfo
Imm32LoadImeVerInfo(PIMEINFOEX pImeInfoEx)845 BOOL APIENTRY Imm32LoadImeVerInfo(PIMEINFOEX pImeInfoEx)
846 {
847 HINSTANCE hinstVersion;
848 BOOL ret = FALSE, bLoaded = FALSE;
849 WCHAR szPath[MAX_PATH];
850 LPVOID pVerInfo;
851 DWORD cbVerInfo, dwHandle;
852
853 /* Load version.dll to use the version info API */
854 Imm32GetSystemLibraryPath(szPath, _countof(szPath), L"version.dll");
855 hinstVersion = GetModuleHandleW(szPath);
856 if (!hinstVersion)
857 {
858 hinstVersion = LoadLibraryW(szPath);
859 if (IS_NULL_UNEXPECTEDLY(hinstVersion))
860 return FALSE;
861
862 bLoaded = TRUE;
863 }
864
865 #define GET_FN(name) do { \
866 s_fn##name = (FN_##name)GetProcAddress(hinstVersion, #name); \
867 if (!s_fn##name) goto Quit; \
868 } while (0)
869 GET_FN(GetFileVersionInfoW);
870 GET_FN(GetFileVersionInfoSizeW);
871 GET_FN(VerQueryValueW);
872 #undef GET_FN
873
874 /* The path of the IME module */
875 Imm32GetSystemLibraryPath(szPath, _countof(szPath), pImeInfoEx->wszImeFile);
876
877 cbVerInfo = s_fnGetFileVersionInfoSizeW(szPath, &dwHandle);
878 if (IS_ZERO_UNEXPECTEDLY(cbVerInfo))
879 goto Quit;
880
881 pVerInfo = ImmLocalAlloc(0, cbVerInfo);
882 if (IS_NULL_UNEXPECTEDLY(pVerInfo))
883 goto Quit;
884
885 /* Load the version info of the IME module */
886 if (s_fnGetFileVersionInfoW(szPath, dwHandle, cbVerInfo, pVerInfo) &&
887 Imm32LoadImeFixedInfo(pImeInfoEx, pVerInfo))
888 {
889 ret = Imm32LoadImeLangAndDesc(pImeInfoEx, pVerInfo);
890 }
891
892 ImmLocalFree(pVerInfo);
893
894 Quit:
895 if (bLoaded)
896 FreeLibrary(hinstVersion);
897 TRACE("ret: %d\n", ret);
898 return ret;
899 }
900
901 // Win: AssignNewLayout
Imm32AssignNewLayout(UINT cKLs,const REG_IME * pLayouts,WORD wLangID)902 HKL APIENTRY Imm32AssignNewLayout(UINT cKLs, const REG_IME *pLayouts, WORD wLangID)
903 {
904 UINT iKL, wID, wLow = 0xE0FF, wHigh = 0xE01F, wNextID = 0;
905
906 for (iKL = 0; iKL < cKLs; ++iKL)
907 {
908 wHigh = max(wHigh, HIWORD(pLayouts[iKL].hKL));
909 wLow = min(wLow, HIWORD(pLayouts[iKL].hKL));
910 }
911
912 if (wHigh < 0xE0FF)
913 {
914 wNextID = wHigh + 1;
915 }
916 else if (wLow > 0xE001)
917 {
918 wNextID = wLow - 1;
919 }
920 else
921 {
922 for (wID = 0xE020; wID <= 0xE0FF; ++wID)
923 {
924 for (iKL = 0; iKL < cKLs; ++iKL)
925 {
926 if (LOWORD(pLayouts[iKL].hKL) == wLangID &&
927 HIWORD(pLayouts[iKL].hKL) == wID)
928 {
929 break;
930 }
931 }
932
933 if (iKL >= cKLs)
934 break;
935 }
936
937 if (wID <= 0xE0FF)
938 wNextID = wID;
939 }
940
941 if (!wNextID)
942 return NULL;
943
944 return UlongToHandle(MAKELONG(wLangID, wNextID));
945 }
946
947 // Win: GetImeLayout
Imm32GetImeLayout(PREG_IME pLayouts,UINT cLayouts)948 UINT APIENTRY Imm32GetImeLayout(PREG_IME pLayouts, UINT cLayouts)
949 {
950 HKEY hkeyLayouts, hkeyIME;
951 WCHAR szImeFileName[80], szImeKey[20];
952 UINT iKey, nCount;
953 DWORD cbData;
954 LONG lError;
955 ULONG Value;
956 HKL hKL;
957
958 /* Open the registry keyboard layouts */
959 lError = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_KEYBOARD_LAYOUTS, &hkeyLayouts);
960 if (IS_ERROR_UNEXPECTEDLY(lError))
961 return 0;
962
963 for (iKey = nCount = 0; ; ++iKey)
964 {
965 /* Get the key name */
966 lError = RegEnumKeyW(hkeyLayouts, iKey, szImeKey, _countof(szImeKey));
967 if (lError != ERROR_SUCCESS)
968 break;
969
970 if (szImeKey[0] != L'E' && szImeKey[0] != L'e')
971 continue; /* Not an IME layout */
972
973 if (pLayouts == NULL) /* for counting only */
974 {
975 ++nCount;
976 continue;
977 }
978
979 if (cLayouts <= nCount)
980 break;
981
982 lError = RegOpenKeyW(hkeyLayouts, szImeKey, &hkeyIME); /* Open the IME key */
983 if (IS_ERROR_UNEXPECTEDLY(lError))
984 continue;
985
986 /* Load the "Ime File" value */
987 szImeFileName[0] = 0;
988 cbData = sizeof(szImeFileName);
989 RegQueryValueExW(hkeyIME, L"Ime File", NULL, NULL, (LPBYTE)szImeFileName, &cbData);
990 szImeFileName[_countof(szImeFileName) - 1] = UNICODE_NULL; /* Avoid buffer overrun */
991
992 RegCloseKey(hkeyIME);
993
994 /* We don't allow the invalid "IME File" values for security reason */
995 if (!szImeFileName[0] || wcscspn(szImeFileName, L":\\/") != wcslen(szImeFileName))
996 {
997 WARN("\n");
998 continue;
999 }
1000
1001 Imm32StrToUInt(szImeKey, &Value, 16);
1002 hKL = UlongToHandle(Value);
1003 if (!IS_IME_HKL(hKL)) /* Not an IME */
1004 {
1005 WARN("\n");
1006 continue;
1007 }
1008
1009 /* Store the IME key and the IME filename */
1010 pLayouts[nCount].hKL = hKL;
1011 StringCchCopyW(pLayouts[nCount].szImeKey, _countof(pLayouts[nCount].szImeKey), szImeKey);
1012 CharUpperW(szImeFileName);
1013 StringCchCopyW(pLayouts[nCount].szFileName, _countof(pLayouts[nCount].szFileName),
1014 szImeFileName);
1015 ++nCount;
1016 }
1017
1018 RegCloseKey(hkeyLayouts);
1019 return nCount;
1020 }
1021
1022 // Win: WriteImeLayout
Imm32WriteImeLayout(HKL hKL,LPCWSTR pchFilePart,LPCWSTR pszLayoutText)1023 BOOL APIENTRY Imm32WriteImeLayout(HKL hKL, LPCWSTR pchFilePart, LPCWSTR pszLayoutText)
1024 {
1025 UINT iPreload;
1026 HKEY hkeyLayouts, hkeyIME, hkeyPreload;
1027 WCHAR szImeKey[20], szPreloadNumber[20], szPreloadKey[20];
1028 DWORD cbData;
1029 LANGID LangID;
1030 LONG lError;
1031 LPCWSTR pszLayoutFile;
1032
1033 /* Open the registry keyboard layouts */
1034 lError = RegOpenKeyW(HKEY_LOCAL_MACHINE, REGKEY_KEYBOARD_LAYOUTS, &hkeyLayouts);
1035 if (IS_ERROR_UNEXPECTEDLY(lError))
1036 return FALSE;
1037
1038 /* Get the IME key from hKL */
1039 StringCchPrintf(szImeKey, _countof(szImeKey), L"%08X", HandleToUlong(hKL));
1040
1041 /* Create a registry IME key */
1042 lError = RegCreateKeyW(hkeyLayouts, szImeKey, &hkeyIME);
1043 if (IS_ERROR_UNEXPECTEDLY(lError))
1044 goto Failure;
1045
1046 /* Write "Ime File" */
1047 cbData = (wcslen(pchFilePart) + 1) * sizeof(WCHAR);
1048 lError = RegSetValueExW(hkeyIME, L"Ime File", 0, REG_SZ, (LPBYTE)pchFilePart, cbData);
1049 if (IS_ERROR_UNEXPECTEDLY(lError))
1050 goto Failure;
1051
1052 /* Write "Layout Text" */
1053 cbData = (wcslen(pszLayoutText) + 1) * sizeof(WCHAR);
1054 lError = RegSetValueExW(hkeyIME, L"Layout Text", 0, REG_SZ, (LPBYTE)pszLayoutText, cbData);
1055 if (IS_ERROR_UNEXPECTEDLY(lError))
1056 goto Failure;
1057
1058 /* Choose "Layout File" from hKL */
1059 LangID = LOWORD(hKL);
1060 switch (LOBYTE(LangID))
1061 {
1062 case LANG_JAPANESE: pszLayoutFile = L"kbdjpn.dll"; break;
1063 case LANG_KOREAN: pszLayoutFile = L"kbdkor.dll"; break;
1064 default: pszLayoutFile = L"kbdus.dll"; break;
1065 }
1066
1067 /* Write "Layout File" */
1068 cbData = (wcslen(pszLayoutFile) + 1) * sizeof(WCHAR);
1069 lError = RegSetValueExW(hkeyIME, L"Layout File", 0, REG_SZ, (LPBYTE)pszLayoutFile, cbData);
1070 if (IS_ERROR_UNEXPECTEDLY(lError))
1071 goto Failure;
1072
1073 RegCloseKey(hkeyIME);
1074 RegCloseKey(hkeyLayouts);
1075
1076 /* Create "Preload" key */
1077 RegCreateKeyW(HKEY_CURRENT_USER, L"Keyboard Layout\\Preload", &hkeyPreload);
1078
1079 #define MAX_PRELOAD 0x400
1080 for (iPreload = 1; iPreload < MAX_PRELOAD; ++iPreload)
1081 {
1082 Imm32UIntToStr(iPreload, 10, szPreloadNumber, _countof(szPreloadNumber));
1083
1084 /* Load the key of the preload number */
1085 cbData = sizeof(szPreloadKey);
1086 lError = RegQueryValueExW(hkeyPreload, szPreloadNumber, NULL, NULL,
1087 (LPBYTE)szPreloadKey, &cbData);
1088 szPreloadKey[_countof(szPreloadKey) - 1] = UNICODE_NULL; /* Avoid buffer overrun */
1089
1090 if (lError != ERROR_SUCCESS || lstrcmpiW(szImeKey, szPreloadKey) == 0)
1091 break; /* Found an empty room or the same key */
1092 }
1093
1094 if (iPreload >= MAX_PRELOAD) /* Not found */
1095 {
1096 ERR("\n");
1097 RegCloseKey(hkeyPreload);
1098 return FALSE;
1099 }
1100 #undef MAX_PRELOAD
1101
1102 /* Write the IME key to the preload number */
1103 cbData = (wcslen(szImeKey) + 1) * sizeof(WCHAR);
1104 lError = RegSetValueExW(hkeyPreload, szPreloadNumber, 0, REG_SZ, (LPBYTE)szImeKey, cbData);
1105 RegCloseKey(hkeyPreload);
1106 return lError == ERROR_SUCCESS;
1107
1108 Failure:
1109 RegCloseKey(hkeyIME);
1110 RegDeleteKeyW(hkeyLayouts, szImeKey);
1111 RegCloseKey(hkeyLayouts);
1112 return FALSE;
1113 }
1114
1115 typedef INT (WINAPI *FN_LZOpenFileW)(LPWSTR, LPOFSTRUCT, WORD);
1116 typedef LONG (WINAPI *FN_LZCopy)(INT, INT);
1117 typedef VOID (WINAPI *FN_LZClose)(INT);
1118
1119 // Win: CopyImeFile
Imm32CopyImeFile(LPWSTR pszOldFile,LPCWSTR pszNewFile)1120 BOOL APIENTRY Imm32CopyImeFile(LPWSTR pszOldFile, LPCWSTR pszNewFile)
1121 {
1122 BOOL ret = FALSE, bLoaded = FALSE;
1123 HMODULE hinstLZ32;
1124 WCHAR szLZ32Path[MAX_PATH];
1125 CHAR szDestA[MAX_PATH];
1126 OFSTRUCT OFStruct;
1127 FN_LZOpenFileW fnLZOpenFileW;
1128 FN_LZCopy fnLZCopy;
1129 FN_LZClose fnLZClose;
1130 HFILE hfDest, hfSrc;
1131
1132 /* Load LZ32.dll for copying/decompressing file */
1133 Imm32GetSystemLibraryPath(szLZ32Path, _countof(szLZ32Path), L"LZ32");
1134 hinstLZ32 = GetModuleHandleW(szLZ32Path);
1135 if (!hinstLZ32)
1136 {
1137 hinstLZ32 = LoadLibraryW(szLZ32Path);
1138 if (IS_NULL_UNEXPECTEDLY(hinstLZ32))
1139 return FALSE;
1140 bLoaded = TRUE;
1141 }
1142
1143 #define GET_FN(name) do { \
1144 fn##name = (FN_##name)GetProcAddress(hinstLZ32, #name); \
1145 if (!fn##name) goto Quit; \
1146 } while (0)
1147 GET_FN(LZOpenFileW);
1148 GET_FN(LZCopy);
1149 GET_FN(LZClose);
1150 #undef GET_FN
1151
1152 if (!WideCharToMultiByte(CP_ACP, 0, pszNewFile, -1, szDestA, _countof(szDestA), NULL, NULL))
1153 goto Quit;
1154 szDestA[_countof(szDestA) - 1] = 0;
1155
1156 hfSrc = fnLZOpenFileW(pszOldFile, &OFStruct, OF_READ);
1157 if (hfSrc < 0)
1158 goto Quit;
1159
1160 hfDest = OpenFile(szDestA, &OFStruct, OF_CREATE);
1161 if (hfDest != HFILE_ERROR)
1162 {
1163 ret = (fnLZCopy(hfSrc, hfDest) >= 0);
1164 _lclose(hfDest);
1165 }
1166
1167 fnLZClose(hfSrc);
1168
1169 Quit:
1170 if (bLoaded)
1171 FreeLibrary(hinstLZ32);
1172 return ret;
1173 }
1174
1175 /***********************************************************************
1176 * ImmCreateIMCC(IMM32.@)
1177 */
ImmCreateIMCC(DWORD size)1178 HIMCC WINAPI ImmCreateIMCC(DWORD size)
1179 {
1180 if (size < sizeof(DWORD))
1181 size = sizeof(DWORD);
1182 return LocalAlloc(LHND, size);
1183 }
1184
1185 /***********************************************************************
1186 * ImmDestroyIMCC(IMM32.@)
1187 */
ImmDestroyIMCC(HIMCC block)1188 HIMCC WINAPI ImmDestroyIMCC(HIMCC block)
1189 {
1190 if (block)
1191 return LocalFree(block);
1192 return NULL;
1193 }
1194
1195 /***********************************************************************
1196 * ImmLockIMCC(IMM32.@)
1197 */
ImmLockIMCC(HIMCC imcc)1198 LPVOID WINAPI ImmLockIMCC(HIMCC imcc)
1199 {
1200 if (imcc)
1201 return LocalLock(imcc);
1202 return NULL;
1203 }
1204
1205 /***********************************************************************
1206 * ImmUnlockIMCC(IMM32.@)
1207 */
ImmUnlockIMCC(HIMCC imcc)1208 BOOL WINAPI ImmUnlockIMCC(HIMCC imcc)
1209 {
1210 if (imcc)
1211 return LocalUnlock(imcc);
1212 return FALSE;
1213 }
1214
1215 /***********************************************************************
1216 * ImmGetIMCCLockCount(IMM32.@)
1217 */
ImmGetIMCCLockCount(HIMCC imcc)1218 DWORD WINAPI ImmGetIMCCLockCount(HIMCC imcc)
1219 {
1220 return LocalFlags(imcc) & LMEM_LOCKCOUNT;
1221 }
1222
1223 /***********************************************************************
1224 * ImmReSizeIMCC(IMM32.@)
1225 */
ImmReSizeIMCC(HIMCC imcc,DWORD size)1226 HIMCC WINAPI ImmReSizeIMCC(HIMCC imcc, DWORD size)
1227 {
1228 if (!imcc)
1229 return NULL;
1230 return LocalReAlloc(imcc, size, LHND);
1231 }
1232
1233 /***********************************************************************
1234 * ImmGetIMCCSize(IMM32.@)
1235 */
ImmGetIMCCSize(HIMCC imcc)1236 DWORD WINAPI ImmGetIMCCSize(HIMCC imcc)
1237 {
1238 if (imcc)
1239 return LocalSize(imcc);
1240 return 0;
1241 }
1242
1243 /***********************************************************************
1244 * ImmGetIMCLockCount(IMM32.@)
1245 */
ImmGetIMCLockCount(HIMC hIMC)1246 DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC)
1247 {
1248 DWORD ret;
1249 HANDLE hInputContext;
1250 PCLIENTIMC pClientImc;
1251
1252 pClientImc = ImmLockClientImc(hIMC);
1253 if (IS_NULL_UNEXPECTEDLY(pClientImc))
1254 return 0;
1255
1256 ret = 0;
1257 hInputContext = pClientImc->hInputContext;
1258 if (hInputContext)
1259 ret = (LocalFlags(hInputContext) & LMEM_LOCKCOUNT);
1260
1261 ImmUnlockClientImc(pClientImc);
1262 return ret;
1263 }
1264
1265 /***********************************************************************
1266 * ImmIMPGetIMEA(IMM32.@)
1267 */
ImmIMPGetIMEA(HWND hWnd,LPIMEPROA pImePro)1268 BOOL WINAPI ImmIMPGetIMEA(HWND hWnd, LPIMEPROA pImePro)
1269 {
1270 FIXME("(%p, %p)\n", hWnd, pImePro);
1271 return FALSE;
1272 }
1273
1274 /***********************************************************************
1275 * ImmIMPGetIMEW(IMM32.@)
1276 */
ImmIMPGetIMEW(HWND hWnd,LPIMEPROW pImePro)1277 BOOL WINAPI ImmIMPGetIMEW(HWND hWnd, LPIMEPROW pImePro)
1278 {
1279 FIXME("(%p, %p)\n", hWnd, pImePro);
1280 return FALSE;
1281 }
1282
1283 /***********************************************************************
1284 * ImmIMPQueryIMEA(IMM32.@)
1285 */
ImmIMPQueryIMEA(LPIMEPROA pImePro)1286 BOOL WINAPI ImmIMPQueryIMEA(LPIMEPROA pImePro)
1287 {
1288 FIXME("(%p)\n", pImePro);
1289 return FALSE;
1290 }
1291
1292 /***********************************************************************
1293 * ImmIMPQueryIMEW(IMM32.@)
1294 */
ImmIMPQueryIMEW(LPIMEPROW pImePro)1295 BOOL WINAPI ImmIMPQueryIMEW(LPIMEPROW pImePro)
1296 {
1297 FIXME("(%p)\n", pImePro);
1298 return FALSE;
1299 }
1300
1301 /***********************************************************************
1302 * ImmIMPSetIMEA(IMM32.@)
1303 */
ImmIMPSetIMEA(HWND hWnd,LPIMEPROA pImePro)1304 BOOL WINAPI ImmIMPSetIMEA(HWND hWnd, LPIMEPROA pImePro)
1305 {
1306 FIXME("(%p, %p)\n", hWnd, pImePro);
1307 return FALSE;
1308 }
1309
1310 /***********************************************************************
1311 * ImmIMPSetIMEW(IMM32.@)
1312 */
ImmIMPSetIMEW(HWND hWnd,LPIMEPROW pImePro)1313 BOOL WINAPI ImmIMPSetIMEW(HWND hWnd, LPIMEPROW pImePro)
1314 {
1315 FIXME("(%p, %p)\n", hWnd, pImePro);
1316 return FALSE;
1317 }
1318