xref: /reactos/dll/win32/imm32/utils.c (revision bbabe248)
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 Oleg Dubinskiy <oleg.dubinskij2013@yandex.ua>
10  *              Copyright 2020-2021 Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
11  */
12 
13 #include "precomp.h"
14 
15 WINE_DEFAULT_DEBUG_CHANNEL(imm);
16 
17 HANDLE g_hImm32Heap = NULL;
18 
19 LPWSTR APIENTRY Imm32WideFromAnsi(LPCSTR pszA)
20 {
21     INT cch = lstrlenA(pszA);
22     LPWSTR pszW = Imm32HeapAlloc(0, (cch + 1) * sizeof(WCHAR));
23     if (pszW == NULL)
24         return NULL;
25     cch = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszA, cch, pszW, cch + 1);
26     pszW[cch] = 0;
27     return pszW;
28 }
29 
30 LPSTR APIENTRY Imm32AnsiFromWide(LPCWSTR pszW)
31 {
32     INT cchW = lstrlenW(pszW);
33     INT cchA = (cchW + 1) * sizeof(WCHAR);
34     LPSTR pszA = Imm32HeapAlloc(0, cchA);
35     if (!pszA)
36         return NULL;
37     cchA = WideCharToMultiByte(CP_ACP, 0, pszW, cchW, pszA, cchA, NULL, NULL);
38     pszA[cchA] = 0;
39     return pszA;
40 }
41 
42 BOOL Imm32GetSystemLibraryPath(LPWSTR pszPath, DWORD cchPath, LPCWSTR pszFileName)
43 {
44     if (!pszFileName[0] || !GetSystemDirectoryW(pszPath, cchPath))
45         return FALSE;
46     StringCchCatW(pszPath, cchPath, L"\\");
47     StringCchCatW(pszPath, cchPath, pszFileName);
48     return TRUE;
49 }
50 
51 VOID APIENTRY LogFontAnsiToWide(const LOGFONTA *plfA, LPLOGFONTW plfW)
52 {
53     size_t cch;
54     RtlCopyMemory(plfW, plfA, offsetof(LOGFONTA, lfFaceName));
55     StringCchLengthA(plfA->lfFaceName, _countof(plfA->lfFaceName), &cch);
56     cch = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, plfA->lfFaceName, (INT)cch,
57                               plfW->lfFaceName, _countof(plfW->lfFaceName));
58     if (cch > _countof(plfW->lfFaceName) - 1)
59         cch = _countof(plfW->lfFaceName) - 1;
60     plfW->lfFaceName[cch] = 0;
61 }
62 
63 VOID APIENTRY LogFontWideToAnsi(const LOGFONTW *plfW, LPLOGFONTA plfA)
64 {
65     size_t cch;
66     RtlCopyMemory(plfA, plfW, offsetof(LOGFONTW, lfFaceName));
67     StringCchLengthW(plfW->lfFaceName, _countof(plfW->lfFaceName), &cch);
68     cch = WideCharToMultiByte(CP_ACP, 0, plfW->lfFaceName, (INT)cch,
69                               plfA->lfFaceName, _countof(plfA->lfFaceName), NULL, NULL);
70     if (cch > _countof(plfA->lfFaceName) - 1)
71         cch = _countof(plfA->lfFaceName) - 1;
72     plfA->lfFaceName[cch] = 0;
73 }
74 
75 PWND FASTCALL ValidateHwndNoErr(HWND hwnd)
76 {
77     PCLIENTINFO ClientInfo = GetWin32ClientInfo();
78     INT index;
79     PUSER_HANDLE_TABLE ht;
80     PUSER_HANDLE_ENTRY he;
81     WORD generation;
82 
83     /* See if the window is cached */
84     if (hwnd == ClientInfo->CallbackWnd.hWnd)
85         return ClientInfo->CallbackWnd.pWnd;
86 
87     if (!NtUserValidateHandleSecure(hwnd))
88         return NULL;
89 
90     ht = g_SharedInfo.aheList; /* handle table */
91     ASSERT(ht);
92     /* ReactOS-Specific! */
93     ASSERT(g_SharedInfo.ulSharedDelta != 0);
94     he = (PUSER_HANDLE_ENTRY)((ULONG_PTR)ht->handles - g_SharedInfo.ulSharedDelta);
95 
96     index = (LOWORD(hwnd) - FIRST_USER_HANDLE) >> 1;
97     if (index < 0 || index >= ht->nb_handles || he[index].type != TYPE_WINDOW)
98         return NULL;
99 
100     generation = HIWORD(hwnd);
101     if (generation != he[index].generation && generation && generation != 0xFFFF)
102         return NULL;
103 
104     return (PWND)&he[index];
105 }
106 
107 LPVOID APIENTRY Imm32HeapAlloc(DWORD dwFlags, DWORD dwBytes)
108 {
109     if (!g_hImm32Heap)
110     {
111         g_hImm32Heap = RtlGetProcessHeap();
112         if (g_hImm32Heap == NULL)
113             return NULL;
114     }
115     return HeapAlloc(g_hImm32Heap, dwFlags, dwBytes);
116 }
117 
118 BOOL APIENTRY
119 Imm32NotifyAction(HIMC hIMC, HWND hwnd, DWORD dwAction, DWORD_PTR dwIndex, DWORD_PTR dwValue,
120                   DWORD_PTR dwCommand, DWORD_PTR dwData)
121 {
122     DWORD dwLayout;
123     HKL hKL;
124     PIMEDPI pImeDpi;
125 
126     if (dwAction)
127     {
128         dwLayout = NtUserQueryInputContext(hIMC, 1);
129         if (dwLayout)
130         {
131             /* find keyboard layout and lock it */
132             hKL = GetKeyboardLayout(dwLayout);
133             pImeDpi = ImmLockImeDpi(hKL);
134             if (pImeDpi)
135             {
136                 /* do notify */
137                 pImeDpi->NotifyIME(hIMC, dwAction, dwIndex, dwValue);
138 
139                 ImmUnlockImeDpi(pImeDpi); /* unlock */
140             }
141         }
142     }
143 
144     if (hwnd && dwCommand)
145         SendMessageW(hwnd, WM_IME_NOTIFY, dwCommand, dwData);
146 
147     return TRUE;
148 }
149 
150 DWORD APIENTRY Imm32AllocAndBuildHimcList(DWORD dwThreadId, HIMC **pphList)
151 {
152 #define INITIAL_COUNT 0x40
153 #define MAX_RETRY 10
154     NTSTATUS Status;
155     DWORD dwCount = INITIAL_COUNT, cRetry = 0;
156     HIMC *phNewList;
157 
158     phNewList = Imm32HeapAlloc(0, dwCount * sizeof(HIMC));
159     if (phNewList == NULL)
160         return 0;
161 
162     Status = NtUserBuildHimcList(dwThreadId, dwCount, phNewList, &dwCount);
163     while (Status == STATUS_BUFFER_TOO_SMALL)
164     {
165         HeapFree(g_hImm32Heap, 0, phNewList);
166         if (cRetry++ >= MAX_RETRY)
167             return 0;
168 
169         phNewList = Imm32HeapAlloc(0, dwCount * sizeof(HIMC));
170         if (phNewList == NULL)
171             return 0;
172 
173         Status = NtUserBuildHimcList(dwThreadId, dwCount, phNewList, &dwCount);
174     }
175 
176     if (NT_ERROR(Status) || !dwCount)
177     {
178         HeapFree(g_hImm32Heap, 0, phNewList);
179         return 0;
180     }
181 
182     *pphList = phNewList;
183     return dwCount;
184 #undef INITIAL_COUNT
185 #undef MAX_RETRY
186 }
187 
188 /***********************************************************************
189  *		ImmCreateIMCC(IMM32.@)
190  */
191 HIMCC WINAPI ImmCreateIMCC(DWORD size)
192 {
193     if (size < 4)
194         size = 4;
195     return LocalAlloc(LHND, size);
196 }
197 
198 /***********************************************************************
199  *       ImmDestroyIMCC(IMM32.@)
200  */
201 HIMCC WINAPI ImmDestroyIMCC(HIMCC block)
202 {
203     if (block)
204         return LocalFree(block);
205     return NULL;
206 }
207 
208 /***********************************************************************
209  *		ImmLockIMCC(IMM32.@)
210  */
211 LPVOID WINAPI ImmLockIMCC(HIMCC imcc)
212 {
213     if (imcc)
214         return LocalLock(imcc);
215     return NULL;
216 }
217 
218 /***********************************************************************
219  *		ImmUnlockIMCC(IMM32.@)
220  */
221 BOOL WINAPI ImmUnlockIMCC(HIMCC imcc)
222 {
223     if (imcc)
224         return LocalUnlock(imcc);
225     return FALSE;
226 }
227 
228 /***********************************************************************
229  *		ImmGetIMCCLockCount(IMM32.@)
230  */
231 DWORD WINAPI ImmGetIMCCLockCount(HIMCC imcc)
232 {
233     return LocalFlags(imcc) & LMEM_LOCKCOUNT;
234 }
235 
236 /***********************************************************************
237  *		ImmReSizeIMCC(IMM32.@)
238  */
239 HIMCC WINAPI ImmReSizeIMCC(HIMCC imcc, DWORD size)
240 {
241     if (!imcc)
242         return NULL;
243     return LocalReAlloc(imcc, size, LHND);
244 }
245 
246 /***********************************************************************
247  *		ImmGetIMCCSize(IMM32.@)
248  */
249 DWORD WINAPI ImmGetIMCCSize(HIMCC imcc)
250 {
251     if (imcc)
252         return LocalSize(imcc);
253     return 0;
254 }
255 
256 /***********************************************************************
257  *		ImmGetIMCLockCount(IMM32.@)
258  */
259 DWORD WINAPI ImmGetIMCLockCount(HIMC hIMC)
260 {
261     DWORD ret;
262     HIMC hClientImc;
263     PCLIENTIMC pClientImc;
264 
265     pClientImc = ImmLockClientImc(hIMC);
266     if (pClientImc == NULL)
267         return 0;
268 
269     ret = 0;
270     hClientImc = pClientImc->hImc;
271     if (hClientImc)
272         ret = (LocalFlags(hClientImc) & LMEM_LOCKCOUNT);
273 
274     ImmUnlockClientImc(pClientImc);
275     return ret;
276 }
277