解决问题
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);
}
*/