...someplace, where there isn't any trouble? Do you suppose there is such a place, Toto?

64 bit Windows - Teil 6

So, wir haben jetzt einen großen Teil technischen Zeugs hinter uns - keine Angst, wenn's um Registry Reflection oder Registry und File System Redirection geht, heben wir diesbezüglich nochmal ab. Aber vielleicht sollten wir uns jetzt auch mal die Frage der Beancounters und Suits, die in unserer Firma arbeiten und auch von unserer Software ernährt werden, stellen:

Wann braucht man überhaupt native Binaries für x64?

Gute Frage. Sind native x64 Binaries vielleicht eine Lösung für ein Problem, das sich eigentlich gar nicht stellt? Ja und nein.

Gegenfrage: Sind 16-bit Binaries eigentlich noch lauffähig auf x64 Plattformen? Das ist zwar ein orthogonales Problem, aber passt hier thematisch ganz gut.

MS hat sich bei x64 schwer angestrengt um den Übergang zu der neuen Plattform möglichst schmerzlos zu gestalten, das muß man ihnen lassen. Aber 16-bit Binaries (also MS-DOS Binaries und Win16 Binaries) laufen auf x64 Systemen nicht mehr. Punkt. Damit, ähem, endet eine 23-jährige Ära von Binärkompatibilität mit DOS. Von, naja, einer Reihe von Ausnahmen abgesehen, die zum großen Teil von einer Unart einer den Kollegen bei επτ€σ nicht ganz unbekannten Firma namens InstallShield herrührt. InstallShield hatte nämlich die unangenehme Angewohnheit, lange Zeit (ich glaube für alle 5.xer Produkte) den Bootstrapper ihrer Setups, also den setup.exe, als 16-bit Windows Applikation auszuliefern. Das führte dazu, daß alle Setups, die InstallShield in dieser Version verwendeten, unter NT erstmal zum Start einer ntvdm führten, in der dann der 16-bittige setup-stub lief, der dann wiederum einen reinrassigen Win32-Prozess startete, welcher schließlich die eigentliche Installation vornahm. Ziemlich braindamaged, das Ganze, aber es gab dafür sicher einen Grund. Ganz bestimmt. Drum werden auf x64 Windows auch solche setups ausgeführt - obwohl sie 16-bittig sind - jedoch anders als man denkt: Der Programmlader erkennt ein derartiges setup.exe und führt stattdessen ein 32-bittiges setup aus, das von MS und InstallShield entwickelt wurde und mit dem OS mitshippt.

Aber jetzt zur Gretchenfrage: Wann braucht man unbedingt native x64 Binaries und kann nicht mit 32-bittigen Binaries auskommen, wann muß man also wirklich portieren?

Gretchenantwort: In der Regel laufen x86 binaries für 32-bit Windows unverändert und ohne Probleme auf x64. Sogar der Service Control Manager auf einem x64-System weiß mit 32-bittigen Services umzugehen, was mich während der Beta von XP x64 Edition am allermeisten erstaunt hat. Daher bleiben also für mich jetzt erstmal nur vier Kategorien von Softwareprodukten, die für x64 native übersetzt werden müssen:

  • Software, die unmittelbar von den Goodies von x64 profitieren will, beispielsweise dem größeren Adreßraum
  • Treiber: Kernel-Mode Code muß native vorliegen, um auf x64 zur Ausführung kommen zu können
  • Plugins für System Binaries wie Shell Extensions, ISAPI extensions (?)
  • Hook-DLLs für User mode processes

Die letzten drei Kategorien lassen sich auf ein fundamentales Problem zurückführen: Ein nativer x64 Prozeß kann keine 32-bittigen x86-DLLs laden (es sei denn es sind resource-only DLLs) und umgekehrt. All dieser Schmuh mit step-up-thunks von Win16 nach Win32 und die step-down-thunks von Win32 nach Win16, die es früher so gab als WinNT, Windows9x und Windows 3.x nebeneinander her sehr verbreitet waren, gibt es nicht unter x64. Puh, eine Sorge weniger!

