Skip to content

Commit

Permalink
Retrieve WSA directory dynamically
Browse files Browse the repository at this point in the history
  • Loading branch information
alesimula committed Nov 21, 2021
1 parent a3cf0e5 commit 9bf4dd6
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 8 deletions.
4 changes: 2 additions & 2 deletions lib/apk_installer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -376,10 +376,10 @@ class ApkInstaller extends StatefulWidget {

static void createLaunchIcon(String package, String appName) {
WinIO.createShortcut(
r"%LOCALAPPDATA%\Microsoft\WindowsApps\MicrosoftCorporationII.WindowsSubsystemForAndroid_8wekyb3d8bbwe\WsaClient.exe",
"%LOCALAPPDATA%\\Microsoft\\WindowsApps\\${Env.WSA_INFO.familyName}\\WsaClient.exe",
"${WinPath.desktop}\\$appName",
args: "/launch wsa://$package",
icon: '%LOCALAPPDATA%\\Packages\\MicrosoftCorporationII.WindowsSubsystemForAndroid_8wekyb3d8bbwe\\LocalState\\$package.ico');
icon: '%LOCALAPPDATA%\\Packages\\${Env.WSA_INFO.familyName}\\LocalState\\$package.ico');
}

static void installApk(String apkFile, String ipAddress, int port, [bool downgrade = false]) async {
Expand Down
15 changes: 9 additions & 6 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@


import 'package:flutter/material.dart' as material;
import 'package:flutter/services.dart';
import 'package:mdi/mdi.dart';
import 'package:wsa_pacman/apk_installer.dart';
import 'package:wsa_pacman/widget/move_window_nomax.dart';
import 'package:fluent_ui/fluent_ui.dart';
import 'package:flutter/foundation.dart';
//import 'package:flutter/material.dart' hide showDialog;
import 'package:shared_value/shared_value.dart';
import 'package:wsa_pacman/windows/win_pkg.dart';
import 'package:wsa_pacman/windows/win_reg.dart';
import 'global_state.dart';

import 'package:provider/provider.dart';
Expand All @@ -20,16 +20,13 @@ import 'package:flutter_acrylic/flutter_acrylic.dart' as flutter_acrylic;
import 'package:url_strategy/url_strategy.dart';

import 'screens/forms.dart';
import 'screens/others.dart';
import 'screens/settings.dart';
import 'proto/options.pb.dart';
import 'utils/string_utils.dart';

import 'dart:io';
import 'dart:developer';
import 'dart:async';

import 'package:synchronized/synchronized.dart';

import 'theme.dart';

const String appTitle = 'WSA Package Manager';
Expand Down Expand Up @@ -86,6 +83,12 @@ class Env {
static final String USER_PROFILE = Platform.environment["UserProfile"] ?? "";
static final String EXEC_DIR = Platform.resolvedExecutable.replaceFirst(RegExp(r'[/\\][^/\\]*$'), r'\');
static final String TOOLS_DIR = "${EXEC_DIR}embedded-tools\\";
static late final String POWERSHELL = WinReg.getString(RegHKey.HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell', 'Path')?.value ?? '$SYSTEM_ROOT\\System32\\WindowsPowerShell\v1.0\\powershell.exe';
static late final String WSA_SYSTEM_PATH = RegExp(r'^(.*)[\\/]+[^\\/]*[\\/]+[^\\/]*$').firstMatch(
WinReg.getString(RegHKey.HKEY_LOCAL_MACHINE, r'SYSTEM\CurrentControlSet\Services\WsaService', 'ImagePath')?.value.unquoted ??
WinReg.getString(RegHKey.HKEY_CURRENT_USER, r'Software\Microsoft\Windows\CurrentVersion\App Paths\WsaClient.exe', null)?.value ?? ''
)?.group(1) ?? '';
static late final WSA_INFO = WinPkgInfo.fromSystemPath(WSA_SYSTEM_PATH);
}

class WSAPeriodicConnector {
Expand Down
1 change: 1 addition & 0 deletions lib/utils/string_utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ extension StringUtils on String {

String get capitalized => '${this[0].toUpperCase()}${substring(1)}';
String get normalized => '${this[0].toUpperCase()}${replaceAll('_', ' ').substring(1).toLowerCase()}';
String get unquoted => RegExp(r'^"?(.*)"?$', multiLine: true).firstMatch(this)?.group(1) ?? this;

bool isNumeric() => contains(RegExp(r'^[0-9]*$'));
bool isSignedNumeric() => contains(RegExp(r'^[+-]?[0-9]*$'));
Expand Down
72 changes: 72 additions & 0 deletions lib/windows/win_pkg.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// ignore_for_file: constant_identifier_names, non_constant_identifier_names

import 'dart:ffi';
import 'dart:io';
import 'dart:typed_data';
import 'package:base32/encodings.dart';
import 'package:charset/charset.dart';
import 'package:crypto/crypto.dart';

import 'package:base32/base32.dart';
import 'package:ffi/ffi.dart';
import 'package:win32/win32.dart';

import '../utils/string_utils.dart';


const _INITIAL_OUTPUT_BUFFER_CHARS = 256;

class WinPkg {
static String getPublisherId(String publisher) {
return base32.encode(Uint8List.fromList(sha256.convert((utf16.encoder as Utf16Encoder).encodeUtf16Le(publisher)).bytes.sublist(0, 8)), encoding: Encoding.crockford).toLowerCase();
}

static String? getPackageFamilyName(String fullName) {
final lpName = ("MicrosoftCorporationII.WindowsSubsystemForAndroid_1.8.32822.0_x64__8wekyb3d8bbwe").toNativeUtf16();
var lpFamilyName = malloc<WCHAR>(_INITIAL_OUTPUT_BUFFER_CHARS).cast<Utf16>();
final lpBufferLenght = malloc<DWORD>()..value = _INITIAL_OUTPUT_BUFFER_CHARS;

try {
int exitCode = PackageFamilyNameFromFullName(lpName, lpBufferLenght, lpFamilyName);
if (exitCode == ERROR_INSUFFICIENT_BUFFER) {
free(lpFamilyName);
lpFamilyName = malloc<WCHAR>(lpBufferLenght.value).cast<Utf16>();
PackageFamilyNameFromFullName(lpName, lpBufferLenght, lpFamilyName);
}
return lpFamilyName.toDartString();
}
finally {
free(lpName);
free(lpFamilyName);
free(lpBufferLenght);
}
}
}


class WinPkgInfo {
late final String name;
late final String publisherId;
late final String version;
late final String architecture;

String get fullName => "${name}_${version}_${architecture}__$publisherId";
String get familyName => "${name}_$publisherId";

WinPkgInfo(String manifest) {
try {
String? identity = RegExp(r'<\s*Identity[^">]*("[^"]*"[^">]*)*>', multiLine: true).firstMatch(manifest)?.group(0)?.replaceAll('\n', ' ');
name = identity?.find(r'\s+Name\s*=\s*"([^"]*)', 1) ?? 'UNKNOWN_APP_NAME';
String? publisher = identity?.find(r'\s+Publisher\s*=\s*"([^"]*)', 1);
publisherId = (publisher != null) ? WinPkg.getPublisherId(publisher) : 'UNKNOWN_PUBLISHER_ID';
version = identity?.find(r'\s+Version\s*=\s*"([^"]*)', 1) ?? 'UNKNOWN_VERSION';
architecture = identity?.find(r'\s+ProcessorArchitecture\s*=\s*"([^"]*)', 1) ?? 'UNKNOWN_ARCHITECTURE';
}
catch(e) {/**/}
}

factory WinPkgInfo.fromSystemPath(String systemPath) {
try {return WinPkgInfo(File("$systemPath\\AppxManifest.xml").readAsStringSync());}
catch(_) {return WinPkgInfo("");}
}
}
90 changes: 90 additions & 0 deletions lib/windows/win_reg.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// ignore_for_file: constant_identifier_names, non_constant_identifier_names

import 'dart:developer';
import 'dart:ffi';

import 'package:ffi/ffi.dart';
import 'package:win32/win32.dart';

const _MAX_ITEMLENGTH = 1024;

extension on String {
static final RegExp _KEY_PATH_NORMALIZER = RegExp(r'[\\]*(.*)');
String? get normalizedRegKey => _KEY_PATH_NORMALIZER.firstMatch(this)?.group(1);
}

enum RegHKey {
HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, HKEY_USERS, HKEY_PERFORMANCE_DATA, HKEY_PERFORMANCE_TEXT,
HKEY_PERFORMANCE_NLSTEXT, HKEY_CURRENT_CONFIG, HKEY_DYN_DATA, HKEY_CURRENT_USER_LOCAL_SETTINGS
}

extension on RegHKey {
int get value {switch(this) {
case RegHKey.HKEY_CLASSES_ROOT: return HKEY_CLASSES_ROOT;
case RegHKey.HKEY_CURRENT_USER: return HKEY_CURRENT_USER;
case RegHKey.HKEY_LOCAL_MACHINE: return HKEY_LOCAL_MACHINE;
case RegHKey.HKEY_USERS: return HKEY_USERS;
case RegHKey.HKEY_PERFORMANCE_DATA: return HKEY_PERFORMANCE_DATA;
case RegHKey.HKEY_PERFORMANCE_TEXT: return HKEY_PERFORMANCE_TEXT;
case RegHKey.HKEY_PERFORMANCE_NLSTEXT: return HKEY_PERFORMANCE_NLSTEXT;
case RegHKey.HKEY_CURRENT_CONFIG: return HKEY_CURRENT_CONFIG;
case RegHKey.HKEY_DYN_DATA: return HKEY_DYN_DATA;
case RegHKey.HKEY_CURRENT_USER_LOCAL_SETTINGS: return HKEY_CURRENT_USER_LOCAL_SETTINGS;
}}
}

class RegValue {
RegValue._create(this.type, this.value);
String value;
int type;
}

class WinReg {
static RegValue? getString(RegHKey hKey, String keyPath, String? valName, {bool noExpand = false}) {
String? keyPathN = keyPath.normalizedRegKey;
if (keyPathN == null) return null;

final lpKey = keyPathN.toNativeUtf16();
final lpValue = (valName != null && valName.isNotEmpty) ? valName.toNativeUtf16() : nullptr;
final lpType = calloc<DWORD>();
final lpData = calloc<BYTE>(_MAX_ITEMLENGTH);
final lpcbData = calloc<DWORD>()..value = _MAX_ITEMLENGTH;

int flags = RRF_RT_ANY;
if (noExpand) flags |= RRF_NOEXPAND;

try {
final status = RegGetValue(hKey.value, lpKey, lpValue, flags, lpType, lpData, lpcbData);

switch (status) {
case ERROR_SUCCESS:
int type = lpType.value;
if (type != REG_SZ && type != REG_EXPAND_SZ && type != REG_MULTI_SZ) {
log('win_reg: Non-string content; type: $type');
return null;
}
log('win_reg: value type: $type');
return RegValue._create(type, lpData.cast<Utf16>().toDartString());

case ERROR_MORE_DATA:
log('win_reg: An item required more than $_MAX_ITEMLENGTH bytes');
return null;
//throw Exception('An item required more than $_MAX_ITEMLENGTH bytes.');

case ERROR_NO_MORE_ITEMS:
return null;

default:
log('win_reg: Unknown error');
return null;
//throw Exception('unknown error');
}
} finally {
free(lpKey);
free(lpValue);
free(lpType);
free(lpData);
free(lpcbData);
}
}
}
14 changes: 14 additions & 0 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.8.2"
base32:
dependency: "direct main"
description:
name: base32
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
bitsdojo_window:
dependency: "direct main"
description:
Expand Down Expand Up @@ -78,6 +85,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.1"
charset:
dependency: "direct main"
description:
name: charset
url: "https://pub.dartlang.org"
source: hosted
version: "0.1.1"
clock:
dependency: transitive
description:
Expand Down
2 changes: 2 additions & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ dependencies:
#path_provider: ^2.0.6
mdi: ^5.0.0-nullsafety.0
win32: ^2.3.0
base32: ^2.1.1
charset: ^0.1.1


dev_dependencies:
Expand Down

0 comments on commit 9bf4dd6

Please sign in to comment.