/* 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
}
}