2020-08-13 02:46:11 +08:00
// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System ;
2020-05-14 02:43:56 +08:00
using System.Runtime.InteropServices ;
using System.Runtime.InteropServices.ComTypes ;
2020-08-13 02:46:11 +08:00
using System.Text ;
using Accessibility ;
2020-07-18 13:32:21 +08:00
using Microsoft.Plugin.Program.Logger ;
2020-05-14 02:43:56 +08:00
namespace Microsoft.Plugin.Program.Programs
{
2020-07-18 13:32:21 +08:00
public class ShellLinkHelper : IShellLinkHelper
2020-05-14 02:43:56 +08:00
{
[Flags()]
2020-08-12 00:08:44 +08:00
private enum SLGP_FLAGS
2020-05-14 02:43:56 +08:00
{
SLGP_SHORTPATH = 0x1 ,
SLGP_UNCPRIORITY = 0x2 ,
2020-08-13 02:46:11 +08:00
SLGP_RAWPATH = 0x4 ,
2020-05-14 02:43:56 +08:00
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
2020-08-12 00:08:44 +08:00
private struct WIN32_FIND_DATAW
2020-05-14 02:43:56 +08:00
{
public uint dwFileAttributes ;
public long ftCreationTime ;
public long ftLastAccessTime ;
public long ftLastWriteTime ;
public uint nFileSizeHigh ;
public uint nFileSizeLow ;
public uint dwReserved0 ;
public uint dwReserved1 ;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string cFileName ;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public string cAlternateFileName ;
}
2020-08-12 00:08:44 +08:00
[Flags()]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Represents flags specified in IShellLink interface")]
2020-05-14 02:43:56 +08:00
public enum SLR_FLAGS
{
SLR_NO_UI = 0x1 ,
SLR_ANY_MATCH = 0x2 ,
SLR_UPDATE = 0x4 ,
SLR_NOUPDATE = 0x8 ,
SLR_NOSEARCH = 0x10 ,
SLR_NOTRACK = 0x20 ,
SLR_NOLINKINFO = 0x40 ,
2020-08-13 02:46:11 +08:00
SLR_INVOKE_MSI = 0x80 ,
2020-05-14 02:43:56 +08:00
}
2020-08-13 02:46:11 +08:00
2020-05-14 02:43:56 +08:00
// Reference : http://www.pinvoke.net/default.aspx/Interfaces.IShellLinkW
/// The IShellLink interface allows Shell links to be created, modified, and resolved
[ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214F9-0000-0000-C000-000000000046")]
interface IShellLinkW
{
/// <summary>Retrieves the path and file name of a Shell link object</summary>
void GetPath ( [ Out ( ) , MarshalAs ( UnmanagedType . LPWStr ) ] StringBuilder pszFile , int cchMaxPath , ref WIN32_FIND_DATAW pfd , SLGP_FLAGS fFlags ) ;
/// <summary>Retrieves the list of item identifiers for a Shell link object</summary>
void GetIDList ( out IntPtr ppidl ) ;
/// <summary>Sets the pointer to an item identifier list (PIDL) for a Shell link object.</summary>
void SetIDList ( IntPtr pidl ) ;
/// <summary>Retrieves the description string for a Shell link object</summary>
void GetDescription ( [ Out ( ) , MarshalAs ( UnmanagedType . LPWStr ) ] StringBuilder pszName , int cchMaxName ) ;
/// <summary>Sets the description for a Shell link object. The description can be any application-defined string</summary>
void SetDescription ( [ MarshalAs ( UnmanagedType . LPWStr ) ] string pszName ) ;
/// <summary>Retrieves the name of the working directory for a Shell link object</summary>
void GetWorkingDirectory ( [ Out ( ) , MarshalAs ( UnmanagedType . LPWStr ) ] StringBuilder pszDir , int cchMaxPath ) ;
/// <summary>Sets the name of the working directory for a Shell link object</summary>
void SetWorkingDirectory ( [ MarshalAs ( UnmanagedType . LPWStr ) ] string pszDir ) ;
/// <summary>Retrieves the command-line arguments associated with a Shell link object</summary>
void GetArguments ( [ Out ( ) , MarshalAs ( UnmanagedType . LPWStr ) ] StringBuilder pszArgs , int cchMaxPath ) ;
/// <summary>Sets the command-line arguments for a Shell link object</summary>
void SetArguments ( [ MarshalAs ( UnmanagedType . LPWStr ) ] string pszArgs ) ;
/// <summary>Retrieves the hot key for a Shell link object</summary>
void GetHotkey ( out short pwHotkey ) ;
/// <summary>Sets a hot key for a Shell link object</summary>
void SetHotkey ( short wHotkey ) ;
/// <summary>Retrieves the show command for a Shell link object</summary>
void GetShowCmd ( out int piShowCmd ) ;
/// <summary>Sets the show command for a Shell link object. The show command sets the initial show state of the window.</summary>
void SetShowCmd ( int iShowCmd ) ;
/// <summary>Retrieves the location (path and index) of the icon for a Shell link object</summary>
void GetIconLocation ( [ Out ( ) , MarshalAs ( UnmanagedType . LPWStr ) ] StringBuilder pszIconPath ,
int cchIconPath , out int piIcon ) ;
/// <summary>Sets the location (path and index) of the icon for a Shell link object</summary>
void SetIconLocation ( [ MarshalAs ( UnmanagedType . LPWStr ) ] string pszIconPath , int iIcon ) ;
/// <summary>Sets the relative path to the Shell link object</summary>
void SetRelativePath ( [ MarshalAs ( UnmanagedType . LPWStr ) ] string pszPathRel , int dwReserved ) ;
/// <summary>Attempts to find the target of a Shell link, even if it has been moved or renamed</summary>
void Resolve ( ref Accessibility . _RemotableHandle hwnd , SLR_FLAGS fFlags ) ;
/// <summary>Sets the path and file name of a Shell link object</summary>
void SetPath ( [ MarshalAs ( UnmanagedType . LPWStr ) ] string pszFile ) ;
}
[ComImport(), Guid("00021401-0000-0000-C000-000000000046")]
2020-08-12 00:08:44 +08:00
private class ShellLink
2020-05-14 02:43:56 +08:00
{
}
2020-07-18 13:32:21 +08:00
// Contains the description of the app
public string description { get ; set ; } = String . Empty ;
2020-05-14 02:43:56 +08:00
2020-07-18 13:32:21 +08:00
// Contains the arguments to the app
public string Arguments { get ; set ; } = String . Empty ;
2020-08-13 02:46:11 +08:00
2020-07-18 13:32:21 +08:00
public bool hasArguments { get ; set ; } = false ;
2020-05-14 02:43:56 +08:00
// Retrieve the target path using Shell Link
2020-07-18 13:32:21 +08:00
public string RetrieveTargetPath ( string path )
2020-05-14 02:43:56 +08:00
{
var link = new ShellLink ( ) ;
const int STGM_READ = 0 ;
2020-07-18 13:32:21 +08:00
try
{
( ( IPersistFile ) link ) . Load ( path , STGM_READ ) ;
}
2020-07-23 04:27:17 +08:00
catch ( System . IO . FileNotFoundException ex )
2020-07-18 13:32:21 +08:00
{
ProgramLogger . LogException ( $"|Win32| ShellLinkHelper.retrieveTargetPath | {path} | Path could not be retrieved" , ex ) ;
return String . Empty ;
}
2020-05-14 02:43:56 +08:00
var hwnd = new _RemotableHandle ( ) ;
( ( IShellLinkW ) link ) . Resolve ( ref hwnd , 0 ) ;
const int MAX_PATH = 260 ;
StringBuilder buffer = new StringBuilder ( MAX_PATH ) ;
var data = new WIN32_FIND_DATAW ( ) ;
( ( IShellLinkW ) link ) . GetPath ( buffer , buffer . Capacity , ref data , SLGP_FLAGS . SLGP_SHORTPATH ) ;
var target = buffer . ToString ( ) ;
// To set the app description
if ( ! String . IsNullOrEmpty ( target ) )
{
buffer = new StringBuilder ( MAX_PATH ) ;
( ( IShellLinkW ) link ) . GetDescription ( buffer , MAX_PATH ) ;
description = buffer . ToString ( ) ;
2020-06-06 02:34:16 +08:00
StringBuilder argumentBuffer = new StringBuilder ( MAX_PATH ) ;
( ( IShellLinkW ) link ) . GetArguments ( argumentBuffer , argumentBuffer . Capacity ) ;
2020-06-13 04:11:24 +08:00
Arguments = argumentBuffer . ToString ( ) ;
2020-06-06 02:34:16 +08:00
// Set variable to true if the program takes in any arguments
if ( argumentBuffer . Length ! = 0 )
{
hasArguments = true ;
}
2020-05-14 02:43:56 +08:00
}
return target ;
}
}
2020-08-13 02:46:11 +08:00
}