Skip to content

Commit

Permalink
Merge pull request #117 from cairoshell/improve-helpers
Browse files Browse the repository at this point in the history
Add helper method for getting shortcut target
  • Loading branch information
josuave authored Dec 28, 2024
2 parents 9fd3ab0 + 349d748 commit 9ba8690
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 0 deletions.
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;
}
}
}

0 comments on commit 9ba8690

Please sign in to comment.