fix(installer): release the ShellLink COM object so reading a .lnk doesn't lock it

This commit is contained in:
mika kuns
2026-08-06 12:00:18 +02:00
parent 46e177eb59
commit c6213d77c4
+23 -7
View File
@@ -8,24 +8,36 @@ public static class ShortcutFactory
{
private const int SlgpRawPath = 0x4;
// Both helpers release the ShellLink RCW explicitly. IPersistFile.Load/Save keeps a handle on
// the .lnk for as long as the COM object lives, so leaving it to the GC lets a read immediately
// followed by a write to the same path fail with "used by another process" — exactly what
// AutostartShortcut.Install does when the recorded target changed.
public static void CreateShortcut(string shortcutPath, string targetPath, string workingDir, string description)
{
var link = (IShellLink)new ShellLink();
link.SetPath(targetPath);
link.SetWorkingDirectory(workingDir);
link.SetDescription(description);
link.SetIconLocation(targetPath, 0);
try
{
link.SetPath(targetPath);
link.SetWorkingDirectory(workingDir);
link.SetDescription(description);
link.SetIconLocation(targetPath, 0);
var file = (IPersistFile)link;
file.Save(shortcutPath, false);
var file = (IPersistFile)link;
file.Save(shortcutPath, false);
}
finally
{
Marshal.FinalReleaseComObject(link);
}
}
/// <summary>Reads the target path of an existing .lnk, or null if it can't be read (missing/corrupt).</summary>
public static string? TryGetTarget(string shortcutPath)
{
IShellLink? link = null;
try
{
var link = (IShellLink)new ShellLink();
link = (IShellLink)new ShellLink();
((IPersistFile)link).Load(shortcutPath, 0);
var sb = new StringBuilder(260);
link.GetPath(sb, sb.Capacity, IntPtr.Zero, SlgpRawPath);
@@ -36,6 +48,10 @@ public static class ShortcutFactory
{
return null;
}
finally
{
if (link is not null) Marshal.FinalReleaseComObject(link);
}
}
[ComImport]