The format of accelerator table resources

Date:March 16, 2007 / year-entry #96
Tags:code
Orig Link:https://blogs.msdn.microsoft.com/oldnewthing/20070316-00/?p=27593
Comments:    9
Summary:Continuing in the extremely sporadic series on the format of resources, today we'll take a look at accelerator tables. This topic is so simple, I'll cover both 16-bit and 32-bit resources on the same day! In 16-bit Windows, the format of an accelerator table resource was simply an array of ACCEL structures. typedef struct tagACCEL...

Continuing in the extremely sporadic series on the format of resources, today we'll take a look at accelerator tables. This topic is so simple, I'll cover both 16-bit and 32-bit resources on the same day!

In 16-bit Windows, the format of an accelerator table resource was simply an array of ACCEL structures.

typedef struct tagACCEL {
    BYTE fVirt;
    BYTE bPadding; /* making the padding explicit */
    WORD key;
    WORD cmd;
} ACCEL, *LPACCEL;

This array is the same array you would pass to the CreateAcceleratorTable, with one important difference: The fVirt of the last entry in the accelerator resource has its high bit set to indicate that it is the end of the table.

The format of 32-bit accelerator table resources is nearly identical to its 16-bit counterpart. The only difference is the addition of an additional word of padding to bring the size of the structure up to a multiple of four bytes.

typedef struct tagACCEL_RESOURCE {
    BYTE fVirt;
    BYTE bPadding; /* making the padding explicit */
    WORD key;
    WORD cmd;
    WORD wPadding; /* making the padding explicit */
} ACCEL_RESOURCE;

Once again, the last entry is marked by setting the high bit of the fVirt member. The extra word of padding adds a second obstacle to taking the resource data and passing it to the CreateAcceleratorTable function to create the accelerator table manually. Not only do you have to strip off the high bit of the fVirt, you also have to convert the table to an array of ACCEL structures and pass the converted table to the CreateAcceleratorTable function.

That's all there is to the format of accelerator table resources. I told you it was pretty simple.


Comments (9)
  1. Bobert says:

    So, I wonder if any software is using that padding word to store data?  It’s safe, right, because it’s just used for padding.

    Hmmm, maybe I’ll do that and in a few years when Microsoft finds use for that word my claim to fame will be a mention in your blog.

  2. Tim says:

    I’m now curious about the next blog entry.  

    It’s bound to be a "So you believed me when I said Accelerator resources were simple? Ha!" type entry, isn’t it? :-)

  3. josh says:

    "you also have to convert the table to an array of ACCEL structures and pass the converted table to the CreateAcceleratorTable function."

    That seems a bit silly, why add the padding if you’ll only have to remove it?  Is there another function that works on accelerator table resources and doesn’t go through CreateAcceleratorTable?

  4. Tom_ says:

    LoadAccelerators is the function you’re looking for, I think!

    There’s another that will take an accelerator table and copy it into an array of HACCEL structs. I vaguely recall having used this before for merging accelerator tables…

  5. Mike Dunn says:

    Bobert’s post makes me wonder – are padding bytes also considered reserved? Could the OS ever decide to use those for some other purpose in the future? Or will they be ignored forever?

  6. ramguru says:

    These series look promising…

  7. ramguru says:

    You guys who want to find sense in padding just think: STRING resource uses WORD PADDING to form an ID of starting string entry. If block of string has ID equal to 2 (each block has up to 16 entries), and you see that first entry (in that block) starts with 27 ID, so there are used 10 (ZERO) WORDS for padding…what a waste!!!! because:

    27=(2-1)*16 + 10 + 1 (first entry)

    28=(2-1)*16 + 10 + 2 (second entry)

    ….

  8. Norman Diamond says:

    WORD key;

    Hmm.  After discovering the hard way that in a Unicode window WM_CHAR really delivers the character value in Unicode, I’m wondering about this.  MSDN does describe that part of WM_CHAR correctly but slyly omits any mention of the corresponding character code here.  If FVIRTKEY is set then the value of key will fit in a byte, so the reason for being a WORD is "obviously" because wchar_t is that size.  Now I have to find a keyboard with a Euro sign on it, make the Euro an accelerator, and see if 0x20AC is really the correct value.

    I told you it was pretty simple.

    Sure, but the coding isn’t quite as simple as the format.  Recently I added accelerators to an MFC project, figured out how to implement a PreTranslateMessage method, and figured out a way to deliver accelerations to one window (not happy with the way I did it though), and other windows lost their accelerators.  Then I figured out that a class’s PreTranslateMessage method had better call its superclass (CWinApp::PreTranslateMessage) "most" of the time.  I think it would be better if MSDN would say this, even though it’s an MFC method.

    Saturday, March 17, 2007 1:46 AM by Mike Dunn

    are padding bytes also considered reserved?

    They can’t be.  Look at the structure declaration in MSDN, and the compiler can put any random garbage in the padding bytes.  The OS must treat the padding as ignored rather than reserved.

  9. josh says:

    Tom_: "LoadAccelerators is the function you’re looking for, I think!"

    I would expect that either LoadAccelerators goes through CreateAcceleratorTable, or there’s another internal function that wants the padding and CreateAcceleratorTable has to add the padding back in before calling that.  Both possibilities seem a bit weird to me.

Comments are closed.


*DISCLAIMER: I DO NOT OWN THIS CONTENT. If you are the owner and would like it removed, please contact me. The content herein is an archived reproduction of entries from Raymond Chen's "Old New Thing" Blog (most recent link is here). It may have slight formatting modifications for consistency and to improve readability.

WHY DID I DUPLICATE THIS CONTENT HERE? Let me first say this site has never had anything to sell and has never shown ads of any kind. I have nothing monetarily to gain by duplicating content here. Because I had made my own local copy of this content throughout the years, for ease of using tools like grep, I decided to put it online after I discovered some of the original content previously and publicly available, had disappeared approximately early to mid 2019. At the same time, I present the content in an easily accessible theme-agnostic way.

The information provided by Raymond's blog is, for all practical purposes, more authoritative on Windows Development than Microsoft's own MSDN documentation and should be considered supplemental reading to that documentation. The wealth of missing details provided by this blog that Microsoft could not or did not document about Windows over the years is vital enough, many would agree an online "backup" of these details is a necessary endeavor. Specifics include:

<-- Back to Old New Thing Archive Index