Applikationsklasse
Sehen wir uns nochmals die vom Assistenten generierte Applikationsklasse in Form
des Klassenbaums an:

Wie Sie sehen erstellt der Assistent drei Methoden: den Konstruktor CDVBasisApp(...),
die bereits bekannte Methode InitInstance(...) und die Methode OnAppAbout(...).
Die zuletzt genannte Methode werden wir zunächst nicht weiter betrachten. Sie ist,
wie erwähnt, dafür verantwortlich den vom Assistenten automatisch generierten About-Dialog
darzustellen.
Den Konstruktor des Anwendungsobjektes können wir ebenfalls getrost bei der Beschreibung
überspringen, er ist standardmäßig leer. Die zentrale Methode ist die Methode
InitInstance(...). Wie Sie bereits wissen wird innerhalb dieser Methode
die Anwendung initialisiert.
/////////////////////////////////////////////////////////////////////////////
// CDVBasisApp Initialisierung
BOOL CDVBasisApp::InitInstance()
{
AfxEnableControlContainer();
// Standardinitialisierung
// Wenn Sie diese Funktionen nicht nutzen und die Größe Ihrer
fertigen
// ausführbaren Datei reduzieren wollen, sollten Sie die nachfolgenden
// spezifischen Initialisierungsroutinen, die Sie nicht benötigen,
entfernen.
#ifdef _AFXDLL
Enable3dControls();
// Bei MFC in gemeinsam genutzten DLLs aufrufen
#else
Enable3dControlsStatic();
// Bei statischen MFC-Anbindungen aufrufen
#endif
// Ändern des Registrierungsschlüssels,
unter dem unsere Einstellungen
// gespeichert sind.
// ZU ERLEDIGEN: Sie sollten dieser Zeichenfolge einen geeigneten
Inhalt geben
// wie z.B. den Namen Ihrer Firma oder Organisation.
SetRegistryKey(_T("Local AppWizard-Generated Applications"));
LoadStdProfileSettings(); // Standard INI-Dateioptionen laden
(einschließlich MRU)
// Dokumentvorlagen der Anwendung
registrieren. Dokumentvorlagen
// dienen als Verbindung zwischen Dokumenten, Rahmenfenstern
und Ansichten.
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CDVBasisDoc),
RUNTIME_CLASS(CMainFrame), // Haupt-SDI-Rahmenfenster
RUNTIME_CLASS(CDVBasisView));
AddDocTemplate(pDocTemplate);
// Befehlszeile parsen, um zu
prüfen auf Standard-Umgebungsbefehle DDE, Datei offen
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
// Verteilung der in der Befehlszeile
angegebenen Befehle
if (!ProcessShellCommand(cmdInfo))
return FALSE;
// Das einzige Fenster ist initialisiert
und kann jetzt angezeigt und
// aktualisiert werden.
m_pMainWnd->ShowWindow(SW_SHOW);
m_pMainWnd->UpdateWindow();
return TRUE;
} |
Gleich am Anfang der Methode steht ein Kommentar den Sie sich unbedingt durchlesen
sollten. Der Assistent hat Ihnen eine InitInstance(...) Methode erzeugt
die alle für ihn erdenklichen Initialisierungsroutinen berücksichtigen. Doch welche
Initialisierungsroutinen sind unbedingt erforderlich und welche nicht? Sehen wir
uns dazu den Ablauf der Methode an.
Die erste auszuführende Initialisierungsroutine Enable3dControls(...)
bzw. Enable3dControlsStatic(...) wird vom Assistenten
eingefügt wenn Sie beim Erstellen des Projektes angegeben haben dass Sie 3D-Controls
verwenden wollen. Durch den Aufruf dieser Methoden wird die DLL CTL3D32.DLL
geladen. Je nach dem, ob Sie die MFC als DLL oder statisch verwenden, wir die eine
oder andere Methode ausgeführt.
So, als nächstes wird es etwas 'unangenehm'. Durch den Aufruf der Methode
SetRegistryKey(...), die später bei der Behandlung der Registrierungsdatenbank
noch ausführlich beschrieben wird, werden durch die Anwendung Einträge in der Registrierungsdatenbank
vorgenommen. Der Assistent erzeugt standardmäßig den als Parameter anzugebenden
Schlüssel Local AppWizard-Generated Applications. Der vollständige Pfad,
unter dem die Werte schließlich in der Datenbank abgelegt werden, lautet HKEY_CURRENT_USER\Software\<key>\<application
name>, wobei <key> der an SetRegistryKey(...) übergebene
String ist und <application name> der Name der Anwendung. Vielleicht sagen
Sie sich nun: ich speichere doch in meiner Anwendung gar nichts in der Registrierungsdatenbank
ab. Und doch werden indirekt Einträge in der Datenbank vorgenommen. Eine vom Assistenten
generierte Anwendung verwendet die Datenbank unter anderem zur Ablage der MRU Liste
(MRU =
most recently
used = Liste mit den zuletzt geöffneten
Dateien).
 |
