So-net無料ブログ作成
NOTE:
リニューアルしました。



前の5件 | -

FSDirWalkerをSets対応にする方法 [ソフトウェア]

Windows 10のRS5向けに、(今のところ)「Sets」と呼ばれるデスクトップのウィンドウをタブでまとめる機能の評価が始まっています。

現在はまだ開発途中なので動作が不安定だったりしてまだまだなのですが、正式に搭載されることになるとアプリケーションそのものの操作性は基本的には変わりは無いものの、タブ切り替えに関係してデスクトップ全般の操作性に影響が出る(特にPCに慣れていないユーザーは面食らうのではと思いますが…)ため、動向に注目しています。

Win32のアプリケーションもSetsのタブに入れることができるのですが、ウィンドウのキャプションバーが通常の(一般的な)状態になっていないと有効にならない様です。現時点のビルドではリボンを使っているアプリケーションもSetsが有効になりません。Windows Ribbon Frameworkという標準のリボンフレームワークを使っていても同じで、Windows添付のペイントやワードパッドもSetsタブの仲間に入れません。同じフレームワークを使っているFSDirWalkerも当然Setsを利用できません。

しかし、WindowsエクスプローラのウィンドウはSetsを利用できる様になっています。
エクスプローラはWindows Ribbon Frameworkを使ってきた筈なので、エクスプローラ側での特別なSets対応や使用するフレームワークを変更していない限り、将来のWindows 10ビルドでは他のWindows Ribbon Framework使用アプリケーションもSetsを利用できる様になると予想してはいるのですが。

それでも、今の段階でFSDirWalkerをSetsのタブに入れて試してみたい。もしそういった要望がある様でしたらレジストリを操作する必要があるものの、リボンを無効化してクラシックメニューにすることで利用可能にできます。

