Menü

Ratgeber: "Programmentwicklung" Mit Visual Studio 32- und 64-Bit-Projekte erstellen

Immer mehr Rechner werden mit 64-Bit-Prozessoren und einem 64-Bit-Windows- Betriebssystem ausgeliefert. Mit Visual Studio 2010 und Visual Basic entwickeln Sie nach Bedarf Anwendungen und Komponenten in 64- und 32-Bit-Varianten. Dabei sind spezielle Konfigurationen zu berücksichtigen.

Mit Visual Studio 32- und 64-Bit-Projekte erstellen
vergrößern
© Hersteller/Archiv

Visual Studio konfigurieren

In der Visual-Studio-Entwicklungsumgebung legen Sie den CPU-Typ für Ihr Programmier-Projekt fest: zum Beispiel x64 für 64Bit-Programme.
vergrößern
© Hersteller/Archiv
In der Visual-Studio-Entwicklungsumgebung legen Sie den CPU-Typ für Ihr Programmier-Projekt fest: zum Beispiel x64 für 64Bit-Programme.

Für jedes Projekt können Sie über Visual Studio gezielt festlegen, welche Prozessorplattformen es unterstützen soll. Nutzen Sie dazu die Registerseite Kompilieren, wählen Sie dort die Schaltfläche Erweiterte Kompilieroptionen an und setzen Sie im nachfolgenden Dialog über das Kombinationslistenfeld Ziel-CPU den Eintrag auf AnyCPU, wenn Sie eine Komponente sowohl für 32-(x86) als auch 64-Bit-Umgebungen (Itanium, x64) verfügbar machen wollen.

Die Komponenten können Sie dann auch über COM-Klassen, 32-Bit-Komponenten oder Steuerelemente (ActiveX, Assemblies) einbinden und für 64-Bit-Anwendungen verfügbar machen. Programme, die mit dieser Einstellung übersetzt werden, sind auf allen Plattformen sofort lauffähig.

x64 nutzen Sie dagegen, wenn eine Anwendung oder Komponente ausschließlich in 64-Bit-Umgebungen mit Intel-Prozessoren nutzbar sein soll. 64-Bit-Anwendungen greifen dann auf die 64-Bit-Variante des .NET Framework zurück. Itanium lautet hingegen der Eintrag, wenn eine Anwendung oder Komponente ausschließlich in 64-Bit-Umgebungen mit Itanium-Prozessor nutzbar sein soll.

Und schließlich ist x86 die richtige Wahl, wenn eine Anwendung oder Komponente nur auf x86-Prozessoren (32-Bit) ausführbar sein soll. 32-Bit-Anwendungen sind unter 32- und 64-Bit-Systemumgebungen unter Verwendung der 32-Bit-Variante des .NET Framework ausführbar. In 64-Bit-Systemen erfolgt die Ausführung über WOW64. Visual Studio 2010 selbst liegt als 32-Bit-Programm vor und richtet sich dementsprechend standardmäßig im Programmverzeichnis C:\Programme (x86) ein. Die Ausführung erfolgt über WOW64.

32-Bit-Komponenten und -Verweise

Es ist nicht zulässig, einzelne Prozesse aus 32- und 64-Bit-Komponenten zu mischen, hier also 64-Bit-Anwendungen mit echten 32-Bit-DLLs oder 32-Bit-Assemblies. Können Sie aufgrund des fehlenden Quelltextes eine 32-Bit-Komponente nicht in eine 64-Bit-Komponente überführen, dann können Sie sich einen COM-Wrapper schreiben. Es wird keine 32- und 64-Bit-Interoperabilität zwischen Prozessen unterstützt. Dies hat zur Folge: In-Process-Server, also COM-Server, die im gleichen Adressraum wie die Hauptanwendung laufen, sind mit 64-Bit-Anwendungen nicht direkt nutzbar.

Anders sieht es hingegen bei Out-Process-Servern aus, die unabhängig von der Hauptanwendung in einem eigenen Adressraum ausgeführt werden (exe-Programmdatei). Diese sind auch in der 32-Bit-Variante in 64-Bit-Anwendungen einsetzbar. .NET-Klassenbibliotheken lassen sich, anders als echte DLLs und COM-Komponenten, flexibel in 32- und 64-Bit-Umgebungen nutzen, indem Sie wie bereits beschrieben die Zielplattform mit AnyCPU angeben.

