Schreiben von 64-Bit-Audiotreibern

Wenn Sie einen 64-Bit-Treiber schreiben oder einen Treiber schreiben, der für die Ausführung auf 32- und 64-Bit-Systemen kompiliert werden kann, befolgen Sie die Portierungsrichtlinien unter Treiberprogrammierungstechniken. Nachfolgend werden einige der Fallstricke beschrieben, die beim Schreiben eines 64-Bit-Audiotreibers auftreten können.

Ein potenzielles Problem, nach dem in vorhandenem 32-Bit-Treibercode gesucht werden kann, ist in erster Linie die Konvertierung zwischen Zeigertypen und ganzzahligen Typen wie DWORD oder ULONG. Programmierer mit Erfahrung beim Schreiben von Code für 32-Bit-Computer können verwendet werden, um davon auszugehen, dass ein Zeigerwert in eine DWORD- oder ULONG-Instanz passt. Für 64-Bit-Code ist diese Annahme gefährlich. Das Umwandeln eines Zeigers auf den Typ DWORD oder ULONG kann dazu führen, dass ein 64-Bit-Zeiger abgeschnitten wird. Ein besserer Ansatz besteht darin, den Zeiger so zu umwandeln, dass er DWORD_PTR oder ULONG_PTR eingibt. Eine ganze Zahl ohne Vorzeichen vom Typ DWORD_PTR oder ULONG_PTR ist immer groß genug, um den gesamten Zeiger zu speichern, unabhängig davon, ob der Code für einen 32- oder 64-Bit-Computer kompiliert wird.

Beispielsweise das IRP-ZeigerfeldIoStatus. Die Informationen sind vom Typ ULONG_PTR. Der folgende Code zeigt, was beim Kopieren eines 64-Bit-Zeigerwerts in dieses Feld nicht zu tun ist:

    PDEVICE_RELATIONS pDeviceRelations;
    Irp->IoStatus.Information = (ULONG)pDeviceRelations;  // wrong

In diesem Codebeispiel wird der Zeiger fälschlicherweise in den pDeviceRelations Typ ULONG umgewandelt, wodurch der Zeigerwert abgeschnitten werden kann, wenn sizeof(pDeviceRelations) > sizeof(ULONG). Der richtige Ansatz besteht darin, den Zeiger auf ULONG_PTR umzustellen, wie im Folgenden gezeigt:

    PDEVICE_RELATIONS pDeviceRelations;
    Irp->IoStatus.Information = (ULONG_PTR)pDeviceRelations;  // correct

Dadurch bleiben alle 64 Bits des Zeigerwerts erhalten.

Eine Ressourcenliste speichert die physische Adresse einer Ressource in einer Struktur vom Typ PHYSICAL_ADDRESS (siehe IResourceList). Um das Abschneiden einer 64-Bit-Adresse zu vermeiden, sollten Sie beim Kopieren einer Adresse in die Struktur oder beim Lesen einer Adresse aus der Struktur auf das QuadPart-Element der Struktur und nicht auf den LowPart-Member zugreifen. Beispielsweise gibt das FindTranslatedPort-Makro einen Zeiger auf eine CM_PARTIAL_RESOURCE_DESCRIPTOR-Struktur zurück, die die Basisadresse eines E/A-Ports enthält. Das u. Port. Das Startelement dieser Struktur ist ein PHYSICAL_ADDRESS Zeiger auf die Basisadresse. Der folgende Code zeigt, was nicht zu tun ist:

    PUSHORT pBase = (PUSHORT)FindTranslatedPort(0)->u.Port.Start.LowPart;  // wrong

Auch hier kann der Zeiger abgeschnitten werden. Stattdessen sollten Sie auf das QuadPart dieses Elements zugreifen, wie im Folgenden gezeigt:

    PUSHORT pBase = (PUSHORT)FindTranslatedPort(0)->u.Port.Start.QuadPart;  // correct

Dadurch wird der gesamte 64-Bit-Zeiger kopiert.

Inline-Win64-Funktionen wie PtrToUlong und UlongToPtr konvertieren sicher zwischen Zeiger- und Ganzzahltypen, ohne sich auf Annahmen über die relativen Größen dieser Typen zu verlassen. Wenn ein Typ kürzer als der andere ist, muss er beim Konvertieren in den längeren Typ erweitert werden. Ob der kürzere Typ mit dem Zeichenbit oder mit Nullen erweitert wird, ist für jede Win64-Funktion gut definiert. Dies bedeutet, dass alle Codeausschnitte wie

    ULONG ulSlotPhysAddr[NUM_PHYS_ADDRS];
    ulSlotPhysAddr[0] = ULONG(pulPhysDmaBuffer) + DMA_BUFFER_SIZE;  // wrong

sollte ersetzt werden durch

    ULONG_PTR ulSlotPhysAddr[NUM_PHYS_ADDRS];
    ulSlotPhysAddr[0] = PtrToUlong(pulPhysDmaBuffer) + DMA_BUFFER_SIZE;  // correct

Dies wird bevorzugt, obwohl ulSlotPhysAddr möglicherweise der Wert eines Hardwareregisters dargestellt wird, das nur 32 statt 64 Bit lang ist. Eine Liste aller neuen Win64-Hilfsfunktionen zum Konvertieren zwischen Zeiger- und Ganzzahltypen finden Sie unter Die neuen Datentypen.