diff --git a/documentation/accelerators b/documentation/accelerators new file mode 100644 index 00000000000..df4adab32da --- /dev/null +++ b/documentation/accelerators @@ -0,0 +1,38 @@ +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. diff --git a/include/winuser.h b/include/winuser.h index 71cabc0cd03..8d7fd494571 100644 --- a/include/winuser.h +++ b/include/winuser.h @@ -119,6 +119,16 @@ typedef struct { HBITMAP32 hbmColor; } ICONINFO,*LPICONINFO; +/* this is the 6 byte accel struct used in Win32 when presented to the user */ +typedef struct +{ + BYTE fVirt; + BYTE pad0; + WORD key; + WORD cmd; +} ACCEL32, *LPACCEL32; + +/* this is the 8 byte accel struct used in Win32 resources (internal only) */ typedef struct { BYTE fVirt; @@ -126,7 +136,7 @@ typedef struct WORD key; WORD cmd; WORD pad1; -} ACCEL32, *LPACCEL32; +} PE_ACCEL, *LPPE_ACCEL; DECL_WINELIB_TYPE(ACCEL) DECL_WINELIB_TYPE(LPACCEL) diff --git a/loader/resource.c b/loader/resource.c index 96e5017b547..6313649e829 100644 --- a/loader/resource.c +++ b/loader/resource.c @@ -13,6 +13,7 @@ #include #include #include "windows.h" +#include "wine/winuser16.h" #include "gdi.h" #include "global.h" #include "heap.h" @@ -425,7 +426,7 @@ HACCEL16 WINAPI LoadAccelerators16(HINSTANCE16 instance, SEGPTR lpTableName) HACCEL32 WINAPI LoadAccelerators32W(HINSTANCE32 instance,LPCWSTR lpTableName) { HRSRC32 hRsrc; - HACCEL32 hRetval; + HACCEL32 hMem,hRetval; DWORD size; if (HIWORD(lpTableName)) @@ -441,16 +442,24 @@ HACCEL32 WINAPI LoadAccelerators32W(HINSTANCE32 instance,LPCWSTR lpTableName) hRetval = 0; } else { - hRetval = LoadResource32( instance, hRsrc ); + hMem = LoadResource32( instance, hRsrc ); size = SizeofResource32( instance, hRsrc ); - if(size>=sizeof(ACCEL32)) + if(size>=sizeof(PE_ACCEL)) { - LPACCEL32 accel_table = (LPACCEL32) hRetval; - /* mark last element as such - sometimes it is not marked in image */ - accel_table[size/sizeof(ACCEL32)-1].fVirt |= 0x80; + LPPE_ACCEL accel_table = (LPPE_ACCEL) hMem; + LPACCEL16 accel16; + int i,nrofaccells = size/sizeof(PE_ACCEL); + + hRetval = GlobalAlloc16(0,sizeof(ACCEL16)*nrofaccells); + accel16 = (LPACCEL16)GlobalLock16(hRetval); + for (i=0;ientries) entries=xsize; i=0; while(!done) { @@ -506,7 +516,9 @@ INT32 WINAPI CopyAcceleratorTable32W(HACCEL32 src, LPACCEL32 dst, /* Copy data to the destination structure array (if dst == NULL, we're just supposed to count the number of entries). */ 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 accelerator table. */ @@ -518,7 +530,7 @@ INT32 WINAPI CopyAcceleratorTable32W(HACCEL32 src, LPACCEL32 dst, } /* 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; i++; @@ -534,7 +546,9 @@ INT32 WINAPI CopyAcceleratorTable32W(HACCEL32 src, LPACCEL32 dst, */ 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 funny. */ @@ -549,18 +563,22 @@ HACCEL32 WINAPI CreateAcceleratorTable32A(LPACCEL32 lpaccel, INT32 cEntries) /* Allocate memory and copy the table. */ - hAccel = (HACCEL32)HeapAlloc(GetProcessHeap(), 0, - cEntries * sizeof(ACCEL32)); - TRACE(accel, "handle %p\n", (LPVOID)hAccel); + hAccel = GlobalAlloc16(0,cEntries*sizeof(ACCEL16)); + + TRACE(accel, "handle %x\n", hAccel); if(!hAccel) { ERR(accel, "Out of memory.\n"); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return (HACCEL32)NULL; } - memcpy((LPACCEL32)hAccel, lpaccel, cEntries * sizeof(ACCEL32)); - + accel = GlobalLock16(hAccel); + for (i=0;imessage, msg->wParam, msg->lParam);