Zunächst zeigen wir Ihnen, wie die Definition einer einfachen 32-Bit-Klassenbibliothek den Zielprozessor für die Hauptanwendung einschränkt. In der Beispielanwendung 32BitApp wird neben der Hauptanwendung Demo64Bit eine gesonderte Klassenbibliothek Class32 definiert. Die Ziel-CPU für diese Klassenbibliothek wird, wie eingangs beschrieben, auf x86 gesetzt.

Die Klassenbibliothek macht die Klasse DialogClass mit der Methode GetFile verfügbar, über die eine Datei in einem benutzerdefinierten Dateiauswahldialog ausgewählt und abgefragt werden kann. Der Dialog selbst nutzt die Laufwerks-, Verzeichnis- und Dateilistenfelder der VB6-Kompatibilitätsobjekte, die ihrerseits ausschließlich als 32-Bit-Varianten verfügbar sind.

Die Methode GetFile instanziert zunächst das Formular mit dem Namen FileSelect und zeigt es modal an. Bestätigen Sie die Dateiauswahl mit OK, wird der Dateiname samt Suchpfad an das aufrufende Programm zurückgeliefert.

Public Class DialogClass Public Function GetFile() As String Dim frm As New FileSelect If frm.ShowDialog = Windows.Forms. DialogResult.OK Then Return frm.FileCtl.Path & "\" & frm. FileCtl.FileName Else Return Nothing End If End Function

Die Klassenbibliothek wird per Verweis in die Hauptanwendung Demo64Bit eingebunden. Sowohl das Hauptprogramm als auch die Klassenbibliothek werden in einer Projektgruppe nebeneinander in Visual Studio verwaltet, wobei die Hauptanwendung als Startprojekt festgelegt ist. Um den Verweis zur 32-Bit-Klasse in die Hauptanwendung aufzunehmen, wählen Sie zur Hauptanwendung den Kontextmenübefehl Verweis hinzufügen an, wechseln im folgenden Dialog auf die Registerseite Projekte und wählen das Projekt Class32 aus.

Klicken Sie im Hauptprogramm die Schaltfläche 32-Bit-Klasse an, wird die Klasse Class32.DialogClass über die Ereignisprozedur btnClass_Click angebunden. Zunächst wird die Klasse via New neu instanziiert und der zugehörige Verweis in der Objektvariablen classObj gesichert.

Anschließend wird über den Objektverweis die Methode GetFile aufgerufen, die ihrerseits den vordefinierten 32-Bit-Dateiauswahldialog einblendet und die gewählte Datei samt Suchpfad zurückgibt. Dieses Ergebnis wird über die Anweisung MsgBox in einem einfachen Meldungsdialog ausgegeben.

Private Sub btnClass_Click(...)Handles btnClass.Click Try Dim classObj As New Class32.Dialog Class MsgBox(classObj.GetFile(), MsgBoxSty le.Information + MsgBoxStyle.OkOnly,"Dateiwahl") Catch ex As Exception MsgBox(ex.Message,MsgBoxStyle.Criti cal, "Fehler") End Try End Sub

An dieser Stelle ist die Ziel-CPU auch für die Hauptanwendung auf x86 gesetzt und die Programmausführung ist dementsprechend fehlerfrei. Lediglich Warnhinweise zu den Dateisystemsteuerelementen weisen darauf hin, dass Sie veraltete Komponenten verwenden. Für die 32-Bit-Anwendung ist dies unproblematisch.

Versuchen Sie, die Ziel-CPU der Hauptanwendung jedoch auf x64 zu ändern, lässt sich das Programm nicht mehr ausführen. Die 32-Bit-Klasse kann in der 64-Bit-Anwendung nicht mehr genutzt werden.

COM-Klassen für 64-Bit-Anwendungen

32-Bit-Komponenten sind nur in 32-Bit-Anwendungen nutzbar. Andernfalls erhalten Sie eine Fehlermeldung. © Hersteller/Archiv
32-Bit-Komponenten sind nur in 32-Bit-Anwendungen nutzbar. Andernfalls erhalten Sie eine Fehlermeldung.

Um 32-Bit-Klassen in einer 64-Bit-Anwendung zu nutzen, sind diese per COM-Wrapper verfügbar zu machen, wie nachfolgend an der Klasse Class32 gezeigt wird.

