2008年01月21日
川俣晶の縁側ソフトウェア技術雑記 total 12137 count

Vista Sidebar GadgetのSystem.Shell.ItemオブジェクトでZIPフォルダを処理させない方法 【訂正版】

Written By: 川俣 晶連絡先

 これは「Vista Sidebar GadgetのSystem.Shell.ItemオブジェクトでZIPフォルダを処理させない方法」が誤っていたことに対応する訂正版です。

問題 §

 Vista Sidebar GadgetのSystem.Shell.Itemオブジェクトに含まれるSHFolder.Itemsを用いてファイルとディレクトリを列挙するとき、ZIPフォルダもアイテムのisFolderプロパティがtrueになり、その内部のアイテムも列挙できます。

 このことは、一般のアプリでは致命的な問題を引き起こします。シェルはZIPフォルダ内のファイルを問題なく扱えるとしても、一般アプリもそうとは限らないからです。そこで、通常のフォルダとZIPフォルダを区別するプログラミングが必要とされます。しかし、ZIPフォルダを明示的に区別するプロパティは見あたりません。

解決策その0・拡張子の判定 §

 拡張子.zipのフォルダを処理しない……という方法が最も容易です。

 しかし、この方法は以下の理由により不完全です。

  • シェルが処理する圧縮フォルダはZIPに限らず、CABやLZH(オプション)もある
  • 一般ユーザーが、通常のフォルダ名に"…….zip"という名前を付ける可能性がゼロではない

 以上の理由から、不特定多数の利用者が使うプログラムでは不十分であると考え、他の方法を模索しました。

解決策その1・FSO (FileSystemObject)を使う §

 WSH上のJScriptでしか確認を取っていませんが、FSOはシェルと直接関係がないのでZIPフォルダは単なるファイルとして認識されます。

サブフォルダの列挙でZIPファイルは出てこない §

   var fso, f, fc, s;

   fso = new ActiveXObject("Scripting.FileSystemObject");

   f = fso.GetFolder(".");

   fc = new Enumerator(f.SubFolders);

   s = "";

   for (; !fc.atEnd(); fc.moveNext())

   {

      s += fc.item();

      s += "<br>";

   }

   WScript.Echo(s);

ファイルの列挙でZIPファイルは出てくる §

   var fso, f, f1, fc, s;

   fso = new ActiveXObject("Scripting.FileSystemObject");

   f = fso.GetFolder(".");

   fc = new Enumerator(f.files);

   s = "";

   for (; !fc.atEnd(); fc.moveNext())

   {

      s += fc.item();

      s += "<br>";

   }

   WScript.Echo(s);

参考にしたURL §

JScript 8.0 ActiveXObject オブジェクト

Scripting ランタイム ライブラリ FileSystemObject の概要

解決策その2・isFileSystemを使う §

 Vista Sidebar GadgetのSystem.Shell.Itemオブジェクトに含まれるSHFolder.Itemsを用いてファイルとディレクトリを列挙する方法を踏襲します。このとき、isFileSystemプロパティは、ZIPフォルダ等のファイルシステム上のファイルではないアイテムの場合にfalseになります。

 このプロパティは、ZIPフォルダ内のフォルダではfalseになりますが、ZIPフォルダそのものはファイルシステム上のファイルであるためtrueになります。ですので、ZIPフォルダを弾く判定には使用できません。しかし、ZIPフォルダ内のファイルやフォルダを弾くためには使用できます。言い換えれば、ZIPフォルダ内を探索してしまうことは阻止できないものの、ZIPフォルダ内のファイルを拾い上げてしまうことは阻止できます。

 以下、コードの抜粋を以下に示します。

    var directoryItem = System.Shell.itemFromPath(path);

    var directoryFolder = directoryItem.SHFolder;

    var directoryCollection = directoryFolder.Items;

    for (var i = 0; i < directoryCollection.count; i++)

    {

        var item = directoryCollection.item(i);

        if( !item.isFileSystem ) continue;

感想 §

 JScriptからWin32 APIは叩けないようですが、COMオブジェクトは呼べます。

 おかげで、FSO経由という抜け道が見つかりました。

 時代遅れでもう使わないよ、などと思ってごめん。

 ありがとうFSO!

 ……しかしここまで調べておきながら、実際にAutumn's Random Music Playerの修正に使ったのは「解決策その2」の方だったという…… (汗。