Once that you know how to code a simple windowless Delphi application with no user interaction, you are ready for the next step...
Message Boxes
In the following example I will use the standard Windows System "Message Box" to get some user input. If you look at the Win32 API Help in its index for "Message Boxes" you will find some information about message boxes. Now look in the API Help for "MessageBox" and there is the function definition for MessageBox() the parameter options and use. The MessageBox function is defined in the API Help "C" as:
int MessageBox(
HWND hWnd, // handle of owner window
LPCTSTR lpText, // address of text in message box
LPCTSTR lpCaption, // address of title of message box
UINT uType // style of message box
);
|
And in Delphi
function MessageBox(
hWnd: Cardinal;
lpText,
lpCaption: PChar;
uType: Cardinal
): Integer;
|
The first parameter is usually set to the "Windows Handle" of the main form window. When the message box closes, the system will give the keyboard focus to the window whose handle is here. Since our next example does not have any windows this parameter is set to 0 (NULL in C). The next parameter is for the message text displayed and the third parameter is for the title bar text. Both of these are PChar type. The fourth parameter is for uType, a Cardinal type. You will set the options for the message box in this parameter. In many windows API functions the options for functions are numeric values called a "flag" (see "Using API Function Flags" below). There are 2 flags you need to set for a MessageBox, the first is the "button" type and the next is the "icon" type. Look at the code for a Message Box:
MessageBox(
hMainWindow,
'There was an Error somewhere',
'ERROR, you got an Error',
MB_OK or MB_ICONERROR);
|
This will make a message box with one "OK" button and the Windows system icon for "error". If you use the flags "MB_OKCANCEL or MB_ICONQUESTION" you will get a message box with two buttons an "OK" button and a "Cancel" button, and the icon will be a "question mark". Since we'll need some user input in the next program the MB_YESNO flag is used in the first message box and the MB_OKCANCEL is used in the next one. By testing the Result of the MessageBox function you can see if one of the buttons was clicked, it will have the "ID" value of the button like "ID_YES". There are other flags for buttons, icons, display, and modal options, read the API help and try the options to see how they affect the message boxes.
Using API function flags
In most API functions there will be ways to change what the function does and other options for that function. A very common way is to use numeric flags in a parameter like in the fourth parameter of the MessageBox() function above. Since this method is used so much, some explanation may help you understand it. You may be used to the Object Oriented Delphi methods of option selection, API (other than COM) isn't object oriented, so API functions are used to create and change things. One method for setting options in a function is with numeric constants like MB_ICONERROR. In windows.pas some of the message box flags are defined as:
const
MB_OK = $00000000;
MB_OKCANCEL = $00000001;
MB_ABORTRETRYIGNORE = $00000002;
MB_YESNOCANCEL = $00000003;
MB_YESNO = $00000004;
MB_RETRYCANCEL = $00000005;
MB_ICONERROR = $00000010;
MB_ICONQUESTION = $00000020;
MB_ICONWARNING = $00000030;
MB_ICONASTERISK = $00000040;
MB_DEFBUTTON1 = $00000000;
MB_DEFBUTTON2 = $00000100;
MB_DEFBUTTON3 = $00000200;
MB_APPLMODAL = $00000000;
MB_SYSTEMMODAL = $00001000;
MB_TASKMODAL = $00002000;
|
Notice that the MB_OK, MB_DEFBUTTON1 and MB_APPLMODAL are all equal to zero (hex $00000000). This is because all of these are the "default" function options, so placing the MB_OK in the parameter or leaving it out, doesn't really change the value but it does give you an indicator in your code of what the function will do. Function flags are given constant names that try to give a description for what option that flag will produce. It is easier to read the code:
MessageBox(hWindow,'Some Error', 'ERROR', MB_OK or MB_ICONERROR);
|
than
MessageBox(hWindow,'Some Error', 'ERROR', 16);
|
To combine these flag constants you should use the "OR" operator. This is like the "+" operator when the bits are not present in the value, but if the bits are there then it will not "add" the bits to the value. This is safer to use since some of the constant values may be the same. For example:
MB_OKCANCEL or MB_ICONERROR or MB_OKCANCEL is equal to 17, hence 2 or 16 or 1 = 17 but
MB_OKCANCEL + MB_ERROR + MB_OKCANCEL is equal to 18, since 1 + 16 + 1 = 18
In the Object Oriented Delphi you set many options by a boolean value or a value in a Set of values, and if the value you assign is not in that set then the program will not compile with a "value not in set" error. With API functions using numeric flags you will get no compiler warnings or errors for values that are not in the function's numeric range of values. This parameter is defined as a Cardinal value, so the compiler will accept any value between 0 and 4294967295. When you first start using API flags like "SPI_GETWORKAREA", "SM_MOUSEPRESENT" and "MB_ICONQUESTION", you may forget that these are defined as numeric values, and you may be used to a Delphi "set" for options and think that "SPI_GETBORDER" is part of a Delphi set, but it's just a number.
Binary combine with the "OR" operator
Some flags are exclusive (like the button flags for MessageBox) and not meant to be combined. For example, if you wanted a a message box with 4 buttons on it, an "OK" button and a "Cancel" button and a "Yes" button and a "No" button, so you used "MB_OKCANCEL or MB_YESNO or MB_ERROR" as the flags. This would not produce a message box with 4 buttons, what you would get is a message box the 2 buttons, a "Retry" button and a "Cancel" button. Why? Because MB_OKCANCEL or MB_YESNO is equal to 5 (1 or 4 = 5) and 5 is the constant value for the Retry and Cancel buttons. What if you combined the MB_OKCANCEL or MB_YESNOCANCEL, what buttons would you get? If you said the "Yes" and "No" buttons (MB_YESNO = 4) you would be wrong, because "1 or 3 = 3", so you would get the "Yes", "No" and "Cancel" buttons.
The "or" operator works on the binary (bit) positions of the numbers, the decimal "1 or 3" is binary "0001 or 0011", since the 0001 bit is already in 0011 it can not put it there again. So you should only use a single button flag. This is why in the API help it says "Specify one of the following flags to indicate the buttons contained in the message box:" Many of the Flag constant values are meant to be combined and will have the bitmask values of 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, etc. This is why these constant values are defined in Hex, which is easier to see binary relationships than in decimal.
If you have not used the boolean "OR" operator very much (or other Boolean Logic), you might want to experiment with it for the Flags in the MessageBox() functions below. Binary operations are fundamental to programming, so you should have some knowledge of it, for API programming. For instance, what does "17 or 9" equal?
PChar typecast
I have seen an abundance of code presented for using API functions where a character array in the parameters will be typecasted as a PChar( ), like this:
MessageBox(
hMainWindow,
PChar('There was an Error somewhere'),
PChar('ERROR, you got an Error'),
MB_OK or MB_ICONERROR
);
|
I will not use this method here, because as far as I can determine the Delphi compiler will automatically create whatever variable type is required for that function's parameter using the character array in the parameter. The compiler reads the "characters" (letters) between the two apostrophes ' as an array of characters (not as a Delphi String), and then creates a variable type to match the function's variable type. So if the function uses a String type then a String type is created, if it is a PChar type, then a PChar type is created, a Wide String will get a wide String type, a PWChar will get a PWChar type, etc.
We are now ready for the last page, where the code of your second API program is waiting...
Next page > More complex example: system info > Page 1, 2, 3
A guide to developing Delphi programs in raw Windows API: Next Chapter >>
>>
Creating an API GUI Windows program with message loop