Der oben genannte Registrierungsdatenbank-Eintrag wird eventuell auch unter
HKEY_USERS dupliziert. |
 |
Falls Sie das Beispiel nicht schon einmal gestartet haben,
starten Sie es jetzt. Gehen Sie dann in das Datei-Menü und öffnen eine
beliebige Datei. Sie werden natürlich im dargestellten Fenster noch nichts sehen
da wir ja noch keine Ausgaben vornehmen können. In der Titelzeile des Fensters
sollte jedoch der Name der geöffneten Datei erscheinen. Schließen Sie die Anwendung
und starten Sie dann den Registrierungsdatenbank-Editor REGEDIT. Wenn alles
richtig funktioniert hat müssten unter dem Pfad HKEY_CURRENT_USER\Software\Local
AppWizard-Generated Applications\DVBasis die nachfolgenden Einträge vorhanden
sein:

Der Eintrag File1 im rechten Teil enthält den Namen der vorher geöffneten
Datei, hier im Bild die Datei D:\TMP\CDoc.htm.
|
 |
Beachten Sie bitte, dass jedes vom Assistenten erstellte Programm ohne Modifikation
des Codes diese Einträge in der Registrierungsdatenbank vornimmt. Außer der
Speicherung der zuletzt benutzten Dateien erfolgen teilweise noch weitere Einträge
in der Datenbank. So wird z.B. auch die bei der Erstellung des Programms angegeben
Dateierweiterung automatisch über die Datenbank mit der Anwendung verknüpft. |
 |
Löschen Sie mittels des Programms REGEDIT den oben angegebenen
Eintrag DVBasis aus der Registrierungsdatenbank.
Anschließend kommentieren Sie den Aufruf der Methode SetRegistryKey(...)
einmal aus, übersetzen das Programm wieder und starten es erneut. Öffnen Sie
das Datei-Menü. Es sollten jetzt keine zuletzt geöffneten Dateien mehr
angezeigt werden. Öffnen Sie als nächstes eine beliebige Datei und beenden dann
das Programm sofort wieder. Wenn Sie jetzt die Registrierungsdatenbank erneut
öffnen werden Sie den oben angegeben Eintrag nicht mehr vorfinden. Die Anwendung
hat also jetzt keine Einträge mehr in der Datenbank vorgenommen. Starten Sie
jetzt erneut das Programm und öffnen dann das Datei-Menü.
|
Hoppla?! Im Datei-Menü ist wieder die zuletzt geöffnete Datei vorhanden.
Doch woher kommt diese Information jetzt? Nun, anstelle eine Eintrags in der Datenbank
hat die Anwendung jetzt im WINDOWS-Verzeichnis die INI-Datei DVBASIS.INI
erstellt und dort die Informationen abgelegt. Was letztendlich besser ist, ein Eintrag
in der Datenbank oder eine INI-Datei im WINDOWS-Verzeichnis , das bleibt jedem selber
überlassen. Später, bei der Behandlung der Registrierungsdatenbank und der INI-Dateien,
werden wir auf dieses Thema nochmals zurückkommen. Dort erfahren Sie auch, wie Sie
die INI-Datei im gleichen Verzeichnis wie die Anwendung anlegen können.
 |