Natürlich ist es auch so, daß alle DLLs, die ein portiertes Binary nachlädt, auch entsprechend native übersetzt sein müssen. Das bedeutet: Wen man eine Shell Extension oder eine Hook-DLL portiert hat, muß man natürlich auch all die Binaries noch portieren, die dieses Binary so der Reihe nach nachlädt.

Generell läßt sich aber als Fazit festhalten: Win32 Binaries für x86 Plattformen sollten von Ausnahmen abgesehen allesamt laufen. Muß man für ein Produkt native x64 Binaries erzeugen, so ist ein Mischbetrieb von x86 Binaries und x64 Binaries für *ein komplettes Produkt* durchaus möglich. Das soll heißen: Teile eines Produktes können durchaus x86 Binaries sein und nur diejenigen Teile müssen neu und native übersetzt sein, die wirklich native sein müssen.

(Edited: Fixed Typos)

64 bit Windows - Teil 5

Weiter geht's! In diesem Teil der Serie will ich darauf eingehen, was es mit meiner anfänglichen Zurückhaltung auf sich hat, was den Einsatz von MFC auf x64 angeht. Ich will außerdem ein Wort über Visual Studio 6 auf x64 verlieren und was über's Debuggen von nativen x64-Anwendungen erzählen.

Doch zu aller erst ein Zitat von Mark Russinovich aus seinem vorletzten Blog Posting was die Zukunft des IA64 angeht:

"...you might have noticed that there?s little support for Itanium, which reflects my belief, and I think that of others, including Microsoft and Dell, that Itanium has a limited future, one only guaranteed so long as there are no 64-way Opteron systems."

OK, jetzt zu dem MFC für x64: Die gute Nachricht ist ja, wie bereits erwähnt, daß mit dem allerneuesten PlatSDK vom Mai 2005 auch MFC libraries shippen, die man auch genauso wie im letzten Beitrag dieser Serie beschrieben, benutzen kann, um auch MFC-Applikationen zu übersetzen. Diese funktionieren auch exakt so wie erwartet, bis auf den ....., tja, hüstel, ... Shared MFC Debug Build und zwar in der ANSI wie in der Unicode-Variante. Wenn man in dieser Buildumgebung Binaries buildet, so erhält man zwar keinen Fehler während des Builds, aber die Binaries laufen schlicht und einfach nicht, sie werden mit einer Fehlermeldung gleich während der Initialisierung beendet. Das gilt sowohl für exe files wie auch für DLLs die man mit diesen beiden Targets buildet. Will man einen shared debug build mit MFC auf x64, bleibt einem daher nichts anderes übrig, als von MS die shared libs für MFC Version 7.1 anzufordern, so wie sie in einer x86-Version mit Visual Studio 2003 mitkommen. Wie das geht, ist beschrieben im KB-Artikel
875446 "How to obtain the 64-bit version of the Visual C++ 7.1 libraries and build tools"
. Im Prinzip muß man eine Emailadresse bei MS anschreiben und zum Ausdruck bringen, daß man gerne die 7.1er MFC libs für x64 hätte. Dann erhält man Post von denen zurück und muß ein paar Fragen beantworten und eine EULA abnicken. Als nächstes muß man einen ftp-Zugang stellen, wo dann die Kontaktperson bei MS die libs ("SDKAMD64") draufkopiert. Ja, und man darf IIRC keine Produkte shippen die mit diesen libs gemacht wurden.

Wenn man also MFC Code hat, der anders als der von επτ€σ so programmiert ist, daß er mit jeder MFC-Version funktioniert, nicht nur mit der aus VC6, dann kann man für seine Shared MFC Debug Builds einfach die Suchpfade so umstellen, so daß sie auf das SDKAMD64 zeigen.

