diff --git a/flutter/lib/desktop/pages/connection_page.dart b/flutter/lib/desktop/pages/connection_page.dart index 8964191f8..506a03b7a 100644 --- a/flutter/lib/desktop/pages/connection_page.dart +++ b/flutter/lib/desktop/pages/connection_page.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_hbb/common/widgets/address_book.dart'; @@ -9,6 +10,7 @@ import 'package:flutter_hbb/consts.dart'; import 'package:flutter_hbb/desktop/widgets/scroll_wrapper.dart'; import 'package:get/get.dart'; import 'package:url_launcher/url_launcher_string.dart'; +import 'package:window_manager/window_manager.dart'; import '../../common.dart'; import '../../common/formatter/id_formatter.dart'; @@ -27,7 +29,7 @@ class ConnectionPage extends StatefulWidget { /// State for the connection page. class _ConnectionPageState extends State - with SingleTickerProviderStateMixin { + with SingleTickerProviderStateMixin, WindowListener { /// Controller for the id input bar. final _idController = IDTextEditingController(); @@ -43,6 +45,8 @@ class _ConnectionPageState extends State var svcStatusCode = 0.obs; var svcIsUsingPublicServer = true.obs; + bool isWindowMinisized = false; + @override void initState() { super.initState(); @@ -63,6 +67,7 @@ class _ConnectionPageState extends State _idInputFocused.value = _idFocusNode.hasFocus; }); Get.put(svcStopped, tag: 'service-stop'); + windowManager.addListener(this); } @override @@ -70,9 +75,24 @@ class _ConnectionPageState extends State _idController.dispose(); _updateTimer?.cancel(); Get.delete(tag: 'service-stop'); + windowManager.removeListener(this); super.dispose(); } + @override + void onWindowEvent(String eventName) { + super.onWindowEvent(eventName); + if (eventName == 'minimize') { + isWindowMinisized = true; + } else if (eventName == 'maximize' || eventName == 'restore') { + if (isWindowMinisized && Platform.isWindows) { + // windows can't update when minisized. + Get.forceAppUpdate(); + } + isWindowMinisized = false; + } + } + @override Widget build(BuildContext context) { return Column( @@ -282,23 +302,34 @@ class _ConnectionPageState extends State .marginOnly(left: em), ), // ready && public - Offstage( - offstage: !(!svcStopped.value && - svcStatusCode.value == 1 && - svcIsUsingPublicServer.value), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text(', ', style: TextStyle(fontSize: em)), - InkWell( - onTap: onUsePublicServerGuide, - child: Text( - translate('setup_server_tip'), - style: TextStyle( - decoration: TextDecoration.underline, fontSize: em), - ), - ) - ], + Flexible( + child: Offstage( + offstage: !(!svcStopped.value && + svcStatusCode.value == 1 && + svcIsUsingPublicServer.value), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text(', ', style: TextStyle(fontSize: em)), + Flexible( + child: InkWell( + onTap: onUsePublicServerGuide, + child: Row( + children: [ + Flexible( + child: Text( + translate('setup_server_tip'), + style: TextStyle( + decoration: TextDecoration.underline, + fontSize: em), + ), + ), + ], + ), + ), + ) + ], + ), ), ) ], diff --git a/flutter/lib/desktop/pages/desktop_setting_page.dart b/flutter/lib/desktop/pages/desktop_setting_page.dart index 23d832580..22247c033 100644 --- a/flutter/lib/desktop/pages/desktop_setting_page.dart +++ b/flutter/lib/desktop/pages/desktop_setting_page.dart @@ -321,6 +321,7 @@ class _GeneralState extends State<_General> { ...devices.map((device) => _Radio(context, value: device, groupValue: currentDevice, + autoNewLine: false, label: device, onChanged: (value) { setDevice(value); setState(() {}); @@ -812,11 +813,7 @@ class _NetworkState extends State<_Network> with AutomaticKeepAliveClientMixin { AbsorbPointer( absorbing: locked, child: Column(children: [ - _CardRow(title: 'Server', children: [ - _Button('ID/Relay Server', changeServer, enabled: enabled), - _Button('Import Server Conf', importServer, - enabled: enabled), - ]), + server(enabled), _Card(title: 'Proxy', children: [ _Button('Socks5 Proxy', changeSocks5Proxy, enabled: enabled), @@ -825,6 +822,156 @@ class _NetworkState extends State<_Network> with AutomaticKeepAliveClientMixin { ), ]).marginOnly(bottom: _kListViewBottomMargin)); } + + server(bool enabled) { + return _futureBuilder(future: () async { + return await bind.mainGetOptions(); + }(), hasData: (data) { + // Setting page is not modal, oldOptions should only be used when getting options, never when setting. + Map oldOptions = jsonDecode(data! as String); + old(String key) { + return (oldOptions[key] ?? "").trim(); + } + + RxString idErrMsg = "".obs; + RxString relayErrMsg = "".obs; + RxString apiErrMsg = "".obs; + var idController = + TextEditingController(text: old('custom-rendezvous-server')); + var relayController = TextEditingController(text: old('relay-server')); + var apiController = TextEditingController(text: old('api-server')); + var keyController = TextEditingController(text: old('key')); + + set(String idServer, String relayServer, String apiServer, + String key) async { + idServer = idServer.trim(); + relayServer = relayServer.trim(); + apiServer = apiServer.trim(); + key = key.trim(); + if (idServer.isNotEmpty) { + idErrMsg.value = + translate(await bind.mainTestIfValidServer(server: idServer)); + if (idErrMsg.isNotEmpty) { + return false; + } + } + if (relayServer.isNotEmpty) { + relayErrMsg.value = + translate(await bind.mainTestIfValidServer(server: relayServer)); + if (relayErrMsg.isNotEmpty) { + return false; + } + } + if (apiServer.isNotEmpty) { + if (!apiServer.startsWith('http://') || + !apiServer.startsWith("https://")) { + apiErrMsg.value = + "${translate("API Server")}: ${translate("invalid_http")}"; + return false; + } + } + // should set one by one + await bind.mainSetOption( + key: 'custom-rendezvous-server', value: idServer); + await bind.mainSetOption(key: 'relay-server', value: relayServer); + await bind.mainSetOption(key: 'api-server', value: apiServer); + await bind.mainSetOption(key: 'key', value: key); + return true; + } + + submit() async { + bool result = await set(idController.text, relayController.text, + apiController.text, keyController.text); + if (result) { + setState(() {}); + showToast(translate('Successful')); + } else { + showToast(translate('Failed')); + } + } + + import() { + Clipboard.getData(Clipboard.kTextPlain).then((value) { + TextEditingController mytext = TextEditingController(); + String? aNullableString = ""; + aNullableString = value?.text; + mytext.text = aNullableString.toString(); + if (mytext.text.isNotEmpty) { + try { + Map config = jsonDecode(mytext.text); + if (config.containsKey('IdServer')) { + String id = config['IdServer'] ?? ''; + String relay = config['RelayServer'] ?? ''; + String api = config['ApiServer'] ?? ''; + String key = config['Key'] ?? ''; + idController.text = id; + relayController.text = relay; + apiController.text = api; + keyController.text = key; + Future success = set(id, relay, api, key); + success.then((value) { + if (value) { + showToast( + translate('Import server configuration successfully')); + } else { + showToast(translate('Invalid server configuration')); + } + }); + } else { + showToast(translate("Invalid server configuration")); + } + } catch (e) { + showToast(translate("Invalid server configuration")); + } + } else { + showToast(translate("Clipboard is empty")); + } + }); + } + + export() { + Map config = {}; + config['IdServer'] = idController.text.trim(); + config['RelayServer'] = relayController.text.trim(); + config['ApiServer'] = apiController.text.trim(); + config['Key'] = keyController.text.trim(); + Clipboard.setData(ClipboardData(text: jsonEncode(config))); + showToast(translate("Export server configuration successfully")); + } + + bool secure = !enabled; + return _Card(title: 'ID/Relay Server', title_suffix: [ + Tooltip( + message: translate('Import Server Config'), + child: IconButton( + icon: Icon(Icons.paste, color: Colors.grey), + onPressed: enabled ? import : null), + ), + Tooltip( + message: translate('Export Server Config'), + child: IconButton( + icon: Icon(Icons.copy, color: Colors.grey), + onPressed: enabled ? export : null)), + ], children: [ + Column( + children: [ + Obx(() => _LabeledTextField(context, 'ID Server', idController, + idErrMsg.value, enabled, secure)), + Obx(() => _LabeledTextField(context, 'Relay Server', + relayController, relayErrMsg.value, enabled, secure)), + Obx(() => _LabeledTextField(context, 'API Server', apiController, + apiErrMsg.value, enabled, secure)), + _LabeledTextField( + context, 'Key', keyController, "", enabled, secure), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [_Button('Apply', submit, enabled: enabled)], + ).marginOnly(top: 15), + ], + ) + ]); + }); + } } class _Account extends StatefulWidget { @@ -955,63 +1102,37 @@ class _AboutState extends State<_About> { //#region components // ignore: non_constant_identifier_names -Widget _Card({required String title, required List children}) { +Widget _Card( + {required String title, + required List children, + List? title_suffix}) { return Row( children: [ - SizedBox( - width: _kCardFixedWidth, - child: Card( - child: Column( - children: [ - Row( - children: [ - Text( - translate(title), - textAlign: TextAlign.start, - style: const TextStyle( - fontSize: _kTitleFontSize, - ), - ), - const Spacer(), - ], - ).marginOnly(left: _kContentHMargin, top: 10, bottom: 10), - ...children - .map((e) => e.marginOnly(top: 4, right: _kContentHMargin)), - ], - ).marginOnly(bottom: 10), - ).marginOnly(left: _kCardLeftMargin, top: 15), - ), - ], - ); -} - -Widget _CardRow({required String title, required List children}) { - return Row( - children: [ - SizedBox( - width: _kCardFixedWidth, - child: Card( - child: Column( - children: [ - Row( - children: [ - Text( - translate(title), - textAlign: TextAlign.start, - style: const TextStyle( - fontSize: _kTitleFontSize, - ), - ), - const Spacer(), - ], - ).marginOnly(left: _kContentHMargin, top: 10, bottom: 10), - Row(children: [ + Flexible( + child: SizedBox( + width: _kCardFixedWidth, + child: Card( + child: Column( + children: [ + Row( + children: [ + Expanded( + child: Text( + translate(title), + textAlign: TextAlign.start, + style: const TextStyle( + fontSize: _kTitleFontSize, + ), + )), + ...?title_suffix + ], + ).marginOnly(left: _kContentHMargin, top: 10, bottom: 10), ...children .map((e) => e.marginOnly(top: 4, right: _kContentHMargin)), - ]), - ], - ).marginOnly(bottom: 10), - ).marginOnly(left: _kCardLeftMargin, top: 15), + ], + ).marginOnly(bottom: 10), + ).marginOnly(left: _kCardLeftMargin, top: 15), + ), ), ], ); @@ -1085,6 +1206,7 @@ Widget _Radio(BuildContext context, required T groupValue, required String label, required Function(T value) onChanged, + bool autoNewLine = true, bool enabled = true}) { var onChange = enabled ? (T? value) { @@ -1099,8 +1221,7 @@ Widget _Radio(BuildContext context, Radio(value: value, groupValue: groupValue, onChanged: onChange), Expanded( child: Text(translate(label), - maxLines: 1, - overflow: TextOverflow.ellipsis, + overflow: autoNewLine ? null : TextOverflow.ellipsis, style: TextStyle( fontSize: _kContentFontSize, color: _disabledTextColor(context, enabled))) @@ -1116,12 +1237,11 @@ Widget _Radio(BuildContext context, Widget _Button(String label, Function() onPressed, {bool enabled = true, String? tip}) { var button = ElevatedButton( - onPressed: enabled ? onPressed : null, - child: Container( - child: Text( - translate(label), - ).marginSymmetric(horizontal: 15), - )); + onPressed: enabled ? onPressed : null, + child: Text( + translate(label), + ).marginSymmetric(horizontal: 15), + ); StatefulWidget child; if (tip == null) { child = button; @@ -1138,12 +1258,11 @@ Widget _SubButton(String label, Function() onPressed, [bool enabled = true]) { return Row( children: [ ElevatedButton( - onPressed: enabled ? onPressed : null, - child: Container( - child: Text( - translate(label), - ).marginSymmetric(horizontal: 15), - )), + onPressed: enabled ? onPressed : null, + child: Text( + translate(label), + ).marginSymmetric(horizontal: 15), + ), ], ).marginOnly(left: _kContentHSubMargin); } @@ -1215,34 +1334,72 @@ Widget _lock( offstage: !locked, child: Row( children: [ - SizedBox( - width: _kCardFixedWidth, - child: Card( - child: ElevatedButton( - child: SizedBox( - height: 25, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon( - Icons.security_sharp, - size: 20, - ), - Text(translate(label)).marginOnly(left: 5), - ]).marginSymmetric(vertical: 2)), - onPressed: () async { - bool checked = await bind.mainCheckSuperUserPermission(); - if (checked) { - onUnlock(); - } - }, - ).marginSymmetric(horizontal: 2, vertical: 4), - ).marginOnly(left: _kCardLeftMargin), - ).marginOnly(top: 10), + Flexible( + child: SizedBox( + width: _kCardFixedWidth, + child: Card( + child: ElevatedButton( + child: SizedBox( + height: 25, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.security_sharp, + size: 20, + ), + Text(translate(label)).marginOnly(left: 5), + ]).marginSymmetric(vertical: 2)), + onPressed: () async { + bool checked = await bind.mainCheckSuperUserPermission(); + if (checked) { + onUnlock(); + } + }, + ).marginSymmetric(horizontal: 2, vertical: 4), + ).marginOnly(left: _kCardLeftMargin), + ).marginOnly(top: 10), + ), ], )); } +_LabeledTextField( + BuildContext context, + String lable, + TextEditingController controller, + String errorText, + bool enabled, + bool secure) { + return Row( + children: [ + Spacer(flex: 1), + Expanded( + flex: 4, + child: Text( + '${translate(lable)}:', + textAlign: TextAlign.right, + style: TextStyle(color: _disabledTextColor(context, enabled)), + ), + ), + Spacer(flex: 1), + Expanded( + flex: 10, + child: TextField( + controller: controller, + enabled: enabled, + obscureText: secure, + decoration: InputDecoration( + errorText: errorText.isNotEmpty ? errorText : null), + style: TextStyle( + color: _disabledTextColor(context, enabled), + )), + ), + Spacer(flex: 1), + ], + ); +} + // ignore: must_be_immutable class _ComboBox extends StatelessWidget { late final List keys; @@ -1312,315 +1469,6 @@ class _ComboBox extends StatelessWidget { //#region dialogs -void changeServer() async { - Map oldOptions = jsonDecode(await bind.mainGetOptions()); - String idServer = oldOptions['custom-rendezvous-server'] ?? ""; - var idServerMsg = ""; - String relayServer = oldOptions['relay-server'] ?? ""; - var relayServerMsg = ""; - String apiServer = oldOptions['api-server'] ?? ""; - var apiServerMsg = ""; - var key = oldOptions['key'] ?? ""; - var idController = TextEditingController(text: idServer); - var relayController = TextEditingController(text: relayServer); - var apiController = TextEditingController(text: apiServer); - var keyController = TextEditingController(text: key); - - var isInProgress = false; - - gFFI.dialogManager.show((setState, close) { - submit() async { - setState(() { - idServerMsg = ""; - relayServerMsg = ""; - apiServerMsg = ""; - isInProgress = true; - }); - cancel() { - setState(() { - isInProgress = false; - }); - } - - idServer = idController.text.trim(); - relayServer = relayController.text.trim(); - apiServer = apiController.text.trim().toLowerCase(); - key = keyController.text.trim(); - - if (idServer.isNotEmpty) { - idServerMsg = - translate(await bind.mainTestIfValidServer(server: idServer)); - if (idServerMsg.isEmpty) { - oldOptions['custom-rendezvous-server'] = idServer; - } else { - cancel(); - return; - } - } else { - oldOptions['custom-rendezvous-server'] = ""; - } - - if (relayServer.isNotEmpty) { - relayServerMsg = - translate(await bind.mainTestIfValidServer(server: relayServer)); - if (relayServerMsg.isEmpty) { - oldOptions['relay-server'] = relayServer; - } else { - cancel(); - return; - } - } else { - oldOptions['relay-server'] = ""; - } - - if (apiServer.isNotEmpty) { - if (apiServer.startsWith('http://') || - apiServer.startsWith("https://")) { - oldOptions['api-server'] = apiServer; - return; - } else { - apiServerMsg = translate("invalid_http"); - cancel(); - return; - } - } else { - oldOptions['api-server'] = ""; - } - // ok - oldOptions['key'] = key; - await bind.mainSetOptions(json: jsonEncode(oldOptions)); - close(); - } - - return CustomAlertDialog( - title: Text(translate("ID/Relay Server")), - content: ConstrainedBox( - constraints: const BoxConstraints(minWidth: 500), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox( - height: 8.0, - ), - Row( - children: [ - ConstrainedBox( - constraints: const BoxConstraints(minWidth: 100), - child: Text("${translate('ID Server')}:") - .marginOnly(bottom: 16.0)), - const SizedBox( - width: 24.0, - ), - Expanded( - child: TextField( - decoration: InputDecoration( - border: const OutlineInputBorder(), - errorText: idServerMsg.isNotEmpty ? idServerMsg : null), - controller: idController, - focusNode: FocusNode()..requestFocus(), - ), - ), - ], - ), - const SizedBox( - height: 8.0, - ), - Row( - children: [ - ConstrainedBox( - constraints: const BoxConstraints(minWidth: 100), - child: Text("${translate('Relay Server')}:") - .marginOnly(bottom: 16.0)), - const SizedBox( - width: 24.0, - ), - Expanded( - child: TextField( - decoration: InputDecoration( - border: const OutlineInputBorder(), - errorText: - relayServerMsg.isNotEmpty ? relayServerMsg : null), - controller: relayController, - ), - ), - ], - ), - const SizedBox( - height: 8.0, - ), - Row( - children: [ - ConstrainedBox( - constraints: const BoxConstraints(minWidth: 100), - child: Text("${translate('API Server')}:") - .marginOnly(bottom: 16.0)), - const SizedBox( - width: 24.0, - ), - Expanded( - child: TextField( - decoration: InputDecoration( - border: const OutlineInputBorder(), - errorText: - apiServerMsg.isNotEmpty ? apiServerMsg : null), - controller: apiController, - ), - ), - ], - ), - const SizedBox( - height: 8.0, - ), - Row( - children: [ - ConstrainedBox( - constraints: const BoxConstraints(minWidth: 100), - child: - Text("${translate('Key')}:").marginOnly(bottom: 16.0)), - const SizedBox( - width: 24.0, - ), - Expanded( - child: TextField( - decoration: const InputDecoration( - border: OutlineInputBorder(), - ), - controller: keyController, - ), - ), - ], - ), - const SizedBox( - height: 4.0, - ), - Offstage( - offstage: !isInProgress, child: const LinearProgressIndicator()) - ], - ), - ), - actions: [ - TextButton(onPressed: close, child: Text(translate("Cancel"))), - TextButton(onPressed: submit, child: Text(translate("OK"))), - ], - onSubmit: submit, - onCancel: close, - ); - }); -} - -void importServer() async { - Future importServerShow(String content) async { - gFFI.dialogManager.show((setState, close) { - return CustomAlertDialog( - title: Text(content), - content: ConstrainedBox( - constraints: const BoxConstraints(minWidth: 500), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox( - height: 4.0, - ), - ], - ), - ), - actions: [ - TextButton(onPressed: close, child: Text(translate("OK"))), - ], - onCancel: close, - ); - }); - } - - Future submit( - String idServer, String relayServer, String apiServer, String key) async { - Map oldOptions = jsonDecode(await bind.mainGetOptions()); - var idServerMsg = ""; - var relayServerMsg = ""; - if (idServer.isNotEmpty) { - idServerMsg = - translate(await bind.mainTestIfValidServer(server: idServer)); - if (idServerMsg.isEmpty) { - oldOptions['custom-rendezvous-server'] = idServer; - } else { - debugPrint('ID Server invalid return'); - return false; - } - } else { - oldOptions['custom-rendezvous-server'] = ""; - } - - if (relayServer.isNotEmpty) { - relayServerMsg = - translate(await bind.mainTestIfValidServer(server: relayServer)); - if (relayServerMsg.isEmpty) { - oldOptions['relay-server'] = relayServer; - } else { - debugPrint('Relay Server invalid return'); - return false; - } - } else { - oldOptions['relay-server'] = ""; - } - - if (apiServer.isNotEmpty) { - if (apiServer.startsWith('http://') || apiServer.startsWith("https://")) { - oldOptions['api-server'] = apiServer; - return false; - } else { - debugPrint('invalid_http'); - return false; - } - } else { - oldOptions['api-server'] = ""; - } - // ok - oldOptions['key'] = key; - await bind.mainSetOptions(json: jsonEncode(oldOptions)); - debugPrint("set ID/Realy Server Ok"); - return true; - } - - Clipboard.getData(Clipboard.kTextPlain).then((value) { - TextEditingController mytext = TextEditingController(); - String? aNullableString = ""; - aNullableString = value?.text; - mytext.text = aNullableString.toString(); - if (mytext.text.isNotEmpty) { - debugPrint('Clipboard is not empty'); - try { - Map config = jsonDecode(mytext.text); - if (config.containsKey('IdServer') && - config.containsKey('RelayServer')) { - debugPrint('IdServer: ${config['IdServer']}'); - debugPrint('RelayServer: ${config['RelayServer']}'); - debugPrint('ApiServer: ${config['ApiServer']}'); - debugPrint('Key: ${config['Key']}'); - Future success = submit(config['IdServer'], - config['RelayServer'], config['ApiServer'], config['Key']); - success.then((value) { - if (value) { - importServerShow( - translate('Import server configuration successfully')); - } else { - importServerShow(translate('Invalid server configuration')); - } - }); - } else { - debugPrint('invalid config info'); - importServerShow(translate("Invalid server configuration")); - } - } catch (e) { - debugPrint('invalid config info'); - importServerShow(translate("Invalid server configuration")); - } - } else { - debugPrint('Clipboard is empty'); - importServerShow(translate("Clipboard is empty")); - } - }); -} - void changeSocks5Proxy() async { var socks = await bind.mainGetSocks(); diff --git a/flutter/lib/desktop/pages/install_page.dart b/flutter/lib/desktop/pages/install_page.dart index 73ad8769d..e7bb28813 100644 --- a/flutter/lib/desktop/pages/install_page.dart +++ b/flutter/lib/desktop/pages/install_page.dart @@ -181,7 +181,7 @@ class _InstallPageState extends State with WindowListener { void install() { btnEnabled.value = false; showProgress.value = true; - String args = '--flutter'; + String args = ''; if (startmenu.value) args += ' startmenu'; if (desktopicon.value) args += ' desktopicon'; bind.installInstallMe(options: args, path: controller.text); diff --git a/flutter/windows/runner/main.cpp b/flutter/windows/runner/main.cpp index 66194ed42..fed399c9a 100644 --- a/flutter/windows/runner/main.cpp +++ b/flutter/windows/runner/main.cpp @@ -16,15 +16,6 @@ typedef void (*FUNC_RUSTDESK_FREE_ARGS)( char**, int); int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, _In_ wchar_t *command_line, _In_ int show_command) { - // uni links dispatch - HWND hwnd = ::FindWindow(L"FLUTTER_RUNNER_WIN32_WINDOW", L"rustdesk"); - if (hwnd != NULL) { - DispatchToUniLinksDesktop(hwnd); - - ::ShowWindow(hwnd, SW_NORMAL); - ::SetForegroundWindow(hwnd); - return EXIT_FAILURE; - } HINSTANCE hInstance = LoadLibraryA("librustdesk.dll"); if (!hInstance) { @@ -56,6 +47,16 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, std::vector rust_args(c_args, c_args + args_len); free_c_args(c_args, args_len); + // uni links dispatch + HWND hwnd = ::FindWindow(L"FLUTTER_RUNNER_WIN32_WINDOW", L"rustdesk"); + if (hwnd != NULL) { + DispatchToUniLinksDesktop(hwnd); + + ::ShowWindow(hwnd, SW_NORMAL); + ::SetForegroundWindow(hwnd); + return EXIT_FAILURE; + } + // Attach to console when present (e.g., 'flutter run') or create a // new console when running with a debugger. if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) @@ -78,7 +79,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, FlutterWindow window(project); Win32Window::Point origin(10, 10); Win32Window::Size size(800, 600); - if (!window.CreateAndShow(L"rustdesk", origin, size)) + if (!window.CreateAndShow(L"RustDesk", origin, size)) { return EXIT_FAILURE; } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 32e30f81c..ca69ef4e4 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -29,8 +29,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable TCP Tunneling", "允许建立TCP隧道"), ("IP Whitelisting", "IP白名单"), ("ID/Relay Server", "ID/中继服务器"), - ("Import Server Conf", "导入服务器配置"), + ("Import Server Config", "导入服务器配置"), + ("Export Server Config", "导出服务器配置"), ("Import server configuration successfully", "导入服务器配置信息成功"), + ("Export server configuration successfully", "导出服务器配置信息成功"), ("Invalid server configuration", "无效服务器配置,请修改后重新拷贝配置信息到剪贴板后点击此按钮"), ("Clipboard is empty", "拷贝配置信息到剪贴板后点击此按钮,可以自动导入配置"), ("Stop service", "停止服务"), diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 6610c312b..84a5c590e 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -29,8 +29,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable TCP Tunneling", "Povolit TCP tunelování"), ("IP Whitelisting", "Povolování pouze z daných IP adres)"), ("ID/Relay Server", "Identifikátor / předávací (relay) server"), - ("Import Server Conf", "Importovat konfiguraci serveru"), + ("Import Server Config", "Importovat konfiguraci serveru"), + ("Export Server Config", ""), ("Import server configuration successfully", "Konfigurace serveru úspěšně importována"), + ("Export server configuration successfully", ""), ("Invalid server configuration", "Neplatná konfigurace serveru"), ("Clipboard is empty", "Schránka je prázdná"), ("Stop service", "Zastavit službu"), diff --git a/src/lang/da.rs b/src/lang/da.rs index 3bf05a3d6..1210c2dba 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -29,8 +29,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable TCP Tunneling", "Slå TCP-tunneling til"), ("IP Whitelisting", "IP-udgivelsesliste"), ("ID/Relay Server", "ID/forbindelsesserver"), - ("Import Server Conf", "Importér serverkonfiguration"), + ("Import Server Config", "Importér serverkonfiguration"), + ("Export Server Config", ""), ("Import server configuration successfully", "Importér serverkonfigurationen"), + ("Export server configuration successfully", ""), ("Invalid server configuration", "Ugyldig serverkonfiguration"), ("Clipboard is empty", "Udklipsholderen er tom"), ("Stop service", "Sluk for forbindelsesserveren"), diff --git a/src/lang/de.rs b/src/lang/de.rs index 095206f8e..95d0c3e5b 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -29,8 +29,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable TCP Tunneling", "TCP-Tunnel aktivieren"), ("IP Whitelisting", "IP-Whitelist"), ("ID/Relay Server", "ID/Vermittlungsserver"), - ("Import Server Conf", "Serverkonfiguration importieren"), + ("Import Server Config", "Serverkonfiguration importieren"), + ("Export Server Config", ""), ("Import server configuration successfully", "Serverkonfiguration erfolgreich importiert"), + ("Export server configuration successfully", ""), ("Invalid server configuration", "Ungültige Serverkonfiguration"), ("Clipboard is empty", "Zwischenablage ist leer"), ("Stop service", "Vermittlungsdienst deaktivieren"), diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 1b2a391d9..57955b9b8 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -29,8 +29,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable TCP Tunneling", "Ebligi tunelado TCP"), ("IP Whitelisting", "Listo de IP akceptataj"), ("ID/Relay Server", "Identigila/Relajsa servilo"), - ("Import Server Conf", "Enporti servilan agordon"), + ("Import Server Config", "Enporti servilan agordon"), + ("Export Server Config", ""), ("Import server configuration successfully", "Importi servilan agordon sukcese"), + ("Export server configuration successfully", ""), ("Invalid server configuration", "Nevalida servila agordo"), ("Clipboard is empty", "La poŝo estas malplena"), ("Stop service", "Haltu servon"), diff --git a/src/lang/es.rs b/src/lang/es.rs index ef90bb711..39e904eda 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -29,8 +29,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable TCP Tunneling", "Habilitar tunel TCP"), ("IP Whitelisting", "Lista blanca de IP"), ("ID/Relay Server", "Servidor ID/Relay"), - ("Import Server Conf", "Importar configuración de servidor"), + ("Import Server Config", "Importar configuración de servidor"), + ("Export Server Config", ""), ("Import server configuration successfully", "Configuración de servidor importada con éxito"), + ("Export server configuration successfully", ""), ("Invalid server configuration", "Configuración de servidor inválida"), ("Clipboard is empty", "El portapapeles está vacío"), ("Stop service", "Parar servicio"), diff --git a/src/lang/fr.rs b/src/lang/fr.rs index 8b6420823..8e75eec3a 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -29,8 +29,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable TCP Tunneling", "Activer le tunneling TCP"), ("IP Whitelisting", "Liste blanche IP"), ("ID/Relay Server", "ID/Serveur Relais"), - ("Import Server Conf", "Importer la configuration du serveur"), + ("Import Server Config", "Importer la configuration du serveur"), + ("Export Server Config", ""), ("Import server configuration successfully", "Configuration du serveur importée avec succès"), + ("Export server configuration successfully", ""), ("Invalid server configuration", "Configuration du serveur non valide"), ("Clipboard is empty", "Presse-papier vide"), ("Stop service", "Arrêter le service"), diff --git a/src/lang/hu.rs b/src/lang/hu.rs index bbc0594a5..e26cdeff7 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -29,8 +29,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable TCP Tunneling", "TCP Tunneling bekapcsolása"), ("IP Whitelisting", "IP Fehérlista"), ("ID/Relay Server", "ID/Relay Szerver"), - ("Import Server Conf", "Szerver Konfiguráció Importálása"), + ("Import Server Config", "Szerver Konfiguráció Importálása"), + ("Export Server Config", ""), ("Import server configuration successfully", "Szerver konfiguráció sikeresen importálva"), + ("Export server configuration successfully", ""), ("Invalid server configuration", "Érvénytelen szerver konfiguráció"), ("Clipboard is empty", "A vágólap üres"), ("Stop service", "Szolgáltatás Kikapcsolása"), diff --git a/src/lang/id.rs b/src/lang/id.rs index fc1ab88c2..8486e9e64 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -29,8 +29,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable TCP Tunneling", "Aktifkan TCP Tunneling"), ("IP Whitelisting", "Daftar Putih IP"), ("ID/Relay Server", "ID/Relay Server"), - ("Import Server Conf", "Impor Konfigurasi Server"), + ("Import Server Config", "Impor Konfigurasi Server"), + ("Export Server Config", ""), ("Import server configuration successfully", "Impor konfigurasi server berhasil"), + ("Export server configuration successfully", ""), ("Invalid server configuration", "Konfigurasi server tidak valid"), ("Clipboard is empty", "Papan klip kosong"), ("Stop service", "Hentikan Layanan"), diff --git a/src/lang/it.rs b/src/lang/it.rs index bf2c76fe8..57ba210c3 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -29,8 +29,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable TCP Tunneling", "Abilita tunnel TCP"), ("IP Whitelisting", "IP autorizzati"), ("ID/Relay Server", "Server ID/Relay"), - ("Import Server Conf", "Importa configurazione Server"), + ("Import Server Config", "Importa configurazione Server"), + ("Export Server Config", ""), ("Import server configuration successfully", "Configurazione Server importata con successo"), + ("Export server configuration successfully", ""), ("Invalid server configuration", "Configurazione Server non valida"), ("Clipboard is empty", "Gli appunti sono vuoti"), ("Stop service", "Arresta servizio"), diff --git a/src/lang/ja.rs b/src/lang/ja.rs index 38e4c0c7d..207a874ec 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -29,8 +29,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable TCP Tunneling", "TCPトンネリングを有効化"), ("IP Whitelisting", "IPホワイトリスト"), ("ID/Relay Server", "認証・中継サーバー"), - ("Import Server Conf", "サーバー設定をインポート"), + ("Import Server Config", "サーバー設定をインポート"), + ("Export Server Config", ""), ("Import server configuration successfully", "サーバー設定をインポートしました"), + ("Export server configuration successfully", ""), ("Invalid server configuration", "無効なサーバー設定です"), ("Clipboard is empty", "クリップボードは空です"), ("Stop service", "サービスを停止"), diff --git a/src/lang/ko.rs b/src/lang/ko.rs index 740465323..5ed580ff3 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -29,8 +29,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable TCP Tunneling", "TCP 터널링 활성화"), ("IP Whitelisting", "IP 화이트리스트"), ("ID/Relay Server", "ID/Relay 서버"), - ("Import Server Conf", "서버 설정 가져오기"), + ("Import Server Config", "서버 설정 가져오기"), + ("Export Server Config", ""), ("Import server configuration successfully", "서버 설정 가져오기 성공"), + ("Export server configuration successfully", ""), ("Invalid server configuration", "잘못된 서버 설정"), ("Clipboard is empty", "클립보드가 비어있습니다"), ("Stop service", "서비스 중단"), diff --git a/src/lang/kz.rs b/src/lang/kz.rs index a4f25dbf8..ad7bdb476 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -29,8 +29,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable TCP Tunneling", "TCP тунелдеуді қосу"), ("IP Whitelisting", "IP Ақ-тізімі"), ("ID/Relay Server", "ID/Relay сербері"), - ("Import Server Conf", "Серверді импорттау"), + ("Import Server Config", "Серверді импорттау"), + ("Export Server Config", ""), ("Import server configuration successfully", "Сервердің конфигурациясы сәтті импортталды"), + ("Export server configuration successfully", ""), ("Invalid server configuration", "Жарамсыз сервердің конфигурациясы"), ("Clipboard is empty", "Көшіру-тақта бос"), ("Stop service", "Сербесті тоқтату"), diff --git a/src/lang/pl.rs b/src/lang/pl.rs index e46796148..2a08479aa 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -29,8 +29,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable TCP Tunneling", "Włącz tunelowanie TCP"), ("IP Whitelisting", "Biała lista IP"), ("ID/Relay Server", "Serwer ID/Pośredniczący"), - ("Import Server Conf", "Importuj konfigurację serwera"), + ("Import Server Config", "Importuj konfigurację serwera"), + ("Export Server Config", ""), ("Import server configuration successfully", "Importowanie konfiguracji serwera powiodło się"), + ("Export server configuration successfully", ""), ("Invalid server configuration", "Nieprawidłowa konfiguracja serwera"), ("Clipboard is empty", "Schowek jest pusty"), ("Stop service", "Zatrzymaj usługę"), diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index 69b61d622..fc40cbfb8 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -29,8 +29,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable TCP Tunneling", "Activar Túnel TCP"), ("IP Whitelisting", "Whitelist de IP"), ("ID/Relay Server", "Servidor ID/Relay"), - ("Import Server Conf", "Importar Configuração do Servidor"), + ("Import Server Config", "Importar Configuração do Servidor"), + ("Export Server Config", ""), ("Import server configuration successfully", "Configuração do servidor importada com sucesso"), + ("Export server configuration successfully", ""), ("Invalid server configuration", "Configuração do servidor inválida"), ("Clipboard is empty", "A área de transferência está vazia"), ("Stop service", "Parar serviço"), diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index e93cbef33..adeee81a4 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -29,8 +29,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable TCP Tunneling", "Habilitar Tunelamento TCP"), ("IP Whitelisting", "Whitelist de IP"), ("ID/Relay Server", "Servidor ID/Relay"), - ("Import Server Conf", "Importar Configuração do Servidor"), + ("Import Server Config", "Importar Configuração do Servidor"), + ("Export Server Config", ""), ("Import server configuration successfully", "Configuração do servidor importada com sucesso"), + ("Export server configuration successfully", ""), ("Invalid server configuration", "Configuração do servidor inválida"), ("Clipboard is empty", "A área de transferência está vazia"), ("Stop service", "Parar serviço"), diff --git a/src/lang/ru.rs b/src/lang/ru.rs index eccc28602..3ddc40d53 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -29,8 +29,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable TCP Tunneling", "Включить туннелирование TCP"), ("IP Whitelisting", "Список разрешенных IP-адресов"), ("ID/Relay Server", "ID/Сервер ретрансляции"), - ("Import Server Conf", "Импортировать конфигурацию сервера"), + ("Import Server Config", "Импортировать конфигурацию сервера"), + ("Export Server Config", ""), ("Import server configuration successfully", "Конфигурация сервера успешно импортирована"), + ("Export server configuration successfully", ""), ("Invalid server configuration", "Недопустимая конфигурация сервера"), ("Clipboard is empty", "Буфер обмена пуст"), ("Stop service", "Остановить службу"), diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 20e096f0e..107f38bf8 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -29,8 +29,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable TCP Tunneling", "Povoliť TCP tunelovanie"), ("IP Whitelisting", "Zoznam povolených IP adries"), ("ID/Relay Server", "ID/Prepojovací server"), - ("Import Server Conf", "Importovať konfiguráciu servera"), + ("Import Server Config", "Importovať konfiguráciu servera"), + ("Export Server Config", ""), ("Import server configuration successfully", "Konfigurácia servera bola úspešne importovaná"), + ("Export server configuration successfully", ""), ("Invalid server configuration", "Neplatná konfigurácia servera"), ("Clipboard is empty", "Schránka je prázdna"), ("Stop service", "Zastaviť službu"), diff --git a/src/lang/template.rs b/src/lang/template.rs index 87dcc3a48..a08eec33d 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -29,8 +29,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable TCP Tunneling", ""), ("IP Whitelisting", ""), ("ID/Relay Server", ""), - ("Import Server Conf", ""), + ("Import Server Config", ""), + ("Export Server Config", ""), ("Import server configuration successfully", ""), + ("Export server configuration successfully", ""), ("Invalid server configuration", ""), ("Clipboard is empty", ""), ("Stop service", ""), diff --git a/src/lang/tr.rs b/src/lang/tr.rs index f8d8b5fff..99fad87bc 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -29,8 +29,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable TCP Tunneling", "TCP Tüneline izin ver"), ("IP Whitelisting", "İzinli IP listesi"), ("ID/Relay Server", "ID/Relay Sunucusu"), - ("Import Server Conf", "Sunucu ayarlarını içe aktar"), + ("Import Server Config", "Sunucu ayarlarını içe aktar"), + ("Export Server Config", ""), ("Import server configuration successfully", "Sunucu ayarları başarıyla içe aktarıldı"), + ("Export server configuration successfully", ""), ("Invalid server configuration", "Geçersiz sunucu ayarı"), ("Clipboard is empty", "Kopyalanan geçici veri boş"), ("Stop service", "Servisi Durdur"), diff --git a/src/lang/tw.rs b/src/lang/tw.rs index 0c085775e..d20888aeb 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -29,8 +29,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable TCP Tunneling", "啟用 TCP 通道"), ("IP Whitelisting", "IP 白名單"), ("ID/Relay Server", "ID/轉送伺服器"), - ("Import Server Conf", "匯入伺服器設定"), + ("Import Server Config", "匯入伺服器設定"), + ("Export Server Config", "導出服務器配置"), ("Import server configuration successfully", "匯入伺服器設定成功"), + ("Export server configuration successfully", ""), + ("Export server configuration successfully", "導出服務器配置信息成功"), ("Invalid server configuration", "無效的伺服器設定"), ("Clipboard is empty", "剪貼簿是空的"), ("Stop service", "停止服務"), diff --git a/src/lang/ua.rs b/src/lang/ua.rs index 8d3451db0..f6c389533 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -29,8 +29,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable TCP Tunneling", "Увімкнути тунелювання TCP"), ("IP Whitelisting", "Список дозволених IP-адрес"), ("ID/Relay Server", "ID/Сервер ретрансляції"), - ("Import Server Conf", "Імпортувати конфігурацію сервера"), + ("Import Server Config", "Імпортувати конфігурацію сервера"), + ("Export Server Config", ""), ("Import server configuration successfully", "Конфігурацію сервера успішно імпортовано"), + ("Export server configuration successfully", ""), ("Invalid server configuration", "Недійсна конфігурація сервера"), ("Clipboard is empty", "Буфер обміну порожній"), ("Stop service", "Зупинити службу"), diff --git a/src/lang/vn.rs b/src/lang/vn.rs index 81428a8ec..f4823dbfd 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -29,8 +29,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("Enable TCP Tunneling", "Cho phép TCP Tunneling"), ("IP Whitelisting", "Cho phép IP"), ("ID/Relay Server", "Máy chủ ID/Relay"), - ("Import Server Conf", "Nhập cấu hình máy chủ"), + ("Import Server Config", "Nhập cấu hình máy chủ"), + ("Export Server Config", ""), ("Import server configuration successfully", "Nhập cấu hình máy chủ thành công"), + ("Export server configuration successfully", ""), ("Invalid server configuration", "Cấu hình máy chủ không hợp lệ"), ("Clipboard is empty", "Khay nhớ tạm trống"), ("Stop service", "Dừng dịch vụ"), diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 190a49a16..53fb60bd8 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -878,6 +878,25 @@ fn get_install_info_with_subkey(subkey: String) -> (String, String, String, Stri (subkey, path, start_menu, exe) } +pub fn copy_exe_cmd(src_exe: &str, _exe: &str, _path: &str) -> String { + #[cfg(feature = "flutter")] + return format!( + "XCOPY \"{}\" \"{}\" /Y /E /H /C /I /K /R /Z", + PathBuf::from(src_exe) + .parent() + .unwrap() + .to_string_lossy() + .to_string(), + _path + ); + #[cfg(not(feature = "flutter"))] + return format!( + "copy /Y \"{src_exe}\" \"{exe}\"", + src_exe = src_exe, + exe = _exe + ); +} + pub fn update_me() -> ResultType<()> { let (_, path, _, exe) = get_install_info(); let src_exe = std::env::current_exe()?.to_str().unwrap_or("").to_owned(); @@ -887,13 +906,13 @@ pub fn update_me() -> ResultType<()> { sc stop {app_name} taskkill /F /IM {broker_exe} taskkill /F /IM {app_name}.exe - copy /Y \"{src_exe}\" \"{exe}\" + {copy_exe} \"{src_exe}\" --extract \"{path}\" sc start {app_name} {lic} ", src_exe = src_exe, - exe = exe, + copy_exe = copy_exe_cmd(&src_exe, &exe, &path), broker_exe = crate::ui::win_privacy::INJECTED_PROCESS_EXE, path = path, app_name = crate::get_app_name(), @@ -1038,18 +1057,6 @@ copy /Y \"{tmp_path}\\Uninstall {app_name}.lnk\" \"{start_menu}\\\" app_name = crate::get_app_name(), ); } - let mut flutter_copy = Default::default(); - if options.contains("--flutter") { - flutter_copy = format!( - "XCOPY \"{}\" \"{}\" /Y /E /H /C /I /K /R /Z", - std::env::current_exe()? - .parent() - .unwrap() - .to_string_lossy() - .to_string(), - path - ); - } let meta = std::fs::symlink_metadata(std::env::current_exe()?)?; let size = meta.len() / 1024; @@ -1072,13 +1079,14 @@ if exist \"{tmp_path}\\{app_name} Tray.lnk\" del /f /q \"{tmp_path}\\{app_name} tmp_path = tmp_path, app_name = crate::get_app_name(), ); + let src_exe = std::env::current_exe()?.to_str().unwrap_or("").to_string(); + let cmds = format!( " {uninstall_str} chcp 65001 md \"{path}\" -{flutter_copy} -copy /Y \"{src_exe}\" \"{exe}\" +{copy_exe} copy /Y \"{ORIGIN_PROCESS_EXE}\" \"{path}\\{broker_exe}\" \"{src_exe}\" --extract \"{path}\" reg add {subkey} /f @@ -1111,7 +1119,7 @@ sc delete {app_name} ", uninstall_str=uninstall_str, path=path, - src_exe=std::env::current_exe()?.to_str().unwrap_or(""), + src_exe=src_exe, exe=exe, ORIGIN_PROCESS_EXE = crate::ui::win_privacy::ORIGIN_PROCESS_EXE, broker_exe=crate::ui::win_privacy::INJECTED_PROCESS_EXE, @@ -1140,7 +1148,7 @@ sc delete {app_name} } else { &dels }, - flutter_copy = flutter_copy, + copy_exe = copy_exe_cmd(&src_exe, &exe, &path), ); run_cmds(cmds, debug, "install")?; std::thread::sleep(std::time::Duration::from_millis(2000)); @@ -1478,7 +1486,13 @@ pub fn run_uac(exe: &str, arg: &str) -> ResultType { } pub fn check_super_user_permission() -> ResultType { - run_uac("cmd", "/c /q") + run_uac( + std::env::current_exe()? + .to_string_lossy() + .to_string() + .as_str(), + "--version", + ) } pub fn elevate(arg: &str) -> ResultType {