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