SSブログ

SetupAPIを使ってディスクドライブを列挙する [CodeTips]

前回の記事は8月だったので、約四ヶ月!間が空いてしまいました。
でも、ここは思い出したようにやっていきます。

さて、今回はWindows Setup API を使って、ディスクドライブデバイスを列挙する例です。

#include <stdio.h>
#include <windows.h>
#include <setupapi.h>
#include <devguid.h>
#define INITGUID
#include <devpkey.h>

int wmain(int argc, WCHAR* argv[])
{
    HDEVINFO hDevInfo;

    hDevInfo = SetupDiGetClassDevsEx(&GUID_DEVCLASS_DISKDRIVE,NULL,NULL,
                                     DIGCF_PROFILE,NULL,NULL,NULL);
    if( hDevInfo != INVALID_HANDLE_VALUE )
    {
        SP_DEVINFO_DATA DevInfoData = {0};
        DevInfoData.cbSize = sizeof(DevInfoData);

        BYTE Buffer[4096];

        DWORD Index = 0;

        while( SetupDiEnumDeviceInfo(hDevInfo,Index,&DevInfoData) )
        {
            DEVPROPTYPE PropertyType;

            if( SetupDiGetDeviceProperty(hDevInfo,&DevInfoData,
                    &DEVPKEY_Device_FriendlyName,&PropertyType,
                    Buffer,sizeof(Buffer),NULL,0) )
            {
                if( PropertyType == DEVPROP_TYPE_STRING )
                {
                    wprintf(L"%s\n",(PWSTR)Buffer);
                }
            }			
            Index++;
        }
        SetupDiDestroyDeviceInfoList(hDevInfo);
    }
    return 0;
}

この例は、SetupAPIのDevice Installation Function(SetupDiのプリフィクスを持つ)を使って、ディスクドライブクラスに登録されているデバイスを列挙して表示します。

SetupDiGetClassDevsEx関数にGUID_DEVCLASS_DISKDRIVEを指定してディスクドライブのみを列挙する様に指定し、同時にDIGCF_PROFILEを指定して現在のハードウェアプロファイルすべてを列挙する様にしています。

GUID_DEVCLASS_DISKDRIVEは、ディスクドライブ(DiskDrive)クラスを示すGUIDで、そのデバイスの列挙を指示します。一般的には内蔵ハードディスクやUSBの外付けディスク、SDカード、メモリスティックなどや仮想ディスクなども含め「ディスク」として認識され、通常エクスプローラ上でドライブが割り当てられるデバイスを指します。

フラグにDIGCF_PROFILEを指定する(0でも可。その場合はすべてのハードウェアプロファイルが対象になる)と面白い情報を得ることができます。アクティブなディスクデバイス以外に非アクティブなデバイスも列挙することができるのです。このサンプルを実行すると、例えば過去にPCに接続して、その時点でそうはたUSBメモリなども表示されます。私も長期間使っているPCに試したところ、いろいろ懐かしいUSBメモリや今は手元に無いデジカメや携帯プレーヤーなどが表示され感慨深いものがありました。

ただ、この例は対象をディスクデバイスクラスのみとしているため、DVD/CD-ROMドライブやフロッピーディスクなどディスクドライブ以外のクラスに属するデバイスは表示されません(恐らくスマートフォンもポータブルデバイス扱いで表示できません。ただ、モバイルデバイスに詳しくないので判りませんが、ものによってはソフトのインストールの為CD-ROMクラスデバイスを登録する機種ある様です。なので、ディスクドライブで表示するものもあるかもしれません)。しかし、これらのクラスを含めるのは簡単でGUID_DEVCLASS_DISKDRIVEの部分をそれぞれのクラスGUID(GUID_DEVCLASS_CDROMなど)に置き換えれば同じ様に列挙できます(もちろんGUIDを指定せず、すべてのデバイスクラス、デバイスを列挙することも可能です)。デバイスクラスはdevguid.hに記述されています。

SetupDiGetClassDevsEx関数が成功したら、後は返されたHDEVINFO を使ってSetupDiEnumDeviceInfo関数でデバイスを列挙します。デバイス情報がSP_DEVINFO_DATAに返されるので、それを使ってSetupDiGetDeviceProperty関数を呼び出し、デバイスのプロパティを得ます。取得したいプロパティの種類は引数で指定できます。ここでは単純にDEVPKEY_Device_FriendlyNameのみを取得しています。フレンドリ名とはその名の通り人間が読む為のデバイス名や商品名で構成されます。

プロパティには型があるので、一応PropertyTypeに返されるプロパティタイプをチェックし、文字列(DEVPROP_TYPE_STRING)の場合のみ表示しています。このPropertyTypeにはいろいろな型があるので、より多くのプロパティを取得したい場合には、それぞれきちんと確認する必要があります。

