Gestern hatte ich darüber berichtet, wie man der WinSxS-Hölle entkommt und eine eigene Version der C/C++-Laufzeit kompiliert. Nun kompilieren wir uns noch eine MFC ohne Manifest und können in Zukunft die C/C++-Laufzeit sowie die MFC unseren Anwendungen beilegen, ohne uns mit Manifestproblemen herumquälen zu müssen.
1. Anpassen der Dateien
Die nötigen Änderungen an den MFC-Dateien halten sich in Grenzen. Zuerst schnappen wir uns die Datei atlmfc\include\MFCassem.h und kommentieren das Manifest ab Zeile 25 bis zum Ende aus. In atlmfc\include\afx.h ersetzen wir die Zeilen 81 bis 97 durch folgende:
#ifndef _UNICODE
#ifdef _DEBUG
#pragma comment(lib, “MyMfc90d.lib”)
#pragma comment(lib, “MyMfc90sd.lib”)
#else
#pragma comment(lib, “MyMfc90.lib”)
#pragma comment(lib, “MyMfc90s.lib”)
#endif
#else
#ifdef _DEBUG
#pragma comment(lib, “MyMfc90ud.lib”)
#pragma comment(lib, “MyMfc90sud.lib”)
#else
#pragma comment(lib, “MyMfc90u.lib”)
#pragma comment(lib, “MyMfc90su.lib”)
#endif
#endif
Damit legen wir fest, dass unsere Anwendungen dynamisch gegen die MyMfc90(u).dll gelinkt werden.
2. Vorbereitung der .DEF-Dateien
In atlmfc\src\mfc\intel und atlmfc\src\mfc\intel befinden sich jeweils vier .DEF-Dateien, deren Modulnamen ebenfalls angepasst werden müssen:
mfc90.def -> MyMfc90
mfc90d.def -> MyMfc90d
mfc90u.def -> MyMfc90u
mfc90ud.def -> MyMfc90ud
Im Gegensatz zur C/C++-Laufzeit werden aber nur die Modulnamen in den .def-Dateien angepasst, die Dateinamen selbst dürfen nicht geändert werden.
3. Anpassung des Makefiles
Die Änderung in der Datei atlmfc\src\atlmfc.mak beschränkt sich darauf, die Erstellung der statischen MFC sowie der WinForms-Komponenten auszuklammern. Dazu löschen wir in Zeile 123 die Einträge MFC_STATIC und MFCM_DLL.
4. Kompilieren
Nun kopieren wir unsere bereits erstellten Batchdateien mit den Umgebungsvariablen aus dem Ordner crt in den Ordner atlmfc\src. Zusätzlich erstellen wir in diesem Verzeichnis eine Datei makemfc_x86.bat mit dem Inhalt
nmake -f atlmfc.mak MFC LIBNAME=MyMfc90 PLATFORM=INTEL MP_BUILD=1
sowie makemfc_amd64.bat mit
nmake -f atlmfc.mak MFC LIBNAME=MyMfc90 PLATFORM=AMD64 MP_BUILD=1
Anschließend öffnen wir eine Eingabeaufforderung und starten
vcvars_x86.bat
makemfc_x86.bat
sowie anschließend
vcvars_amd64.bat
makemfc_amd64.bat
Nach ein paar Minuten sollte der Compiler seine Arbeit erledigt haben und wieder das Befehlsprompt erscheinen.
5. Kopieren der Lib-Dateien
Der letzte Schritt ist das Kopieren der lib-Dateien nach atlmfc\lib, damit der Linker diese später auch findet. Die Lib-Dateien für die 32-bit Version werden bei der MFC-Erstellung in atlmfc\lib\Intel abgelegt und müssen deshalb manuell nach atlmfc\lib kopiert werden. Die Lib-Dateien für die x64-Version landen dagegen direkt im richtigen Verzeichnis (atlmfc\lib\amd64).
Die MFC-Dlls finden wir in atlmfc\src\mfc\intel bzw. atlmfc\src\mfc\amd64. Zusammen mit den Dlls der C/C++-Laufzeit sowie den jeweiligen PDB-Dateien kopieren wir sie in einen Ordner, der in die PATH-Umgebungsvariable eingetragen wird. Somit ist sichergestellt, dass Visual Studio 2008 beim Debuggen auch alle nötigen Dateien findet.
6. Kontrolle
Zur Kontrolle erstellen wir uns ein Testprojekt und prüfen, ob gegen die richtigen Dateien gelinkt wird. Dazu lassen wir uns vom AppWizard eine einfache MFC-Anwendung erstellen und kompilieren diese. Mit Hilfe der Schnellansicht von SpeedCommander lässt sich leicht ermitteln, ob die Programmdatei an die richtigen Module gebunden wurden. Wenn es so ausschaut, dann ist alles in bester Ordnung:

Die gleiche Aktion führen wir noch einmal für die MyMfc90(ud).dll durch, diese sollten ebenfalls gegen die MyVcr90(d).dll gelinkt sein.
7. Letzte Worte
Zum Abschluss sei nochmals erwähnt, dass sich diese beiden Artikel wirklich nur an den nativen Entwickler richten, der vollständigen Einfluss auf die von ihm verwendeten Komponenten hat. Dazu gehört, dass alle Fremdkomponenten im Quellcode vorliegen und somit gegen die angepasste C/C++-Laufzeit bzw. die MFC kompiliert werden können. Verwendet man dagegen zusätzliche Managed Code-Erweiterungen oder fertige Libs/Dlls, die bereits gegen die originale MsVcr90.dll gelinkt sind, dann sollte man um die manifestlose Lösung einen großen Bogen machen.