IEnumIDList.Next メソッドで取得した pidl を保持する - IEnumIDList.Next メソッドで取得した pidlを保持して利用するとメモリーアクセスエラーになる - C#

IEnumIDList.Next メソッドで取得した pidl を保持するコードを紹介します。

概要

IEnumIDList.Next メソッドで取得した pidlを保存する場合は、代入では保存できません。これは、IEnumIDList.Next で取得されたpidlはCoTaskMemFree() (C#の場合はMarshal.FreeCoTaskMem())により解放されてしまうためです。
代入している場合は、CoTaskMemFree()呼び出し後は実体が解放されるため、メモリアクセスエラーになります。
pidlを保持する場合は、pidlを複製する必要があります。IEnumIDList.Next で取得されるPIDLは相対PIDLのため、複製には、ILClone() APIを利用します。もしくは、ILCombine APIで第一引数にNULLを与える方法でも動作します。

補足:絶対 PIDLを複製する場合

絶対PIDLを複製する場合は、ILCloneFull APIを利用します。または、ILCombine APIで第二引数にNULLを与える方法でも動作します。

コード例

  WindowsAPI.IEnumIDList pEnum = null;
  WindowsAPI.SHCONTF flags = WindowsAPI.SHCONTF.SHCONTF_FOLDERS | WindowsAPI.SHCONTF.SHCONTF_NONFOLDERS | WindowsAPI.SHCONTF.SHCONTF_INCLUDEHIDDEN;
  uint hRes = ShellFolder.EnumObjects(IntPtr.Zero, flags, out pEnum);
  if (hRes != 0) Marshal.ThrowExceptionForHR((int)hRes);

  IntPtr[] pIDL = new IntPtr[1];//IntPtr.Zero;
  Int32 iGot = 0;

  // Grab the first enumeration.
  pEnum.Next(1, pIDL, out iGot);

  // Then continue with all the rest.
  while (!pIDL.Equals(IntPtr.Zero) && iGot == 1) {
          
    // Free the PIDL and reset counters.
    Marshal.FreeCoTaskMem(pIDL[0]);

    //SavePidl
    pidl_store = WindowsAPI.ILClone(pIDL[0]);

    //pIDL = null;// IntPtr.Zero;
    iGot = 0;

    // Grab the next item.
    pEnum.Next(1, pIDL, out iGot);
  }

  // Free the interface pointer.
  if (pEnum != null) Marshal.ReleaseComObject(pEnum);
著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
最終更新日: 2024-01-07
作成日: 2015-06-12
iPentec all rights reserverd.