diff --git a/core/src/cn/harryh/arkpets/ArkConfig.java b/core/src/cn/harryh/arkpets/ArkConfig.java index 127a33d2..80c020c2 100644 --- a/core/src/cn/harryh/arkpets/ArkConfig.java +++ b/core/src/cn/harryh/arkpets/ArkConfig.java @@ -185,87 +185,6 @@ public enum RenderOutline { } - /** Only available in Windows OS. - */ - public static class StartupConfig { - public static File startupDir; - public static File startupFile; - - static { - try { - startupDir = new File(System.getProperty("user.home") + "/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Startup"); - if (!startupDir.isDirectory()) - throw new FileNotFoundException("No such directory " + startupDir.getAbsolutePath()); - startupFile = new File(startupDir.getAbsolutePath(), startUpScript); - } catch (Exception e) { - startupDir = null; - startupFile = null; - Logger.error("Config", "Auto-startup config may be unavailable, details see below.", e); - } - } - - public static boolean addStartup() { - try { - String script = generateScript(); - if (script == null || startupDir == null) - throw new IOException("Generate script failed."); - FileUtil.writeString(startupFile, charsetVBS, script, false); - Logger.info("Config", "Auto-startup was added: " + startupFile.getAbsolutePath()); - return true; - } catch (Exception e) { - Logger.error("Config", "Auto-startup adding failed, details see below.", e); - return false; - } - } - - public static void removeStartup() { - try { - FileUtil.delete(startupFile.toPath(), false); - Logger.info("Config", "Auto-startup was removed: " + startupFile.getAbsolutePath()); - } catch (Exception e) { - Logger.error("Config", "Auto-startup removing failed, details see below.", e); - } - } - - public static boolean isSetStartup() { - try { - if (!startupFile.exists()) - return false; - String script = generateScript(); - if (script == null || startupDir == null) - throw new IOException("Generate script failed."); - String checksum1 = FileUtil.getMD5(Objects.requireNonNull(script).getBytes(charsetVBS)); - String checksum2 = FileUtil.getMD5(startupFile); - return checksum1.equals(checksum2); - } catch (Exception e) { - return false; - } - } - - /** Gets a content of a VBS script which can start ArkPets. - * @return The script's content. - */ - public static String generateScript() { - if (!new File(startupTarget).exists()) - return null; - String cd = System.getProperty("user.dir"); - cd = cd.replaceAll("\"", "\"\""); - cd = cd + (cd.endsWith("\\") ? "" : "\\"); - String run = startupTarget + " --direct-start"; - run = run.replaceAll("\"", "\"\""); - return "rem *** This is an auto-startup script, you can delete it if you want. ***\n" + - "const cd = \"" + cd + "\"\n" + - "const ex = \"" + startupTarget + "\"\n" + - "set fso=WScript.CreateObject(\"Scripting.FileSystemObject\")\n" + - "if fso.FileExists(cd & ex) then\n" + - " set s = WScript.CreateObject(\"WScript.shell\")\n" + - " s.CurrentDirectory = cd\n" + - " s.Run \"" + run + "\"\n" + - "end if\n"; - } - } - - @SuppressWarnings("unused") public static class Monitor { public String name; diff --git a/core/src/cn/harryh/arkpets/Const.java b/core/src/cn/harryh/arkpets/Const.java index 23490430..b03398d8 100644 --- a/core/src/cn/harryh/arkpets/Const.java +++ b/core/src/cn/harryh/arkpets/Const.java @@ -55,7 +55,6 @@ public final class Const { // Encoding presets public static final String charsetDefault = "UTF-8"; - public static final String charsetVBS = "GBK"; // Paths of static files and internal files public static final String configExternal = "ArkPetsConfig.json"; @@ -65,8 +64,6 @@ public final class Const { public static final String pass1FShader = "shaders/TCPBFragment.glsl"; public static final String pass2VShader = "shaders/TCPBVertex.glsl"; public static final String pass2FShader = "shaders/OutlineFragment.glsl"; - public static final String startupTarget = "ArkPets.exe"; - public static final String startUpScript = "ArkPetsStartupService.vbs"; // Changeable constants public static boolean isHttpsTrustAll = false; diff --git a/core/src/cn/harryh/arkpets/platform/NullStartupConfig.java b/core/src/cn/harryh/arkpets/platform/NullStartupConfig.java new file mode 100644 index 00000000..2eb9cf9d --- /dev/null +++ b/core/src/cn/harryh/arkpets/platform/NullStartupConfig.java @@ -0,0 +1,26 @@ +/** Copyright (c) 2022-2024, Harry Huang, Litwak913 + * At GPL-3.0 License + */ +package cn.harryh.arkpets.platform; + +public class NullStartupConfig extends StartupConfig { + @Override + public boolean addStartup() { + return true; + } + + @Override + public void removeStartup() { + + } + + @Override + public boolean isSetStartup() { + return false; + } + + @Override + public boolean isStartupAvailable() { + return false; + } +} diff --git a/core/src/cn/harryh/arkpets/platform/StartupConfig.java b/core/src/cn/harryh/arkpets/platform/StartupConfig.java new file mode 100644 index 00000000..759715cc --- /dev/null +++ b/core/src/cn/harryh/arkpets/platform/StartupConfig.java @@ -0,0 +1,36 @@ +/** Copyright (c) 2022-2024, Harry Huang, Litwak913 + * At GPL-3.0 License + */ +package cn.harryh.arkpets.platform; + +import com.sun.jna.Platform; + + +public abstract class StartupConfig { + /** Gets the platform StartupConfig. + * @return platform StartupConfig. + */ + public static StartupConfig getInstance() { + if (Platform.isWindows()) { + return new WindowsStartupConfig(); + } + return new NullStartupConfig(); + } + + /** Enable autostart. + * @return true=success, false=failure. + */ + public abstract boolean addStartup(); + + /** Disable autostart. + */ + public abstract void removeStartup(); + + /** Returns true if autostart is enabled. + */ + public abstract boolean isSetStartup(); + + /** Returns true if autostart is available. + */ + public abstract boolean isStartupAvailable(); +} diff --git a/core/src/cn/harryh/arkpets/platform/WindowsStartupConfig.java b/core/src/cn/harryh/arkpets/platform/WindowsStartupConfig.java new file mode 100644 index 00000000..cf406364 --- /dev/null +++ b/core/src/cn/harryh/arkpets/platform/WindowsStartupConfig.java @@ -0,0 +1,146 @@ +/** Copyright (c) 2022-2024, Harry Huang, Litwak913 + * At GPL-3.0 License + */ +package cn.harryh.arkpets.platform; + +import cn.harryh.arkpets.utils.IOUtils; +import cn.harryh.arkpets.utils.Logger; +import com.sun.jna.Pointer; +import com.sun.jna.WString; +import com.sun.jna.platform.win32.COM.COMUtils; +import com.sun.jna.platform.win32.COM.Unknown; +import com.sun.jna.platform.win32.Guid; +import com.sun.jna.platform.win32.Ole32; +import com.sun.jna.platform.win32.WTypes; +import com.sun.jna.platform.win32.WinNT; +import com.sun.jna.ptr.PointerByReference; + +import java.io.File; +import java.io.FileNotFoundException; + + +public class WindowsStartupConfig extends StartupConfig { + private boolean available; + private File startupDir; + private File startupFile; + + private static final String startupTarget = "ArkPets.exe"; + private static final String startupShortcut = "ArkPetsStartup.lnk"; + private static final String oldStartupScript = "ArkPetsStartupService.vbs"; + + public WindowsStartupConfig() { + try { + this.startupDir = new File(System.getProperty("user.home") + "/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Startup"); + if (!this.startupDir.isDirectory()) + throw new FileNotFoundException("No such directory " + startupDir.getAbsolutePath()); + if (!new File(startupTarget).exists()) + throw new FileNotFoundException("Executable not found."); + this.startupFile = new File(startupDir.getAbsolutePath(), startupShortcut); + this.available = true; + } catch (Exception e) { + this.startupDir = null; + this.startupFile = null; + this.available = false; + Logger.error("Config", "Auto-startup config may be unavailable, details see below.", e); + } + File oldStartup = new File(startupDir.getAbsolutePath(), oldStartupScript); + if (oldStartup.exists()) { + Logger.debug("Config", "Found old startup script,migrate to shortcut."); + if(oldStartup.delete()){ + addStartup(); + } + } + } + + @Override + public boolean addStartup() { + if (!this.available) return false; + try { + IShellLink lnk = IShellLink.create(); + IPersistFile pf = lnk.getPF(); + String cd = System.getProperty("user.dir"); + cd = cd.replaceAll("\"", "\"\""); + lnk.SetPath(cd + "\\" + startupTarget); + lnk.SetArguments("--direct-start"); + lnk.SetWorkingDirectory(cd); + pf.Save(startupFile.getAbsolutePath().replaceAll("\"", "\"\"")); + pf.Release(); + lnk.Release(); + return true; + } catch (Exception e) { + Logger.error("Config", "Auto-startup adding failed, details see below.", e); + return false; + } + } + + @Override + public void removeStartup() { + try { + IOUtils.FileUtil.delete(startupFile.toPath(), false); + Logger.info("Config", "Auto-startup was removed: " + startupFile.getAbsolutePath()); + } catch (Exception e) { + Logger.error("Config", "Auto-startup removing failed, details see below.", e); + } + } + + @Override + public boolean isSetStartup() { + if (!this.available) return false; + return startupFile.exists(); + } + + @Override + public boolean isStartupAvailable() { + return this.available; + } + + private static class IPersistFile extends Unknown { + private IPersistFile(Pointer ptr) { + super(ptr); + } + + public void Save(String path) { + int res = this._invokeNativeInt(6, new Object[]{this.getPointer(), new WString(path), true}); + COMUtils.checkRC(new WinNT.HRESULT(res)); + } + } + + private static class IShellLink extends Unknown { + private static final Guid.GUID CLSID_ShellLink = new Guid.GUID("{00021401-0000-0000-c000-000000000046}"); + private static final Guid.GUID IID_IShellLinkW = new Guid.GUID("{000214F9-0000-0000-c000-000000000046}"); + private static final Guid.GUID IID_IPersistFile = new Guid.GUID("{0000010B-0000-0000-c000-000000000046}"); + + private IShellLink(Pointer ptr) { + super(ptr); + } + + public static IShellLink create() { + PointerByReference p = new PointerByReference(); + WinNT.HRESULT hr = Ole32.INSTANCE.CoCreateInstance(CLSID_ShellLink, Pointer.NULL, WTypes.CLSCTX_INPROC_SERVER, IID_IShellLinkW, p); + COMUtils.checkRC(hr); + return new IShellLink(p.getValue()); + } + + public void SetPath(String path) { + int res = this._invokeNativeInt(20, new Object[]{this.getPointer(), new WString(path)}); + COMUtils.checkRC(new WinNT.HRESULT(res)); + } + + public void SetWorkingDirectory(String path) { + int res = this._invokeNativeInt(9, new Object[]{this.getPointer(), new WString(path)}); + COMUtils.checkRC(new WinNT.HRESULT(res)); + } + + public void SetArguments(String arg) { + int res = this._invokeNativeInt(11, new Object[]{this.getPointer(), new WString(arg)}); + COMUtils.checkRC(new WinNT.HRESULT(res)); + } + + public IPersistFile getPF() { + PointerByReference p = new PointerByReference(); + WinNT.HRESULT hr = this.QueryInterface(new Guid.REFIID(new Guid.IID(IID_IPersistFile)), p); + COMUtils.checkRC(hr); + return new IPersistFile(p.getValue()); + } + } +} diff --git a/desktop/src/cn/harryh/arkpets/controllers/SettingsModule.java b/desktop/src/cn/harryh/arkpets/controllers/SettingsModule.java index df8f3b0d..5803f3ca 100644 --- a/desktop/src/cn/harryh/arkpets/controllers/SettingsModule.java +++ b/desktop/src/cn/harryh/arkpets/controllers/SettingsModule.java @@ -8,6 +8,7 @@ import cn.harryh.arkpets.Const; import cn.harryh.arkpets.guitasks.CheckAppUpdateTask; import cn.harryh.arkpets.guitasks.GuiTask; +import cn.harryh.arkpets.platform.StartupConfig; import cn.harryh.arkpets.utils.*; import cn.harryh.arkpets.utils.GuiComponents.*; import com.badlogic.gdx.graphics.Color; @@ -287,10 +288,11 @@ else if (args.contains(Const.LogConfig.debugArg)) configNetworkAgentStatus.setText("未使用代理"); configNetworkAgentStatus.setStyle("-fx-text-fill:" + GuiPrefabs.Colors.COLOR_LIGHT_GRAY); - configAutoStartup.setSelected(ArkConfig.StartupConfig.isSetStartup()); + StartupConfig startup = StartupConfig.getInstance(); + configAutoStartup.setSelected(startup.isSetStartup()); configAutoStartup.setOnAction(e -> { if (configAutoStartup.isSelected()) { - if (ArkConfig.StartupConfig.addStartup()) { + if (startup.addStartup()) { GuiPrefabs.Dialogs.createCommonDialog(app.body, GuiPrefabs.Icons.getIcon(GuiPrefabs.Icons.ICON_SUCCESS_ALT, GuiPrefabs.Colors.COLOR_SUCCESS), "开机自启动", @@ -298,7 +300,7 @@ else if (args.contains(Const.LogConfig.debugArg)) "下次开机时将会自动生成您最后一次启动的桌宠。", null).show(); } else { - if (ArkConfig.StartupConfig.generateScript() == null) + if (!startup.isStartupAvailable()) GuiPrefabs.Dialogs.createCommonDialog(app.body, GuiPrefabs.Icons.getIcon(GuiPrefabs.Icons.ICON_WARNING_ALT, GuiPrefabs.Colors.COLOR_WARNING), "开机自启动", @@ -315,7 +317,7 @@ else if (args.contains(Const.LogConfig.debugArg)) configAutoStartup.setSelected(false); } } else { - ArkConfig.StartupConfig.removeStartup(); + startup.removeStartup(); } });