[SHELL32] SHCreateDefaultContextMenu: Pass HWND to callback (#6764)
[reactos.git] / dll / win32 / imm32 / utils.c
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 Imm32HeapFree(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 Imm32HeapFree(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 }