Last Updated 2004/01/22
Programming Tips Windows95系  索 引 
Windows95でのセクタ入出力(FDD/HDD)
2004/01/22

Win32 SDK に書かれている CreateFile("\\\\.\\A:", ...) というデバイスオープン方法は Windows NT のためのものであり,この方法は Windows 95 では使用できない.
Windows95 ではその代わりに、VWIN32 VxD をオープンして,DOS IOCTL 発行を要求する.セクタ入出力は DOS IOCTL の機能を用いる.
(実際にこれを処理するのは DOS ではなく VxD)


(1) VWIN32 VxD をオープンして、ハンドルを取得

    HANDLE hvxd = CreateFile("\\\\.\\VWIN32", 0, 0, NULL, 0,
                             FILE_FLAG_DELETE_ON_CLOSE, NULL);


(2) DOS IOCTL (AH=44h) Block Device Request (AL=0Dh)
トラック入出力 (sub function 61h/41h) の要求パケットを設定


    #pragma pack(1)
    typedef struct  tagTRACKIO {
        BYTE    func;           /* 0 */
        WORD    head;           /* head no. */
        WORD    cylinder;       /* cylinder no. */
        WORD    sector;         /* sector no. */
        WORD    num;            /* # of sectors to read */
        void *  pbuf;           /* transfer address (32bit offset) */
        unsigned short  myDS;   /* DS */
    } TRACKIO;
    #pragma pack()

TRACKIO は,DOS IOCTL Block Device Request (AX=440Dh) の CL=41h/61h「トラック入出力」で定義される,要求パケットである.最初のメンバ func は 0 にする.head 〜 num までは入出力したいヘッド/シリンダ/セクタ番号と,セクタ数を指定する.(詳細は DOS IOCTL の文献を参照)

最後の二つのメンバ (pbuf と myDS) は注意が必要である.このフィールドは入出力バッファのアドレスを指定する.
従来の DOS IOCTL では,最後のフィールドは、16bit segment+16bit offset の 32bit FAR アドレス (4バイト) なのだが,今回の場合は 16bit segment + 32bit offset の 48bit FAR アドレス (6バイト) で指定する.この辺は明文化されていない.

また上記の例で構造体のアラインメントを 1 にしている点も注意が必要である.


(3) DOS IOCTL (AH=44h) Block Device Request (AL=0Dh) レジスタを設定

DOS IOCTL 呼出のためのレジスタ・セットアップを行う.
但し,自分のレジスタそのものを変更するのではなく,以下の様な構造体の各メンバに,レジスタとして設定すべき値を各々セットする.

    typedef struct DIOCRegs {
        DWORD   reg_EBX;   // EBX register
        DWORD   reg_EDX;   // EDX register
        DWORD   reg_ECX;   // ECX register
        DWORD   reg_EAX;   // EAX register
        DWORD   reg_EDI;   // EDI register
        DWORD   reg_ESI;   // ESI register
        DWORD   reg_Flags; // Flags register
    } DIOC_REGISTERS;
 
    reg_EAX    440Dh (DOS IOCTL - block device request)
    reg_EBX    ドライブ番号 (current=0, A=1, B=2, C=3, ...)
    reg_ECX    0841h(読取時) / 0861h(書込時)
    reg_EDX    上記 TRACKIO 構造体の 32bit offset address

(詳細は DOS IOCTL の文献を参照)


(4) VWIN32 に対して DOS IOCTL 発行を要求

DeviceIoControl() を用いて VWIN32 に対して DOS IOCTL 発行を要求する.
この時 VWIN32 に対する機能コードは1を用いる.

  DIOC_REGISTER  r;    /* 既に step 3 で設定済みのレジスタ・セット */
  DeviceIoControl(hvxd, 1, &r, sizeof r, &r, sizeof r, &retsize, NULL);


この様な方法でセクタ入出力を行うには,事前にヘッド/シリンダ/セクタ数などを取得する必要がある.
これには DOS IOCTL AX=440Dh CL=60h の「デバイス・パラメータの取得」を用いる事ができる.
(詳細は DOS IOCTL の文献を参照)

この機能呼出には,上記注意点で述べた 48bit FAR address などの、DOS と仕様が異なる個所は無いはずなので,DOS の文献の通りで良い.
(情報取得 60h の場合.設定 40h は未確認)



Windows95 上からセクタ入出力などの直接的なドライブ・アクセスを行う場合は,Windows95 で新たに提供された DOS IOCTL 機能「Exclusive Volume Lock」を行ってドライブをロックする様に心がけた方が良い.
通常のファイル単位アクセスの場合は,OS がファイルの排他処理を行うが,セクタ単位入出力の場合にはこの排他が働かない.
その為 Windows95 でドライブをロック/アンロックする DOS IOCTL 機能が新たにサポートされている.
具体的には,DOS IOCTL AX=440Dh CL=4Ah/4Bh, 6Bh〜70h がドライブロック関連の DOS IOCTL である.これらは DOS の IOCTL 文献には載っていない.
Win32 SDK の Windows95 固有技術のパートに説明がある.
Exclusive Volume Lock 関連の DOS IOCTL 呼出を Win32 アプリから行うには,先の例と同じ様に VWIN32 への DeviceIoControl() を用いる.


参照
物理アドレス使用
前後のTips
Windows95でのセクタ入出力(FDD/HDD)

DSS ProgrammingTipsCGI Ver2.02