feat: add boot on start

This commit is contained in:
Ixniy Evonniy 2026-07-01 01:04:42 +03:00
parent b006570ab7
commit ac07317119
3 changed files with 91 additions and 0 deletions

BIN
cache.db

Binary file not shown.

View File

@ -229,6 +229,43 @@ file_exists :: (path: string) -> bool {
return attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY); return attribs != INVALID_FILE_ATTRIBUTES && !(attribs & FILE_ATTRIBUTE_DIRECTORY);
} }
is_autostart_enabled :: () -> bool {
hKey: HKEY;
subkey := utf8_to_wide("Software\\Microsoft\\Windows\\CurrentVersion\\Run");
status := RegOpenKeyExW(HKEY_CURRENT_USER, subkey, 0, KEY_READ, *hKey);
if status != 0 return false;
defer RegCloseKey(hKey);
value_name := utf8_to_wide("SingboxTray");
type: DWORD;
status = RegQueryValueExW(hKey, value_name, null, *type, null, null);
return status == 0;
}
set_autostart :: (enable: bool) -> bool {
hKey: HKEY;
subkey := utf8_to_wide("Software\\Microsoft\\Windows\\CurrentVersion\\Run");
status := RegOpenKeyExW(HKEY_CURRENT_USER, subkey, 0, KEY_WRITE, *hKey);
if status != 0 return false;
defer RegCloseKey(hKey);
value_name := utf8_to_wide("SingboxTray");
if enable {
path_buffer: [MAX_PATH] u16;
len := GetModuleFileNameW(null, path_buffer.data, MAX_PATH);
if len == 0 return false;
path_len_bytes := cast(DWORD) ((len + 1) * 2);
status = RegSetValueExW(hKey, value_name, 0, REG_SZ, cast(*u8) path_buffer.data, path_len_bytes);
return status == 0;
} else {
status = RegDeleteValueW(hKey, value_name);
return status == 0 || status == 2; // ERROR_FILE_NOT_FOUND is 2
}
}
// Hidden Process Spawning with Job Object configuration and stdout/stderr redirection // Hidden Process Spawning with Job Object configuration and stdout/stderr redirection
create_process_hidden :: (cmd: string, stdout_handle: HANDLE = INVALID_HANDLE_VALUE) -> HANDLE, PROCESS_INFORMATION, bool { create_process_hidden :: (cmd: string, stdout_handle: HANDLE = INVALID_HANDLE_VALUE) -> HANDLE, PROCESS_INFORMATION, bool {
startup_info: STARTUPINFOW; startup_info: STARTUPINFOW;
@ -579,6 +616,14 @@ show_context_menu :: (app: *App_State) {
AppendMenuW(hMenu, MF_SEPARATOR, 0, null); AppendMenuW(hMenu, MF_SEPARATOR, 0, null);
autostart_flags := MF_STRING;
if is_autostart_enabled() {
autostart_flags |= MF_CHECKED;
}
AppendMenuW(hMenu, autostart_flags, CMD_TOGGLE_AUTOSTART, utf8_to_wide("Start on Windows boot"));
AppendMenuW(hMenu, MF_SEPARATOR, 0, null);
AppendMenuW(hMenu, MF_STRING, CMD_EXIT, utf8_to_wide("Exit")); AppendMenuW(hMenu, MF_STRING, CMD_EXIT, utf8_to_wide("Exit"));
cursor_pos: POINT; cursor_pos: POINT;
@ -678,6 +723,21 @@ show_context_menu :: (app: *App_State) {
} }
} }
} }
case CMD_TOGGLE_AUTOSTART; {
currently_enabled := is_autostart_enabled();
success := set_autostart(!currently_enabled);
if success {
new_state := !currently_enabled;
if new_state {
log_info("Autostart on boot enabled.\n");
} else {
log_info("Autostart on boot disabled.\n");
}
} else {
log_error("Failed to toggle autostart registry configuration.\n");
MessageBoxW(app.hwnd, utf8_to_wide("Failed to update Windows registry autostart configuration."), utf8_to_wide("Sing-box Tray"), MB_ICONERROR);
}
}
case CMD_EXIT; { case CMD_EXIT; {
DestroyWindow(app.hwnd); DestroyWindow(app.hwnd);
} }
@ -767,6 +827,25 @@ main :: () {
} }
global_is_test_mode = is_test; global_is_test_mode = is_test;
// Change working directory to the executable's directory to resolve relative paths
// correctly when started via Windows autostart/registry.
{
buffer: [2048] u16;
len := GetModuleFileNameW(null, buffer.data, 2048);
if len > 0 {
last_backslash_idx := -1;
for i: 0..len-1 {
if buffer[i] == #char "\\" || buffer[i] == #char "/" {
last_backslash_idx = i;
}
}
if last_backslash_idx != -1 {
buffer[last_backslash_idx] = 0;
SetCurrentDirectoryW(buffer.data);
}
}
}
hInstance := GetModuleHandleW(null); hInstance := GetModuleHandleW(null);
class_name_str := ifx is_test then "SingboxTrayControllerClassTest" else "SingboxTrayControllerClass"; class_name_str := ifx is_test then "SingboxTrayControllerClassTest" else "SingboxTrayControllerClass";
class_name := utf8_to_wide(class_name_str); class_name := utf8_to_wide(class_name_str);

