CopyAcceleratorTableA: dont access lpAccelDst it its NULL (w3seek)
[reactos.git] / reactos / lib / user32 / windows / accel.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * PROJECT: ReactOS user32.dll
22 * FILE: lib/user32/windows/input.c
23 * PURPOSE: Accelerator tables
24 * PROGRAMMER: KJK::Hyperion <noog@libero.it>
25 * UPDATE HISTORY:
26 * 09/05/2001 CSH Created
27 * 08/07/2003 KJK Fully implemented
28 */
29
30 /* INCLUDES ******************************************************************/
31
32 #include "user32.h"
33 #include <user32/accel.h>
34 #include <win32k/ntuser.h>
35
36 /* this is the 8 byte accel struct used in Win32 resources (internal only) */
37 typedef struct
38 {
39 BYTE fVirt;
40 BYTE pad0;
41 WORD key;
42 WORD cmd;
43 WORD pad1;
44 } PE_ACCEL, *LPPE_ACCEL;
45
46 /* FUNCTIONS *****************************************************************/
47
48 /* Lock guarding the cache */
49 CRITICAL_SECTION U32AccelCacheLock;
50
51 /* Cache */
52 U32_ACCEL_CACHE_ENTRY * U32AccelCache = NULL;
53
54 /* Look up a handle or resource address in the cache */
55 U32_ACCEL_CACHE_ENTRY ** WINAPI U32AccelCacheFind(HANDLE Object, HGLOBAL Data)
56 {
57 /*
58 to avoid using a double-link list and still allow elements to be removed,
59 return a pointer to the list link that points to the desired entry
60 */
61 U32_ACCEL_CACHE_ENTRY ** ppEntry = &U32AccelCache;
62
63 for(; *ppEntry; ppEntry = &((*ppEntry)->Next))
64 if((*ppEntry)->Object == Object || (*ppEntry)->Data == Data) break;
65
66 return ppEntry;
67 }
68
69 /* Allocate an entry and insert it into the cache */
70 void WINAPI U32AccelCacheAdd(HACCEL Object, HGLOBAL Data)
71 {
72 U32_ACCEL_CACHE_ENTRY * pEntry =
73 LocalAlloc(LMEM_FIXED, sizeof(U32_ACCEL_CACHE_ENTRY));
74
75 /* failed to allocate an entry - not critical */
76 if(pEntry == NULL) return;
77
78 /* initialize the entry */
79 pEntry->Usage = 1;
80 pEntry->Object = Object;
81 pEntry->Data = Data;
82
83 /* insert the entry into the cache */
84 pEntry->Next = U32AccelCache;
85 U32AccelCache = pEntry;
86 }
87
88 /* Create an accelerator table from a loaded resource */
89 HACCEL WINAPI U32LoadAccelerators(HINSTANCE hInstance, HRSRC hTableRes)
90 {
91 HGLOBAL hAccTableData;
92 HACCEL hAccTable = NULL;
93 U32_ACCEL_CACHE_ENTRY * pEntry;
94 PE_ACCEL * pAccTableResData;
95 SIZE_T i = 0;
96 SIZE_T j = 0;
97 ACCEL * pAccTableData;
98
99 /* load the accelerator table */
100 hAccTableData = LoadResource(hInstance, hTableRes);
101
102 /* failure */
103 if(hAccTableData == NULL) return NULL;
104
105 EnterCriticalSection(&U32AccelCacheLock);
106
107 /* see if this accelerator table has already been loaded */
108 pEntry = *U32AccelCacheFind(NULL, hAccTableData);
109
110 /* accelerator table already loaded */
111 if(pEntry)
112 {
113 /* increment the reference count */
114 ++ pEntry->Usage;
115
116 /* return the existing object */
117 hAccTable = pEntry->Object;
118
119 /* success */
120 goto l_Leave;
121 }
122
123 /* determine the number of entries in the table */
124 i = SizeofResource(hInstance, hTableRes) / sizeof(PE_ACCEL);
125
126 /* allocate the buffer for the table to be passed to Win32K */
127 pAccTableData = LocalAlloc(LMEM_FIXED, i * sizeof(ACCEL));
128
129 /* failure */
130 if(pAccTableData == NULL) goto l_Leave;
131
132 pAccTableResData = (PE_ACCEL *)hAccTableData;
133
134 /* copy the table */
135 for(j = 0; j < i; ++ j)
136 {
137 pAccTableData[j].fVirt = pAccTableResData[j].fVirt;
138 pAccTableData[j].key = pAccTableResData[j].key;
139 pAccTableData[j].cmd = pAccTableResData[j].cmd;
140 }
141 pAccTableData[i - 1].fVirt |= 0x80;
142
143 /* create a new accelerator table object */
144 hAccTable = NtUserCreateAcceleratorTable(pAccTableData, i);
145
146 /* free the buffer */
147 LocalFree(pAccTableData);
148
149 /* failure */
150 if(hAccTable == NULL) goto l_Leave;
151
152 /* success - cache the object */
153 U32AccelCacheAdd(hAccTable, pAccTableResData);
154
155 l_Leave:
156 LeaveCriticalSection(&U32AccelCacheLock);
157 return hAccTable;
158 }
159
160 /* Checks if a message can be translated through an accelerator table */
161 BOOL WINAPI U32IsValidAccelMessage(UINT uMsg)
162 {
163 switch(uMsg)
164 {
165 case WM_KEYDOWN:
166 case WM_KEYUP:
167 case WM_CHAR:
168 case WM_SYSKEYDOWN:
169 case WM_SYSKEYUP:
170 return TRUE;
171
172 default:
173 return FALSE;
174 }
175 }
176
177 /* WIN32 FUNCTIONS ***********************************************************/
178
179 /*
180 * Dereference the specified accelerator table, removing it from the cache and
181 * deleting the associated NtUser object as appropriate
182 *
183 * @implemented
184 */
185 BOOL WINAPI DestroyAcceleratorTable(HACCEL hAccel)
186 {
187 U32_ACCEL_CACHE_ENTRY ** ppEntry;
188 ULONG_PTR nUsage = 0;
189
190 EnterCriticalSection(&U32AccelCacheLock);
191
192 /* see if this accelerator table has been cached */
193 ppEntry = U32AccelCacheFind(hAccel, NULL);
194
195 /* accelerator table cached */
196 if(*ppEntry)
197 {
198 U32_ACCEL_CACHE_ENTRY * pEntry = *ppEntry;
199
200 /* decrement the reference count */
201 nUsage = pEntry->Usage = pEntry->Usage - 1;
202
203 /* reference count now zero: destroy the cache entry */
204 if(nUsage == 0)
205 {
206 /* unlink the cache entry */
207 *ppEntry = pEntry->Next;
208
209 /* free the cache entry */
210 LocalFree(pEntry);
211 }
212 }
213
214 LeaveCriticalSection(&U32AccelCacheLock);
215
216 if(nUsage > 0) return FALSE;
217
218 /* destroy the object */
219 return NtUserDestroyAcceleratorTable(hAccel);
220 }
221
222
223 /*
224 * Create an accelerator table from a named resource
225 *
226 * @implemented
227 */
228 HACCEL WINAPI LoadAcceleratorsW(HINSTANCE hInstance, LPCWSTR lpTableName)
229 {
230 return U32LoadAccelerators
231 (
232 hInstance,
233 FindResourceExW(hInstance, MAKEINTRESOURCEW(RT_ACCELERATOR), lpTableName, 0)
234 );
235 }
236
237
238 /*
239 * @implemented
240 */
241 HACCEL WINAPI LoadAcceleratorsA(HINSTANCE hInstance, LPCSTR lpTableName)
242 {
243 HRSRC Accel;
244
245 Accel = FindResourceExA(hInstance, MAKEINTRESOURCEA(RT_ACCELERATOR), lpTableName, 0);
246 if (NULL == Accel)
247 {
248 return NULL;
249 }
250
251 return U32LoadAccelerators(hInstance, Accel);
252 }
253
254 /*
255 * Translate a key press into a WM_COMMAND message
256 *
257 * @implemented
258 */
259 int WINAPI TranslateAcceleratorW(HWND hWnd, HACCEL hAccTable, LPMSG lpMsg)
260 {
261 if(!U32IsValidAccelMessage(lpMsg->message)) return 0;
262
263 return NtUserTranslateAccelerator(hWnd, hAccTable, lpMsg);
264 }
265
266 /*
267 * @implemented
268 */
269 int WINAPI CopyAcceleratorTableW
270 (
271 HACCEL hAccelSrc,
272 LPACCEL lpAccelDst,
273 int cAccelEntries
274 )
275 {
276 return NtUserCopyAcceleratorTable(hAccelSrc, lpAccelDst, cAccelEntries);
277 }
278
279 /*
280 * @implemented
281 */
282 HACCEL WINAPI CreateAcceleratorTableW(LPACCEL lpaccl, int cEntries)
283 {
284 return NtUserCreateAcceleratorTable(lpaccl, cEntries);
285 }
286
287
288 int WINAPI CopyAcceleratorTableA
289 (
290 HACCEL hAccelSrc,
291 LPACCEL lpAccelDst, /* can be NULL */
292 int cAccelEntries
293 )
294 {
295 int i;
296
297 cAccelEntries = CopyAcceleratorTableW(hAccelSrc, lpAccelDst, cAccelEntries);
298
299 if (lpAccelDst == NULL) return cAccelEntries;
300
301 for(i = 0; i < cAccelEntries; ++ i)
302 if(!(lpAccelDst[i].fVirt & FVIRTKEY))
303 {
304 NTSTATUS nErrCode = RtlUnicodeToMultiByteN(
305 (PCHAR)&lpAccelDst[i].key,
306 sizeof(lpAccelDst[i].key),
307 NULL,
308 (PWCHAR)&lpAccelDst[i].key,
309 sizeof(lpAccelDst[i].key)
310 );
311
312 if(!NT_SUCCESS(nErrCode)) lpAccelDst[i].key = 0;
313 }
314
315 return cAccelEntries;
316 }
317
318
319 /*
320 * @implemented
321 */
322 HACCEL WINAPI CreateAcceleratorTableA(LPACCEL lpaccl, int cEntries)
323 {
324 int i;
325
326 for(i = 0; i < cEntries; ++ i)
327 if(!lpaccl[i].fVirt)
328 {
329 NTSTATUS nErrCode = RtlMultiByteToUnicodeN
330 (
331 (PWCHAR)&lpaccl[i].key,
332 sizeof(lpaccl[i].key),
333 NULL,
334 (PCHAR)&lpaccl[i].key,
335 sizeof(lpaccl[i].key)
336 );
337
338 if(!NT_SUCCESS(nErrCode)) lpaccl[i].key = -1;
339 }
340
341 return CreateAcceleratorTableW(lpaccl, cEntries);
342 }
343
344
345 /*
346 * @implemented
347 */
348 int WINAPI TranslateAcceleratorA(HWND hWnd, HACCEL hAccTable, LPMSG lpMsg)
349 {
350 MSG mCopy = *lpMsg;
351 CHAR cChar;
352 WCHAR wChar;
353 NTSTATUS Status;
354
355 if(!U32IsValidAccelMessage(lpMsg->message)) return 0;
356
357 Status = RtlMultiByteToUnicodeN(&wChar, sizeof(wChar), NULL, &cChar, sizeof(cChar));
358 if(!NT_SUCCESS(Status))
359 {
360 SetLastError(RtlNtStatusToDosError(Status));
361 return 0;
362 }
363
364 return TranslateAcceleratorW(hWnd, hAccTable, &mCopy);
365 }
366
367 /* EOF */