IEnumIDListの実装IShellFolderを取得した側は、フォルダのアイテムを列挙したくなった段階でIShellFolder::EnumObjectsを呼び出します。IEnumIDListを継承したクラスのオブジェクトが必要になります。m_uCount;};見て分かるように、IEnumIDListを継承したCEnumIDListというクラスを定義しています。このクラスを型としたオブジェクトをEnumObjectsで作成することになります。呼び出し側はIEnumIDListを通じてオブジェクトにアクセスできるようになります。コンストラクタの引数については後述します。CEnumIDList::Nextの実装はPIDLを返すようになっていなければなりません。そのアイテムのデータを定義する必要があります。今回は、1つのアイテムをITEMDATA構造体で識別することにします。szName[10];};ubは、この構造体のサイズを指定します。levelは、このアイテムが存在することになるレベル(フォルダの階層)を指定します。1であるアイテムは1つの下のフォルダで表示されます。iconIndexは、アイテムのアイコンのインデックスを指定します。attributeは、アイテムの属性を指定します。SFGAO_FOLDERが含まれる場合、そのアイテムはフォルダであると認識します。szNameは、アイテムの名前を指定します。ITEMDATA構造体の先頭にサイズを受け取るメンバが存在するのには理由があります。それは、この構造体をPIDLとして扱いたい(キャストしたい)からです。PIDLはITEMIDLIST構造体のポインタであり、ITEMIDLIST構造体にはSHITEMID構造体が含まれています。SHITEMID;cbは、自身と可変長データのサイズの合計が格納されます。ITEMDATA構造体の先頭にもcbを含めるようにしています。abIDは配列の要素数が1になっていますが、これはこのメンバが可変長データの先頭であることを示す指標に過ぎません。当然ながら先に示したITEMDATA構造体のlevelメンバ以降のデータでも問題はありません。次のコードは、ITEMDATA構造体を使用して各アイテムを定義しています。sizeof(g_itemData[0]);1番目のアイテムはlevelが0になっているため、最初フォルダを開いたときにはこのアイテムが表示されます。このアイテムは属性がSFGAO_FOLDERになっています。よって、アイテムを開くことで1つの下のフォルダに移動することになります。このフォルダで表示されるアイテムは、levelが1になっている3番目のアイテムになります。g_itemDataの要素数が3つになっているため、g_nItemCountの値は3になります。CEnumIDListのメソッドを順に見ていきます。コンストラクタからです。0;}第1引数であるlevelは、列挙の対象となっているフォルダの階層を示す値が格納されています。この値はメンバとして保存することになります。列挙の方法に関する定数が格納されています。この値もメンバとして保存することになります。m_uCountは、列挙をするに当たって確認したアイテムの数を格納することになります。列挙できたアイテムの数を格納するわけではないことに注意してください。IEnumIDListを取得した呼び出し側は、Nextを通じてアイテムを列挙することになります。これ以上アイテムを列挙できませんから制御を返すようにします。ループ文では、g_itemDataの各要素を確認するためにm_uCountを添え字として使用しています。そのアイテムは列挙しないようにします。次に、アイテムがフォルダであるかを調べ、フォルダである場合はフラグとしてSHCONTF_FOLDERSが指定されていないかを確認します。これが指定されていない場合はフォルダを列挙する必要がないということですから、continueでループの先頭に戻ることになります。アイテムが非フォルダである場合は、フラグとしてSHCONTF_NONFOLDERSが指定されていないかを確認します。これが指定されていない場合は非フォルダを列挙する必要がないということですから、continueでループの先頭に戻ることになります。g_itemData[m_uCount]が列挙できるアイテムであると判定できたならば、PIDLを作成するためのメモリを確保することになります。これはPIDLの終端2バイト0になっていなければならない決まりがあるからです。終端2バイトも0で埋まるようにしています。先に埋めておいた終端2バイトは0のままとなります。1つのアイテムを列挙したことを示すために*pceltFetchedに1を格納します。CEnumIDListには、Nextの他にResetやSkip、Cloneなどのメソッドが含まれています。念のために実装しておきます。Resetは、アイテムを最初から列挙したくなった場合に呼ばれるため、m_uCountに0を指定します。Cloneは、自身と同じCEnumIDListを必要とする際に呼ばれます。その引数は現在のオブジェクトのメンバを指定するようにします。これにより、新しいオブジェクトが現在のオブジェクトと同じデータを持つことができます。Skipを呼び出すことでm_uCountの値も現在のオブジェクトと同一にしておきます。