diff --git a/Windows.Shell/Registration/ShellAssociation.cs b/Windows.Shell/Registration/ShellAssociation.cs
index 4721d2e8..c9a1ac2a 100644
--- a/Windows.Shell/Registration/ShellAssociation.cs
+++ b/Windows.Shell/Registration/ShellAssociation.cs
@@ -1,7 +1,11 @@
using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Text;
+using Vanara.InteropServices;
+using Vanara.PInvoke;
+using static Vanara.PInvoke.Shell32;
using static Vanara.PInvoke.ShlwApi;
namespace Vanara.Windows.Shell
@@ -34,6 +38,12 @@ namespace Vanara.Windows.Shell
///
public string AppPublisher => GetString(ASSOCSTR.ASSOCSTR_APPPUBLISHER);
+ ///
+ /// Introduced in Internet Explorer 6. Describes a general type of MIME file association, such as image and bmp, so that
+ /// applications can make general assumptions about a specific file type.
+ ///
+ public string ContentType => GetString(ASSOCSTR.ASSOCSTR_CONTENTTYPE);
+
///
/// Introduced in Internet Explorer 6. Returns the path to the icon resources to use by default for this association. Positive
/// numbers indicate an index into the dll's resource table, while negative numbers indicate a resource ID. An example of the syntax
@@ -50,6 +60,20 @@ namespace Vanara.Windows.Shell
/// The friendly name of a document type.
public string FriendlyDocName => GetString(ASSOCSTR.ASSOCSTR_FRIENDLYDOCNAME);
+ /// Gets a list of file name extension handlers.
+ /// The handlers for this association.
+ public IReadOnlyList Handlers
+ {
+ get
+ {
+ 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, () => { });
+ return (IReadOnlyList)e.Select(i => new ShellAssociationHandler(i)).ToList();
+ }
+ }
+
///
/// Corresponds to the InfoTip registry value. Returns an info tip for an item, or list of properties in the form of an
/// IPropertyDescriptionList from which to create an info tip, such as when hovering the cursor over a file name. The list of
@@ -62,6 +86,15 @@ namespace Vanara.Windows.Shell
///
public ProgId ProgId => ProgId.Open(GetString(ASSOCSTR.ASSOCSTR_PROGID), true, true, true);
+ ///
+ /// Introduced in Internet Explorer 6. Corresponds to the QuickTip registry value. Same as ASSOCSTR_INFOTIP, except that it always
+ /// returns a list of property names in the form of an IPropertyDescriptionList. The difference between this value and
+ /// ASSOCSTR_INFOTIP is that this returns properties that are safe for any scenario that causes slow property retrieval, such as
+ /// offline or slow networks. Some of the properties returned from ASSOCSTR_INFOTIP might not be appropriate for slow property
+ /// retrieval scenarios. The list of properties can be parsed with PSGetPropertyDescriptionListFromString.
+ ///
+ public string QuickTip => GetString(ASSOCSTR.ASSOCSTR_QUICKTIP);
+
///
/// Introduced in Internet Explorer 6. For an object that has a Shell extension associated with it, you can use this to retrieve the
/// CLSID of that Shell extension object by passing a string representation of the IID of the interface you want to retrieve as the
@@ -73,27 +106,6 @@ namespace Vanara.Windows.Shell
/// Introduced in Windows 8.
public Guid? SupportedUriProtocols { get { try { return new Guid(GetString(ASSOCSTR.ASSOCSTR_SUPPORTED_URI_PROTOCOLS)); } catch { return null; } } }
- /// Gets the command verbs for this file association.
- /// Returns a value.
- public IReadOnlyDictionary Verbs => throw new NotImplementedException(); // TODO
-
- #region AllPropLists // TODO: Enhance
-
- ///
- /// Introduced in Internet Explorer 6. Describes a general type of MIME file association, such as image and bmp, so that applications
- /// can make general assumptions about a specific file type.
- ///
- public string ContentType => GetString(ASSOCSTR.ASSOCSTR_CONTENTTYPE);
-
- ///
- /// Introduced in Internet Explorer 6. Corresponds to the QuickTip registry value. Same as ASSOCSTR_INFOTIP, except that it always
- /// returns a list of property names in the form of an IPropertyDescriptionList. The difference between this value and
- /// ASSOCSTR_INFOTIP is that this returns properties that are safe for any scenario that causes slow property retrieval, such as
- /// offline or slow networks. Some of the properties returned from ASSOCSTR_INFOTIP might not be appropriate for slow property
- /// retrieval scenarios. The list of properties can be parsed with PSGetPropertyDescriptionListFromString.
- ///
- public string QuickTip => GetString(ASSOCSTR.ASSOCSTR_QUICKTIP);
-
///
/// Introduced in Internet Explorer 6. Corresponds to the TileInfo registry value. Contains a list of properties to be displayed for
/// a particular file type in a Windows Explorer window that is in tile view. This is the same as ASSOCSTR_INFOTIP, but, like
@@ -102,7 +114,9 @@ namespace Vanara.Windows.Shell
///
public string TileInfo => GetString(ASSOCSTR.ASSOCSTR_TILEINFO);
- #endregion AllPropLists // TODO: Enhance
+ /// Gets the command verbs for this file association.
+ /// Returns a value.
+ public IReadOnlyDictionary Verbs => throw new NotImplementedException(); // TODO
/// Initializes a new instance of the class based on the supplied executable name.
/// The full path of the application executable.
@@ -114,7 +128,9 @@ namespace Vanara.Windows.Shell
/// A instance if exists; otherwise.
public static ShellAssociation CreateFromCLSID(Guid classId) => CreateAndInit(0, classId.ToString("B"));
- /// Initializes a new instance of the class based on the supplied programmatic identifier (ProgId).
+ ///
+ /// Initializes a new instance of the class based on the supplied programmatic identifier (ProgId).
+ ///
/// The ProgId.
/// A instance if exists; otherwise.
public static ShellAssociation CreateFromProgId(string progId) => CreateAndInit(0, progId);
@@ -129,6 +145,71 @@ namespace Vanara.Windows.Shell
return CreateAndInit(ASSOCF.ASSOCF_INIT_DEFAULTTOSTAR, ext);
}
+ /// Searches for and retrieves file or protocol association-related binary data from the registry.
+ /// The ASSOCDATA value that specifies the type of data that is to be returned.
+ ///
+ /// An optional string with information about the location of the data. It is normally set to a Shell verb such as open. Set this
+ /// 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)
+ {
+ try
+ {
+ const ASSOCF flags = 0;
+ var sz = 0U;
+ qassoc.GetData(flags, data, extra, default, ref sz);
+ if (sz == 0) return null;
+ var ret = new Vanara.InteropServices.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)
+ {
+ return null;
+ }
+ }
+
+ /// Searches for and retrieves a file or protocol association-related key from the registry.
+ /// The ASSOCKEY value that specifies the type of key that is to be returned.
+ ///
+ /// An optional string with information about the location of the key. It is normally set to a Shell verb such as open. Set this
+ /// parameter to if it is not used.
+ ///
+ /// A handle to the resulting registry key.
+ public SafeRegistryHandle GetKey(ASSOCKEY key, string extra = null)
+ {
+ const ASSOCF flags = 0;
+ qassoc.GetKey(flags, key, extra, out var hkey);
+ return new SafeRegistryHandle((IntPtr)hkey, true);
+ }
+
+ /// Searches for and retrieves a file or protocol association-related string from the registry.
+ /// An ASSOCSTR value that specifies the type of string that is to be returned.
+ ///
+ /// An optional string with information about the location of the string. It is typically set to a Shell verb such as open. Set this
+ /// parameter to if it is not used.
+ ///
+ ///
+ /// A string used to return the requested string. If there are no results for this value, is returned.
+ ///
+ public string GetString(ASSOCSTR astr, string extra = null)
+ {
+ try
+ {
+ const ASSOCF flags = ASSOCF.ASSOCF_NOTRUNCATE | ASSOCF.ASSOCF_REMAPRUNDLL;
+ var sz = 0U;
+ qassoc.GetString(flags, astr, extra, null, ref sz);
+ var sb = new StringBuilder((int)sz, (int)sz);
+ 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)
+ {
+ return null;
+ }
+ }
+
private static ShellAssociation CreateAndInit(ASSOCF flags, string assoc)
{
// if (Environment.OSVersion.Version.Major >= 6)
@@ -148,21 +229,100 @@ namespace Vanara.Windows.Shell
}
}
- private SafeRegistryHandle GetKey(ASSOCKEY key, string extra = null)
+ /// Represents a handler (executable) for a .
+ public class ShellAssociationHandler : ComObjWrapper
{
- const ASSOCF flags = 0;
- qassoc.GetKey(flags, key, extra, out var hkey);
- return new SafeRegistryHandle((IntPtr)hkey, true);
- }
+ internal ShellAssociationHandler(IAssocHandler h) : base(h)
+ {
+ }
- private string GetString(ASSOCSTR astr, string extra = null)
- {
- const ASSOCF flags = ASSOCF.ASSOCF_NOTRUNCATE | ASSOCF.ASSOCF_REMAPRUNDLL;
- var sz = 0U;
- qassoc.GetString(flags, astr, extra, null, ref sz);
- var sb = new StringBuilder((int)sz, (int)sz);
- qassoc.GetString(flags, astr, extra, sb, ref sz);
- return sb.ToString();
+ /// Retrieves the location of the icon associated with the application.
+ ///
+ /// An instance that contains the path and the index of the icon within the resource file for the
+ /// application's icon.
+ ///
+ public IconLocation IconLocation => ComInterface.GetIconLocation(out var p, out var i).Succeeded ? new IconLocation(p, i) : null;
+
+ /// Indicates whether the application is registered as a recommended handler for the queried file type.
+ /// if this instance is recommended; otherwise, .
+ ///
+ ///
+ /// Applications that register themselves as handlers for particular file types can specify whether they are recommended
+ /// handlers. This has no effect on the actual behavior of the applications when launched. It is simply provided as a hint to
+ /// the user and a value that the UI can utilize programmatically, if desired. For example, the Shell's Open With dialog
+ /// separates entries into Recommended Programs and Other Programs.
+ ///
+ ///
+ /// Note that program recommendations may change over time. One example is provided when the user chooses an application from
+ /// the Other Programs of the Open With dialog to open a particular file type. That may cause the Shell to
+ /// "promote" that application to recommended status for that file type. Because the recommended status may change over time,
+ /// applications should not cache this value, but query it each time it is needed.
+ ///
+ ///
+ public bool IsRecommended => ComInterface.IsRecommended() == HRESULT.S_OK;
+
+ /// Retrieves the full path and file name of the executable file associated with the file type.
+ /// A string that contains the full path of the file, including the file name.
+ public string Name => ComInterface.GetName(out var n).Succeeded ? n : null;
+
+ /// Retrieves the display name of an application.
+ /// A string that contains the display name of the application.
+ public string UIName => ComInterface.GetUIName(out var n).Succeeded ? n : null;
+
+ /// Indicates whether the current object is equal to another object of the same type.
+ /// An object to compare with this object.
+ /// true if the current object is equal to the parameter; otherwise, false.
+ public override bool Equals(IAssocHandler other) => Name.Equals(other.GetName(out var n).Succeeded ? n : null);
+
+ /// Returns a hash code for this instance.
+ /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
+ public override int GetHashCode() => Name.GetHashCode();
+
+ /// Directly invokes the associated handler.
+ /// A sequence of selected items on which to invoke the handler.
+ ///
+ ///
+ /// IAssocHandler objects are typically used to populate an Open With menu. When one of those menu items is selected,
+ /// this method is called to launch the chosen application.
+ ///
+ /// Invoke and CreateInvoker
+ ///
+ /// The IDataObject used by these methods can represent either a single file or a selection of multiple files. Not all
+ /// applications support the multiple file option. The applications that do support that scenario might impose other
+ /// restrictions, such as the number of files that can be opened simultaneously, or the acceptable combination of file types.
+ ///
+ ///
+ /// Therefore, an application often must determine whether the handler supports the selection before trying to invoke the
+ /// handler. For example, an application might enable a menu item only if it has verified that the selection in question was
+ /// supported by that handler.
+ ///
+ ///
+ public void Invoke(params ShellItem[] items)
+ {
+ if (items.Length == 0)
+ throw new ArgumentException("", nameof(items));
+
+ if (items.Length == 1)
+ {
+ ComInterface.Invoke(new ShellDataObject(items)).ThrowIfFailed();
+ }
+ else
+ {
+ ComInterface.CreateInvoker(new ShellDataObject(items), out var invoker).ThrowIfFailed();
+ using var pInvoker = ComReleaserFactory.Create(invoker);
+ var hr = invoker.SupportsSelection();
+ if (hr == HRESULT.S_FALSE)
+ throw new ArgumentException("This handler is unable to support the selections provided.", nameof(items));
+ hr.ThrowIfFailed();
+ invoker.Invoke().ThrowIfFailed();
+ }
+ }
+
+ /// Sets an application as the default application for this file type.
+ ///
+ /// A string that contains the display name of the application.
+ ///
+ public void MakeDefault(string description) => ComInterface.MakeDefault(description).ThrowIfFailed();
}
}
}
\ No newline at end of file