ファイルを列挙する<前|次>ファイルを列挙するフォルダやエクスプローラーのようないわゆる「ファイラー」を作製してしまおうというのが今度のシリーズです。この講座を終えると、結構しっかりとしたファイラーが作れてしまう......らしいです、はい。その第1回目に当たる今回は、ファイルの列挙という、言ってみれば最も基礎的な部分の実現方法を紹介しましょう。Namesというページを参考にしています。APIとインターフェイス通常、ファイルを列挙する場合にはFindFirstFile()とFindNextFile()というふたつのAPIを使用します。このふたつの関数には「使いやすい」「ワイルドカードを使用できる」「同時にファイルデータを取得できる」といったメリットがあります。このAPIではデスクトップやマイコンピュータといった特殊なフォルダのファイルを取得できません。これらのファイルの取得にはインターフェイスを使用しなければならないのです。言っても、この方法は扱いが面倒だというデメリットがあるので、もしFindFirstFile()等で十分なのであれば、そちらの使用をお奨めします。ファイル操作を目的としてインターフェイスを使用する場合、中心となるのがITEMIDLIST構造体と、IShellFolderインターフェイスです。ITEMIDLIST構造体はファイルやフォルダを示す構造体です。パスという文字列ではないので、デスクトップやマイコンピュータなども示すことができます。前回までに何度か出てきているので知っているかもしれませんね。IShellFolderインターフェイスはフォルダを意味するインターフェイスです。このインターフェイスを使用することで、ファイルを列挙したり、そのファイルのファイル名やアイコンを取得することができます。このふたつは、次のような形で使用します。1:あるフォルダを示すアイテムIDを取得する2:そのアイテムIDをIShellFolderにバインドする3:IShellFolder::EnumObjects()を使ってファイルを列挙する列挙されたファイルはアイテムIDとして取得するので、再びIShellFolderにバインドすればどんどん深いフォルダへと進むことができるというわけです。今回のプロジェクトは、単純なSDIアプリケーションとします。作業の中心となるクラスはビュークラスとします。必要なファイルのインクルードです。インクルードするファイルはshlobj.hです。このファイルをインクルードすれば、インターフェイス関係はすべてOKです。StdAfx.hの中でインクルードしてください。次にIMallocインターフェイスの取得です。フォルダを選択するダイアログ(前編)で説明しましたが、インターフェイスのほとんどは動的にメモリを確保し、返ってきたポインタを使用して操作するという形を取ります。その確保や解放を行うのがIMallocです。このインターフェイスは何度となく使用するので、メンバ変数として取っておきましょう。メンバ変数の宣言です。型はLPMALLOC、変数名はm_pMallocとしましょう(特に書きませんが、アクセス指定はすべてprivateとします)。なんでまたLPMALLOCってポインタなの、と思われるかもしれません。インターフェイスを使用する場合、そのほとんどをポインタを介して操作します。実際のオブジェクトを操作することは滅多にないと考えていいでしょう。ウィンドウやGDIオブジェクトを操作するときにハンドルを介するのと同じようなものです。このハンドルの場合と同じように、構築と消滅が必要です。構築、つまりIMallocへのポインタの取得にはSHGetMalloc()というAPIを使用します。今回のファイル操作を行うクラスのコンストラクタに次のコードを書き込んでください。);}たったこれだけでインターフェイスを取得できます。まー、ポインタのポインタを渡すとゆーかなり変な状況ではあるんですけどね......。インターフェイスの破棄は、そのインターフェイスのRelease()メソッド(クラスの「メンバ関数」とほぼ同じです)を使用すればOK。デストラクタで次のように破棄します。m_pMalloc->Release();}正確に言えば、「破棄」というのは間違いなんですが、でもその辺の難しいところは今のところ必要ないと思います、多分......。下準備はこれで終わり。同時に、インターフェイスの操作方法についてのおさらいもできたということで、さっそく本題に入っていくことにしましょう。デスクトップフォルダを取得するさて、まず最初に取得するのはデスクトップフォルダを示すIShellFolderインターフェイスです。このIShellFolderは、言ってみればフォルダの親分みたいなものです。実際、すべてのファイルのルートに位置するわけですが、このインターフェイスを使用するとどこにあるファイルでも操作することができるのです。このインターフェイスがあれば、どんなに深い場所に位置するフォルダでも簡単にバインドできるというわけです。このインターフェイスも所々で何度も使用するので、メンバ変数として持っておきましょう。型はLPSHELLFOLDER、変数名はm_pDTFolderとします。IMallocと同じような形で、取得と解放を行います。取得にはSHGetDesktopFolder()というAPIを使用します。これはSHGetMalloc()と構文的にまったく同じなので説明する必要はないでしょう。解放もIMallocと同じです。このふたつは、すでにIMallocのコードと一緒に書いてあるので確認しておいてください。アイテムIDを取得するフォルダにバインドするアイテムIDの取得には、いくつか方法があります。「デスクトップフォルダ」ですが、これは必要ありません。SHGetDesktopFolder()で、アイテムIDどころかIShellFolderが取得できてしまうのですから。通常のフォルダはどうでしょう。パスをフォルダに変換する場合には、実はIShellFolderのParseDisplayName()というメソッドを使用します。なんで直接バインドできないんだとか思いますが、それは置いといて、次の関数でアイテムIDへの変換を行えます。NULL;HRESULThRes;ULONGchEaten;//文字列のサイズを受け取ります。ULONGdwAttributes;//属性を受け取ります。OLECHARochPath[MAX_PATH];//ワイドバイト文字列です。LPITEMIDLISTpIDL;//フォルダを示すアイテムIDです。これをしないとインターフェイスはダメなのです。実際にITEMIDLISTを取得します。pIDL;//取得したアイテムIDを返します。}と、実はこのコードはファイルパスからアイテムIDを取得するで紹介したものとほとんど同じです。違いは、デスクトップフォルダが最初に取得したメンバ変数の物を使用しているというくらいです。一度見直してみましょう。インターフェイスではUnicodeを使用します。そのため、MultiByteToWideChar()というAPIを使用して文字列を変換します。変換したあと、IShellFolder::ParseDisplayName()メソッドを使用してアイテムIDを取得します。これで、パスからアイテムIDに変換できました。このように、IShellFolderが持つメソッドにはファイルの情報を取得するメソッドがいくつかあります。これらについてはまた後ほど紹介しましょう。アイテムIDの取得方法はもうひとつあります。それはSHGetSpecialFolderLocation()というAPIを使用する方法です。この関数を使用すると、ゴミ箱やコントロールパネルといった特殊なフォルダを示すアイテムIDを直接取得することができます。この関数は「フォルダを選択するダイアログ」にも利用できます。「スタートメニュー」のフォルダを取得して、それをルートに指定すれば、インストーラに見られるようなダイアログが簡単に作製できるでしょう。ここからの処理をまとめた関数を紹介します。作ってない関数もあるので、このままではコンパイルできませんから。ファイルのリストを作製します。IShellFolderにバインドします。デスクトップフォルダを指定します。IEnumIDListを取得します。IEnumIDListからアイテムIDを取得していきます。