Welcome to the new Friends-of-FPC!

Here you can find all kinds of information about the FreePascal Compiler. We have many tutorials and howtos as well as a selection of tools to help you with your programming. We also have some example codes for you. And if you want to contribute some information/ sources/ tools yourself you can do so.
Also we have finally relaunched the FoFPC forum. It's your chance for some Q&A about everything FreePascal.

Friends-of-FPC

Tutorials: Learn how to code with FreePascal.

Source Codes: A collection of examples, miscellaneous source codes and open source stuff.

Tools and Help Files: Intro- duction of some tools that might help you with FPC.

Community

Forum: Ask or answer questions about the FreePascal Compiler, programming or just babble about coding.

Contribute! Contribute your own Tutorial, Source Codes or Tools and send them to us!

Website

About: Information about Friends-of-FPC.org.

Win32 Programmierung mit FPC - Teil 5 - by Delax

Fangen wir gleich richtig an. Ich sagte in einem früheren Teil das Windows "Event Driven" ist. Intern werden Nachrichten an Programme verschickt, mit denen das Programm über das System informiert wird: "Wurde eine Taste gedrückt", "Geht gerade der Bildschirmschoner los?", und so weiter. Ich sagte auch jedes Programm brauche so eine Art Schnittstelle zum System, welche diese Nachrichten verwaltet. Und eben dies macht der "Event Handler" unseres Programmes.

Der "Event Handler" eures Programmes wird von euch geschrieben, aber keine Sorge: ihr müsst euch nicht um alle Nachrichten kümmern, die da ankommen. Zumal es für jede Kleinigkeit, die gerade im System passiert eine eigene Nachricht gibt. Ihr könnt also nur bestimmte Nachrichten aussondern, diese bearbeiten und die restlichen Windows überlassen.

Nochmal eine Rückblende. Als ihr euer Fenster registriert habt, kam die Zeile WindowClass.lpfnWndProc := WndProc(@WindowProc); vor. Damit habt ihr eure "WndProc" angegeben. Die "WndProc" ist der "Event Handler", also die Funktion in eurem Programm, welche die Nachrichten verarbeitet. Euer Fenster nutzt von nun an die angegebene WinProc zum verabreiten von Windows-Nachrichten.

In Wirklichkeit kommen diese Nachrichten nicht wild auf euer Programm zu. Es hätte dann auch gar keine Zeit mehr sich um seine eigenen Aufgaben zu kümmern. Windows legt die Nachrichten vielmehr in einer Art Zwischenspeicher ab. Dort bleiben sie dann, bis sie verarbeitet werden.

Um es wirklich glasklar zu machen ein Beispiel: Windows hat eine Nachricht. Die Nachricht wird auf den Stapel gelegt. Ihr schaut nach was auf dem Stapel liegt. Wenn es euch interessiert, holt es ab und bearbeitet es. Wenn nicht, dann lasst Windows sich darum kümmern.

Schauen wir uns mal eine solche WinProc an.

function WindowProc(
                     HWND hwnd,
                     UINT msg,
                     WPARAM wparam,
                     LPARAM lparam )

Ein Blick auf die Parameter:

hwnd: Das ist unser Window Handle. Ist eigentlich nur wichtig, wenn wir mehrere Fenster der gleichen Klasse geöffnet haben. hwnd überprüft in dem Fall welche Nachrichten von welchem Fenster verursacht wurden.

msg: Das ist die eigentliche Nachricht, die WinProc verarbeitet. Naja - in Wirklichkeit ist es nur eine ID Nummer, kommt aber nahe dran.

wParam/ lParam: Für weitergehende Bearbeitung der Nachrichten. Hier steht der eigentliche Inhalt.

Wichtig ist LResult Callback. Nicht vergessen. So. Nun läuft die ganze Sache folgendermaßen ab: Wir holen die Nachricht ab. Schauen nach ob die Nachricht ID in msg für uns interessant ist und wenn ja, kommt ein Stück Code, wie wir weiter damit verfahren wollen. In msg stehen reine IDs, hier mal eine Auswahl:

WM_ACTIVATE - Ein Fenster wird aktiviert.
WM_CLOSE - Ein Fenster wird geschlossen.
WM_CREATE - Ein Fenster wird neu erzeugt.
WM_DESTROY - Ein Fenster wird zerstört.
WM_MOUSEMOVE - Die Maus wird bewegt

Das sind natürlich nur ein paar. Wie immer gilt: schnappt euch ein Windows Buch oder die Windows SDK Hilfe um einen kompletten Überblick zu bekommen.

Um es wirklich supereinfach zu machen interessiert uns erst mal nur eine Nachricht: WM_DESTROY. Die brauchen wir um festzustellen ob der User unser Fenster geschlossen hat, damit wir unser Programm daraufhin beenden. Merke: nur weil der User das Fenster zumacht, wird unser Programm von Windows nicht automatisch beendet! Das ist unser Job! Hier also unsere WndProc:

function WindowProc(Window: HWnd; AMessage, WParam,
                     LParam: Longint): Longint; stdcall; export;

begin
   WindowProc := 0;

   case AMessage of
     wm_Destroy:
       begin
          PostQuitMessage(0);
          Exit;
       end;
   end;

   WindowProc := DefWindowProc(Window, AMessage, WParam, LParam);
 end;

In dem "Hello World" Programm sieht die WinProc jedoch ein bischen anders aus - dort malen wir gleich noch Kram ins Fenster. Uns soll das erst einmal nicht interessieren.

Wars das? Naja...ja und nein - die einfache WndProc Funktion ist fertig, ja. Aber ist euch aufgefallen das wir nirgendwo die Nachrichten abholen und an die WndProc weiterleiten? Das müssen wir in der WinMain, also unserer Hauptschleife erledigen. Ihr erinnert euch an das allerersten Beispiel? Die WinMain ist die Hauptprozedur unseres Programmes.

In Pascal gibt es die Funktion "WinMain" eigentlich nicht, sondern das "begin" zeigt an das es sich um die WinMain handelt. Wer sich jetzt ein bischen mit Windowsprogrammierung unter C/ c++ auskennt wird sich fragen: wie bekommen wir denn dann das Handle zu unserer Applikation? In C/ C++ ist es so das der Wert, den man bei WinMain erhält das Handle zu der Applikation ist. Wir erinnern uns: das ist das Handle, welches der Scheduler verteilt.

Das wir dieses Handle nun nicht bekommen ist in der tat ein Problem, da wir es für viele Dinge brauchen. Zum Beispiel für die Fensterklasse. Doch hier hilft uns der FPC. Das Handle ist nämlich in einer Struktur gespeichert und lässt sich mit "system.MainInstance" abfragen. Das hilft zwar nicht immer, aber oft genug.

Nun macht eine normale Applikation im Hauptprogramm wenig anderes, als die Nachrichten zu verarbeiten. In unserem Fall sieht das so aus.

  while GetMessage(@AMessage, 0, 0, 0) do begin
     TranslateMessage(AMessage);
     DispatchMessage(AMessage);
   end;

Was tun wir da? GetMessage holt sich die aktuelle Nachricht und speichert sie in AMessage. Dann wird sie übersetzt und wenn wir schließlich verschickt. Einfach, oder?

Und das ist wirklich alles. Hmm...ich sehe schon wie ihr mit Fragezeichen im Gesicht vor eurem Monitor sitzt, aber es ist wirklich einfacher als man denkt - Übung macht hier den Meister.

Delax/ Sundancer Inc.
[delax@sundancerinc.de]

Back to previous page

Useful Links









Link to us