2006年06月27日

トレイが引き出されるプログラム

ASPI を使って、ATAPI と SCSI 接続されているディスクドライブのトレイが片っ端から開かれるサンプルプログラムを作成してみました。エラー処理もせず、メッセージの一つも出ない簡単なものですが、参考になればと思います。

開発環境:Microsoft Visual C++ 6.0
実行可能条件:WINASPI32.DLL がインストールされていること。
Windows 95/98/Me では標準でインストール済。
Windows 2000/XP では別途必要。

#include "windows.h" の部分を書き換えたり、 LoadLibrary, FreeLibrary, CreateEvent, CloseHandle ResetEvent, WaitForSingleObject といったWindows特有のAPIをなんとかすれば、 他の開発環境、他のOSでも何とかなると思います。

OpenTray.lzh (プロジェクトファイル付)

#include "windows.h"

// ASPI API関数
typedef DWORD (*fGetASPI32SupportInfo)(void);  //ASPIが利用可能か
typedef DWORD (*fSendASPI32Command)(void*);    //コマンドを実行

// ASPI コマンド
#define SC_HA_INQUIRY    0x00  // ホストアダプタに関する情報を取得する
#define SC_GET_DEV_TYPE  0x01  // デバイスの情報を取得する
#define SC_EXEC_SCSI_CMD 0x02  // コマンドの実行

// コマンドの結果
#define SS_PENDING       0x00  // ASPI実行中
#define SS_COMP          0x01  // 正常終了

// デバイスの種類
#define DTYPE_CDROM      0x05  // CD-ROM device

// コマンドのフラグ
#define SRB_DIR_IN       0x08  // ドライブからデータを受け取る
#define SRB_DIR_OUT      0x10  // ドライブへデータを送る
#define SRB_EVENT_NOTIFY 0x40  // ASPIコマンド実行終了検知にイベントを使用

// MMCコマンド
#define SCSI_START_STOP_UNIT 0x1B  // Start/Stop unit

// -----------------------------------------------------------------------

// WINASPI32.dll へのハンドル
HINSTANCE m_hModule;

// イベントへのハンドル 
HANDLE m_hEvent;

// ASPI API 関数へのポインタ
fGetASPI32SupportInfo lpGetASPI32SupportInfo;  //ASPIが利用可能か
fSendASPI32Command    lpSendASPI32Command;     //コマンドを実行

// -----------------------------------------------------------------------

//構造体のメンバの幅詰をする
#pragma pack(push, 1)

// -----------------------------------------------------------------------

// SC_HA_INQUIRY ASPIコマンド
typedef struct tSRB_HAInquiry
{
    BYTE  SRB_Cmd;           // = SC_HA_INQUIRY
    BYTE  SRB_Status;
    BYTE  SRB_Ha;            // ホストアダプタ番号(入力)
    BYTE  SRB_Flags;
    DWORD Reserved1;
    BYTE  HA_Count;
    BYTE  HA_SCSI_ID;
    BYTE  HA_ManagerId[16];
    BYTE  HA_Identifier[16];
    BYTE  HA_Unique[16];     // ターゲットの数など(出力)
    WORD  Reserved2;
} SRB_HAInquiry;

// -----------------------------------------------------------------------

// SC_GET_DEV_TYPE ASPIコマンド
typedef struct tSRB_GDEVBlock
{
    BYTE  SRB_Cmd            // = SC_GET_DEV_TYPE
    BYTE  SRB_Status;
    BYTE  SRB_Ha;            // ホストアダプタ番号(入力)
    BYTE  SRB_Flags;
    DWORD Reserved1;
    BYTE  SRB_Tgt;           // ターゲット番号(入力)
    BYTE  SRB_Lun;           // ターゲットの論理ユニット番号(入力)
    BYTE  SRB_DeviceType;    // ターゲットのデバイスタイプ(出力)
    BYTE  Reserved2;
} SRB_GDEVBlock;

// -----------------------------------------------------------------------

// SC_EXEC_SCSI_CMD ASPIコマンド
typedef struct SRB_ExecSCSICmd
{
    BYTE  SRB_Cmd;           // = SC_EXEC_SCSI_CMD
    BYTE  SRB_Status;
    BYTE  SRB_Ha;            // ホストアダプタ番号(入力)
    BYTE  SRB_Flags;         // リクエストフラグ(入力)
    DWORD Reserved1;
    BYTE  SRB_Tgt;           // ターゲット番号(入力)
    BYTE  SRB_Lun;           // ターゲットの論理ユニット番号(入力)
    WORD  Reserved2;
    DWORD SRB_BufLen;        // データ用確保バッファ長
    BYTE* SRB_BufPointer;    // データバッファアドレス
    BYTE  SRB_SenseLen;      // センスデータ用確保バッファ長
    BYTE  SRB_CDBLen;        // CDBの長さ
    BYTE  SRB_HaStat;
    BYTE  SRB_TgtStat;
    VOID* SRB_PostProc;      // イベントハンドル
    BYTE  Reserved3[20];
    BYTE  CDBByte[16];       // CDBの内容
    BYTE  SenseArea[32+2];   // エラーコード(+2しているのはバウンダリ調整用)
} SRB_ExecSCSICmd;

