2017-12-21 65 views
0

그물에있는 모든 샘플 코드는 열거 인터페이스 Next() 호출의 첫 번째 인수로 1을 전달하는 습관에 의문을 제기하지 않습니다. 그러나 문서에서는 하나의 호출에서 하나 이상의 항목을 얻을 수 있다고 분명히 약속합니다. 이 코드 조각에서 볼 수 있듯이 이렇게하면 폴더의 파일 계산 프로세스가 상당히 빨라집니다 (실제로는 근본적으로 비슷한 WPD 인터페이스가 그렇게 작동합니다).다음> 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 초 밖에 걸리지 않았습니다. 두 번째는 이미 3에서 4까지 캐시 된 데이터입니다. 말할 필요도없이 두 번째 파일도 단순한 파일 수에는 용납되지 않지만 15 초는 절대 바보입니다. WPD의 평범하지 않은 속도이지만 100 단계 카운트, 최대 100ms. 새로운 C# 7.2 기능

+0

질문에 대한 답을 모르겠지만 기능에 'out'매개 변수로 전달되는 로컬 변수에 아무 것도 지정하지 않아도됩니다. –

+0

음, khhm, 너 어디서 그런거야? -- 바로 이거 야. 당신의 경우, pidl이 미리 정의되어 있다면 거기에는 유형이 없습니다. 그래서 MSDN 문서가 완벽하다는 것을 절대적으로 확실하게 확신 할 수 없다고 말한 것입니다. –

+0

doc에서는 celt 요소의 배열을 할당해야하지만 배열 만 할당해야한다고 명시되어 있습니다. 배열의 항목은 null 일 수도 있고 아닐 수도 있지만 반환 할 때 할당되거나 할당되지 않습니다. 따라서 가져온 문자열을 반복하여 하나씩 해제해야합니다. 또한, 인터페이스 구현자가 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); 
} 

. 불행하게도 실제로 그렇게 빠르지는 않습니다 ...