mirror of
https://github.com/WSA-Installer/wsa-installer.git
synced 2026-07-29 11:24:06 -07:00
feat: add source code — app.py, run.py, build scripts, NSIS, requirements
This commit is contained in:
@@ -0,0 +1,241 @@
|
||||
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
|
||||
<Package IgnorableNamespaces="desktop8 build" xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3" xmlns:uap4="http://schemas.microsoft.com/appx/manifest/uap/windows10/4" xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5" xmlns:uap7="http://schemas.microsoft.com/appx/manifest/uap/windows10/7" xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10" xmlns:desktop2="http://schemas.microsoft.com/appx/manifest/desktop/windows10/2" xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6" xmlns:desktop8="http://schemas.microsoft.com/appx/manifest/desktop/windows10/8" xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10" xmlns:com2="http://schemas.microsoft.com/appx/manifest/com/windows10/2" xmlns:com3="http://schemas.microsoft.com/appx/manifest/com/windows10/3" xmlns:build="http://schemas.microsoft.com/developer/appx/2015/build" xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest">
|
||||
<Identity Name="MicrosoftCorporationII.WindowsSubsystemForAndroid" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" Version="2407.40000.4.0" ProcessorArchitecture="x64" />
|
||||
<Properties>
|
||||
<DisplayName>ms-resource:WsaPackageDisplayName</DisplayName>
|
||||
<PublisherDisplayName>Microsoft Corp.</PublisherDisplayName>
|
||||
<Logo>Images\StoreLogo.png</Logo>
|
||||
<desktop6:FileSystemWriteVirtualization>disabled</desktop6:FileSystemWriteVirtualization>
|
||||
<desktop6:RegistryWriteVirtualization>disabled</desktop6:RegistryWriteVirtualization>
|
||||
</Properties>
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.22000.120" MaxVersionTested="10.0.22000.120" />
|
||||
<PackageDependency Name="Microsoft.UI.Xaml.2.8" MinVersion="8.2208.12001.0" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
|
||||
<PackageDependency Name="Microsoft.VCLibs.140.00.UWPDesktop" MinVersion="14.0.33728.0" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
|
||||
<PackageDependency Name="Microsoft.VCLibs.140.00" MinVersion="14.0.33519.0" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
|
||||
</Dependencies>
|
||||
<Resources>
|
||||
<Resource Language="EN-US" />
|
||||
<Resource Language="EN-GB" />
|
||||
<Resource uap:Scale="200" />
|
||||
<Resource Language="af-za" />
|
||||
<Resource Language="ar-sa" />
|
||||
<Resource Language="az-latn-az" />
|
||||
<Resource Language="bg-bg" />
|
||||
<Resource Language="bs-latn-ba" />
|
||||
<Resource Language="ca-es" />
|
||||
<Resource Language="cs-cz" />
|
||||
<Resource Language="cy-gb" />
|
||||
<Resource Language="da-dk" />
|
||||
<Resource Language="de-de" />
|
||||
<Resource Language="el-gr" />
|
||||
<Resource Language="es-es" />
|
||||
<Resource Language="es-mx" />
|
||||
<Resource Language="et-ee" />
|
||||
<Resource Language="eu-es" />
|
||||
<Resource Language="fa-ir" />
|
||||
<Resource Language="fi-fi" />
|
||||
<Resource Language="fr-ca" />
|
||||
<Resource Language="fr-fr" />
|
||||
<Resource Language="gl-es" />
|
||||
<Resource Language="he-il" />
|
||||
<Resource Language="hi-in" />
|
||||
<Resource Language="hr-hr" />
|
||||
<Resource Language="hu-hu" />
|
||||
<Resource Language="id-id" />
|
||||
<Resource Language="is-is" />
|
||||
<Resource Language="it-it" />
|
||||
<Resource Language="ja-jp" />
|
||||
<Resource Language="ka-ge" />
|
||||
<Resource Language="kk-kz" />
|
||||
<Resource Language="ko-kr" />
|
||||
<Resource Language="lt-lt" />
|
||||
<Resource Language="lv-lv" />
|
||||
<Resource Language="ms-my" />
|
||||
<Resource Language="nb-no" />
|
||||
<Resource Language="nl-nl" />
|
||||
<Resource Language="nn-no" />
|
||||
<Resource Language="pl-pl" />
|
||||
<Resource Language="pt-br" />
|
||||
<Resource Language="pt-pt" />
|
||||
<Resource Language="qps-ploc" />
|
||||
<Resource Language="qps-ploca" />
|
||||
<Resource Language="qps-plocm" />
|
||||
<Resource Language="ro-ro" />
|
||||
<Resource Language="ru-ru" />
|
||||
<Resource Language="sk-sk" />
|
||||
<Resource Language="sl-si" />
|
||||
<Resource Language="sq-al" />
|
||||
<Resource Language="sr-cyrl-rs" />
|
||||
<Resource Language="sr-latn-rs" />
|
||||
<Resource Language="sv-se" />
|
||||
<Resource Language="th-th" />
|
||||
<Resource Language="tr-tr" />
|
||||
<Resource Language="uk-ua" />
|
||||
<Resource Language="vi-vn" />
|
||||
<Resource Language="zh-cn" />
|
||||
<Resource Language="zh-tw" />
|
||||
<Resource uap:Scale="100" />
|
||||
<Resource uap:Scale="125" />
|
||||
<Resource uap:Scale="150" />
|
||||
<Resource uap:Scale="400" />
|
||||
</Resources>
|
||||
<Applications>
|
||||
<Application Id="App" Executable="WsaClient\WsaClient.exe" EntryPoint="Windows.FullTrustApplication">
|
||||
<uap:VisualElements DisplayName="ms-resource:WsaDisplayName" Description="ms-resource:WsaDescription" BackgroundColor="transparent" Square150x150Logo="Images\MedTile.png" Square44x44Logo="Images\AppList.png" AppListEntry="none">
|
||||
<uap:DefaultTile Wide310x150Logo="Images\WideTile.png" Square71x71Logo="Images\SmallTile.png" Square310x310Logo="Images\LargeTile.png" />
|
||||
<uap:SplashScreen Image="Images\SplashScreen.png" />
|
||||
</uap:VisualElements>
|
||||
<Extensions>
|
||||
<desktop:Extension Category="windows.toastNotificationActivation">
|
||||
<desktop:ToastNotificationActivation ToastActivatorCLSID="18AF5090-C390-45D6-9FF1-CA3E608503B0" />
|
||||
</desktop:Extension>
|
||||
<uap:Extension Category="windows.protocol">
|
||||
<uap3:Protocol Name="wsa" Parameters="/launch %1" />
|
||||
</uap:Extension>
|
||||
<uap:Extension Category="windows.protocol">
|
||||
<uap3:Protocol Name="wsa-client" Parameters="/deeplink %1" />
|
||||
</uap:Extension>
|
||||
<uap5:Extension Category="windows.startupTask" uap10:Parameters="/restart 0">
|
||||
<uap5:StartupTask TaskId="ContinuousVirtualMachine" Enabled="false" />
|
||||
</uap5:Extension>
|
||||
<uap5:Extension Category="windows.startupTask" uap10:Parameters="/partiallyrunning">
|
||||
<uap5:StartupTask TaskId="PartiallyRunningVirtualMachine" Enabled="false" />
|
||||
</uap5:Extension>
|
||||
<uap3:Extension Category="windows.appExecutionAlias">
|
||||
<uap3:AppExecutionAlias>
|
||||
<desktop:ExecutionAlias Alias="WsaClient.exe" />
|
||||
</uap3:AppExecutionAlias>
|
||||
</uap3:Extension>
|
||||
<desktop6:Extension Category="windows.service" Executable="WsaService\WsaService.exe" EntryPoint="WsaService.Service">
|
||||
<desktop6:Service Name="WsaService" StartupType="manual" StartAccount="localSystem" />
|
||||
</desktop6:Extension>
|
||||
<com2:Extension Category="windows.comServer">
|
||||
<com2:ComServer>
|
||||
<com:ExeServer Executable="WsaClient\WsaClient.exe" LaunchAndActivationPermission="O:SYG:SYD:(A;;11;;;IU)(A;;11;;;S-1-15-2-4120862662-1149765626-4064695116-299589112-4208539117-2961988684-1460418210)S:(ML;;NX;;;ME)">
|
||||
<com:Class Id="A6727475-2A07-4ACC-9FA6-58347FDF7A37" DisplayName="CLSID_VirtioGpuDevice" />
|
||||
</com:ExeServer>
|
||||
<com3:ServiceServer ServiceName="WsaService" LaunchAndActivationPermission="O:SYG:SYD:(A;;11;;;IU)">
|
||||
<com3:Class Id="D738F5F3-7527-4DD6-BA47-D75688104C46" DisplayName="CLSID_WsaServer" />
|
||||
</com3:ServiceServer>
|
||||
<com:ExeServer Executable="WsaClient\WsaClient.exe">
|
||||
<com:Class Id="18AF5090-C390-45D6-9FF1-CA3E608503B0" DisplayName="CLSID_WsaToastActivator" />
|
||||
<com:Class Id="df32c7a1-a920-458d-a5c5-0e627f222be9" DisplayName="CLSID_WsaWnsRefreshHandler" />
|
||||
<com:Class Id="5c3e8567-7095-47c0-98e5-1d196ffcc857" DisplayName="CLSID_WsaWnsPushHandler" />
|
||||
<com:Class Id="BAF81707-7A8C-4A96-8B01-A9F16E444905" DisplayName="CLSID_WsaSession" />
|
||||
</com:ExeServer>
|
||||
<com:SurrogateServer DisplayName="WslDeviceHost_Virtio" AppId="58AC9971-23C7-45EA-933F-7B155AA16FC2">
|
||||
<com:Class Id="5A167A26-2D39-4456-B802-61F1ABE83D84" Path="wsldevicehost.dll" ThreadingModel="Both" />
|
||||
<com:Class Id="5a918e2f-d58a-48d9-be09-36ea1615a7f2" Path="wsldevicehost.dll" ThreadingModel="Both" />
|
||||
<com:Class Id="16479D2E-F0C3-4DBA-BF7A-04FFF0892B07" Path="wsldevicehost.dll" ThreadingModel="Both" />
|
||||
</com:SurrogateServer>
|
||||
<com:ExeServer Executable="WsaClient\WsaClient.exe" LaunchAndActivationPermission="O:SYG:SYD:(A;;11;;;IU)(A;;11;;;S-1-15-2-4120862662-1149765626-4064695116-299589112-4208539117-2961988684-1460418210)S:(ML;;NX;;;ME)">
|
||||
<com:Class Id="286DD941-F692-41ED-A20D-8E8AA9181B10" DisplayName="CLSID_WsaClient" />
|
||||
</com:ExeServer>
|
||||
<com:ExeServer Executable="WsaClient\WsaClient.exe" LaunchAndActivationPermission="O:SYG:SYD:(A;;9;;;IU)(A;;9;;;S-1-15-2-4120862662-1149765626-4064695116-299589112-4208539117-2961988684-1460418210)S:(ML;;NX;;;ME)">
|
||||
<com:Class Id="E04AE257-E3B5-4A50-830F-7CFB124A8661" DisplayName="CLSID_WsaClientBindOnly" />
|
||||
<com:Class Id="A09CE5A1-6194-4387-A6F1-FA4FD1C93AF0" DisplayName="CLSID_WsaTestHooks" />
|
||||
</com:ExeServer>
|
||||
<com:ExeServer Executable="WsaSettingsBroker\WsaSettingsBroker.exe" LaunchAndActivationPermission="O:SYG:SYD:(A;;11;;;IU)(A;;11;;;S-1-15-2-4120862662-1149765626-4064695116-299589112-4208539117-2961988684-1460418210)S:(ML;;NX;;;ME)">
|
||||
<com:Class Id="92E5D48B-DD18-4339-884F-D6087F81E797" DisplayName="CLSID_WsaSettingsBroker" />
|
||||
</com:ExeServer>
|
||||
</com2:ComServer>
|
||||
</com2:Extension>
|
||||
<com2:Extension Category="windows.comInterface">
|
||||
<com2:ComInterface>
|
||||
<com:Interface Id="02754A08-9A4F-48DA-8209-51238D00278A" ProxyStubClsid="76913B52-F9EB-4FAE-8DE7-24C20BDCF37B" />
|
||||
<com:Interface Id="04A4E322-4148-44AF-9053-A7BEDD09178C" ProxyStubClsid="76913B52-F9EB-4FAE-8DE7-24C20BDCF37B" />
|
||||
<com:Interface Id="6A0E8133-9C70-4193-821F-A6FF231D5665" ProxyStubClsid="76913B52-F9EB-4FAE-8DE7-24C20BDCF37B" />
|
||||
<com:Interface Id="3C80B0C2-966E-4AC8-BA88-793970E0650B" ProxyStubClsid="76913B52-F9EB-4FAE-8DE7-24C20BDCF37B" />
|
||||
<com:Interface Id="E080792C-6458-49A4-AA35-D77EE2C6B1C9" ProxyStubClsid="76913B52-F9EB-4FAE-8DE7-24C20BDCF37B" />
|
||||
<com:Interface Id="D5873B8F-2048-4877-83A2-473DBA08ABD2" ProxyStubClsid="76913B52-F9EB-4FAE-8DE7-24C20BDCF37B" />
|
||||
<com:Interface Id="A2FD4EB6-587F-4646-A548-E245BDDF6FEB" ProxyStubClsid="76913B52-F9EB-4FAE-8DE7-24C20BDCF37B" />
|
||||
<com:ProxyStub Id="76913B52-F9EB-4FAE-8DE7-24C20BDCF37B" Path="WsaProxy\WsaProxy.dll" />
|
||||
</com2:ComInterface>
|
||||
</com2:Extension>
|
||||
<uap3:Extension Category="windows.appUriHandler" uap10:Parameters="/appuri %1">
|
||||
<uap3:AppUriHandler uap7:Name="WsaAppUriHandler">
|
||||
<uap3:Host Name="WindowsSubsystemForAndroid.microsoft.com" />
|
||||
</uap3:AppUriHandler>
|
||||
</uap3:Extension>
|
||||
</Extensions>
|
||||
</Application>
|
||||
<Application Id="SettingsApp" Executable="WsaSettings.exe" EntryPoint="WsaSettings.App">
|
||||
<uap:VisualElements DisplayName="ms-resource:WsaSettingsDisplayName" Description="ms-resource:WsaSettingsDescription" Square150x150Logo="Images\MedTile.png" Square44x44Logo="Images\AppList.png" BackgroundColor="transparent">
|
||||
<uap:DefaultTile Wide310x150Logo="Images\WideTile.png" Square71x71Logo="Images\SmallTile.png" Square310x310Logo="Images\LargeTile.png" />
|
||||
<uap:SplashScreen Image="Images\SplashScreen.png" />
|
||||
</uap:VisualElements>
|
||||
<Extensions>
|
||||
<uap:Extension Category="windows.protocol">
|
||||
<uap3:Protocol Name="wsa-settings" />
|
||||
</uap:Extension>
|
||||
</Extensions>
|
||||
</Application>
|
||||
</Applications>
|
||||
<Capabilities>
|
||||
<Capability Name="internetClient" />
|
||||
<Capability Name="internetClientServer" />
|
||||
<Capability Name="privateNetworkClientServer" />
|
||||
<rescap:Capability Name="runFullTrust" />
|
||||
<rescap:Capability Name="unvirtualizedResources" />
|
||||
<rescap:Capability Name="packagedServices" />
|
||||
<rescap:Capability Name="localSystemServices" />
|
||||
<rescap:Capability Name="packageManagement" />
|
||||
<rescap:Capability Name="packageQuery" />
|
||||
<rescap:Capability Name="customInstallActions" />
|
||||
<uap4:CustomCapability Name="Microsoft.classicAppInstaller_8wekyb3d8bbwe" />
|
||||
<uap4:CustomCapability Name="Microsoft.delegatedWebFeatures_8wekyb3d8bbwe" />
|
||||
<DeviceCapability Name="webcam" />
|
||||
<DeviceCapability Name="microphone" />
|
||||
<DeviceCapability Name="location" />
|
||||
</Capabilities>
|
||||
<Extensions>
|
||||
<desktop6:Extension Category="windows.customInstall">
|
||||
<desktop6:CustomInstall Folder="CustomInstall" desktop8:RunAsUser="true">
|
||||
<desktop6:RepairActions>
|
||||
<desktop6:RepairAction File="WSARepair.exe" Name="Repair" Arguments="repair" />
|
||||
</desktop6:RepairActions>
|
||||
<desktop6:UninstallActions>
|
||||
<desktop6:UninstallAction File="WSARepair.exe" Name="Uninstall" Arguments="uninstall" />
|
||||
</desktop6:UninstallActions>
|
||||
</desktop6:CustomInstall>
|
||||
</desktop6:Extension>
|
||||
<Extension Category="windows.activatableClass.proxyStub">
|
||||
<ProxyStub ClassId="76913B52-F9EB-4FAE-8DE7-24C20BDCF37B">
|
||||
<Path>WsaProxy\WsaProxy.dll</Path>
|
||||
<Interface Name="IWsaClient" InterfaceId="BC35C837-7915-45DE-AC1B-7A743AAD7188" />
|
||||
</ProxyStub>
|
||||
</Extension>
|
||||
<desktop2:Extension Category="windows.firewallRules">
|
||||
<desktop2:FirewallRules Executable="WsaClient\WsaClient.exe">
|
||||
<desktop2:Rule Direction="in" IPProtocol="TCP" LocalPortMin="58526" LocalPortMax="58526" Profile="private" />
|
||||
</desktop2:FirewallRules>
|
||||
</desktop2:Extension>
|
||||
<Extension Category="windows.activatableClass.inProcessServer">
|
||||
<InProcessServer>
|
||||
<Path>Microsoft.Web.WebView2.Core.dll</Path>
|
||||
<ActivatableClass ActivatableClassId="Microsoft.Web.WebView2.Core.CoreWebView2Controller" ThreadingModel="both" />
|
||||
<ActivatableClass ActivatableClassId="Microsoft.Web.WebView2.Core.CoreWebView2ControllerWindowReference" ThreadingModel="both" />
|
||||
<ActivatableClass ActivatableClassId="Microsoft.Web.WebView2.Core.CoreWebView2EnvironmentOptions" ThreadingModel="both" />
|
||||
<ActivatableClass ActivatableClassId="Microsoft.Web.WebView2.Core.CoreWebView2CompositionController" ThreadingModel="both" />
|
||||
<ActivatableClass ActivatableClassId="Microsoft.Web.WebView2.Core.CoreWebView2Environment" ThreadingModel="both" />
|
||||
</InProcessServer>
|
||||
</Extension>
|
||||
</Extensions>
|
||||
<build:Metadata>
|
||||
<build:Item Name="cl.exe" Version="19.42.34433.0" />
|
||||
<build:Item Name="CodeSharingProject" Value="248F659F-DAC5-46E8-AC09-60EC9FC95053" />
|
||||
<build:Item Name="VisualStudio" Version="17.0" />
|
||||
<build:Item Name="OperatingSystem" Version="10.0.20348.1 (WinBuild.160101.0800)" />
|
||||
<build:Item Name="Microsoft.Build.AppxPackage.dll" Version="17.12.40391.52126" />
|
||||
<build:Item Name="ProjectGUID" Value="a2be7e6a-792a-4530-8614-bc091a63d7bb" />
|
||||
<build:Item Name="OptimizingToolset" Value="None" />
|
||||
<build:Item Name="TargetRuntime" Value="Native" />
|
||||
<build:Item Name="Microsoft.Windows.UI.Xaml.Build.Tasks.dll" Version="0.0.0.0" />
|
||||
<build:Item Name="WindowsDesktop" Version="10.0.22000.0" />
|
||||
<build:Item Name="MakePri.exe" Version="10.0.22000.832 (WinBuild.160101.0800)" />
|
||||
<build:Item Name="Microsoft.Build.DesktopBridge.Tasks.dll" Version="17.12.40308.65294" />
|
||||
<build:Item Name="TargetFrameworkMoniker" Value=".NETFramework,Version=v4.5.1" />
|
||||
</build:Metadata>
|
||||
<mp:PhoneIdentity PhoneProductId="dd5d7f57-f9ab-4533-8aa3-8b7325addf8a" PhonePublisherId="d949d1ab-24a8-4463-9586-acee62f6de38" />
|
||||
</Package>
|
||||
@@ -0,0 +1,33 @@
|
||||
:: This file is part of MagiskOnWSALocal.
|
||||
::
|
||||
:: MagiskOnWSALocal is free software: you can redistribute it and/or modify
|
||||
:: it under the terms of the GNU Affero General Public License as
|
||||
:: published by the Free Software Foundation, either version 3 of the
|
||||
:: License, or (at your option) any later version.
|
||||
::
|
||||
:: MagiskOnWSALocal is distributed in the hope that it will be useful,
|
||||
:: but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
:: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
:: GNU Affero General Public License for more details.
|
||||
::
|
||||
:: You should have received a copy of the GNU Affero General Public License
|
||||
:: along with MagiskOnWSALocal. If not, see <https://www.gnu.org/licenses/>.
|
||||
::
|
||||
:: Copyright (C) 2023 LSPosed Contributors
|
||||
::
|
||||
|
||||
@echo off
|
||||
%~d0
|
||||
cd "%~dp0"
|
||||
if not exist Install.ps1 (
|
||||
echo "Install.ps1" is not found.
|
||||
echo Press any key to exit
|
||||
pause>nul
|
||||
exit 1
|
||||
) else (
|
||||
|
||||
|
||||
powershell.exe -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File ".\Install.ps1"
|
||||
|
||||
exit
|
||||
)
|
||||
Binary file not shown.
@@ -0,0 +1,101 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
# WSA_Installer_Download_onedir.spec
|
||||
# --onedir mode
|
||||
|
||||
from PyInstaller.utils.hooks import collect_submodules
|
||||
|
||||
import os
|
||||
# SPECPATH in PyInstaller 6.x is already the directory containing the .spec file
|
||||
# (from os.path.split in build_main.py:1140), so use it directly.
|
||||
_project_root = os.path.abspath(SPECPATH)
|
||||
_venv_site = os.path.join(_project_root, 'venv', 'Lib', 'site-packages')
|
||||
|
||||
# Resolve base Python DLLs from venv's pyvenv.cfg (portable, no hardcoded user path)
|
||||
_dlls_dir = os.path.join(_project_root, 'venv', 'DLLs')
|
||||
if not os.path.isdir(_dlls_dir):
|
||||
_pyvenv_cfg = os.path.join(_project_root, 'venv', 'pyvenv.cfg')
|
||||
if os.path.isfile(_pyvenv_cfg):
|
||||
with open(_pyvenv_cfg) as _f:
|
||||
for _line in _f:
|
||||
if _line.strip().startswith('home = '):
|
||||
_dlls_dir = os.path.join(_line.split('=', 1)[1].strip(), 'DLLs')
|
||||
break
|
||||
|
||||
a = Analysis(
|
||||
['run.py'],
|
||||
pathex=[_venv_site],
|
||||
binaries=[
|
||||
('widget_ui.pyd', '.'),
|
||||
('playstore_patcher_mem.pyd', '.'),
|
||||
('*.pyd', '.'),
|
||||
(os.path.join(_dlls_dir, 'sqlite3.dll'), '.'),
|
||||
(os.path.join(_dlls_dir, '_sqlite3.pyd'), '.'),
|
||||
],
|
||||
datas=[('assets', 'assets')],
|
||||
hiddenimports=[
|
||||
'requests',
|
||||
'flet',
|
||||
'pyautogui',
|
||||
'pyperclip',
|
||||
'pywinauto',
|
||||
'PyQt6',
|
||||
]
|
||||
+ collect_submodules('requests')
|
||||
+ collect_submodules('flet')
|
||||
+ collect_submodules('pyautogui')
|
||||
+ collect_submodules('pywinauto')
|
||||
+ collect_submodules('PyQt6')
|
||||
+ [
|
||||
'six',
|
||||
'flet_desktop', 'flet.utils',
|
||||
'email', 'email.message', 'email.mime',
|
||||
'http.client', 'widget_ui',
|
||||
'sqlite3', '_sqlite3',
|
||||
],
|
||||
hookspath=['hooks'],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[
|
||||
'tkinter', 'unittest',
|
||||
'PySide6', 'rich', 'pygments', 'markdown_it',
|
||||
'yaml', 'cryptography', 'cffi', 'pycparser',
|
||||
'dateutil', 'arrow', 'tzdata', 'zstandard',
|
||||
'pyarmor', 'nuitka', 'PyInstaller',
|
||||
'altgraph', 'pefile', 'pywin32_ctypes', 'Cython', 'maturin',
|
||||
'chardet', 'click', 'colorama', 'jinja2', 'markupsafe',
|
||||
'slugify', 'cookiecutter', 'qrcode', 'watchdog',
|
||||
'setuptools', 'pip', 'flet_cli',
|
||||
],
|
||||
noarchive=False,
|
||||
optimize=0,
|
||||
)
|
||||
|
||||
pyz = PYZ(a.pure)
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
[],
|
||||
exclude_binaries=True,
|
||||
name='WSA Installer',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
console=False,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
uac_admin=True,
|
||||
icon='assets\\icon.ico',
|
||||
)
|
||||
coll = COLLECT(
|
||||
exe,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
name='WSA Installer',
|
||||
)
|
||||
@@ -0,0 +1,309 @@
|
||||
; ============================================================
|
||||
; WSA_Installer_Setup.nsi — NSIS Installer Script
|
||||
; Modified for MR CYBER with Social Buttons & Branding
|
||||
; ============================================================
|
||||
|
||||
!include "MUI2.nsh"
|
||||
!include "LogicLib.nsh"
|
||||
!include "WinVer.nsh"
|
||||
!include "nsDialogs.nsh"
|
||||
!include "FileFunc.nsh"
|
||||
!include "StrFunc.nsh"
|
||||
${StrLoc}
|
||||
|
||||
; ── App Info ─────────────────────────────────────────────────
|
||||
!define APP_NAME "WSA Installer"
|
||||
!ifndef APP_VERSION
|
||||
!define APP_VERSION "1.0"
|
||||
!endif
|
||||
!define APP_PUBLISHER "MR CYBER"
|
||||
!define APP_EXE "WSA Installer.exe"
|
||||
!define APP_ICON "assets\icon.ico"
|
||||
!define SOURCE_DIR "dist\WSA Installer"
|
||||
!define INSTALL_DIR "$PROGRAMFILES64\WSA Installer"
|
||||
!define UNINSTALL_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\WSAInstaller"
|
||||
!define MUTEX_NAME "WSAInstallerSetupMutex"
|
||||
|
||||
; ── Social Links ─────────────────────────────────────────────
|
||||
!define YT_URL "https://www.youtube.com/@AT_Tech_Zone"
|
||||
!define COFFEE_URL "https://buymeacoffee.com/mrcyberdev"
|
||||
|
||||
; ── Output ───────────────────────────────────────────────────
|
||||
Name "${APP_NAME}"
|
||||
OutFile "dist\WSA_Installer_Setup.exe"
|
||||
InstallDir "${INSTALL_DIR}"
|
||||
InstallDirRegKey HKLM "${UNINSTALL_KEY}" "InstallLocation"
|
||||
BrandingText "WSA Installer | Developed by AT Tech Zone & MR CYBER"
|
||||
RequestExecutionLevel admin ; Must run as admin
|
||||
SetCompressor /SOLID lzma ; Best compression
|
||||
SilentInstall normal ; Enable /S silent mode for auto-update
|
||||
|
||||
; ── MUI Settings ─────────────────────────────────────────────
|
||||
!define MUI_ICON "${APP_ICON}"
|
||||
!define MUI_UNICON "${APP_ICON}"
|
||||
!define MUI_WELCOMEPAGE_TITLE "Welcome to ${APP_NAME} Setup"
|
||||
!define MUI_WELCOMEPAGE_TEXT "This professional installer will set up Windows Subsystem for Android (WSA) with Google Play Store support on your Windows 11 PC.$\n$\nFeatures:$\n - One-click installation of WSA$\n - Full Google Play Store integration$\n - Optimized for performance and stability$\n - Developed by AT Tech Zone & MR CYBER$\n$\nClick Next to start the installation process."
|
||||
|
||||
; --- Branding Images ---
|
||||
!define MUI_HEADERIMAGE
|
||||
!define MUI_HEADERIMAGE_BITMAP "assets\header.bmp"
|
||||
!define MUI_WELCOMEFINISHPAGE_BITMAP "assets\sidebar.bmp"
|
||||
!define MUI_UNWELCOMEFINISHPAGE_BITMAP "assets\sidebar.bmp"
|
||||
|
||||
; --- Light Mode (Default) ---
|
||||
; White background and standard text colors
|
||||
!define MUI_BGCOLOR "FFFFFF"
|
||||
!define MUI_TEXTCOLOR "000000"
|
||||
|
||||
!define MUI_FINISHPAGE_RUN "$INSTDIR\${APP_EXE}"
|
||||
!define MUI_FINISHPAGE_RUN_TEXT "Launch ${APP_NAME} now"
|
||||
!define MUI_ABORTWARNING
|
||||
|
||||
; ── MUI Pages ────────────────────────────────────────────────
|
||||
!insertmacro MUI_PAGE_WELCOME
|
||||
|
||||
; Maintenance / Repair Gate (Page 2)
|
||||
Page custom MaintenancePage
|
||||
|
||||
!insertmacro MUI_PAGE_DIRECTORY
|
||||
!insertmacro MUI_PAGE_INSTFILES
|
||||
|
||||
; Custom Socials Page (Page 3) - Moved to after installation
|
||||
Page custom SocialsPage
|
||||
!insertmacro MUI_PAGE_FINISH
|
||||
|
||||
!insertmacro MUI_UNPAGE_INSTFILES
|
||||
|
||||
!insertmacro MUI_LANGUAGE "English"
|
||||
|
||||
; ── Version Info ─────────────────────────────────────────────
|
||||
VIProductVersion "${APP_VERSION}.0.0"
|
||||
VIAddVersionKey "ProductName" "${APP_NAME}"
|
||||
VIAddVersionKey "ProductVersion" "${APP_VERSION}"
|
||||
VIAddVersionKey "CompanyName" "AT Tech Zone / MR CYBER"
|
||||
VIAddVersionKey "FileDescription" "WSA Installer Download Edition - Easy Android on Windows"
|
||||
VIAddVersionKey "FileVersion" "${APP_VERSION}"
|
||||
VIAddVersionKey "LegalCopyright" "© 2026 AT Tech Zone. All rights reserved."
|
||||
|
||||
; ── Maintenance Page ──────────────────────────────────────────
|
||||
Var ButtonRepair
|
||||
Var ButtonUninstall
|
||||
Var MaintenanceDialog
|
||||
Var RepairMode
|
||||
|
||||
Function MaintenancePage
|
||||
; Skip in silent/repair mode (from Windows Settings)
|
||||
${If} $RepairMode == 1
|
||||
Return
|
||||
${EndIf}
|
||||
|
||||
; Check if app is installed
|
||||
ReadRegStr $R0 HKLM "${UNINSTALL_KEY}" "UninstallString"
|
||||
${If} $R0 == ""
|
||||
Return ; Skip page if not installed
|
||||
${EndIf}
|
||||
|
||||
nsDialogs::Create 1018
|
||||
Pop $MaintenanceDialog
|
||||
${If} $MaintenanceDialog == "error"
|
||||
Abort
|
||||
${EndIf}
|
||||
|
||||
${NSD_CreateLabel} 0 0 100% 24u "${APP_NAME} is already installed.$\nSelect an action below to manage your installation:"
|
||||
Pop $0
|
||||
|
||||
${NSD_CreateButton} 25% 45u 50% 25u "Repair / Reinstall"
|
||||
Pop $ButtonRepair
|
||||
${NSD_OnClick} $ButtonRepair OnClickRepair
|
||||
|
||||
${NSD_CreateButton} 25% 75u 50% 25u "Uninstall"
|
||||
Pop $ButtonUninstall
|
||||
${NSD_OnClick} $ButtonUninstall OnClickUninstall
|
||||
|
||||
nsDialogs::Show
|
||||
FunctionEnd
|
||||
|
||||
Function OnClickRepair
|
||||
; Pre-fill install directory from existing installation
|
||||
ReadRegStr $INSTDIR HKLM "${UNINSTALL_KEY}" "InstallLocation"
|
||||
${If} $INSTDIR == ""
|
||||
StrCpy $INSTDIR "${INSTALL_DIR}"
|
||||
${EndIf}
|
||||
; Move to the next page (Directory)
|
||||
SendMessage $HWNDPARENT ${WM_COMMAND} 1 0
|
||||
FunctionEnd
|
||||
|
||||
Function OnClickUninstall
|
||||
; Perform silent uninstall and then exit
|
||||
ExecWait '"$INSTDIR\Uninstall.exe" /S _?=$INSTDIR'
|
||||
Quit
|
||||
FunctionEnd
|
||||
|
||||
; ── Custom Socials Page ──────────────────────────────────────
|
||||
Var Dialog
|
||||
Var Label
|
||||
Var ButtonYT
|
||||
Var ButtonCoffee
|
||||
|
||||
Function SocialsPage
|
||||
; Skip in silent/repair mode (from Windows Settings)
|
||||
${If} $RepairMode == 1
|
||||
Return
|
||||
${EndIf}
|
||||
|
||||
nsDialogs::Create 1018
|
||||
Pop $Dialog
|
||||
|
||||
${If} $Dialog == "error"
|
||||
Abort
|
||||
${EndIf}
|
||||
|
||||
${NSD_CreateLabel} 0 0 100% 24u "We hope you find this tool useful! $\nIf you'd like to support future development, consider subscribing or donating."
|
||||
Pop $Label
|
||||
|
||||
${NSD_CreateButton} 25% 45u 50% 25u "Subscribe on YouTube"
|
||||
Pop $ButtonYT
|
||||
${NSD_OnClick} $ButtonYT OnClickYT
|
||||
|
||||
${NSD_CreateButton} 25% 75u 50% 25u "Buy Me a Coffee"
|
||||
Pop $ButtonCoffee
|
||||
${NSD_OnClick} $ButtonCoffee OnClickCoffee
|
||||
|
||||
nsDialogs::Show
|
||||
FunctionEnd
|
||||
|
||||
Function OnClickYT
|
||||
ExecShell "open" "${YT_URL}"
|
||||
FunctionEnd
|
||||
|
||||
Function OnClickCoffee
|
||||
ExecShell "open" "${COFFEE_URL}"
|
||||
FunctionEnd
|
||||
|
||||
; ── Installer Functions ───────────────────────────────────────
|
||||
Function .onInit
|
||||
; Prevent multiple instances of setup
|
||||
System::Call 'kernel32::CreateMutex(p 0, i 1, t "${MUTEX_NAME}") p .r0 ?e'
|
||||
Pop $0
|
||||
${If} $0 != 0
|
||||
MessageBox MB_OK|MB_ICONEXCLAMATION "Setup is already running."
|
||||
Abort
|
||||
${EndIf}
|
||||
|
||||
${IfNot} ${AtLeastWin10}
|
||||
MessageBox MB_OK|MB_ICONSTOP "WSA Installer requires Windows 11 (22H2 or later).$\nSetup will now exit."
|
||||
Abort
|
||||
${EndIf}
|
||||
|
||||
; Detect /repair flag (from Windows Settings "Modify" / "Repair" buttons)
|
||||
${GetParameters} $R0
|
||||
${StrLoc} $R0 $R0 "/repair" ">"
|
||||
${If} $R0 != ""
|
||||
StrCpy $RepairMode 1
|
||||
SetSilent silent
|
||||
${EndIf}
|
||||
FunctionEnd
|
||||
|
||||
Function .onInstSuccess
|
||||
ExecShell "open" "${YT_URL}"
|
||||
FunctionEnd
|
||||
|
||||
; ── Main Install Section ─────────────────────────────────────
|
||||
Section "WSA Installer (Required)" SecMain
|
||||
SectionIn RO
|
||||
|
||||
; Detect repair vs fresh install
|
||||
${If} $RepairMode == 1
|
||||
DetailPrint "Repairing ${APP_NAME} installation..."
|
||||
${Else}
|
||||
DetailPrint "Installing ${APP_NAME}..."
|
||||
${EndIf}
|
||||
|
||||
; ── Kill old server before install ───────────────────────────
|
||||
DetailPrint "Stopping old WSA Background Service..."
|
||||
ExecWait 'sc stop WSABackgroundService'
|
||||
Sleep 2000
|
||||
ExecWait 'sc delete WSABackgroundService'
|
||||
DetailPrint "Closing any running WSA Installer instance..."
|
||||
ExecWait 'taskkill /F /IM "${APP_EXE}" /T'
|
||||
Sleep 1000
|
||||
|
||||
SetOutPath "$INSTDIR"
|
||||
SetOverwrite on
|
||||
|
||||
; Copy ALL files from PyInstaller output
|
||||
File /r "${SOURCE_DIR}\*.*"
|
||||
|
||||
; Save running installer inside install folder (for Windows Settings Repair)
|
||||
; NSIS extracts to temp dir, so original EXE is NOT locked — safe to copy
|
||||
CreateDirectory "$INSTDIR\out_asset"
|
||||
CopyFiles "$EXEPATH" "$INSTDIR\out_asset\WSA_Installer_Setup.exe"
|
||||
|
||||
; Registry keys
|
||||
WriteRegStr HKLM "${UNINSTALL_KEY}" "DisplayName" "${APP_NAME}"
|
||||
WriteRegStr HKLM "${UNINSTALL_KEY}" "DisplayVersion" "${APP_VERSION}"
|
||||
WriteRegStr HKLM "${UNINSTALL_KEY}" "Publisher" "${APP_PUBLISHER}"
|
||||
WriteRegStr HKLM "${UNINSTALL_KEY}" "InstallLocation" "$INSTDIR"
|
||||
WriteRegStr HKLM "${UNINSTALL_KEY}" "UninstallString" "$INSTDIR\Uninstall.exe"
|
||||
WriteRegStr HKLM "${UNINSTALL_KEY}" "QuietUninstallString" '"$INSTDIR\Uninstall.exe" /S'
|
||||
WriteRegStr HKLM "${UNINSTALL_KEY}" "DisplayIcon" "$INSTDIR\${APP_EXE}"
|
||||
WriteRegDWORD HKLM "${UNINSTALL_KEY}" "NoModify" 0
|
||||
WriteRegStr HKLM "${UNINSTALL_KEY}" "ModifyPath" '"$INSTDIR\out_asset\WSA_Installer_Setup.exe" /S /repair'
|
||||
WriteRegStr HKLM "${UNINSTALL_KEY}" "Repair" '"$INSTDIR\out_asset\WSA_Installer_Setup.exe" /S /repair'
|
||||
WriteRegDWORD HKLM "${UNINSTALL_KEY}" "EstimatedSize" 52000
|
||||
|
||||
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||
|
||||
; Shortcuts
|
||||
CreateShortCut "$DESKTOP\${APP_NAME}.lnk" "$INSTDIR\${APP_EXE}" "" "$INSTDIR\${APP_EXE}" 0
|
||||
CreateDirectory "$SMPROGRAMS\${APP_NAME}"
|
||||
CreateShortCut "$SMPROGRAMS\${APP_NAME}\${APP_NAME}.lnk" "$INSTDIR\${APP_EXE}" "" "$INSTDIR\${APP_EXE}" 0
|
||||
CreateShortCut "$SMPROGRAMS\${APP_NAME}\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
|
||||
|
||||
; Install and start Windows service
|
||||
DetailPrint "Installing Windows background service..."
|
||||
ExecWait 'sc create WSABackgroundService binPath= "$INSTDIR\${APP_EXE} --bg-service" start= auto'
|
||||
ExecWait 'sc failure WSABackgroundService reset=86400 actions=restart/10000/restart/15000/restart/30000'
|
||||
ExecWait 'sc description WSABackgroundService "Monitors Windows Subsystem for Android and manages Play Store patcher SDK. Auto-restarts on failure."'
|
||||
ExecWait 'sc start WSABackgroundService'
|
||||
DetailPrint "Service started."
|
||||
SectionEnd
|
||||
|
||||
; ── Uninstaller ───────────────────────────────────────────────
|
||||
Section "Uninstall"
|
||||
|
||||
; Stop and delete the Windows service FIRST (prevents SCM auto-restart)
|
||||
ExecWait 'sc stop WSABackgroundService'
|
||||
Sleep 2000
|
||||
ExecWait 'sc delete WSABackgroundService'
|
||||
Sleep 500
|
||||
|
||||
; Ensure the application is not running
|
||||
ExecWait 'taskkill /F /IM "${APP_EXE}" /T'
|
||||
|
||||
; Run Python uninstaller to clean WSA and related data
|
||||
; We capture the exit code in $0. 0 = Success, 1 = Cancel/Error
|
||||
ExecWait '"$INSTDIR\${APP_EXE}" --uninstall' $0
|
||||
|
||||
${If} $0 != 0
|
||||
MessageBox MB_OK|MB_ICONINFORMATION "Uninstallation was cancelled or interrupted. The installation directory will not be removed."
|
||||
Abort
|
||||
${EndIf}
|
||||
|
||||
; If we reach here, uninstallation was successful
|
||||
DetailPrint "WSA Uninstalled successfully. Removing remaining files..."
|
||||
|
||||
; Safety delay to release file handles
|
||||
Sleep 1000
|
||||
|
||||
RMDir /r "$INSTDIR"
|
||||
Delete "$DESKTOP\${APP_NAME}.lnk"
|
||||
Delete "$SMPROGRAMS\${APP_NAME}\${APP_NAME}.lnk"
|
||||
Delete "$SMPROGRAMS\${APP_NAME}\Uninstall.lnk"
|
||||
RMDir "$SMPROGRAMS\${APP_NAME}"
|
||||
DeleteRegKey HKLM "${UNINSTALL_KEY}"
|
||||
SectionEnd
|
||||
|
||||
Function un.onUninstSuccess
|
||||
ExecShell "open" "${YT_URL}"
|
||||
FunctionEnd
|
||||
+285
@@ -0,0 +1,285 @@
|
||||
@echo off
|
||||
chcp 65001 >nul 2>nul
|
||||
setlocal enabledelayedexpansion
|
||||
cd /d "%~dp0"
|
||||
|
||||
:: ═══════════════════════════════════════════════════════════════
|
||||
:: VERSION — Change this to update app.py, file_version_info,
|
||||
:: and NSIS installer version in one shot.
|
||||
:: ═══════════════════════════════════════════════════════════════
|
||||
SET VERSION=1.2
|
||||
:: -------- Step 0: Activate Virtual Environment --------
|
||||
if exist "venv\Scripts\activate.bat" (
|
||||
echo [+] Activating virtual environment...
|
||||
call venv\Scripts\activate.bat
|
||||
)
|
||||
|
||||
title WSA Installer Build Script
|
||||
|
||||
echo ============================================
|
||||
echo WSA Installer Build Script
|
||||
echo 1. Clean
|
||||
echo 2. Check dependencies
|
||||
echo 3. Nuitka module (app.py -^> app.pyd)
|
||||
echo 4. PyInstaller onedir
|
||||
echo 5. Patch Flet client (icon + metadata)
|
||||
echo 6. (optional) bundle.wsa
|
||||
echo 7. NSIS installer
|
||||
echo ============================================
|
||||
echo.
|
||||
|
||||
:: -------- Step 1: Clean --------
|
||||
echo [1/7] Cleaning previous build...
|
||||
if exist "dist" rmdir /s /q "dist"
|
||||
if exist "build" rmdir /s /q "build"
|
||||
if exist "app.pyd" del /f /q "app.pyd"
|
||||
if exist "app.pyi" del /f /q "app.pyi"
|
||||
for /d %%d in (*.build) do rmdir /s /q "%%d" 2>nul
|
||||
echo [+] Clean complete.
|
||||
echo.
|
||||
|
||||
:: -------- Step 2: Dependencies --------
|
||||
echo [2/7] Checking dependencies...
|
||||
venv\Scripts\python.exe -c "import requests, flet, pyautogui, pyperclip, pywinauto, PyQt6" >nul 2>nul
|
||||
if %errorlevel% neq 0 (
|
||||
echo [!] Missing dependencies — installing...
|
||||
venv\Scripts\python.exe -m pip install -r requirements.txt
|
||||
if !errorlevel! neq 0 (
|
||||
echo [!] PIP INSTALL FAILED.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo [+] Dependencies installed.
|
||||
) else (
|
||||
echo [+] All dependencies OK.
|
||||
)
|
||||
echo.
|
||||
|
||||
:: -------- Step 2.5: Update version across all files --------
|
||||
echo [2.5/7] Setting version to %VERSION%...
|
||||
|
||||
:: app.py: APP_ID suffix
|
||||
powershell -Command "$c = Get-Content 'app.py' -Raw; $c = $c -replace 'mrcyber\.wsainstaller\.download\.\d+\.\d+', 'mrcyber.wsainstaller.download.%VERSION%'; Set-Content 'app.py' -Value $c -Encoding UTF8 -NoNewline"
|
||||
|
||||
:: file_version_info.txt: string versions (1.0.0.0 -> X.Y.0.0) and tuple versions (1, 0, 0, 0)
|
||||
for /f "tokens=1,2 delims=." %%a in ("%VERSION%") do (
|
||||
set MAJOR=%%a
|
||||
set MINOR=%%b
|
||||
)
|
||||
powershell -Command "$c = Get-Content 'file_version_info.txt' -Raw; $c = $c -replace '\d+\.\d+\.\d+\.\d+', '%VERSION%.0.0'; $c = $c -replace '\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)', '(!MAJOR!, !MINOR!, 0, 0)'; Set-Content 'file_version_info.txt' -Value $c -Encoding UTF8 -NoNewline"
|
||||
|
||||
echo [+] Version updated to %VERSION%
|
||||
echo - app.py APP_ID = mrcyber.wsainstaller.download.%VERSION%
|
||||
echo - file_version_info FileVersion = %VERSION%.0.0
|
||||
echo - NSIS will use /DAPP_VERSION=%VERSION%
|
||||
echo.
|
||||
|
||||
:: -------- Step 3: Nuitka module (Protect source code) --------
|
||||
echo [3/7] Compiling app.pyd with Nuitka...
|
||||
|
||||
:: Backup app.py before compilation
|
||||
copy /y app.py app.py.backup >nul
|
||||
echo [+] Backup created: app.py.backup
|
||||
|
||||
:: Compile app.py directly (keeps PyInit_app export correct)
|
||||
python -m nuitka --module --remove-output app.py
|
||||
if %errorlevel% neq 0 (
|
||||
echo [!] NUITKA MODULE COMPILATION FAILED.
|
||||
copy /y app.py.backup app.py >nul
|
||||
del app.py.backup
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
:: Find the compiled .pyd (ABI-tagged: app.cp314-win_amd64.pyd)
|
||||
if exist app.*.pyd (
|
||||
for %%f in (app.*.pyd) do (
|
||||
ren "%%f" "app.pyd"
|
||||
goto :pyd_renamed
|
||||
)
|
||||
)
|
||||
echo [!] No .pyd file found after Nuitka compilation.
|
||||
copy /y app.py.backup app.py >nul
|
||||
del app.py.backup
|
||||
pause
|
||||
exit /b 1
|
||||
:pyd_renamed
|
||||
|
||||
:: Verify app.pyd exists
|
||||
if not exist "app.pyd" (
|
||||
echo [!] app.pyd not found after rename.
|
||||
copy /y app.py.backup app.py >nul
|
||||
del app.py.backup
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo [+] app.pyd created successfully (PyInit_app export intact).
|
||||
|
||||
:: Delete interface file (exposes function signatures)
|
||||
if exist "app.pyi" (
|
||||
del /f /q "app.pyi"
|
||||
echo [+] app.pyi deleted.
|
||||
)
|
||||
|
||||
:: Rename app.py to wsa.py — hides source from PyInstaller, forces it to bundle app.pyd
|
||||
ren app.py wsa.py
|
||||
echo [+] app.py renamed to wsa.py — source hidden from PyInstaller.
|
||||
|
||||
:: Backup no longer needed
|
||||
echo.
|
||||
|
||||
:: -------- Step 3.5: Compile WSARepair.py to WSARepair.exe --------
|
||||
echo [3.5/7] Compiling WSARepair.exe...
|
||||
|
||||
venv\Scripts\pyinstaller.exe --onefile --name WSARepair --distpath assets --workpath build_tmp --specpath build_tmp --noconfirm WSARepair.py
|
||||
if %errorlevel% neq 0 (
|
||||
echo [!] WSARepair.py compilation failed — skipping.
|
||||
) else (
|
||||
echo [+] WSARepair.exe compiled to assets\
|
||||
)
|
||||
|
||||
:: Clean up build artifacts
|
||||
if exist "build_tmp" rmdir /s /q "build_tmp"
|
||||
echo.
|
||||
|
||||
:: -------- Step 4: PyInstaller onedir --------
|
||||
echo [4/7] Running PyInstaller (onedir)...
|
||||
echo Spec: WSA_Installer_Download_onedir.spec
|
||||
echo.
|
||||
|
||||
venv\Scripts\pyinstaller.exe --noconfirm "WSA_Installer_Download_onedir.spec"
|
||||
if %errorlevel% neq 0 (
|
||||
echo [!] PyInstaller failed, trying python -m PyInstaller...
|
||||
venv\Scripts\python.exe -m PyInstaller "WSA_Installer_Download_onedir.spec"
|
||||
if %errorlevel% neq 0 (
|
||||
echo [!] PYINSTALLER FAILED.
|
||||
if exist "wsa.py" (
|
||||
ren wsa.py app.py
|
||||
)
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
)
|
||||
|
||||
echo [+] PyInstaller onedir build complete.
|
||||
echo.
|
||||
|
||||
:: -------- Restore app.py from wsa.py --------
|
||||
echo [4.5/7] Restoring app.py...
|
||||
if exist "wsa.py" (
|
||||
ren wsa.py app.py
|
||||
echo [+] app.py restored from wsa.py.
|
||||
)
|
||||
echo.
|
||||
|
||||
:: -------- Step 4.6 removed: clean_venv replaced by embedded Python in .pyd --------
|
||||
|
||||
:: -------- Step 5: Patch Flet client EXE --------
|
||||
echo [5/7] Patching Flet client EXE (icon + metadata)...
|
||||
|
||||
set FLET_EXE=dist\WSA Installer\_internal\flet_desktop\app\flet\flet.exe
|
||||
|
||||
if not exist "patch_flet" mkdir "patch_flet"
|
||||
|
||||
if exist "!FLET_EXE!" (
|
||||
:: Backup original
|
||||
copy /y "!FLET_EXE!" "patch_flet\flet.exe.bak" >nul
|
||||
echo [+] Backed up original flet.exe
|
||||
|
||||
venv\Scripts\python.exe patch_flet.py "!FLET_EXE!" "assets\icon.ico" "file_version_info.txt"
|
||||
if !errorlevel! equ 0 (
|
||||
echo [+] Flet client patched successfully
|
||||
copy /y "!FLET_EXE!" "patch_flet\flet.exe" >nul
|
||||
echo [+] Patched copy saved to patch_flet\flet.exe
|
||||
) else (
|
||||
echo [!] Patch FAILED — restoring backup...
|
||||
copy /y "patch_flet\flet.exe.bak" "!FLET_EXE!" >nul
|
||||
)
|
||||
|
||||
:: Also patch the cached Flet client for immediate effect
|
||||
for /d %%d in ("%USERPROFILE%\.flet\client\flet-desktop-full-*") do (
|
||||
if exist "%%d\flet.exe" (
|
||||
echo [~] Patching cached Flet client at %%d...
|
||||
copy /y "%%d\flet.exe" "%%d\flet.exe.bak" >nul 2>nul
|
||||
venv\Scripts\python.exe patch_flet.py "%%d\flet.exe" "assets\icon.ico" "file_version_info.txt"
|
||||
)
|
||||
)
|
||||
|
||||
:: Create patched flet-windows.zip so client machines extract patched version
|
||||
:: instead of downloading original from GitHub
|
||||
set FLET_APP_DIR=dist\WSA Installer\_internal\flet_desktop\app
|
||||
if exist "!FLET_APP_DIR!\flet" (
|
||||
echo [~] Creating patched flet-windows.zip...
|
||||
del /f /q "!FLET_APP_DIR!\flet-windows.zip" >nul 2>nul
|
||||
powershell -Command "Compress-Archive -Path '!FLET_APP_DIR!\flet' -DestinationPath '!FLET_APP_DIR!\flet-windows.zip' -Force"
|
||||
if !errorlevel! equ 0 (
|
||||
echo [+] Patched flet-windows.zip created for client cache extraction
|
||||
) else (
|
||||
echo [!] Failed to create flet-windows.zip
|
||||
)
|
||||
)
|
||||
) else (
|
||||
echo [~] flet.exe not found at !FLET_EXE! — skipping patch
|
||||
)
|
||||
echo.
|
||||
|
||||
:: -------- Step 6: Bundle prompt (bundle.wsa) --------
|
||||
echo [6/7] PyInstaller build done.
|
||||
echo Output folder: dist\WSA Installer\
|
||||
echo ========================================
|
||||
echo.
|
||||
echo Enter path to bundle.wsa file (or leave empty to skip):
|
||||
set /p BUNDLE_PATH="bundle.wsa path: "
|
||||
if not "!BUNDLE_PATH!"=="" (
|
||||
if exist "!BUNDLE_PATH!" (
|
||||
echo Copying bundle.wsa to dist\WSA Installer\out_asset\...
|
||||
if not exist "dist\WSA Installer\out_asset" mkdir "dist\WSA Installer\out_asset"
|
||||
copy /y "!BUNDLE_PATH!" "dist\WSA Installer\out_asset\bundle.wsa" >nul
|
||||
echo [+] bundle.wsa copied.
|
||||
) else (
|
||||
echo [~] File not found: !BUNDLE_PATH!
|
||||
)
|
||||
) else (
|
||||
echo Skipping bundle copy.
|
||||
)
|
||||
echo.
|
||||
|
||||
:: -------- Step 7: NSIS --------
|
||||
echo [7/7] Building NSIS installer...
|
||||
if not exist "WSA_Installer_Setup.nsi" (
|
||||
echo [!] WSA_Installer_Setup.nsi not found - skipping NSIS.
|
||||
goto :finish
|
||||
)
|
||||
|
||||
makensis /DAPP_VERSION=%VERSION% "WSA_Installer_Setup.nsi"
|
||||
if %errorlevel% equ 0 (
|
||||
echo [+] NSIS installer created: dist\WSA_Installer_Setup.exe
|
||||
) else (
|
||||
echo [~] makensis not in PATH, trying default path...
|
||||
if exist "C:\Program Files (x86)\NSIS\makensis.exe" (
|
||||
"C:\Program Files (x86)\NSIS\makensis.exe" /DAPP_VERSION=%VERSION% "WSA_Installer_Setup.nsi"
|
||||
if !errorlevel! equ 0 (
|
||||
echo [+] NSIS installer created: dist\WSA_Installer_Setup.exe
|
||||
) else (
|
||||
echo [!] NSIS failed. Install NSIS from https://nsis.sourceforge.io/
|
||||
)
|
||||
) else (
|
||||
echo [!] NSIS not found. Install NSIS from https://nsis.sourceforge.io/
|
||||
)
|
||||
)
|
||||
|
||||
:finish
|
||||
:: Safety: restore app.py if wsa.py still exists
|
||||
if exist "wsa.py" (
|
||||
echo [~] Restoring app.py from wsa.py...
|
||||
ren wsa.py app.py
|
||||
)
|
||||
echo.
|
||||
echo ========================================
|
||||
echo ALL DONE
|
||||
echo ========================================
|
||||
echo EXE + deps : dist\WSA Installer\
|
||||
echo Installer : dist\WSA_Installer_Setup.exe
|
||||
echo ========================================
|
||||
echo.
|
||||
pause
|
||||
@@ -0,0 +1,168 @@
|
||||
@echo off
|
||||
chcp 65001 >nul 2>nul
|
||||
setlocal enabledelayedexpansion
|
||||
cd /d "%~dp0"
|
||||
|
||||
:: -------- Step 0: Activate Virtual Environment --------
|
||||
if exist "venv\Scripts\activate.bat" (
|
||||
echo [+] Activating virtual environment...
|
||||
call venv\Scripts\activate.bat
|
||||
)
|
||||
|
||||
title WSA Installer Build Script (Nuitka Standalone)
|
||||
|
||||
set DIST_FINAL=dist\WSA Installer
|
||||
|
||||
echo ============================================
|
||||
echo WSA Installer Build Script
|
||||
echo 1. Clean + Check dependencies
|
||||
echo 2. Nuitka --standalone app
|
||||
echo 3. Restructure into _internal\ layout
|
||||
echo 4. Compile launcher (C# via PowerShell)
|
||||
echo 5. Copy assets + bundle.wsa
|
||||
echo 6. NSIS installer
|
||||
echo ============================================
|
||||
echo.
|
||||
|
||||
:: -------- Step 1: Clean + Dependencies --------
|
||||
echo [1/6] Cleaning previous build...
|
||||
if exist "dist" rmdir /s /q "dist"
|
||||
if exist "*.build" for /d %%d in (*.build) do rmdir /s /q "%%d" 2>nul
|
||||
if exist "app.build_src_backup" del /f /q "app.build_src_backup"
|
||||
echo [+] Clean complete.
|
||||
echo.
|
||||
|
||||
echo [1/6] Checking dependencies...
|
||||
venv\Scripts\python.exe -c "import py7zr, requests, flet, pyautogui, pyperclip, pywinauto, PyQt6" >nul 2>nul
|
||||
if %errorlevel% neq 0 (
|
||||
echo [!] Missing dependencies — installing...
|
||||
venv\Scripts\pip.exe install -r requirements.txt
|
||||
if !errorlevel! neq 0 (
|
||||
echo [!] PIP INSTALL FAILED.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo [+] Dependencies installed.
|
||||
) else (
|
||||
echo [+] All dependencies OK.
|
||||
)
|
||||
echo.
|
||||
|
||||
:: -------- Step 2: Nuitka --standalone --------
|
||||
echo [2/6] Compiling run.py to standalone EXE with Nuitka...
|
||||
echo This may take 30-60 minutes.
|
||||
echo.
|
||||
python -m nuitka --standalone ^
|
||||
--remove-output ^
|
||||
--windows-uac-admin ^
|
||||
--windows-icon-from-ico=assets\icon.ico ^
|
||||
--output-dir=tmp_nuitka ^
|
||||
run.py
|
||||
if %errorlevel% neq 0 (
|
||||
echo [!] NUITKA COMPILATION FAILED (errorlevel=%errorlevel%^)
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo [+] Nuitka build complete.
|
||||
echo.
|
||||
|
||||
:: -------- Step 3: Restructure into _internal\ layout --------
|
||||
echo [3/6] Restructuring output (PyInstaller-style _internal\)...
|
||||
|
||||
:: Create final directory structure
|
||||
if not exist "%DIST_FINAL%\_internal" mkdir "%DIST_FINAL%\_internal"
|
||||
|
||||
:: Rename run.exe -> WSA Installer.exe
|
||||
ren "tmp_nuitka\run.dist\run.exe" "WSA Installer.exe"
|
||||
|
||||
:: Move everything into _internal\ (including the real EXE)
|
||||
xcopy /e /i /y "tmp_nuitka\run.dist\*.*" "%DIST_FINAL%\_internal\" >nul
|
||||
|
||||
:: Clean up Nuitka temp
|
||||
rmdir /s /q "tmp_nuitka"
|
||||
|
||||
:: Copy assets into _internal\
|
||||
if exist "assets" (
|
||||
xcopy /e /i /y "assets" "%DIST_FINAL%\_internal\assets" >nul
|
||||
)
|
||||
|
||||
echo [+] Restructure done. _internal\ has the real EXE + all deps.
|
||||
echo.
|
||||
|
||||
:: -------- Step 4: Compile launcher (C# -> WSA Installer.exe) --------
|
||||
echo [4/6] Compiling launcher EXE (C# via PowerShell)...
|
||||
|
||||
if not exist "launcher.cs" (
|
||||
echo [!] launcher.cs not found — creating batch launcher instead...
|
||||
echo @start "" /D "%%~dp0_internal" "%%~dp0_internal\WSA Installer.exe" %%* > "%DIST_FINAL%\WSA Installer.cmd"
|
||||
echo [+] Created batch launcher: WSA Installer.cmd
|
||||
echo [~] NSIS and shortcuts will still work.
|
||||
) else (
|
||||
:: Compile launcher.cs to GUI EXE at root level
|
||||
powershell -Command "Add-Type -TypeDefinition (Get-Content 'launcher.cs' -Raw) -OutputAssembly '%DIST_FINAL%\WSA Installer.exe' -OutputType WindowsApplication" >nul 2>nul
|
||||
if %errorlevel% neq 0 (
|
||||
echo [!] LAUNCHER COMPILATION FAILED.
|
||||
echo Trying alternative: batch launcher...
|
||||
echo @start "" /D "%%~dp0_internal" "%%~dp0_internal\WSA Installer.exe" %%* > "%DIST_FINAL%\WSA Installer.cmd"
|
||||
echo [+] Created batch launcher instead: WSA Installer.cmd
|
||||
echo [~] NSIS and shortcuts will still work.
|
||||
)
|
||||
)
|
||||
echo.
|
||||
|
||||
:: -------- Step 5: Bundle prompt (bundle.wsa) --------
|
||||
echo [5/6] Build done.
|
||||
echo Output folder: %DIST_FINAL%
|
||||
echo Executable : %DIST_FINAL%\WSA Installer.exe
|
||||
echo.
|
||||
echo Enter path to bundle.wsa file (or leave empty to skip):
|
||||
set /p BUNDLE_PATH="bundle.wsa path: "
|
||||
if not "!BUNDLE_PATH!"=="" (
|
||||
if exist "!BUNDLE_PATH!" (
|
||||
echo Copying bundle.wsa to %DIST_FINAL%\out_asset\...
|
||||
if not exist "%DIST_FINAL%\out_asset" mkdir "%DIST_FINAL%\out_asset"
|
||||
copy /y "!BUNDLE_PATH!" "%DIST_FINAL%\out_asset\bundle.wsa" >nul
|
||||
echo [+] bundle.wsa copied.
|
||||
) else (
|
||||
echo [~] File not found: !BUNDLE_PATH!
|
||||
)
|
||||
) else (
|
||||
echo Skipping bundle copy.
|
||||
)
|
||||
echo.
|
||||
|
||||
:: -------- Step 6: NSIS --------
|
||||
echo [6/6] Building NSIS installer...
|
||||
if not exist "WSA_Installer_Setup.nsi" (
|
||||
echo [~] WSA_Installer_Setup.nsi not found - skipping NSIS.
|
||||
goto :finish
|
||||
)
|
||||
|
||||
makensis "WSA_Installer_Setup.nsi"
|
||||
if %errorlevel% equ 0 (
|
||||
echo [+] NSIS installer created: dist\WSA_Installer_Setup.exe
|
||||
) else (
|
||||
echo [~] makensis not in PATH, trying default path...
|
||||
if exist "C:\Program Files (x86)\NSIS\makensis.exe" (
|
||||
"C:\Program Files (x86)\NSIS\makensis.exe" "WSA_Installer_Setup.nsi"
|
||||
if !errorlevel! equ 0 (
|
||||
echo [+] NSIS installer created: dist\WSA_Installer_Setup.exe
|
||||
) else (
|
||||
echo [!] NSIS failed. Install NSIS from https://nsis.sourceforge.io/
|
||||
)
|
||||
) else (
|
||||
echo [!] NSIS not found. Install NSIS from https://nsis.sourceforge.io/
|
||||
)
|
||||
)
|
||||
|
||||
:finish
|
||||
echo.
|
||||
echo ========================================
|
||||
echo ALL DONE
|
||||
echo ========================================
|
||||
echo Launcher : %DIST_FINAL%\WSA Installer.exe
|
||||
echo App + deps : %DIST_FINAL%\_internal\
|
||||
echo Installer : dist\WSA_Installer_Setup.exe
|
||||
echo ========================================
|
||||
echo.
|
||||
pause
|
||||
@@ -0,0 +1,33 @@
|
||||
@echo off
|
||||
chcp 65001 >nul 2>nul
|
||||
setlocal
|
||||
cd /d "%~dp0"
|
||||
|
||||
:: -------- Create venv if missing --------
|
||||
if not exist "venv\Scripts\python.exe" (
|
||||
echo [+] Creating virtual environment...
|
||||
python -m venv venv
|
||||
if %errorlevel% neq 0 (
|
||||
echo [!] Failed to create venv. Make sure Python is installed and in PATH.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo [+] venv created.
|
||||
)
|
||||
|
||||
:: -------- Install requirements if flet is missing --------
|
||||
venv\Scripts\python.exe -c "import flet" >nul 2>nul
|
||||
if %errorlevel% neq 0 (
|
||||
echo [+] Installing dependencies...
|
||||
venv\Scripts\python.exe -m pip install -r requirements.txt
|
||||
if %errorlevel% neq 0 (
|
||||
echo [!] pip install failed.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
echo [+] Dependencies installed.
|
||||
)
|
||||
|
||||
:: -------- Run --------
|
||||
echo [+] Starting WSA Installer...
|
||||
venv\Scripts\python.exe run.py %*
|
||||
@@ -0,0 +1,36 @@
|
||||
# UTF-8
|
||||
#
|
||||
# For more details about fixed file info 'ffi' see:
|
||||
# https://learn.microsoft.com/en-us/windows/win32/api/verrsrc/ns-verrsrc-vs_fixedfileinfo
|
||||
VSVersionInfo(
|
||||
ffi=FixedFileInfo(
|
||||
filevers=(1, 2, 0, 0),
|
||||
prodvers=(1, 2, 0, 0),
|
||||
mask=0x3f,
|
||||
flags=0x0,
|
||||
OS=0x40004,
|
||||
fileType=0x1,
|
||||
subtype=0x0,
|
||||
date=(0, 0)
|
||||
),
|
||||
kids=[
|
||||
StringFileInfo(
|
||||
[
|
||||
StringTable(
|
||||
'040904B0',
|
||||
[
|
||||
StringStruct('CompanyName', 'MR CYBER'),
|
||||
StringStruct('FileDescription', 'WSA Installer Download Edition - Easy Android on Windows'),
|
||||
StringStruct('FileVersion', '1.2.0.0'),
|
||||
StringStruct('InternalName', 'WSA Installer'),
|
||||
StringStruct('LegalCopyright', '(C) 2026 AT Tech Zone. All rights reserved.'),
|
||||
StringStruct('OriginalFilename', 'WSA Installer.exe'),
|
||||
StringStruct('ProductName', 'WSA Installer'),
|
||||
StringStruct('ProductVersion', '1.2.0.0')
|
||||
]
|
||||
)
|
||||
]
|
||||
),
|
||||
VarFileInfo([VarStruct('Translation', [1033, 1200])])
|
||||
]
|
||||
)
|
||||
@@ -0,0 +1,19 @@
|
||||
requests
|
||||
flet
|
||||
pyautogui
|
||||
pyperclip
|
||||
pywinauto
|
||||
PyQt6
|
||||
PyQt6-WebEngine
|
||||
pycryptodomex
|
||||
pillow
|
||||
comtypes
|
||||
psutil
|
||||
brotli
|
||||
inflate64
|
||||
multivolumefile
|
||||
pybcj
|
||||
pyppmd
|
||||
texttable
|
||||
pywin32
|
||||
packaging
|
||||
@@ -0,0 +1,80 @@
|
||||
"""WSARepair.exe --- proxy for Windows Settings Repair/Uninstall buttons."""
|
||||
import sys, os, subprocess, time, winreg
|
||||
|
||||
def log(msg):
|
||||
print(f"""[WSARepair {time.strftime("%H:%M:%S")}] {msg}""", flush=True)
|
||||
|
||||
def _find_installer():
|
||||
log("Looking for WSA Installer...")
|
||||
|
||||
# Method 1: NSIS uninstaller registry InstallLocation + DisplayIcon
|
||||
nsus_key = r"Software\Microsoft\Windows\CurrentVersion\Uninstall\WSAInstaller"
|
||||
try:
|
||||
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, nsus_key, 0,
|
||||
winreg.KEY_READ | winreg.KEY_WOW64_64KEY)
|
||||
install_dir, _ = winreg.QueryValueEx(key, "InstallLocation")
|
||||
winreg.CloseKey(key)
|
||||
if install_dir:
|
||||
exe = os.path.join(install_dir, "WSA Installer.exe")
|
||||
log(f"NSIS InstallLocation: {exe}")
|
||||
if os.path.exists(exe):
|
||||
log(f"Found: {exe}"); return exe
|
||||
log("Not on disk, trying DisplayIcon...")
|
||||
except FileNotFoundError:
|
||||
log("NSIS uninstall key not found")
|
||||
except Exception as e:
|
||||
log(f"NSIS registry error: {e}")
|
||||
|
||||
# Method 2: NSIS DisplayIcon
|
||||
try:
|
||||
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, nsus_key, 0,
|
||||
winreg.KEY_READ | winreg.KEY_WOW64_64KEY)
|
||||
icon_path, _ = winreg.QueryValueEx(key, "DisplayIcon")
|
||||
winreg.CloseKey(key)
|
||||
log(f"NSIS DisplayIcon: {icon_path}")
|
||||
if icon_path and os.path.exists(icon_path):
|
||||
log(f"Found: {icon_path}"); return icon_path
|
||||
except Exception as e:
|
||||
log(f"DisplayIcon error: {e}")
|
||||
|
||||
# Method 3: HKLM\SOFTWARE\WSAInstaller\InstallerPath (custom, backup)
|
||||
try:
|
||||
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\WSAInstaller", 0,
|
||||
winreg.KEY_READ | winreg.KEY_WOW64_64KEY)
|
||||
exe_path, _ = winreg.QueryValueEx(key, "InstallerPath")
|
||||
winreg.CloseKey(key)
|
||||
log(f"Custom registry: {exe_path}")
|
||||
if exe_path and os.path.exists(exe_path):
|
||||
log(f"Found: {exe_path}"); return exe_path
|
||||
except Exception:
|
||||
log("Custom registry key not found")
|
||||
|
||||
# Method 4: Hardcoded Program Files path
|
||||
fixed = r"C:\Program Files\WSA Installer\WSA Installer.exe"
|
||||
log(f"Hardcoded: {fixed}")
|
||||
if os.path.exists(fixed):
|
||||
log(f"Found: {fixed}"); return fixed
|
||||
|
||||
log("ERROR: No installer found"); return ""
|
||||
|
||||
def main():
|
||||
log("Started")
|
||||
log(f"Args: {sys.argv}")
|
||||
a = sys.argv[1].lower() if len(sys.argv) > 1 else ""
|
||||
log(f"Action: {a}")
|
||||
if a not in ("repair", "uninstall"):
|
||||
log(f"Bad action: {a}"); return 1
|
||||
exe = _find_installer()
|
||||
if not exe or not os.path.exists(exe):
|
||||
log("Cannot proceed - not found"); return 1
|
||||
f = "--repair-wsa" if a == "repair" else "--uninstall"
|
||||
log(f"Launch: {exe} {f}")
|
||||
try:
|
||||
subprocess.Popen([exe, f], creationflags=subprocess.DETACHED_PROCESS,
|
||||
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
||||
log("Launched OK"); return 0
|
||||
except Exception as e:
|
||||
log(f"Launch failed: {e}"); return 1
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
+10996
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
class Launcher
|
||||
{
|
||||
static void Main()
|
||||
{
|
||||
var dir = Path.GetDirectoryName(typeof(Launcher).Assembly.Location);
|
||||
var exePath = Path.Combine(dir, "_internal", "WSA Installer.exe");
|
||||
|
||||
var proc = new Process();
|
||||
proc.StartInfo.FileName = exePath;
|
||||
proc.StartInfo.WorkingDirectory = Path.Combine(dir, "_internal");
|
||||
proc.Start();
|
||||
proc.WaitForExit();
|
||||
Environment.Exit(proc.ExitCode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
import os
|
||||
import sys
|
||||
import struct
|
||||
|
||||
import win32api
|
||||
from PyInstaller.utils.win32 import versioninfo as _vi
|
||||
|
||||
RT_ICON = 3
|
||||
RT_GROUP_ICON = 14
|
||||
LOAD_LIBRARY_AS_DATAFILE = 0x00000002
|
||||
|
||||
|
||||
def read_ico(ico_path):
|
||||
with open(ico_path, 'rb') as f:
|
||||
data = f.read()
|
||||
if data[:4] != b'\x00\x00\x01\x00':
|
||||
raise ValueError(f"Not a valid .ico file: {ico_path}")
|
||||
count = struct.unpack_from('<H', data, 4)[0]
|
||||
entries = []
|
||||
for i in range(count):
|
||||
w, h, colors, reserved, planes, bpp, size, offset = \
|
||||
struct.unpack_from('<BBBBHHII', data, 6 + i * 16)
|
||||
icon_data = data[offset:offset + size]
|
||||
entries.append({
|
||||
'w': w if w else 256,
|
||||
'h': h if h else 256,
|
||||
'colors': colors,
|
||||
'planes': planes,
|
||||
'bpp': bpp,
|
||||
'size': size,
|
||||
'data': icon_data,
|
||||
})
|
||||
return entries
|
||||
|
||||
|
||||
def build_group_icon(entries):
|
||||
group = struct.pack('<HHH', 0, 1, len(entries))
|
||||
for i, e in enumerate(entries):
|
||||
w = e['w'] if e['w'] < 256 else 0
|
||||
h = e['h'] if e['h'] < 256 else 0
|
||||
group += struct.pack(
|
||||
'<BBBBHHIH',
|
||||
w, h, e['colors'], 0, e['planes'], e['bpp'], e['size'], i + 1,
|
||||
)
|
||||
return group
|
||||
|
||||
|
||||
def discover_ids(exe_path):
|
||||
icon_ids = set()
|
||||
group_ids = set()
|
||||
try:
|
||||
h_mod = win32api.LoadLibraryEx(exe_path, 0, LOAD_LIBRARY_AS_DATAFILE)
|
||||
for res_type in (RT_ICON, RT_GROUP_ICON):
|
||||
try:
|
||||
names = win32api.EnumResourceNames(h_mod, res_type)
|
||||
for name in names:
|
||||
if res_type == RT_ICON:
|
||||
icon_ids.add(name)
|
||||
elif res_type == RT_GROUP_ICON:
|
||||
group_ids.add(name)
|
||||
except win32api.error:
|
||||
pass
|
||||
win32api.FreeLibrary(h_mod)
|
||||
except Exception as e:
|
||||
print(f" [~] Discovery error: {e}")
|
||||
return set(), set()
|
||||
return icon_ids, group_ids
|
||||
|
||||
|
||||
def patch_icons(exe_path, ico_path):
|
||||
entries = read_ico(ico_path)
|
||||
icon_ids, group_ids = discover_ids(exe_path)
|
||||
|
||||
if not group_ids:
|
||||
group_ids.add(1)
|
||||
|
||||
handle = win32api.BeginUpdateResource(exe_path, 0)
|
||||
|
||||
group_data = build_group_icon(entries)
|
||||
for gid in group_ids:
|
||||
win32api.UpdateResource(handle, RT_GROUP_ICON, gid, group_data)
|
||||
print(f" [+] Updated RT_GROUP_ICON ID={gid}")
|
||||
|
||||
for i, e in enumerate(entries):
|
||||
res_id = i + 1
|
||||
win32api.UpdateResource(handle, RT_ICON, res_id, e['data'])
|
||||
sz = f"{e['w']}x{e['h']}"
|
||||
print(f" [+] Updated RT_ICON ID={res_id} ({sz})")
|
||||
|
||||
win32api.EndUpdateResource(handle, 0)
|
||||
return True
|
||||
|
||||
|
||||
def patch_version_info(exe_path, version_info_path):
|
||||
info = _vi.load_version_info_from_text_file(version_info_path)
|
||||
_vi.write_version_info_to_executable(exe_path, info)
|
||||
print(f" [+] Updated version info from {version_info_path}")
|
||||
|
||||
|
||||
def patch_embedded_string(exe_path, old_str, new_str):
|
||||
with open(exe_path, 'rb') as f:
|
||||
data = bytearray(f.read())
|
||||
|
||||
old_utf16 = old_str.encode('utf-16-le')
|
||||
new_utf16 = new_str.encode('utf-16-le')
|
||||
|
||||
if len(new_utf16) > len(old_utf16):
|
||||
print(f" [~] New string ({len(new_utf16)} bytes) longer than old ({len(old_utf16)} bytes) — skipping")
|
||||
return False
|
||||
|
||||
idx = data.find(old_utf16)
|
||||
if idx < 0:
|
||||
print(f" [~] String '{old_str}' not found in binary — skipping")
|
||||
return False
|
||||
|
||||
padded = new_utf16 + b'\x00' * (len(old_utf16) - len(new_utf16))
|
||||
data[idx:idx + len(old_utf16)] = padded
|
||||
|
||||
with open(exe_path, 'wb') as f:
|
||||
f.write(data)
|
||||
|
||||
print(f" [+] Replaced '{old_str}' -> '{new_str}' at offset 0x{idx:X}")
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: patch_flet.py <exe_path> [icon.ico] [file_version_info.txt]")
|
||||
sys.exit(1)
|
||||
|
||||
exe_path = os.path.abspath(sys.argv[1])
|
||||
|
||||
if not os.path.exists(exe_path):
|
||||
print(f"Error: {exe_path} not found")
|
||||
sys.exit(1)
|
||||
|
||||
print(f" Patcher: {exe_path}")
|
||||
|
||||
ico_path = sys.argv[2] if len(sys.argv) > 2 else None
|
||||
ver_path = sys.argv[3] if len(sys.argv) > 3 else None
|
||||
|
||||
if ico_path:
|
||||
ico_path = os.path.abspath(ico_path)
|
||||
if os.path.exists(ico_path):
|
||||
patch_icons(exe_path, ico_path)
|
||||
else:
|
||||
print(f" [~] Icon not found: {ico_path}")
|
||||
|
||||
if ver_path:
|
||||
ver_path = os.path.abspath(ver_path)
|
||||
if os.path.exists(ver_path):
|
||||
patch_version_info(exe_path, ver_path)
|
||||
else:
|
||||
print(f" [~] Version info not found: {ver_path}")
|
||||
|
||||
patch_embedded_string(exe_path, 'Flet description', 'WSA Installer')
|
||||
|
||||
print(f" [+] Done: {exe_path}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,2 @@
|
||||
import app
|
||||
app.start()
|
||||
Reference in New Issue
Block a user