diff --git a/lib/common/helper/system_helper.dart b/lib/common/helper/system_helper.dart index 9506b6b..71aefcd 100644 --- a/lib/common/helper/system_helper.dart +++ b/lib/common/helper/system_helper.dart @@ -98,15 +98,17 @@ class SystemHelper { "$programDataPath\\Microsoft\\Windows\\Start Menu\\Programs\\Roberts Space Industries\\RSI Launcher.lnk"; final rsiLinkFile = File(rsiFilePath); if (await rsiLinkFile.exists()) { - final r = await Process.run(SystemHelper.powershellPath, [ - "(New-Object -ComObject WScript.Shell).CreateShortcut(\"$rsiFilePath\").targetpath", - ]); - if (r.stdout.toString().contains("RSI Launcher.exe")) { - final start = r.stdout.toString().split("RSI Launcher.exe"); - if (skipEXE) { - return start[0]; + try { + final targetPath = await win32.resolveShortcut(lnkPath: rsiFilePath); + if (targetPath.contains("RSI Launcher.exe")) { + final start = targetPath.split("RSI Launcher.exe"); + if (skipEXE) { + return start[0]; + } + return "${start[0]}RSI Launcher.exe"; } - return "${start[0]}RSI Launcher.exe"; + } catch (e) { + dPrint("resolveShortcut error: $e"); } } return ""; @@ -147,45 +149,78 @@ class SystemHelper { } static Future getSystemMemorySizeGB() async { - final r = await Process.run(powershellPath, [ - "(Get-CimInstance Win32_PhysicalMemory | Measure-Object -Property capacity -Sum).sum /1gb", - ]); - return int.tryParse(r.stdout.toString().trim()) ?? 0; + try { + final memoryGb = await win32.getSystemMemorySizeGb(); + return memoryGb.toInt(); + } catch (e) { + dPrint("getSystemMemorySizeGB error: $e"); + return 0; + } } static Future getSystemCimInstance(String win32InstanceName, {pathName = "Name"}) async { - final r = await Process.run(powershellPath, ["(Get-CimInstance $win32InstanceName).$pathName"]); - return r.stdout.toString().trim(); + // This method is deprecated, use getSystemInfo() instead + try { + final sysInfo = await win32.getSystemInfo(); + if (win32InstanceName.contains("OperatingSystem")) { + return sysInfo.osName; + } else if (win32InstanceName.contains("Processor")) { + return sysInfo.cpuName; + } else if (win32InstanceName.contains("VideoController")) { + return sysInfo.gpuInfo; + } else if (win32InstanceName.contains("DiskDrive")) { + return sysInfo.diskInfo; + } + } catch (e) { + dPrint("getSystemCimInstance error: $e"); + } + return ""; } static Future getSystemName() async { - final r = await Process.run(powershellPath, ["(Get-ComputerInfo | Select-Object -expand OsName)"]); - return r.stdout.toString().trim(); + try { + final sysInfo = await win32.getSystemInfo(); + return sysInfo.osName; + } catch (e) { + dPrint("getSystemName error: $e"); + return ""; + } } static Future getCpuName() async { - final r = await Process.run(powershellPath, ["(Get-WmiObject -Class Win32_Processor).Name"]); - return r.stdout.toString().trim(); + try { + final sysInfo = await win32.getSystemInfo(); + return sysInfo.cpuName; + } catch (e) { + dPrint("getCpuName error: $e"); + return ""; + } } static Future getGpuInfo() async { - const cmd = r""" - $adapterMemory = (Get-ItemProperty -Path "HKLM:\SYSTEM\ControlSet001\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\0*" -Name "HardwareInformation.AdapterString", "HardwareInformation.qwMemorySize" -Exclude PSPath -ErrorAction SilentlyContinue) -foreach ($adapter in $adapterMemory) { - [PSCustomObject] @{ - Model=$adapter."HardwareInformation.AdapterString" - "VRAM (GB)"=[math]::round($adapter."HardwareInformation.qwMemorySize"/1GB) - } -} - """; - final r = await Process.run(powershellPath, [cmd]); - return r.stdout.toString().trim(); + try { + // Try registry first for more accurate VRAM info + final regInfo = await win32.getGpuInfoFromRegistry(); + if (regInfo.isNotEmpty) { + return regInfo; + } + // Fallback to WMI + final sysInfo = await win32.getSystemInfo(); + return sysInfo.gpuInfo; + } catch (e) { + dPrint("getGpuInfo error: $e"); + return ""; + } } static Future getDiskInfo() async { - return (await Process.run(powershellPath, [ - "Get-PhysicalDisk | format-table BusType,FriendlyName,Size", - ])).stdout.toString().trim(); + try { + final sysInfo = await win32.getSystemInfo(); + return sysInfo.diskInfo; + } catch (e) { + dPrint("getDiskInfo error: $e"); + return ""; + } } static Future getDirLen(String path, {List? skipPath}) async { @@ -212,11 +247,12 @@ foreach ($adapter in $adapterMemory) { } static Future getNumberOfLogicalProcessors() async { - final cpuNumberResult = await Process.run(powershellPath, [ - "(Get-WmiObject -Class Win32_Processor).NumberOfLogicalProcessors", - ]); - if (cpuNumberResult.exitCode != 0) return 0; - return int.tryParse(cpuNumberResult.stdout.toString().trim()) ?? 0; + try { + return await win32.getNumberOfLogicalProcessors(); + } catch (e) { + dPrint("getNumberOfLogicalProcessors error: $e"); + return 0; + } } static Future getCpuAffinity() async { @@ -244,10 +280,11 @@ foreach ($adapter in $adapterMemory) { static Future openDir(dynamic path, {bool isFile = false}) async { dPrint("SystemHelper.openDir path === $path"); if (Platform.isWindows) { - await Process.run(SystemHelper.powershellPath, [ - "explorer.exe", - isFile ? "/select,$path" : "\"/select,\"$path\"\"", - ]); + try { + await win32.openDirWithExplorer(path: path.toString(), isFile: isFile); + } catch (e) { + dPrint("openDir error: $e"); + } } } diff --git a/lib/common/rust/api/webview_api.dart b/lib/common/rust/api/webview_api.dart index ca03cf4..d889e82 100644 --- a/lib/common/rust/api/webview_api.dart +++ b/lib/common/rust/api/webview_api.dart @@ -8,9 +8,8 @@ import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; import 'package:freezed_annotation/freezed_annotation.dart' hide protected; part 'webview_api.freezed.dart'; -// These functions are ignored because they are not marked as `pub`: `handle_command`, `load_app_icon`, `run_webview_loop`, `send_command` -// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `UserEvent`, `WebViewCommand`, `WebViewInstance` -// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`, `clone`, `clone`, `clone`, `clone`, `fmt`, `fmt`, `fmt`, `fmt`, `fmt` +// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `WebViewCommand` +// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`, `clone`, `clone`, `clone`, `fmt`, `fmt`, `fmt`, `fmt` /// Create a new WebView window and return its ID String webviewCreate({required WebViewConfiguration config}) => diff --git a/lib/common/rust/api/win32_api.dart b/lib/common/rust/api/win32_api.dart index 78d9de7..88a0284 100644 --- a/lib/common/rust/api/win32_api.dart +++ b/lib/common/rust/api/win32_api.dart @@ -7,7 +7,7 @@ import '../frb_generated.dart'; import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; // These functions are ignored because they are not marked as `pub`: `get_process_path` -// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`, `fmt` +// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`, `clone`, `fmt`, `fmt` Future sendNotify({ String? summary, @@ -21,6 +21,35 @@ Future sendNotify({ appId: appId, ); +/// Get system memory size in GB +Future getSystemMemorySizeGb() => + RustLib.instance.api.crateApiWin32ApiGetSystemMemorySizeGb(); + +/// Get number of logical processors +Future getNumberOfLogicalProcessors() => + RustLib.instance.api.crateApiWin32ApiGetNumberOfLogicalProcessors(); + +/// Get all system information at once +Future getSystemInfo() => + RustLib.instance.api.crateApiWin32ApiGetSystemInfo(); + +/// Get GPU info from registry (more accurate VRAM) +Future getGpuInfoFromRegistry() => + RustLib.instance.api.crateApiWin32ApiGetGpuInfoFromRegistry(); + +/// Resolve shortcut (.lnk) file to get target path +Future resolveShortcut({required String lnkPath}) => + RustLib.instance.api.crateApiWin32ApiResolveShortcut(lnkPath: lnkPath); + +/// Open file explorer and select file/folder +Future openDirWithExplorer({ + required String path, + required bool isFile, +}) => RustLib.instance.api.crateApiWin32ApiOpenDirWithExplorer( + path: path, + isFile: isFile, +); + Future setForegroundWindow({required String windowName}) => RustLib .instance .api @@ -59,3 +88,32 @@ class ProcessInfo { name == other.name && path == other.path; } + +/// System information struct +class SystemInfo { + final String osName; + final String cpuName; + final String gpuInfo; + final String diskInfo; + + const SystemInfo({ + required this.osName, + required this.cpuName, + required this.gpuInfo, + required this.diskInfo, + }); + + @override + int get hashCode => + osName.hashCode ^ cpuName.hashCode ^ gpuInfo.hashCode ^ diskInfo.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is SystemInfo && + runtimeType == other.runtimeType && + osName == other.osName && + cpuName == other.cpuName && + gpuInfo == other.gpuInfo && + diskInfo == other.diskInfo; +} diff --git a/lib/common/rust/frb_generated.dart b/lib/common/rust/frb_generated.dart index ba7174b..0bea161 100644 --- a/lib/common/rust/frb_generated.dart +++ b/lib/common/rust/frb_generated.dart @@ -71,7 +71,7 @@ class RustLib extends BaseEntrypoint { String get codegenVersion => '2.11.1'; @override - int get rustContentHash => -1082688871; + int get rustContentHash => 1317751362; static const kDefaultExternalLibraryLoaderConfig = ExternalLibraryLoaderConfig( @@ -102,6 +102,10 @@ abstract class RustLibApi extends BaseApi { String? pathSuffix, }); + Future crateApiWin32ApiGetGpuInfoFromRegistry(); + + Future crateApiWin32ApiGetNumberOfLogicalProcessors(); + Future> crateApiWin32ApiGetProcessListByName({ required String processName, }); @@ -114,6 +118,10 @@ abstract class RustLibApi extends BaseApi { required String asarPath, }); + Future crateApiWin32ApiGetSystemInfo(); + + Future crateApiWin32ApiGetSystemMemorySizeGb(); + Future crateApiOrtApiLoadTranslationModel({ required String modelPath, required String modelKey, @@ -121,6 +129,11 @@ abstract class RustLibApi extends BaseApi { required bool useXnnpack, }); + Future crateApiWin32ApiOpenDirWithExplorer({ + required String path, + required bool isFile, + }); + Future crateApiUnp4KApiP4KClose(); Future crateApiUnp4KApiP4KExtractToDisk({ @@ -138,6 +151,8 @@ abstract class RustLibApi extends BaseApi { Future crateApiUnp4KApiP4KOpen({required String p4KPath}); + Future crateApiWin32ApiResolveShortcut({required String lnkPath}); + Future crateApiAsarApiRsiLauncherAsarDataWriteMainJs({ required RsiLauncherAsarData that, required List content, @@ -402,6 +417,59 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { argNames: ["urls", "pathSuffix"], ); + @override + Future crateApiWin32ApiGetGpuInfoFromRegistry() { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + return wire.wire__crate__api__win32_api__get_gpu_info_from_registry( + port_, + ); + }, + codec: DcoCodec( + decodeSuccessData: dco_decode_String, + decodeErrorData: dco_decode_AnyhowException, + ), + constMeta: kCrateApiWin32ApiGetGpuInfoFromRegistryConstMeta, + argValues: [], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateApiWin32ApiGetGpuInfoFromRegistryConstMeta => + const TaskConstMeta( + debugName: "get_gpu_info_from_registry", + argNames: [], + ); + + @override + Future crateApiWin32ApiGetNumberOfLogicalProcessors() { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + return wire + .wire__crate__api__win32_api__get_number_of_logical_processors( + port_, + ); + }, + codec: DcoCodec( + decodeSuccessData: dco_decode_u_32, + decodeErrorData: dco_decode_AnyhowException, + ), + constMeta: kCrateApiWin32ApiGetNumberOfLogicalProcessorsConstMeta, + argValues: [], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateApiWin32ApiGetNumberOfLogicalProcessorsConstMeta => + const TaskConstMeta( + debugName: "get_number_of_logical_processors", + argNames: [], + ); + @override Future> crateApiWin32ApiGetProcessListByName({ required String processName, @@ -492,6 +560,50 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { argNames: ["asarPath"], ); + @override + Future crateApiWin32ApiGetSystemInfo() { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + return wire.wire__crate__api__win32_api__get_system_info(port_); + }, + codec: DcoCodec( + decodeSuccessData: dco_decode_system_info, + decodeErrorData: dco_decode_AnyhowException, + ), + constMeta: kCrateApiWin32ApiGetSystemInfoConstMeta, + argValues: [], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateApiWin32ApiGetSystemInfoConstMeta => + const TaskConstMeta(debugName: "get_system_info", argNames: []); + + @override + Future crateApiWin32ApiGetSystemMemorySizeGb() { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + return wire.wire__crate__api__win32_api__get_system_memory_size_gb( + port_, + ); + }, + codec: DcoCodec( + decodeSuccessData: dco_decode_u_64, + decodeErrorData: dco_decode_AnyhowException, + ), + constMeta: kCrateApiWin32ApiGetSystemMemorySizeGbConstMeta, + argValues: [], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateApiWin32ApiGetSystemMemorySizeGbConstMeta => + const TaskConstMeta(debugName: "get_system_memory_size_gb", argNames: []); + @override Future crateApiOrtApiLoadTranslationModel({ required String modelPath, @@ -531,6 +643,39 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { argNames: ["modelPath", "modelKey", "quantizationSuffix", "useXnnpack"], ); + @override + Future crateApiWin32ApiOpenDirWithExplorer({ + required String path, + required bool isFile, + }) { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + var arg0 = cst_encode_String(path); + var arg1 = cst_encode_bool(isFile); + return wire.wire__crate__api__win32_api__open_dir_with_explorer( + port_, + arg0, + arg1, + ); + }, + codec: DcoCodec( + decodeSuccessData: dco_decode_unit, + decodeErrorData: dco_decode_AnyhowException, + ), + constMeta: kCrateApiWin32ApiOpenDirWithExplorerConstMeta, + argValues: [path, isFile], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateApiWin32ApiOpenDirWithExplorerConstMeta => + const TaskConstMeta( + debugName: "open_dir_with_explorer", + argNames: ["path", "isFile"], + ); + @override Future crateApiUnp4KApiP4KClose() { return handler.executeNormal( @@ -679,6 +824,31 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { TaskConstMeta get kCrateApiUnp4KApiP4KOpenConstMeta => const TaskConstMeta(debugName: "p4k_open", argNames: ["p4KPath"]); + @override + Future crateApiWin32ApiResolveShortcut({required String lnkPath}) { + return handler.executeNormal( + NormalTask( + callFfi: (port_) { + var arg0 = cst_encode_String(lnkPath); + return wire.wire__crate__api__win32_api__resolve_shortcut( + port_, + arg0, + ); + }, + codec: DcoCodec( + decodeSuccessData: dco_decode_String, + decodeErrorData: dco_decode_AnyhowException, + ), + constMeta: kCrateApiWin32ApiResolveShortcutConstMeta, + argValues: [lnkPath], + apiImpl: this, + ), + ); + } + + TaskConstMeta get kCrateApiWin32ApiResolveShortcutConstMeta => + const TaskConstMeta(debugName: "resolve_shortcut", argNames: ["lnkPath"]); + @override Future crateApiAsarApiRsiLauncherAsarDataWriteMainJs({ required RsiLauncherAsarData that, @@ -1667,6 +1837,20 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { ); } + @protected + SystemInfo dco_decode_system_info(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + final arr = raw as List; + if (arr.length != 4) + throw Exception('unexpected arr length: expect 4 but see ${arr.length}'); + return SystemInfo( + osName: dco_decode_String(arr[0]), + cpuName: dco_decode_String(arr[1]), + gpuInfo: dco_decode_String(arr[2]), + diskInfo: dco_decode_String(arr[3]), + ); + } + @protected int dco_decode_u_16(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs @@ -2081,6 +2265,21 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { ); } + @protected + SystemInfo sse_decode_system_info(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + var var_osName = sse_decode_String(deserializer); + var var_cpuName = sse_decode_String(deserializer); + var var_gpuInfo = sse_decode_String(deserializer); + var var_diskInfo = sse_decode_String(deserializer); + return SystemInfo( + osName: var_osName, + cpuName: var_cpuName, + gpuInfo: var_gpuInfo, + diskInfo: var_diskInfo, + ); + } + @protected int sse_decode_u_16(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -2556,6 +2755,15 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { sse_encode_opt_list_prim_u_8_strict(self.data, serializer); } + @protected + void sse_encode_system_info(SystemInfo self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_String(self.osName, serializer); + sse_encode_String(self.cpuName, serializer); + sse_encode_String(self.gpuInfo, serializer); + sse_encode_String(self.diskInfo, serializer); + } + @protected void sse_encode_u_16(int self, SseSerializer serializer) { // Codec=Sse (Serialization based), see doc to use other codecs diff --git a/lib/common/rust/frb_generated.io.dart b/lib/common/rust/frb_generated.io.dart index 9bdbb07..500914c 100644 --- a/lib/common/rust/frb_generated.io.dart +++ b/lib/common/rust/frb_generated.io.dart @@ -126,6 +126,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected RustHttpResponse dco_decode_rust_http_response(dynamic raw); + @protected + SystemInfo dco_decode_system_info(dynamic raw); + @protected int dco_decode_u_16(dynamic raw); @@ -274,6 +277,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected RustHttpResponse sse_decode_rust_http_response(SseDeserializer deserializer); + @protected + SystemInfo sse_decode_system_info(SseDeserializer deserializer); + @protected int sse_decode_u_16(SseDeserializer deserializer); @@ -588,6 +594,17 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { wireObj.data = cst_encode_opt_list_prim_u_8_strict(apiObj.data); } + @protected + void cst_api_fill_to_wire_system_info( + SystemInfo apiObj, + wire_cst_system_info wireObj, + ) { + wireObj.os_name = cst_encode_String(apiObj.osName); + wireObj.cpu_name = cst_encode_String(apiObj.cpuName); + wireObj.gpu_info = cst_encode_String(apiObj.gpuInfo); + wireObj.disk_info = cst_encode_String(apiObj.diskInfo); + } + @protected void cst_api_fill_to_wire_web_view_configuration( WebViewConfiguration apiObj, @@ -829,6 +846,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); + @protected + void sse_encode_system_info(SystemInfo self, SseSerializer serializer); + @protected void sse_encode_u_16(int self, SseSerializer serializer); @@ -1036,6 +1056,34 @@ class RustLibWire implements BaseWire { ) >(); + void wire__crate__api__win32_api__get_gpu_info_from_registry(int port_) { + return _wire__crate__api__win32_api__get_gpu_info_from_registry(port_); + } + + late final _wire__crate__api__win32_api__get_gpu_info_from_registryPtr = + _lookup>( + 'frbgen_starcitizen_doctor_wire__crate__api__win32_api__get_gpu_info_from_registry', + ); + late final _wire__crate__api__win32_api__get_gpu_info_from_registry = + _wire__crate__api__win32_api__get_gpu_info_from_registryPtr + .asFunction(); + + void wire__crate__api__win32_api__get_number_of_logical_processors( + int port_, + ) { + return _wire__crate__api__win32_api__get_number_of_logical_processors( + port_, + ); + } + + late final _wire__crate__api__win32_api__get_number_of_logical_processorsPtr = + _lookup>( + 'frbgen_starcitizen_doctor_wire__crate__api__win32_api__get_number_of_logical_processors', + ); + late final _wire__crate__api__win32_api__get_number_of_logical_processors = + _wire__crate__api__win32_api__get_number_of_logical_processorsPtr + .asFunction(); + void wire__crate__api__win32_api__get_process_list_by_name( int port_, ffi.Pointer process_name, @@ -1117,6 +1165,30 @@ class RustLibWire implements BaseWire { void Function(int, ffi.Pointer) >(); + void wire__crate__api__win32_api__get_system_info(int port_) { + return _wire__crate__api__win32_api__get_system_info(port_); + } + + late final _wire__crate__api__win32_api__get_system_infoPtr = + _lookup>( + 'frbgen_starcitizen_doctor_wire__crate__api__win32_api__get_system_info', + ); + late final _wire__crate__api__win32_api__get_system_info = + _wire__crate__api__win32_api__get_system_infoPtr + .asFunction(); + + void wire__crate__api__win32_api__get_system_memory_size_gb(int port_) { + return _wire__crate__api__win32_api__get_system_memory_size_gb(port_); + } + + late final _wire__crate__api__win32_api__get_system_memory_size_gbPtr = + _lookup>( + 'frbgen_starcitizen_doctor_wire__crate__api__win32_api__get_system_memory_size_gb', + ); + late final _wire__crate__api__win32_api__get_system_memory_size_gb = + _wire__crate__api__win32_api__get_system_memory_size_gbPtr + .asFunction(); + void wire__crate__api__ort_api__load_translation_model( int port_, ffi.Pointer model_path, @@ -1159,6 +1231,36 @@ class RustLibWire implements BaseWire { ) >(); + void wire__crate__api__win32_api__open_dir_with_explorer( + int port_, + ffi.Pointer path, + bool is_file, + ) { + return _wire__crate__api__win32_api__open_dir_with_explorer( + port_, + path, + is_file, + ); + } + + late final _wire__crate__api__win32_api__open_dir_with_explorerPtr = + _lookup< + ffi.NativeFunction< + ffi.Void Function( + ffi.Int64, + ffi.Pointer, + ffi.Bool, + ) + > + >( + 'frbgen_starcitizen_doctor_wire__crate__api__win32_api__open_dir_with_explorer', + ); + late final _wire__crate__api__win32_api__open_dir_with_explorer = + _wire__crate__api__win32_api__open_dir_with_explorerPtr + .asFunction< + void Function(int, ffi.Pointer, bool) + >(); + void wire__crate__api__unp4k_api__p4k_close(int port_) { return _wire__crate__api__unp4k_api__p4k_close(port_); } @@ -1278,6 +1380,30 @@ class RustLibWire implements BaseWire { void Function(int, ffi.Pointer) >(); + void wire__crate__api__win32_api__resolve_shortcut( + int port_, + ffi.Pointer lnk_path, + ) { + return _wire__crate__api__win32_api__resolve_shortcut(port_, lnk_path); + } + + late final _wire__crate__api__win32_api__resolve_shortcutPtr = + _lookup< + ffi.NativeFunction< + ffi.Void Function( + ffi.Int64, + ffi.Pointer, + ) + > + >( + 'frbgen_starcitizen_doctor_wire__crate__api__win32_api__resolve_shortcut', + ); + late final _wire__crate__api__win32_api__resolve_shortcut = + _wire__crate__api__win32_api__resolve_shortcutPtr + .asFunction< + void Function(int, ffi.Pointer) + >(); + void wire__crate__api__asar_api__rsi_launcher_asar_data_write_main_js( int port_, ffi.Pointer that, @@ -2321,6 +2447,16 @@ final class wire_cst_rust_http_response extends ffi.Struct { external ffi.Pointer data; } +final class wire_cst_system_info extends ffi.Struct { + external ffi.Pointer os_name; + + external ffi.Pointer cpu_name; + + external ffi.Pointer gpu_info; + + external ffi.Pointer disk_info; +} + final class wire_cst_web_view_navigation_state extends ffi.Struct { external ffi.Pointer url; diff --git a/lib/common/rust/rust_webview_controller.dart b/lib/common/rust/rust_webview_controller.dart index b8ec5af..43fd6fb 100644 --- a/lib/common/rust/rust_webview_controller.dart +++ b/lib/common/rust/rust_webview_controller.dart @@ -4,7 +4,8 @@ import 'dart:async'; import 'dart:convert'; import 'package:flutter/services.dart'; -import 'package:starcitizen_doctor/common/rust/api/webview_api.dart' as rust_webview; +import 'package:starcitizen_doctor/common/rust/api/webview_api.dart' + as rust_webview; import 'package:starcitizen_doctor/common/utils/log.dart'; typedef OnWebMessageCallback = void Function(String message); @@ -76,7 +77,9 @@ class RustWebViewController { Future _loadScripts() async { try { _localizationScript = await rootBundle.loadString('assets/web_script.js'); - _requestInterceptorScript = await rootBundle.loadString('assets/request_interceptor.js'); + _requestInterceptorScript = await rootBundle.loadString( + 'assets/request_interceptor.js', + ); } catch (e) { dPrint("Failed to load scripts: $e"); } @@ -286,12 +289,16 @@ class RustWebViewController { } /// 添加导航完成回调(用于在页面加载完成后注入脚本) - void addOnNavigationCompletedCallback(OnNavigationCompletedCallback callback) { + void addOnNavigationCompletedCallback( + OnNavigationCompletedCallback callback, + ) { _navigationCompletedCallbacks.add(callback); } /// 移除导航完成回调 - void removeOnNavigationCompletedCallback(OnNavigationCompletedCallback callback) { + void removeOnNavigationCompletedCallback( + OnNavigationCompletedCallback callback, + ) { _navigationCompletedCallbacks.remove(callback); } @@ -320,7 +327,9 @@ class RustWebViewController { /// 更新翻译词典 void updateReplaceWords(List> words, bool enableCapture) { final jsonWords = json.encode(words); - executeScript("WebLocalizationUpdateReplaceWords($jsonWords, $enableCapture)"); + executeScript( + "WebLocalizationUpdateReplaceWords($jsonWords, $enableCapture)", + ); } /// 执行 RSI 登录脚本 diff --git a/rust/Cargo.lock b/rust/Cargo.lock index cdade69..25e45b2 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -4117,6 +4117,7 @@ dependencies = [ "walkdir", "win32job", "windows 0.62.2", + "wmi", "wry", ] @@ -5589,7 +5590,7 @@ dependencies = [ "webview2-com-sys", "windows 0.61.3", "windows-core 0.61.2", - "windows-implement", + "windows-implement 0.60.2", "windows-interface", ] @@ -5662,6 +5663,19 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddf874e74c7a99773e62b1c671427abf01a425e77c3d3fb9fb1e4883ea934529" +dependencies = [ + "windows-collections 0.1.1", + "windows-core 0.60.1", + "windows-future 0.1.1", + "windows-link 0.1.3", + "windows-numerics 0.1.1", +] + [[package]] name = "windows" version = "0.61.3" @@ -5687,6 +5701,15 @@ dependencies = [ "windows-numerics 0.3.1", ] +[[package]] +name = "windows-collections" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5467f79cc1ba3f52ebb2ed41dbb459b8e7db636cc3429458d9a852e15bc24dec" +dependencies = [ + "windows-core 0.60.1", +] + [[package]] name = "windows-collections" version = "0.2.0" @@ -5705,13 +5728,26 @@ dependencies = [ "windows-core 0.62.2", ] +[[package]] +name = "windows-core" +version = "0.60.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca21a92a9cae9bf4ccae5cf8368dce0837100ddf6e6d57936749e85f152f6247" +dependencies = [ + "windows-implement 0.59.0", + "windows-interface", + "windows-link 0.1.3", + "windows-result 0.3.4", + "windows-strings 0.3.1", +] + [[package]] name = "windows-core" version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ - "windows-implement", + "windows-implement 0.60.2", "windows-interface", "windows-link 0.1.3", "windows-result 0.3.4", @@ -5724,13 +5760,23 @@ version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ - "windows-implement", + "windows-implement 0.60.2", "windows-interface", "windows-link 0.2.1", "windows-result 0.4.1", "windows-strings 0.5.1", ] +[[package]] +name = "windows-future" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a787db4595e7eb80239b74ce8babfb1363d8e343ab072f2ffe901400c03349f0" +dependencies = [ + "windows-core 0.60.1", + "windows-link 0.1.3", +] + [[package]] name = "windows-future" version = "0.2.1" @@ -5753,6 +5799,17 @@ dependencies = [ "windows-threading 0.2.1", ] +[[package]] +name = "windows-implement" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.111", +] + [[package]] name = "windows-implement" version = "0.60.2" @@ -5787,6 +5844,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" +[[package]] +name = "windows-numerics" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "005dea54e2f6499f2cee279b8f703b3cf3b5734a2d8d21867c8f44003182eeed" +dependencies = [ + "windows-core 0.60.1", + "windows-link 0.1.3", +] + [[package]] name = "windows-numerics" version = "0.2.0" @@ -5836,6 +5903,15 @@ dependencies = [ "windows-link 0.2.1", ] +[[package]] +name = "windows-strings" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" +dependencies = [ + "windows-link 0.1.3", +] + [[package]] name = "windows-strings" version = "0.4.2" @@ -6203,6 +6279,21 @@ version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +[[package]] +name = "wmi" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f902b4592b911109e7352bcfec7b754b07ec71e514d7dfa280eaef924c1cb08" +dependencies = [ + "chrono", + "futures", + "log", + "serde", + "thiserror 2.0.17", + "windows 0.60.0", + "windows-core 0.60.1", +] + [[package]] name = "writeable" version = "0.6.2" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index fa42165..cad68f5 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -47,9 +47,17 @@ windows = { version = "0.62.2", features = [ "Win32_UI_WindowsAndMessaging", "Win32_System_Diagnostics_ToolHelp", "Win32_System_Threading", - "Win32_Foundation" + "Win32_Foundation", + "Win32_System_SystemInformation", + "Win32_System_Registry", + "Win32_Storage_FileSystem", + "Win32_UI_Shell", + "Win32_System_Com", + "Win32_System_Ole", + "Win32_System_Variant" ] } win32job = "2.0.3" +wmi = "0.15" [lints.rust] unexpected_cfgs = { level = "warn", check-cfg = ['cfg(frb_expand)'] } diff --git a/rust/src/api/win32_api.rs b/rust/src/api/win32_api.rs index 338be7b..8a1b05f 100644 --- a/rust/src/api/win32_api.rs +++ b/rust/src/api/win32_api.rs @@ -26,6 +26,359 @@ pub fn send_notify( Ok(()) } +/// Get system memory size in GB +#[cfg(target_os = "windows")] +pub fn get_system_memory_size_gb() -> anyhow::Result { + use windows::Win32::System::SystemInformation::{GlobalMemoryStatusEx, MEMORYSTATUSEX}; + use std::mem; + + unsafe { + let mut mem_status: MEMORYSTATUSEX = mem::zeroed(); + mem_status.dwLength = mem::size_of::() as u32; + + GlobalMemoryStatusEx(&mut mem_status)?; + + // Convert bytes to GB + Ok(mem_status.ullTotalPhys / (1024 * 1024 * 1024)) + } +} + +#[cfg(not(target_os = "windows"))] +pub fn get_system_memory_size_gb() -> anyhow::Result { + Ok(0) +} + +/// Get number of logical processors +#[cfg(target_os = "windows")] +pub fn get_number_of_logical_processors() -> anyhow::Result { + use windows::Win32::System::SystemInformation::{GetSystemInfo, SYSTEM_INFO}; + use std::mem; + + unsafe { + let mut sys_info: SYSTEM_INFO = mem::zeroed(); + GetSystemInfo(&mut sys_info); + Ok(sys_info.dwNumberOfProcessors) + } +} + +#[cfg(not(target_os = "windows"))] +pub fn get_number_of_logical_processors() -> anyhow::Result { + Ok(0) +} + +/// System information struct +#[derive(Debug, Clone)] +pub struct SystemInfo { + pub os_name: String, + pub cpu_name: String, + pub gpu_info: String, + pub disk_info: String, +} + +/// Get all system information at once +#[cfg(target_os = "windows")] +pub fn get_system_info() -> anyhow::Result { + use wmi::{COMLibrary, WMIConnection}; + use serde::Deserialize; + + #[derive(Deserialize, Debug)] + #[serde(rename = "Caption")] + struct OsInfo { + #[serde(rename = "Caption")] + caption: Option, + } + + #[derive(Deserialize, Debug)] + struct CpuInfo { + #[serde(rename = "Name")] + name: Option, + } + + #[derive(Deserialize, Debug)] + struct GpuInfo { + #[serde(rename = "Name")] + name: Option, + #[serde(rename = "AdapterRAM")] + adapter_ram: Option, + } + + #[derive(Deserialize, Debug)] + struct DiskInfo { + #[serde(rename = "MediaType")] + media_type: Option, + #[serde(rename = "Model")] + model: Option, + #[serde(rename = "Size")] + size: Option, + } + + let com_con = COMLibrary::new()?; + let wmi_con = WMIConnection::new(com_con)?; + + // Get OS name using raw query + let os_name = match wmi_con.raw_query::("SELECT Caption FROM Win32_OperatingSystem") { + Ok(results) => results.first() + .and_then(|os| os.caption.clone()) + .unwrap_or_default(), + Err(_) => String::new(), + }; + + // Get CPU name using raw query + let cpu_name = match wmi_con.raw_query::("SELECT Name FROM Win32_Processor") { + Ok(results) => results.first() + .and_then(|cpu| cpu.name.clone()) + .unwrap_or_default(), + Err(_) => String::new(), + }; + + // Get GPU info using raw query + let gpu_info = match wmi_con.raw_query::("SELECT Name, AdapterRAM FROM Win32_VideoController") { + Ok(results) => results.iter() + .filter_map(|gpu| { + gpu.name.as_ref().map(|name| { + let vram_gb = gpu.adapter_ram.unwrap_or(0) / (1024 * 1024 * 1024); + format!("{} ({} GB)", name, vram_gb) + }) + }) + .collect::>() + .join("\n"), + Err(_) => String::new(), + }; + + // Get Disk info using raw query + let disk_info = match wmi_con.raw_query::("SELECT MediaType, Model, Size FROM Win32_DiskDrive") { + Ok(results) => results.iter() + .filter(|disk| disk.model.is_some()) + .map(|disk| { + let size_gb = disk.size.unwrap_or(0) / (1024 * 1024 * 1024); + format!("{}\t{}\t{} GB", + disk.media_type.as_deref().unwrap_or(""), + disk.model.as_deref().unwrap_or(""), + size_gb) + }) + .collect::>() + .join("\n"), + Err(_) => String::new(), + }; + + Ok(SystemInfo { + os_name, + cpu_name, + gpu_info, + disk_info, + }) +} + +#[cfg(not(target_os = "windows"))] +pub fn get_system_info() -> anyhow::Result { + Ok(SystemInfo { + os_name: String::new(), + cpu_name: String::new(), + gpu_info: String::new(), + disk_info: String::new(), + }) +} + +/// Get GPU info from registry (more accurate VRAM) +#[cfg(target_os = "windows")] +pub fn get_gpu_info_from_registry() -> anyhow::Result { + use windows::Win32::System::Registry::{ + RegOpenKeyExW, RegQueryValueExW, RegEnumKeyExW, RegCloseKey, + HKEY_LOCAL_MACHINE, KEY_READ, REG_VALUE_TYPE, + }; + use windows::core::{HSTRING, PCWSTR}; + use std::mem; + + let mut result = Vec::new(); + let base_path = HSTRING::from(r"SYSTEM\ControlSet001\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}"); + + unsafe { + let mut hkey = std::mem::zeroed(); + if RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + PCWSTR(base_path.as_ptr()), + Some(0), + KEY_READ, + &mut hkey, + ).is_err() { + return Ok(String::new()); + } + + let mut index = 0u32; + let mut key_name = [0u16; 256]; + + loop { + let mut key_name_len = key_name.len() as u32; + if RegEnumKeyExW( + hkey, + index, + Some(windows::core::PWSTR::from_raw(key_name.as_mut_ptr())), + &mut key_name_len, + None, + None, + None, + None, + ).is_err() { + break; + } + + let subkey_name = String::from_utf16_lossy(&key_name[..key_name_len as usize]); + + // Only process numbered subkeys (0000, 0001, etc.) + if subkey_name.chars().all(|c| c.is_ascii_digit()) { + let full_path = HSTRING::from(format!( + r"SYSTEM\ControlSet001\Control\Class\{{4d36e968-e325-11ce-bfc1-08002be10318}}\{}", + subkey_name + )); + + let mut subkey = mem::zeroed(); + if RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + PCWSTR(full_path.as_ptr()), + Some(0), + KEY_READ, + &mut subkey, + ).is_ok() { + // Read adapter string + let adapter_name = HSTRING::from("HardwareInformation.AdapterString"); + let mut adapter_buffer = [0u16; 512]; + let mut adapter_size = (adapter_buffer.len() * 2) as u32; + let mut adapter_type = REG_VALUE_TYPE::default(); + + let adapter_string = if RegQueryValueExW( + subkey, + PCWSTR(adapter_name.as_ptr()), + None, + Some(&mut adapter_type), + Some(adapter_buffer.as_mut_ptr() as *mut u8), + Some(&mut adapter_size), + ).is_ok() { + let len = (adapter_size as usize / 2).saturating_sub(1); + String::from_utf16_lossy(&adapter_buffer[..len]) + } else { + String::new() + }; + + // Read memory size + let mem_name = HSTRING::from("HardwareInformation.qwMemorySize"); + let mut mem_value: u64 = 0; + let mut mem_size = std::mem::size_of::() as u32; + let mut mem_type = REG_VALUE_TYPE::default(); + + let vram_gb = if RegQueryValueExW( + subkey, + PCWSTR(mem_name.as_ptr()), + None, + Some(&mut mem_type), + Some(&mut mem_value as *mut u64 as *mut u8), + Some(&mut mem_size), + ).is_ok() { + mem_value / (1024 * 1024 * 1024) + } else { + 0 + }; + + if !adapter_string.is_empty() { + result.push(format!("Model: {}\nVRAM (GB): {}", adapter_string, vram_gb)); + } + + let _ = RegCloseKey(subkey); + } + } + + index += 1; + } + + let _ = RegCloseKey(hkey); + } + + Ok(result.join("\n\n")) +} + +#[cfg(not(target_os = "windows"))] +pub fn get_gpu_info_from_registry() -> anyhow::Result { + Ok(String::new()) +} + +/// Resolve shortcut (.lnk) file to get target path +#[cfg(target_os = "windows")] +pub fn resolve_shortcut(lnk_path: &str) -> anyhow::Result { + use windows::core::{HSTRING, Interface}; + use windows::Win32::System::Com::{ + CoCreateInstance, CoInitializeEx, CoUninitialize, + CLSCTX_INPROC_SERVER, COINIT_APARTMENTTHREADED, STGM_READ, + }; + use windows::Win32::UI::Shell::{IShellLinkW, ShellLink}; + use windows::Win32::System::Com::IPersistFile; + + unsafe { + // Initialize COM + let _ = CoInitializeEx(None, COINIT_APARTMENTTHREADED); + + let result = (|| -> anyhow::Result { + // Create ShellLink instance + let shell_link: IShellLinkW = CoCreateInstance( + &ShellLink, + None, + CLSCTX_INPROC_SERVER, + )?; + + // Get IPersistFile interface + let persist_file: IPersistFile = shell_link.cast()?; + + // Load the shortcut file + let lnk_path_w = HSTRING::from(lnk_path); + persist_file.Load(windows::core::PCWSTR(lnk_path_w.as_ptr()), STGM_READ)?; + + // Get target path + let mut path_buffer = [0u16; 260]; + shell_link.GetPath( + &mut path_buffer, + std::ptr::null_mut(), + 0, + )?; + + let path = String::from_utf16_lossy( + &path_buffer[..path_buffer.iter().position(|&c| c == 0).unwrap_or(path_buffer.len())] + ); + + Ok(path) + })(); + + CoUninitialize(); + result + } +} + +#[cfg(not(target_os = "windows"))] +pub fn resolve_shortcut(lnk_path: &str) -> anyhow::Result { + Ok(String::new()) +} + +/// Open file explorer and select file/folder +#[cfg(target_os = "windows")] +pub fn open_dir_with_explorer(path: &str, is_file: bool) -> anyhow::Result<()> { + use std::process::Command; + + if is_file { + Command::new("explorer.exe") + .args(["/select,", path]) + .spawn()?; + } else { + Command::new("explorer.exe") + .args(["/select,", path]) + .spawn()?; + } + + Ok(()) +} + +#[cfg(not(target_os = "windows"))] +pub fn open_dir_with_explorer(path: &str, is_file: bool) -> anyhow::Result<()> { + println!("open_dir_with_explorer (unix): {} is_file={}", path, is_file); + Ok(()) +} + #[cfg(target_os = "windows")] pub fn set_foreground_window(window_name: &str) -> anyhow::Result { diff --git a/rust/src/frb_generated.rs b/rust/src/frb_generated.rs index e91ad96..9540266 100644 --- a/rust/src/frb_generated.rs +++ b/rust/src/frb_generated.rs @@ -37,7 +37,7 @@ flutter_rust_bridge::frb_generated_boilerplate!( default_rust_auto_opaque = RustAutoOpaqueNom, ); pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.11.1"; -pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = -1082688871; +pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 1317751362; // Section: executor @@ -183,6 +183,48 @@ fn wire__crate__api__http_api__get_faster_url_impl( }, ) } +fn wire__crate__api__win32_api__get_gpu_info_from_registry_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "get_gpu_info_from_registry", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + move |context| { + transform_result_dco::<_, _, flutter_rust_bridge::for_generated::anyhow::Error>( + (move || { + let output_ok = crate::api::win32_api::get_gpu_info_from_registry()?; + Ok(output_ok) + })(), + ) + } + }, + ) +} +fn wire__crate__api__win32_api__get_number_of_logical_processors_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "get_number_of_logical_processors", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + move |context| { + transform_result_dco::<_, _, flutter_rust_bridge::for_generated::anyhow::Error>( + (move || { + let output_ok = crate::api::win32_api::get_number_of_logical_processors()?; + Ok(output_ok) + })(), + ) + } + }, + ) +} fn wire__crate__api__win32_api__get_process_list_by_name_impl( port_: flutter_rust_bridge::for_generated::MessagePort, process_name: impl CstDecode, @@ -257,6 +299,48 @@ fn wire__crate__api__asar_api__get_rsi_launcher_asar_data_impl( }, ) } +fn wire__crate__api__win32_api__get_system_info_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "get_system_info", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + move |context| { + transform_result_dco::<_, _, flutter_rust_bridge::for_generated::anyhow::Error>( + (move || { + let output_ok = crate::api::win32_api::get_system_info()?; + Ok(output_ok) + })(), + ) + } + }, + ) +} +fn wire__crate__api__win32_api__get_system_memory_size_gb_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "get_system_memory_size_gb", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + move |context| { + transform_result_dco::<_, _, flutter_rust_bridge::for_generated::anyhow::Error>( + (move || { + let output_ok = crate::api::win32_api::get_system_memory_size_gb()?; + Ok(output_ok) + })(), + ) + } + }, + ) +} fn wire__crate__api__ort_api__load_translation_model_impl( port_: flutter_rust_bridge::for_generated::MessagePort, model_path: impl CstDecode, @@ -291,6 +375,32 @@ fn wire__crate__api__ort_api__load_translation_model_impl( }, ) } +fn wire__crate__api__win32_api__open_dir_with_explorer_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + path: impl CstDecode, + is_file: impl CstDecode, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "open_dir_with_explorer", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let api_path = path.cst_decode(); + let api_is_file = is_file.cst_decode(); + move |context| { + transform_result_dco::<_, _, flutter_rust_bridge::for_generated::anyhow::Error>( + (move || { + let output_ok = + crate::api::win32_api::open_dir_with_explorer(&api_path, api_is_file)?; + Ok(output_ok) + })(), + ) + } + }, + ) +} fn wire__crate__api__unp4k_api__p4k_close_impl( port_: flutter_rust_bridge::for_generated::MessagePort, ) { @@ -436,6 +546,29 @@ fn wire__crate__api__unp4k_api__p4k_open_impl( }, ) } +fn wire__crate__api__win32_api__resolve_shortcut_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + lnk_path: impl CstDecode, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "resolve_shortcut", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let api_lnk_path = lnk_path.cst_decode(); + move |context| { + transform_result_dco::<_, _, flutter_rust_bridge::for_generated::anyhow::Error>( + (move || { + let output_ok = crate::api::win32_api::resolve_shortcut(&api_lnk_path)?; + Ok(output_ok) + })(), + ) + } + }, + ) +} fn wire__crate__api__asar_api__rsi_launcher_asar_data_write_main_js_impl( port_: flutter_rust_bridge::for_generated::MessagePort, that: impl CstDecode, @@ -1451,6 +1584,22 @@ impl SseDecode for crate::http_package::RustHttpResponse { } } +impl SseDecode for crate::api::win32_api::SystemInfo { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut var_osName = ::sse_decode(deserializer); + let mut var_cpuName = ::sse_decode(deserializer); + let mut var_gpuInfo = ::sse_decode(deserializer); + let mut var_diskInfo = ::sse_decode(deserializer); + return crate::api::win32_api::SystemInfo { + os_name: var_osName, + cpu_name: var_cpuName, + gpu_info: var_gpuInfo, + disk_info: var_diskInfo, + }; + } +} + impl SseDecode for u16 { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { @@ -1789,6 +1938,29 @@ impl flutter_rust_bridge::IntoIntoDart } } // Codec=Dco (DartCObject based), see doc to use other codecs +impl flutter_rust_bridge::IntoDart for crate::api::win32_api::SystemInfo { + fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi { + [ + self.os_name.into_into_dart().into_dart(), + self.cpu_name.into_into_dart().into_dart(), + self.gpu_info.into_into_dart().into_dart(), + self.disk_info.into_into_dart().into_dart(), + ] + .into_dart() + } +} +impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive + for crate::api::win32_api::SystemInfo +{ +} +impl flutter_rust_bridge::IntoIntoDart + for crate::api::win32_api::SystemInfo +{ + fn into_into_dart(self) -> crate::api::win32_api::SystemInfo { + self + } +} +// Codec=Dco (DartCObject based), see doc to use other codecs impl flutter_rust_bridge::IntoDart for crate::api::webview_api::WebViewConfiguration { fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi { [ @@ -2159,6 +2331,16 @@ impl SseEncode for crate::http_package::RustHttpResponse { } } +impl SseEncode for crate::api::win32_api::SystemInfo { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.os_name, serializer); + ::sse_encode(self.cpu_name, serializer); + ::sse_encode(self.gpu_info, serializer); + ::sse_encode(self.disk_info, serializer); + } +} + impl SseEncode for u16 { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { @@ -2481,6 +2663,17 @@ mod io { } } } + impl CstDecode for wire_cst_system_info { + // Codec=Cst (C-struct based), see doc to use other codecs + fn cst_decode(self) -> crate::api::win32_api::SystemInfo { + crate::api::win32_api::SystemInfo { + os_name: self.os_name.cst_decode(), + cpu_name: self.cpu_name.cst_decode(), + gpu_info: self.gpu_info.cst_decode(), + disk_info: self.disk_info.cst_decode(), + } + } + } impl CstDecode for wire_cst_web_view_configuration { // Codec=Cst (C-struct based), see doc to use other codecs fn cst_decode(self) -> crate::api::webview_api::WebViewConfiguration { @@ -2637,6 +2830,21 @@ mod io { Self::new_with_null_ptr() } } + impl NewWithNullPtr for wire_cst_system_info { + fn new_with_null_ptr() -> Self { + Self { + os_name: core::ptr::null_mut(), + cpu_name: core::ptr::null_mut(), + gpu_info: core::ptr::null_mut(), + disk_info: core::ptr::null_mut(), + } + } + } + impl Default for wire_cst_system_info { + fn default() -> Self { + Self::new_with_null_ptr() + } + } impl NewWithNullPtr for wire_cst_web_view_configuration { fn new_with_null_ptr() -> Self { Self { @@ -2738,6 +2946,20 @@ mod io { wire__crate__api__http_api__get_faster_url_impl(port_, urls, path_suffix) } + #[unsafe(no_mangle)] + pub extern "C" fn frbgen_starcitizen_doctor_wire__crate__api__win32_api__get_gpu_info_from_registry( + port_: i64, + ) { + wire__crate__api__win32_api__get_gpu_info_from_registry_impl(port_) + } + + #[unsafe(no_mangle)] + pub extern "C" fn frbgen_starcitizen_doctor_wire__crate__api__win32_api__get_number_of_logical_processors( + port_: i64, + ) { + wire__crate__api__win32_api__get_number_of_logical_processors_impl(port_) + } + #[unsafe(no_mangle)] pub extern "C" fn frbgen_starcitizen_doctor_wire__crate__api__win32_api__get_process_list_by_name( port_: i64, @@ -2762,6 +2984,20 @@ mod io { wire__crate__api__asar_api__get_rsi_launcher_asar_data_impl(port_, asar_path) } + #[unsafe(no_mangle)] + pub extern "C" fn frbgen_starcitizen_doctor_wire__crate__api__win32_api__get_system_info( + port_: i64, + ) { + wire__crate__api__win32_api__get_system_info_impl(port_) + } + + #[unsafe(no_mangle)] + pub extern "C" fn frbgen_starcitizen_doctor_wire__crate__api__win32_api__get_system_memory_size_gb( + port_: i64, + ) { + wire__crate__api__win32_api__get_system_memory_size_gb_impl(port_) + } + #[unsafe(no_mangle)] pub extern "C" fn frbgen_starcitizen_doctor_wire__crate__api__ort_api__load_translation_model( port_: i64, @@ -2779,6 +3015,15 @@ mod io { ) } + #[unsafe(no_mangle)] + pub extern "C" fn frbgen_starcitizen_doctor_wire__crate__api__win32_api__open_dir_with_explorer( + port_: i64, + path: *mut wire_cst_list_prim_u_8_strict, + is_file: bool, + ) { + wire__crate__api__win32_api__open_dir_with_explorer_impl(port_, path, is_file) + } + #[unsafe(no_mangle)] pub extern "C" fn frbgen_starcitizen_doctor_wire__crate__api__unp4k_api__p4k_close(port_: i64) { wire__crate__api__unp4k_api__p4k_close_impl(port_) @@ -2823,6 +3068,14 @@ mod io { wire__crate__api__unp4k_api__p4k_open_impl(port_, p4k_path) } + #[unsafe(no_mangle)] + pub extern "C" fn frbgen_starcitizen_doctor_wire__crate__api__win32_api__resolve_shortcut( + port_: i64, + lnk_path: *mut wire_cst_list_prim_u_8_strict, + ) { + wire__crate__api__win32_api__resolve_shortcut_impl(port_, lnk_path) + } + #[unsafe(no_mangle)] pub extern "C" fn frbgen_starcitizen_doctor_wire__crate__api__asar_api__rsi_launcher_asar_data_write_main_js( port_: i64, @@ -3245,6 +3498,14 @@ mod io { } #[repr(C)] #[derive(Clone, Copy)] + pub struct wire_cst_system_info { + os_name: *mut wire_cst_list_prim_u_8_strict, + cpu_name: *mut wire_cst_list_prim_u_8_strict, + gpu_info: *mut wire_cst_list_prim_u_8_strict, + disk_info: *mut wire_cst_list_prim_u_8_strict, + } + #[repr(C)] + #[derive(Clone, Copy)] pub struct wire_cst_web_view_configuration { title: *mut wire_cst_list_prim_u_8_strict, width: u32,