From 902ccfeeeb3137d816c123eb79f9b4c379cdff37 Mon Sep 17 00:00:00 2001 From: dahall Date: Tue, 14 Jun 2022 10:00:51 -0600 Subject: [PATCH] Fixed parameters of functions in INamespaceWalk --- PInvoke/Shell32/ShObjIdl.INamespaceWalk.cs | 4 +- UnitTests/PInvoke/Shell32/ExplorerTests.cs | 115 +++++++++++++++++++++++++++-- 2 files changed, 112 insertions(+), 7 deletions(-) diff --git a/PInvoke/Shell32/ShObjIdl.INamespaceWalk.cs b/PInvoke/Shell32/ShObjIdl.INamespaceWalk.cs index 5b2ebf34..24815178 100644 --- a/PInvoke/Shell32/ShObjIdl.INamespaceWalk.cs +++ b/PInvoke/Shell32/ShObjIdl.INamespaceWalk.cs @@ -217,7 +217,7 @@ namespace Vanara.PInvoke // https://docs.microsoft.com/en-us/windows/desktop/api/shobjidl_core/nf-shobjidl_core-inamespacewalk-walk HRESULT Walk( IUnknown // *punkToWalk, DWORD dwFlags, int cDepth, INamespaceWalkCB *pnswcb ); [PreserveSig] - HRESULT Walk([In, MarshalAs(UnmanagedType.IUnknown)] object punkToWalk, NAMESPACEWALKFLAG dwFlags, int cDepth, [In] INamespaceWalkCB pnswcb); + HRESULT Walk([In, MarshalAs(UnmanagedType.IUnknown)] object punkToWalk, NAMESPACEWALKFLAG dwFlags, int cDepth, [In, Optional] INamespaceWalkCB pnswcb); /// Gets a list of objects found during a namespace walk initiated by INamespaceWalk::Walk. /// @@ -249,7 +249,7 @@ namespace Vanara.PInvoke // https://docs.microsoft.com/en-us/windows/desktop/api/shobjidl_core/nf-shobjidl_core-inamespacewalk-getidarrayresult HRESULT // GetIDArrayResult( UINT *pcItems, PIDLIST_ABSOLUTE **prgpidl ); [PreserveSig] - HRESULT GetIDArrayResult(out uint pcItems, [In, Out, MarshalAs(UnmanagedType.LPArray, SizeConst = 0)] IntPtr[] prgpidl); + HRESULT GetIDArrayResult(out uint pcItems, out InteropServices.SafeCoTaskMemHandle prgpidl); } /// diff --git a/UnitTests/PInvoke/Shell32/ExplorerTests.cs b/UnitTests/PInvoke/Shell32/ExplorerTests.cs index 3ef77546..0a68d7db 100644 --- a/UnitTests/PInvoke/Shell32/ExplorerTests.cs +++ b/UnitTests/PInvoke/Shell32/ExplorerTests.cs @@ -1,14 +1,119 @@ using NUnit.Framework; using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Threading; +using Vanara.InteropServices; +using static Vanara.PInvoke.Shell32; -namespace Vanara.PInvoke.Tests +namespace Vanara.PInvoke.Tests; + +[TestFixture] +public class ExplorerTests { - [TestFixture] - public class ExplorerTests + [Test] + public void WalkNamespaceTest1() { - // TODO: [Test] - public void GetExplTest() + using var pFolder = ComReleaserFactory.Create(new MyDocuments() as IShellFolder2); + INamespaceWalk walk = new(); + WalkerCallback callback = new("Progress Title", "Cancel"); + List mycnt = new(); + callback.ItemFound += (f, p) => mycnt.Add(pFolder.Item.GetDisplayNameOf(SHGDNF.SHGDN_FORPARSING, p)); + Assert.That(walk.Walk(pFolder.Item, NAMESPACEWALKFLAG.NSWF_NONE_IMPLIES_ALL | NAMESPACEWALKFLAG.NSWF_DONT_ACCUMULATE_RESULT | NAMESPACEWALKFLAG.NSWF_SHOW_PROGRESS, 0, callback), ResultIs.Successful); + Assert.That(mycnt.Count, Is.GreaterThan(0)); + mycnt.WriteValues(); + } + + [Test] + public void WalkNamespaceTest2() + { + using var pFolder = ComReleaserFactory.Create(new MyDocuments() as IShellFolder2); + INamespaceWalk walk = new(); + Assert.That(walk.Walk(pFolder.Item, NAMESPACEWALKFLAG.NSWF_NONE_IMPLIES_ALL, 0), ResultIs.Successful); + Assert.That(walk.GetIDArrayResult(out var cnt, out var ppidls), ResultIs.Successful); + foreach (var pidl in ppidls.ToEnumerable((int)cnt).Select(p => new PIDL(p))) + TestContext.WriteLine(pFolder.Item.GetDisplayNameOf(SHGDNF.SHGDN_NORMAL, pidl)); + } + + [Test] + public void WalkNamespaceTest3() + { + using var pFolder = ComReleaserFactory.Create(new MyDocuments() as IShellFolder2); + ShellNamespaceWalker walker = new(pFolder.Item, 0, NAMESPACEWALKFLAG.NSWF_NONE_IMPLIES_ALL | NAMESPACEWALKFLAG.NSWF_DONT_ACCUMULATE_RESULT); + var items = walker.ToArray(); + Assert.That(items, Has.Length.GreaterThanOrEqualTo(30)); + items.WriteValues(); + } + + + public class ShellNamespaceWalker : IEnumerable, IAsyncEnumerable + { + private readonly object objToWalk; + private readonly int depth; + private readonly NAMESPACEWALKFLAG flags; + + public ShellNamespaceWalker(object objToWalk, int depth, NAMESPACEWALKFLAG flags) { + this.objToWalk=objToWalk; + this.depth=depth; + this.flags=flags; } + + IAsyncEnumerator IAsyncEnumerable.GetAsyncEnumerator(CancellationToken cancellationToken) => throw new NotImplementedException(); + + IEnumerator IEnumerable.GetEnumerator() + { + INamespaceWalk walk = new(); + var callback = new WalkerCallback(); + Queue q = new(); + bool done = false; + AutoResetEvent evt = new(false); + callback.ItemFound += (f, p) => { lock (q) { q.Enqueue(SHCreateItemFromIDList(p)); } evt.Set(); }; + callback.Completed += hr => { done = true; evt.Set(); }; + walk.Walk(objToWalk, flags | NAMESPACEWALKFLAG.NSWF_ASYNC, depth, callback).ThrowIfFailed(); + while (!done && evt.WaitOne()) + { + lock (q) + { + while (q.Count > 0) + yield return q.Dequeue(); + } + } + } + + IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this).GetEnumerator(); + } + + class WalkerCallback : INamespaceWalkCB2, IActionProgress + { + private readonly string cancel; + private readonly string title; + + public WalkerCallback(string progressDlgTitle = "", string progressDlgCancelText = "Cancel") + { + cancel=progressDlgCancelText; + title=progressDlgTitle; + } + + public event Action ItemFound; + public event Action FolderEntered; + public event Action FolderLeft; + public event Action Completed; + + public HRESULT FoundItem([In] IShellFolder psf, [In] IntPtr pidl) { ItemFound?.Invoke(psf, new PIDL(pidl, true)); return HRESULT.S_OK; } + public HRESULT EnterFolder([In] IShellFolder psf, [In] IntPtr pidl) { FolderEntered?.Invoke(psf, new PIDL(pidl, true)); return HRESULT.S_OK; } + public HRESULT LeaveFolder([In] IShellFolder psf, [In] IntPtr pidl) { FolderLeft?.Invoke(psf, new PIDL(pidl, true)); return HRESULT.S_OK; } + public HRESULT InitializeProgressDialog([MarshalAs(UnmanagedType.LPWStr), Out] out string ppszTitle, [MarshalAs(UnmanagedType.LPWStr), Out] out string ppszCancel) + { ppszTitle = title; ppszCancel = cancel; return HRESULT.S_OK; } + public HRESULT WalkComplete(HRESULT hr) { Completed?.Invoke(hr); return HRESULT.S_OK; } + + public void Begin(SPACTION action, SPBEGINF flags) { } + public void UpdateProgress(ulong ulCompleted, ulong ulTotal) { } + public void UpdateText(SPTEXT sptext, [In, MarshalAs(UnmanagedType.LPWStr)] string pszText, [MarshalAs(UnmanagedType.Bool)] bool fMayCompact) { } + public bool QueryCancel() => false; + public void ResetCancel() { } + public void End() { } } } \ No newline at end of file