SetupDiGetDevicePropertyはWindows Vista以降で登場したAPIなので、Windows XP以前では使えません。もし、Windows XPで実行したい場合はSetupDiGetDevicePropertyの部分を以下の様に書き換えます。

ULONG ulRegDataType;
ULONG cbBuffer = sizeof(Buffer);
if( CM_Get_DevNode_Registry_Property(DevInfoData.DevInst,CM_DRP_FRIENDLYNAME,
                            &ulRegDataType,Buffer,&cbBuffer,0) == CR_SUCCESS )
{
    wprintf(L"%s\n",(PWSTR)Buffer);
}


この様にコンフィグレーションマネージャのAPIを使用するため、cfgmgr32.hのインクルードも追加してください。

#include <cfgmgr32.h>


こうやって多数のデバイスが列挙されたら、不要なものを削除したくなるかもしれません。その様な場合はデバイスマネージャやDeviceWalkerなどで削除すると良いでしょう。

今回、この例の様なフレンドリ名に加え、もう少しだけ表示するプロパティを追加した「完全版」サンプルをGitHubに上げておきました。以下はその一部(mainのみ)です。このサンプルもディスクドライブクラスのみ列挙しています。

int wmain(int /*argc*/, WCHAR* /*argv[]*/)
{
    _wsetlocale(LC_ALL, L"");

    CSimpleArray devProps; 

    HDEVINFO hDevInfo;
    hDevInfo = SetupDiGetClassDevsEx(&GUID_DEVCLASS_DISKDRIVE,NULL,NULL,DIGCF_PROFILE,NULL,NULL,NULL);

    if( hDevInfo != INVALID_HANDLE_VALUE )
    {
        SP_DEVINFO_DATA DevInfoData = {0};
        DevInfoData.cbSize = sizeof(DevInfoData);

        DWORD dwIndex = 0;
        while( SetupDiEnumDeviceInfo(hDevInfo,dwIndex,&DevInfoData) )
        {
            CDevicePropertySet *set = new CDevicePropertySet;

            if( set != NULL )
            {
                if( !set->FriendlyName.GetProperty(hDevInfo, DevInfoData, DEVPKEY_Device_FriendlyName) )
                {
                    // When could not acquire friendly name, instead get the Instance ID as a friendly name.
                    // Possible cause is the target device deleted after call SetupDiEnumDeviceInfo().
                    //
                    set->FriendlyName.GetProperty(hDevInfo, DevInfoData, DEVPKEY_Device_InstanceId);
                }

                if( set->FriendlyName.IsValidData() )
                {
                    set->FriendlyName.GetProperty(hDevInfo, DevInfoData, DEVPKEY_Device_FriendlyName);
                    set->DevNodeStatus.GetProperty(hDevInfo,DevInfoData,DEVPKEY_Device_DevNodeStatus);
                    set->FriendlyName.GetProperty(hDevInfo,DevInfoData,DEVPKEY_Device_FriendlyName);
                    set->InstallDate.GetProperty(hDevInfo,DevInfoData,DEVPKEY_Device_InstallDate);
                    set->FirstInstallDate.GetProperty(hDevInfo,DevInfoData,DEVPKEY_Device_FirstInstallDate);
                    set->RemovalRelations.GetProperty(hDevInfo,DevInfoData,DEVPKEY_Device_RemovalRelations);

                    devProps.Add( set );
                }
                else
                {
                    // When could not make friendly name, free an object.
                    // But it normally does not occurs.
                    //
                    delete set;
                }
            }

            dwIndex++;
        }

        SetupDiDestroyDeviceInfoList(hDevInfo);
    }
    else
    {
        return -1; // error
    }

    // sort by friendly name
    //
    qsort(devProps.GetData(),devProps.GetSize(),sizeof(CDevicePropertySet *),_compare);

    // print information
    //
    int i,c;
    c = devProps.GetSize();
    for(i = 0; i < c; i++)
    {
        PrintFriendlyName(*devProps[i]);

        PrintDateTime(devProps[i]->InstallDate);

        PrintRelationVolumes(devProps[i]->RemovalRelations);

        printf("\n");
    }

    // frees object memory
    //
    c = devProps.GetSize();
    for(i = 0; i < c; i++)
    {
        delete devProps[i];
    }

    // frees pointer array
    //
    devProps.RemoveAll();

    return 0;
}


すべてのソースコードを以下に載せましたので、興味のある方はどうぞ。

GitHub レポジトリ:
https://github.com/katsu-y/fsstoragedevice


nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:[必須]
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

Facebook コメント

トラックバック 0

NtDisplayString/NtDe..Filter Manager APIを使.. ブログトップ

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。