#import "Basic"; #import "Windows"; #import "Windows_Utf8"; #import "File"; #import "String"; #import "Thread"; // Win32 declarations are provided by win32.jai loaded in the main workspace. Dialog_State :: struct { edit_hwnd: HWND; ok_hwnd: HWND; cancel_hwnd: HWND; dialog_done: bool; url_saved: bool; is_test_mode: bool; } dialog_proc :: (hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #c_call { ctx: #Context; push_context ctx { state := cast(*Dialog_State) GetWindowLongPtrW(hwnd, GWLP_USERDATA); if msg == { case WM_CREATE; { create_struct := cast(*CREATESTRUCTW) lparam; state = cast(*Dialog_State) create_struct.lpCreateParams; SetWindowLongPtrW(hwnd, GWLP_USERDATA, cast(LONG_PTR) state); hFont := GetStockObject(DEFAULT_GUI_FONT); static_label := CreateWindowExW( 0, utf8_to_wide("STATIC"), utf8_to_wide("Enter Sing-box Config URL:"), WS_CHILD | WS_VISIBLE | SS_LEFT, 20, 20, 410, 20, hwnd, null, null, null ); SendMessageW(static_label, WM_SETFONT, cast(WPARAM) hFont, TRUE); state.edit_hwnd = CreateWindowExW( WS_EX_CLIENTEDGE, utf8_to_wide("EDIT"), utf8_to_wide(""), WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | ES_AUTOHSCROLL, 20, 45, 410, 25, hwnd, null, null, null ); SendMessageW(state.edit_hwnd, WM_SETFONT, cast(WPARAM) hFont, TRUE); // Populate with existing URL if present config_filename := global_config_path; config_data, read_ok := read_entire_file(config_filename); if read_ok { existing_url := get_json_string_field(config_data, "\"_url\""); if existing_url { wide_url := utf8_to_wide(existing_url); SetWindowTextW(state.edit_hwnd, wide_url); } free(config_data); } state.ok_hwnd = CreateWindowExW( 0, utf8_to_wide("BUTTON"), utf8_to_wide("OK"), WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_DEFPUSHBUTTON, 220, 85, 100, 30, hwnd, cast(HMENU) IDOK, null, null ); SendMessageW(state.ok_hwnd, WM_SETFONT, cast(WPARAM) hFont, TRUE); state.cancel_hwnd = CreateWindowExW( 0, utf8_to_wide("BUTTON"), utf8_to_wide("Cancel"), WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON, 330, 85, 100, 30, hwnd, cast(HMENU) IDCANCEL, null, null ); SendMessageW(state.cancel_hwnd, WM_SETFONT, cast(WPARAM) hFont, TRUE); SetFocus(state.edit_hwnd); return 0; } case WM_COMMAND; { control_id := LOWORD(wparam); if control_id == IDOK { length := GetWindowTextLengthW(state.edit_hwnd); if length > 0 { buffer := cast(*u16) alloc((length + 1) * size_of(u16)); defer free(buffer); GetWindowTextW(state.edit_hwnd, buffer, length + 1); url_utf8 := wide_to_utf8(buffer); defer free(url_utf8); trimmed_url := trim(url_utf8); if trimmed_url { mode: string; port := ifx state.is_test_mode then 10899 else 10801; update_interval := 3600; config_filename := global_config_path; config_data, read_ok := read_entire_file(config_filename); if read_ok { extracted_mode := get_json_string_field(config_data, "\"_mode\""); if extracted_mode { mode = copy_string(extracted_mode); } else { mode = copy_string("system_proxy"); } port_str := get_json_val_field(config_data, "\"_port\""); if port_str { val, ok := to_integer(port_str); if ok port = xx val; } interval_str := get_json_val_field(config_data, "\"_update_interval\""); if interval_str { val, ok := to_integer(interval_str); if ok update_interval = xx val; } free(config_data); } else { mode = copy_string("system_proxy"); } defer free(mode); minimal_json := tprint("{\n \"_url\": \"%\",\n \"_mode\": \"%\",\n \"_port\": %,\n \"_update_interval\": %,\n \"inbounds\": [],\n \"outbounds\": []\n}", trimmed_url, mode, port, update_interval); write_entire_file(config_filename, minimal_json); state.url_saved = true; } } else { config_filename := global_config_path; DeleteFileW(utf8_to_wide(config_filename)); state.url_saved = true; } DestroyWindow(hwnd); return 0; } else if control_id == IDCANCEL { DestroyWindow(hwnd); return 0; } } case WM_CLOSE; { DestroyWindow(hwnd); return 0; } case WM_DESTROY; { if state { state.dialog_done = true; } PostThreadMessageW(GetCurrentThreadId(), WM_NULL, 0, 0); return 0; } } return DefWindowProcW(hwnd, msg, wparam, lparam); } } show_config_url_dialog :: (parent_hwnd: HWND, is_test_mode := false) -> bool { hInstance := GetModuleHandleW(null); class_name := utf8_to_wide("Sing-boxConfigUrlDialogClass"); wclass: WNDCLASSEXW; wclass.cbSize = size_of(WNDCLASSEXW); wclass.style = CS_HREDRAW | CS_VREDRAW; wclass.lpfnWndProc = dialog_proc; wclass.hInstance = hInstance; wclass.hCursor = LoadCursorW(null, IDC_ARROW); wclass.hbrBackground = cast(HBRUSH) (COLOR_WINDOW + 1); wclass.lpszClassName = class_name; RegisterClassExW(*wclass); defer UnregisterClassW(class_name, hInstance); screen_w := GetSystemMetrics(SM_CXSCREEN); screen_h := GetSystemMetrics(SM_CYSCREEN); dialog_w: s32 = 460; dialog_h: s32 = 170; dialog_x := (screen_w - dialog_w) / 2; dialog_y := (screen_h - dialog_h) / 2; state: Dialog_State; state.is_test_mode = is_test_mode; dialog_hwnd := CreateWindowExW( WS_EX_DLGMODALFRAME, class_name, utf8_to_wide("Configure Sing-box URL"), WS_POPUP | WS_CAPTION | WS_SYSMENU, dialog_x, dialog_y, dialog_w, dialog_h, parent_hwnd, null, hInstance, *state ); if !dialog_hwnd return false; if parent_hwnd { EnableWindow(parent_hwnd, FALSE); } ShowWindow(dialog_hwnd, SW_SHOW); UpdateWindow(dialog_hwnd); while !state.dialog_done { msg: MSG; if GetMessageW(*msg, null, 0, 0) { if !IsDialogMessageW(dialog_hwnd, *msg) { TranslateMessage(*msg); DispatchMessageW(*msg); } } else { PostQuitMessage(cast(s32) msg.wParam); break; } } if parent_hwnd { EnableWindow(parent_hwnd, TRUE); SetFocus(parent_hwnd); } return state.url_saved; } show_config_port_dialog :: (parent_hwnd: HWND, is_test_mode := false) -> bool { // Port Dialog Proc port_dialog_proc :: (hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #c_call { ctx: #Context; push_context ctx { state := cast(*Dialog_State) GetWindowLongPtrW(hwnd, GWLP_USERDATA); if msg == { case WM_CREATE; { create_struct := cast(*CREATESTRUCTW) lparam; state = cast(*Dialog_State) create_struct.lpCreateParams; SetWindowLongPtrW(hwnd, GWLP_USERDATA, cast(LONG_PTR) state); hFont := GetStockObject(DEFAULT_GUI_FONT); label_hwnd := CreateWindowExW( 0, utf8_to_wide("STATIC"), utf8_to_wide("Enter SOCKS/HTTP proxy port (default 10801):"), WS_CHILD | WS_VISIBLE, 20, 20, 410, 20, hwnd, null, null, null ); SendMessageW(label_hwnd, WM_SETFONT, cast(WPARAM) hFont, TRUE); state.edit_hwnd = CreateWindowExW( 0, utf8_to_wide("EDIT"), utf8_to_wide(""), WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER | ES_AUTOHSCROLL | ES_NUMBER, 20, 45, 410, 25, hwnd, null, null, null ); SendMessageW(state.edit_hwnd, WM_SETFONT, cast(WPARAM) hFont, TRUE); // Populate with existing port if present config_filename := global_config_path; config_data, read_ok := read_entire_file(config_filename); port := ifx state.is_test_mode then 10899 else 10801; if !state.is_test_mode && read_ok { port_str := get_json_val_field(config_data, "\"_port\""); if port_str { val, ok := to_integer(port_str); if ok { port = xx val; } } free(config_data); } else if state.is_test_mode && read_ok { port_str := get_json_val_field(config_data, "\"_port\""); if port_str { val, ok := to_integer(port_str); if ok { port = xx val; } } free(config_data); } wide_port := utf8_to_wide(tprint("%", port)); SetWindowTextW(state.edit_hwnd, wide_port); state.ok_hwnd = CreateWindowExW( 0, utf8_to_wide("BUTTON"), utf8_to_wide("OK"), WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_DEFPUSHBUTTON, 220, 85, 100, 30, hwnd, cast(HMENU) IDOK, null, null ); SendMessageW(state.ok_hwnd, WM_SETFONT, cast(WPARAM) hFont, TRUE); state.cancel_hwnd = CreateWindowExW( 0, utf8_to_wide("BUTTON"), utf8_to_wide("Cancel"), WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON, 330, 85, 100, 30, hwnd, cast(HMENU) IDCANCEL, null, null ); SendMessageW(state.cancel_hwnd, WM_SETFONT, cast(WPARAM) hFont, TRUE); SetFocus(state.edit_hwnd); return 0; } case WM_COMMAND; { control_id := LOWORD(wparam); if control_id == IDOK { length := GetWindowTextLengthW(state.edit_hwnd); if length > 0 { buffer := cast(*u16) alloc((length + 1) * size_of(u16)); defer free(buffer); GetWindowTextW(state.edit_hwnd, buffer, length + 1); port_utf8 := wide_to_utf8(buffer); defer free(port_utf8); val, ok := to_integer(trim(port_utf8)); if ok && val > 0 && val <= 65535 { port := xx val; config_filename := global_config_path; config_data, read_ok := read_entire_file(config_filename); url := ""; mode := "system_proxy"; update_interval := 3600; if read_ok { extracted_url := get_json_string_field(config_data, "\"_url\""); if extracted_url url = copy_string(extracted_url); extracted_mode := get_json_string_field(config_data, "\"_mode\""); if extracted_mode { mode = copy_string(extracted_mode); } else { mode = copy_string("system_proxy"); } interval_str := get_json_val_field(config_data, "\"_update_interval\""); if interval_str { val, ok := to_integer(interval_str); if ok update_interval = xx val; } updated := set_json_metadata(config_data, url, mode, port, update_interval); write_entire_file(config_filename, updated); free(config_data); free(updated); } else { minimal_json := tprint("{\n \"_url\": \"\",\n \"_mode\": \"system_proxy\",\n \"_port\": %,\n \"_update_interval\": %,\n \"inbounds\": [],\n \"outbounds\": []\n}", port, update_interval); write_entire_file(config_filename, minimal_json); } if url free(url); free(mode); state.url_saved = true; } } DestroyWindow(hwnd); return 0; } else if control_id == IDCANCEL { DestroyWindow(hwnd); return 0; } } case WM_CLOSE; { DestroyWindow(hwnd); return 0; } case WM_DESTROY; { state.dialog_done = true; // Wake up the dialog loop PostThreadMessageW(GetCurrentThreadId(), WM_NULL, 0, 0); return 0; } } return DefWindowProcW(hwnd, msg, wparam, lparam); } } hInstance := GetModuleHandleW(null); class_name := utf8_to_wide("Sing-boxPortDialogClass"); wclass: WNDCLASSEXW; wclass.cbSize = size_of(WNDCLASSEXW); wclass.lpfnWndProc = port_dialog_proc; wclass.hInstance = hInstance; wclass.hCursor = LoadCursorW(null, IDC_ARROW); wclass.lpszClassName = class_name; RegisterClassExW(*wclass); defer UnregisterClassW(class_name, hInstance); screen_w := GetSystemMetrics(SM_CXSCREEN); screen_h := GetSystemMetrics(SM_CYSCREEN); dialog_w: s32 = 460; dialog_h: s32 = 170; dialog_x := (screen_w - dialog_w) / 2; dialog_y := (screen_h - dialog_h) / 2; state: Dialog_State; state.is_test_mode = is_test_mode; dialog_hwnd := CreateWindowExW( WS_EX_DLGMODALFRAME, class_name, utf8_to_wide("Configure Sing-box Port"), WS_POPUP | WS_CAPTION | WS_SYSMENU, dialog_x, dialog_y, dialog_w, dialog_h, parent_hwnd, null, hInstance, *state ); if !dialog_hwnd return false; if parent_hwnd { EnableWindow(parent_hwnd, FALSE); } ShowWindow(dialog_hwnd, SW_SHOW); UpdateWindow(dialog_hwnd); while !state.dialog_done { msg: MSG; if GetMessageW(*msg, null, 0, 0) { if !IsDialogMessageW(dialog_hwnd, *msg) { TranslateMessage(*msg); DispatchMessageW(*msg); } } else { PostQuitMessage(cast(s32) msg.wParam); break; } } if parent_hwnd { EnableWindow(parent_hwnd, TRUE); SetFocus(parent_hwnd); } return state.url_saved; } Download_Thread_Data :: struct { url: string; dest_path: string; success: bool; error_msg: string; done: bool; } download_thread_proc :: (thread: *Thread) -> s64 { data := cast(*Download_Thread_Data) thread.data; data.success, data.error_msg = download_file(data.url, data.dest_path); data.done = true; return 0; } Download_Dialog_State :: struct { dialog_done: bool; thread: Thread; thread_data: Download_Thread_Data; static_hwnd: HWND; } download_dialog_proc :: (hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #c_call { ctx: #Context; push_context ctx { state := cast(*Download_Dialog_State) GetWindowLongPtrW(hwnd, GWLP_USERDATA); if msg == { case WM_CREATE; { create_struct := cast(*CREATESTRUCTW) lparam; state = cast(*Download_Dialog_State) create_struct.lpCreateParams; SetWindowLongPtrW(hwnd, GWLP_USERDATA, cast(LONG_PTR) state); hFont := GetStockObject(DEFAULT_GUI_FONT); state.static_hwnd = CreateWindowExW( 0, utf8_to_wide("STATIC"), utf8_to_wide("Downloading Sing-box core executable...\nThis may take a moment, please wait."), WS_CHILD | WS_VISIBLE | SS_LEFT, 30, 30, 400, 50, hwnd, null, null, null ); SendMessageW(state.static_hwnd, WM_SETFONT, cast(WPARAM) hFont, TRUE); thread_init(*state.thread, download_thread_proc); state.thread.data = *state.thread_data; thread_start(*state.thread); SetTimer(hwnd, 1, 100, null); return 0; } case WM_TIMER; { if wparam == 1 { if state.thread_data.done { KillTimer(hwnd, 1); thread_is_done(*state.thread, -1); // Capture error_msg (which may be temp-allocated inside download thread) BEFORE deinit frees the thread temp storage. captured_success := state.thread_data.success; captured_err := copy_string(state.thread_data.error_msg); thread_deinit(*state.thread); // Overwrite with safe copies (heap allocated) so that the post-loop return sees valid data. state.thread_data.success = captured_success; state.thread_data.error_msg = captured_err; // Free the (copied) input paths now that thread is done with them. if state.thread_data.url.count > 0 { free(state.thread_data.url); state.thread_data.url = ""; } if state.thread_data.dest_path.count > 0 { free(state.thread_data.dest_path); state.thread_data.dest_path = ""; } DestroyWindow(hwnd); } } return 0; } case WM_CLOSE; { if state.thread_data.done { DestroyWindow(hwnd); } return 0; } case WM_DESTROY; { if state { state.dialog_done = true; } PostThreadMessageW(GetCurrentThreadId(), WM_NULL, 0, 0); return 0; } } return DefWindowProcW(hwnd, msg, wparam, lparam); } } show_download_progress_dialog :: (parent_hwnd: HWND, url: string, dest_path: string) -> bool, string { hInstance := GetModuleHandleW(null); class_name := utf8_to_wide("Sing-boxDownloadDialogClass"); wclass: WNDCLASSEXW; wclass.cbSize = size_of(WNDCLASSEXW); wclass.style = CS_HREDRAW | CS_VREDRAW; wclass.lpfnWndProc = download_dialog_proc; wclass.hInstance = hInstance; wclass.hCursor = LoadCursorW(null, IDC_ARROW); wclass.hbrBackground = cast(HBRUSH) (COLOR_WINDOW + 1); wclass.lpszClassName = class_name; RegisterClassExW(*wclass); defer UnregisterClassW(class_name, hInstance); screen_w := GetSystemMetrics(SM_CXSCREEN); screen_h := GetSystemMetrics(SM_CYSCREEN); dialog_w: s32 = 460; dialog_h: s32 = 150; dialog_x := (screen_w - dialog_w) / 2; dialog_y := (screen_h - dialog_h) / 2; state: Download_Dialog_State; state.thread_data.url = copy_string(url); state.thread_data.dest_path = copy_string(dest_path); dialog_hwnd := CreateWindowExW( WS_EX_DLGMODALFRAME, class_name, utf8_to_wide("Downloading Sing-box Core"), WS_POPUP | WS_CAPTION, dialog_x, dialog_y, dialog_w, dialog_h, parent_hwnd, null, hInstance, *state ); if !dialog_hwnd { free(state.thread_data.url); free(state.thread_data.dest_path); return false, "Failed to create dialog window"; } if parent_hwnd { EnableWindow(parent_hwnd, FALSE); } ShowWindow(dialog_hwnd, SW_SHOW); UpdateWindow(dialog_hwnd); while !state.dialog_done { msg: MSG; if GetMessageW(*msg, null, 0, 0) { if !IsDialogMessageW(dialog_hwnd, *msg) { TranslateMessage(*msg); DispatchMessageW(*msg); } } else { PostQuitMessage(cast(s32) msg.wParam); break; } } if parent_hwnd { EnableWindow(parent_hwnd, TRUE); SetFocus(parent_hwnd); } return state.thread_data.success, state.thread_data.error_msg; }