Löschen Sie nun aus dem WINDOWS-Verzeichnis die Datei DVBASIS.INI
und fügen den Aufruf von SetRegistryKey(...) wieder zur Anwendung hinzu. |
Fahren wir mit der Analyse der InitInstance(...) Methode fort. Nach
dem Aufruf der Methode SetRegistryKey(...) wird die Methode LoadStdProfileSettings(...)
aufgerufen. Diese Methode ist, wie auch im Kommentar beschrieben, für die Ausgabe
der MRU-Liste zuständig. Wenn Sie keine MRU-Liste verwenden, und auch keine sonstigen
Einstellungen abspeichern wollen, können Sie die beiden Aufrufe von SetRegistryKey(...)
und LoadStdProfileSettings(...) aus dem Programm entfernen.
Als nächstes folgt die Definition der Dokumentenverwaltung. Die Dokumentverwaltung
wird später, nach der Behandlung der Dokumenten- und Ansichtsklasse, erläutert.
Diese Initialisierung dürfen Sie auf keinen Fall entfernen!
Die Aufrufe der beiden nachfolgenden Methoden EnableShellOpen(...) und
RegisterShellFileTypes(...) sind für die
DDE (dynamic
data
exchange) Initialisierung zuständig. Wenn Sie weder DDE
noch OLE (object
linking and
embedding) Funktionalität in der Anwendung benötigen können
Sie diese Aufrufe getrost entfernen. Die Aufruf der Methode RegisterShellFileTypes(...)
erstellt zudem ebenfalls Einträge in der Registrierungsdatenbank, durch die die
bei der Projekterstellung angegeben Dateierweiterung mit der Anwendung verknüpft
wird.
Die nachfolgenden Anweisungen, die laut Kommentar im obigen Listing nur mit Auswertung
der Kommandozeile zu tun haben, dürfen Sie aber auf keinen Fall entfernen. Hinter
den dort aufgerufenen Methoden ParseCommandLine(...) und ProcessShellCommand(...)
steckt weit mehr als nur die Verarbeitung der Kommandozeile!
 |
Kommentieren Sie im Beispiel einmal die Zeilen für die (angebliche)
Kommandozeilen-Verarbeitung wie folgt aus.
// Befehlszeile
parsen, um zu prüfen auf Standard-Umgebungsbefehle DDE, Datei offen
// CCommandLineInfo
cmdInfo;
// ParseCommandLine(cmdInfo);
// Verteilung der in der Befehlszeile angegebenen Befehle
// if (!ProcessShellCommand(cmdInfo))
// return FALSE;
// Das einzige Fenster ist initialisiert und kann jetzt angezeigt
und....
|
Übersetzen und starten Sie das Programm. Kurz nach dem Programmstart werden
Sie etwa folgende Meldung erhalten:

Wenn Sie dann den OK-Button anklicken unterbricht der Debugger die
Anwendung und zeigt Ihnen aus der Datei winocc.cpp die nachfolgende
Methode an:

Der Debugger sollte dabei auf der ASSERT-Zeile stehen. Nun, was ist hier
passiert? Sehen Sie sich einmal den Namen der Methode an, in der der Fehler
aufgetreten ist! Bemühen wir den Debugger weiter. Öffnen Sie das Aufrufliste-Fenster
(oder anders ausgedrückt, den Stack-Trace) entweder über das Symbol
,
das Ansicht-Menü oder durch Drücken der Taste <ALT>-<F7>.

Ganz oben steht die Methode (einschließlich der Parameter) in der der Fehler
aufgetreten ist, hier also die Methode ShowWindow(....). Dieser Methode
wurde durch die darunter stehende Methode InitInstance(...) des Beispiels
aufgerufen. Sie können jetzt im Aufrufliste-Fenster einen Doppelklick auf die
InitInstance(...) Methode ausführen und gelangen dann zur Aufrufstelle
von ShowWindow(...) in dieser Methode. Stellen Sie nun den Cursor über
die Variable m_pMainWnd und sehen sich deren Wert im Tooltipp an: der
Zeiger auf das Hauptfenster m_pMainWnd enthält den Wert 0, d.h. die
Anwendung besitzt kein Hauptfenster!
 |
MERKE: Bei einer durch den Assistenten generierten Anwendung wird das
Hauptfenster indirekt durch die Methode ProcessShellCommand(...)
erstellt! |
Entfernen Sie jetzt die vorher einfügten Kommentare und übersetzen und starten
das Programm wieder. Es sollte danach wieder korrekt laufen.
|
Die beiden letzten Aufruf von ShowWindow(...) und UpdateWindow(...)
in InitInstance(...) benötigen in der Zwischenzeit wohl keine weiteren
Erklärungen. Sie zeigen das Rahmenfenster an und veranlassen eine Aktualisierung
des Fensterinhalts.
Hiermit beenden wir die Behandlung der Applikationsklasse und wenden uns als
nächstes der Dokumentenklasse zu. Die Beschreibung der Fensterklasse für das Rahmenfenster
sparen wir uns. Diese Klasse enthält wirklich nichts neues.
|