ShellShortcut.cs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. /**************************************************************************
  2. *
  3. * Filename: ShellShortcut.cs
  4. * Author: Mattias Sjögren (mattias@mvps.org)
  5. * http://www.msjogren.net/dotnet/
  6. *
  7. * Description: Defines a .NET friendly class, ShellShortcut, for reading
  8. * and writing shortcuts.
  9. * Define the conditional compilation symbol UNICODE to use
  10. * IShellLinkW internally.
  11. *
  12. * Public types: class ShellShortcut
  13. *
  14. *
  15. * Dependencies: ShellLinkNative.cs
  16. *
  17. *
  18. * Copyright ©2001-2002, Mattias Sjögren
  19. *
  20. **************************************************************************/
  21. using System;
  22. using System.Diagnostics;
  23. using System.Drawing;
  24. using System.IO;
  25. using System.Runtime.InteropServices;
  26. using System.Text;
  27. using System.Windows.Forms;
  28. namespace MediaBrowser.Installer.Code
  29. {
  30. /// <remarks>
  31. /// .NET friendly wrapper for the ShellLink class
  32. /// </remarks>
  33. public class ShellShortcut : IDisposable
  34. {
  35. private const int INFOTIPSIZE = 1024;
  36. private const int MAX_PATH = 260;
  37. private const int SW_SHOWNORMAL = 1;
  38. private const int SW_SHOWMINIMIZED = 2;
  39. private const int SW_SHOWMAXIMIZED = 3;
  40. private const int SW_SHOWMINNOACTIVE = 7;
  41. #if UNICODE
  42. private IShellLinkW m_Link;
  43. #else
  44. private IShellLinkA m_Link;
  45. #endif
  46. private string m_sPath;
  47. ///
  48. /// <param name='linkPath'>
  49. /// Path to new or existing shortcut file (.lnk).
  50. /// </param>
  51. ///
  52. public ShellShortcut(string linkPath)
  53. {
  54. IPersistFile pf;
  55. m_sPath = linkPath;
  56. #if UNICODE
  57. m_Link = (IShellLinkW) new ShellLink();
  58. #else
  59. m_Link = (IShellLinkA) new ShellLink();
  60. #endif
  61. if ( File.Exists( linkPath ) ) {
  62. pf = (IPersistFile)m_Link;
  63. pf.Load( linkPath, 0 );
  64. }
  65. }
  66. //
  67. // IDisplosable implementation
  68. //
  69. public void Dispose()
  70. {
  71. if ( m_Link != null ) {
  72. Marshal.ReleaseComObject( m_Link );
  73. m_Link = null;
  74. }
  75. }
  76. /// <value>
  77. /// Gets or sets the argument list of the shortcut.
  78. /// </value>
  79. public string Arguments
  80. {
  81. get
  82. {
  83. StringBuilder sb = new StringBuilder( INFOTIPSIZE );
  84. m_Link.GetArguments( sb, sb.Capacity );
  85. return sb.ToString();
  86. }
  87. set { m_Link.SetArguments( value ); }
  88. }
  89. /// <value>
  90. /// Gets or sets a description of the shortcut.
  91. /// </value>
  92. public string Description
  93. {
  94. get
  95. {
  96. StringBuilder sb = new StringBuilder( INFOTIPSIZE );
  97. m_Link.GetDescription( sb, sb.Capacity );
  98. return sb.ToString();
  99. }
  100. set { m_Link.SetDescription( value ); }
  101. }
  102. /// <value>
  103. /// Gets or sets the working directory (aka start in directory) of the shortcut.
  104. /// </value>
  105. public string WorkingDirectory
  106. {
  107. get
  108. {
  109. StringBuilder sb = new StringBuilder( MAX_PATH );
  110. m_Link.GetWorkingDirectory( sb, sb.Capacity );
  111. return sb.ToString();
  112. }
  113. set { m_Link.SetWorkingDirectory( value ); }
  114. }
  115. //
  116. // If Path returns an empty string, the shortcut is associated with
  117. // a PIDL instead, which can be retrieved with IShellLink.GetIDList().
  118. // This is beyond the scope of this wrapper class.
  119. //
  120. /// <value>
  121. /// Gets or sets the target path of the shortcut.
  122. /// </value>
  123. public string Path
  124. {
  125. get
  126. {
  127. #if UNICODE
  128. WIN32_FIND_DATAW wfd = new WIN32_FIND_DATAW();
  129. #else
  130. WIN32_FIND_DATAA wfd = new WIN32_FIND_DATAA();
  131. #endif
  132. StringBuilder sb = new StringBuilder( MAX_PATH );
  133. m_Link.GetPath( sb, sb.Capacity, out wfd, SLGP_FLAGS.SLGP_UNCPRIORITY );
  134. return sb.ToString();
  135. }
  136. set { m_Link.SetPath( value ); }
  137. }
  138. /// <value>
  139. /// Gets or sets the path of the <see cref="Icon"/> assigned to the shortcut.
  140. /// </value>
  141. /// <summary>
  142. /// <seealso cref="IconIndex"/>
  143. /// </summary>
  144. public string IconPath
  145. {
  146. get
  147. {
  148. StringBuilder sb = new StringBuilder( MAX_PATH );
  149. int nIconIdx;
  150. m_Link.GetIconLocation( sb, sb.Capacity, out nIconIdx );
  151. return sb.ToString();
  152. }
  153. set { m_Link.SetIconLocation( value, IconIndex ); }
  154. }
  155. /// <value>
  156. /// Gets or sets the index of the <see cref="Icon"/> assigned to the shortcut.
  157. /// Set to zero when the <see cref="IconPath"/> property specifies a .ICO file.
  158. /// </value>
  159. /// <summary>
  160. /// <seealso cref="IconPath"/>
  161. /// </summary>
  162. public int IconIndex
  163. {
  164. get
  165. {
  166. StringBuilder sb = new StringBuilder( MAX_PATH );
  167. int nIconIdx;
  168. m_Link.GetIconLocation( sb, sb.Capacity, out nIconIdx );
  169. return nIconIdx;
  170. }
  171. set { m_Link.SetIconLocation( IconPath, value ); }
  172. }
  173. /// <value>
  174. /// Retrieves the Icon of the shortcut as it will appear in Explorer.
  175. /// Use the <see cref="IconPath"/> and <see cref="IconIndex"/>
  176. /// properties to change it.
  177. /// </value>
  178. public Icon Icon
  179. {
  180. get
  181. {
  182. StringBuilder sb = new StringBuilder( MAX_PATH );
  183. int nIconIdx;
  184. IntPtr hIcon, hInst;
  185. Icon ico, clone;
  186. m_Link.GetIconLocation( sb, sb.Capacity, out nIconIdx );
  187. hInst = Marshal.GetHINSTANCE( this.GetType().Module );
  188. hIcon = Native.ExtractIcon( hInst, sb.ToString(), nIconIdx );
  189. if ( hIcon == IntPtr.Zero )
  190. return null;
  191. // Return a cloned Icon, because we have to free the original ourselves.
  192. ico = Icon.FromHandle( hIcon );
  193. clone = (Icon)ico.Clone();
  194. ico.Dispose();
  195. Native.DestroyIcon( hIcon );
  196. return clone;
  197. }
  198. }
  199. /// <value>
  200. /// Gets or sets the System.Diagnostics.ProcessWindowStyle value
  201. /// that decides the initial show state of the shortcut target. Note that
  202. /// ProcessWindowStyle.Hidden is not a valid property value.
  203. /// </value>
  204. public ProcessWindowStyle WindowStyle
  205. {
  206. get
  207. {
  208. int nWS;
  209. m_Link.GetShowCmd( out nWS );
  210. switch ( nWS ) {
  211. case SW_SHOWMINIMIZED:
  212. case SW_SHOWMINNOACTIVE:
  213. return ProcessWindowStyle.Minimized;
  214. case SW_SHOWMAXIMIZED:
  215. return ProcessWindowStyle.Maximized;
  216. default:
  217. return ProcessWindowStyle.Normal;
  218. }
  219. }
  220. set
  221. {
  222. int nWS;
  223. switch ( value ) {
  224. case ProcessWindowStyle.Normal:
  225. nWS = SW_SHOWNORMAL;
  226. break;
  227. case ProcessWindowStyle.Minimized:
  228. nWS = SW_SHOWMINNOACTIVE;
  229. break;
  230. case ProcessWindowStyle.Maximized:
  231. nWS = SW_SHOWMAXIMIZED;
  232. break;
  233. default: // ProcessWindowStyle.Hidden
  234. throw new ArgumentException("Unsupported ProcessWindowStyle value.");
  235. }
  236. m_Link.SetShowCmd( nWS );
  237. }
  238. }
  239. /// <value>
  240. /// Gets or sets the hotkey for the shortcut.
  241. /// </value>
  242. public Keys Hotkey
  243. {
  244. get
  245. {
  246. short wHotkey;
  247. int dwHotkey;
  248. m_Link.GetHotkey( out wHotkey );
  249. //
  250. // Convert from IShellLink 16-bit format to Keys enumeration 32-bit value
  251. // IShellLink: 0xMMVK
  252. // Keys: 0x00MM00VK
  253. // MM = Modifier (Alt, Control, Shift)
  254. // VK = Virtual key code
  255. //
  256. dwHotkey = ((wHotkey & 0xFF00) << 8) | (wHotkey & 0xFF);
  257. return (Keys) dwHotkey;
  258. }
  259. set
  260. {
  261. short wHotkey;
  262. if ( (value & Keys.Modifiers) == 0 )
  263. throw new ArgumentException("Hotkey must include a modifier key.");
  264. //
  265. // Convert from Keys enumeration 32-bit value to IShellLink 16-bit format
  266. // IShellLink: 0xMMVK
  267. // Keys: 0x00MM00VK
  268. // MM = Modifier (Alt, Control, Shift)
  269. // VK = Virtual key code
  270. //
  271. wHotkey = unchecked((short) ( ((int) (value & Keys.Modifiers) >> 8) | (int) (value & Keys.KeyCode) ));
  272. m_Link.SetHotkey( wHotkey );
  273. }
  274. }
  275. /// <summary>
  276. /// Saves the shortcut to disk.
  277. /// </summary>
  278. public void Save()
  279. {
  280. IPersistFile pf = (IPersistFile) m_Link;
  281. pf.Save( m_sPath, true );
  282. }
  283. /// <summary>
  284. /// Returns a reference to the internal ShellLink object,
  285. /// which can be used to perform more advanced operations
  286. /// not supported by this wrapper class, by using the
  287. /// IShellLink interface directly.
  288. /// </summary>
  289. public object ShellLink
  290. {
  291. get { return m_Link; }
  292. }
  293. #region Native Win32 API functions
  294. private class Native
  295. {
  296. [DllImport("shell32.dll", CharSet=CharSet.Auto)]
  297. public static extern IntPtr ExtractIcon(IntPtr hInst, string lpszExeFileName, int nIconIndex);
  298. [DllImport("user32.dll")]
  299. public static extern bool DestroyIcon(IntPtr hIcon);
  300. }
  301. #endregion
  302. }
  303. }