2017-12-21 96 views
0

ネット上のどこのサンプルコードでも、列挙インターフェイスNext()コールの最初の引数として1を渡す習慣は疑問ではありません。しかし、ドキュメントは、1回の呼び出しで複数の項目を取得できることを明確に約束しています。このコードの断片で分かるように、そうすることで、フォルダ内のファイルを数えるプロセスが大幅に高速化されます(実際は、基本的に似たWPDインターフェイスがそのように機能します)。次> 1でシェルを列挙する1

string FolderPath = @"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\<Phone-USB-ID>\Internal storage\Pictures\Test"; 
SHCreateItemFromParsingName(FolderPath, IntPtr.Zero, typeof(IShellItem).GUID, out IShellItem item); 
item.BindToHandler(IntPtr.Zero, BHID_SFObject, typeof(IShellFolder).GUID, out IShellFolder folder); 
folder.EnumObjects(IntPtr.Zero, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, out IEnumIDList list); 
uint count = 0; 
try { 
    do { 
    //var ObjectIDs = new ObjectIDLargeArray(); 
    //var pidl = Marshal.AllocHGlobal(Marshal.SizeOf(ObjectIDs)); 
    //Marshal.StructureToPtr(ObjectIDs, pidl, true); 
    //var pidl = Marshal.AllocCoTaskMem(100 * IntPtr.Size); 
    int hr = list.Next(100, out var pidl, out uint fetched); // <<<<< 
    if (hr == 0) 
     count += fetched; 
    if (fetched == 0) 
     break; 

    //Marshal.FreeHGlobal(pidl); 
    Marshal.FreeCoTaskMem(pidl); 
    } 
    while (true); 
} 
catch (Exception e) { 
    Console.WriteLine(e); 
} 

[StructLayout(LayoutKind.Sequential)] 
internal class ObjectIDLargeArray { 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)] 
    public IntPtr[] IDs; 
} 

ドキュメントおよびウェブ上の使用が発信者がIDのバッファを割り当てる必要があるかどうかについて全く明らかではないが返されるが、コードからわかるように、私は両方の特定の配列、すべてのアプローチを試みましたメモリの割り当てられたブロック。 2と3のような非常に小さな値の場合、シェルは単にfetchedにゴミを返すかもしれません。それ以上のものは、アクセス違反の例外です。

新しく接続された電話機では、以前のキャッシングはなく、500枚の写真のフォルダ内のファイルを数えると約15秒です。データがすでにキャッシュされている2回目は、3から4です。言うまでもなく、2番目のファイルでも単なるファイル数では受け入れられませんが、15秒は絶対にばかげています。それ以外のWPDの速度は普通ですが、100ステップカウントでは数百msです。新しいC#7.2の機能の

+0

私はあなたの質問に対する答えはわかりませんが、関数に 'out'パラメータとして渡されたローカル変数には何も割り当てられていません。 –

+0

さて、khhm、あなたはどこにそんなものを見ますか? - ああ、そうだ。あなたの中で、もしpidlがあらかじめ定義されていれば、そこには型がありません。だから私は、MSDNドキュメントが完璧であることを絶対に確実にすることはできないと言いました。 –

+0

文書には、celt要素の配列を割り当てる必要があることが明確に記載されていますが、配列のみが割り当てられています。配列内の項目はnullでもかまいませんが、返されると割り振られます(そうでない場合はフェッチされたものをループして1つずつ解放する必要があります)。また、たとえインタフェース実装者がcelt> 1をサポートしていても、必ずしもそうであるとは限りません。そうでなければ、あなたは10を要求し、それは1にフェッチされた(または0)を入れます –

答えて

0

解決礼儀、inパラメータ:それは事前に割り当てられたアレイと単一の値の場合の両方で、すべての権利を果たします

internal interface IEnumIDList { 
    [PreserveSig] 
    [MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)] 
    HResult Next(uint celt, in IntPtr rgelt, out uint pceltFetched); 
} 

。残念ながらもっと速くはありません。