在Java中从ProcessBuilder执行时,Windows REG命令无法正常工作。

9
我正在尝试使用Java创建启动注册表键,但结果非常奇怪。在某些操作系统(例如XP)上,该命令可以完美地工作。然而,在Windows 7上,它只会在运行编译后的jar或类时创建该键,并且无法从网页上的小程序中创建。此外,在Windows 8上,该命令根本无法工作。我已经尝试进行调试,似乎REG命令执行成功。如果我在命令提示符中手动运行该命令,则创建键,输出与从程序内部运行时相同。以下是代码示例:
public static int regadd(String key, String name, String val) throws IOException, InterruptedException {
    ProcessBuilder pb = new ProcessBuilder(new String[]{"REG", "ADD", key, "/v", name, "/d", val, "/f"});
    pb.redirectOutput(new File(PathManager.getDirectory(), "log0.txt"));

    int i = pb.start().waitFor();
    Logger.log("ADD: " + i);

    return i;
}

在log0.txt文件中,它打印了以下内容:
"The operation completed successfully."
此外,程序的"result"也打印出了:
ADD: 0
所以此时,我无法确定问题出在哪里。我知道还有其他不可靠的添加注册表的方法,但我希望我的代码能够与所有VM分发版兼容。有没有一种方法来实现这个或修复现有的方法呢?

有两件事情引人注目,1-“而不是来自网页上的小程序”。小程序在安全沙箱内运行,这意味着它们在访问客户机器方面功能非常有限,例如运行进程等,因此除非小程序经过签名并具有适当的安全权限,否则将失败。2- Windows 7+与XP有不同的安全模型。可能是Windows安全管理器介入并静默地阻止了操作的进行。这样做有一些很好的理由,但我没有空间再继续解释了。 - MadProgrammer
你可以尝试以“管理员”身份运行浏览器,但我不确定这是否会影响Java插件的运行方式... - MadProgrammer
2
注册表虚拟化(Windows)- MSDN - 微软 - Holger
我应该提到,其他进程启动良好,并且可以毫无问题地使用IO。小程序已经签名并获得了完全的访问权限、写入权限等。Reg命令正在成功执行,但它的行为就像被沙盒隔离一样,即使不应该这样。 - Colby
请提供一个具体的例子,说明您想要创建哪些键,因为这可能会影响结果。 - Robert
显示剩余3条评论
4个回答

7
我假设你安装了多个Java虚拟机(32位、64位等),根据你执行代码的方式,会使用不同的JavaVM并得到不同的结果。
例如,在applet中,通常会进入32位Java VM(因为Web浏览器是32位的,因此VM也必须是32位的)。
在这种情况下,我认为也会执行32位版本的reg.exe。最终,写入到HKLM\Software的所有内容都会重定向到HKLM\SOFTWARE\Wow6432Node(对于HKCU\Software也是如此 -> HKCU\Software\Wow6432Node)。
无论如何,我强烈建议您监视实际发生的情况。下载并启动Sysinternals ProcessMonitor,简单查找写入到注册表的内容以及确切位置。然后,您可以确定您要添加的注册表键是否已创建,或者是否由于任何虚拟化技术而找不到它们。

我该如何执行64位版本的reg.exe?或者有其他方法可以添加到真实的注册表中吗? - Colby
它不能被重定向到wow6432node,因为这些键需要与现有应用程序进行交互。 - Colby

5

我开发了一个插件来创建注册表中的键。

import javaQuery.core.Registry;
import javaQuery.importClass.javaQueryBundle;

public class Demo {
    public static void main(String[] args) {
        String response = javaQueryBundle.createRegistry().createKey(Registry.HKEY_CURRENT_USER, "\\jqreg", Registry.key_String_Value, "Software", "javaQueryAPI");
        System.out.println(response);
    }
}

下载库文件,如果您有任何问题,请告诉我。


1

Reg add文档:

http://technet.microsoft.com/en-us/library/cc742162.aspx

所以我们可以使用http://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html#exec%28java.lang.String%29

Runtime.exec(String command)来执行命令并返回一个进程。
Process proc = Runtime.getRuntime().exec("REG ADD HKLM\Software\MyCo /v Data /t REG_BINARY /d fe340ead");

现在我们有了一个包含特定方法的Process变量: http://docs.oracle.com/javase/7/docs/api/java/lang/Process.html#getInputStream%28%29
Process.getInputStream();

让我们继续我们的代码:

InputStream in = proc.getInputStream();
for (int i = 0; i < in.available(); i++) {
    System.out.println("" + in.read());
}

我想这可能有点有用。


我已经做到了这一步!原帖显示reg.exe的输出是“操作成功完成”。 - Colby

1
为了调试这个问题,您可以尝试执行另一个程序,比如notepad.exe,以检查它是否在客户端执行。
然后您可以尝试使用"cmd.exe /C reg"代替"reg",这样会起作用。
如果可以,请告知我。

是的,其他程序可以正常运行。reg.exe正在运行,这不是问题所在。问题出在注册表可视化方面。 - Colby

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接