Kapitel 1 - Windowsprogramme in C++ und ihre Besonderheiten
Leitfaden :
Was unterscheidet die Windowsprogrammierung vom guten alten DOS ?
Wo ist verdammt nochmal der Anfang ?
__________________________________________________ _____________
Was unterscheidet die Windowsprogrammierung vom guten alten DOS ?
Wer von euch hat denn schonmal Programme unter DOS geschrieben z.B. in QBasic ?
Ich hatte das damals noch in der Schule (ja ich weiss ich bin alt
).
Mit diesem Grundwissen hab ich mich dann in die eMule Welt gestürzt .
Nach einer Stunde bin ich völlig entnerft zu dem Schluss gekommen ohne C++-Buch geht wohl garnichts. Dabei war nicht der Code das Problem, sondern einfach die ungewohnte Strukturierung von objektorientierten Sprachen.
Bis dahin galt für mich ein Programmablauf ist linear....er beginnt in Zeile 1 und endet mit der letzten Zeile. Das war typisch für DOS und wie ist das nun im Windows?
Im Windows gibt es das
Meldungsrouting.
Vereinfacht gesagt eine Tastatureingabe, ein Mausklick...jeder Vorgang in Windows löst eine Meldung aus diese wird an die Ebene (z.B. ein Fenster) weitergeleitet für die sie bestimmt ist.
Dabei unterscheidet man Low-Level-Meldungen von Meldungen höherer Ebenen.
Für den Programmierer sind Low-Level-Meldungen normalerweise belanglos.
Mich interessiert es ja nicht ob der User irgendwo in Windows rumklickt oder gerade eine Eingabe in einem anderen Programm macht.
Mich interessiert eigentlich ja nur ob er z.B. gerade mit der Maus auf den Verbindungsbutton von eMule gedrückt hat.
Hier mal ein kleiner Auszug aus der
WINUSER.H zu Veranschaulichung:
Code:
#define WM_SETFOCUS 0x0007
#define WM_KILLFOCUS 0x0008
#define WM_ENABLE 0x000A
#define WM_SETREDRAW 0x000B
#define WM_SETTEXT 0x000C
#define WM_GETTEXT 0x000D
#define WM_GETTEXTLENGTH 0x000E
#define WM_PAINT 0x000F
#define WM_CLOSE 0x0010
#ifndef _WIN32_WCE
#define WM_QUERYENDSESSION 0x0011
#define WM_QUERYOPEN 0x0013
#define WM_ENDSESSION 0x0016
#endif
#define WM_QUIT 0x0012
#define WM_ERASEBKGND 0x0014
#define WM_SYSCOLORCHANGE 0x0015
#define WM_SHOWWINDOW 0x0018
#define WM_WININICHANGE 0x001A
Meldungen werden immer mit Namen angesprochen auch wenn das Betriebssystem dafür Integer verwendet, deshalb werden per #define-Anweisung die Namen mit den Zahlen verbunden.
Wenn ihr eMule nach WM_ durchsucht werdet ihr feststellen das im Muli neue Meldungen definiert werden. WM steht dabei für Window Message (Fenstermeldung).
Das Herzstück eines jeden Windowsprogramms ist die
Message Loop...eine Endlosschleife die so lange durchlaufen wird bis sie die Meldung
WM_Quit und somit false erhält.
In dieser Schleife werden die empfangenen Messages bearbeitet TranslateMessage( ) behandelt Tastatureingaben und DispatchMessage( ) ist eine riesige switch-Anweisung mit jeweils einer case-Anweisung pro Message die der Programmierer abfangen möchte.
Beispiele lass ich mal wegfallen,wenn sich jemand intensiv dafür interssiert kann man die immernoch nachreichen
.
Da diese Schleife bei umfangreichen Programmen wie eMule sehr sehr lang werden kann.
Löst die MFC das Problem indem sie die Informationen über die Meldungsverarbeitung möglichst eng an die Funktionen koppelt,die die Meldungen behandeln.
Dies geschieht über Meldungstabellen die mit
Code:
BEGIN_MESSAGE_MAP(...)
anfangen und mit
enden.
So jetzt habt ihr alles Wichtige mal gehört nun endlich zu eMule.
Da ich als "Linear-Programmierer" irgendwie immer einen Anfang und ein Ende brauche um mich in ein Programm reinzudenken stellte sich mir als erstes die Frage :
Wo ist verdammt nochmal der Anfang ?
Wie ihr sicherlich schon gemerkt habt kann man tagelang darüber diskutieren wo denn nun wirklich der Anfang eines Windowsprogrammes liegt so es denn einen gibt.
Also kurz, knapp, bündig.....für mich beginnt ein Windowsprogramm beim Initialisieren des Hauptfensters.
Also in unserem Falle genau hier:
emule.cpp Code:
BOOL CemuleApp::InitInstance()
{
CWinApp::InitInstance();
AfxEnableControlContainer();
CemuleDlg dlg;
emuledlg = &dlg;
m_pMainWnd = &dlg;
dlg.DoModal();
return FALSE;
}
Somit läßt sich auch schon sagen eMule ist keine SDI oder MDI-Anwendung sondern eine Dialogbasierte Anwendung.
Für das Hauptfenster interessant sind erstmal folgende Dateien :
CWinApp-Klasse für die gesammte Anwendung CemuleApp
Emule.cpp
Emule.h
Dialogklasse für die gesammte Anwendung CemuleDlg
EmuleDlg.cpp
EmuleDlg.h
und natürlich
emule.rc und
resource.h
Wie komm ich jetzt eigentlich zu der Behauptung das eMule eine Dialogbasierte Anwendung ist und warum soll gerade EmuleDlg das Hauptfenster sein ?
Gut die Wahl der der Namensgebung spricht ja für meine Aussage,aber das muß ja nichts heißen.
In der
emule.h steht folgendes :
Code:
class CemuleApp : public CWinApp
Das bedeutet das die Klasse CemuleApp von CWinApp abgeleitet wird und somit die zentrale Anwendungsklasse ist.
Wenn wir uns jetzt wieder CemuleApp::InitInstance() in emule.cpp anschauen sehen wir das dort die Dialogklasse CemuleDlg zum Hauptdialog ernannt wird .
Code:
CemuleDlg dlg;
emuledlg = &dlg;
m_pMainWnd = &dlg;
Und warum nun Dialog ?
Das ist schnell erklärt :
Typisch für einen Dialog ist die Funktion
dlg.DoModal( ) welche den Dialog erzeugt und das
return false am Ende von
BOOL CemuleApp::InitInstance() .
SDI- und MDI-Anwendungen liefern hier ein
true zurück was soviel bedeutet wie die Initialisierung wurde erfolgreich abgeschlossen führe den Rest der Anwendung aus.
Bei dialogbasierten Anwendungen gibt es keinen Rest der Anwendung, daher liefert
InitInstance ( ) ein
false zurück.
Pause