Commit 688c5658 authored by Marcus Meissner's avatar Marcus Meissner Committed by Alexandre Julliard

Fixed accelerator handling. ACCEL16 used internal, ACCEL32 for Win32

API, PE_ACCEL for PE Accelerators. See documentation/accelerators.
parent f25ac7cc
Some notes concerning accelerators.
There are _three_ differently sized accelerator structures exposed to the
user. The general layout is:
BYTE fVirt;
WORD key;
WORD cmd;
We now have three different appearances:
- Accelerators in NE resources. These have a size of 5 byte and do not have
any padding. This is also the internal layout of the global handle HACCEL
(16 and 32) in Windows 95 and WINE. Exposed to the user as Win16 global
handles HACCEL16 and HACCEL32 by the Win16/Win32 API.
- Accelerators in PE resources. These have a size of 8 byte. Layout is:
BYTE fVirt;
BYTE pad0;
WORD key;
WORD cmd;
WORD pad1;
They are exposed to the user only by direct accessing PE resources.
- Accelerators in the Win32 API. These have a size of 6 byte. Layout is:
BYTE fVirt;
BYTE pad0;
WORD key;
WORD cmd;
These are exposed to the user by the CopyAcceleratorTable and
CreateAcceleratorTable in the Win32 API.
Why two types of accelerators in the Win32 API? We can only guess, but
my best bet is that the Win32 resource compiler can/does not handle struct
packing. Win32 ACCEL is defined using #pragma(2) for the compiler but without
any packing for RC, so it will assume #pragma(4).
Findings researched by Uwe Bonnes, Ulrich Weigand and Marcus Meissner.
...@@ -119,15 +119,25 @@ typedef struct { ...@@ -119,15 +119,25 @@ typedef struct {
HBITMAP32 hbmColor; HBITMAP32 hbmColor;
} ICONINFO,*LPICONINFO; } ICONINFO,*LPICONINFO;
/* this is the 6 byte accel struct used in Win32 when presented to the user */
typedef struct typedef struct
{ {
BYTE fVirt; BYTE fVirt;
BYTE pad0; BYTE pad0;
WORD key; WORD key;
WORD cmd; WORD cmd;
WORD pad1;
} ACCEL32, *LPACCEL32; } ACCEL32, *LPACCEL32;
/* this is the 8 byte accel struct used in Win32 resources (internal only) */
typedef struct
{
BYTE fVirt;
BYTE pad0;
WORD key;
WORD cmd;
WORD pad1;
} PE_ACCEL, *LPPE_ACCEL;
DECL_WINELIB_TYPE(ACCEL) DECL_WINELIB_TYPE(ACCEL)
DECL_WINELIB_TYPE(LPACCEL) DECL_WINELIB_TYPE(LPACCEL)
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include "windows.h" #include "windows.h"
#include "wine/winuser16.h"
#include "gdi.h" #include "gdi.h"
#include "global.h" #include "global.h"
#include "heap.h" #include "heap.h"
...@@ -425,7 +426,7 @@ HACCEL16 WINAPI LoadAccelerators16(HINSTANCE16 instance, SEGPTR lpTableName) ...@@ -425,7 +426,7 @@ HACCEL16 WINAPI LoadAccelerators16(HINSTANCE16 instance, SEGPTR lpTableName)
HACCEL32 WINAPI LoadAccelerators32W(HINSTANCE32 instance,LPCWSTR lpTableName) HACCEL32 WINAPI LoadAccelerators32W(HINSTANCE32 instance,LPCWSTR lpTableName)
{ {
HRSRC32 hRsrc; HRSRC32 hRsrc;
HACCEL32 hRetval; HACCEL32 hMem,hRetval;
DWORD size; DWORD size;
if (HIWORD(lpTableName)) if (HIWORD(lpTableName))
...@@ -441,16 +442,24 @@ HACCEL32 WINAPI LoadAccelerators32W(HINSTANCE32 instance,LPCWSTR lpTableName) ...@@ -441,16 +442,24 @@ HACCEL32 WINAPI LoadAccelerators32W(HINSTANCE32 instance,LPCWSTR lpTableName)
hRetval = 0; hRetval = 0;
} }
else { else {
hRetval = LoadResource32( instance, hRsrc ); hMem = LoadResource32( instance, hRsrc );
size = SizeofResource32( instance, hRsrc ); size = SizeofResource32( instance, hRsrc );
if(size>=sizeof(ACCEL32)) if(size>=sizeof(PE_ACCEL))
{ {
LPACCEL32 accel_table = (LPACCEL32) hRetval; LPPE_ACCEL accel_table = (LPPE_ACCEL) hMem;
/* mark last element as such - sometimes it is not marked in image */ LPACCEL16 accel16;
accel_table[size/sizeof(ACCEL32)-1].fVirt |= 0x80; int i,nrofaccells = size/sizeof(PE_ACCEL);
hRetval = GlobalAlloc16(0,sizeof(ACCEL16)*nrofaccells);
accel16 = (LPACCEL16)GlobalLock16(hRetval);
for (i=0;i<nrofaccells;i++) {
accel16[i].fVirt = accel_table[i].fVirt;
accel16[i].key = accel_table[i].key;
accel16[i].cmd = accel_table[i].cmd;
}
accel16[i-1].fVirt |= 0x80;
} }
} }
TRACE(accel, "returning HACCEL 0x%x\n", hRsrc); TRACE(accel, "returning HACCEL 0x%x\n", hRsrc);
return hRetval; return hRetval;
} }
...@@ -484,18 +493,19 @@ INT32 WINAPI CopyAcceleratorTable32A(HACCEL32 src, LPACCEL32 dst, INT32 entries) ...@@ -484,18 +493,19 @@ INT32 WINAPI CopyAcceleratorTable32A(HACCEL32 src, LPACCEL32 dst, INT32 entries)
INT32 WINAPI CopyAcceleratorTable32W(HACCEL32 src, LPACCEL32 dst, INT32 WINAPI CopyAcceleratorTable32W(HACCEL32 src, LPACCEL32 dst,
INT32 entries) INT32 entries)
{ {
int i; int i,xsize;
LPACCEL32 accel = (LPACCEL32)src; LPACCEL16 accel = (LPACCEL16)GlobalLock16(src);
BOOL32 done = FALSE; BOOL32 done = FALSE;
/* Do parameter checking to avoid the explosions and the screaming /* Do parameter checking to avoid the explosions and the screaming
as far as possible. */ as far as possible. */
if((dst && (entries < 1)) || (src == (HACCEL32)NULL)) { if((dst && (entries < 1)) || (src == (HACCEL32)NULL) || !accel) {
WARN(accel, "Application sent invalid parameters (%p %p %d).\n", WARN(accel, "Application sent invalid parameters (%p %p %d).\n",
(LPVOID)src, (LPVOID)dst, entries); (LPVOID)src, (LPVOID)dst, entries);
return 0; return 0;
} }
xsize = GlobalSize16(src)/sizeof(ACCEL16);
if (xsize>entries) entries=xsize;
i=0; i=0;
while(!done) { while(!done) {
...@@ -506,7 +516,9 @@ INT32 WINAPI CopyAcceleratorTable32W(HACCEL32 src, LPACCEL32 dst, ...@@ -506,7 +516,9 @@ INT32 WINAPI CopyAcceleratorTable32W(HACCEL32 src, LPACCEL32 dst,
/* Copy data to the destination structure array (if dst == NULL, /* Copy data to the destination structure array (if dst == NULL,
we're just supposed to count the number of entries). */ we're just supposed to count the number of entries). */
if(dst) { if(dst) {
memcpy(&dst[i], &accel[i], sizeof(ACCEL32)); dst[i].fVirt = accel[i].fVirt;
dst[i].key = accel[i].key;
dst[i].cmd = accel[i].cmd;
/* Check if we've reached the end of the application supplied /* Check if we've reached the end of the application supplied
accelerator table. */ accelerator table. */
...@@ -518,7 +530,7 @@ INT32 WINAPI CopyAcceleratorTable32W(HACCEL32 src, LPACCEL32 dst, ...@@ -518,7 +530,7 @@ INT32 WINAPI CopyAcceleratorTable32W(HACCEL32 src, LPACCEL32 dst,
} }
/* The highest order bit seems to mark the end of the accelerator /* The highest order bit seems to mark the end of the accelerator
resource table. (?) */ resource table, but not always. Use GlobalSize() check too. */
if((accel[i].fVirt & 0x80) != 0) done = TRUE; if((accel[i].fVirt & 0x80) != 0) done = TRUE;
i++; i++;
...@@ -534,7 +546,9 @@ INT32 WINAPI CopyAcceleratorTable32W(HACCEL32 src, LPACCEL32 dst, ...@@ -534,7 +546,9 @@ INT32 WINAPI CopyAcceleratorTable32W(HACCEL32 src, LPACCEL32 dst,
*/ */
HACCEL32 WINAPI CreateAcceleratorTable32A(LPACCEL32 lpaccel, INT32 cEntries) HACCEL32 WINAPI CreateAcceleratorTable32A(LPACCEL32 lpaccel, INT32 cEntries)
{ {
HACCEL32 hAccel; HACCEL32 hAccel;
LPACCEL16 accel;
int i;
/* Do parameter checking just in case someone's trying to be /* Do parameter checking just in case someone's trying to be
funny. */ funny. */
...@@ -549,18 +563,22 @@ HACCEL32 WINAPI CreateAcceleratorTable32A(LPACCEL32 lpaccel, INT32 cEntries) ...@@ -549,18 +563,22 @@ HACCEL32 WINAPI CreateAcceleratorTable32A(LPACCEL32 lpaccel, INT32 cEntries)
/* Allocate memory and copy the table. */ /* Allocate memory and copy the table. */
hAccel = (HACCEL32)HeapAlloc(GetProcessHeap(), 0, hAccel = GlobalAlloc16(0,cEntries*sizeof(ACCEL16));
cEntries * sizeof(ACCEL32));
TRACE(accel, "handle %p\n", (LPVOID)hAccel); TRACE(accel, "handle %x\n", hAccel);
if(!hAccel) { if(!hAccel) {
ERR(accel, "Out of memory.\n"); ERR(accel, "Out of memory.\n");
SetLastError(ERROR_NOT_ENOUGH_MEMORY); SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return (HACCEL32)NULL; return (HACCEL32)NULL;
} }
memcpy((LPACCEL32)hAccel, lpaccel, cEntries * sizeof(ACCEL32)); accel = GlobalLock16(hAccel);
for (i=0;i<cEntries;i++) {
accel[i].fVirt = lpaccel[i].fVirt;
accel[i].key = lpaccel[i].key;
accel[i].cmd = lpaccel[i].cmd;
}
/* Set the end-of-table terminator. */ /* Set the end-of-table terminator. */
((LPACCEL32)hAccel)[cEntries-1].fVirt |= 0x80; accel[cEntries-1].fVirt |= 0x80;
TRACE(accel, "Allocated accelerator handle %x\n", hAccel); TRACE(accel, "Allocated accelerator handle %x\n", hAccel);
return hAccel; return hAccel;
...@@ -582,31 +600,8 @@ HACCEL32 WINAPI CreateAcceleratorTable32A(LPACCEL32 lpaccel, INT32 cEntries) ...@@ -582,31 +600,8 @@ HACCEL32 WINAPI CreateAcceleratorTable32A(LPACCEL32 lpaccel, INT32 cEntries)
BOOL32 WINAPI DestroyAcceleratorTable( HACCEL32 handle ) BOOL32 WINAPI DestroyAcceleratorTable( HACCEL32 handle )
{ {
FIXME(accel, "(0x%x): stub\n", handle); FIXME(accel, "(0x%x): stub\n", handle);
/* FIXME: GlobalFree16(handle); */
return TRUE;
/* Weird.. I thought this should work. According to the API
specification, DestroyAcceleratorTable() should only be called on
HACCEL32's made by CreateAcceleratorTable(), but Microsoft Visual
Studio 97 calls this function with a series of different handle
values without ever calling CreateAcceleratorTable(). Something
is very fishy in Denmark... */
/* Update: looks like the calls to this function matches the calls
to LoadAccelerators() in M$ Visual Studio, except that the handle
values are off by some variable size from the HACCEL's returned
from LoadAccelerators(). WTH? */
/* Parameter checking to avoid any embarassing situations. */
#if 0
if(!handle) {
WARN(accel, "Application sent NULL ptr.\n");
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
HeapFree(GetProcessHeap(), 0, (LPACCEL32)handle);
#endif
return TRUE;
} }
/********************************************************************** /**********************************************************************
......
...@@ -603,7 +603,8 @@ static BOOL32 KBD_translate_accelerator(HWND32 hWnd,LPMSG32 msg, ...@@ -603,7 +603,8 @@ static BOOL32 KBD_translate_accelerator(HWND32 hWnd,LPMSG32 msg,
*/ */
INT32 WINAPI TranslateAccelerator32(HWND32 hWnd, HACCEL32 hAccel, LPMSG32 msg) INT32 WINAPI TranslateAccelerator32(HWND32 hWnd, HACCEL32 hAccel, LPMSG32 msg)
{ {
LPACCEL32 lpAccelTbl = (LPACCEL32)LockResource32(hAccel); /* YES, Accel16! */
LPACCEL16 lpAccelTbl = (LPACCEL16)LockResource16(hAccel);
int i; int i;
TRACE(accel,"hwnd=0x%x hacc=0x%x msg=0x%x wp=0x%x lp=0x%lx\n", hWnd, hAccel, msg->message, msg->wParam, msg->lParam); TRACE(accel,"hwnd=0x%x hacc=0x%x msg=0x%x wp=0x%x lp=0x%lx\n", hWnd, hAccel, msg->message, msg->wParam, msg->lParam);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment