using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; namespace VSoft.Prams { public class ShellLink : IDisposable { // Fields private IShellLinkW linkW; private IShellLinkA linkA; private string shortcutFile; // Methods public ShellLink() { this.shortcutFile = ""; if (Environment.OSVersion.Platform == PlatformID.Win32NT) { this.linkW = (IShellLinkW)new CShellLink(); } else { this.linkA = (IShellLinkA)new CShellLink(); } } public ShellLink(string linkFile) : this() { this.Open(linkFile); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } private bool disposed = false; // Dispose(bool disposing) executes in two distinct scenarios. // If disposing equals true, the method has been called directly // or indirectly by a user's code. Managed and unmanaged resources // can be disposed. // If disposing equals false, the method has been called by the // runtime from inside the finalizer and you should not reference // other objects. Only unmanaged resources can be disposed. protected virtual void Dispose(bool disposing) { // Check to see if Dispose has already been called. if (!this.disposed) { // If disposing equals true, dispose all managed // and unmanaged resources. if (disposing) { if (this.linkW != null) { Marshal.ReleaseComObject(this.linkW); this.linkW = null; } if (this.linkA != null) { Marshal.ReleaseComObject(this.linkA); this.linkA = null; } // Dispose managed resources. this.Dispose(); } // Call the appropriate methods to clean up // unmanaged resources here. // If disposing is false, // only the following code is executed. // Note disposing has been done. disposed = true; } } ~ShellLink() { this.Dispose(false); } private Icon getIcon(bool large) { int piIcon = 0; StringBuilder pszIconPath = new StringBuilder(260, 260); if (this.linkA == null) { this.linkW.GetIconLocation(pszIconPath, pszIconPath.Capacity, out piIcon); } else { this.linkA.GetIconLocation(pszIconPath, pszIconPath.Capacity, out piIcon); } string lpszFile = pszIconPath.ToString(); if (lpszFile.Length == 0) { FileIcon.SHGetFileInfoConstants flags = FileIcon.SHGetFileInfoConstants.SHGFI_ATTRIBUTES | FileIcon.SHGetFileInfoConstants.SHGFI_ICON; if (large) { //flags = flags; } else { flags |= FileIcon.SHGetFileInfoConstants.SHGFI_SMALLICON; } FileIcon icon = new FileIcon(this.Target, flags); return icon.ShellIcon; } IntPtr[] phIconLarge = new IntPtr[] { IntPtr.Zero }; if (large) { UnManagedMethods.ExtractIconEx(lpszFile, piIcon, phIconLarge, null, 1); } else { UnManagedMethods.ExtractIconEx(lpszFile, piIcon, null, phIconLarge, 1); } Icon icon2 = null; if (phIconLarge[0] != IntPtr.Zero) { icon2 = Icon.FromHandle(phIconLarge[0]); } return icon2; } public void Open(string linkFile) { this.Open(linkFile, IntPtr.Zero, EShellLinkResolveFlags.SLR_ANY_MATCH | EShellLinkResolveFlags.SLR_NO_UI, 1); } public void Open(string linkFile, IntPtr hWnd, EShellLinkResolveFlags resolveFlags) { this.Open(linkFile, hWnd, resolveFlags, 1); } public void Open(string linkFile, IntPtr hWnd, EShellLinkResolveFlags resolveFlags, ushort timeOut) { uint num; if ((resolveFlags & EShellLinkResolveFlags.SLR_NO_UI) == EShellLinkResolveFlags.SLR_NO_UI) { num = (uint)(resolveFlags | ((EShellLinkResolveFlags)(timeOut << 0x10))); } else { num = (uint)resolveFlags; } if (this.linkA == null) { ((IPersistFile)this.linkW).Load(linkFile, 0); this.linkW.Resolve(hWnd, num); this.shortcutFile = linkFile; } else { ((IPersistFile)this.linkA).Load(linkFile, 0); this.linkA.Resolve(hWnd, num); this.shortcutFile = linkFile; } } public void Save() { this.Save(this.shortcutFile); } public void Save(string linkFile) { if (this.linkA == null) { ((IPersistFile)this.linkW).Save(linkFile, true); this.shortcutFile = linkFile; } else { ((IPersistFile)this.linkA).Save(linkFile, true); this.shortcutFile = linkFile; } } // Properties public string ShortCutFile { get => this.shortcutFile; set => this.shortcutFile = value; } public Icon LargeIcon => this.getIcon(true); public Icon SmallIcon => this.getIcon(false); public string IconPath { get { StringBuilder pszIconPath = new StringBuilder(260, 260); int piIcon = 0; if (this.linkA == null) { this.linkW.GetIconLocation(pszIconPath, pszIconPath.Capacity, out piIcon); } else { this.linkA.GetIconLocation(pszIconPath, pszIconPath.Capacity, out piIcon); } return pszIconPath.ToString(); } set { StringBuilder pszIconPath = new StringBuilder(260, 260); int piIcon = 0; if (this.linkA == null) { this.linkW.GetIconLocation(pszIconPath, pszIconPath.Capacity, out piIcon); } else { this.linkA.GetIconLocation(pszIconPath, pszIconPath.Capacity, out piIcon); } if (this.linkA == null) { this.linkW.SetIconLocation(value, piIcon); } else { this.linkA.SetIconLocation(value, piIcon); } } } public int IconIndex { get { StringBuilder pszIconPath = new StringBuilder(260, 260); int piIcon = 0; if (this.linkA == null) { this.linkW.GetIconLocation(pszIconPath, pszIconPath.Capacity, out piIcon); return piIcon; } this.linkA.GetIconLocation(pszIconPath, pszIconPath.Capacity, out piIcon); return piIcon; } set { StringBuilder pszIconPath = new StringBuilder(260, 260); int piIcon = 0; if (this.linkA == null) { this.linkW.GetIconLocation(pszIconPath, pszIconPath.Capacity, out piIcon); } else { this.linkA.GetIconLocation(pszIconPath, pszIconPath.Capacity, out piIcon); } if (this.linkA == null) { this.linkW.SetIconLocation(pszIconPath.ToString(), value); } else { this.linkA.SetIconLocation(pszIconPath.ToString(), value); } } } public string Target { get { StringBuilder pszFile = new StringBuilder(260, 260); if (this.linkA == null) { _WIN32_FIND_DATAW pfd = new _WIN32_FIND_DATAW(); this.linkW.GetPath(pszFile, pszFile.Capacity, ref pfd, 2); } else { _WIN32_FIND_DATAA pfd = new _WIN32_FIND_DATAA(); this.linkA.GetPath(pszFile, pszFile.Capacity, ref pfd, 2); } return pszFile.ToString(); } set { if (this.linkA == null) { this.linkW.SetPath(value); } else { this.linkA.SetPath(value); } } } public string WorkingDirectory { get { StringBuilder pszDir = new StringBuilder(260, 260); if (this.linkA == null) { this.linkW.GetWorkingDirectory(pszDir, pszDir.Capacity); } else { this.linkA.GetWorkingDirectory(pszDir, pszDir.Capacity); } return pszDir.ToString(); } set { if (this.linkA == null) { this.linkW.SetWorkingDirectory(value); } else { this.linkA.SetWorkingDirectory(value); } } } public string Description { get { StringBuilder pszFile = new StringBuilder(0x400, 0x400); if (this.linkA == null) { this.linkW.GetDescription(pszFile, pszFile.Capacity); } else { this.linkA.GetDescription(pszFile, pszFile.Capacity); } return pszFile.ToString(); } set { if (this.linkA == null) { this.linkW.SetDescription(value); } else { this.linkA.SetDescription(value); } } } public string Arguments { get { StringBuilder pszArgs = new StringBuilder(260, 260); if (this.linkA == null) { this.linkW.GetArguments(pszArgs, pszArgs.Capacity); } else { this.linkA.GetArguments(pszArgs, pszArgs.Capacity); } return pszArgs.ToString(); } set { if (this.linkA == null) { this.linkW.SetArguments(value); } else { this.linkA.SetArguments(value); } } } public LinkDisplayMode DisplayMode { get { uint piShowCmd = 0; if (this.linkA == null) { this.linkW.GetShowCmd(out piShowCmd); } else { this.linkA.GetShowCmd(out piShowCmd); } return (LinkDisplayMode)piShowCmd; } set { if (this.linkA == null) { this.linkW.SetShowCmd((uint)value); } else { this.linkA.SetShowCmd((uint)value); } } } public Keys HotKey { get { short pwHotkey = 0; if (this.linkA == null) { this.linkW.GetHotkey(out pwHotkey); } else { this.linkA.GetHotkey(out pwHotkey); } return (Keys)pwHotkey; } set { if (this.linkA == null) { this.linkW.SetHotkey((short)value); } else { this.linkA.SetHotkey((short)value); } } } // Nested Types [StructLayout(LayoutKind.Sequential, Pack = 4)] private struct _FILETIME { public uint dwLowDateTime; public uint dwHighDateTime; } [StructLayout(LayoutKind.Sequential, Pack = 4)] private struct _WIN32_FIND_DATAA { public uint dwFileAttributes; public ShellLink._FILETIME ftCreationTime; public ShellLink._FILETIME ftLastAccessTime; public ShellLink._FILETIME ftLastWriteTime; public uint nFileSizeHigh; public uint nFileSizeLow; public uint dwReserved0; public uint dwReserved1; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string cFileName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] public string cAlternateFileName; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)] private struct _WIN32_FIND_DATAW { public uint dwFileAttributes; public ShellLink._FILETIME ftCreationTime; public ShellLink._FILETIME ftLastAccessTime; public ShellLink._FILETIME ftLastWriteTime; public uint nFileSizeHigh; public uint nFileSizeLow; public uint dwReserved0; public uint dwReserved1; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string cFileName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] public string cAlternateFileName; } [ComImport, ClassInterface(ClassInterfaceType.None), Guid("00021401-0000-0000-C000-000000000046")] private class CShellLink { } private enum EShellLinkGP : uint { SLGP_SHORTPATH = 1, SLGP_UNCPRIORITY = 2 } [Flags] public enum EShellLinkResolveFlags : uint { SLR_ANY_MATCH = 2, SLR_INVOKE_MSI = 0x80, SLR_NOLINKINFO = 0x40, SLR_NO_UI = 1, SLR_NO_UI_WITH_MSG_PUMP = 0x101, SLR_NOUPDATE = 8, SLR_NOSEARCH = 0x10, SLR_NOTRACK = 0x20, SLR_UPDATE = 4 } [Flags] private enum EShowWindowFlags : uint { SW_HIDE = 0, SW_SHOWNORMAL = 1, SW_NORMAL = 1, SW_SHOWMINIMIZED = 2, SW_SHOWMAXIMIZED = 3, SW_MAXIMIZE = 3, SW_SHOWNOACTIVATE = 4, SW_SHOW = 5, SW_MINIMIZE = 6, SW_SHOWMINNOACTIVE = 7, SW_SHOWNA = 8, SW_RESTORE = 9, SW_SHOWDEFAULT = 10, SW_MAX = 10 } [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("0000010C-0000-0000-C000-000000000046")] private interface IPersist { [PreserveSig] void GetClassID(out Guid pClassID); } [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("0000010B-0000-0000-C000-000000000046")] private interface IPersistFile { [PreserveSig] void GetClassID(out Guid pClassID); void IsDirty(); void Load([MarshalAs(UnmanagedType.LPWStr)] string pszFileName, uint dwMode); void Save([MarshalAs(UnmanagedType.LPWStr)] string pszFileName, [MarshalAs(UnmanagedType.Bool)] bool fRemember); void SaveCompleted([MarshalAs(UnmanagedType.LPWStr)] string pszFileName); void GetCurFile([MarshalAs(UnmanagedType.LPWStr)] out string ppszFileName); } [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214EE-0000-0000-C000-000000000046")] private interface IShellLinkA { void GetPath([Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder pszFile, int cchMaxPath, ref ShellLink._WIN32_FIND_DATAA pfd, uint fFlags); void GetIDList(out IntPtr ppidl); void SetIDList(IntPtr pidl); void GetDescription([Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder pszFile, int cchMaxName); void SetDescription([MarshalAs(UnmanagedType.LPStr)] string pszName); void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder pszDir, int cchMaxPath); void SetWorkingDirectory([MarshalAs(UnmanagedType.LPStr)] string pszDir); void GetArguments([Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder pszArgs, int cchMaxPath); void SetArguments([MarshalAs(UnmanagedType.LPStr)] string pszArgs); void GetHotkey(out short pwHotkey); void SetHotkey(short pwHotkey); void GetShowCmd(out uint piShowCmd); void SetShowCmd(uint piShowCmd); void GetIconLocation([Out, MarshalAs(UnmanagedType.LPStr)] StringBuilder pszIconPath, int cchIconPath, out int piIcon); void SetIconLocation([MarshalAs(UnmanagedType.LPStr)] string pszIconPath, int iIcon); void SetRelativePath([MarshalAs(UnmanagedType.LPStr)] string pszPathRel, uint dwReserved); void Resolve(IntPtr hWnd, uint fFlags); void SetPath([MarshalAs(UnmanagedType.LPStr)] string pszFile); } [ComImport, Guid("000214F9-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] private interface IShellLinkW { void GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, ref ShellLink._WIN32_FIND_DATAW pfd, uint fFlags); void GetIDList(out IntPtr ppidl); void SetIDList(IntPtr pidl); void GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxName); void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName); void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath); void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir); void GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath); void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs); void GetHotkey(out short pwHotkey); void SetHotkey(short pwHotkey); void GetShowCmd(out uint piShowCmd); void SetShowCmd(uint piShowCmd); void GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchIconPath, out int piIcon); void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon); void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, uint dwReserved); void Resolve(IntPtr hWnd, uint fFlags); void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile); } public enum LinkDisplayMode : uint { edmNormal = 1, edmMinimized = 7, edmMaximized = 3 } private class UnManagedMethods { // Methods [DllImport("user32")] internal static extern int DestroyIcon(IntPtr hIcon); [DllImport("shell32", CharSet = CharSet.Auto)] internal static extern int ExtractIconEx([MarshalAs(UnmanagedType.LPWStr)] string lpszFile, int nIconIndex, IntPtr[] phIconLarge, IntPtr[] phIconSmall, int nIcons); } } }