So und jetzt zum Debuggen. Der in VC6 integrierte Debugger ist ein x86-Debugger und der kann natürlich auf einer x64-Umgebung überhaupt nicht verwendet werden. Glücklicherweise kommen aber mit dem PlatSDK vom Mai 2005 eine aktualisierte Version der Debugging Tools for Windows mit, und damit der WinDbg (sprich: "Wind-Bag") für x64. Mit dem läßt sich sehr komfortabel alles Debuggen, was man an x64 Binaries so erzeugen kann, so daß eigentlich nur der Wechel der Tools ein bißchen lästig ist. Um den Code zu schreiben und zu übersetzen, setzt man also Visual Studio 6 ein, um zu Debuggen nimmt man dann den WinDbg. Was aber wirklich doof ist an der Situation, ist daß man den Debugger von VC6 auch nicht mehr richtig zum Debuggen vonn x86-Prozessen auf einer x64-Maschine verwenden kann, denn sobald man aus dem Debugger heraus seinen Debuggee beendet, der Prozeß sich also nicht selbst beendet hat, lebt der Debuggee als Zombieprozeß weiter. Das sieht zwar erstmal nicht schlimm aus, aber weil der Prozeß weiterlebt, hat man Probleme, wenn man einfach nur im Code des Debuggee was ändern weill und ihn dann neu übersetzen will, denn man kann ja die exe oder DLL nicht überschreiben. Und weil man den Debuggee nur beenden kann, indem man seinen Elternprozeß (also msdev.exe) beendet, muß man devstudio beenden und neu starten, um das Binary des Debuggees neu zu erzeugen. Ziemlich lästig ist das. Ich denke, wenn man auf einer x64-Maschine VC6 benützen will um x86 Binaries zu entwickeln, testen und debuggen, so sollte man das in einer VMWare Session tun tun, die auf dem x64-Host läuft.

So, was ich beim nächsten Mal schreibe muß ich erst noch rausfinden. Folgende Themen sind noch zu beackern:

  • Datentypen auf x64
  • Wann braucht man überhaupt native Binaries für x64?
  • Die Sache mit der File System Redirection und der Registry Redirection
  • Häufig gemachte Fehler bei x64 Ports

Inci beim Fußballkucken

Hier ist Inci beim Fußballkucken. Ich finde, sie hätte sich dafür nicht so aufbrezeln müssen...

"Hacking" the Starteam Client

Bei Starteam hat mich in dem Client schon immer aufgeregt, daß man einen "Compare Contents" (anderswo auch "Diff" genannt) immer nur über die Maus machen kann, sei es mit einem Klick auf einen Toolbarbutton oder mit einem Kontextmenüitem nach einem rechten Mausklick. Andere Clients von Versionskontrollsystemen wie etwa WinCVS bieten hier eine Schnelltaste ("Accelerator"), beispielsweise Ctrl-D. Nach einer Umfrage per Email unter meinen Kollegen, die leider keinen Hinweis ergab, ob sich dieses Verhalten irgendwie customizen liesse, habe ich mir kurz Gedanken gemacht, ob man das irgendwie von außen ändern könnte. Meine ersten Ideen waren erstmal höllisch kompliziert, wie etwa einen Messagehook oder einen Low-Level Keyboard-Hook, aber das ist ja alles Mist und viel zu aufwendig. Viel einfacher ist es, das Binary zu patchen und das Ganze ist in nicht mal 5 Minuten mit einem installierten VS6 erledigt.

Zunächst mal muss man sich darüber im klaren sein, daß Starteam.exe eine reinrassige MFC-Applikation ist. Das erkennt man mit Spyxx an den Fensterklassennamen der Applikation, die alle irgendwie mit Afx... beginnen. Und in MFC-Applikationen ist klar, daß ein Klick auf einen Toolbarbutton, ebenso wie die Auswahl aus einem Kontextmenü letztlich in der Message WM_COMMAND münden. Fraglich ist nur, welche ID dabei mitgeschickt wird. Aber zu dem Zweck gibt es ja den Spyxx. Dort wählt man bei einer geöffneten Starteam-View das zugehörige MDI Child Window aus und selektiert als zu überwachende Message den WM_COMMAND. Dann wählt man einmal den "Compare Contents" für ein File in Starteam aus. Spyxx zeigt einem dann Folgendes an:

Man erkennt also, daß für "Compare Contents" die ID 41059 mitgeschickt wird. Nun macht man sich am Besten eine Kopie von starteam.exe, bespielsweise als _starteam.exe. Diese Datei öffnet man jetzt in Visual Studio, aber als Ressource. Man erhält dann eine Übersicht der Ressourcen, die etwa folgendermaßen ausschaut:

Hier sind die Accelerator Tables ausgeklappt und man erkennt, daß es davon 4 Stück gibt. Ich bescheiße jetzt mal ein bißchen und behaupte, wir müssen diejenige mit der ID 15002 auswählen. Diese wählen wir an und klicken in die leere Fläche für den nächsten neuen Eintrag. Es öffnet sich dann ein Dialog, den wir wie folgt ausfüllen:

Um die Eingaben zu übernehmen klicken wir einfach neben den Dialog und dann schaut die Accelerator-Table etwa so aus:

Nun beenden wir msdev.exe und bejahen die Frage, ob die Veränderungen gespeichert werden. Voilá, ab jetzt wird mit Ctr-D der Differ gestartet, weil natürlich die Messageloop in den MFC eine klassische TranslateAccelerator-TranslateMessage/DispatchMessage-Loop ist, wie etwa folgender Code:

  while( GetMessage(&msg, NULL, 0, 0) ) 
  {
    if( !TranslateAccelerator (msg.hwnd, hAccelTable, &msg) ) 
    {
      TranslateMessage( &msg );
      DispatchMessage( &msg );
    }
  }

Das bedeutet schlicht und einfach, daß Accelerator-Aufrufe durch TranslateAccelerator in Messages vom Typ WM_COMMAND mit der ID des Accelerators umgewandelt werden. Praktisch, oder?

Die einzige Kröte, die man jetzt noch schlucken muß ist der Umstand, daß das List-Control von Starteam immer den Fokus verliert wenn man zwischen Prozessen hin- und herswitcht. Aber immerhin kann man jetzt beispielsweise die rechte Hand immer an der Maus zum Klicken lassen und muß nicht immer hin- und herutschen, und mit der linken Hand kann man auf dem Keyboard Ctrl-D und Alt-F4 bedienen fuer den Aufruf und das Beenden des Differs.

64 bit Windows - Teil 4

Bevor jemand auf die Idee kommt, daß die Serie über 64-bit Windows schon beendet ist, geht's nun weiter. Wir wissen bereits, daß die einzige Hardwareplattform für x64, die mittelfristig weitere Verbreitung finden wird, die AMD64/EM64T-Plattform ist und nicht IA64. Weiterhin wissen wir, daß man aus der Kombination mit aktuellem PlatSDK (das Windows 2003 SP1 PlatSDK) und VC6 eine Entwicklungsumgebung zustande bringt. Was wir noch nicht wissen, ist, was man ändern muß um auch einen sauberen Build für x64 hinzukriegen. Und darum geht es in dieser Folge.

Wir fangen an, indem wir erstmal mit dem Projektwizard aus VC6 ein Projekt erzeugen. VC6 starten wir dazu nicht bereits jetzt wie in der letzten Folge beschrieben aus einer PlatSDK Buildkonsole, sondern starten msdev "ganz normaaaaal" (Roy Makaay) aus dem Startmenü. Wir nehmen auch erstmal kein MFC-Projekt, sondern ein Projekt vom Typ "Win32 Application". Als Untertyp wählenden wir "A typical "Hello World!" application". Was eine typische Hello-World-Application ist, hat sich mir zwar bis zum heutigen Tag noch nicht vollständig erschlossen, aber wie sie ausschaut ist klar: Eine Applikation mit GUI, Messageloop und indirektem (event-driven) Zeichnen in der Client-Area des Applikationsfensters, dazu ein Menü, über das die Applikation beendet werden kann oder eine modale Dialogbox angezeigt werden kann. Wir erzeugen also das Projekt und übersetzen es einmal im Win32 Debug Build, um sicherzugehen, daß das Projekt auch wirklich einwandfrei buildet. Nun beenden wir msdev wieder.

