シェル名前空間とは、簡単に言うと通常のファイルシステムの上位概念のことです。
シェル名前空間のアイテムを識別するためのものがアイテム ID リストになります。
図と表にまとめるとこんな感じです。
ファイルシステム | シェル名前空間 | |
要素 | ファイル フォルダ | ファイル フォルダ 仮想フォルダ |
ルート | ドライブ名 | デスクトップ |
識別 | パス | アイテム ID リスト |
図を見てもらえばわかるとおり、シェル名前空間はコンピュータやネットワークなどの仮想フォルダと通常のファイルシステムを含んでいます。
デスクトップは通常のファイルシステムとシェル名前空間の両方に属していますが、それぞれの場合で役割が全く異なります。
ファイルシステムのデスクトップは通常のフォルダと変わりません。しかし、シェル名前空間のデスクトップはシェル名前空間のルートで、直下にコンピュータやネットワークを保持しています。
ITEMIDLIST LPITEMIDLIST //「絶対位置」を表すITEMIDLIST IDLIST_ABSOLUTE PIDLIST_ABSOLUTE PCIDLIST_ABSOLUTE //「相対位置」を表すITEMIDLIST IDLIST_RELATIVE PIDLIST_RELATIVE PCIDLIST_RELATIVE //「子要素」を表すITEMIDLIST PITEMID_CHILD PUITEMID_CHILD PCITEMID_CHILD PCUITEMID_CHILD //P:ポインタ //C:const //U:64-bit用
通常は ITEMIDLIST または IDLIST_ABSOLUTE を使い、用途を限定する場合に IDLIST_RELATIVE や PITEMID_CHILD を使うみたいです。
HRESULT SHGetSpecialFolderLocation( HWND hwndOwner, //NULLを指定 int nFolder, //取得したいアイテムIDリストのCSIDL PIDLIST_ABSOLUTE *ppidl //ここに格納される CoTaskMemFree()で解放する );
HRESULT SHGetKnownFolderIDList( REFKNOWNFOLDERID rfid, //取得したいアイテムIDリストのKNOWNFOLDERID DWORD dwFlags, //0でいい HANDLE hToken, //NULLでいい PIDLIST_ABSOLUTE *ppidl //ここに格納される ILFree()で解放する );
同様の方法でファイルパスを取得することもできます。
HRESULT SHGetKnownFolderPath( REFKNOWNFOLDERID rfid, //取得したいアイテムIDリストのKNOWNFOLDERID DWORD dwFlags, //0でいい HANDLE hToken, //NULLでいい PWSTR *ppsPath //ここに格納される CoTaskMemFree()で解放する );
CSIDL | KNOWNFOLDERID | 意味 |
CSIDL_DESKTOP(仮想フォルダ) CSIDL_DESKTOPDIRECTORY(ファイルシステム) | FOLDERID_Desktop | デスクトップ |
CSIDL_DRIVES | FOLDERID_ComputerFolder | コンピュータ |
CSIDL_CONTROLS | FOLDERID_ControlPanelFolder | コントロールパネル |
CSIDL_COMPUTERSNEARME CSIDL_NETWORK | FOLDERID_NetworkFolder | ネットワーク |
- | FOLDERID_HomeGroup | ホームグループ |
- | FOLDERID_Libraries | ライブラリ |
- | FOLDERID_DocumentsLibrary | ライブラリのドキュメント |
- | FOLDERID_PicturesLibrary | ライブラリのピクチャ |
- | FOLDERID_VideosLibrary | ライブラリのビデオ |
- | FOLDERID_MusicLibrary | ライブラリのミュージック |
CSIDL_BITBUCKET | FOLDERID_RecycleBinFolder | ごみ箱 |
その他に関しては msdn - CSIDLとか msdn - KNOWNFOLDERID を参照してください。
使い終わったアイテム ID リストは解放する必要があります。
void CoTaskMemFree( LPVOID pv );
void ILFree( PIDLIST_RELATIVE pidl );
アイテム ID リストとファイルパスは相互に変換することができます。ただし、仮想フォルダは変換できません。
BOOL SHGetPathFromIDList( PCIDLIST_ABSOLUTE pidl, //取得したいアイテム ID リスト(仮想フォルダ以外) LPTSTR pszPath //パスを受け取るバッファ );
PIDLIST_ABSOLUTE ILCreateFromPath( PCTSTR pszPath //対象のファイルパス );
ILCreateFromPath() で取得したアイテム ID リストは使い終わったら ILFree() で解放する必要があります。
BOOL ILIsEqual( PCIDLIST_ABSOLUTE pidl1, PCIDLIST_ABSOLUTE pidl2 );
一致ならTRUEを、不一致ならFALSEを返します。
アイテム ID リストからファイルパスを文字列として取得することができます。しかし、仮想フォルダの場合は文字列として取得するすべがありません(私が知らないだけかもしれません)。なので、これを可能にする関数を作成します。
KNOWNFOLDERID fid[11] = { FOLDERID_Desktop, FOLDERID_ComputerFolder, FOLDERID_ControlPanelFolder, FOLDERID_NetworkFolder, FOLDERID_HomeGroup, FOLDERID_Libraries, FOLDERID_DocumentsLibrary, FOLDERID_PicturesLibrary, FOLDERID_VideosLibrary, FOLDERID_MusicLibrary, FOLDERID_RecycleBinFolder }; TCHAR *stVirtual[11] = { TEXT("Desktop"), TEXT("Computer"), TEXT("ControlPanel"), TEXT("Network"), TEXT("HomeGroup"), TEXT("Liblary"), TEXT("Documents"), TEXT("Pictures"), TEXT("Videos"), TEXT("Music"), TEXT("ごみ箱") }; //アイテムIDリストからパスを作成 int ConvertPIDLToPath(PCIDLIST_ABSOLUTE pidlDir, LPTSTR lpDir, TCHAR *lpDrive) { for(int i=0; i<11; i++){ //仮想フォルダかどうかチェック PIDLIST_ABSOLUTE pidl; SHGetKnownFolderIDList(fid[i], 0, NULL, &pidl); if(ILIsEqual(pidlDir, pidl)){ //仮想フォルダ ILFree(pidl); lstrcpy(lpDir, stVirtual[i]); if(lpDrive != NULL) *lpDrive = 'C'; return 1; } } if(SHGetPathFromIDList(pidlDir, lpDir)){ //通常のフォルダ int n = PathGetDriveNumber(lpDir); if(lpDrive != NULL) *lpDrive = n + 'A'; return 2; }else{ //不明なフォルダ //ネットワークドライブなど lstrcpy(lpDir, TEXT("unknown")); if(lpDrive != NULL) *lpDrive = '@'; return 3; } } //パスからアイテムIDリストを作成 //ILFree()で解放する PIDLIST_ABSOLUTE ConvertPathToPIDL(LPCTSTR lpDir) { for(int i=0; i<11; i++){ if(lstrcmp(lpDir, stVirtual[i]) == 0){ //仮想フォルダのアイテムIDリストを返す PIDLIST_ABSOLUTE pidl; SHGetKnownFolderIDList(fid[i], 0, NULL, &pidl); return pidl; } } //通常のフォルダのアイテムIDリストを返す return ILCreateFromPath(lpDir); }