C# 使用 WIN32API IShellLink 创建 快捷方式

解决问题

C# 使用 IShellLink 创建快捷方式

C# use IShellLink create a shortcut
如何在 C# 中使用 WIN32API 创建快捷方式?
How to create shortcut using WIN32API in C#?
C# 使用控制台应用程序创建快捷方式
C# creating a shortcut with console application

关键字

 C# WIN32API IShellLink 快捷方式

namespace System.IO
{
    using System;
    using System.Diagnostics;
    using System.Reflection;
    using System.Runtime.InteropServices;
    using System.Runtime.InteropServices.ComTypes;
    using System.Text;

    /// <summary>
    /// 编辑快捷方式文件的类。
    /// 在 Win 端后缀为.lnk的文件。
    /// </summary>
    public static class LinkFile
    {
        [Conditional("DEBUG")]
        public static void Test()
        {
            string linkFilePath = @"D:\画图(系统自带).lnk";
            string targetPath = @"C:\Windows\system32\mspaint.exe";
            var info = new LinkFileInfo(targetPath);
            info.Description = "画图支持编辑常用的图片格式";
            // Keys.Alt | Keys.Control | Keys.Shift | Keys.F1
            // = (short)(((1 | 2 | 4) << 8) | (int)Keys.F1)
            info.Hotkey = (short)(((1 | 2 | 4) << 8) | 112);
            Write(linkFilePath, info, false);

            var newInfo = Read(linkFilePath);
            TraceWriteLine("LinkFile new info target path: " + newInfo?.TargetPath);
        }

        public static bool Create(string linkFilePath, string targetPath, string arguments = null,
            string description = null, string iconLocation = null)
        {
            var info = new LinkFileInfo(targetPath, arguments, description, iconLocation);
            return Write(linkFilePath, info, false);
        }

        public static bool Write(string linkFilePath, LinkFileInfo info, bool useExistsFile)
        {
            bool isSuccessful = false;
            try
            {
                var shortcut = (IShellLink)new ShellLink();
                var persistFile = shortcut as IPersistFile;
                if (useExistsFile && System.IO.File.Exists(linkFilePath)) LoadPersistFile(persistFile, linkFilePath);

                if (info.Arguments != null) shortcut.SetArguments(info.Arguments);
                if (info.Description != null) shortcut.SetDescription(info.Description);
                if (info.Hotkey != 0) shortcut.SetHotkey(info.Hotkey);
                if (info.IconLocation != null) shortcut.SetIconLocation(info.IconLocation, info.IconLocationID);
                if (info.TargetPath != null) shortcut.SetPath(info.TargetPath);
                if (info.WindowStyle != -1) shortcut.SetShowCmd(info.WindowStyle);
                if (info.WorkingDirectory != null) shortcut.SetWorkingDirectory(info.WorkingDirectory);

                persistFile?.Save(linkFilePath, false);
                isSuccessful = persistFile != null;
            }
            catch (Exception ex)
            {
                TraceWriteLine("LinkFile write exception: ", ex);
            }
            return isSuccessful;
        }

