Why do some WinAPI functions need struct sizes passed as their parameters?

For example, consider SendInput

. The signature looks like this:

UINT WINAPI SendInput(
  _In_ UINT    nInputs,
  _In_ LPINPUT pInputs,
  _In_ int     cbSize
);

      

The documentation says:

cbSize [in] Type: int The size, in bytes, of the INPUT structure. If cbSize is not the size of the INPUT structure, the function does not work.

Since the function already uses an INPUT structure (and probably does something with its various fields), shouldn't the size of the structure be known in advance?

The only reason I can imagine is some odd backward compatibility trick to keep old file libraries compatible with newer header files, which may have introduced new fields at the end of the structure.

+3


source to share


2 answers


This is a simple form of source control for structs.

In a later version of the API, you can add more fields to the end of the structure, which will change its size. Programs written for an older version will not have the specified values ​​in the new fields, and the cbSize parameter will reflect this. This API can check the cbSize and know which version of the structure it actually has, and provide default values ​​for new fields as needed.

An alternative would be to define a new framework that has a lot to do with the old framework, and then create a new API that works just like the old one. This is a lot of code duplication and it makes it harder to re-compile old programs using the new SDK and keep working.



Using a size field eliminates the need for duplicate code. This was the usual way of doing things in C, but less type-safe.

But that's a little dangerous too. If the caller has not set the correct size field, or if the API implementation is not very careful, this scheme can lead to access violations, reading uninitialized fields, or writing past the end of a structure.

+14


source


Yes, this is done, so Microsoft may change the INPUT structure in a future version of winapi. From the passed cbSize, it can determine if the program is using the old or new version of the structure. This is not easy to detect from the structure itself.

Passing it as an argument to a function is not common, they usually insert it cbSize

as a member of a structure. Compare with WNDCLASSEX , MENUITEMINFO, SCROLLINFO, MSGBOXPARAMS for example. It is easier to do this with just one argument for functions like SendInput () and GetMouseMovePointsEx () because they take arrays of structures.



Another approach is for structures like LVITEM , LVCOLUMN, etc., they don't use cbSize at all. Using api requires you to explicitly specify the desired version in the manifest .

+6


source







All Articles