Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is everything in the Windows API typedef'd?

Tags:

c

typedef

winapi

More specifically, why is the same thing typedef'd with multiple different names in many cases, and why typedef pointer types (obscuring logic at times)?

For example:

typedef const WCHAR *LPCWSTR, *PCWSTR;

What is the point of that?

like image 984
Robert Allan Hennigan Leahy Avatar asked Jan 17 '12 04:01

Robert Allan Hennigan Leahy


People also ask

What is the purpose of Windows API?

The Windows API (application programming interface) allows user-written programs to interact with Windows, for example to display things on screen and get input from mouse and keyboard. All Windows programs except console programs must interact with the Windows API regardless of the language.

Why would you use typedef?

The typedef keyword allows the programmer to create new names for types such as int or, more commonly in C++, templated types--it literally stands for "type definition". Typedefs can be used both to provide more clarity to your code and to make it easier to make changes to the underlying data types that you use.

Do you need typedef in C++?

typedef is necessary for many template metaprogramming tasks -- whenever a class is treated as a "compile-time type function", a typedef is used as a "compile-time type value" to obtain the resulting type.

What are the data types accepted in window based programming?

The following table contains the following types: character, integer, Boolean, pointer, and handle. The character, integer, and Boolean types are common to most C compilers.


2 Answers

There's actually a few different things going on here:

  • First the Near/Far pointers: Back in Win16 days, you had near and far pointers; near pointers were basically just 16 bits offsets, so could only refer to objects within 64k of an app's default data pointer (DS or Data Segment register), but they were small and fast; whereas a larger 'far pointer' or long pointer consisted of both segment and offset, so could refer to anything within the 1M address space. When the 386 came along, all this segment:offset business finally went away, and all pointers were just 32 bit addresses into flat 32bit address spaces. And that's why there's both P... and LP... versions.

  • Why bother with typedefs in the first place? It's just a convenience or shorthand: typing "LPSTR" is more convenient than "const char far *". But it also becomes a recognizable idiom: you see LPSTR and know straight away that it's how Windows deals with strings in its API.

  • There's also an abstraction going on here: Windows generally defines its own versions of types and uses them instead of the C versions. So Windows APIs use DWORD instead of int, or VOID instead of void. This was needed to plug some holes in C at the time - there was no bool, so introducing BOOL avoided having different APIs use different types to represent boolean values (eg char vs int). It also to some extent made the Windows API independent of an underlying C implementation: C doesn't require that int is a specific size: it could be 16 bits or 32 bits depending on the compiler. But for an OS API, its important to specify these things exactly. So rather than using int or long, Windows instead uses INT and LONG, which it then defines as needed, and typedefs to whatever underlying C type does the actual job.

  • Finally, some of these typedefs are actually hinting at specific usages beyond just type information. BOOL and INT are both typedef'd as int, but it's clear that an API parameter specified as BOOL is going to be used in a TRUE/FALSE sense, not as an integer value. (Remember that this predates the 'bool' type.) Likewise, BYTE - which is unsigned char - suggests that a parameter is actually going to be used as a 8-bit numberic value rather than as a alphanumeric or symbol character. And LPSTR indicates that the value is expected to be a NUL-terminated string, rather than just pointing to arbitrary char values. BSTR and LPWSTR have the same underlying typedef - they're both WCHAR * - but BSTRs have a length prefix and so must be allocated with the SysAllocString API, having a separate typedef here helps keep the two separate in code and document API requirements: if you see an API that takes a BSTR as a parameter, then you know that you can't just pass in a wide string, even though the underlying type is the same, there's additional requirements for that parameter.

like image 71
BrendanMcK Avatar answered Oct 10 '22 13:10

BrendanMcK


The reason there is both PCWSTR and LPCWSTR is that in ancient times there was a difference. LPCWSTR used to be const WCHAR FAR *.

like image 37
Jim Rhodes Avatar answered Oct 10 '22 15:10

Jim Rhodes