        /// <summary>
        /// 注意:可能返回 null 。
        /// </summary>
        /// <param name="linkFilePath"></param>
        /// <returns></returns>
        public static LinkFileInfo Read(string linkFilePath)
        {
            LinkFileInfo info = null;
            if (System.IO.File.Exists(linkFilePath))
            {
                try
                {
                    info = new LinkFileInfo();
                    var shortcut = (IShellLink)new ShellLink();
                    var persistFile = shortcut as IPersistFile;
                    if (persistFile != null)
                    {
                        LoadPersistFile(persistFile, linkFilePath);

                        int builderCapacity = 4000;
                        StringBuilder builder;

                        builder = new StringBuilder(builderCapacity);
                        shortcut.GetArguments(builder, builderCapacity);
                        info.Arguments = builder.ToString();

                        builder = new StringBuilder(builderCapacity);
                        shortcut.GetDescription(builder, builderCapacity);
                        info.Description = builder.ToString();

                        short pwHotkey;
                        shortcut.GetHotkey(out pwHotkey);
                        info.Hotkey = pwHotkey;

                        builder = new StringBuilder(builderCapacity);
                        int piIcon;
                        shortcut.GetIconLocation(builder, builderCapacity, out piIcon);
                        info.IconLocation = builder.ToString();
                        info.IconLocationID = piIcon;

                        builder = new StringBuilder(builderCapacity);
                        var pfd = IntPtr.Zero;
                        //const int SLGP_SHORTPATH = 0x1;
                        //const int SLGP_UNCPRIORITY = 0x2;
                        const short SLGP_RAWPATH = 0x4;
                        //const int SLGP_RELATIVEPRIORITY = 0x8;
                        shortcut.GetPath(builder, builderCapacity, pfd, SLGP_RAWPATH);
                        info.TargetPath = builder.ToString();

                        int piShowCmd;
                        shortcut.GetShowCmd(out piShowCmd);
                        info.WindowStyle = piShowCmd;

                        builder = new StringBuilder(builderCapacity);
                        shortcut.GetWorkingDirectory(builder, builderCapacity);
                        info.WorkingDirectory = builder.ToString();
                    }
                }
                catch (Exception ex)
                {
                    TraceWriteLine("LinkFile load exception: ", ex);
                }
            }
            return info;
        }

        private static void LoadPersistFile(IPersistFile persistFile, string linkFilePath)
        {
            try
            {
                // https://learn.microsoft.com/zh-cn/windows/win32/stg/stgm-constants
                // 指定不会拒绝对对象的后续打开进行读取或写入访问。 如果未指定共享组中的标志,则假定此标志。
                const int STGM_SHARE_DENY_NONE = 0x00000040;
                persistFile?.Load(linkFilePath, STGM_SHARE_DENY_NONE);
            }
            catch (Exception ex)
            {
                TraceWriteLine("LinkFile load persist file exception: ", ex);
            }
        }

        private static void TraceWriteLine(string message)
        {
            Trace.WriteLine(message);
        }

        private static void TraceWriteLine(string message, Exception ex)
        {
            Trace.WriteLine(message + ex);
        }

        #region IShellLink

        [Obfuscation]
        [ComImport]
        [Guid("00021401-0000-0000-C000-000000000046")]
        internal class ShellLink
        {
        }

        /// <summary>
        /// https://learn.microsoft.com/zh-cn/windows/win32/shell/links
        /// </summary>
        [Obfuscation]
        [ComImport]
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
        [Guid("000214F9-0000-0000-C000-000000000046")]
        internal interface IShellLink
        {
            void GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, IntPtr pfd, short fFlags);
            void GetIDList(out IntPtr ppidl);
            void SetIDList(IntPtr pidl);
            void GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, 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 wHotkey);
            void GetShowCmd(out int piShowCmd);
            void SetShowCmd(int iShowCmd);
            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, int dwReserved);
            void Resolve(IntPtr hwnd, int fFlags);
            void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
        }

        #endregion

    }

    #region 快捷方式的信息。

    /// <summary>
    /// 快捷方式的信息。
    /// </summary>
    public class LinkFileInfo
    {
        internal LinkFileInfo()
        {
        }

        public LinkFileInfo(string targetPath, string arguments = null,
            string description = null, string iconLocation = null)
        {
            this.TargetPath = targetPath;
            this.Arguments = arguments;
            this.Description = description;
            this.IconLocation = iconLocation;

        }

        public string Arguments { get; set; }

        /// <summary>
        /// 设置备注。
        /// </summary>
        public string Description { get; set; }

        /// <summary>
        /// 键代码(KeyCode)和System.Windows.Forms.Keys相同。位屏蔽为 0x000000ff。
        /// 修饰符(Modifiers)和System.Windows.Forms.Keys不同。位屏蔽为 0x0000ff00。
        /// <para>示例:</para>
        /// <![CDATA[
        /// Alt = 1 << 8
        /// Control = 2 << 8
        /// Shift = 4 << 8
        /// WindowsKey = 8 << 8
        /// Keys.Alt | Keys.Control | Keys.Shift | Keys.F1
        /// = (short)(((1 | 2 | 4) << 8) | (int)Keys.F1)
        /// = (short)(((1 | 2 | 4) << 8) | 112)
        /// ]]>
        /// </summary>
        public short Hotkey { get; set; }

        /// <summary>
        /// 设置图标路径。
        /// </summary>
        public string IconLocation { get; set; }

        /// <summary>
        /// 设置图标ID。
        /// </summary>
        public int IconLocationID { get; set; }

        /// <summary>
        /// 目标路径。
        /// </summary>
        public string TargetPath { get; set; }

        /// <summary>
        /// 设置运行方式,默认为常规窗口。
        /// https://learn.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-showwindow
        /// </summary>
        public int WindowStyle { get; set; } = -1;

        public string WorkingDirectory { get; set; }
    }

    #endregion
}


