ファイルアトリビュート

 操作した後は、ファイルの情報を取得しましょう(別に後でなくてもいーけど)。

ファイル名の取得
 IShellFolder::GetDisplayNameOf()を使用しましょう。以上復習でした。
(注:どうやらSHGDN_NORMALを立てているにも関わらずフルパスが返ってくることがあるみたいです。特に、デスクトップフォルダとフルパスを示すアイテムIDリストの場合に起きるようです。そういう場合には_tsplitpath()などを使って分割しましょう。)

フルパスの取得
 こちらはいくつか方法があるので、それぞれの長所と短所を見てみましょう。

 まず、ファイル名の取得と同じようにIShellFolder::GetDisplayNameOf()を使用する方法。メリットは親フォルダがあれば、アイテムIDリストはフルパスでなくてもいいという点、デメリットは親フォルダを示すIShellFolderが必要という点でしょう。
 その点SHGetPathFromIDList()親フォルダが必要ありませんが、アイテムIDリストはフルパスである必要があります
 このふたつは結果としては同じです。これら以外の方法としてはアイテムIDリストを渡り歩くというものがあります。ひとつひとつ抜き出してファイル名表示していくというわけです。これだと「デスクトップからのフルパス」が表示されるので、階層を見失うことがありません。その反面、普通のパスとは違うので(ルートはマイコンピュータ、ドライブはボリューム名)IShellFolder::ParseDisplayName()でそのままアイテムIDリストに変換できないのが残念です。

 これらの3つの方法のうちから、状況に応じて使い分けてください。

アイコンの取得
 アイコンの取得にはSHGetFileInfo()を使用します。IExtractIconを使っても取得できるのですが、こっちの方が楽なんで。


HICON CT_Filer2View::GetIcon( LPITEMIDLIST p_pidlFile )
{
	if( p_pidlFile == NULL )
		return NULL;

	HICON		hIcon;
	HIMAGELIST	hImgList;
	SHFILEINFO  stSHFileInfo;
	CImageList	cImgList;

	// システムイメージリストと、アイコンのインデックスを取得します。
	hImgList = (HIMAGELIST)::SHGetFileInfo( (LPCSTR)p_pidlFile, 0, &stSHFileInfo, sizeof( SHFILEINFO )
		, SHGFI_PIDL | SHGFI_ICON | SHGFI_SMALLICON | SHGFI_SYSICONINDEX );

	cImgList.Attach( hImgList );
	hIcon = cImgList.ExtractIcon( stSHFileInfo.iIcon );
	cImgList.Detach();

	return hIcon;
}
	

 SHGetFileInfo()に上のようなフラグを渡すことで、戻り値にシステムイメージリストへのハンドルが返ってきます。このイメージリストはウィンドウズが内部的に持っているイメージリストで、スタートメニューやエクスプローラーのアイコンもこの中に入っています。
 このシステムイメージリストを使用するメリットは、なんと言っても速い!! ということに尽きるでしょう。なんせすでにメモリの中に存在するものなので、そこからアイコンハンドルをコピーしてくるだけですから。
 注意すること。絶対にイメージリストは削除しない! 何度か他のところでも書いてますが、これ削除するとウィンドウズからアイコンが消えます(笑)。CImageList::Detach()を忘れずに書いておきましょう。失敗したらリブートです。
 あ、ここで渡すアイテムIDリストはフルパスです!! SHGetPathFromIDList()と同じ、APIですから。

細かい属性の取得
 細かい属性の取得にはIShellFolder::GetAttributesOf()を使用します。が、実際に試してみた感じでは、あまり信用できないような気がする……。
 もうひとつ、SHGetDataFromIDList()でもファイル属性が取得できます。こちらはWIN32_FIND_DATAFindFirstFile()とかで取得できるもの)が取得できます。が、属性についてはこちらもあまり信用できないような気が……。

 もう少し詳しく書くと、デスクトップのショートカットとか、マイコンピュータのドライブとかをうまく認識してくれません。そういった「特別の場合」のみ別にするのはちょっと大変かも……。

 結論、はっきり言って信用できるデータは得られません(汗)。

フォルダかどうかチェック!
 フォルダかどうかのチェックは、結構難しいと思います。実際、前述のような状況のため、フラグをチェックしても間違っていることが多々あります。
 また、IShellFolder::EnumObjects()でのSHCONTF_FOLDERSとSHCONTF_NONFOLDERSのフラグでは、なぜかマイコンピュータ内のドライブがどちらでも表示されてしまいました。

 そこで、筆者はIShellFolder::BindToObject()とIShellFolder::EnumObjects()を実際に試してみるということをしています。要するに、「フォルダの中身の取得」と同じことをすべてのファイルに試してみるわけです。成功したらフォルダ、失敗したらフォルダじゃない。当然のことですね。
 もちろん思いっきり力業ですが、試してみたところ、実際にはほとんど負担になりませんでした。細かいベンチマークを行えば違いが出るのでしょうけれども、少なくとも体感的には分かりませんでした(CPU133のメモリ64)。
 実際に試してみて、どんな感じかみてみてください。

ショートカットかどうかチェック!!
 まず、上の「フォルダかどうかのチェック」を行います。次にSHGetPathFromIDList()からフルパスを取得して、拡張子がlnkかどうかチェック。またもや力業だなぁ。でも、速くて確実な方法でしょう。ちなみにフォルダのチェックを行うのは、フォルダ名では普通にピリオドを使えるからです。つまりWindows.lnkとかいうフォルダ名もあり得るというわけです。

なんだ、これだけか?
 これだけです。ってゆーか、筆者にも分からないことは多いです。細かい属性が確実に取得できればなーとは思いますが、今のところ、そういったものは見つかってません(汗)。でも、実際に使用してみて、ちゃんと動いているんで大丈夫でしょう(大汗)。実際、このシェル関係は、すべてのPCで確実に動くとは考えない方がいいかもしんない……。
 次回はショートカットです。

(C)KAB-studio 1998 ALL RIGHTS RESERVED.