/* Copyright (C) 2008-2016 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ using System; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Security; using System.Text; namespace Alphaleonis.Win32.Filesystem { /// Contains Shell32 information about a file. [SerializableAttribute] [SecurityCritical] public sealed class Shell32Info { #region Constructors /// Initializes a Shell32Info instance. /// Shell32 is limited to MAX_PATH length. /// This constructor does not check if a file exists. This constructor is a placeholder for a string that is used to access the file in subsequent operations. /// /// The fully qualified name of the new file, or the relative file name. Do not end the path with the directory separator character. public Shell32Info(string fileName) : this(fileName, PathFormat.RelativePath) { } /// Initializes a Shell32Info instance. /// Shell32 is limited to MAX_PATH length. /// This constructor does not check if a file exists. This constructor is a placeholder for a string that is used to access the file in subsequent operations. /// /// The fully qualified name of the new file, or the relative file name. Do not end the path with the directory separator character. /// Indicates the format of the path parameter(s). public Shell32Info(string fileName, PathFormat pathFormat) { if (Utils.IsNullOrWhiteSpace(fileName)) throw new ArgumentNullException("fileName"); // Shell32 is limited to MAX_PATH length. // Get a full path of regular format. FullPath = Path.GetExtendedLengthPathCore(null, fileName, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck); Initialize(); } #endregion // Constructors #region Methods /// Gets an handle to the Shell icon that represents the file. /// Icon size or . Can also be combined with and others. /// An handle to the Shell icon that represents the file. /// Caller is responsible for destroying this handle with DestroyIcon() when no longer needed. [SecurityCritical] public IntPtr GetIcon(Shell32.FileAttributes iconAttributes) { return Shell32.GetFileIcon(FullPath, iconAttributes); } /// Gets the Shell command association from the registry. /// The shell verb. /// /// Returns the associated file- or protocol-related Shell command from the registry or string.Empty if no association can be /// found. /// [SecurityCritical] public string GetVerbCommand(string shellVerb) { return GetString(_iQaNone, Shell32.AssociationString.Command, shellVerb); } [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] [SecurityCritical] private static string GetString(NativeMethods.IQueryAssociations iQa, Shell32.AssociationString assocString, string shellVerb) { // GetString() throws Exceptions. try { // Use a large buffer to prevent calling this function twice. var size = NativeMethods.DefaultFileBufferSize; var buffer = new StringBuilder(size); iQa.GetString(Shell32.AssociationAttributes.NoTruncate | Shell32.AssociationAttributes.RemapRunDll, assocString, shellVerb, buffer, out size); return buffer.ToString(); } catch { return string.Empty; } } private NativeMethods.IQueryAssociations _iQaNone; // Retrieve info from Shell. private NativeMethods.IQueryAssociations _iQaByExe; // Retrieve info from exe file. [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] [SecurityCritical] private void Initialize() { if (Initialized) return; var iidIQueryAssociations = new Guid(NativeMethods.QueryAssociationsGuid); if (NativeMethods.AssocCreate(NativeMethods.ClsidQueryAssociations, ref iidIQueryAssociations, out _iQaNone) == Win32Errors.S_OK) { try { _iQaNone.Init(Shell32.AssociationAttributes.None, FullPath, IntPtr.Zero, IntPtr.Zero); if (NativeMethods.AssocCreate(NativeMethods.ClsidQueryAssociations, ref iidIQueryAssociations, out _iQaByExe) == Win32Errors.S_OK) { _iQaByExe.Init(Shell32.AssociationAttributes.InitByExeName, FullPath, IntPtr.Zero, IntPtr.Zero); Initialized = true; } } catch { } } } /// Refreshes the state of the object. [SecurityCritical] public void Refresh() { Association = Command = ContentType = DdeApplication = DefaultIcon = FriendlyAppName = FriendlyDocName = OpenWithAppName = null; Attributes = Shell32.GetAttributesOf.None; Initialized = false; Initialize(); } /// Returns the path as a string. /// The path. public override string ToString() { return FullPath; } #endregion // Methods #region Properties private string _association; /// Gets the Shell file or protocol association from the registry. public string Association { get { if (_association == null) _association = GetString(_iQaNone, Shell32.AssociationString.Executable, null); return _association; } private set { _association = value; } } private Shell32.GetAttributesOf _attributes; /// The attributes of the file object. public Shell32.GetAttributesOf Attributes { get { if (_attributes == Shell32.GetAttributesOf.None) { var fileInfo = Shell32.GetFileInfoCore(FullPath, FileAttributes.Normal, Shell32.FileAttributes.Attributes, false, true); _attributes = fileInfo.Attributes; } return _attributes; } private set { _attributes = value; } } private string _command; /// Gets the Shell command association from the registry. public string Command { get { if (_command == null) _command = GetString(_iQaNone, Shell32.AssociationString.Command, null); return _command; } private set { _command = value; } } private string _contentType; /// Gets the Shell command association from the registry. public string ContentType { get { if (_contentType == null) _contentType = GetString(_iQaNone, Shell32.AssociationString.ContentType, null); return _contentType; } private set { _contentType = value; } } private string _ddeApplication; /// Gets the Shell DDE association from the registry. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Dde")] public string DdeApplication { get { if (_ddeApplication == null) _ddeApplication = GetString(_iQaNone, Shell32.AssociationString.DdeApplication, null); return _ddeApplication; } private set { _ddeApplication = value; } } private string _defaultIcon; /// Gets the Shell default icon association from the registry. public string DefaultIcon { get { if (_defaultIcon == null) _defaultIcon = GetString(_iQaNone, Shell32.AssociationString.DefaultIcon, null); return _defaultIcon; } private set { _defaultIcon = value; } } /// Represents the fully qualified path of the file. public string FullPath { get; private set; } private string _friendlyAppName; /// Gets the Shell friendly application name association from the registry. public string FriendlyAppName { get { if (_friendlyAppName == null) _friendlyAppName = GetString(_iQaByExe, Shell32.AssociationString.FriendlyAppName, null); return _friendlyAppName; } private set { _friendlyAppName = value; } } private string _friendlyDocName; /// Gets the Shell friendly document name association from the registry. public string FriendlyDocName { get { if (_friendlyDocName == null) _friendlyDocName = GetString(_iQaNone, Shell32.AssociationString.FriendlyDocName, null); return _friendlyDocName; } private set { _friendlyDocName = value; } } /// Reflects the initialization state of the instance. internal bool Initialized { get; set; } private string _openWithAppName; /// Gets the Shell "Open With" command association from the registry. public string OpenWithAppName { get { if (_openWithAppName == null) _openWithAppName = GetString(_iQaNone, Shell32.AssociationString.FriendlyAppName, null); return _openWithAppName; } private set { _openWithAppName = value; } } #endregion // Properties } }