namespace System.Windows.Forms
{
    using System.Reflection;

    /// <summary>
    /// 支持转换 LinkFileInfo.Hotkey 与 System.Windows.Forms.Keys 的类。
    /// </summary>
    public class LinkFileInfoHotkey
    {
        [Obfuscation]
        [Flags]
        internal enum KeyModifiers
        {
            None = 0,
            Alt = 1,
            Control = 2,
            Shift = 4,
            WindowsKey = 8
        }

        public static short GetKeyNumber(Keys keyData)
        {
            short keyNumber = 0;
            if (keyData != Keys.None)
            {
                var keyNumberModifiers = KeyModifiers.None;
                if ((keyData & Keys.Alt) == Keys.Alt)
                {
                    keyNumberModifiers |= KeyModifiers.Alt;
                }
                if ((keyData & Keys.Control) == Keys.Control)
                {
                    keyNumberModifiers |= KeyModifiers.Control;
                }
                if ((keyData & Keys.Shift) == Keys.Shift)
                {
                    keyNumberModifiers |= KeyModifiers.Shift;
                }
                if ((keyData == Keys.LWin) || (keyData == Keys.RWin))
                {
                    keyNumberModifiers |= KeyModifiers.WindowsKey;
                }
                const int keyCodeHelper = 0x000000ff;
                var keyCode = (int)keyData & keyCodeHelper;
                keyNumber = (short)((((int)keyNumberModifiers) << 8) | keyCode);
            }
            return keyNumber;
        }

        public static Keys GetKey(short keyNumber)
        {
            Keys keyData = Keys.None;
            if (keyNumber != 0)
            {
                const int modifiersHelper = 0x0000ff00;
                var keyNumberModifiers = (KeyModifiers)((modifiersHelper & keyNumber) >> 8);
                var keyModifiers = Keys.None;
                if ((keyNumberModifiers & KeyModifiers.Alt) == KeyModifiers.Alt)
                {
                    keyModifiers |= Keys.Alt;
                }
                if ((keyNumberModifiers & KeyModifiers.Control) == KeyModifiers.Control)
                {
                    keyModifiers |= Keys.Control;
                }
                if ((keyNumberModifiers & KeyModifiers.Shift) == KeyModifiers.Shift)
                {
                    keyModifiers |= Keys.Shift;
                }
                if ((keyNumberModifiers & KeyModifiers.WindowsKey) == KeyModifiers.WindowsKey)
                {
                    keyModifiers |= Keys.RWin;
                }
                const int keyCodeHelper = 0x000000ff;
                Keys keyCode = (Keys)(keyNumber & keyCodeHelper);
                keyData = keyModifiers | keyCode;
            }
            return keyData;
        }
    }
}

/*
        private static void TraceWriteLine(string message)
        {
            Trace.WriteLine(message);
        }

        private static void TraceWriteLine(string message, Exception ex)
        {
            Trace.WriteLine(message + ex);
        }
 */

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值