365 lines
16 KiB
Plaintext
365 lines
16 KiB
Plaintext
|
Header File Organization
|
||
|
------------------------
|
||
|
|
||
|
This document describes the rules for public Windows 3.1 header files. These
|
||
|
rules are designed to promote consistency, clarity, Win32 compatibility, ANSI
|
||
|
compatibility, motherhood, and apple pie a la mode.
|
||
|
|
||
|
In the past, windows.h has been fairly randomly organized: it wasn't very
|
||
|
easy to look in the file and figure out how constants, types, and functions
|
||
|
are related. However, the new windows.h is much more rationally organized,
|
||
|
and it's now far easier to understand and modify. In interests of
|
||
|
consistency, readability, and maintainability, it's important that all of our
|
||
|
public header files are consistently organized.
|
||
|
|
||
|
* Include a copyright banner at the top of the file. Something like:
|
||
|
|
||
|
/*****************************************************************************\
|
||
|
* *
|
||
|
* header.h - Brief description of purpose of header file *
|
||
|
* *
|
||
|
* Version 3.10 * *
|
||
|
* *
|
||
|
* Copyright (c) 1992, Microsoft Corp. All rights reserved. *
|
||
|
* *
|
||
|
\*****************************************************************************/
|
||
|
|
||
|
If this header file has been released before, the copyright date
|
||
|
should be something like: 1985-1992.
|
||
|
|
||
|
* Arrange your header in functional groups, like windows.h. Try to
|
||
|
keep related types, structures, constants and functions as close
|
||
|
together as possible in the header. Separate functional groups
|
||
|
within the header with a banner comment, as in windows.h.
|
||
|
|
||
|
* Within a functional group, general typedefs and constants should come
|
||
|
first, followed by logically organized function prototypes.
|
||
|
|
||
|
* Constants or types used by only one or two functions should be
|
||
|
declared near the function.
|
||
|
|
||
|
* Make sure that everything defined in the header file is included by
|
||
|
default: don't require people to #define things to get certain
|
||
|
definitions.
|
||
|
|
||
|
* If you do want to break up your header file, use the #define NOXXX
|
||
|
convention used by windows.h. Try not to have too many groups
|
||
|
controled by NOXXX #defines, because they get confusing and hard to
|
||
|
deal with. Compiler speed and memory capacity is not the problem it
|
||
|
once was, especially with precompiled headers.
|
||
|
|
||
|
* Constants designed to be ANDed or ORed should be defined in hex.
|
||
|
The number of digits should reflect the data size: 2 for bytes,
|
||
|
4 for words, and 8 for longs. Long hex constants should have
|
||
|
an appended L, e.g., 0x12345678L.
|
||
|
|
||
|
* Ordinal constants values (e.g., 1, 2, 3, 4) should be declared
|
||
|
in decimal.
|
||
|
|
||
|
* Provide a comment on all #else's and #endif's that suggests its
|
||
|
corresponding #ifdef: e.g.
|
||
|
|
||
|
#ifdef FOO
|
||
|
...
|
||
|
#else /* FOO */
|
||
|
|
||
|
#endif /* !FOO */
|
||
|
|
||
|
* Precede the header file with #pragma pack(1), and terminate with
|
||
|
#pragma pack(). This ensures that the structures declared in the
|
||
|
header will be packed properly, regardless of what compiler packing
|
||
|
options the user is using for his own code. Because the Windows RC
|
||
|
compiler chokes on #pragma statements in .rc files, it's a good idea
|
||
|
to include this (and any other #pragmas) in an #ifndef RC_INVOKED.
|
||
|
|
||
|
#ifndef RC_INVOKED
|
||
|
#pragma pack(1) /* Assume byte packing throughout */
|
||
|
#endif /* RC_INVOKED */
|
||
|
|
||
|
and:
|
||
|
|
||
|
#ifndef RC_INVOKED
|
||
|
#pragma pack() /* Revert to default packing */
|
||
|
#endif /* RC_INVOKED */
|
||
|
|
||
|
* Prevent multiple inclusion of your header file with the following
|
||
|
construct:
|
||
|
|
||
|
#ifndef _INC_MYHEADER
|
||
|
#define _INC_MYHEADER
|
||
|
|
||
|
...body of header...
|
||
|
|
||
|
#endif /* _INC_MYHEADER */
|
||
|
|
||
|
This is the convention used by the C runtimes. For each header there
|
||
|
is a #define that can be used to determine whether the header has
|
||
|
already been included.
|
||
|
|
||
|
|
||
|
|
||
|
Win32 Upward Compatibility
|
||
|
--------------------------
|
||
|
|
||
|
Part of the goal of 3.1 is to provide a more unified API that will scale with
|
||
|
minimal pain to 32 bits in Win32. To this end, there are a few things you
|
||
|
have to worry about in your headers (and in your code, but that's a different
|
||
|
story...)
|
||
|
|
||
|
In 32-bit Windows, almost all 16 bit parameters, return values, and field
|
||
|
types have been widened to 32 bits. This allows us to generate much more
|
||
|
efficient code on the 386 and on RISC machines.
|
||
|
|
||
|
We need a way of declaring the quantities that will "float" to 32 bits in
|
||
|
32-bit Windows. It turns out that the C language already provides for this
|
||
|
capability: the "int" type, for example, is 16 bits on 16 bit platforms, but
|
||
|
is 32 bits on 32 bit platforms. "short" is always 16 bits on any platform,
|
||
|
"long" is always 32 bits, and "char" is always 8 bits.
|
||
|
|
||
|
So, functions and structures with "int" declarations are already portably
|
||
|
declared. The problem, though is with the WORD type. "WORD" has become an
|
||
|
industry-wide synonym for a 16 bit unsigned quantity. But, it's also used
|
||
|
widely in Windows header files.
|
||
|
|
||
|
Enter the UINT type. The new UINT type is typedef'd as "unsigned int": an
|
||
|
unsigned value that is 16 bits on 16 bit platforms, and floats to 32 bits on
|
||
|
32 bit platforms. In the 3.1 headers, UINT is used in place of WORD wherever
|
||
|
the size of the return value, parameter, or field will change depending on
|
||
|
the platform.
|
||
|
|
||
|
This is a rule that applies to code you write too: on 32 bit platforms, use
|
||
|
of the UINT type rather than WORD will generate faster smaller code. But be
|
||
|
careful of hard-coded size dependencies on WORD: be sure to use sizeof()
|
||
|
instead of constants, etc.
|
||
|
|
||
|
In some cases there may be structure fields whose size WON'T be changing in
|
||
|
32-bit windows, perhaps because the structure is used in a file format and
|
||
|
compatibility is required. If you know ahead of time that this is the case,
|
||
|
be sure to use short and WORD to indicate 16 bit quantities across platforms.
|
||
|
There are a few of these exceptions with the 3.1 bitmap information
|
||
|
structures in windows.h. If you don't know, then use UINT and int.
|
||
|
|
||
|
The new WPARAM, LPARAM, and LRESULT types, used for polymorphic or arbitrary
|
||
|
parameters and return values (e.g., the SendMessage() function), also provide
|
||
|
a useful degree of platform isolation. The WPARAM type is similar to UINT in
|
||
|
that its size varies with the platform. WPARAM should be used in function
|
||
|
parameter, return value, AND structure declarations, even though its size may
|
||
|
vary. The use of these types indicates to the programmer that the value must
|
||
|
be cast and assigned to the proper type before use.
|
||
|
|
||
|
Hence, the following rules:
|
||
|
|
||
|
* Use int and UINT instead of short or WORD, UNLESS you know for sure
|
||
|
that the quantity will remain 16 bits in 32-bit Windows. The Windows
|
||
|
HIWORD and LOWORD macros use WORD, for example. Be sure to check your
|
||
|
uses of short as well as WORD: there are probably a few lurking out
|
||
|
there that should be changed to int. Use int FAR* or UINT FAR* instead
|
||
|
of LPINT or LPWORD.
|
||
|
|
||
|
* Use the LPARAM, WPARAM, and LRESULT types instead of WORD, LONG, or
|
||
|
DWORD as appropriate.
|
||
|
|
||
|
|
||
|
ANSI Compatibility
|
||
|
------------------
|
||
|
|
||
|
Public header files should be ANSI compliant so that people can take
|
||
|
advantage of the highest compiler warning levels possible. This also helps
|
||
|
ensure that our header files work with a wider range of development tools.
|
||
|
|
||
|
* Don't define constants, typedefs, or functions named with a preceding
|
||
|
underscore. This violates the ANSI namespace conventions. There are
|
||
|
a few violations of this rule already in existence (e.g., _lread), but
|
||
|
try not to create any new problems. (The rules are actually more
|
||
|
complicated than "don't use underscores", but you're safe if you keep
|
||
|
away from them).
|
||
|
|
||
|
* Don't use "//" style comments in the header: these are convenient
|
||
|
but non-ANSI, and warning level 4 complains.
|
||
|
|
||
|
* Always test your header file by compiling it with the -W4 compiler
|
||
|
option to ensure that it's ANSI-compatible.
|
||
|
|
||
|
* Make sure that you have no identifier conflicts with the following
|
||
|
C library header files (NOTE: This list may be incomplete. It's
|
||
|
a good start, though).
|
||
|
|
||
|
assert.h
|
||
|
ctype.h
|
||
|
errno.h
|
||
|
float.h
|
||
|
limits.h
|
||
|
locale.h
|
||
|
math.h
|
||
|
setjmp.h
|
||
|
signal.h
|
||
|
stdarg.h
|
||
|
stddef.h
|
||
|
stdio.h
|
||
|
stdlib.h
|
||
|
string.h
|
||
|
time.h
|
||
|
|
||
|
* Structure declarations should be declared with the "tag" prefix, rather
|
||
|
than a leading underscore, as shown below:
|
||
|
|
||
|
typedef struct tagFOO
|
||
|
{
|
||
|
int i;
|
||
|
UINT u;
|
||
|
} FOO;
|
||
|
|
||
|
* Declare fully-prototyped typedefs for all callback functions. By
|
||
|
convention, the type name should be all caps and end in PROC. For
|
||
|
example, the window procedure callback function typedef from windows.h:
|
||
|
|
||
|
typedef LRESULT (CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM);
|
||
|
|
||
|
Windows 3.0 Backward Compatibility
|
||
|
----------------------------------
|
||
|
|
||
|
In order to allow users to develop applications with 3.1 headers that will
|
||
|
still run on 3.0, users can #define the WINVER constant to be equal to the
|
||
|
version number of Windows they are compiling against. For 3.0, this would be
|
||
|
0x0300. This constant should be used to ensure that new, non-3.0 compatible
|
||
|
features are not declared when the user is compiling a 3.0 application. Keep
|
||
|
in mind that this version number is hex, not decimal (to be compatible with
|
||
|
the GetExpWinVer() API).
|
||
|
|
||
|
Some of you may own headers that are designed to work with windows 3.0 as
|
||
|
well as 3.1: in this case, you won't have some of the new 3.1 typedefs and
|
||
|
macros defined (e.g., UINT). You can use #ifdef _INC_WINDOWS to determine
|
||
|
whether you've included the 3.1 windows.h. Because yours may not be the only
|
||
|
header that will want to define certain types like UINT and LPCSTR, you
|
||
|
should #define these to be WORD and LPSTR, respectively, since you cannot
|
||
|
typedef something twice. The other option, of course, is to have separate
|
||
|
3.0 and 3.1 versions of your header.
|
||
|
|
||
|
* New, non-3.0 compatible declarations and definitions should be inside
|
||
|
#ifdef (WINVER >= 0x030a)/#endif so that the 3.1 headers can be used
|
||
|
to create 3.0-compatible applications.
|
||
|
|
||
|
* If your header must be compatible with the 3.0 windows.h, use #ifdef
|
||
|
_INC_WINDOWS around #definitions that define the missing types. The
|
||
|
3.0 windows.h file did not #define _INC_WINDOWS.
|
||
|
Use #define rather than typedef to ensure that other headers can
|
||
|
safely do the same thing. Here's an example that will handle
|
||
|
most of the common problems:
|
||
|
|
||
|
#ifndef _INC_WINDOWS /* If not included with 3.1 headers... */
|
||
|
#define LPCSTR LPSTR
|
||
|
#define WINAPI FAR PASCAL
|
||
|
#define CALLBACK FAR PASCAL
|
||
|
#define UINT WORD
|
||
|
#define LPARAM LONG
|
||
|
#define WPARAM WORD
|
||
|
#define LRESULT LONG
|
||
|
#define HMODULE HANDLE
|
||
|
#define HINSTANCE HANDLE
|
||
|
#define HLOCAL HANDLE
|
||
|
#define HGLOBAL HANDLE
|
||
|
#endif /* _INC_WINDOWS */
|
||
|
|
||
|
C++ Compatibility
|
||
|
-----------------
|
||
|
|
||
|
To be able to use functions declared in your header directly from C++, you
|
||
|
need to do one thing:
|
||
|
|
||
|
* Bracket the header file typedefs inside an extern "c" {} block,
|
||
|
conditionally using the __cplusplus #define:
|
||
|
Near the beginning of your header:
|
||
|
|
||
|
#ifdef __cplusplus
|
||
|
extern "C" { /* Assume C declarations for C++ */
|
||
|
#endif /* __cplusplus */
|
||
|
|
||
|
And at the end:
|
||
|
|
||
|
#ifdef __cplusplus
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
STRICT Compatibility and Windows 3.0 Backward Compatibility
|
||
|
-----------------------------------------------------------
|
||
|
|
||
|
One of the most important features of STRICT is that handle types are no
|
||
|
longer defined as WORDs. They are declared in such a way that will cause a
|
||
|
compiler error if you try to pass the wrong type of handle or a non-handle
|
||
|
value to a function, for example. It's important that all of our handle
|
||
|
types be declared this way when the user #defines STRICT.
|
||
|
|
||
|
A number of new types and such have been defined in windows.h, such as
|
||
|
HINSTANCE, HGLOBAL, and HLOCAL, which should be used where appropriate in
|
||
|
place of the generic HANDLE type. HANDLE should be used only in cases of
|
||
|
an arbitrary handle type.
|
||
|
|
||
|
The WPARAM, LPARAM, and LRESULT types should be used for arbitrary or
|
||
|
polymorphic parameters or return values. Typedefs exist for all callback
|
||
|
functions, which are used in place of FARPROC.
|
||
|
|
||
|
In most cases, functions declared with these types are fully 3.0 compatible
|
||
|
unless STRICT is #defined. It may sometimes be necessary to use #ifdef
|
||
|
STRICT/#else/#endif to provide 3.0-compatible, non-STRICT declarations in
|
||
|
some cases.
|
||
|
|
||
|
* Use DECLARE_HANDLE() to declare handle types. If you have polymorphic
|
||
|
API parameters (or structure fields) that are designed to accept more
|
||
|
than one type of handle (e.g., the GDI SelectObject function), there
|
||
|
are a few tricks you can employ. 1) Declare a generic handle type
|
||
|
like HGDIOBJ as void _near*, which will accept any handle type. The
|
||
|
HANDLE type can be used for this purpose. 2) if the number of
|
||
|
polymorphic types is small, and there are lots of cases where they can
|
||
|
be used polymorphically, use DECLARE_HANDLE to declare one handle
|
||
|
type, and typedef the rest to be the same as the first one (e.g,
|
||
|
HMODULE and HINSTANCE in windows.h).
|
||
|
|
||
|
* Structure and function declarations should use the appropriate STRICT
|
||
|
type, rather than the generic HANDLE,
|
||
|
|
||
|
* Declare arbitrarily or polymorphic types with LPARAM, WPARAM, and
|
||
|
LRESULT instead of WORD, LONG, or DWORD. This indicates to a
|
||
|
programmer that these values should not be used directly, but should
|
||
|
instead be cast and assigned to the proper type of value before use.
|
||
|
|
||
|
* Declare arbitrarily or polymorphic pointer types with void FAR*
|
||
|
instead of LPSTR or BYTE FAR*. The nice thing about the void FAR*
|
||
|
type is that you can pass any type of pointer to it without having to
|
||
|
cast first.
|
||
|
|
||
|
* If any of the above STRICT rules result in declarations that are
|
||
|
not compatible with previously released versions of the header file,
|
||
|
use #ifdef STRICT/#else/#endif to ensure that both declarations
|
||
|
are present.
|
||
|
|
||
|
* Use WINAPI instead of FAR PASCAL for declaring APIs. Use CALLBACK
|
||
|
instead of FAR PASCAL in callback function typedefs.
|
||
|
|
||
|
* Be sure to use "const" where appropriate in your pointer parameters.
|
||
|
If the pointer is read-only, then it should be const. If the function
|
||
|
writes through the pointer, it must not be const. For const
|
||
|
zero-terminated string pointers, use LPCSTR instead of LPSTR.
|
||
|
|
||
|
* Don't declare NPXXX or SPXXX pointer parameter types for new structures.
|
||
|
(but don't remove them if they've already been defined in a shipped
|
||
|
header). Users are encouraged to use "*", const, _near, _far, and
|
||
|
_huge explicitly where appropriate. Now that our headers contain
|
||
|
"const" pointer types, having LP, NP, and const pointer type variants
|
||
|
for every structure would just clog the compiler up with typedefs.
|
||
|
|
||
|
* Spell out pointer declarations, rather than using the LPXXX type form.
|
||
|
This allows for use of const and _huge where appropriate, without
|
||
|
having to define lots of new typedefs:
|
||
|
|
||
|
SetFoo(const FOO FAR* pfoo);
|
||
|
GetFoo(FOO FAR* pfoo);
|
||
|
|
||
|
* Use parameter names in your API function prototypes. This greatly
|
||
|
contributes to the readability and usefulness of your header, at
|
||
|
very little cost. Make sure all your APIs and callback declarations
|
||
|
are fully prototyped. Use the same naming conventions as in our
|
||
|
documentation (contact gregro or ralphw for a summary of those
|
||
|
conventions). NOTE: As of this writing, windows.h does not yet
|
||
|
include function prototype names.
|