Fixed accelerator handling. ACCEL16 used internal, ACCEL32 for Win32
API, PE_ACCEL for PE Accelerators. See documentation/accelerators.
This commit is contained in:
parent
f25ac7ccc5
commit
688c565880
|
@ -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.
|
|
@ -119,6 +119,16 @@ 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
|
||||||
|
{
|
||||||
|
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
|
typedef struct
|
||||||
{
|
{
|
||||||
BYTE fVirt;
|
BYTE fVirt;
|
||||||
|
@ -126,7 +136,7 @@ typedef struct
|
||||||
WORD key;
|
WORD key;
|
||||||
WORD cmd;
|
WORD cmd;
|
||||||
WORD pad1;
|
WORD pad1;
|
||||||
} ACCEL32, *LPACCEL32;
|
} PE_ACCEL, *LPPE_ACCEL;
|
||||||
|
|
||||||
DECL_WINELIB_TYPE(ACCEL)
|
DECL_WINELIB_TYPE(ACCEL)
|
||||||
DECL_WINELIB_TYPE(LPACCEL)
|
DECL_WINELIB_TYPE(LPACCEL)
|
||||||
|
|
|
@ -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)
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
/* 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,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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++;
|
||||||
|
@ -535,6 +547,8 @@ 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)
|
||||||
|
|
||||||
|
|
||||||
/* 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,30 +600,7 @@ 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); */
|
||||||
|
|
||||||
/* 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;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue