Rework registry handling

This commit is contained in:
crschnick 2024-05-25 19:30:21 +00:00
parent 4ea51c1cf4
commit 05c7028e1e
5 changed files with 196 additions and 85 deletions

View file

@ -81,7 +81,7 @@ public class AppAvCheck {
@Override
public boolean isActive() {
return WindowsRegistry.exists(
return WindowsRegistry.local().valueExists(
WindowsRegistry.HKEY_LOCAL_MACHINE, "SOFTWARE\\Bitdefender", "InstallDir");
}
},
@ -93,7 +93,7 @@ public class AppAvCheck {
@Override
public boolean isActive() {
return WindowsRegistry.exists(WindowsRegistry.HKEY_LOCAL_MACHINE, "SOFTWARE\\Malwarebytes", "id");
return WindowsRegistry.local().valueExists(WindowsRegistry.HKEY_LOCAL_MACHINE, "SOFTWARE\\Malwarebytes", "id");
}
},
MCAFEE("McAfee") {
@ -104,7 +104,7 @@ public class AppAvCheck {
@Override
public boolean isActive() {
return WindowsRegistry.exists(WindowsRegistry.HKEY_LOCAL_MACHINE, "SOFTWARE\\McAfee", "mi");
return WindowsRegistry.local().valueExists(WindowsRegistry.HKEY_LOCAL_MACHINE, "SOFTWARE\\McAfee", "mi");
}
};

View file

@ -64,11 +64,11 @@ public interface ExternalEditorType extends PrefsChoiceValue {
@Override
protected Optional<Path> determineInstallation() {
var found = WindowsRegistry.readString(WindowsRegistry.HKEY_LOCAL_MACHINE, "SOFTWARE\\Notepad++", null);
var found = WindowsRegistry.local().readString(WindowsRegistry.HKEY_LOCAL_MACHINE, "SOFTWARE\\Notepad++", null);
// Check 32 bit install
if (found.isEmpty()) {
found = WindowsRegistry.readString(
found = WindowsRegistry.local().readString(
WindowsRegistry.HKEY_LOCAL_MACHINE, "WOW6432Node\\SOFTWARE\\Notepad++", null);
}
return found.map(p -> p + "\\notepad++.exe").map(Path::of);

View file

@ -85,7 +85,7 @@ public interface TabbyTerminalType extends ExternalTerminalType {
@Override
protected Optional<Path> determineInstallation() {
var perUser = WindowsRegistry.readString(
var perUser = WindowsRegistry.local().readString(
WindowsRegistry.HKEY_CURRENT_USER,
"SOFTWARE\\71445fac-d6ef-5436-9da7-5a323762d7f5",
"InstallLocation")
@ -95,7 +95,7 @@ public interface TabbyTerminalType extends ExternalTerminalType {
return perUser;
}
var systemWide = WindowsRegistry.readString(
var systemWide = WindowsRegistry.local().readString(
WindowsRegistry.HKEY_LOCAL_MACHINE,
"SOFTWARE\\71445fac-d6ef-5436-9da7-5a323762d7f5",
"InstallLocation")

View file

@ -52,7 +52,7 @@ public interface WezTerminalType extends ExternalTerminalType {
@Override
protected Optional<Path> determineInstallation() {
Optional<String> launcherDir;
launcherDir = WindowsRegistry.readString(
launcherDir = WindowsRegistry.local().readString(
WindowsRegistry.HKEY_LOCAL_MACHINE,
"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{BCF6F0DA-5B9A-408D-8562-F680AE6E1EAF}_is1",
"InstallLocation")

View file

@ -6,103 +6,214 @@ import io.xpipe.core.process.ShellControl;
import com.sun.jna.platform.win32.Advapi32Util;
import com.sun.jna.platform.win32.WinReg;
import lombok.Value;
import java.util.Optional;
public class WindowsRegistry {
public abstract class WindowsRegistry {
@Value
public static class Key {
int hkey;
String key;
}
public static WindowsRegistry.Local local() {
return new Local();
}
public static WindowsRegistry ofShell(ShellControl shellControl) {
return shellControl.isLocal() ? local() : new Remote(shellControl);
}
public static final int HKEY_CURRENT_USER = 0x80000001;
public static final int HKEY_LOCAL_MACHINE = 0x80000002;
public static boolean exists(int hkey, String key, String valueName) {
// This can fail even with errors in case the jna native library extraction fails
try {
return Advapi32Util.registryValueExists(
hkey == HKEY_LOCAL_MACHINE ? WinReg.HKEY_LOCAL_MACHINE : WinReg.HKEY_CURRENT_USER, key, valueName);
} catch (Throwable t) {
ErrorEvent.fromThrowable(t).handle();
return false;
}
}
public abstract boolean keyExists(int hkey, String key) throws Exception;
public static Optional<String> readString(int hkey, String key) {
public abstract boolean valueExists(int hkey, String key, String valueName) throws Exception;
public abstract Optional<String> readString(int hkey, String key, String valueName) throws Exception;
public Optional<String> readString(int hkey, String key) throws Exception {
return readString(hkey, key, null);
}
public static Optional<String> readString(int hkey, String key, String valueName) {
// This can fail even with errors in case the jna native library extraction fails
try {
if (!Advapi32Util.registryValueExists(
hkey == HKEY_LOCAL_MACHINE ? WinReg.HKEY_LOCAL_MACHINE : WinReg.HKEY_CURRENT_USER,
key,
valueName)) {
public abstract Optional<String> findValuesRecursive(int hkey, String key, String valueName) throws Exception;
public abstract Optional<Key> findKeyForEqualMatchRecursive(int hkey, String key, String match) throws Exception;
public static class Local extends WindowsRegistry {
private WinReg.HKEY hkey(int hkey) {
return hkey == HKEY_LOCAL_MACHINE ? WinReg.HKEY_LOCAL_MACHINE : WinReg.HKEY_CURRENT_USER;
}
@Override
public boolean keyExists(int hkey, String key) throws Exception {
// This can fail even with errors in case the jna native library extraction or loading fails
try {
return Advapi32Util.registryKeyExists(hkey(hkey), key);
} catch (Throwable t) {
ErrorEvent.fromThrowable(t).handle();
return false;
}
}
@Override
public boolean valueExists(int hkey, String key, String valueName) {
// This can fail even with errors in case the jna native library extraction or loading fails
try {
return Advapi32Util.registryValueExists(hkey(hkey), key, valueName);
} catch (Throwable t) {
ErrorEvent.fromThrowable(t).handle();
return false;
}
}
@Override
public Optional<String> readString(int hkey, String key, String valueName) {
// This can fail even with errors in case the jna native library extraction or loading fails
try {
if (!Advapi32Util.registryValueExists(
hkey(hkey),
key,
valueName)) {
return Optional.empty();
}
return Optional.ofNullable(Advapi32Util.registryGetStringValue(hkey(hkey), key, valueName));
} catch (Throwable t) {
ErrorEvent.fromThrowable(t).handle();
return Optional.empty();
}
}
@Override
public Optional<String> findValuesRecursive(int hkey, String key, String valueName) throws Exception {
try (var sc = LocalShell.getShell().start()) {
return new Remote(sc).findValuesRecursive(hkey, key, valueName);
}
}
@Override
public Optional<Key> findKeyForEqualMatchRecursive(int hkey, String key, String match) throws Exception {
try (var sc = LocalShell.getShell().start()) {
return new Remote(sc).findKeyForEqualMatchRecursive(hkey, key, match);
}
}
}
public static class Remote extends WindowsRegistry {
private final ShellControl shellControl;
public Remote(ShellControl shellControl) {this.shellControl = shellControl;}
private String hkey(int hkey) {
return hkey == HKEY_LOCAL_MACHINE ? "HKEY_LOCAL_MACHINE" : "HKEY_CURRENT_USER";
}
@Override
public boolean keyExists(int hkey, String key) throws Exception {
var command = CommandBuilder.of()
.add("reg", "query")
.addQuoted(hkey(hkey) + "\\" + key)
.add("/ve");
try (var c = shellControl.command(command).start()) {
return c.discardAndCheckExit();
}
}
@Override
public boolean valueExists(int hkey, String key, String valueName) throws Exception {
var command = CommandBuilder.of()
.add("reg", "query")
.addQuoted(hkey(hkey) + "\\" + key)
.add("/v")
.addQuoted(valueName);
try (var c = shellControl.command(command).start()) {
return c.discardAndCheckExit();
}
}
@Override
public Optional<String> readString(int hkey, String key, String valueName) throws Exception {
var command = CommandBuilder.of()
.add("reg", "query")
.addQuoted(hkey(hkey) + "\\" + key)
.add("/v")
.addQuoted(valueName);
String output;
try (var c = shellControl.command(command).start()) {
output = c.readStdoutDiscardErr();
if (c.getExitCode() != 0) {
return Optional.empty();
}
}
// Output has the following format:
// \n<Version information>\n\n<key>\t<registry type>\t<value>
if (output.contains("\t")) {
String[] parsed = output.split("\t");
return Optional.of(parsed[parsed.length - 1]);
}
if (output.contains(" ")) {
String[] parsed = output.split(" ");
return Optional.of(parsed[parsed.length - 1]);
}
return Optional.ofNullable(Advapi32Util.registryGetStringValue(
hkey == HKEY_LOCAL_MACHINE ? WinReg.HKEY_LOCAL_MACHINE : WinReg.HKEY_CURRENT_USER, key, valueName));
} catch (Throwable t) {
ErrorEvent.fromThrowable(t).handle();
return Optional.empty();
}
}
public static boolean remoteKeyExists(ShellControl shellControl, int hkey, String key) throws Exception {
var command = CommandBuilder.of()
.add("reg", "query")
.addQuoted((hkey == HKEY_LOCAL_MACHINE ? "HKEY_LOCAL_MACHINE" : "HKEY_CURRENT_USER") + "\\" + key)
.add("/ve");
try (var c = shellControl.command(command).start()) {
return c.discardAndCheckExit();
}
}
public static Optional<String> findRemoteValuesRecursive(
ShellControl shellControl, int hkey, String key, String valueName) throws Exception {
var command = CommandBuilder.of()
.add("reg", "query")
.addQuoted((hkey == HKEY_LOCAL_MACHINE ? "HKEY_LOCAL_MACHINE" : "HKEY_CURRENT_USER") + "\\" + key)
.add("/v")
.addQuoted(valueName)
.add("/s");
try (var c = shellControl.command(command).start()) {
var output = c.readStdoutDiscardErr();
if (c.getExitCode() != 0) {
return Optional.empty();
} else {
return Optional.of(output);
}
}
}
public static Optional<String> readRemoteString(ShellControl shellControl, int hkey, String key, String valueName)
throws Exception {
var command = CommandBuilder.of()
.add("reg", "query")
.addQuoted((hkey == HKEY_LOCAL_MACHINE ? "HKEY_LOCAL_MACHINE" : "HKEY_CURRENT_USER") + "\\" + key)
.add("/v")
.addQuoted(valueName);
String output;
try (var c = shellControl.command(command).start()) {
output = c.readStdoutDiscardErr();
if (c.getExitCode() != 0) {
return Optional.empty();
@Override
public Optional<String> findValuesRecursive(int hkey, String key, String valueName) throws Exception {
var command = CommandBuilder.of()
.add("reg", "query")
.addQuoted(hkey(hkey) + "\\" + key)
.add("/v")
.addQuoted(valueName)
.add("/s");
try (var c = shellControl.command(command).start()) {
var output = c.readStdoutDiscardErr();
if (c.getExitCode() != 0) {
return Optional.empty();
} else {
return Optional.of(output);
}
}
}
// Output has the following format:
// \n<Version information>\n\n<key>\t<registry type>\t<value>
if (output.contains("\t")) {
String[] parsed = output.split("\t");
return Optional.of(parsed[parsed.length - 1]);
@Override
public Optional<Key> findKeyForEqualMatchRecursive(int hkey, String key, String match) throws Exception {
var command = CommandBuilder.of()
.add("reg", "query")
.addQuoted(hkey(hkey) + "\\" + key)
.add("/f")
.addQuoted(match)
.add("/s")
.add("/e")
.add("/d");
try (var c = shellControl.command(command).start()) {
var output = c.readStdoutDiscardErr();
if (c.getExitCode() != 0) {
return Optional.empty();
} else {
return output.lines().findFirst().flatMap(s -> {
if (s.startsWith("HKEY_CURRENT_USER\\")) {
return Optional.of(new Key(HKEY_CURRENT_USER, s.replace("HKEY_CURRENT_USER\\", "")));
}
if (s.startsWith("HKEY_LOCAL_MACHINE\\")) {
return Optional.of(new Key(HKEY_LOCAL_MACHINE, s.replace("HKEY_LOCAL_MACHINE\\", "")));
}
return Optional.empty();
});
}
}
}
if (output.contains(" ")) {
String[] parsed = output.split(" ");
return Optional.of(parsed[parsed.length - 1]);
}
return Optional.empty();
}
}