java操作注册表添加右键菜单

先看效果:
java操作注册表添加右键菜单_第1张图片
java操作注册表添加右键菜单_第2张图片

通过自己指定注册表的方式, 实现了自定义的右键菜单. 直接在文件或者目录上右键就可以执行指定的命令, 很方便. 我自己在工作中经常需要转换文件格式, 从一个数据文件转换为csv格式, 之前是通过一个swing gui工具, 然后把文件拖拽上去, 虽然方便但却不是最方便的, 直接绑定右键菜单的方式就好了很多, 可以不事先启动gui工具, 也不用管工具是在什么地方, 随时随地想转就转. 下面来研究实现:
右键菜单主要是通过改注册表实现的, 但是直接通过注册表文件.reg改注册表方式不够智能, 因为有些路径是写死的, 每次换了地方都需要手动先把.reg里的路径改了再导入, 很不方便, 所以这里通过java操作命令行调用注册表命令动态导入注册表, 优点是可以动态改变路径.

reg命令

    windows操作注册表的命令是reg命令, 具体用法可以在cmd里通过reg /? 或者reg add /?等查询.
java操作注册表添加右键菜单_第3张图片
用法就是:

reg query "HKEY_CLASSES_ROOT\*\shell\myutil"
reg add "HKEY_CLASSES_ROOT\*\shell\myutil" /v "SubCommands" /d "subcommand.1;subcommand.2" /f
reg add "HKEY_CLASSES_ROOT\*\shell\myutil" /ve /d "subcommand.1;subcommand.2" /f
reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CommandStore\shell\subcommand.2\command" /ve /d "\"cmd.exe\" /k \"java -cp \"D:\tmp\ContextMenuTest.jar\" work.drqf.Test %1\"" /f

reg query命令没什么问题. 但是reg add要注意:
(1). /ve选项表示名称为默认, 在win7上可以写成/v “” , 但win10这样写会报错, 必须用/ve
(2). 注意key和data要加引号, data中有嵌套引号要记得转义, 简单的转义是上面的例子.
(3). 上面的转义是在cmd中执行时的转义用法, win7只有cmd, 所以没什么问题, 但是win10分cmd和power shell两个命令行工具, 这两个工具的用法不一样, power shell的转义是用两个双引号"“而不是\”, 所以上面的对应的reg add就是:

reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CommandStore\shell\subcommand.2\command" /ve /d """cmd.exe"" /k ""java -cp ""D:\tmp\ContextMenuTest.jar"" work.drqf.Test %1""" /f

所以一定要分清楚是用cmd.exe来执行命令, 还是用powershell来执行. win10直接右键用的是cmd.exe.

右键菜单注册表值

这个路径下面是在文件上右键时的命令:

HKEY_CLASSES_ROOT\*

这个路径下面是在目录上右键时的命令:

HKEY_CLASSES_ROOT\Directory

HKEY_CLASSES_ROOT\Directory和HKEY_CLASSES_ROOT\Folder貌似都可以配置文件夹上右键菜单, 不知道有什么区别.
先看文件命令配置, 目录的其实是一样的, 照抄就好.
java操作注册表添加右键菜单_第4张图片
shell下面添加myutil这一项, myutil里添加两个值, MUIVerb表示的是右键菜单上实际显示出来的名称MyUtil, 如果没有MUIVerb这个值, 则显示的是key的值, 即myutil. SubCommands指定的是二级菜单, 名称是固定的, 必须叫这个名字, 值是各个子命令以分号分隔的值.
其中子命令存储在:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CommandStore\shell

所以照葫芦画瓢, 在这里添加两个对应的子命令, 目录层次见下图:
java操作注册表添加右键菜单_第5张图片
然后文件上右键, 就会出现二级菜单了.
注意: 如果二级菜单不出现, 要看父级菜单myutil下面的那个默认项是否被设了值, 正确的显示结果应该是"(数值未设置)", 而不是空白. 我第一次就是误把这里设了个空白, 结果二级菜单死活不出现. 如果误设了值, 直接在那个默认上面delete就好.
目录的设置方法和文件的配置方法一模一样, 子目录命令不用再配置, 直接引用同样的.
java操作注册表添加右键菜单_第6张图片
MUIVerb不是必须的, 只有SubCommands也是可以的.

如果不需要二级菜单, 直接点击myutil执行命令的话, 那么不需要SubCommands值, 直接在myutil下追加command项目, 在command默认值上设置data为指定的命令就行了.
java操作注册表添加右键菜单_第7张图片
注意命令中的"cmd.exe"引号里前后不要有空格, 写成"cmd.exe "就执行不了.

好了, 注册表的项目清楚了, 那么通过java代码来实现:

package work.drqf;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Paths;
import java.util.Arrays;

public class Test {
     

	public static void main(String[] args) throws Exception {
     
		// 如果不传参数, 表示首次执行, 就录入注册表信息.
		if (args.length == 0 || "".equals(args[0])) {
     
			registerUrlHandler();
			System.out.println("-----Register Url Handler success!-----");
		} else {
     
			// 通过注册表执行了程序, 这里打印出参数. 可以添加其他自定义逻辑
			System.out.println(Arrays.toString(args));
			System.out.println("Hello World");
		}
	}

	private static void registerUrlHandler() throws Exception {
     

		String curPath = Paths.get("./").toAbsolutePath().getParent().toString();

		addRegister("HKEY_CLASSES_ROOT\\*\\shell\\myutil", "MUIVerb", "MyUtil");
		addRegister("HKEY_CLASSES_ROOT\\*\\shell\\myutil", "SubCommands", "subcommand.1;subcommand.2");

		addRegister("HKEY_CLASSES_ROOT\\Directory\\shell\\myutil", "SubCommands", "subcommand.1;subcommand.2");

		addRegister(
				"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CommandStore\\shell\\subcommand.1",
				"MUIVerb", "Sub1");
		addRegister(
				"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CommandStore\\shell\\subcommand.1\\command",
				"", "\\\"cmd.exe\\\" /k \\\" echo aaaaa-%1\\\"");

		addRegister(
				"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CommandStore\\shell\\subcommand.2",
				"MUIVerb", "Sub2");
		addRegister(
				"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CommandStore\\shell\\subcommand.2\\command",
				"",
				"\\\"cmd.exe\\\" /k \\\"java -cp \\\"" + curPath + "\\ContextMenuTest.jar\\\" work.drqf.Test %1\\\"");
	}

	private static void addRegister(String key, String v, String data) throws Exception {
     
		Runtime runtime = Runtime.getRuntime();
		String cmd0 = null;
		if ("".equals(v)) {
     
			cmd0 = "reg add \"" + key + "\" /ve /d \"" + data + "\" /f";
		} else {
     
			cmd0 = "reg add \"" + key + "\" /v \"" + v + "\" /d \"" + data + "\" /f";
		}
		System.out.println(cmd0);
		Process proc = runtime.exec(cmd0);
		proc.waitFor();
		System.out.println(readStream(proc.getErrorStream()));
		System.out.println(readStream(proc.getInputStream()));
	}

	private static String readStream(InputStream is) throws IOException {
     
		try (BufferedReader br = new BufferedReader(new InputStreamReader(is));) {
     
			String content = "";
			String line = "";
			while ((line = br.readLine()) != null) {
     
				content += line;
			}
			return content;
		}
	}

}

注意代码里面的转义\\\", 由于/d 后面是全部用""引起来的, 所以如果命令里有嵌套引号, 是需要用反斜杠转义的. 更深层次的嵌套好像不用加更多的反斜杠, 最多\\\"就可以了.
把代码导出为jar包放在D:\tmp
java操作注册表添加右键菜单_第8张图片
再写一个bat文件用于首次调用jar包, 登录注册表信息:
runContextMenuTest.bat

%~d0
cd %~dp0
java -cp .\ContextMenuTest.jar work.drqf.Test %1
pause

前两行是切换到当前目录, 然后是调用java, 最后一行是控制台暂停, 方便查看控制台内容, 正式程序不需要的话可以去掉.
执行bat文件在win10下需要以管理员身份运行. 执行bat会自动导入注册表, 非常方便.
每次程序位置变更了, 手动执行bat重新导入一次就好.
如图, 在文件上右键, 打印出文件名和Hello World内容.
java程序拿到了文件名, 就可以做更多想做的事.
java操作注册表添加右键菜单_第9张图片

你可能感兴趣的:(java,注册表,右键菜单,java,shell,windows,cmd)