You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

338 rivejä
11 KiB

  1. /* Copyright (C) 2008-2016 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
  2. *
  3. * Permission is hereby granted, free of charge, to any person obtaining a copy
  4. * of this software and associated documentation files (the "Software"), to deal
  5. * in the Software without restriction, including without limitation the rights
  6. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. * copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in
  11. * all copies or substantial portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. * THE SOFTWARE.
  20. */
  21. using System;
  22. using System.Diagnostics.CodeAnalysis;
  23. using System.IO;
  24. using System.Security;
  25. using System.Text;
  26. namespace Alphaleonis.Win32.Filesystem
  27. {
  28. /// <summary>Contains Shell32 information about a file.</summary>
  29. [SerializableAttribute]
  30. [SecurityCritical]
  31. public sealed class Shell32Info
  32. {
  33. #region Constructors
  34. /// <summary>Initializes a Shell32Info instance.
  35. /// <remarks>Shell32 is limited to MAX_PATH length.</remarks>
  36. /// <remarks>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.</remarks>
  37. /// </summary>
  38. /// <param name="fileName">The fully qualified name of the new file, or the relative file name. Do not end the path with the directory separator character.</param>
  39. public Shell32Info(string fileName) : this(fileName, PathFormat.RelativePath)
  40. {
  41. }
  42. /// <summary>Initializes a Shell32Info instance.
  43. /// <remarks>Shell32 is limited to MAX_PATH length.</remarks>
  44. /// <remarks>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.</remarks>
  45. /// </summary>
  46. /// <param name="fileName">The fully qualified name of the new file, or the relative file name. Do not end the path with the directory separator character.</param>
  47. /// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
  48. public Shell32Info(string fileName, PathFormat pathFormat)
  49. {
  50. if (Utils.IsNullOrWhiteSpace(fileName))
  51. throw new ArgumentNullException("fileName");
  52. // Shell32 is limited to MAX_PATH length.
  53. // Get a full path of regular format.
  54. FullPath = Path.GetExtendedLengthPathCore(null, fileName, pathFormat, GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck);
  55. Initialize();
  56. }
  57. #endregion // Constructors
  58. #region Methods
  59. /// <summary>Gets an <see cref="IntPtr"/> handle to the Shell icon that represents the file.</summary>
  60. /// <param name="iconAttributes">Icon size <see cref="Shell32.FileAttributes.SmallIcon"/> or <see cref="Shell32.FileAttributes.LargeIcon"/>. Can also be combined with <see cref="Shell32.FileAttributes.AddOverlays"/> and others.</param>
  61. /// <returns>An <see cref="IntPtr"/> handle to the Shell icon that represents the file.</returns>
  62. /// <remarks>Caller is responsible for destroying this handle with DestroyIcon() when no longer needed.</remarks>
  63. [SecurityCritical]
  64. public IntPtr GetIcon(Shell32.FileAttributes iconAttributes)
  65. {
  66. return Shell32.GetFileIcon(FullPath, iconAttributes);
  67. }
  68. /// <summary>Gets the Shell command association from the registry.</summary>
  69. /// <param name="shellVerb">The shell verb.</param>
  70. /// <returns>
  71. /// Returns the associated file- or protocol-related Shell command from the registry or <c>string.Empty</c> if no association can be
  72. /// found.
  73. /// </returns>
  74. [SecurityCritical]
  75. public string GetVerbCommand(string shellVerb)
  76. {
  77. return GetString(_iQaNone, Shell32.AssociationString.Command, shellVerb);
  78. }
  79. [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
  80. [SecurityCritical]
  81. private static string GetString(NativeMethods.IQueryAssociations iQa, Shell32.AssociationString assocString, string shellVerb)
  82. {
  83. // GetString() throws Exceptions.
  84. try
  85. {
  86. // Use a large buffer to prevent calling this function twice.
  87. var size = NativeMethods.DefaultFileBufferSize;
  88. var buffer = new StringBuilder(size);
  89. iQa.GetString(Shell32.AssociationAttributes.NoTruncate | Shell32.AssociationAttributes.RemapRunDll, assocString, shellVerb, buffer, out size);
  90. return buffer.ToString();
  91. }
  92. catch
  93. {
  94. return string.Empty;
  95. }
  96. }
  97. private NativeMethods.IQueryAssociations _iQaNone; // Retrieve info from Shell.
  98. private NativeMethods.IQueryAssociations _iQaByExe; // Retrieve info from exe file.
  99. [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
  100. [SecurityCritical]
  101. private void Initialize()
  102. {
  103. if (Initialized)
  104. return;
  105. var iidIQueryAssociations = new Guid(NativeMethods.QueryAssociationsGuid);
  106. if (NativeMethods.AssocCreate(NativeMethods.ClsidQueryAssociations, ref iidIQueryAssociations, out _iQaNone) == Win32Errors.S_OK)
  107. {
  108. try
  109. {
  110. _iQaNone.Init(Shell32.AssociationAttributes.None, FullPath, IntPtr.Zero, IntPtr.Zero);
  111. if (NativeMethods.AssocCreate(NativeMethods.ClsidQueryAssociations, ref iidIQueryAssociations, out _iQaByExe) == Win32Errors.S_OK)
  112. {
  113. _iQaByExe.Init(Shell32.AssociationAttributes.InitByExeName, FullPath, IntPtr.Zero, IntPtr.Zero);
  114. Initialized = true;
  115. }
  116. }
  117. catch
  118. {
  119. }
  120. }
  121. }
  122. /// <summary>Refreshes the state of the object.</summary>
  123. [SecurityCritical]
  124. public void Refresh()
  125. {
  126. Association = Command = ContentType = DdeApplication = DefaultIcon = FriendlyAppName = FriendlyDocName = OpenWithAppName = null;
  127. Attributes = Shell32.GetAttributesOf.None;
  128. Initialized = false;
  129. Initialize();
  130. }
  131. /// <summary>Returns the path as a string.</summary>
  132. /// <returns>The path.</returns>
  133. public override string ToString()
  134. {
  135. return FullPath;
  136. }
  137. #endregion // Methods
  138. #region Properties
  139. private string _association;
  140. /// <summary>Gets the Shell file or protocol association from the registry.</summary>
  141. public string Association
  142. {
  143. get
  144. {
  145. if (_association == null)
  146. _association = GetString(_iQaNone, Shell32.AssociationString.Executable, null);
  147. return _association;
  148. }
  149. private set { _association = value; }
  150. }
  151. private Shell32.GetAttributesOf _attributes;
  152. /// <summary>The attributes of the file object.</summary>
  153. public Shell32.GetAttributesOf Attributes
  154. {
  155. get
  156. {
  157. if (_attributes == Shell32.GetAttributesOf.None)
  158. {
  159. var fileInfo = Shell32.GetFileInfoCore(FullPath, FileAttributes.Normal, Shell32.FileAttributes.Attributes, false, true);
  160. _attributes = fileInfo.Attributes;
  161. }
  162. return _attributes;
  163. }
  164. private set { _attributes = value; }
  165. }
  166. private string _command;
  167. /// <summary>Gets the Shell command association from the registry.</summary>
  168. public string Command
  169. {
  170. get
  171. {
  172. if (_command == null)
  173. _command = GetString(_iQaNone, Shell32.AssociationString.Command, null);
  174. return _command;
  175. }
  176. private set { _command = value; }
  177. }
  178. private string _contentType;
  179. /// <summary>Gets the Shell command association from the registry.</summary>
  180. public string ContentType
  181. {
  182. get
  183. {
  184. if (_contentType == null)
  185. _contentType = GetString(_iQaNone, Shell32.AssociationString.ContentType, null);
  186. return _contentType;
  187. }
  188. private set { _contentType = value; }
  189. }
  190. private string _ddeApplication;
  191. /// <summary>Gets the Shell DDE association from the registry.</summary>
  192. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Dde")]
  193. public string DdeApplication
  194. {
  195. get
  196. {
  197. if (_ddeApplication == null)
  198. _ddeApplication = GetString(_iQaNone, Shell32.AssociationString.DdeApplication, null);
  199. return _ddeApplication;
  200. }
  201. private set { _ddeApplication = value; }
  202. }
  203. private string _defaultIcon;
  204. /// <summary>Gets the Shell default icon association from the registry.</summary>
  205. public string DefaultIcon
  206. {
  207. get
  208. {
  209. if (_defaultIcon == null)
  210. _defaultIcon = GetString(_iQaNone, Shell32.AssociationString.DefaultIcon, null);
  211. return _defaultIcon;
  212. }
  213. private set { _defaultIcon = value; }
  214. }
  215. /// <summary>Represents the fully qualified path of the file.</summary>
  216. public string FullPath { get; private set; }
  217. private string _friendlyAppName;
  218. /// <summary>Gets the Shell friendly application name association from the registry.</summary>
  219. public string FriendlyAppName
  220. {
  221. get
  222. {
  223. if (_friendlyAppName == null)
  224. _friendlyAppName = GetString(_iQaByExe, Shell32.AssociationString.FriendlyAppName, null);
  225. return _friendlyAppName;
  226. }
  227. private set { _friendlyAppName = value; }
  228. }
  229. private string _friendlyDocName;
  230. /// <summary>Gets the Shell friendly document name association from the registry.</summary>
  231. public string FriendlyDocName
  232. {
  233. get
  234. {
  235. if (_friendlyDocName == null)
  236. _friendlyDocName = GetString(_iQaNone, Shell32.AssociationString.FriendlyDocName, null);
  237. return _friendlyDocName;
  238. }
  239. private set { _friendlyDocName = value; }
  240. }
  241. /// <summary>Reflects the initialization state of the instance.</summary>
  242. internal bool Initialized { get; set; }
  243. private string _openWithAppName;
  244. /// <summary>Gets the Shell "Open With" command association from the registry.</summary>
  245. public string OpenWithAppName
  246. {
  247. get
  248. {
  249. if (_openWithAppName == null)
  250. _openWithAppName = GetString(_iQaNone, Shell32.AssociationString.FriendlyAppName, null);
  251. return _openWithAppName;
  252. }
  253. private set { _openWithAppName = value; }
  254. }
  255. #endregion // Properties
  256. }
  257. }