View File

@ -82,6 +82,7 @@ CMD_EXIT :: 1005;
CMD_MODE_PROXY :: 1006; CMD_MODE_PROXY :: 1006;
CMD_MODE_SYS_PROXY :: 1007; CMD_MODE_SYS_PROXY :: 1007;
CMD_SET_PORT :: 1008; CMD_SET_PORT :: 1008;
CMD_TOGGLE_AUTOSTART:: 1009;
// Boolean constants // Boolean constants
FALSE :: 0; FALSE :: 0;
@ -143,6 +144,7 @@ REGSAM :: u32;
HKEY_CURRENT_USER :: cast(HKEY) 0x80000001; HKEY_CURRENT_USER :: cast(HKEY) 0x80000001;
KEY_WRITE :: 0x20006; KEY_WRITE :: 0x20006;
KEY_READ :: 0x20019;
INTERNET_OPTION_SETTINGS_CHANGED :: 39; INTERNET_OPTION_SETTINGS_CHANGED :: 39;
INTERNET_OPTION_REFRESH :: 37; INTERNET_OPTION_REFRESH :: 37;
@ -150,6 +152,15 @@ INTERNET_OPTION_REFRESH :: 37;
RegOpenKeyExW :: (hKey: HKEY, lpSubKey: LPCWSTR, ulOptions: DWORD, samDesired: REGSAM, phkResult: *HKEY) -> LSTATUS #foreign advapi32; RegOpenKeyExW :: (hKey: HKEY, lpSubKey: LPCWSTR, ulOptions: DWORD, samDesired: REGSAM, phkResult: *HKEY) -> LSTATUS #foreign advapi32;
RegSetValueExW :: (hKey: HKEY, lpValueName: LPCWSTR, Reserved: DWORD, dwType: DWORD, lpData: *u8, cbData: DWORD) -> LSTATUS #foreign advapi32; RegSetValueExW :: (hKey: HKEY, lpValueName: LPCWSTR, Reserved: DWORD, dwType: DWORD, lpData: *u8, cbData: DWORD) -> LSTATUS #foreign advapi32;
RegCloseKey :: (hKey: HKEY) -> LSTATUS #foreign advapi32; RegCloseKey :: (hKey: HKEY) -> LSTATUS #foreign advapi32;
RegDeleteValueW :: (hKey: HKEY, lpValueName: LPCWSTR) -> LSTATUS #foreign advapi32;
RegQueryValueExW :: (
hKey: HKEY,
lpValueName: LPCWSTR,
lpReserved: *DWORD,
lpType: *DWORD,
lpData: *u8,
lpcbData: *DWORD
) -> LSTATUS #foreign advapi32;
InternetSetOptionW :: (hInternet: HANDLE, dwOption: DWORD, lpBuffer: *void, dwBufferLength: DWORD) -> BOOL #foreign wininet; InternetSetOptionW :: (hInternet: HANDLE, dwOption: DWORD, lpBuffer: *void, dwBufferLength: DWORD) -> BOOL #foreign wininet;
@ -265,3 +276,4 @@ set_windows_system_proxy :: (enable: bool, server: string) -> bool {