COM-Wrapper müssen als Out-Process-Server kodiert sein. Sie haben dementsprechend das exe-Dateiformat und werden in einem eigenen Adressraum ausgeführt. Die 32-Bit-Funktionalität, die Sie bereitstellen wollen, nehmen Sie in dem Projekt in eine COM-Klasse auf. Unser Beispielprojekt heißt Prog32 und wird in einer Projektgruppe zusammen mit der Hauptanwendung Demo64Bit verwaltet. Die COM-Klasse legen Sie über den Kontextmenübefehl Hinzufügen/Neues Element und Anwahl der Projektvorlage COM-Klasse an.

Im Beispielprogramm 64BitApp mit 32-Komponente wird der Klassenname auf ComClassFileSelect gesetzt. Der Klassentyp sorgt dafür, dass automatisch COM-GUIDs (GUID = Globally Unique Identifier) generiert und mit der Klasse verknüpft werden. Diese Informationen werden in der Systemregistrierung abgelegt und erlauben die spätere Objektanlage beispielsweise über die COM-Anweisung CreateObject oder eine direkte Instanziierung via New.

<ComClass(ComClassFileSelect.ClassId, ComClassFileSelect.InterfaceId, ComClassFileSelect.EventsId)> Public Class ComClassFileSelect #Region "COM-GUIDs" Public Const ClassId As String = "e7aa7583-fe5d-4a93-a663-f8324be52366" Public Const InterfaceId As String = "08b31858-6423-4f4d-b8a0-8b7c3ac43173" Public Const EventsId As String = "2ddd36d2-6b21-4bab-898d-b755de8a59a3" +End Region ... End Class

Die COM-Klasse selbst muss für die spätere Instanzierung die Methode New definieren.

Die Methode GetFile ist in der Klasse ComClassFileSelect angelehnt an die gleichnamige Methode der 32-Bit-Klassenbibliothek definiert. Über die Methode wird erneut eine Datei per Dateiauswahldialog ausgewählt und abgefragt, wobei erneut der Dialog FileSelect mit den 32-Bit-Dateisystemsteuerelementen zum Einsatz kommt. Der Dialog wird via New instanziiert, modal angezeigt und nach Übernahme des Ergebniswertes via Close geschlossen. Das Ergebnis wird im Zeichenkettenformat an das aufrufende Programm übergeben.

Um die Anwendung Prog32 mit der integrierten COM-Klasse in einer 64-Bit-Anwendung nutzen zu können, müssen Sie die Ziel-CPU auf AnyCPU setzen, das Programm übersetzen und dann in der Hauptanwendung Demo64Bit einen Verweis auf die Programmdatei ergänzen. Nach der Verweiserstellung legen Sie über F2 die Schnittstelle der angebundenen 32-Bit-Anwendung mitsamt der internen COM-Klasse im Objektkatalog offen.

Für das Hauptprogramm legen Sie die Ziel-CPU mit x64 fest. Wählen Sie im Hauptprogramm die Schaltfläche 32-Bit-Programm an, wird die COM-Klasse Prog32.ComClassFileSelect über die Ereignisprozedur btnProg32_Click und das Schlüsselwort New neu instanziert und der zugehörige Verweis in der Objektvariablen oApp gesichert.

Anschließend wird über den Objektverweis die Methode GetFile aufgerufen. Das Ergebnis wird erneut über die Anweisung MsgBox in einem einfachen Meldungsdialog ausgegeben. Anschließend wird die Objektvariable auf Nothing gesetzt und der der Garbage Collector (GC) mit dem Aufräumen beauftragt.

Private Sub btnProg32_Click(...)Handles btnProg32.Click Try "COM-Klasse (32-Bit) objektspezifisch laden (COM-Verweis erforderlich) Dim oApp As New Prog32.ComClassFile Select ,Methode aufrufen Dim fName As String = oApp.GetFile() MsgBox(fName, MsgBoxStyle.Information + MsgBoxStyle.OkOnly, "Dateiwahl") oApp = Nothing GC.Collect() Catch ex As Exception MsgBox(ex.Message, MsgBoxStyle.Criti cal, "Fehler") End Try End Su

Damit ist die 64-Bit-Hauptanwendung kodiert, die ihrerseits die 32-Bit-COM-Klasse mitsamt den untergeordneten 32-Bit-Steuerelementen fehlerfrei verwenden kann. Damit Dialoge korrekt überlagert werden, ist in der COM-Klasse der Dialog zur Dateiauswahl als oberstes Fenster definiert (Topmost = True).

