Programming Win32 with GNU C and C++ Programming Win32 with GNU C and C++ Under Construction... Win32 programming is a big topic. I suggest you buy an appropriately big book to learn about it. Probably the best book there is on the topic is Programming Windows 95 (or 98, or 2000 by now) by Charles Petzold (Microsoft Press). I also recommend the CD-ROM Programmer's Bookshelf for Windows 95 (or an appropriate update) also from Microsoft Press, which includes Petzold as well as four other Win32 programming books. However, I will try to scratch the surface here, especially the relevant details of using GNU C and C++ plus the related tools to build Win32 programs. For starters, here is a quick look at some very short Win32 programs you can build with Mingw and gcc. After that, dig into the sections below for more details and reference information. ● An introduction to (mostly) GNU C and C++ programming tools for people who are unfamiliar with GNU C and C++ (i.e. how to use the compiler and such). ● Programming Windows for people who are familiar with programming in C and C++, but don't know windows programming. ● Basics of C and C++ programming for beginning programmers (i.e. what is programming, what is a compiler, what is the pre-processor, and topics like that). If you are a complete beginner you may want to look at this section first (especially the references at the bottom of the first page). Written by Colin Peters. This collection of pages is available as a single compressed file (in .zip format) which you can put in a directory on your hard drive and read at your leisure offline. This tutorial was last updated on August 12, 2001. http://webclub.kcom.ne.jp/ma/colinp/win32/ [10/17/2002 9:54:09 PM]
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Programming Win32 with GNU C and C++
Programming Win32 with GNU C and C++Under Construction...
Win32 programming is a big topic. I suggest you buy an appropriately big book to learn about it. Probably the best book there is on the topic is Programming Windows 95 (or 98, or 2000 by now) by Charles Petzold (Microsoft Press). I also recommend the CD-ROM Programmer's Bookshelf for Windows 95 (or an appropriate update) also from Microsoft Press, which includes Petzold as well as four other Win32 programming books.
However, I will try to scratch the surface here, especially the relevant details of using GNU C and C++ plus the related tools to build Win32 programs.
For starters, here is a quick look at some very short Win32 programs you can build with Mingw and gcc. After that, dig into the sections below for more details and reference information.
● An introduction to (mostly) GNU C and C++ programming tools for people who are unfamiliar with GNU C and C++ (i.e. how to use the compiler and such).
● Programming Windows for people who are familiar with programming in C and C++, but don't know windows programming.
● Basics of C and C++ programming for beginning programmers (i.e. what is programming, what is a compiler, what is the pre-processor, and topics like that). If you are a complete beginner you may want to look at this section first (especially the references at the bottom of the first page).
Written by Colin Peters. This collection of pages is available as a single compressed file (in .zip format) which you can put in a directory on your hard drive and read at your leisure offline.
This tutorial was last updated on August 12, 2001.
/* * The simplest Windows program you will ever write. * * This source code is in the PUBLIC DOMAIN and has NO WARRANTY. * * Colin Peters <colinp at ma.kcom.ne.jp>, July 1, 2001. */#include <windows.h>
int STDCALLWinMain (HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow){ MessageBox (NULL, "Hello, Windows!", "Hello", MB_OK); return 0;}
/* * A basic example of Win32 programming in C. * * This source code is in the PUBLIC DOMAIN and has NO WARRANTY. * * Colin Peters <colinp at ma.kcom.ne.jp> */#include <windows.h>#include <string.h>
/* * This is the window function for the main window. Whenever a message is * dispatched using DispatchMessage (or sent with SendMessage) this function * gets called with the contents of the message. */LRESULT CALLBACKMainWndProc (HWND hwnd, UINT nMsg, WPARAM wParam, LPARAM lParam){ /* The window handle for the "Click Me" button. */ static HWND hwndButton = 0; static int cx, cy; /* Height and width of our button. */
HDC hdc; /* A device context used for drawing */ PAINTSTRUCT ps; /* Also used during window drawing */ RECT rc; /* A rectangle used during drawing */
/* * Perform processing based on what kind of message we got. */ switch (nMsg) { case WM_CREATE: { /* The window is being created. Create our button * window now. */ TEXTMETRIC tm;
/* First we use the system fixed font size to choose * a nice button size. */ hdc = GetDC (hwnd); SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)); GetTextMetrics (hdc, &tm); cx = tm.tmAveCharWidth * 30; cy = (tm.tmHeight + tm.tmExternalLeading) * 2; ReleaseDC (hwnd, hdc);
/* Now create the button */ hwndButton = CreateWindow ( "button", /* Builtin button class */ "Click Here", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 0, 0, cx, cy, hwnd, /* Parent is this window. */ (HMENU) 1, /* Control ID: 1 */ ((LPCREATESTRUCT) lParam)->hInstance, NULL );
return 0; break; }
http://webclub.kcom.ne.jp/ma/colinp/win32/test.txt (1 of 4) [10/17/2002 9:54:11 PM]
case WM_DESTROY: /* The window is being destroyed, close the application * (the child button gets destroyed automatically). */ PostQuitMessage (0); return 0; break;
case WM_PAINT: /* The window needs to be painted (redrawn). */ hdc = BeginPaint (hwnd, &ps); GetClientRect (hwnd, &rc);
/* Draw "Hello, World" in the middle of the upper * half of the window. */ rc.bottom = rc.bottom / 2; DrawText (hdc, "Hello, World", -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint (hwnd, &ps); return 0; break;
case WM_SIZE: /* The window size is changing. If the button exists * then place it in the center of the bottom half of * the window. */ if (hwndButton && (wParam == SIZEFULLSCREEN || wParam == SIZENORMAL) ) { rc.left = (LOWORD(lParam) - cx) / 2; rc.top = HIWORD(lParam) * 3 / 4 - cy / 2; MoveWindow ( hwndButton, rc.left, rc.top, cx, cy, TRUE); } break;
case WM_COMMAND: /* Check the control ID, notification code and * control handle to see if this is a button click * message from our child button. */ if (LOWORD(wParam) == 1 && HIWORD(wParam) == BN_CLICKED && (HWND) lParam == hwndButton) { /* Our button was clicked. Close the window. */ DestroyWindow (hwnd); } return 0; break; }
/* If we don't handle a message completely we hand it to the system * provided default window function. */ return DefWindowProc (hwnd, nMsg, wParam, lParam);}
int STDCALLWinMain (HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow)
http://webclub.kcom.ne.jp/ma/colinp/win32/test.txt (2 of 4) [10/17/2002 9:54:11 PM]
{ HWND hwndMain; /* Handle for the main window. */ MSG msg; /* A Win32 message structure. */ WNDCLASSEX wndclass; /* A window class structure. */ char* szMainWndClass = "WinTestWin"; /* The name of the main window class */
/* * First we create a window class for our main window. */
/* Initialize the entire structure to zero. */ memset (&wndclass, 0, sizeof(WNDCLASSEX));
/* This class is called WinTestWin */ wndclass.lpszClassName = szMainWndClass;
/* cbSize gives the size of the structure for extensibility. */ wndclass.cbSize = sizeof(WNDCLASSEX);
/* All windows of this class redraw when resized. */ wndclass.style = CS_HREDRAW | CS_VREDRAW;
/* All windows of this class use the MainWndProc window function. */ wndclass.lpfnWndProc = MainWndProc;
/* This class is used with the current program instance. */ wndclass.hInstance = hInst;
/* Use standard application icon and arrow cursor provided by the OS */ wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION); wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
/* Color the background white */ wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
/* * Now register the window class for use. */ RegisterClassEx (&wndclass);
/* * Create our main window using that window class. */ hwndMain = CreateWindow ( szMainWndClass, /* Class name */ "Hello", /* Caption */ WS_OVERLAPPEDWINDOW, /* Style */ CW_USEDEFAULT, /* Initial x (use default) */ CW_USEDEFAULT, /* Initial y (use default) */ CW_USEDEFAULT, /* Initial x size (use default) */ CW_USEDEFAULT, /* Initial y size (use default) */ NULL, /* No parent window */ NULL, /* No menu */ hInst, /* This program instance */ NULL /* Creation parameters */ ); /* * Display the window which we just created (using the nShow * passed by the OS, which allows for start minimized and that * sort of thing).
http://webclub.kcom.ne.jp/ma/colinp/win32/test.txt (3 of 4) [10/17/2002 9:54:11 PM]
/* * The main message loop. All messages being sent to the windows * of the application (or at least the primary thread) are retrieved * by the GetMessage call, then translated (mainly for keyboard * messages) and dispatched to the appropriate window procedure. * This is the simplest kind of message loop. More complex loops * are required for idle processing or handling modeless dialog * boxes. When one of the windows calls PostQuitMessage GetMessage * will return zero and the wParam of the message will be filled * with the argument to PostQuitMessage. The loop will end and * the application will close. */ while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg); DispatchMessage (&msg); } return msg.wParam;}
http://webclub.kcom.ne.jp/ma/colinp/win32/test.txt (4 of 4) [10/17/2002 9:54:11 PM]
Introduction to GNU Programming Tools
Introduction to (mostly) GNU Programming ToolsTo write Win32 programs you need a whole set of tools. Most of these tools are included in the gcc compiler suite. For those parts that aren't included I'll discuss one or two options if possible.
EditorAn editor is a program which you use to edit your source code. The GNU compiler suite, like any C or C++ compiler, understands code written in plain text. You can't use a word processor like Word(TM), because uses it's own special file format to store information about the formatting of the text you write (like which parts are in bold and which are italics), margin settings, pictures, and so on. (Word(TM) and almost any other word processor can store plain text, but word processors really aren't much good for writing source code anyway.)
The details of actually using an editor are usually explained by the documentation for the editor itself. For advice on writing source code see the appropriate section in my basics of programming pages.
Choosing an Editor
In the GNU world one of the most widely used editors is called Emacs. Emacs includes a whole programming language (basically a form of LISP) which makes it almost infinitely customizable. There are special modes specifically for writing source code and debugging as well. There is a version of Emacs compiled for Win32.
An alternative to Emacs, and the editor I use, is a version of vi called vim.Vim is less powerful and customizable than Emacs, but it is also a lot smaller, and I'm used to it (which is the main basis for choosing an editor anyway).
There are any number of other text editors available, many of them with special features for programming (like syntax coloring, where special keywords in the programming language you are using are drawn in a different color). A cursory search of the Web should turn up any number of text editors for you to choose from.
Writing Source CodeHere is some basic advice on writing source code for your programs.
Split any Significant Program Into Modules
A single source file shouldn't be too long. I generally find that one or two thousand lines is the upper limit. Bascially the idea is that you should be able to split any significant program into bite-sized chunks of related functions. If a program is split up into appropriate modules you will find that you don't have to search through reams of unrelated code for the piece you want to edit, and you also won't have to jump around between half a dozen or more source files when working on a single problem. For C++ programs an effective strategy is often to put each class (or related set of small classes) in it's own file. For C programs one generally puts sets of closely related functions in a single file.
Use a Consistent and Clear Style
Place braces, "{" and "}", clearly, and indent appropriately to represent the nesting of loops, if and else clauses, switches and other such statements. Source code which uses a consistent style is much easier to read, and if you write programs that anybody actually uses you will end up reading the code at some point and wondering what you were thinking when you wrote it.
Name Functions, Classes and Variables Clearly
When you look at the name of a function, class or variable it should be clear
1. What the purpose of the item is (e.g. ReadBitmapFile, fileToRead, cBitmap)2. What type of item it is (a function, a class, or a variable and what type of variable)
When I say clear I mean clear within some basic framework. It would be silly, though not unheard of, to label each item like "function_ReadBitmapFile", "variable_file_handle_FileToRead", "class_Bitmap" and so on. However, using consistant abbreviations and conventions to do the same thing is a good idea. Thus a name beginning with a capitol letter is a function, a name prefixed with 'c' is a class, and variables are prefixed with a lower-case abbreviation representing their type (like n for integer, d for double, sz for C-style string, str for C++ string objects, and so on) in much of the code I write.
Don't give in to the temptation to save typing by over-abbreviation. When you look at code six months later it really is easier to understand "GetWindowHandle (nListIndex)" rather than "gwhn(n)". Of course, don't go completely overboard with long names either ("GetWindowHandleAtGivenIndexInList (nListIndex)" is generally redundant).
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/style.html (1 of 2) [10/17/2002 9:54:12 PM]
Writing Source Code
Use Comments
Not only do comments help you understand the code you wrote when you read it again, they also help you organize yourself while you are writing code. By writing comments at the beginning of if else clauses or switch cases explaining what you intend to do but filling in the actual code later you can quickly lay down the fundamental structure of a piece of code and evaluate for yourself whether an idea works when translated into code. However, avoid using meaningless comments like:
nErr = ERROR_NO_MEMORY; /* Set error value to no memory error. */
or
for (x = 1; x < 10; ++x) /* Loop from 1 to 9 */
Anyone who knows enough about C programming to think about editing code should be able to understand the code at the level written in those comments without reading the comments themselves. Comments should explain why the memory error value is set (if it wasn't explained already) and why there is a loop from 1 to 9 (particularly, why 1 and why 9) and what it does.
Be Consistent
I said something like that above, but it can't be said enough. All 'rules' of programming are matters of taste. Some people prefer larger modules and some prefer smaller. Some people comment almost every line, some write large blocks of explanation (my style), and some write only terse comments on particularly obscure points. There are various religions... er... schools of thought concerning where the opening brace should be placed after a while statement, and whether functions should be named like "get_next_handle" or "GetNextHandle" and so on. What is important is not really which style you choose, but that it is clear to you and you use it consistently.
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/style.html (2 of 2) [10/17/2002 9:54:12 PM]
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/flow.html (1 of 2) [10/17/2002 9:54:14 PM]
Flow Control and Statement Blocks
Do-Until Loops and Do-While Loops
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/flow.html (2 of 2) [10/17/2002 9:54:14 PM]
Variables, Constants and Basic Types
VariablesIn math a variable is an abstract label that can represent any number. In programming a variable performs almost the same task, but the differences are important. In programming a variable is a label for a specific piece of memory where some data will be stored. A variable can be used to hold a piece of data which was input by the user, or the result of a calculation, or in fact anything that it is possible to represent as digital data.
Variable Declarations
In C and C++ a variable must be declared before it can be used. Declaring a variable tells the compiler the type of the variable and it's name along with any other special properties it has.
int x; /* x is an integer */double dFirst, b; /* dFirst and b are double-precision floating-point numbers */char c; /* c is a character */
The above are all examples of simple declarations. The structure of a declaration is like this:
type name-list;
The basic types available are described below. The name list is a list of one or more names separated by commas. Variable names are case sensitive (FOO, Foo and foo are all different variables) and can consist of any combination of letters or numbers and underscore characters '_' except for the first character, which cannot be a number. It is also not recommended to use the underscore as the first character, since that is used for special symbols supplied by the compiler or standard library authors.
Basic Types
Integers (int, short, long)
In math an integer is a positive or negative number with no fractional part, like -1, 0, 1, 2, 758 or -23476. In C or C++ an integer is a type that represents positive or negative whole numbers with a natural-sized word of memory. You can declare variables of the integer type using the type name int, like this:
int x; /* x is an integer variable */
When I say an integer (or "int", as C programmers often call them) is "natural-sized" I mean that it is the largest size that the computer can easily (i.e. quickly) manipulate with one simple instruction. (For example, it is generally possible to multiply two integers with a single instruction.) When programming for Win32, you are generally dealing with what is called a 32-bit machine, and that means the "natural size" for a word is 32-bits. This, in turn, means that an int can represent any number between about -2 billion and +2 billion.
By putting the keyword short in front of the int you can declare a short integer variable. You can also just use the word short by itself. Short integers are smaller than ints (but there is really not much call to use them these days). Generally a short will be 16 bits, capable of representing integers in the range -32767 to +32767.
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/variable.html (1 of 8) [10/17/2002 9:54:15 PM]
Variables, Constants and Basic Types
On the other hand the keyword long declares a long integer type variable. Back in the days of 16-bit computers a long was 32 bits and an int was 16 bits (the same size as a short). Today a long is still generally 32 bits, but ints have caught up.
Unsigned
In math an integer can be either positive or negative, and normal int variables in C or C++ are the same. However, you can also declare a variable as an unsigned int, which means that it can only represent positive numbers (in the range of 0 to 4 billion or so), which doesn't make much sense in math, but that's C for you. You can also declare unsigned short int variables and unsigned long int variables.
There is also a keyword signed which can be used in the same way as unsigned to indicate that the variable can hold both positive and negative numbers. However, this is the default for ints, so it is not generally necessary.
Real Numbers (float, double)
A number with a decimal point, like 1.1, 3.141, or 6.03e24 (or, for that matter 1.000000), is called a real number in math, but in C this is called a float or possibly a double. The word "float" stands for floating point, which describes the general way these numbers are represented in memory. (What it comes down to is that they are basically represented in a kind of binary scientific notation, with a limited number of digits after the decimal point-- or maybe it should be called the binary point?) A double is just like a float except that it has more significant digits. Both types require considerably more memory to store and processing time to manipulate than ints and their relatives.
Nowadays floats are not used much, and normally you will see doubles where a real number is necessary.
Characters (char)
A character (signified by the type name char) is a type of variable which represents a letter, number, or punctuation mark (plus a few other symbols). A char variable can also represent a small integer number.
The signed and unsigned keywords can be used with char like they can with int. Whether char is by default signed or unsigned is not standardized, so you need to use one of those keywords if it is important that you know whether the variable is signed or unsigned. Signed characters can generally represent numbers in the range -128 to 127, while unsigned characters can represent numbers from 0 to 255. Ordinary English letters, numbers and punctuation marks are always represented with positive numbers.
Wide Characters (wchar_t)
Some languages, like Chinese and Japanese, cannot fit their alphabets into the 256 values available with a char. For these languages there is an extended character type called wchar_t. Unfortunately I don't know much more about it.
Strings
A string is a sequence of characters, for example a file name or a line of text from a book. There is built in string type in C, although there is one in C++. In C strings are represented as arrays of characters terminated with a 'null' character (with the value zero). For more about strings see the section on strings.
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/variable.html (2 of 8) [10/17/2002 9:54:15 PM]
Variables, Constants and Basic Types
Void
Void is not a type used for actual variables directly. However it is used when declaring functions which return no value in place of a returned type. Void is also used to declare void pointers, which are variables that point at objects with any type.
Enumerations
An enumeration is a set of named constant integers. You specify an enumeration type like this:
After you have done that you can declare a variable of the enumeration type:
enum eColor colorBackground = white;
In C you need to include the enum keyword when declaring variables of the enumeration type, in C++ you only need to include enum when specifying the enumeration, so the above variable declaration could be:
eColor colorBackground = white;
Boolean (C++ only)
In C++ there is a Boolean type, which has two possible values: true or false. The Boolean type is identified by the type name bool.
bool bFlag = false;
Boolean variables can be assigned the results of comparisons, like this:
bFlag = (x != 10);
Constants and LiteralsSometimes you don't want a variable that you can change, you just want to enter some raw data that the program can use. For example, in the ever-popular "Hello, world!" program shown below, the text "Hello, world!\n" is not a variable. Instead, this is an example of a literal, in particular, that is a piece of raw text, and a chunk of text is called a string, so a literal chunk of text is called a string literal.
int main (int argc, char* argv[]){ printf("Hello, world!\n"); return 0;}
There are several kinds of literals:
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/variable.html (3 of 8) [10/17/2002 9:54:15 PM]
Variables, Constants and Basic Types
● Character literals are single characters enclosed in single quotes, like 'x', 'A' or '\n'. (But the last one is not a single character you say? I'll get to that.)
● Integer literals are just integers. They can be in regular decimal format or in hexadecimal if you put "0x" at the front. So 1999 and -28768 are integer literals in decimal, and 0xFFFF is an integer literal in hexadecimal (hexadecimal literals can't have a sign, i.e. they are in unsigned representation).
● Unsigned integer literals are unsigned numbers with a 'U' at the end like 4095U.● Long integer literals are integers in the same format as regular integer literals, but followed by a letter 'L' as in
1939290L, or 0x10000000L.● Floating point literals are numbers with a decimal point like 6.4, -0.001 or 3.14123. They can also be written using
scientific notation where "E" means "times ten to the power of" an integer following it. Thus 6.0E3 means 6.0 times 10 to the power of 3 (or 1000, so the final value is 6000), an 1.0e-10 means 0.0000000001.
● String literals are pieces of text enclosed in quotes. "Hello, world!\n" or "Syntax error." are string literals.● Boolean literals are available only in C++. You can define a Boolean value simply using the word "true" or "false".
Here are some examples of variables being initialized using literals:
char c = 'A'; /* The character variable c contains the character "A". */int x = 10; /* The integer variable x contains the value 10. */long l = 2000000000L; /* The long integer variable l contains the value two billion. */double d = 6.02e23; /* The double-precision floating point variable d contains * the value 6.02 times ten to the power of 23. */bool b = true; /* The boolean variable b contains the value true. */char* message = "Whoa!"; /* The character pointer variable message points at the * beginning of the word "Whoa!". */
That last one might be a bit tricky. Try looking at the discussion of strings in basic types above.
Escaped Characters
When declaring character or string literals you may want to include a character which cannot be included by directly typing it. For example, if you wanted to put a 'newline' character in a string you can't type something like this:
const char* szMessage = "This is not avalid string literal."
You also couldn't include a quote character, because that would end the string literal.
const char* szInstructions = "Enclosed the name in "quotes"."; /* Won't work! */
To include special characters like this you need to use an escape code, which is a backslash (\) followed by a special code from the following list:
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/variable.html (4 of 8) [10/17/2002 9:54:15 PM]
Variables, Constants and Basic Types
● \f : form feed● \a : bell● \\ : backslash● \? : question mark (not usually necessary)● \' : single quote or apostrophe● \" : double quote
In addition there are two ways to specify a character using a number:
● A backslash followed by one, two or three digits specifies a character using an octal number. The most common use for this is to specify a 'null character' like this : '\0'.
● A backslash followed by an x and then followed by a sequence of hexadecimal digits specifies the character represented by that hexadecimal number.
Thus the above examples could be done like this (with an appropriate change in the content of the first string literal):
const char* szMessage = "This is a\nvalid string literal.";const char* szInstructions = "Enclose the name in \"quotes\".";
Constant Variables
Sometimes you need a number in your program, but it doesn't need to be changed. In this case you can use constant variables. You declare a constant by adding the keyword const to the type name, like this:
const double pi = 3.1415923;
Since the variable is a constant, you have to initialize it with a value and you cannot change it. This kind of thing will cause an error (or at least a warning):
pi = pi * 2; /* Error: modifying const variable. */
External, Static and Automatic VariablesGenerally, declaring a variable assigns the variable name to a piece of memory. However, including the keyword extern in front of the type says that "there is this variable of this type somewhere (perhaps in another module) and I want to use it." The variable name and type are known to the compiler while it reads the rest of your source file (so it won't tell you the variable does not exist), but it assumes that the actual variable will be defined, and perhaps initialized, elsewhere. When your program is linked the reference from the module that used the extern variable will be connected to the real variable in the module that defined it.
For example, consider two files, one called one.c and one called two.c. Here is the first:
/* In the file one.c */
extern int x; /* The variable x is actually defined elsewhere, but used below. */
int foo (int y){
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/variable.html (5 of 8) [10/17/2002 9:54:15 PM]
Variables, Constants and Basic Types
return x + y; /* You can use x here, for example. This adds x and * the supplied value, and returns the result. */}
Here is the second file:
/* In the file two.c */
int x = 0; /* Notice how the variable is defined here. */
void bar (int z){ x += z; /* This adds a value to x and saves it in x. */ return;}
In yet a third file main could do this:
int main (int argc, char* argv[]){ int y = 1; int z = 5;
/* foo returns x + y, and x is zero now. */ printf ("y is %d and x + y is %d\n", y, foo(y));
/* bar adds z to x, so x becomes 5 (the current value of z). */ bar (z);
/* Now x + y is 6. */ printf ("now x + y is %d\n", foo(y));
return 0;}
The output of the program would be
y is 1 and x + y is 1now x + y is 6
Notice how you don't need to add any special keyword where the variable is defined. Variables defined outside of the body of any function are automatically accessible as external variables. If you leave the extern off the declaration in the file one.c, it becomes an external definition, and the linker will complain, because there are two externally accessible variables with the same name.
The keyword static, on the other hand, declares a variable which cannot be used as an external variable from another file. If a variable is static then you can define a variable with the same name in two files, like this:
/* In the file one.c */
static int x = 0; /* This x is defined here, and used below. */
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/variable.html (6 of 8) [10/17/2002 9:54:15 PM]
Variables, Constants and Basic Types
int foo (int y){ return x + y; /* You can use x here, for example. This adds x and * the supplied value, and returns the result. */}
Here is the second file:
/* In the file two.c */
static int x = 0; /* This x is defined here and is separate from the * one above. */
void bar (int z){ x += z; /* This adds a value to the x defined in this file and * saves it in that x. */ return;}
This time main could do this:
int main (int argc, char* argv[]){ int y = 1; int z = 5;
/* foo returns x + y, and x is zero now. (meaning the x in one.c) */ printf ("y is %d and x + y is %d\n", y, foo(y));
/* bar adds z to x (in two.c), so x becomes 5 (the current value of z). */ bar (z);
/* But bar didn't change x in one.c, so x + y is still 1, not 6. */ printf ("now x + y is %d\n", foo(y));
return 0;}
The output of the program would be
y is 1 and x + y is 1now x + y is 1
In fact, extern and static don't work just for variables, they also work for functions.
There is a third class of variable, neither static nor extern, called automatic variables. Automatic variables are variables declared inside a function, unless the keyword extern or static was used to declare the variable (i.e. variables declared inside a function are automatic by default). Automatic variables only exist from the point where they are declared until the end of the function or statement block (a set of statements enclosed in '{' and '}') where they were declared. After the function (or
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/variable.html (7 of 8) [10/17/2002 9:54:15 PM]
Variables, Constants and Basic Types
statement block) ends, the variable is thrown away and its value is lost (and the memory it took up is free for use by other automatic variables in other functions).
In C, all the variables you use in a statement block (including the body of a function) have to be declared at the start of the block. In C++ you can declare variables anywhere in the function. The following fragment of code is fine in C++, but incorrect in C.
int x = 1; int y = 2;
printf ("x + y is %d\n", x, y);
int z; /* Create a new variable z. */ z = x + y; /* Assign the sum of x and y to the variable z. */ printf ("z is %d\n", z);
To be correct in C you would have to move the definition of z to the front of the statement block like this.
{ /* Beginning of the block */ int x = 1; int y = 2; int z;
/* ... */
printf ("x + y is %d\n", x, y);
z = x + y; /* Assign the sum of x and y to the variable z. */ printf ("z is %d\n", z);
/* ... */
} /* End of the block. */
The arguments of a function are also automatic variables. You don't need to declare them inside the function body, because they are already declared in the argument list.
In C++ you can also declare variables inside the initializing statement of a for loop, like this:
for (int i = 0; i <= MAX_INDEX; i++) { // ... do some processing ... }
Such variables are available until the end of the for loop, (that is, inside the body of the loop) but not afterwards.
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/variable.html (8 of 8) [10/17/2002 9:54:15 PM]
Programming Concepts
Programming ConceptsHere are a few basic programming concepts to help you get started. I focus on concepts which are important to C and C++ programming, because that is what I'm trying to explain. Other languages have different emphasis, or perhaps entirely different concepts.
Bits and Bytes
Computers only deal with numbers. Even though when you are programming you may be dealing with letters of the alphabet, to the computer these are all numbers which just happen to represent letters. Furthermore, a computer doesn't even understand digits from zero to nine; it only really understands one and zero.
When you write down a large number each digit represents a power of ten (ones, tens, hundreds, thousands). The computer, basically, deals with any number larger than one in the same way, with each digit representing a power of two (ones, twos, fours, eights and so on). This system, binary arithmetic, can represent any number that normal decimal arithmetic (with powers of ten) can.
Each digit (zero or one) in binary arithmetic is called a binary digit or bit. Computers often deal with these bits in groups which allow them to store a certain range of numbers:
● A byte is a group of eight bits, which can represent 256 different values (integers from 0 to 255 for example, or 256 different letters and symbols). A byte is sometimes also called an octet, usually in connection with communications systems (like the protocols used on the Internet).
● A word is a larger group of bytes. In Win32 programming a word is usually regarded as two bytes, or 16 bits (this is a holdover from the days before Win32; the 32 in Win32 stands for 32-bits to differentiate it from the old 16-bit system). A group of four bytes, or 32 bits, is called a double-word.
Representation
To a computer everything is a number. A picture is just a big list of numbers which happen to mean what colors get drawn where on a screen. A novel is just a different big list of numbers, where some of the numbers represent letters and others represent the font (shape of characters to be displayed) or things like the size of the page.
At the fundamental level, everything in a computer is a string of bits. For convenience, these strings of bits are arranged in groups (bytes or words). Furthermore, different meaning can be assigned to the same group of bits or bytes. The arrangement of bits to carry a certain meaning or value can be called the representation. For example, a single byte can represent numbers between 0 and 255. This is called the unsigned integer representation of a byte. However, a single byte can also represent numbers between -128 and 127. Because this allows numbers with a sign to be represented, this is called the signed integer representation of the byte. A single byte can also represent a letter (A, B, C... Y, Z) or symbol (#, $, %). This is called the character representation. A collection of bytes can represent a word or sentence, and this is called a string.
A word might also represent an address in memory. A number of bytes together can represent a real number (with a decimal point, like 3.14123), called the floating point representation. There is no limit on the set of possible representations (although only a certain set of the possible representations are standard).
Memory
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/concept.html (1 of 7) [10/17/2002 9:54:16 PM]
Programming Concepts
A computer's memory is a very large set of bytes in which it stores the numbers (and letters and so on, but they're really all just bits) that it is using at the moment. When you write a letter using a word processor for example, the computer loads the word processing program file into memory, and also keeps the letter in memory as you write it. When you have finished the letter you can save it, and exit the word processor program, which is then discarded from memory along with your letter (but the files stay on disk where you can use them to load the program again later).
I say the memory is a collection of bytes because the bytes are arranged and numbered in order from zero to some very large number (if you have 128 Mbytes of memory for example, the bytes are numbered from zero to 134,217,727). The number of each byte is called its address.
Program
This is important. The whole point of programming is to create programs, so it's important to know what a program is. A program is a list of step by step instructions telling the computer how to do something.
Computers are very stupid, so they need explicit, detailed, step-by-step instructions in order to do anything. Reading a file from a disk into memory, displaying a word on the screen, and so on are all accomplished by telling the computer exactly which signals need to be sent to the hardware (the disk drive, or the video controller) at what time. A collection of these instructions strung together to make the computer do something useful (or at least do something) is a program.
File
A file is a collection of data stored together under one name on a disk (or some other permanent media). The computer must read the data from a file into memory before it can do anything with it, and in order to save data so that it will not be lost when the computer is turned off (or the program ends), the data will usually have to be written to a file.
Variables
A variable in math is a symbol representing an arbitrary number. In programming, a variable is also a symbol (the variable name) which represents an arbitrary number (the value of the variable). However, that is pretty much where the similarity ends. In math you write and manipulate equations to prove things which are true for all possible values of a variable, or to find the set of possible values for which the equation is true. In programming a variable has a particular value at any given time, and the reason it is called a variable is because that value can be changed as the program runs. A variable can be used to store a number input by a user, or the position of the mouse (periodically updated), or the result of a calculation, and so on.
Each variable in C or C++ has a type. The type of a variable determines its size in memory (the number of bytes it takes to store) and its representation, such as int for integer words, char for character bytes, and float for floating point numbers. There is more on variables in C and C++ in the section on Variables.
Assignment and Arithmetic
Variables can be used to perform arithmetic. That is, you can add, subtract, multiply and divide using variables (as well as ordinary numbers, or constants). You have to assign the result of such arithmetic to a variable (or otherwise make use of it immediately). Thus the following statement:
x = y + 4;
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/concept.html (2 of 7) [10/17/2002 9:54:16 PM]
Programming Concepts
This assigns the result of adding four to the current value of the variable y to the variable x. Note that this is very different from what the same set of symbols means in math. To further illustrate, the following doesn't make much sense in math:
x = x + 1;
There is no (ordinary) number which is equal to itself plus one, which is what the above would mean in math, but in programming it is perfectly ordinary and results in the variable x having a value one greater after the statement has been performed.
Functions
Again functions in programming are something like functions in math. In math a function is something that takes a number or set of numbers and produces a result (generally another number or set of numbers). A function in C programming can take a number (or any combination of variables and constants) and can return a single value. For example, a (trivial) function that adds two numbers and returns the sum could look like this:
int Add (int x, int y){ return (x + y);}
The first line says that "Add is a function that takes two integer arguments, x and y, and returns an integer." The stuff (or code) inside the braces {} tells the computer how to accomplish the function. In this case, it tells the computer to add together x and y and then return the result.
Each C program starts with a single function, usually called main, from which all other functions are called.
The real reason to use functions is to structure your program so that it is easier to write, more efficient, more flexible and easier to change. Consider, for example, if you were writing a program to show a list of information about people in your electronic address book. Say you design the program to take a name and display all the entries that match the name, showing either the phone number or the address of the person. You could write this as one long main function. However, it would be much better to break it down into smaller functions. For example:
● A function to read the option settings and arguments (the name to search for, and whether it is phone numbers or addresses). If the user didn't enter the data properly this function could call another function to display some help.
● A function which takes a name and fills in a list with the data (probably a structure) for each entry matching the name. It does this by calling a function which finds the next entry matching the name repeatedly until it reaches the end of the address book.
● A function which displays a list of phone numbers from the list obtained by the function above.● A function which displays a list of addresses from the list obtained by the function above.
If you do this then the main function could look something like this:
int main (int argc, char* argv[]){ struct option_t options; /* A structure to hold the options settings */ struct person_t* list; /* A pointer to the first entry in the list */
/* Read the options and fill the options structure. */ if (!read_options (argc, argv, &options))
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/concept.html (3 of 7) [10/17/2002 9:54:16 PM]
/* Get the list of people matching the name. */ if (!get_list (options.name, &list)) { /* No matches. Stop. */ printf ("No names match!\n"); return 1; }
/* Print the list of phone numbers or addresses */ if (options.phone_numbers_flag) { print_phone_numbers (list); } else { print_addresses (list); }
/* Finished, clean up and exit. */ free_list (list); return 0;}
Although there are a lot of details in there that probably don't make much sense right now, even a novice can see basically what is happening. Even without the comments it wouldn't be very difficult. On the other hand, if everything was in one long function it would be very difficult to figure out what the program was supposed to do. Also, if you want to change the way options are set, or the format used to print the entries, you don't have to change this function at all, only the function which reads the options or prints the report.
Flow Control
Flow control is a general term for deciding what gets done next in a program. There are a number of generally useful forms that show up in many programming languages including C. See the section on Flow Control and Statement Blocks for more detailed information.
If, then, else
Perhaps the simplest form of flow control is a statement which is performed if some condition is met. In C, for example, the following fragment of code will output (using a function called printf) the words "x is too small" if x is less than 10:
if (x < 10) { printf ("x is too small\n"); }
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/concept.html (4 of 7) [10/17/2002 9:54:16 PM]
Programming Concepts
The part that gets executed if the condition is met is sometimes called the then clause. It is also possible to add statements which are executed if the condition is not met, for example:
if (x < 10) { printf ("x is too small\n"); } else { printf ("x is ok\n"); }
If the value of the variable x is greater or equal to ten, "x is ok" is output. The set of statements executed when the condition is not met is called, appropriately enough, the else clause.
Loops
A loop is a block of code that can be executed more than once. In C there are three types of loop, but probably the easiest one to understand is the 'while' loop. It looks like this:
c = getchar(); /* Read a single character */ while (c != EOF) /* If not End Of File then... */ { printf ("%02x ", c); /* Print the value of the character */ c = getchar(); /* Get another character */ }
This loop starts after the function getchar has been used to read a character into the variable c. If the character 'read' was a special end-of-file character then the loop doesn't get executed, and the program will continue after the final '}', otherwise printf is used to display the value of the character (in hexadecimal, just to make it interesting) and another character is read. At that point the loop checks the condition "c != EOF" again and, if c is not EOF, does the loop again. It will keep running the loop until the condition "c != EOF" is false, that is, until the special EOF character is returned by getchar.
Pointers
Pointers are very important in C, and still pretty important in C++, but they are often very difficult for new programmers to understand and use. Recall that the computer has a memory divided into bytes, and that each byte of that memory has an address. Each variable in your program is stored somewhere in the computer's memory, and therefore there is an address for that variable. A pointer is a variable which stores an address, so it can point to another variable.
Below is a simple example of pointers and the operators '&' ("address of"), and '*' ("the variable pointed to by"). Don't worry if it doesn't make perfect sense. I'll try to explain in more detail in the section on pointers.
int x = 10; /* Initialize an integer variable x with the value 10 */ int* px; /* Declare a variable px with the type "pointer to integer" */
px = &x; /* Assign the address of x to px */ printf ("%d\n", x); /* Prints the value of x, "10" */ *px = 5; /* Assign 5 to the variable pointed to by px (that is, x) */ printf ("%d\n", x); /* Print the value of x again, now its "5"! */
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/concept.html (5 of 7) [10/17/2002 9:54:16 PM]
Programming Concepts
The above example is pretty pointless, but in practice pointers make it possible to do some very useful things because they allow your code to choose which variables it works with at run time (that is, while the program is running and probably based on some sort of input one way or another). In addition to memory allocation (which allows you to create arbitrary new variables at run time) this is essential for almost any program.
C++ insulates the programmer from some of the more mundane uses of pointers (for example, using pointers to create variable length lists and such), but you will still run into them with great regularity.
Data Structures
C and C++ offer certain basic types for variables which correspond to some different representations. However, sometimes you want to group together a set of data for some reason. For example, in the address book example above (under functions) we wanted to group together various pieces of information associated with a person, such as the name, address and phone number. For this you can use a structure. A structure is a set of variables grouped together, and structures themselves can be treated as variables. For the address book, say that each person has a name, address, telephone number, sex and age. We could define a structure like this:
struct person_t{ char name[64]; /* A 64-character array for the name */ struct address_t address; /* An address structure for the address */ int telephone; /* The telephone number, stored as an integer */ char sex; /* The sex, stored as a single character ('M' or 'F') */ unsigned int age; /* The age, stored as an unsigned integer. */};
That is not really a great structure, but it would do the job. Notice that a structure can contain other structures, like the address structure above (that would have to be defined as well, but I haven't shown the definition).
Then we could define variables of the "person" type and use them for various things. For example, we could write a function which read in the data for a person input by the user and then another function which searched for the 'best match' for that person.
In C++ there is a type of structure called a class (or, from a C++ perspective, a structure is just a kind of class). A class is a way of representing an abstract object. Like a structure, a class contains data about the object it represents. However, a class also has functions. For example, if we defined a person class corresponding to the structure defined in the example above (under data structures), it could have member functions which performed tasks related to the object, such as filling it with user input data, or displaying the contents:
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/concept.html (6 of 7) [10/17/2002 9:54:16 PM]
Programming Concepts
class cPerson{ // Declarations of various data members go here...
public: void Display (); void GetFromUser ();};
Then the code fragment to get a person's data from the user and then search for a match could look like this:
cPerson search_for, found;
search_for.GetFromUser(); Match (&search_for, &found); found.Display();
For more on why this can be a good thing (and the other things that classes can do), read Stroustrup's book, or any number of other books on object oriented programming.
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/concept.html (7 of 7) [10/17/2002 9:54:16 PM]
The Compiler
The CompilerAfter you have written your code with an editor, the compiler takes the source code files, for example C files (ending in .c) or C++ files (ending in .cpp or .cc) and transforms them into object files (ending in .o).
With the GNU compiler suite there are separate compilers for each language (that is, there is a different program that compiles C programs and one that compiles C++ programs). But actually, you don't use these programs directly, you use a program called a front end. The idea of a front end is that it can take options and arguments that are easy to remember and understand and figure out which programs to use and what options to use for each program.
For the GNU suite the main front end is called gcc. To get it to compile a program you type a command like this (in a DOS window or other command-line environment):
gcc -c -o foo.o foo.c
That command takes a source code file called foo.c, which, presumably, you wrote, and compiles it (that's what the -c means: compile) into an object file called foo.o (the -o option, followed by a file name, tells gcc to put the output of the compiler in a file with the name you give after the -o).
One of the things gcc does for you is figure out which compiler to use. It calls the C compiler if you give it a source file ending in .c, and calls the C++ compiler for files ending in .cc or .cpp. It also calls the preprocessor (called cpp, but not to be confused with the ending for C++ source files). Finally, gcc acts as the front end for the linker as well.
Take a look at the actual documentation for gcc online (from Cygnus Solutions).
Characters and StringsCharacters (letters, numbers, punctuation, etc.) and strings (sequences of characters) are always stumbling blocks for beginning programmers in C and C++. In both C and C++ there is a basic character type called char. A variable of type char stores a single byte which represents an ASCII character. ASCII is a standard which defines which values of a byte represent which letters, numbers or punctuation symbols. This includes upper and lower-case English letters, numbers, space, tab, period, comma and so on. It does not include letters from other languages, although there are ways around this.
In recent years the "wide character" type wchar_t has been defined as a larger type big enough to hold letters in languages other than English. The whole topic of internationalization (making it possible to write programs for people in many different countries) is quite large in itself, so I'll leave that for someone else to deal with.
To get back to characters, there is no basic type called "string" in C (there is one in standard C++). However, there are many standard and non-standard library functions which operate on a char pointer treating it as a string. These functions all expect the pointer to point to the first member of an array of char. They also expect the special 'null' character to appear in the array after the last character in the string. In fact the C and C++ languages support a special syntax for creating static arrays and getting a pointer to the first character, shown below:
char* szString = "Hello, World!\n";
In the above code fragment the "Hello, World!\n" part defines a piece of memory containing the letters 'H' 'e' 'l' 'l' 'o' and so on, up to the final newline character and a null character. In the initialization of the variable szString this syntax then gives a pointer to the first letter in the defined piece of memory. You could imagine it something like the picture below:
The LinkerThe linker is a program that takes the object files (.o) produced by the compiler, including object files stored in libraries and turns them into programs (or DLLs). It does this by combining the object files and linking (or resolving) the names (or symbols) used in one object but not defined to symbols (i.e. pieces of code or data) defining those names in other objects. This is why it is called linking.
In the GNU compiler suite the linker is called ld. However you should not run ld directly except under very special circumstances. Instead you should use the front end, gcc, which was mentioned in the section on the compiler. To link a program you can type in a command like this:
gcc -o foobar.exe foo.o bar.o
That command produces a program called foobar.exe as output (from the -o foobar.exe argument) by combining the object files foo.o and bar.o. For any object file included directly on the linker command line (like foo.o and bar.o in that example) the linker simply includes all the symbols (functions and data) from the object file in the program. It also checks for the entry point (e.g. the function main in a console-based C program) and includes the position of that function in the program header so that when the program is run it will start at that function.
Linking With Libraries
To link with a library you can do two things. You can include the library on the linker command line directly, like this:
gcc -o foobar.exe foo.o bar.o libstuff.a
In addition to linking the object files foo.o and bar.o this will add the objects in the library libstuff.a that contain functions and data used by the first two objects (or, in turn, the objects linked in to provide those functions and/or data) to the program. You can also do this with the -l option (l for library).
gcc -o foobar.exe foo.o bar.o -lstuff
The -l option doesn't require that you know exactly where the library is, as long as it is one of a standard set of directories (the library path). Notice that you don't put a space between the name of the library and the -l option. Also, you don't use the full file name of the library but instead only the part after lib and before .a. The linker looks for the library called libstuff.a in some standard places and checks all the objects in the library for symbols which are used by foo.o or bar.o but which aren't defined by either of them. If it finds an object which supplies a needed symbol it includes that object in the executable (but
http://webclub.kcom.ne.jp/ma/colinp/win32/tools/link.html (1 of 3) [10/17/2002 9:54:18 PM]
not the whole library). Of course, it also checks objects included from libraries in this way for undefined symbols and trys to resolve them as well, which may lead to more objects being included from libraries until all the symbols are resolved.
One thing that is important to remember about linking with gcc is that it checks libraries in the order they appear, and it will only resolve references to symbols in libraries earlier on the command line if the object containing the symbol definition was already included for some other reason. Thus if foo.o uses a function in libstuff.a the following command line will fail:
gcc -o foobar.exe -lstuff foo.o bar.o
Also if the library libmorestuff.a uses functions in libstuff.a which are not used by foo.o or bar.o then the following may fail:
gcc -o foobar.exe foo.o bar.o -lstuff -lmorestuff
Finally, if a symbol is defined in two different libraries gcc will use the first one it finds and ignore the second one unless the second one is included in an object file which gets included for some other reason. Say the library libstuff.a defines a function called StuffIt and libmorestuff.a also defines a function called StuffIt in the same object file as a function called StuffSomeMore. If foo.o contained a call to StuffIt the function used will be the one in libstuff.a. However, if foo.o contained a call to both StuffIt and StuffSomeMore, or if bar.o contained a call to StuffSomeMore then the above example would result in an "duplicate symbol" error.
Telling gcc Where to Find Libraries
gcc will search in some default locations for libraries. It will also search all the directories listed in the environment variable LIBRARY_PATH. So, for example, including the following statement in the autoexec.bat file for Windows 98 will allow a Mingw32 version of gcc to find libstuff.a in the directory C:\mylibs or in the directory C:\usr\local\lib (note, you can use either slashes or backslashes as path separators, and you can leave off the drive letters if you always compile on the same drive as the directories listed in the path).
SET LIBRARY_PATH=C:\mylibs;C:\usr\local\lib
One of the directories not searched by default is the current directory. To include the current directory, or any other directory in the search use the -L option. The following command line would search in the current directory (indicated by the special name '.') and in the directory \usr\local\lib on the same drive for the library libstuff.a.
Like the -l option you don't include a space between the -L and the directory name. You can use slashes or backslashes with the Mingw32 version of gcc, but I prefer to use slashes. Remember to include the -L option before the -l option so that the library path is set before gcc tries to search for the library.
http://webclub.kcom.ne.jp/ma/colinp/win32/tools/link.html (3 of 3) [10/17/2002 9:54:18 PM]
Basic Syntax
Basic SyntaxLike English, C++ has words, space and punctuation. Also like English the number of spaces between words, or the position of line breaks (as long as they don't break a word in half) do not affect the meaning of a sentence. The compiler does not care how easy it is to read a piece of source code. Using spaces, line breaks, and indentation is for the convenience of human readers (such as yourself). However, computers are sticklers for 'proper' spelling, punctuation and, in the case of C++, capitalization. If you leave out a comma or a semi-colon, or use a lower-case letter where an upper case one should be used it will change the meaning of the code, and the compiler will probably complain. (Actually it's worse when the compiler doesn't complain, because you end up with a program that doesn't do what you wanted!)
Of course, C++ is not English. The punctuation, the use of capitalization, the words and their meanings are all different.
Tokens
In C++ a word or a single piece of punctuation is called a token. Tokens are separated by white space, which can mean any number of ordinary spaces, tab characters, or line breaks. Punctuation, like parentheses '(' ')', braces '{' '}', or commas and periods, don't need to be separated from other tokens by spaces. For example the tokens in this piece of code:
int main(int argc, char* argv[]){ return 0;}
Are the following, in order:
intmain(intargc,char*argv[]){return0;}
Written either way the code has the same meaning, but obviously the first one is easier to read.
Keywords
In C++ there are a relatively small set of words that have fixed meanings. These words are called keywords and they include:
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/syntax.html (1 of 3) [10/17/2002 9:54:18 PM]
Basic Syntax
● The names of the basic types (int, char, float, double, bool, wchar_t) and their modifiers (short, long, signed, unsigned)● The boolean constants (true, false)● Keywords for variable and member declarations (extern, static, const, virtual, mutable, inline, auto, volatile, register,
export)● Flow control constructs like loops (do, while, for), conditionals (if, else), switches (switch, case, default) and special
flow control keywords (continue, break, goto)● Keywords for declaring and using new types (class, struct, union, enum, typedef, template, public, private, protected,
Plus some others. Learning C++ is not a matter of memorizing a bunch of keywords, but it is good to be aware of reserved words like these, so that you don't try to use them as variable or function names.
Symbols
Words that are not keywords are available for use as the names of types (including classes, structures and enums), functions, variables, namespaces and such programmer-defined objects. Symbols, as such words are called, can generally consist of any combination of letters (upper-case and/or lower case), numbers and the underscore character '_'. One exception is that you can't begin a symbol name with a number. The following are all valid symbols:
The last example, that begins with an underscore, is a valid symbol. However, you should generally avoid such symbols since symbols with leading underscores are often used by libraries to avoid name conflicts (a better method is to use namespaces, but namespaces are a recent addition to C++).
Comments
In order to make your source code easier to read and understand it is useful (absolutely necessary in fact) to use comments in plain English (or whatever your native language might be) in the code to explain and clarify. Consider the difference comments make between:
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/syntax.html (2 of 3) [10/17/2002 9:54:18 PM]
Basic Syntax
WNDCLASSEX wc; /* Window class structure */
/* Prepare the window class structure to be filled in */ memset(&wc, 0, sizeof(WNDCLASSEX)); /* Zero clear */ wc.size = sizeof(WNDCLASSEX); /* size is the size of the structure in bytes */
There are two ways to include comments in your code. A comment can be enclosed in /* */, like the above. This type of comment can cover several lines or have ordinary C++ code on either side on the same line:
/* This is a multi-line comment */
int main (int argc /* Argument count */, char* argv[] /* Array of arguments */)
The second way to include comments is to put two slashes (//) before a comment. After the two slashes everything up to the end of the line is ignored by the compiler.
// This is a single line comment.
int x; // A variable declaration.
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/syntax.html (3 of 3) [10/17/2002 9:54:18 PM]
Basics of C and C++ Programming
Basics of C++ ProgrammingThese pages attempt to give an overview of some basic concepts, including the structure of the C++ programming language. You can read through them below, or you can refer back to them from pages in the main tutorial when you feel you don't understand a particular topic or piece of terminology.
Concepts and Terminology
Unless you are just starting to program you probably already know everything in this section.
● Computer Basics and Programming Concepts
C++ Language Structures
Most people find learning by example easier than working from simple descriptions, so most people will find these pages most useful for reference when looking at examples elsewhere.
● Basic Syntax: Spaces, words and punctuation in the C++ language.● Variables, Constants and Built-in Types: How to store data.● Operators and Basic Expressions: How to do math (and other things).● Flow Control and Statement Blocks: Repeating actions and responding to conditions.● Functions and Arguments: Organizing the program.● Modules and Scope: Dividing large programs into manageable pieces.● Arrays: Groups of the same type of variable.● Character Strings: How to deal with text.● Pointers: Variables which point at other variables.● Defining New Types: Variables beyond the basic types.● Classes and Objects: The basis of object-oriented programming.● Casts: Converting between types.● The Preprocessor: The preprocessing step applied to all C++ source code.
Design
These are pages on software design and good programming practices (at least in my opinion).
● The Programming Process: What are the steps involved in creating a program?● Writing Source Code: Basic advice on coding style.
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/index.html (1 of 2) [10/17/2002 9:54:20 PM]
Basics of C and C++ Programming
Other Online Tutorials
● DevCentral C/C++ Tutorials● The Programming Sharehouse's big list of C/C++ tutorials.● Scroll down a bit on this page for some C++ Win32 tutorials.● C++ Annotations, for people who already know C.
Book Recommendations
For C programming go out and get "The C Programming Language" 2nd Ed. (or later editions) by Brian W. Kernighan and Dennis M. Ritchie. It is perhaps not the easiest tutorial for C programming, but it is the ultimate bible of C, and you will keep referring back to it even when you are an experienced programmer.
K&R is particularly appropriate if you already know how to program in another language (even BASIC, for example). However, for programming beginners I have had Teach Yourself C in 21 Days and Teach Yourself C++ in 21 Days, both by Sam's Net publishers, recommended to me. I can't actually say anything myself, since I haven't read them.
For a bible of C++ see The C++ Programming Language 3rd Ed. by Bjarne Stroustrup. That book is probably not good for beginners, but more experienced programmers should benefit from the detailed, if somewhat theoretical approach to C++ programming.
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/index.html (2 of 2) [10/17/2002 9:54:20 PM]
PreprocessingBoth C and C++ source code passes through a stage called preprocessing. This process is performed by a tool called the preprocessor, before the code is compiled by the compiler.
Preprocessing is done automatically. You don't have to explicitly invoke the preprocessor. Also, it simply modifies the source code as seen by the compiler. The preprocessor does not touch your actual source code file except to read it. So when I say the preprocessor "deletes comments and replaces them with a space" and things like that, it means that if there is a comment in your source file (the input to the preprocessor) then the source that the compiler sees will have a space in that position. It does not mean that the source file stored on your hard drive is edited.
What Happens During Preprocessing
The preprocessing step is a relatively simple process of text substitution. Basically it performs the following actions:
● Lines that end with a backslash ('\') are spliced together with the following line. This provides for macro definitions longer than a single line (see below).
● Comments are removed and replaced with a single space.● Preprocessor directives are obeyed, including macro substitution, conditional compilation and
includes.
It is important to realize that preprocessing is entirely done before the meaning of the source code itself is examined at all by the compiler. Using the #define directive is not like defining a variable, and a macro is not a function.
Preprocessor Directives
Preprocessing directives are indicated by lines starting with the 'sharp' symbol #. Each preprocessing directive occupies a single line (but keep in mind the line splicing performed by the preprocessor as mentioned above).
● Including Other Files● Macro and Symbolic Constant Definitions● Conditional Compilation
Preprocessor Gotchas!
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/preprocess.html (1 of 2) [10/17/2002 9:54:22 PM]
Preprocessing
The gcc preprocessor (cpp) can catch people off guard because it does some things in a way that is correct according to the standard but not what many people expect (and also not what some other preprocessors do). Two problems which I have seen raised recently are:
1. Backslash line splicing comes before comment removal.2. Text must be valid C/C++ tokens even if conditional compilation is used to hide it from the
compiler.
The first problem causes code like this to behave unexpectedly:
// See library in \foo\bar\y = foobar(x);baz(y);
The function foobar is never called and y is not assigned the value expected before the function baz is called. Why? Because the single line comment above ended in a backslash, and backslash as the last character on a line means the preprocessor should splice on the next line replacing the backslash and newline with whitespace. This happens before comments are removed. So, after line splicing the above source looks like this:
// See library in \foo\bar y = foobar(x);baz(y);
The comment is removed and all the compiler sees is "baz(y);". Be careful not to include a backslash as the last character in a 'single line' comment. (Note that this wouldn't be a problem in traditional C comments using /* */.)
The second problem causes the preprocessor to fail on code like this:
#if 0This isn't good code.#endif
The problem here is that there is an unclosed single quote in the line of text (the apostrophe in "isn't"). Even though the text is not passed to the compiler the preprocessor still works on C++ tokens (it needs to know about quoting of strings and characters in particular). If you are writing plain english text then use comments, not #if 0 blocks.
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/preprocess.html (2 of 2) [10/17/2002 9:54:22 PM]
The Preprocessor
The PreprocessorThe preprocessor is a program that performs simple text substitutions on your source code based on a set of commands called preprocessor directives which are those lines beginning with the # symbol in your C or C++ source code. Generally you will not use the preprocessor directly but it will be called by gcc for each C and C++ source file before the compiler is called. The preprocessor for the GNU compiler suite is called cpp.
For more information on what the preprocessor does see the section on the preprocessor in the basics of programming pages.
You will not run the preprocessor directly, but you can pass arguments and options to it from the gcc command line. The following sections describe the most common cases where you will want to do this.
Telling the Preprocessor Where to Find Include Files
You can tell the preprocessor to search extra directories for include files using the -I option or the C_INCLUDE_PATH and CPLUS_INCLUDE_PATH environment variables.
The following command line will tell the preprocessor to search the directory /src/bar/include (\src\bar\include on the current drive in DOS-speak) and the directory include under the current directory for include files used by foo.c. These directories will be searched before the system default directories.
Including the following lines in Windows 95/98 autoexec.bat file, or setting the equivalent environment variables in the control panel for Windows NT, will search /extra/include/c for include files used by C source files, /extra/include/plus for include files used by C++ source files, and /extra/include/both for include files used by either C or C++. These directories will be searched after any directories specified with the -I option, but before the standard system directories.
SET C_INCLUDE_PATH=/extra/include/c;/extra/include/bothSET CPLUS_INCLUDE_PATH=/extra/include/plus;/extra/include/both
Defining Constants at Compile Time
http://webclub.kcom.ne.jp/ma/colinp/win32/tools/preprocess.html (1 of 2) [10/17/2002 9:54:22 PM]
The Preprocessor
You can tell the preprocessor to act like you included a #define preprocessor directive as the first line of every source file you are compiling by using the -D option.
gcc -c -o foo.o -DBAR foo.c
The above command line will have the same effect on the compilation of foo.c as if you added the line
#define BAR 1
to the top of foo.c.
gcc -c -o foo.o -DBAZ=fuz foo.c
The above command line will have the same effect as if you added the line
#define BAZ fuz
to the top of foo.c.
http://webclub.kcom.ne.jp/ma/colinp/win32/tools/preprocess.html (2 of 2) [10/17/2002 9:54:22 PM]
Trouble With Symbolic ConstantsWhen you define a symbolic constant with a preprocessor directive make sure you understand clearly what you are doing.
Operators in Symbolic Constants
Let's say you define a set of constants like this:
#define FOO 8#define BAR 4#define FOOBAR FOO+BAR
There is not actually much wrong with that, except that something like the following could happen:
printf ("The answer is %d\n", 6*FOOBAR);
The result of this code is a program which prints "the answer is 52", but 6 times 12 (FOO plus BAR) is 72, so what went wrong? The problem is that the printf line gets expanded to this:
printf ("The anwser is %d\n", 6*8+4);
The regular rules of precedence in C say that multiplication should be done before addition, so the printf displays 6 time 8 (48) plus 4, which is 52. To get the answer you were probably expecting you should define FOOBAR like this:
#define FOOBAR (FOO+BAR)
If that is done the printed result is the correct number, 72.
Confused Use of Symbolic Constants
Here is some code based on something which I actually saw someone try to use at one point:
struct foo{ /* ... some members ... */};
main (){
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/baddefine.html (1 of 3) [10/17/2002 9:54:23 PM]
fooStructure = (struct foo*) FOOPTR; /* Why is this cast necessary? */
/* ... code for clearing the structure pointed to by fooStructure ... */}
The author of the code came to me with a couple of questions. He inserted some debugging printf statements into his program and found that the value given by FOOPTR in main was different from that in the ClearFooStructure function (and in the fooStructure pointer in that function). He also wondered why he needed the cast to a pointer to struct foo on the line with the comment "Why is this cast necessary?"
The problem is that the author was confusing preprocessing, which is an entirely text substitution oriented step, with the actual programming language. If we expand FOOPTR in the main function it gives us a pointer to the variable called fooStructure. In main the variable fooStructure is a valid struct foo variable and FOOPTR is a valid variable. However, the positioning of the define does not magically associate FOOPTR with the variable fooStructure at the point it is defined. The preprocessor just substitutes text. Thus in ClearFooStructure we get something like this:
struct foo* fooStructure;
fooStructure = (struct foo*) (&fooStructure);
Now it should be evident (if you know some C) why the cast is necessary and why this doesn't do the right thing. The pointer fooStructure is being set to point at itself. The cast forces the compiler to let you make a pointer to a struct foo point at the space allocated for a pointer to a struct foo (not an actual struct foo). If the author had named the pointer something else there would have been no fooStructure variable at all and the file would have failed to compile.
There are several morals here. If a cast is necessary where you don't think one should be necessary, or if a warning message occurs, the compiler is usually trying to tell you that you are doing something unconventional and probably not what you meant. (It is both a strength and a weakness of C that it lets you tell the compiler that you know what you are doing and force it to do strange things. PASCAL, I hear, just
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/baddefine.html (2 of 3) [10/17/2002 9:54:23 PM]
wouldn't allow this sort of thing, which can be frustrating if you actually need to do something strange.) The second moral is that preprocessor symbolic constants are not part of the programming language. Preprocessing should be viewed as something separate from the language itself.
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/baddefine.html (3 of 3) [10/17/2002 9:54:23 PM]
Trouble With Macros
Trouble With MacrosMacros may seem like a great idea at first, but it is important to use them with caution. A macro is not a function. Consider the macro MAX defined like this:
#define MAX(a,b) (((a)>(b)) ? (a) : (b))
The problem with such a definition is that either a or b may be evaluated twice when the macro is included. This is no problem when a and b are just variable names, but consider this:
z = MAX(++x,y); /* Increase x by 1 and set z to the maximum of the new x and y */
That gets expanded to this:
z = (((++x)>(y) ? (++x) : (y));
This does not do what the comment says (and might reasonably have been expected for a function call). This increments x by 1, compares the new value to y, and if the incremented value is greater than y it increments x again and sets z to that value. On the other hand, if y is greater than the starting x value plus one then x is only incremented by one and z is set to the value of y.
The moral of the story is to be very careful when using arguments to macros which might have side effects. Also, consider what happens if you put a function call in as one of the arguments to a macro like that. Yes, it could get called more than once (which might not be what you wanted).
Including Other Files: #includeOne of the most common uses of the preprocessor is to include other files in a piece of source code. File inclusion directives look like this:
#include <stdio.h>
#include "foo.h"
The preprocessor searches for the file named after the #include and replaces the #include statement with the full contents of that file. Generally this is useful for including common definitions of types and constants that you want to share across several source files.
Because files you include with #include will often be included in several source modules you must avoid writing statements in include files which actually define functions or variables. Type, enumeration and structure declarations, class declarations, external function and variable declarations are safe. So are preprocessor macro declarations. Function definitions and variable definitions are generally undesirable and may lead to duplicate definition errors at link time. Thus
struct bar { int nValue; struct bar* pNext; }; /* Safe: structure declaration */
is quite reasonable as an include file. The following is not:
int nGlobal; /* Unsafe: variable definition */
int foo (int* p) /* Unsafe: function definition */ { *p += nGlobal; }
struct bar { int nValue; struct bar* pNext; } barShared; /* Unsafe: variable definition */
Files which contain type definitions, external function and variable declarations and such meant to be included in
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/include.html (1 of 2) [10/17/2002 9:54:24 PM]
Including Other Files
several source files generally have the extension .h. For C++ sometimes such files are given the extension .hpp or no extension at all (the standard C++ system header files have no extension).
The difference between the <> form and the "" form of #include is that the <> form looks for 'system' includes. It does not search in the same directory as the source file being compiled. The "" form looks first in the same directory as the source file, and then, if it doesn't find the file, searches in the system include directories. See the section on the preprocessor in the introduction to GNU tools for information on how to control which directories are searched for include files.
Protecting Files from Multiple Inclusion
As a project grows it may become harder to keep track of which header files are actually being included by a piece of code. In the interests of making modules reasonably independent you may include certain header files for other modules in the shared header file definining the interface for that module. If you do this you will almost inevatibly end up with some piece of code which includes two headers for two modules it uses, but where each of those headers includes its own copy of a third header for a module used by both of those modules you are using. If this happens the same header file may be included twice (or more) in your source file. Unless you do something this may lead to errors as things are declared twice. It also wastes the compiler and preprocessor's time reading the same material twice.
Here is a simple strategy for preventing such problems using symbolic constants and conditional compilation.
For every header file include some directives like this:
#ifndef FOO_H#define FOO_H
/* ... contents of header file ... */
#endif
The symbolic constant FOO_H should be different for each header file. A good strategy might be to use the name of the header file, and possibly add on the library or program name which the header is a part of.
With these directives the first time a header is included in a particular source file FOO_H will not be defined and the text inside the #if (including the definition of FOO_H) will be processed. The second time the header appears FOO_H will be defined and the text of the header will be skipped.
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/include.html (2 of 2) [10/17/2002 9:54:24 PM]
Macros and Symbolic Constants
Macro and Symbolic Constants: #defineYou can use a #define preprocessor directive to define a piece of text which will be substituted for another piece of text wherever it occurs in the source file after the line containing the #define. This also affects any #ifdef and #ifndef directives that occur later in the file. There are two basic forms of #define. The first defines a simple text substitution, the second performs a more complex 'macro' substitution.
By convention all macros and symbolic constants have names that are ALL_CAPITOLS. This helps them stand out in the code and makes sure you do not confuse them with ordinary variables or function calls.
Symbolic Constants
The following two directives are examples of simple text substitution or symbolic constants.
#define MAGIC_NUMBER 12874538#define BAR
The first line means that any occurance of the text "MAGIC_NUMBER" after the #define will be replaced by the text "12874538". The second line means that BAR will be replaced by no text at all (which can be useful if there are cases where you need to insert a special keyword and other cases where no keyword is required in the same position).
Such definitions are useful for keeping the definition of shared constants and magic formulae isolated. You might use the magic number in several places in your source code, but by using MAGIC_NUMBER instead of the number itself you can change the magic number definition in one place (in a header file most likely) if the number changes.
One of the most common uses of symbolic constants is for buffer sizes. For example:
#define BUFFER_SIZE 64
char caBuffer[BUFFER_SIZE];
void FillBuffer (char c){ int i; for (i = 0; i < BUFFER_SIZE; ++i) { caBuffer[i] = c;
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/define.html (1 of 2) [10/17/2002 9:54:24 PM]
Macros and Symbolic Constants
}}
Be careful with symbolic constants. They can lead to confusion.
Macros
The following directive is an example of a macro.
#define MAX(a,b) ((a)>(b) ? (a) : (b))
That definition means that later in the source code you can do something like this:
int x, y;
/* ... x and y get set to some values ... */
nMaxOfXY = MAX(x,y);
The variable nMaxOfXY will be set to the maximum of either x and y. After the preprocessing step what the compiler sees for the last line above is this:
nMaxOfXY = ((x)>(y) ? (x) : (y));
Notice how the parameters of the macro a and b were replaced by the expressions x and y used later in the code.
This kind of macro use can be dangerous. You should avoid it where possible (but it's not always possible, and it is still very common in C programs).
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/define.html (2 of 2) [10/17/2002 9:54:24 PM]
Conditional Compilation
Conditional Compilation: #if, #ifdef, #ifndefYou can use the preprocessing directives #if, #ifdef and #ifndef to control which parts of a source file get passed to the compiler. This can be useful if, for example, you want to write code that can be compiled using different compilers or on different operating systems. It is also useful if you want to build different versions of the same basic program with different feature sets.
Basically the use of #if looks like this:
#if FOO/* Code compiled if FOO is not zero */#elif BAR/* Code compiled if FOO is zero but BAR is not zero */#else/* Code compiled if both FOO and BAR are zero */#endif
"elif" stands for "else if". There can be any number of #elif directives (including none) before the end of the #if ... #endif sequence. The #else directive is also optional. It should be obvious from the above that macro and symbolic constant substitution is performed on the text after the #if (and other) directives before they are evaluated. But you don't need to use symbolic constants:
#if 0/* This code is never compiled */#endif
That type of construct can be useful during debugging.
The preprocessor also understands the keyword 'defined' which gets set to 1 if a given constant has been defined earlier (using #define), even if the actual value of the constant is zero or nothing at all. Also, you can use '!', the C logical-not operator to invert the truth-value of an expression (i.e. false, or zero expressions become true, and true, or non-zero, expressions become false), including a 'defined' expression. For example:
#if defined(FOO)/* Code compiled if FOO is defined (even if zero) */#endif
#if !defined(BAR)
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/ifndef.html (1 of 2) [10/17/2002 9:54:25 PM]
Conditional Compilation
/* Code compiled only if BAR has not been defined */#endif
The #ifdef directive is equivalent to #if defined, and the #ifndef directive is equivalent to #if ! defined.
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/ifndef.html (2 of 2) [10/17/2002 9:54:25 PM]
The Programming Process
The Programming ProcessThe procress of creating a program consists the following stages:
The process goes in cycles. You start with a design, and try to write code to implement that design. As you write the code you may come across problems that send you back to the design stage. Once you have code written you try to compile it. If there are errors or other problems you go back to editing the source code and eventually try again. If your code compiles you try to link it. If that doesn't work you usually have to go back to editing the source code again.
If the code links then you try running it. If it doesn't do what you wanted (if there are bugs that is), or if it just plain doesn't work, then you probably need to go back to the source code again, or you may even need to go back and change the design.
Here's a rough outline of what happens at each step.
Design
Decide what you need the program to do. Try to break the problem down into functional blocks; pieces that you can turn into functions or classes in a programming language. The design process can be further broken down. First there is a basic investigation process, where you try to figure out what needs to be done and how, in theory, it could be done. Secondly you determine the functional blocks of the system and define their interfaces. Thirdly you design the details of interal processing for each functional block.
Writing Source Code
Write a text file (source file or source code) which contains text in the programming language you are using. There should be a file for each class, or each closely related group of functions or classes. There may be one file for each functional block in the design, or the blocks may be split up into smaller pieces. Some parts may even be split off into separate libraries.
Compiling
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/process.html (1 of 2) [10/17/2002 9:54:25 PM]
The Programming Process
Take the source code and compile it into object code. Object code is a translation of the instructions you wrote in the programming language into the native language of the computer (basically lots of numbers, also called machine language). Each source file is translated into one object file.
Linking
Link all the object code files for the program together to create an executable. An executable is a file in the native language of the computer arranged so that it can be read from a disk into the computer's memory and executed (or run) from start to finish. If you are using libraries you may have to include those libraries, which are sets of object files archived together for easy access.
Debugging
Almost no programs run perfectly, or even well, the first time they are run. You will have to find out what is wrong with a program and probably go back to the source code to fix the problem. This process is called debugging, and for some programs it never seems to end. Debugging should include testing, which means component testing (each functional block alone), integration testing (combinations of functional blocks and their interfaces) and system testing (the whole system).
After all that the program is finished. Except, of course, that you will always find some new feature you want to implement, or piece of code you want to tweak. At that point you go back to step one and design your modifications, and start into the cycle again.
http://webclub.kcom.ne.jp/ma/colinp/win32/basics/process.html (2 of 2) [10/17/2002 9:54:25 PM]
The Archiver or Librarian
The Archiver or LibrarianAn archiver is a program which allows you to store a set of related object (.o) files together in one archive (.a) file for convenient searching and inclusion by the linker. The archiver for the GNU compiler suite is called ar.
Using ar is pretty simple. Generally using the following form of the command line is enough:
ar -ru libfoobar.a foo.o bar.o
That replaces (-r) the copies of foo.o and bar.o in the library libfoobar.a with the files of the same name. If the library does not exist it creates a new one and if either foo.o or bar.o are not in the library to start with it adds them. The u option tells ar to check that the files foo.o and bar.o are newer than the copies stored in the library (if any) before copying them into the library.
For instructions on including libraries in programs see the section on the linker.
The DebuggerWhen you have finally gotten your program to compile and link without errors you can run it and see if it works. It probably won't. This is not me saying you are a bad programmer, this is me saying you are a human being. Programs of significant size never work right the first time. Some problems can be solved by familiarity with the code and watching the behavior of the program, or by looking through the source code. But there comes a time where you would like to see what the program is actually doing inside. This is what a debugger allows you to do. The debugger generally used with the GNU compiler suite is called gdb.
Including Debugging Information in Your Programs
In order to use a debugger first you have to compile with debugging information included. The option to do this with gcc is -g. At both the compiling and linking steps simply include the -g option like this:
gcc -g -c -o foo.o foo.c
gcc -g -c -o bar.o bar.c
gcc -g -o foobar.exe foo.o bar.o
Running the Debugger
You can run the debugger like this:
gdb foobar.exe
This will set up gdb to debug the program foobar.exe and will give you the gdb prompt, from which you can run commands to debug the program. At the gdb prompt type the command help to get help.
Viewing Code
The command list or l will list the next ten lines in the current source file. Using the command with a line number will list the lines around the given line in the current source file. Using l with a function name will list the lines around the beginning of that function.
To switch to a different source file use the following form.
http://webclub.kcom.ne.jp/ma/colinp/win32/tools/debug.html (1 of 3) [10/17/2002 9:54:26 PM]
The Debugger
list foo.c:1
This lists the first few lines of the file foo.c and sets the current source file to foo.c.
Setting Breakpoints
Generally you will not want to trace through the whole program, so you should set breakpoints at the functions you are interested in. This will cause the program to pause and allow you to use other gdb commands whenever the program hits the indicated point in the source code. The command for setting a breakpoint is b, like this:
b WinMain
That will set a breakpoint at the beginning of the function WinMain.
Running a Program
You can start the program running with the run or r command. You can type arguments to pass to the program after r just like you were running the program on the command line.
Viewing the Contents of a Variable
When the program is stopped at some point you can display the contents of variables using the print command:
print n
That prints the contents of the variable n. You can also print the contents of structures, C++ objects and arrays like that. gdb will try to figure out the correct type from context.
Continuing
You can set the program running again after hitting a breakpoint by using the c command.
Stepping Through the Program
You can continue one step at a time through a program using the step or s and the next or n commands.
Exiting gdb
http://webclub.kcom.ne.jp/ma/colinp/win32/tools/debug.html (2 of 3) [10/17/2002 9:54:26 PM]
The Debugger
Type q to exit gdb. Generally it is best to do this only after the program being debugged has finished.
http://webclub.kcom.ne.jp/ma/colinp/win32/tools/debug.html (3 of 3) [10/17/2002 9:54:26 PM]
The Resource Compiler
The Resource CompilerThe resource compiler takes resource scripts (.rc) and turns them into object files (.o) to be linked to your program. The resource compiler provided for the GNU compiler suite is called windres. Currently there is a limitation with the resource compiler and linker combination that means you can not reliably use more than one object file with resources. You must compile all the resources for a single program or DLL in one resource script and create one object file.
You can run windres like this:
windres -i foo.rc -o foo.o
That takes the resource script foo.rc and turns it into the object file foo.o. Then you can link that object file just like any other object file in your program.
For more information on resource scripts see the section on resource scripts and the section on resources in general in the Win32 programming tutorial.
The DLL Import Library ToolIn order to create DLLs, or to use DLLs provided by other programmers, you generally need to create import libraries. Import libraries look like ordinary libraries, but they contain special object files with the information required to perform dynamic linking at run-time. Import libraries are created using a definition or .def file. The tool for doing this with the GNU compiler suite is called dlltool.
Note: Many (all?) of the functions of dlltool have been absorbed into the linker in the latest versions of gcc for Mingw. It is possible to build DLLs and produce import libraries without using dlltool at all. I will fix this section of the tutorial as soon as I get familiar with the options in the latest linker myself. For the time being, dlltool will still work as described below so there is no need to worry too much.
To use dlltool to create an import library from a given .def file you can do something like this:
That command generates an import library called libfoo.a from the definition file foo.def. The --dllname option tells dlltool to associate the library with a DLL that will be called foo.dll. The name included after in the --dllname option is the one that will be used by Windows to search for the DLL when your program is loaded. It should simply be the name of the DLL, without any directory name or path information.
PASCAL/STDCALL/WINAPI Functions
The STDCALL calling convention for functions is widely used in Win32 API functions (WINAPI and PASCAL are both synonyms for STDCALL). Internally gcc uses a special notation for such functions which includes an at mark (@) and a number at the end of the function name. However, most DLLs export the function names in plain form (without the @). In such a case the .def file should contain the complete names, with an @, and you have to supply the -k option to dlltool to tell it to remove (or kill) the @ extension from the names used by Windows when connecting the program which uses the import library to the DLL (the @ extension is still present inside the import library so that gcc, which uses the @ extensions, can find the correct symbols in the import library).
Sometimes you will have a DLL you want to use but no .def or import library. dlltool is not the right tool to use for this problem. Instead you should use impdef, which is not part of the GNU compiler suite, to
http://webclub.kcom.ne.jp/ma/colinp/win32/tools/dlltool.html (1 of 2) [10/17/2002 9:54:27 PM]
The DLL Import Library Tool
extract the exported function names from the DLL and create a .def file. This is an unreliable process, but it is only generally necessary if you are using a DLL which is not open-source software. (And you'd never do that unless you absolutely had to, right?)
● Download impdef.exe (as a 3 Kbyte .zip compressed file) from my homepage.
Here's how you use impdef:
impdef foobar.dll >foobar.def
That outputs the exported function names in the DLL foobar.dll and puts them in a .def file called foobar.def. If all goes well you can then use the .def file to produce an import library like this:
The Project Building ToolA project building tool, or project management tool, allows you to automatically rebuild a program or library containing a large number of source files. Generally a project building tool will recompile only those files which have changed, or depend on files which have changed. The project building tool also insulates you from setting all the options for gcc and other programs.
The project building tool most often used with the GNU compiler suite is GNU make. I won't attempt to explain how to use make here. See the documentation for make from the Free Software Foundation for that.
One alternative to make is a tool called Jam, but make is much more common.
Getting gcc to Generate Dependency Information
Make needs to be told which files depend on which other files. For example, if you have a header file a.h included by a source file b.c and you change a.h (but not b.c) wouldn't it be nice if make automatically rebuilt b.c to reflect the changes the next time you typed "make"? That doesn't happen by default (incidentally, with Jam this does happen automatically). You need to tell make explicitly about the relationship between a.h and b.c. You need to tell make that b.c depends on a.h.
One way to do this is to manually put the dependencies into the make file. For the above situation you might add a line like this:
b.o : b.c a.h
What that says is that the object file b.o depends on both the source file b.c and the header a.h, so when either one is newer than the object file the object file will be rebuilt.
If you have more than a couple of files or a couple of headers then writing all these dependencies out by hand is a very tedious and error-prone process. Fortunately it can be automated using the -M option to gcc.
For example, you could add something like this to your make file:
Assuming CC is set to gcc and CFLAGS is set to the appropriate set of compiler flags, and that ALL_SOURCES is a list of all the source files in your program, that will output dependency information into the file named "depends". The last line includes the file named depends in the make file itself.
Unfortunately this still means you have to explicitly do "make depends" every time there might be a change in the dependencies of your program, but it is still better than doing it by hand.
http://webclub.kcom.ne.jp/ma/colinp/win32/tools/project.html (2 of 2) [10/17/2002 9:54:27 PM]
Revision Management Software
Revision Management SoftwareWhen you start dealing with large software projects composed of multiple source files, or even multiple libraries and programs, you will almost inevitably run up against the problem of revision management. This is especially true if you are not the only person working on a piece of software. Unless you use some kind of revision management software you may find that modifying and maintaining a large project, especially with several active programmers, is at the least difficult, and probably next to impossible for any project which could really be called "large".
Fortunately there are at least two free revision management packages available. One is RCS, (Revision Control System) and the other is CVS. I won't go into the details here, but here is documentation for CVS from the Free Software Foundation.
Creating and Using Resource ScriptsResources are specified using a special, very simple text file called a resource script or .rc file. You write this file, specifying all the various resources you want to include in your program, and then compile it with a program called a resource complier (for Win32 versions of EGCS and gcc this program is called windres). The resource complier produces an object file containing the resource data objects in a format the linker can include in your programs. (With Microsoft and other compilers the resource compiler produces a special intermediate format called .res, which their linkers can understand but otherwise don't resemble object files).
For an introduction to windres, the resource compiler for the GNU compiler suite, and a simple example of how to use it, see the resource compiler page in the introduction to GNU programming tools.
Resource script files are passed through the C preprocessor so you can use preprocessor commands and C style comments /* ... */ (you can also use C++ style comments \\ ... but some preprocessors for other compilers do not automatically understand those). However, other than that resource scripts are very different from C code. Generally resource script statements are sensitive to where you put line breaks and that sort of thing, so try to follow the given syntax as closely as possible.
Each resource type is described on it's own page, which you can access through the links on the index page for this section.
Including Files for Definitions
Most of the time you should include at least windows.h in your resource file to define all the constants from the Win32 API. You should also include a header file of your own, resources.h for example, that defines all the constant IDs you will use for various resources (that way you can include the resources.h file in any source code that needs to access a resource and you only have to set the ID in one place, which reduces the chances of making a mistake or having mismatched ID numbers). For example this is a fragment of a resource file:
If you do include your own header files in resource scripts make sure to enclose everything that is not a C pre-processor statement in #ifndef RC_INVOKED ... #endif blocks. Resource compilers generally define RC_INVOKED during preprocessing so that you can keep them from reading, and being confused by, C or C++ statements in your header files. For example, you might have something like this in the resources.h header:
#ifndef RC_INVOKEDextern int foo; /* The resource compiler would not understand this */#endif
The Win32 headers and the standard C run-time headers should already be set up this way (but if they aren't now you know how to fix them, right!).
http://webclub.kcom.ne.jp/ma/colinp/win32/resources/script.html (2 of 2) [10/17/2002 9:54:28 PM]
Win32 Resources
Using ResourcesResources are an important part of programming using the Windows GUI (Grapical User Interface). Unless you only write console (text-only) programs you will probably end up creating and using a few resources. The following pages cover creating resources of several types and using them in your programs.
● Introducing Resources● Creating and Using Resource Scripts● Menus● Keyboard Accelerators● Dialogs● Icons● Cursors● Bitmaps● Strings● User Data
The syntax for resource scripts is also available on the Web at Microsoft's site.
Introducing ResourcesWhen we talk about resources in Win32 programming what we usually mean is a special kind of data used by the Win32 API to create pieces of the user interface. For example, to include a menu bar on the top of a window you are creating with the CreateWindow function you can include a menu handle (type HMENU) as the hMenu parameter (the ninth parameter in case you're interested). To get a menu handle you can call the LoadMenu function, like this for example:
In this example there must be a menu resource named "MenuName" linked into the program (you can load resources in other files by loading the file with LoadLibrary and using the instance handle returned by that call as hInstance for LoadMenu or some other resource loading function). Creating the resource data, making it part of your program, and making use of the resource data inside your program is what the rest of the pages in this section are about.
You can define resources for your program using a very simple language (a resource script), something like a programming language restricted to defining variables and structures. You can use graphics programs to draw bitmaps, icons and cursors, and then include them in your resource script by name. There are also programs for designing dialog boxes and menus interactively, and integrated resource editing packages that combine all these functions. Unfortunately most of these programs cost money and are not open source. I would be interested if anyone could point me to some good open source alternatives.
Resource IDs
Every resource in a resource script has an ID. A resource ID can be either a name enclosed in quotes (e.g. "MyResource") or a number. Generally I use numbers because they are slightly easier to manage and take less memory than text names. Usually you will use the C preprocessor to define constants for the IDs of all your resources and put them in a header file so that you can include the header in both your source code and the resource script.
The Win32 API functions that load resources all take two arguments, one is the instance handle, which I will discuss below, and the other is the resource ID. If you are using text names you could simply use a pointer to the name to load the resource:
hIcon = LoadIcon (hInstance, "HappyFaceIcon");
http://webclub.kcom.ne.jp/ma/colinp/win32/resources/intro.html (1 of 2) [10/17/2002 9:54:29 PM]
Introducing Resources
But if you are using numbers you need to use the MAKEINTRESOURCE macro defined in windows.h to put the ID in a form that the resource loading functions will recognize:
The other piece of information needed for loading a resource is an instance handle. An instance handle is a number assigned by the Windows operating system to each executable file (.exe or .dll for example) that is loaded by an application. Normal programs consist of a single .exe file, along with several .dll files loaded in automatically. To access resources you have added to a program you need the instance handle of the .exe file. You can obtain this instance handle either by saving the handle that is passed as an argument to WinMain, or you can call GetModuleHandle like this:
That example loads the DLL foo.dll and then loads the icon identified by the ID constant ID_ICON_FOO from the DLL.
http://webclub.kcom.ne.jp/ma/colinp/win32/resources/intro.html (2 of 2) [10/17/2002 9:54:29 PM]
Menu Resources
Menu ResourcesUnder Construction...
A menu is the set of commands that appears at the top of many windows, or that you can make appear using the right mouse button (this is often called a context menu, because it depends on what is under the mouse pointer, the context). Basically any list of commands which you click to activate, and which may be divided into several sub-menus (or popup menus) is probably built using a menu resource.
You can build menus from scratch inside your programs using API functions, but it is often more convenient to build them as resources and include them in your programs.
The basic menu syntax in the resource script file is:
id MENUBEGIN item ...END
id is the ID number of the menu. Each item is one of the following:
● MENUITEM SEPARATOR - A break will appear in the menu between the preceding items and the remaining items.
● MENUITEM - A menu item, which will generate a WM_COMMAND message. ● POPUP - A popup menu or sub-menu.
The syntax of menu items is:
MENUITEM text, result, [options]
text is the text that will appear as the menu item in the displayed menu. This should be enclosed in quotes. An ampersand (&) indicates that the next character should be underlined (and that the underlined character should be the key that the user can use to activate the menu item when using the menu). The \t character sequence represents a tab and aligns menu text in columns. Usually you use \t to separate an indicator of the menu item's accelerator key from the rest of the menu text, for example:
MENUITEM "E&xit\tCtrl+Q", CMD_FILE_EXIT
The x will appear underlined, and the Ctrl+Q will be separated from the rest of the text against the right
http://webclub.kcom.ne.jp/ma/colinp/win32/resources/menu.html (1 of 2) [10/17/2002 9:54:29 PM]
Menu Resources
side of the menu.
result is the number which will be sent to your window with the WM_COMMAND message to indicate which menu item was selected.
options can be CHECKED or GRAYED to indicate that the menu item should initially have a check mark next to it, or be inactive (there are other options, but they are rarely used).
The syntax of a popup menu is:
POPUP textBEGIN item ...END
text is the same as text for a menu item, and item syntax is the same as a top menu's item (thus you can nest any number of menus).
http://webclub.kcom.ne.jp/ma/colinp/win32/resources/menu.html (2 of 2) [10/17/2002 9:54:29 PM]
Keyboard Accelerators
Keyboard AcceleratorsUnder Construction...
A keyboard accelerator is basically a special way of translating a key or combination of keys pressed by the user into WM_COMMAND messages like the ones your windows receive when the user clicks on a menu item. For example, most Windows programs have a menu option Copy under the Edit menu which copies the currently selected object (or objects) into the clipboard. Most programs also allow you to perform the same operation by pressing the control key (Ctrl on most keyboards) and the C key at the same time. In fact the message that is caused by the user clicking the Copy menu item and the message caused by the user pressing Ctrl+C is probably the same: a WM_COMMAND message with an ID associated with the copy operation. Windows uses a table called an accelerator table to convert keystrokes by the user into messages to send to the program. These tables are resources which you can create in a resource script and include in your programs to get similar functionality.
In a resource script accelerator tables have the following syntax:
table_id is the ID number of the acclerator table which you will use to associate the table with a window in your programs. Each row of the table contains an event, plus the id number that is sent with WM_COMMAND messages by that event. A row may also contain a type which must be either ASCII or VIRTKEY, and options.
An event is one of:
● A single character in quotes, e.g. "a" (case is important). ● A caret followed by a single character, enclosed in quotes, e.g. "^C" This represents the given key
pressed at the same time as the control key, for instance, the example just given represents control and the C key pressed at the same time.
● An ASCII character code number. ● A virtual key code, which is either a single uppercase character in quotes or a special constant
beginning with VK_ (e.g. VK_F1). In this case type must be VIRTKEY to differentiate it from the first and second types of event.
options can be one or more of:
http://webclub.kcom.ne.jp/ma/colinp/win32/resources/accel.html (1 of 2) [10/17/2002 9:54:29 PM]
Keyboard Accelerators
● ALT - Only activates when the Alt key is down. ● SHIFT - Only activates when the Shift key is down. ● CONTROL - Only activates when the Control key is down. ● NOINVERT - Provides no visual feedback in the menu (usually not necessary).
separated by spaces. The first three are only valid if type is VIRTKEY.
http://webclub.kcom.ne.jp/ma/colinp/win32/resources/accel.html (2 of 2) [10/17/2002 9:54:29 PM]
Dialogs
DialogsUnder Construction...
Dialog boxes, or simply dialogs, are those windows with a bunch of buttons and spaces to fill in that pop up every so often in Windows programs so that you can set or modify the properties of some object, or select a file, and so on.
Icons are the small pictures that you see on the desktop or in Explorer representing files and programs. They are also the pictures that appear in the upper left corner of various program windows or on the left end of the buttons in the task bar representing running programs. Icons are basically just small bitmaps, but they include a special second bitmap which acts as a mask. The mask bitmap indicates which parts of the icon image are transparent.
You can create icons and include them in your programs. This can be useful for representing different object types graphically in the program, or simply to identify the program itself with a custom icon.
To create icons you use an icon editor (if anyone has any recommendations for an icon editor send me email) and save it as a .ico file.
Once you have an icon file you can include it in your resource scripts like this:
ICON_ID ICON "test.ico"
In this example ICON_ID is a preprocessor constant we defined elsewhere to be the icon's resource ID.
Cursor ResourcesA cursor, or pointer, is a small picture which can be used as a marker for the current mouse position. The picture, like an icon, has two parts: a normal picture, and a stencil or mask which indicates which parts of the cursor image are transparent. You can create cursors and include them in your programs as resources. This can be useful for providing visual feedback, such as the pointing hand that indicates the mouse is over a hyperlink in most web browsing software.
You create a cursor using a cursor editing program (sometimes graphics programs can create cursors) to create a cursor file (.cur). Note: I am planning to write up a simple cursor editor one of these days and put it up on the net, with source code of course, but if anyone knows of a good cursor editor (free or otherwise) please drop me an email.
After you have a cursor file you can use the following syntax to include the cursor in your resource script:
CURSOR_ID CURSOR "test.cur"
CURSOR_ID, in this example, is a preprocessor constant defined elsewhere (probably in an include file), you would substitute your own ID constants for cursors you create. Similarly, the cursor file is named test.cur in the example, but you would replace that with the name of the cursor you had created in your own resource scripts.
Once you have a cursor resource in your program you can use the LoadCursor function to retrieve it:
Note that you can also use the LoadCursor function to get handles to standard Windows cursors included with the operating system:
HCURSOR hCursorSystem = LoadCursor (NULL, nID);
where nID is one of the following (for example):
● IDC_APPSTARTING The arrow and hourglass pointer used when performing tasks in the background.● IDC_ARROW The default arrow pointer● IDC_IBEAM The text edit pointer (I-beam)● IDC_NO A circle with a diagonal bar (like a no-smoking sign)● IDC_SIZEALL A four pointed arrow● IDC_SIZENESW A diagonal line with arrowheads pointing to the upper-right and lower-left● IDC_SIZENS A vertical line with arrowheads pointing up and down● IDC_SIZENWSE Like IDC_SIZENESW except the arrows point to the upper-left and lower-right● IDC_SIZEWE A horizontal line with arrows pointing left and right● IDC_WAIT The busy pointer (by default an hourglass)
Once you have a cursor handle you can set the current cursor using SetCursor (don't forget to save the old one):
/* ... part of the code where the cursor is different ... */
SetCursor (hPreviousCursor); /* Restore the cursor */
Of course, generally the setting of the cursor and restoration will be in different functions, and you will have to store the previous cursor handle in a static variable or (better) in a class member variable. Also, since the cursor is shared by many windows and programs, it is good programming practice only to set the cursor when you know your window has 'control' of it (possibly because you have used the SetCapture function).
Another use for cursor handles is setting the cursor for a window class. All windows of the given class will then have that cursor:
RegisterClassEx (&wc); /* Register the window class */
The cursor identified by ID_WINDOW_CURSOR in the application's resource script will appear whenever the mouse pointer is over a window created with that window class.
http://webclub.kcom.ne.jp/ma/colinp/win32/resources/cursor.html (2 of 2) [10/17/2002 9:54:31 PM]
Bitmap Resources
Bitmap ResourcesA bitmap is a kind of picture. You can create resources from bitmaps and include them in your programs (or DLLs). Generally you do this to create user interface elements like tool bars with custom graphics. The other way to use bitmaps is to load them directly from a file (surprisingly there is no Win32 API function to do this), but that is a different story.
Creating a bitmap is simply a matter of using some graphics program (the Paint program included with Windows will do) to draw an image and save if in the Windows Bitmap file format (with the extension .bmp generally). Then you include the bitmap in your resource script using the BITMAP keyword. For example:
#include "resources.h"
BITMAP_ID BITMAP "test.bmp"
That command line includes the bitmap file test.bmp as a bitmap resource in the program. In the resources.h header file BITMAP_ID is defined as some integer, e.g.:
#define BITMAP_ID 10
Then, to use the bitmap in your program you use LoadBitmap. The LoadBitmap function does not load a bitmap from a .bmp file as you might expect, but loads a bitmap resource with the given ID from the file associated with the instance handle supplied. For example, to get a bitmap handle for the bitmap resource created by the above resource script you might use code like this:
#include <windows.h>#include "resources.h"
/* ...other code, including the beginning of the function... */
/* Get the instance handle for this program */ HINSTANCE hInstance = (HINSTANCE) GetModuleHandle (NULL);
DeleteObject (hbmp); /* Delete objects when you're finished with them. */
/* ...more code until the end of the function... */
Once you have a bitmap handle you can select the bitmap into a device context and then copy the bitmap bits onto a window (or do various other things to it). I'll describe how to use bitmaps (and what a device context is for that matter) when I get around to writing the section of the tutorial on drawing graphics with the Win32 GDI (Graphics
http://webclub.kcom.ne.jp/ma/colinp/win32/resources/bitmap.html (1 of 2) [10/17/2002 9:54:31 PM]
Bitmap Resources
Device Interface) functions.
http://webclub.kcom.ne.jp/ma/colinp/win32/resources/bitmap.html (2 of 2) [10/17/2002 9:54:31 PM]
String Resources
String ResourcesUnder Construction...
The resources for a program can include a string table. A string table associates an ID number with a string. This can be useful for specifying error or status messages.
In fact, it is a good idea to separate the output messages of a program from the code which does the output, and especially from the code that generates the event which eventually leads to output. A string table makes it easier to modify the output of the program, to standardize error messages for example, without digging through the source code looking for strings. However, many programmers still include literal strings distributed throughout their source (like me, for example).
Dynamic Link LibrariesDynamic Link Libraries, or DLLs, are a method used in Win32 programming to share code between several different programs. The code is stored in a DLL file and linked to the programs that use it when the programs are run (instead of when the programs are built, like static libraries).
● Introduction to DLLs: What DLLs are and how they work.● Creating a DLL: How to build a DLL which you can use in your programs.● Using a DLL: How to build programs which use DLLs.
Win32 Library by Function NameInstructions on using these lists are located at the bottom of the page.
● Complete List (long) ● Special: __CPPValidateParameters@8 to _TrackMouseEvent ● A: AbortDoc to auxSetVolume ● B: BackupEventLog to ByeByeGDI ● C: CalcChildScroll to CursorLibTransact ● D: data_from_ndr to dwOKSubclass ● E: EditWndProc to ExtTextOut ● E: FatalAppExit to FtSubFt@16 ● G: GdiComment to GrayString ● H: HACCEL_UserFree to HWND_UserUnmarshal ● I: I_RemoteMain to IUnknown_Release_Proxy ● J: joyConfigChanged to joySetThreshold ● K: K32_NtCreateFile to KillTimer ● L: LAddrParamsInited to LZStart ● M: MailToProtocolHandler to MultinetGetErrorText ● N: NdrAllocate to ntohs ● O: OaBuildVersion to OutputDebugString ● P: PackDDElParam to PwdSetPasswordStatus ● Q: QT_Thunk to QueueUserAPC ● R: RaiseException to RtlZeroMemory ● S: s_perror to SzFindSz@8 ● T: TabbedTextOut to TUISPIDLLCallback ● U: UFromSz@4 to UuidToString ● V: ValidateErrorQueue to VRetrieveDriverErrorRowCol ● W-Z: WaitCommEvent to YieldTask
The above set of text files contain the names of Win32 API functions (and other functions available with a basic installation of Windows 98) arranged in alphabetical order, followed by the name of the library which contains the function. In order to use the function in programs compiled with gcc you can simply add -l plus the name of the library to the end of your link command line. For example, if you wanted to use the function BindMoniker you would select the link to the functions that begin with b given above. You would find that BindMoniker is in the ole32 library. Then you could link your program like this:
gcc -o foo.exe foo.o -lole32 -mwindows
http://webclub.kcom.ne.jp/ma/colinp/win32/fn2lib/index.html (1 of 2) [10/17/2002 9:54:32 PM]
Win32 Library by Function Name
Some functions, notably functions in oledlg and mfcuia32, have double entries because they exist in more than one library. There are also certain functions contained in libraries which do not have the same name as the DLL containing the function. For example the toolhelp functions are provided in the library th32, even though they are in the kernel32 DLL. Some of these functions are included in both import libraries. When they are not the DLL name will be included like this:
Process32First th32 (DLL:kernel32)
Cygwin and Mingw32 users should note that the kernel32 library is automatically included in all programs (even console mode programs), although this index still contains kernel32 functions for completeness. The -mwindows option includes the following set of libraries under Mingw32: user32, gdi32, comdlg32, kernel32, advapi32 and shell32.
http://webclub.kcom.ne.jp/ma/colinp/win32/fn2lib/index.html (2 of 2) [10/17/2002 9:54:32 PM]
Introduction to DLLs
Introducing Dynamic Link Libraries
What is a Dynamic Link Library?
A dynamic link library (or shared library) takes the idea of an ordinary library (also called a statically linked library) one step further. The idea with a static library is for a set of functions to be collected together so that a number of different programs could use them. This means that the programmers only have to write code to do a particular task once, and then, if they are good programmers, they can use the same function in lots of other programs that do similar things. However, with static linking the linker builds a program from all the object files that contain functions or data used in the program, which includes any library functions that are used. Each program gets it's own copy of all the library functions built into it.
A natural extension of the idea of a library is to put all the code for the functions in a library, but do the linking when the program is run instead of at link time (thus it is "dynamic"). A dynamic link library is a lot like a program, but instead of being run by the user to do one thing it has a lot of functions "exported" so that other programs can call them. There are several advantages to this. First, since there is only (in theory) one copy of the DLL on any computer used by all the applications that need that library code, each application can be smaller and save disk space. Also, if there is a bug in the DLL a new DLL can be created and the bug will be fixed in all the programs that use the DLL just by replacing the old DLL file. DLLs can also be loaded dynamically by the program itself, allowing the program to install extra functions without being recompiled.
How Does It Work?
Consider two files: a program foo.exe, and a dynamic link library bar.dll which foo.exe uses. How does the operating system connect these two files when foo is run? What happens is this: first the program file foo.exe is loaded, and the operating system finds a table of data in the file which states, effectively, "this program uses the following list of functions from the DLL bar.dll". This is called a list of imports or imported functions from the DLL bar.dll in the program foo.exe. The loader code next searches for the file bar.dll, and if it finds it then the file is loaded. Inside the bar.dll file is another list. This list, called the export list, gives the address inside the DLL file of each of the functions which the DLL allows other programs to access. Then the loader goes through both lists and fills in a table inside foo.exe (actually the copy of that table in memory) with the addresses of all those functions in bar.dll (based on where the dll was loaded in memory by the OS). Now, whenever the program wants to call a function in the DLL it simply uses the address stored in the appropriate table entry by the loader.
What this means is that a few extra things have to be done to use DLLs as compared to ordinary libraries. Each program must contain an import list for each DLL it uses, which I will talk about in the page on using DLLs, and each DLL must contain an export list, which I will talk about in the page on creating
http://webclub.kcom.ne.jp/ma/colinp/win32/dll/intro.html (1 of 3) [10/17/2002 9:54:33 PM]
Introduction to DLLs
DLLs.
Relocatable Dynamic Link Libraries
In the page on creating DLLs I will show how to make a "relocatable" DLL. It is possible, and simpler, to make non-relocatable DLLs, but it is a very bad idea most of the time.
When Windows loads your program it creates a whole new "address space" for the program. What this means is when your program contains the instruction "read memory from address 10A0F0" or something like that the computer hardware actually looks up in a table to figure out where in physical memory that location is, and performs the read operation on that memory. This is all done in hardware so it's very fast, and it means that every program can behave like it is running on a whole separate computer. The address 10A0F0 in another program would mean a completely different part of the physical memory of the computer.
Now, programs, when they are loaded, are "mapped" into address space. This process basically copies the code and static data of your program from the executable file into a certain part of address space, for example, a block of space starting at address 40000. The same thing happens when you load a DLL. Maybe you see what the problem could be?
A DLL, or a program for that matter, tells the operating system what address it would prefer to be mapped into. But, although the same address means different things to different programs, within a single program an address can only be used once. So what if there are two DLLs that both want to be mapped to address 100000? The OS will map the first one loaded to that address no problem, but the next one cannot be put there.
So the OS checks to see if the second DLL is relocatable. If so, then it maps the DLL to a different part of memory, say 200000. Then it performs the necessary relocations.
Why can't you just map the DLL to a separate part of memory? Well, the problem is that inside the DLL there are bits of code that say things like "read data from 10A0F0" or "call function at 101000". These addresses assume that the DLL is mapped into the part of address space that it prefers. If the DLL is mapped into a different part of memory then a call to 101000 might end up in the middle of the code of a different DLL, or in data, or nowhere at all.
So a relocatable DLL contains information so that the OS can change all those internal addresses. So that if the DLL wanted to be loaded at 100000, but was relocated to 200000 then the read data code will read from 20A0F0 instead of 10A0F0, and the function call will go to 202000 instead of 101000.
If you don't include this special data in your DLL it will be non-relocatable, and that means that if another DLL gets loaded into the preferred address first the program will not be able to load your DLL,
http://webclub.kcom.ne.jp/ma/colinp/win32/dll/intro.html (2 of 3) [10/17/2002 9:54:33 PM]
Introduction to DLLs
and will probably not run at all.
http://webclub.kcom.ne.jp/ma/colinp/win32/dll/intro.html (3 of 3) [10/17/2002 9:54:33 PM]
Using Dynamic Link Libraries
Using Dynamic Link Libraries
Using DLLs In Your Programs
In order to use a DLL you must have the appropriate header files and/or prototypes for the functions you want to call, plus the DLL of course, and a special library called an import library. An import library is a lot like a normal library except that instead of normal functions it contains an import table like I described in the introduction, and a short function with the name of the function you really want to call which looks up the correct address in the import table and calls the real DLL function. By linking your program with an import library you gain access to the functions exported by the DLL for which the import library was created.
Using an import library is just like linking with an ordinary library.
I talk about creating import libraries for your own DLLs in the section on creating DLLs. But sometimes you don't have an import library for a DLL that someone else gave you, which is what the next section is about.
Using Other People's DLLs
What if you have a DLL but you don't have an import library for it? At the moment this is the case for a lot of commercial DLL libraries which provide import libraries for Microsoft compatible compilers. At this time gcc does not understand Microsoft .lib files correctly (although that will be fixed in the future). To use the DLL you have to generate an import library that GCC will understand. You do that using dlltool in the same way as you generate import libraries for your own programs. But before you can do that you need a .def file. Fortunately there is a tool for automatically generating .def files called impdef.exe which is discussed in the section for DLL import library tools in the introduction to GNU programming tools.
Note, however, that impdef isn't perfect. Some newer DLLs confuse it so that it may not be possible to automatically generate the .def file, or the file won't work without changes. Also, gcc requires that functions with PASCAL calling convention (also called STDCALL or WINAPI functions) to have @nn added to the end of the function name, where nn is the number of bytes passed on the stack to the function in question (if you didn't understand that don't worry, just think of it as a magic number). Sometimes the functions will be exported with such "mangled" names, in which case things should be fine (as long as you don't use the -k option for dlltool). But in most cases, including almot all of the Win32 API functions, the mangled version is not exported. In this case you have to add the @nn on to each function name manually. You can generally determine the correct number by writing a program that uses the function and trying to link it. gcc will report the correct number in its linker error message (if the
http://webclub.kcom.ne.jp/ma/colinp/win32/dll/use.html (1 of 3) [10/17/2002 9:54:33 PM]
Using Dynamic Link Libraries
prototype is done correctly). You also have to use the -k option when creating the import library with dlltool, which I talk about a bit more in the section on creating DLLs.
There are other tools that will show you the exports for a DLL, including TDUMP from Borland and DUMPBIN (I think) from Microsoft. Also, using Explorer in Windows 95 you can Quick View a DLL, and that will also give you a list of its exports. Unfortunately you can't save it to a file or copy it to the clipboard, so it's very inconvenient for creating import libraries.
Global Variables in DLLs
With Win32 Microsoft introduced the idea that DLLs could contain global variables which you could access the same way you can access a function. The variables are also listed in the import/export tables with the functions, but instead of pointing to a function's code the variable entries point to the actual spot in memory where the variable is stored.
Microsoft made a special keyword for Visual C++ which makes the compiler generate the code to automatically follow the pointer in the import table and get or set the real value of such a variable whenever you manipulate it in your program. EGCS 1.1 and above should allow you to use the __declspec (dllexport) and __declspec (dllimport) syntax to use such variables. You can also access such variables by performing a little magic in your header files, if you are using another version of gcc for example. Say there was a variable foobar exported by a DLL you use. Here's how you could use it in your programs (assuming foobar is an int):
Then you can go ahead and use foobar just like it was the same variable all through your program, and the DLL will see the changes you make in the variable as well. But, before you start doing this all over the place a few words of warning:
● Older versions of dlltool used __imp_ as the prefix instead of _imp__. The new prefix is more compatible with Microsoft, and dlltool includes both for backward compatibility, but these type of changes show just how dangerous such a kludge can be.
● Using defines like that can cause strange errors, because define has no concept of scope. So, for example, a C++ member function called foobar might get inappropriately mangled by the define.
● You have to include the header file to access the variable, unlike normal global variables which you can declare inside individual source files or even functions.
● You can't use the same header file for making the DLL itself, since it must deal directly with the foobar variable.
All things considered, global variables should be avoided in any case, and even more so when you are
http://webclub.kcom.ne.jp/ma/colinp/win32/dll/use.html (2 of 3) [10/17/2002 9:54:33 PM]
Using Dynamic Link Libraries
dealing with dynamic linking. Still, it is possible to work with global variables in a DLL, but just because you can do something doesn't mean you should do it.
http://webclub.kcom.ne.jp/ma/colinp/win32/dll/use.html (3 of 3) [10/17/2002 9:54:33 PM]
Creating Dynamic Link Libraries
Creating Dynamic Link Libraries
.def Files and Export Lists
When you want to create a DLL you must generate an export list, which lists all of the functions which you will allow programs to call directly. It is a good idea to keep the export list for any one DLL to a managable size. You create an export list by writing a .def file, which you can use as input to the dlltool program to create import libraries for your DLL and to create the special export table that needs to be linked into your DLL.
A .def file looks like this:
EXPORTSFooBar
That simply says that there are two functions, Foo and Bar, which are exported by the DLL in question. Generally you won't have to get much more sophisticated than that.
Generating an Import Library
For other programs to be able to use your DLL you need to provide an import library which can be linked to those programs (or other DLLs for that matter). The tool for generating import libraries from .def files is called dlltool and is discussed in its own section in the introduction to GNU programming tools.
DLL Initialization in DllMain
When using Mingw32 to build DLLs you have the option to include a function called DllMain to perform initialization or cleanup. In general there will be an entry point function of some sort for any DLL (whether you use Mingw32 or not). In Mingw32 this entry point function is supplied by the DLL startup code automatically linked to a DLL, and that startup code calls DllMain. There is a default DllMain which will be called if you don't supply one in your own code.
DllMain might look something like this:
BOOL WINAPIDllMain (HANDLE hDll, DWORD dwReason, LPVOID lpReserved){ switch (dwReason) { case DLL_PROCESS_ATTACH: // Code to run when the DLL is loaded break;
case DLL_PROCESS_DETACH: // Code to run when the DLL is freed break;
case DLL_THREAD_ATTACH:
http://webclub.kcom.ne.jp/ma/colinp/win32/dll/make.html (1 of 5) [10/17/2002 9:54:34 PM]
Creating Dynamic Link Libraries
// Code to run when a thread is created during the DLL's lifetime break;
case DLL_THREAD_DETACH: // Code to run when a thread ends normally. break; } return TRUE;}
You put your code where the comments are. Notice that the function always returns TRUE. This is really only important when dwReason is DLL_PROCESS_ATTACH. If your code returns FALSE here that means that the DLL failed to initialize properly (for example, it couldn't allocate some memory it needed). The DLL will not be loaded and DllMain will be called again with DLL_PROCESS_DETACH immediately. If this DLL is being loaded automatically (instead of with the LoadLibrary function) that will make the loading of the entire program fail.
DllMain in C++ Modules
If you are writing code in C++ you should note that DllMain must not be "name-mangled" like normal C++ functions are (name mangling is a process that makes it possible to have two functions with the same name in C++ as long as they have different arguments). You can prevent the mangling of the DllMain function by adding
extern "C"
Before the name DllMain in the code above. You could also put DllMain in a separate .c source code file (but then you would have to worry about any calls made from inside DllMain to C++ code).
If you do not force DllMain to be a C function it will not be found by the call in the Mingw32 start up code, and the default DllMain in libmingw32.a will get called instead. If your initialization code doesn't seem to be called, and you are programming in C++, check that your DllMain function is either in a separate C source file or is forced to be a C function with extern "C".
Linking a DLL
Now, if you have created your .def file and have your object files ready, you can create a DLL. I have to warn you though, it's not pretty:
This creates a relocatable DLL called bar.dll from the object file bar.o and the .def file bar.def. Relocatable DLLs are better, because they can be placed anywhere in memory and you don't have to worry about whether two DLLs in your program will be fixed at the same base address (see below).
The first line generates an output file which we will discard, called junk.tmp, as well as a base file called base.tmp. A base file gives the information necessary to generate relocation information for the DLL. This step would not be strictly necessary if you didn't want a relocatable DLL, but it is better this way, really.
http://webclub.kcom.ne.jp/ma/colinp/win32/dll/make.html (2 of 5) [10/17/2002 9:54:34 PM]
Creating Dynamic Link Libraries
After removing the junk.tmp file the third line invokes dlltool to build the temp.exp file, which contains the export table to be linked with the DLL, as well as putting the relocation information in a form which can be linked in and used by the operating system to relocate the DLL (and also putting it in the temp.exp file). If you wanted to be really ambitious I think you could output the import library at the same time, but why make things more complex then they already are?
If you are exporting PASCAL functions without the @nn extensions remember that -k doesn't seem to work in that line. See the below section for what you have to put in the .def file to get this to work.
Since the base file is no longer needed the fourth line deletes it, and then the fifth line performs the final linking of the object files containing the functions in the DLL and the export table into the form of a complete DLL file. Then we delete the export table file since we no longer need it. If all goes well you should have a DLL file ready for use.
Probably you will want to automate this process using a make file or some such method. With the Mingw32 version of Jam the above process could be done from compiling bar.c to finished DLL and import library with the following line in a Jamfile:
Dll bar.dll : bar.c : bar.def ;
Standard Call or PASCAL Functions
I talked a little about standard call or PASCAL calling convention functions on the last page, but now I'll talk about them a bit more. A calling convention is a way of arranging information in memory, that is, on the "stack", before calling a function, as well as a standard for who gets rid of the information on the stack after it has been used. The C language uses a convention where after a function returns the caller cleans up the mess.
The PASCAL convention works sort of the other way around. The function called cleans up the mess before it returns. The C convention has the advantage that the called function doesn't need to know how many arguments were passed (which makes the magic of printf, and other variable argument functions, possible). The PASCAL convention makes for smaller code, because the code to clean up the arguments is only in one place (the function), instead of in every function that calls the given function.
GCC can generate function calls, and functions, that use the PASCAL calling convention using the special __attribute__((stdcall)) keyword sequence. In fact, the GNU Win32 API headers define PASCAL, WINAPI and STDCALL constants to all be that magic keyword sequence.
The problem for DLL writers is that internally GCC mangles PASCAL functions with an at symbol (@) plus a number indicating the number of bytes in the argument list. This prevents you from making a call to such a function with the wrong number of arguments, which would have that function destroying part of your stack, causing crashes and mysterious errors. Instead you get a link time error if you don't use the right prototype. However, many times DLLs will export names without that @nn addition, and there is no way to figure out what the number should be without looking at the prototype of the function and counting bytes, or trying to link a program which uses the function and seeing the number in the linker error. Both of these methods are tedious if you have a lot of functions to deal with.
If you want to create an import library where the DLL gives names without the @nn but those functions are PASCAL then you need to add the @nn to the function names in the .def file. For example if the above Foo and Bar functions were PASCAL functions that took single integer arguments the .def file might look like this:
EXPORTSFoo@4Bar@4
http://webclub.kcom.ne.jp/ma/colinp/win32/dll/make.html (3 of 5) [10/17/2002 9:54:34 PM]
Creating Dynamic Link Libraries
Then you need to use the -k option for dlltool telling it to kill the @nn for the exported function names (but keep it for internal use). E.g.:
That takes care of the program's side of the problem. The program linked with the produced library will look for the names without the associated @nn extension, and if the library exports the names without @nn they will be found.
Unfortunately, when building a DLL the -k option doesn't work! This line (see the section on linking a DLL above)
doesn't remove the @nn from the exported names in the created DLL (this is a bug in my opinion). Fortunately you can use the aliasing feature of dlltool to get this to work. Change your .def file to look like this:
EXPORTSFoo@4Foo=Foo@4Bar@4Bar=Bar@4
What the extra lines say are "export a symbol Foo (or Bar) pointing at the internal symbol Foo@4 (or Bar@4)." The import library produced by this .def file will have four internal symbols (available for use by your programs): Foo, Foo@4, Bar and Bar@4, but if -k is used Foo and Foo@4 both link to the exported symbol Foo, and similarly for Bar and Bar@4. The DLL produced using this .def file will export four names, Foo, Foo@4, Bar and Bar@4. The exported symbols all point to the internal @nn names.
The program will generate internal calls to Foo@4 and Bar@4, which will be resolved in the import library. Those symbols in the import library are, in turn, linked to exported names Foo and Bar. The DLL exports Foo and Bar symbols which point to the internal symbols Foo@4 and Bar@4, so everything works out in the end.
If you've really been paying attention closely you may notice that the above process is a little risky. If your program does not properly prototype the functions as STDCALL (or PASCAL) then it will try to link with Foo and Bar, and it will find them! However, they will be connected to the same STDCALL functions in the DLL as Foo@4 and Bar@4. Your program will corrupt the stack every time it calls Foo or Bar, and probably crash shortly afterwards.
To be completely correct and safe you have to use two .def files. One .def file for creating the import library and one for building the DLL. The import library .def file (call it bar_i.def) looks like this:
EXPORTSFoo@4Bar@4
same as before, and the DLL building .def file (call it bar_e.def) looks like this:
EXPORTSFoo=Foo@4Bar=Bar@4
http://webclub.kcom.ne.jp/ma/colinp/win32/dll/make.html (4 of 5) [10/17/2002 9:54:34 PM]
Creating Dynamic Link Libraries
Now when you build the import library using the first .def file like so:
the DLL exports the internal symbols Foo@4 and Bar@4 with only the names Foo and Bar. The DLL and the import library now match up exactly, so the only errors you should get will be linking errors... unless you forget the -k when building an import library, or use the wrong .def file somewhere...
http://webclub.kcom.ne.jp/ma/colinp/win32/dll/make.html (5 of 5) [10/17/2002 9:54:34 PM]