それにはレジストリエディタを使って以下のレジストリキー下に値を追加します。
(恐らくこの記事の内容に興味を持たれる方であればレジストリエディタの扱いには慣れていると思うので、おなじみの警告をくどくどとはしませんが、注意はしてください(^^;)

HKEY_CURRENT_USER\Software\YamashitaSoftwareWorks\FSDirWalker DisableRibbon(REG_DWORD)=0x1

この値を設定してからFSDirWalkerを実行してください。一般的なWin32アプリケーションの様なUIになってSetsが有効になっているはずです。

リボンUIに戻す場合は、この値に0x0を設定するか、DisableRibbonエントリを削除してください。

nice!(0)  コメント(0) 

FSDirWalker 2.2.320.0を公開しました [ソフトウェア]

先日、FSDirWalker 2.2.320.0を公開しました。ダウンロードはこちらからできます。
今回の主な機能追加・変更点は次のとおりです。
  • ナビゲーションペインに[シェルフォルダ]を追加

    Windowsシェルで定義済みのフォルダをナビゲーションペインから選択できる様にしました。

  • リボンの操作タブに[オブジェクト]ドロップダウン、[オブジェクトIDの生成][オブジェクトIDの削除]コマンドを追加

    NTFSフォーマット下のファイルで使用できるオブジェクトIDについて、生成または削除するコマンドを追加しました。コンテキストメニューからも選択できます。

  • [ファイル](アプリケーション)タブのメニューに[ツール]メニューを追加

    この項目は、実行時のモードによって表示される項目が変わります。

    • 管理者モードで実行時

      [仮想ハードディスクのアタッチ]
      仮想ハードディスクファイル(*.VHDファイル)をアタッチします。

      [システム起動時に処理される一覧を編集]
      PC起動時にセッションマネージャによって処理される以下のレジストリエントリの内容を編集します。
      HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager
      PendingFileRenameOperations

    • ユーザーモードで実行時

      [システム起動時に処理される一覧を参照]
      PC起動時にセッションマネージャによって処理されるレジストリエントリの内容(編集と同じエントリ)を表示します。


  • コピー開始ダイアログに[オブジェクトIDを持っている場合コピー先に移譲する]オプションを追加

    コピーされるファイルがオブジェクトIDを持っている場合、そのIDをコピー先のファイルに「移譲」します。オブジェクトIDはシステム全体で一意であり、同じIDが存在できないため、コピー元のIDは削除されます。


  • Windows PE/RE(回復コンソール)で実行時に、削除されたファイルを復元する機能を追加

    WindowsのFile Managemant APIが利用可能な環境でのみ有効になります。この機能は一度削除されたファイルの復元を試みます。通常このコマンドが使用できる環境はリボンが表示されないため、クラシックメニューの[ツール]項目から選択します。ウィザードが表示されるので、その指示に従って操作してください。
    この機能については別途記事を書く予定です。


  • オプションの[ファイル固有のアイコンを表示]と[ダブルクリックでファイルを開く]項目のデフォルトを'有効'(初回起動時から有効になる様に)に変更

    ファイルリスト上でファイルをダブルクリックした時に、シェルに登録されたアプリケーションを使ってファイルを開くオプションと、実行ファイルの様に固有のアイコンを持っている場合、ファイルリストのアイコンに表示するオプションをデフォルトでONにしました。従来はデフォルトでOFFになっており、オプションダイアログから変更する必要がありました。

他にも複数の不具合を修正しています。

nice!(0)  コメント(5) 

復旧中

過去記事整理&リニューアル中です。

nice!(0)  コメント(0) 

Filter Manager APIを使ってボリュームを列挙する例 [CodeTips]

年明け最初に上げようと思って、昨年末に用意していた内容を上げておきます。
ということは、「あけましておめでとうございます」ですね。明日から5月だというのに…(^^;


GitHubの説明などで 'FltMgr' (Filter Manager) APIと書いていますが、正確には"Filter Manager Support for Minifilter Drivers"の”User-Mode Library” (FltLib.dll) のAPI を使用しています。

Windowsにfltmcというコマンドがありますが、このサンプルではfltmcの instancesやvolumesオプションで表示される様な内容を取得する例を示します。fltmcがコマンド目的上フィルタドライバを中心にした情報の見せ方なのに対し、サンプルではボリュームを中心とした見せ方となってします。

なお、このサンプルは管理者モードで実行してください。

あと、すっかり当たり前に公開してしまったのですが、コード中、print_string()でUNICODE_STRINGを使用している箇所があります(どさくさに紛れて__based変数も)。ここは当然ながらUNICODE_STRINGは必ずしも必須ではありません(使用しない場合はこの部分を適切なC文字列の処理に変更してください)。表示したい内容がポインタとオフセット、レングスで与えられるため、手軽に処理する例としてこの様な使い方をしています。

Visual Studio 2010プロジェクト,Windows 7 WDK用 sourcesを含むすべての内容は GitHubに公開しています。

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

//
// fsfltview
//
// Sample: Using the filter manager for volume and filter instance enumeration.
//
// Note:   This code is need to run under administrator mode.
//
// Author: YAMASHITA Katsuhiro
//
#include <SDKDDKVer.h>

#include <stdio.h>
#include <stdlib.h>

#include <windows.h>
#include <fltuser.h>  // for FltMgr

#if 0
#include <winternl.h> // for UNICODE_STRING
#else
typedef struct _UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;
} UNICODE_STRING;
typedef UNICODE_STRING *PUNICODE_STRING;
#endif

#define _VOLUME_NAME_LENGTH 256

WORD g_wVersion = 0;

HRESULT
_FindFirst_VolumeInstance(
    PCWSTR pszVolumeName,
    INSTANCE_INFORMATION_CLASS dwInformationClass,
    LPVOID  *lpReturnedBuffer,
    LPHANDLE  lpVolumeInstanceFind
    )
{
    HRESULT hr;
    HANDLE hVolumeInstanceFind;
    DWORD BytesReturned;

    PVOID lpBuffer = NULL;
    DWORD dwBufferSize = 0;

    for(;;)
    {
        hr = FilterVolumeInstanceFindFirst(
                pszVolumeName,
                dwInformationClass,
                lpBuffer,
                dwBufferSize,
                &BytesReturned,
                &hVolumeInstanceFind
                );

        if( HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER )
        {
            if( lpBuffer )
                free(lpBuffer);
            lpBuffer = malloc(BytesReturned);
            if( lpBuffer == NULL )
            {
                hr = E_OUTOFMEMORY;
                break;
            }
            dwBufferSize = BytesReturned;

            continue;
        }
        else
        {
            break;
        }
    }

    if( hr == S_OK && lpBuffer != NULL )
    {
        *lpReturnedBuffer = lpBuffer;
        *lpVolumeInstanceFind = hVolumeInstanceFind;
    }
    else
    {
        *lpReturnedBuffer = NULL;
        *lpVolumeInstanceFind = NULL;

        if( lpBuffer != NULL )
            free(lpBuffer);
    }

    return hr;
}

HRESULT
_FindNext_VolumeInstance(
    HANDLE  hVolumeInstanceFind,
    INSTANCE_INFORMATION_CLASS dwInformationClass,
    LPVOID  *lpReturnedBuffer
    )
{
    HRESULT hr;
    DWORD BytesReturned;

    PVOID lpBuffer = NULL;
    DWORD dwBufferSize = 0;

    for(;;)
    {
        hr = FilterVolumeInstanceFindNext(
                hVolumeInstanceFind,
                dwInformationClass,
                lpBuffer,
                dwBufferSize,
                &BytesReturned
                );

        if( HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER )
        {
            if( lpBuffer )
                free(lpBuffer);
            lpBuffer = malloc(BytesReturned);
            if( lpBuffer == NULL )
            {
                hr = E_OUTOFMEMORY;
                break;
            }
            dwBufferSize = BytesReturned;

            continue;
        }
        else
        {
            break;
        }
    }

    if( hr == S_OK && lpBuffer != NULL )
    {
        *lpReturnedBuffer = lpBuffer;
    }
    else
    {
        *lpReturnedBuffer = NULL;

        if( lpBuffer != NULL )
            free(lpBuffer);
    }
    return hr;
}

void print_string(PCSTR Title,PVOID pBuffer,USHORT offset,USHORT len)
{
    BYTE __based(pBuffer) *pBased = 0;
    UNICODE_STRING us;
    us.Length = len;
    us.MaximumLength = us.Length;
    us.Buffer = (PWSTR)(pBased + offset);
    printf("%s%wZ\n",Title,&us);
}

void EnumVolumeInstance(PCWSTR pszVolumeName)
{
    HRESULT hr;
    HANDLE hVolumeInstanceFind;
    INSTANCE_INFORMATION_CLASS InfoClass;
    PVOID pBuffer;

    if( g_wVersion >= _WIN32_WINNT_VISTA )
        InfoClass = InstanceAggregateStandardInformation;
    else
        InfoClass = InstanceFullInformation;

    hr = _FindFirst_VolumeInstance(pszVolumeName,InfoClass,
                (PVOID *)&pBuffer,&hVolumeInstanceFind);

    if( hr == S_OK )
    {
        do
        {
            if( g_wVersion >= _WIN32_WINNT_VISTA )
            {
                INSTANCE_AGGREGATE_STANDARD_INFORMATION *piasi 
                    = (INSTANCE_AGGREGATE_STANDARD_INFORMATION *)pBuffer;

                if( piasi->Flags == FLTFL_IASI_IS_MINIFILTER )
                {
                    print_string("\tInstance Name: ",piasi,
                        piasi->Type.MiniFilter.InstanceNameBufferOffset,
                        piasi->Type.MiniFilter.InstanceNameLength);

                    print_string("\tFilter Name  : ",piasi,
                        piasi->Type.MiniFilter.FilterNameBufferOffset,
                        piasi->Type.MiniFilter.FilterNameLength);

                    print_string("\tAltitude     : ",piasi,
                        piasi->Type.MiniFilter.AltitudeBufferOffset,
                        piasi->Type.MiniFilter.AltitudeLength);

                    printf("\n");
                }
                else if( piasi->Flags == FLTFL_IASI_IS_LEGACYFILTER )
                {
                    print_string("\tFilter Name  : ",piasi,
                        piasi->Type.LegacyFilter.FilterNameBufferOffset,
                        piasi->Type.LegacyFilter.FilterNameLength);

                    print_string("\tAltitude     : ",piasi,
                        piasi->Type.LegacyFilter.AltitudeBufferOffset,
                        piasi->Type.LegacyFilter.AltitudeLength);

                    printf("\n");
                }
            }
            else
            {
                INSTANCE_FULL_INFORMATION *pifi
                    = (INSTANCE_FULL_INFORMATION *)pBuffer;

                print_string("\tInstance Name: ",pifi,
                    pifi->InstanceNameBufferOffset,
                    pifi->InstanceNameLength);

                print_string("\tFilter Name  : ",pifi,
                    pifi->FilterNameBufferOffset,
                    pifi->FilterNameLength);

                print_string("\tAltitude     : ",pifi,
                    pifi->AltitudeBufferOffset,
                    pifi->AltitudeLength);

                printf("\n");
            }
            free(pBuffer);

            hr = _FindNext_VolumeInstance(hVolumeInstanceFind,
							InfoClass,(PVOID *)&pBuffer);
        }
        while( hr == S_OK );
    }
    else
    {
        printf("\tenum volume instance error: 0x%08X\n\n",hr);
    }
}

int __cdecl wmain(int /*argc*/, WCHAR* /*argv*/[])
{
    HRESULT hr;
    HANDLE hFilterFind;
    DWORD BytesReturned;

    WORD wVersion = LOWORD(GetVersion());
    g_wVersion = MAKEWORD(HIBYTE(wVersion),LOBYTE(wVersion));

    DWORD dwBufferSize = sizeof(FILTER_VOLUME_STANDARD_INFORMATION)
						 + (sizeof(WCHAR) * _VOLUME_NAME_LENGTH);
    FILTER_VOLUME_STANDARD_INFORMATION *lpBuffer =
						 (FILTER_VOLUME_STANDARD_INFORMATION *)malloc(dwBufferSize);
    if( lpBuffer == NULL )
        return -1;

    hr = FilterVolumeFindFirst(
                FilterVolumeStandardInformation,
                lpBuffer,
                dwBufferSize,
                &BytesReturned,
                &hFilterFind
                ); 

    if( hr == S_OK )
    {
        do
        {
            WCHAR sz[_VOLUME_NAME_LENGTH+1];
            WCHAR szDosDrive[MAX_PATH];

            memcpy(sz,lpBuffer->FilterVolumeName,lpBuffer->FilterVolumeNameLength);
            sz[ lpBuffer->FilterVolumeNameLength/sizeof(WCHAR) ] = UNICODE_NULL;

            if( FilterGetDosName(sz,szDosDrive,MAX_PATH) != S_OK )
            {
                szDosDrive[0] = 0;
            }

            if( szDosDrive[0] != L'\0' )
                printf("%S (%s:)\n",sz,szDosDrive);
            else
                printf("%S\n",sz);

            EnumVolumeInstance(sz);

            hr = FilterVolumeFindNext(
                        hFilterFind,
                        FilterVolumeStandardInformation,
                        lpBuffer,
                        dwBufferSize,
                        &BytesReturned
                        ); 
        }
        while( hr == S_OK );
    }
    else
    {
        printf("error: 0x%08X\n",hr);
    }

    free(lpBuffer);

    return 0;
}






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


前の5件 | -