// -----------------------------------------------------------------------

//構造体のメンバの幅詰はここまで
#pragma pack(pop)

// -----------------------------------------------------------------------

//Ha, Tgt, Lun で指定されたドライブのトレイを開く
void OpenTray(BYTE Ha, BYTE Tgt, BYTE Lun)
{
    DWORD ret;
    ::ResetEvent(m_hEvent);

    SRB_ExecSCSICmd cmd;
    memset(&cmd, 0, sizeof(cmd));

    cmd.SRB_Ha  = Ha;
    cmd.SRB_Tgt = Tgt;
    cmd.SRB_Lun = Lun;

    cmd.SRB_Cmd        = SC_EXEC_SCSI_CMD;
    cmd.SRB_Flags      = SRB_DIR_OUT | SRB_EVENT_NOTIFY;  // イベントを使用
    cmd.SRB_BufLen     = 0;
    cmd.SRB_BufPointer = NULL;
    cmd.SRB_SenseLen   = 14;
    cmd.SRB_CDBLen     = 6;
    cmd.SRB_PostProc   = (LPVOID)m_hEvent;

    cmd.CDBByte[ 0]    = SCSI_START_STOP_UNIT;  // Start/Stop unit  0x1b
    cmd.CDBByte[ 4]    = 0x02;                  //トレイを出す (0x03にするとトレイを入れる)

    ret = lpSendASPI32Command((void*)&cmd);
    if(ret == SS_PENDING)
    {
        ::WaitForSingleObject(m_hEvent, INFINITE);
    }
    // 実行結果は cmd.SRB_Status に格納される
    // エラーコードは cmd.SenseArea に格納される
}

int main(int argc, char *argv[])
{
    m_hModule = NULL;
    m_hEvent = NULL;

    // DLLを開く
    m_hModule = ::LoadLibrary("WNASPI32.DLL");
    if(m_hModule == NULL)  //DLLが開けなかったとき
    {
        return 1;
    }

    lpSendASPI32Command    = (fSendASPI32Command)::GetProcAddress(m_hModule, "SendASPI32Command");
    lpGetASPI32SupportInfo = (fGetASPI32SupportInfo)::GetProcAddress(m_hModule, "GetASPI32SupportInfo");
    if(!(lpGetASPI32SupportInfo && lpSendASPI32Command))  // 関数が使えないとき
    {
        ::FreeLibrary(m_hModule);
        return 1;
    }

    //イベントの用意
    m_hEvent = ::CreateEvent(NULL, TRUE, FALSE, NULL);

    BYTE Ha, Tgt, Lun;
    int HaMax, TgtMax;
    DWORD Info;

    // ホストアダプタの数を取得
    Info = lpGetASPI32SupportInfo();  //ASPIが利用可能か
    if((Info & 0x0000ff00) != 0x00000100)
    {
        HaMax = 0;  //利用不可
    }
    else            //利用可能
    {
        HaMax = Info & 0x00ff;  //ホストアダプタの数
    }

    // 全てのホストアダプタを検索
    for(Ha = 0; Ha < HaMax; Ha++)
    {
        // ターゲットの数を取得
        SRB_HAInquiry ha_cmd;
        memset(&ha_cmd, 0, sizeof(ha_cmd));
        ha_cmd.SRB_Cmd = SC_HA_INQUIRY;
        ha_cmd.SRB_Ha  = Ha;
        Info = lpSendASPI32Command((void*)&ha_cmd);
        //一つのアダプタにあるターゲットの数
        if(ha_cmd.HA_Unique[3] == 0)
        {
            TgtMax = 8;
        }
        else
        {
            TgtMax = ha_cmd.HA_Unique[3];
        }
        //個々のアダプタに接続しているデバイスの情報を取得
        for(Tgt = 0; Tgt < TgtMax; Tgt++)
        {
            Lun = 0;

            SRB_GDEVBlock dev_cmd;
            memset(&dev_cmd, 0, sizeof(dev_cmd));
            dev_cmd.SRB_Cmd = SC_GET_DEV_TYPE;
            dev_cmd.SRB_Ha  = Ha;
            dev_cmd.SRB_Tgt = Tgt;
            dev_cmd.SRB_Lun = Lun;

            Info = lpSendASPI32Command((void*)&dev_cmd);

            if(dev_cmd.SRB_Status == SS_COMP)
            {
               	if(dev_cmd.SRB_DeviceType == DTYPE_CDROM)  //CD-ROMドライブを発見
                {
                    OpenTray(Ha, Tgt, Lun);  //Ha, Tgt, Lun で指定したドライブのトレイを開く
                }
            }
        }
    }

    //イベントを解放する
    ::CloseHandle(m_hEvent);

    // DLLを解放する
    ::FreeLibrary(m_hModule);

    return 0;
}
posted by 七癖 at 17:15| Comment(0) | TrackBack(0) | Multimedia Commands | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。

この記事へのトラックバック
×

この広告は90日以上新しい記事の投稿がないブログに表示されております。