Geschwindigkeitsoptimierung

Anbindung einer 32-Bit-Klasse per Verweis (COM-Klasse und WMI).
vergrößern
© Hersteller/Archiv
Anbindung einer 32-Bit-Klasse per Verweis (COM-Klasse und WMI).

Bleibt abschließend zu betrachten, wie Sie Systemaufrufe anhand von API-Deklarationen optimieren. Grundlage dafür sind die mit Windows 7 eingeführten Änderungen in der Systemarchitektur. Im Windows-Systemverzeichnis finden Sie eine Vielzahl neuer DLLs, die am Präfix API-MS-WIN erkennbar sind. Die Dateien selbst weisen geringe Größen auf und exportieren lediglich bereits bekannte API-Funktionen.

Mit dem Dependency Walker legen Sie die exportierten API-Funktionen und auch Abhängigkeiten zwischen Modulen offen. Starten Sie dazu einfach das Programm und übernehmen Sie die zu analysierende DLL per Drag & Drop in das Analyse-Tool. Die Datei api-mswin-core-file-11-1-0-dll exportiert beispielsweise die grundlegenden API-Funktionen zu den Dateioperationen.

Laden Sie aus Vista bekannte DLLs in den Dependency Walker, dann sehen Sie, dass die neuen DLLs statisch an die alten System-DLLs gebunden sind. In diesem Zusammenhang taucht auch die neue Systemdatei kernelbase.dll auf. Viele Kernfunktionen haben in älteren Windows-Systemen API-Aufrufe direkt an ntdll.dll abgesetzt. Unter Windows 7 ist hingegen die neue kernelbase.dll dazwischen geschaltet. Die DLLs sind leer ohne eigentliche Funktion. Sie werden nach Bedarf mit geringem Speicherverbrauch geladen.

Während der API-Aufrufe werden dann die API-Funktionen durch die tatsächlichen API-Aufrufe ersetzt. Ziel der Änderungen ist ein schnelleres Ausführen und Laden von Anwendungen und deren Bibliotheken, ohne dass das Auswirkungen auf die API-Funktionen selbst hat. Wie Sie die ASPI-Funktion wahlweise per Stub File oder direkt aufrufen, soll an dieser Stelle praktisch gezeigt werden. Prinzipiell spielt es keine Rolle, ob Sie DLL-Funktionen wie gewohnt oder aber über die neuen kompakteren DLLs und entsprechend angepasste Deklarationsanweisungen aufrufen.

Wie Sie die API-Funktion deklarieren, zeigen die nachfolgenden Deklarationsanweisungen. Die API-Stub-File-DLL (Ersatzdatei) ist anders als bei der herkömmlichen Deklaration nicht mehr direkt an die Datei kernel32.exe gebunden. Um beide Deklarationen parallel zu definieren, sind die Aufrufnamen mit GetWindowsDirectory und GetWindowsDirectoryStubFile unterschiedlich benannt.

,alte Deklaration:: Declare Function GetWindowsDirectory Lib "kernel32" Alias "GetWindowsDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Integer) As Integer "alternative Deklaration über Stub File: Declare Function GetWindowsDirectoryBy StubFile Lib "api-ms-win-core-sysinfo-l1-1-0.dll" Alias "GetWindowsDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Integer) As Integer

So sieht die Herstellung des COM-Verweises aus (COM-Klasse und WMI).
vergrößern
© Hersteller/Archiv
So sieht die Herstellung des COM-Verweises aus (COM-Klasse und WMI).

Die benutzerdefinierte Funktion WinDir ermittelt korrekten Verzeichnisnamen, wobei Sie über den Optionalparameter OldCalling (Standard True) frei festlegen, ob die alte oder neue Aufrufsyntax verwendet werden soll. Nutzen Sie die neue Aufrufsyntax (OldCalling = False), dann erzielen Sie für Ihre Anwendung das gleiche Ladeverhalten, das auch in den System-DLLs selbst zum Einsatz kommt. Nach außen hin macht es unter Windows 7 und höher keinen Unterschied, welche Deklarationsanweisung Sie verwenden.

