次の方法で共有


64 ビット オーディオ ドライバーの作成

64 ビット ドライバーを作成する場合、または 32 ビット システムと 64 ビット システムの両方で実行するようにコンパイルできるドライバーを作成する場合は、ドライバー プログラミング手法の移植ガイドラインに従ってください。 64 ビット オーディオ ドライバーを作成する際に遭遇する可能性のある落とし穴のいくつかを以下に説明します。

何よりもまず、既存の 32 ビット ドライバー コードで探す必要がある潜在的な問題は、ポインター型と DWORD や ULONG などの整数型の間の変換です。 32 ビット コンピューター用のコードを記述した経験のあるプログラマは、ポインター値が DWORD または ULONG に収まると想定することに慣れている可能性があります。 64 ビット コードの場合、この仮定は危険です。 ポインターを DWORD 型または ULONG 型にキャストすると、64 ビット ポインターが切り捨てられる可能性があります。 より良い方法は、ポインターを DWORD_PTR 型または ULONG_PTR 型にキャストすることです。 DWORD_PTR 型または ULONG_PTR 型の符号なし整数は、コードが 32 ビット マシン用にコンパイルされるか 64 ビット マシン用にコンパイルされるかに関係なく、常にポインター全体を格納するのに十分な大きさになります。

たとえば、IRP ポインター フィールドloStatusInformationは ULONG_PTR 型です。 次のコードは、64 ビットのポインター値をこのフィールドにコピーするときに行わない操作を示しています:

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

このコード サンプルでは、pDeviceRelationsポインターが誤って ULONG 型にキャストされ、sizeof(pDeviceRelations) > sizeof(ULONG). 正しいアプローチは、次のようにポインタを ULONG_PTR にキャストすることです。

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

これにより、ポインター値の 64 ビットすべてが保存されます。

リソース リストは、リソースの物理アドレスを PHYSICAL_ADDRESS 型の構造体に格納します (IResourceListを参照)。 64 ビット アドレスの切り捨てを回避するには、構造体にアドレスをコピーするとき、または構造体からアドレスを読み取るときに、LowPart メンバーではなく、構造体の QuadPart メンバーにアクセスする必要があります。 たとえば、 FindTranslatedPort マクロは、I/O ポートのベース アドレスを含むCM_PARTIAL_RESOURCE_DESCRIPTOR構造体へのポインターを返します。 この構造体の u メンバーはベース アドレスへのPHYSICAL_ADDRESS ポインターです。 次のコードは、してはいけないことを示しています。

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

繰り返しますが、これによりポインタが切り詰められる可能性があります。 代わりに、次に示すように、このメンバーの QuadPart にアクセスする必要があります:

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

これにより、64 ビット ポインター全体がコピーされます。

PtrToUlong UlongToPtr などのインライン Win64 関数は、ポインター型と整数型の間で、これらの型の相対的なサイズに関する仮定に依存することなく、これらの型の間で安全に変換します。 一方のタイプがもう一方のタイプより短い場合は、長いタイプに変換するときに拡張する必要があります。 短い型を符号ビットで埋めるかゼロで拡張するかは、Win64 関数ごとに明確に定義されています。 これは、次のようなコード スニペットが

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

に置き換える必要があります

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

これは、ulSlotPhysAddr64 ビット長ではなく 32 ビット長のハードウェア レジスタの値を表す場合でも、推奨されます。 ポインター型と整数型の間で変換するためのすべての新しい Win64 ヘルパー関数の一覧については、新しいデータ型を参照してください。