Assuming you don't understand what
#define ID_BUTTON 1
even does:
The #define
, const
, constexpr
, and enum
statements don't create variables; they create cconstants. Both variables and constants are identifiers that refer to values in your program. The difference is that constants cannot be changed at runtime, while variables can.
#define
doesn't create just any ordinary constant, however. It actually tells a part of the compiler called the preprocessor to actually replace the text ID_BUTTON
in your source code with the string 1
. This can be useful, and this is what you have to do for C, but in C++, a constexpr
(which was introduced in C++11) is usually more optimal. See Christian Hackl's answer for more on that.
If you're going to use a constant to pass values to an API, which is what you're planning on doing with ID_BUTTON
, the API will usually tell you what type it expects, so you can use that type instead of having the compiler determine the best type for the job. However, see my discussion below on control identifiers in Windows, as there's a catch for the specific case of ID_BUTTON
.
If you're in control of the type, you'll have to use a little more thought to figure out what type to use. In some cases, the language's type promotion rules will let you get away with just saying 1
without a type, but if you're creating known small or large integers, or bit fields, or floating-point numbers, you'll need to use the appropriate type name or qualifiers (short
, long
, unsigned
, float
, double
, etc.). It takes a little time to figure out where to go, but once you've done it enough you'll be natural at it.
Assuming you don't understand how control identifiers in Windows works:
Most of the API functions that take a control identifier, such as GetDlgItem()
, take the control identifier as an int
; your control identifiers should thus have type int
.
However, CreateWindow()
and CreateWindowEx()
expect the control identifier as the third to last parameter. This parameter is of type HMENU
. C++ won't let you shove an int
into an HMENU
, so you'll have to use a cast: (HMENU) ID_BUTTON
. (There's probably an equivalent C++-style cast, but I don't know/forget what it is.)
In addition, if you're going to use a resource file, you'll have to use #define
statements to create your ID_xxx
constant names, as the resource file format doesn't have const
, constexpr
, or enum
. In this case, continue using #define
for the identifiers, shove these #define
s in their own include file, and #include
that file from both your C++ source and the resource file.
If you're not using a resource file, you don't need to worry about using control identifiers at all; just use the HWND
for each control directly. You should still assign control identifiers in case you need tab navigation or other dialog box message processing in your windows, but other than that you can just use the HWND
s directly. (I forget if control identifiers are involved in tab navigation or not.)
Finally, there are a number of predefined control identifiers that have special meaning to the dialog manager. This is from Microsoft's winuser.h:
/*
* Dialog Box Command IDs
*/
#define IDOK 1
#define IDCANCEL 2
#define IDABORT 3
#define IDRETRY 4
#define IDIGNORE 5
#define IDYES 6
#define IDNO 7
#if(WINVER >= 0x0400)
#define IDCLOSE 8
#define IDHELP 9
#endif /* WINVER >= 0x0400 */
Your own control identifiers should avoid colliding with these; your ID_BUTTON
conflicts with IDOK
. (If they do collide, you'll see weird things like your controls activating on keyboard shortcuts that the dialog manager knows about, for example.) The canonical solution to this problem is to start numbering your control identifiers at 100
(I believe Visual Studio was responsible for this, but I don't know for sure).