Da die Umleitung der DLL-Aufrufe allerdings über Dateien erfolgt, die in älteren Windows-Systemen nicht verfügbar sind, lassen sich so geänderte Anwendungen auch ausschließlich unter Windows 7 oder höher ausführen, auch wenn diese Systemfunktionen in den älteren Windows-Systemen dennoch verfügbar sind. Sie müssen also genau abwägen, unter welchen Systemen eine Programmausführung später gewünscht ist. Prinzipiell sollten Sie aus Kompatibilitätsgründen bevorzugt mit den bekannten, alten Deklarationen die erforderlichen API-Aufrufe vornehmen.

Function WinDirectory(Optional OldCal ling As Boolean = True) As String Dim Buffer As String = Space(255) Dim gcLen As Integer = Len(Buffer) Dim aLen As Integer If OldCalling Then aLen = GetWindowsDirectory(Buffer, gcLen) Else aLen = GetWindowsDirectoryByStubFile (Buffer, gcLen) End If Return Buffer.Substring(0, aLen) End Function

Wählen Sie im Beispielprogramm die Schaltfläche ohne Stub Files an, wird das Windows-Verzeichnis in der bewährten Variante ermittelt und über einen Meldungsdialog angezeigt.

Private Sub btnNormalDeclaration_ Click(...)Handles btnNormalDeclaration.Click MsgBox(obj.WinDirectory(), MsgBoxSty le.Information, "Windows-Verzeichnis (herkoemmliche Deklaration)") End Sub

Den Aufruf in der neuen Variante zeigt die Ereignisprozedur, die nach Anwahl der Schaltfläche Stub Files ausgeführt wird. In Anwendungen können Sie die Ausführung später auch systemspezifisch anhand der abgefragten Versionsinformationen des Systems automatisch variieren und entsprechend dem aktuellen System unterschiedlich abrufen.

Private Sub btnStubFileDeclaration_ Click(..) Handles btnStubFileDeclaration.Click MsgBox(obj.WinDirectory(False), Msg BoxStyle.Information, "Windows-Verzeichnis (Stub File)") End Sub

Damit sind Sie für den Umstieg gewappnet und portieren Ihre bestehenden 32-Bit-Anwendungen Schritt für Schritt in die neue, schöne 64-Bit-Welt.

Plattform und Entwicklung von 64-Bit-Anwendunge

Alle Anwendungen, die mit dem .NET Framework 1.0 oder 1.1 entwickelt werden, sind 32-Bit-Anwendungen. 64-Bit-Anwendungen werden erst mit .NET 2.0 und höher unterstützt. Dazu wird eine Common Language Runtime (CLR) in gesonderten 32- und 64-Bit-Varianten bereitgestellt, wobei die letztgenannte Variante nur in 64-Bit-Systemumgebungen installiert wird.

Damit sich API-Aufrufe in 32- und 64-Bit-Anwendungen identisch verhalten, müssen Ganzzahlzeiger nicht als In32 oder Integer, sondern explizit als IntPtr (Ganzzahlzeiger) deklariert werden. Verzichten Sie darauf, erhalten Sie in 64-Bit-Anwendungen keine Ergebnisse zurückgeliefert.

  • .NE T 2.0 und höher

Erzeugen Sie eine .NET-Anwendung auf einem Computer mit 32-Bit- oder 64-Bit-System mit einer Framework-Version größer 2.0, so wird diese immer als systemeigene Anwendung ausgeführt. Auch in der 64-Bit-Systemumgebung erfolgt die Programmausführung, also ohne das Subsystem WOW64.

Mit dem Dienstprogramm corflags.exe, das Bestandteil des .NET Framework SDK 2.0 und höher ist und das Sie über die SDK-Eingabeaufforderung starten, legen Sie optional fest, ob ein Assembly des Typs exe oder dll für die Ausführung unter einer bestimmten Plattform vorgesehen ist. Mit dem Tool erreichen Sie ferner, dass .NET-Anwendungen über WOW64 ausgeführt werden. Standardmäßig erhalten mit Visual Studio 2005/2008 übersetzte Anwendungen die Hauptversionsnummer 2 und die Nebenversionsnummer 5 zugewiesen.

Setzen Sie die Nebenversionsnummer auf 0 zurück und zwar so, wie diese auch durch Visual Studio 2003 für das .NET Framework 1.x zugewiesen wird, so werden diese als ältere Anwendungen über WOW64 ausgeführt. Die Methode Module.GetPEKind im Namensraum System.Reflection erlaubt die Abfrage auf Quelltextebene, ob ein Assembly auf einer bestimmten Plattform oder unter WOW64 auszuführen ist.

 
Anzeige
Anzeige
x