Search code examples
c#pinvokehotkeys

How can I assign a hot key to a shortcut programmatically?


I am revising my question again and re-sharing the complete code in a testable way:

I am using this class to create shortcut to desktop on C#:

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Text;

namespace WinForms;

class Program
{
    // Define the IShellLinkW interface
    [ComImport]
    [Guid("000214F9-0000-0000-C000-000000000046")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    interface IShellLinkW
    {
        void GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, out IntPtr pfd, uint fFlags);
        void GetIDList(out IntPtr ppidl);
        void SetIDList(IntPtr pidl);
        void GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, 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 wHotKey);
        void SetHotKey(short wHotKey);
        void GetShowCmd(out int iShowCmd);
        void SetShowCmd(int iShowCmd);
        void GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchIconPath, out int iIcon);
        void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
        void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, uint dwReserved);
        void Resolve(IntPtr hwnd, uint fFlags);
        void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
    }

    // Define the CLSID of ShellLink
    [ComImport]
    [Guid("00021401-0000-0000-C000-000000000046")]
    class ShellLink
    {
    }

    // Define the hotkey modifiers
    const int MOD_ALT = 0x0001;
    const int MOD_CONTROL = 0x0002;
    const int MOD_SHIFT = 0x0004;

    static void Main(string[] args)
    {
        // Create an instance of ShellLink
        IShellLinkW link = (IShellLinkW)new ShellLink();

        // Set the path of the target file
        link.SetPath(@"C:\Program Files\MyApp\MyApp.exe");

        // Set the working directory of the target file
        link.SetWorkingDirectory(@"C:\Program Files\MyApp");

        // Set the description of the shortcut
        link.SetDescription("My shortcut for MyApp");

        // Set the hotkey of the shortcut
        short hotkey = (short)(MOD_CONTROL | MOD_ALT | (int)ConsoleKey.S);
        link.SetHotKey(hotkey);

        // Save the shortcut to the desktop
        IPersistFile file = (IPersistFile)link;
        string desktopPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
        string shortcutPath = Path.Combine(desktopPath, "MyApp.lnk");
        file.Save(shortcutPath, false);

        // Release the COM objects
        Marshal.FinalReleaseComObject(file);
        Marshal.FinalReleaseComObject(link);
    }
}

Unfortunately, although this code can create a shortcut to the desktop, it only assigns the S key as a shortcut key like this:

enter image description here

Whereas I want to assign Ctrl + Alt + S. How can I assing Ctrl + Alt + S to my "MyApp.lnk" shortcut in this scenerio?


Solution

  • Have you tried using virtual key codes rather than casting from ConsoleKey.[Key]?

    // Define virtual key codes and modifiers
    const int VK_S = 0x53; // Virtual-Key code for 'S'
    const byte HOTKEYF_CONTROL = 0x02; // Modifier byte for Control
    const byte HOTKEYF_ALT = 0x01; // Modifier byte for Alt
    
    // Combine the modifiers and the key code into a short
    // High-order byte for modifiers, low-order byte for the key
    short hotkey = (short)((HOTKEYF_CONTROL << 8) | (HOTKEYF_ALT << 8) | VK_S);
    
    link.SetHotKey(hotkey);