|

Win32/ FPC - Chapter 6 - by Delax
Now we will have some fun! We put all the basics together and create a working Windows application. All the different parts will be put in seperate procedures to avoid confusion and we'll add some error handling to track bugs.
Let's take a look at the variable section.
{$APPTYPE GUI}
{$MODE DELPHI}
program Win32_Source03;
uses windows;
const
AppName = 'Win32/ FPC - Source 03';
VAR
active : BOOLEAN;
msg : MSG;
hWindow : hwnd;
The unit Windows should be self explaining. active is a simple variable to check if the user has terminated our application. msg is a variable where the Windows messages will be stored in. hWindow will be the handle of our window.
The program starts with a little procedure to handle errors that might occur in our program. Whenever an error occurs, we call this procedure that puts out an error message and terminates the application.
// Try, Throw, Catch mechanism. Simple proc to display given errors. //
procedure ThrowError(pcErrorMessage : pChar);
begin
MessageBox(0, pcErrorMessage, 'Error', MB_OK);
Halt(0);
end;
Now for the function to handle Windows messages - the WinProc. In C/ Cpp the WinProc has to be the first procedure (but has to be below the WinMain, but that's a C/ Cpp problem ;).
// WinProc to handle Windows messages. //
function WindowProc(hEventWindow : hwnd; msg : DWORD; wParam : WPARAM;
lParam : LPARAM) : LRESULT; export;
begin
case (msg) of
WM_ACTIVATE : begin
active := true;
end;
WM_DESTROY : begin
active := false;
PostQuitMessage(0);
Exit;
end;
WM_KEYDOWN : begin
active := false;
end;
else
WindowProc := DefWindowProc(hEventWindow, msg, wParam, lParam);
end;
end;
All right. We are checking for 3 events: WM_ACTIVATE, WM_DESTROY and WM_KEYDOWN. WM_ACTIVATE is sent if our window is opened. In this case we set the active variable to true. If WM_DESTROY is sent, we'll terminate the program. The same happens if the user presses a key.
Next, we need a Windows Class.
// Register the Window Class //
procedure RegisterWindow();
var
WinClass: WndClassEx;
begin
WinClass.cbSize := Sizeof(WndClassEx);
WinClass.Style := cs_hRedraw OR cs_vRedraw;
WinClass.lpfnWndProc := WndProc(@WindowProc);
WinClass.cbClsExtra := 0;
WinClass.cbWndExtra := 0;
WinClass.hInstance := system.MainInstance;
WinClass.hIcon := LoadIcon(0, idi_Application);
WinClass.hCursor := LoadCursor(0, idc_Arrow);
WinClass.hbrBackground := GetStockObject(LTGRAY_BRUSH);
WinClass.lpszMenuName := nil;
WinClass.lpszClassName := 'WindowClass';
WinClass.hIconSm := LoadIcon(0, IDI_APPLICATION);
if RegisterClassEx(WinClass) = 0 then ThrowError('Registering the Windows Class failed!');
end;
Note that we don't use WndClass, but WndClassEx. The "Ex" is for extended and was introduced with Windows 98. Windows 95 and NT4 do not know the Ex structure, but on the other hand: it does not hurt either as older versions of Windows just use the normal Window Class structure instead. And it's the modern version, so we'll use it from now on.
Note that we are checking if the Window Class has been correctly registered. If not we throw an error.
Now we'll create the Window.
// Create the window. Throw error if this fails. //
procedure CreateWindow();
begin
hWindow := CreateWindowEx(
WS_EX_TOPMOST,
'WindowClass',
AppName,
WS_CAPTION OR WS_POPUPWINDOW OR WS_VISIBLE,
0, 0,
640, 480,
0, 0,
system.MainInstance,
NIL);
if hWindow <> 0 then begin
ShowWindow(hWindow, CmdShow);
ShowWindow(hWindow, SW_SHOW);
UpdateWindow(hWindow);
end else ThrowError('Window could not be created');
end;
We'll use CreateWindowEx because we also used the extended Window Class. We also check if our window has been created properly. If the Window could not be created we'll throw an error message.
// Destroy the window. //
procedure KillWindow();
begin
DestroyWindow(hWindow);
end;
Here the window is killed and the window handle is freed again. This should be done for a really clean escape. Now for the main loop.
// Main. //
begin
active := false;
RegisterWindow();
CreateWindow();
// Main loop. //
repeat
if PeekMessage(@msg,0,0,0,0) = TRUE then begin // if message waiting then get it
GetMessage(@msg,0,0,0);
TranslateMessage(msg);
DispatchMessage(msg);
end;
// -------- enter main loop code here -------- //
until active = false;
KillWindow();
end.
First, we set active to false. Why? Because if the window is created properly, active will become true anyway. If it is not created, the program will terminate itself automatically.
Now we call our procedures to create the Window Class and the window. Then we start the actual main loop. In this case it is a Repeat/ Until loop.
As of right now we only to the message handling here, but in a real application we would do all our main loop work here. As we will see most of the code is done in the WinProc actually, depending on the type of application. In our little program we only wait if there is a quit or keypressed message so we can leave the Repeat/ Until loop and therefore terminate our program.
Yaaaaay! We did it! We opened a Window! You can get the Source Code here. Download it, play around and then let's start off with the real coding ;)
Delax/ Sundancer Inc.
[delax@sundancerinc.de]
Back to previous page
|