From 31f9a112e5357f2ebd1398627d24e85950a0c834 Mon Sep 17 00:00:00 2001 From: dahall Date: Sun, 24 Jan 2021 19:01:13 -0700 Subject: [PATCH] Added ability to ShellAssociations from ShellItem and improved readability of exception handlers for ERROR_* conditions --- UnitTests/Windows.Shell/ShellAssocTests.cs | 14 ++++++++++++++ Windows.Shell/Registration/ShellAssociation.cs | 17 +++++++++++------ Windows.Shell/ShellObjects/ShellItem.cs | 11 +++++++++-- 3 files changed, 34 insertions(+), 8 deletions(-) diff --git a/UnitTests/Windows.Shell/ShellAssocTests.cs b/UnitTests/Windows.Shell/ShellAssocTests.cs index 7b5b3b56..9c964abe 100644 --- a/UnitTests/Windows.Shell/ShellAssocTests.cs +++ b/UnitTests/Windows.Shell/ShellAssocTests.cs @@ -1,5 +1,6 @@ using NUnit.Framework; using System; +using Vanara.PInvoke.Tests; using static Vanara.PInvoke.Shell32; namespace Vanara.Windows.Shell.Tests @@ -16,6 +17,19 @@ namespace Vanara.Windows.Shell.Tests Assert.That(sha.Handlers, Has.One.Property("UIName").EqualTo("Excel")); } + [Test] + public void ExamineShellItemAssoc() + { + using var shi = ShellItem.Open(TestCaseSources.TempDir); + var sha = shi.Association; + sha.WriteValues(); + foreach (var h in sha.Handlers) + { + TestContext.WriteLine(new string('=', 40)); + h.WriteValues(); + } + } + [Test] public void ReadProgIDTest() { diff --git a/Windows.Shell/Registration/ShellAssociation.cs b/Windows.Shell/Registration/ShellAssociation.cs index c9a1ac2a..38450fb5 100644 --- a/Windows.Shell/Registration/ShellAssociation.cs +++ b/Windows.Shell/Registration/ShellAssociation.cs @@ -15,6 +15,11 @@ namespace Vanara.Windows.Shell { private IQueryAssociations qassoc; + /// Initializes a new instance of the class. + /// The IQueryAssociations instance to use. + /// The optional file extension. This should be in the ".ext" format. + internal ShellAssociation(IQueryAssociations pQA, string ext) : this(ext) => qassoc = pQA; + /// Initializes a new instance of the class. /// The file extension. This should be in the ".ext" format. private ShellAssociation(string ext) => Extension = ext; @@ -69,7 +74,7 @@ namespace Vanara.Windows.Shell if (SHAssocEnumHandlers(Extension, ASSOC_FILTER.ASSOC_FILTER_NONE, out var ieah).Failed) return (IReadOnlyList)new List(); using var pieah = ComReleaserFactory.Create(ieah); - var e = new Vanara.Collections.IEnumFromCom(ieah.Next, () => { }); + var e = new Collections.IEnumFromCom(ieah.Next, () => { }); return (IReadOnlyList)e.Select(i => new ShellAssociationHandler(i)).ToList(); } } @@ -116,7 +121,7 @@ namespace Vanara.Windows.Shell /// Gets the command verbs for this file association. /// Returns a value. - public IReadOnlyDictionary Verbs => throw new NotImplementedException(); // TODO + public IReadOnlyDictionary Verbs => null; //throw new NotImplementedException(); // TODO /// Initializes a new instance of the class based on the supplied executable name. /// The full path of the application executable. @@ -152,7 +157,7 @@ namespace Vanara.Windows.Shell /// parameter to if it is not used. /// /// A value that, when this method returns successfully, receives the requested data value. - public Vanara.InteropServices.SafeCoTaskMemHandle GetData(ASSOCDATA data, string extra = null) + public SafeCoTaskMemHandle GetData(ASSOCDATA data, string extra = null) { try { @@ -160,11 +165,11 @@ namespace Vanara.Windows.Shell var sz = 0U; qassoc.GetData(flags, data, extra, default, ref sz); if (sz == 0) return null; - var ret = new Vanara.InteropServices.SafeCoTaskMemHandle(sz); + var ret = new SafeCoTaskMemHandle(sz); qassoc.GetData(flags, data, extra, ret, ref sz); return ret; } - catch (System.Runtime.InteropServices.COMException e) when (e.ErrorCode == (HRESULT)(Win32Error)Win32Error.ERROR_NO_ASSOCIATION) + catch (System.Runtime.InteropServices.COMException e) when (e.ErrorCode == HRESULT.HRESULT_FROM_WIN32(Win32Error.ERROR_NO_ASSOCIATION)) { return null; } @@ -204,7 +209,7 @@ namespace Vanara.Windows.Shell qassoc.GetString(flags, astr, extra, sb, ref sz); return sb.ToString(); } - catch (System.Runtime.InteropServices.COMException e) when (e.ErrorCode == (HRESULT)(Win32Error)Win32Error.ERROR_NO_ASSOCIATION) + catch (System.Runtime.InteropServices.COMException e) when (e.ErrorCode == HRESULT.HRESULT_FROM_WIN32(Win32Error.ERROR_NO_ASSOCIATION)) { return null; } diff --git a/Windows.Shell/ShellObjects/ShellItem.cs b/Windows.Shell/ShellObjects/ShellItem.cs index a539b49d..69b2a130 100644 --- a/Windows.Shell/ShellObjects/ShellItem.cs +++ b/Windows.Shell/ShellObjects/ShellItem.cs @@ -403,6 +403,11 @@ namespace Vanara.Windows.Shell remove { ((INotifyPropertyChanged)Properties).PropertyChanged -= value; } } + /// Gets the associations defined in the registry for this shell item. + /// The shell associations. + public ShellAssociation Association => + new ShellAssociation(GetHandler(BHID.BHID_AssociationArray), FileInfo?.Extension); + /// Gets the attributes for the Shell item. /// The attributes of the Shell item. public ShellItemAttribute Attributes => (ShellItemAttribute)(iShellItem?.GetAttributes((SFGAO)0xFFFFFFFF) ?? 0); @@ -817,11 +822,13 @@ namespace Vanara.Windows.Shell internal static string GetStringValue(Action method, int buffSize = MAX_PATH) { + var ret = new StringBuilder(buffSize); while (true) { - var ret = new StringBuilder(buffSize, buffSize); try { method(ret, ret.Capacity); } - catch (COMException ex) { if (ex.ErrorCode == unchecked((int)0x8007007A) || ex.ErrorCode == unchecked((int)0x800700EA) || buffSize <= 8192) buffSize *= 2; else throw; } + catch (COMException ex) when (ex.ErrorCode == HRESULT.HRESULT_FROM_WIN32(Win32Error.ERROR_INSUFFICIENT_BUFFER) || + ex.ErrorCode == HRESULT.HRESULT_FROM_WIN32(Win32Error.ERROR_MORE_DATA) || ret.Capacity <= 8192) + { ret.Capacity *= 2; } return ret.ToString(); } }