Jetzt starten wir eine PlatSDK Buildconsole. Zu diesem Zweck wählen wir aus dem Startmenü den Eintrag "Microsoft Platform SDK for Windows Server 2003 SP1" -
"Open Build Environment Window" -
"Windows XP 64-bit Build Environment" -
"Set Windows XP x64 Build Environment (Debug)"
worauf sich eine Konsole öffnet. Von hier aus starten wir msdev.exe mit dem Kommandozeilenparameter /useenv. Da drin checken wir zur Sicherheit nochmal ab, ob auch wirklich die korrekten Pfade verwendet werden. Wir wählen zu dem Zweck den Menüpunkt "Tools" - "Options" aus. Der sechste Tab in diesem Property Sheet heißt "Directories". Wenn hier für "Include files" und für "Library files" Pfade aus dem PlatSDK drin stehen, dann paßt alles.

Als erstes fügen wir nun erstmal einmal neue Buildtargets hinzu. Unter "Build" - "Configurations..." fügen wir ein Target "x64 Debug", ausgehend vom Debug Build, und ein Target "x64 Release", ausgehend vom Release Build, hinzu. Dann wechseln wir zum Target "Win32 x64 Debug" und öffnen für unser Projekt die "Project Settings". Unter C/C++ ändern wir erstmal unter "General" die Debug Info von "Program Database for Edit and Contimue" ab auf "Program Database". Als nächstes gehen wir auf die Kategorie "Code Generation" und wählen statt einer single-threaded runtime eine multithreaded runtime. Dann gehen wir in das mehrzeilige Editfeld mit dem Label "Project Options" und editieren. Ja, da drin darf man auch editieren. Wir schmeißen die Option /GX und /GZ raus und ergänzen stattdessen die Optionen /EHsc und /Wp64. Nun gehen wir auf den Linker Tab und die Kategorie "Debug". Dort entfernen wir das Häkchen bei "Separate Types". Schlußendlich gehen wir auch hier in das mehrzeilige Editfeld "Project Options" und ergänzen am Ende (wichtig: AM ENDE!) /machine:AMD64. Nun machen wir einen "Rebuild All" für dieses Target. Wir werden zwei Compilerwarnungen erhalten und Gazillionen von Linkerfehlern vom Typ "unresolved external symbol __security_cookie". Um den Linkerfehler zu beseitigen müssen wir nämlich noch eine lib ergänzen, die man unter x64 praktisch immer für die C-runtme braucht. Zu dem Zweck gehen wir wieder auf die Project Settings und ergänzen im Link-Tab unter der Kategorie "Input" im Feld "Object/library modules" die library bufferoverflowu.lib. Die beiden Warnungen kriegen wir mit einfachen casts zu int weg, sie rühren daher, dass ein WPARAM keine 32-bit mehr breit ist wie ein int und dass strlen einen size_t zurückliefert, der auch keine 32-bit mehr breit ist. All diese Schritte können wir nun auch für den x64 Releasebuild ausführen. Wer bis jetzt gut aufgepaßt hat, wird feststellen, daß ich bisher noch nichts drüber geschrieben habe, daß wir eigentlich auch eine x64-Maschine zum Entwickeln brauchen. Und in der Tat, alles bisher läßt sich auf einer normalen x86-Umgebung durchführen, weil die x64-Compiler des PlatSDKs Cross-Compiler sind und eigentlich x86-Binaries. Aber wenn wir nun einmal unser Binary ausführen oder debuggen wollen, brauchen wir natürlich spätestens jetzt eine Kiste auf der die x64 Edition von XP oder dem W2K3 Server läuft. So, das nächste Mal schauen wir uns an, was es damit auf sich hat, daß ich erstmal kein MFC-Projekt machen wollte und wir schauen uns die Situation an, wo wir VC6 auf einer x64-Edition von XP/W2K3 Server ausführen und unser Binary auf dieser Plattform debuggen wollen.

<< 1 ... 37 38 39 40 41 42 43 44 45 46 47 >>