C# 創(chuàng)建系統(tǒng)右鍵菜單按鈕關(guān)聯(lián)指定程序(無(wú)需管理員權(quán)限)

前言

為了將“解決自媒體一鍵多平臺(tái)發(fā)布”項(xiàng)目做得更適合自己的使用習(xí)慣,Windows端的桌面版也立項(xiàng)了。

本篇文章分享的內(nèi)容是:實(shí)現(xiàn)系統(tǒng)右鍵菜單按鈕關(guān)聯(lián)桌面程序問(wèn)題。

一、開(kāi)發(fā)環(huán)境

  • vs2019
  • Windows 10

二、具體代碼

本次實(shí)現(xiàn)系統(tǒng)右鍵菜單按鈕功能,是通過(guò)Windows注冊(cè)表實(shí)現(xiàn)的。

1、訪問(wèn)HKEY_CURRENT_USER

使用HKEY_CURRENT_USER,是為了避免向用戶申請(qǐng)管理員權(quán)限。具體代碼如下:

//using Microsoft.Win32;
var userRegistry = Registry.CurrentUser;

2、訪問(wèn)Software\Classes\*\shell

當(dāng)前用戶的右鍵菜單按鈕信息(僅指文件),是儲(chǔ)存在Software\Classes\*\shell中的,所以我們需要拿到shell的寫權(quán)限。具體代碼如下:

var shellRegistryKey = userRegistry.OpenSubKey("Software").OpenSubKey("Classes").OpenSubKey("*").OpenSubKey("shell", true);

提示:OpenSubKey("shell", true)中的第二個(gè)參數(shù)設(shè)置為true,是為了在shell中寫入子項(xiàng)(也就是拿到shell的寫權(quán)限)。

3、判斷準(zhǔn)備生成的右鍵菜單按鈕名是否存在

為防止重復(fù)寫入導(dǎo)致出錯(cuò),先判斷子項(xiàng)名(右鍵菜單按鈕名)是否存在。代碼如下:

var isRegistryKeyNameExsit = shellRegistryKey.GetSubKeyNames().Contains(keyName);

4、寫入右鍵菜單按鈕名

首先shell中寫入子項(xiàng)(可以理解為在注冊(cè)表中的名字),然后設(shè)置剛創(chuàng)建的子項(xiàng)在右鍵菜單中的按鈕名。具體代碼:

var contextMenuRegistryKey = shellRegistryKey.CreateSubKey(keyName);

contextMenuRegistryKey.SetValue("", keyName);

提示:contextMenuRegistryKey.SetValue("", keyName)中的keyName是顯示在右鍵菜單中的按鈕名,可以不同子項(xiàng)名,使用其他名字。

5、關(guān)聯(lián)指定程序

首先在新建的子項(xiàng)中創(chuàng)建名為command的子項(xiàng),然后設(shè)置子項(xiàng)中的默認(rèn)項(xiàng)的值為"程序路徑" "%1",這樣就將指定程序與右鍵菜單按鈕進(jìn)行了關(guān)聯(lián)。

contextMenuRegistryKey.CreateSubKey("command");
command.SetValue("", $"\"{programPath}\" \"%1\"");

提示:"程序路徑" "%1"%1是為了把右鍵打開(kāi)關(guān)聯(lián)程序時(shí),把選擇的文件路徑傳給關(guān)聯(lián)程序。

如果關(guān)聯(lián)程序時(shí)Winform程序,則還需要修改Winform默認(rèn)程序,實(shí)現(xiàn)接收傳入的文件路徑的功能。

5.1、修改Winform默認(rèn)程序

(1)修改Program.cs

將默認(rèn)的無(wú)參Main()方法修改為如下代碼:

static void Main(string[] args)

(2)修改Main()方法的默認(rèn)啟動(dòng)窗口程序

代碼如下:

Application.Run(new Form1(args));

(3)修改Form1.cs

為了接收參數(shù),需要一個(gè)新的構(gòu)造函數(shù),具體代碼如下:

public Form1(string[] args) : this()
{
    this.label1.Text = string.Join(",", args);
}

提示:this()是為了不修改默認(rèn)的無(wú)參構(gòu)造函數(shù),直接調(diào)用它。

三、完整的程序代碼

1、注冊(cè)表修改

/// <summary>
/// 注冊(cè)表幫助類
/// 版本:v1
/// 日期:2022年10月15日
/// 作者:hxsfx
/// </summary>
public class RegistryHelper
{
        /// <summary>
        /// 計(jì)算機(jī)\HKEY_CURRENT_USER\Software\Classes\*\shell
        /// </summary>
        private static RegistryKey RegistryUserSoftwareClassesAllShell
        {
            get
            {
                return Registry.CurrentUser.OpenSubKey("Software").OpenSubKey("Classes").OpenSubKey("*").OpenSubKey("shell", true);
            }
        }
        /// <summary>
        /// 生成右鍵菜單按鈕(當(dāng)前用戶)
        /// </summary>
        /// <param name="keyName">右鍵菜單名</param>
        /// <param name="programPath">點(diǎn)擊按鈕后打開(kāi)的程序路徑</param>
        public static void CreateUserContextMenu(string keyName, string programPath)
        {
            if (!RegistryUserSoftwareClassesAllShell.GetSubKeyNames().Contains(keyName))
            {
                var contextMenuRegistryKey = RegistryUserSoftwareClassesAllShell.CreateSubKey(keyName);
                contextMenuRegistryKey.SetValue("", keyName);
                var command = contextMenuRegistryKey.CreateSubKey("command");
                command.SetValue("", $"\"{programPath}\" \"%1\"");
            }
        }
        /// <summary>
        /// 刪除右鍵菜單按鈕(當(dāng)前用戶)
        /// </summary>
        /// <param name="keyName">右鍵菜單名</param>
        public static void DeleteUserContextMenu(string keyName)
        {
            if (RegistryUserSoftwareClassesAllShell.GetSubKeyNames().Contains(keyName))
            {
                RegistryUserSoftwareClassesAllShell.DeleteSubKeyTree(keyName);
            }
        }
}

2、Winform代碼

(1)Program.cs

static class Program
{
    /// <summary>
    /// 應(yīng)用程序的主入口點(diǎn)。
    /// </summary>
    [STAThread]
    static void Main(string[] args)
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1(args));
    }
}

(1)窗口Form1.cs

public partial class Form1 : Form
{
    public Form1(string[] args) : this()
    {
        this.label1.Text = string.Join(",", args);
    }
    public Form1()
    {
        InitializeComponent();
    }
}

四、最后

其實(shí)個(gè)人不是很喜歡通過(guò)注冊(cè)表來(lái)實(shí)現(xiàn)功能,一方面是不了解注冊(cè)表,另一方面是總覺(jué)得注冊(cè)表不夠優(yōu)雅。哈哈~

如果各位小伙伴有什么其他更好的辦法,可以告訴我哦~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容