Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/ManagedShell.Common/Helpers/ShellHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ public static string GetAppUserModelIdForHandle(IntPtr hWnd)
StringBuilder outAumid = new StringBuilder((int)len);

GetApplicationUserModelId(hProcess, ref len, outAumid);
CloseHandle((int)hProcess);

if (outAumid.Length > 0)
{
Expand Down
16 changes: 16 additions & 0 deletions src/ManagedShell.Interop/NativeMethods.Msi.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System.Runtime.InteropServices;
using System.Text;

namespace ManagedShell.Interop
{
public partial class NativeMethods
{
const string Msi_DllName = "msi.dll";

[DllImport(Msi_DllName, CharSet = CharSet.Unicode)]
public static extern uint MsiGetShortcutTarget(string szShortcutTarget, [Out] StringBuilder szProductCode, [Out] StringBuilder szFeatureId, [Out] StringBuilder szComponentCode);

[DllImport(Msi_DllName, CharSet = CharSet.Unicode)]
public static extern int MsiGetComponentPath(string szProduct, string szComponent, [Out] StringBuilder lpPathBuf, [In, Out] ref int pcchBuf);
}
}
74 changes: 74 additions & 0 deletions src/ManagedShell.ShellFolders/ShellLinkHelper.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
using ManagedShell.Common.Logging;
using ManagedShell.Interop;
using ManagedShell.ShellFolders.Enums;
using ManagedShell.ShellFolders.Interfaces;

Expand Down Expand Up @@ -74,5 +76,77 @@ public static IShellLink Load(IntPtr userInputHwnd, string existingLinkPath)

return shellLink;
}

public static string GetLinkTarget(IntPtr userInputHwnd, string filePath)
{
IShellLink link = Load(userInputHwnd, filePath);
string target = "";

try
{
// First, query Windows Installer to see if this is an installed application shortcut
StringBuilder product = new StringBuilder(39);
StringBuilder feature = new StringBuilder(39);
StringBuilder component = new StringBuilder(39);

uint result = NativeMethods.MsiGetShortcutTarget(filePath, product, feature, component);

if (result == 0)
{
// This is a Windows Installer shortcut
int pathLength = 1024;
StringBuilder path = new StringBuilder(pathLength);
int installState = NativeMethods.MsiGetComponentPath(product.ToString(), component.ToString(), path, ref pathLength);
if (installState == 1)
{
// Locally installed application
target = path.ToString();
}
}
}
catch (Exception e)
{
ShellLogger.Error($"ShellLinkHelper: Unable to query Windows Installer target for {filePath}", e);
}

if (string.IsNullOrEmpty(target))
{
try
{
// Check for an associated identifier list to get an IShellItem object from
IntPtr pidl = IntPtr.Zero;
link.GetIDList(out pidl);

if (pidl != IntPtr.Zero)
{
IShellItem _shellItem;
Interop.SHCreateItemFromIDList(pidl, typeof(IShellItem).GUID, out _shellItem);
ShellItem item = new ShellItem(_shellItem);
target = item.Path;
}
}
catch (Exception e)
{
ShellLogger.Error($"ShellLinkHelper: Unable to get ID list for {filePath}", e);
}
}

if (string.IsNullOrEmpty(target))
{
try
{
// Get the shortcut path as a last resort
StringBuilder builder = new StringBuilder(260);
link.GetPath(builder, 260, out Structs.WIN32_FIND_DATA pfd, SLGP_FLAGS.SLGP_RAWPATH);
target = builder.ToString();
}
catch (Exception e)
{
ShellLogger.Error($"ShellLinkHelper: Unable to get path for {filePath}", e);
}
}

return target;
}
}
}