fix(windows): resolve tray-only startup freeze and installer failure (v2.3.5)
This commit is contained in:
parent
5cc5a68878
commit
9cc42fddd6
8 changed files with 245 additions and 101 deletions
8
.github/workflows/custom-build-release.yml
vendored
8
.github/workflows/custom-build-release.yml
vendored
|
|
@ -169,9 +169,6 @@ jobs:
|
|||
cp scripts/windows/install.bat "$stage/"
|
||||
cp output/simpmusic.crt "$stage/"
|
||||
cp "$msix" "$stage/"
|
||||
if [ -f output/simpmusic.appinstaller ]; then
|
||||
cp output/simpmusic.appinstaller "$stage/"
|
||||
fi
|
||||
( cd "$stage" && zip -q -j \
|
||||
"${GITHUB_WORKSPACE}/installers/SimpMusic-Windows-installer.zip" \
|
||||
* )
|
||||
|
|
@ -194,13 +191,10 @@ jobs:
|
|||
cp "$zsync" staging_desktop/SimpMusic-v${VERSION}-Linux-x86_64.AppImage.zsync
|
||||
fi
|
||||
|
||||
# Windows offline installer zip and MSIX / appinstaller
|
||||
# Windows offline installer zip and standalone MSIX
|
||||
if [ -f installers/SimpMusic-Windows-installer.zip ]; then
|
||||
cp installers/SimpMusic-Windows-installer.zip staging_desktop/SimpMusic-v${VERSION}-Windows-x64-installer.zip
|
||||
fi
|
||||
if [ -f output/simpmusic.appinstaller ]; then
|
||||
cp output/simpmusic.appinstaller staging_desktop/simpmusic.appinstaller
|
||||
fi
|
||||
msix=$(ls output/simpmusic-*.x64.msix 2>/dev/null | head -1)
|
||||
if [ -n "$msix" ]; then
|
||||
cp "$msix" staging_desktop/
|
||||
|
|
|
|||
|
|
@ -420,3 +420,6 @@
|
|||
# Preserve BuildKonfig and VersionManager for runtime version/hash checks
|
||||
-keep class com.maxrave.simpmusic.BuildKonfig { *; }
|
||||
-keep class com.maxrave.simpmusic.utils.VersionManager { *; }
|
||||
|
||||
# Preserve Windows Taskbar Thumbnail Controller and JNA Win32 callbacks
|
||||
-keep class com.maxrave.simpmusic.WindowsTaskbarThumbnailController** { *; }
|
||||
|
|
|
|||
|
|
@ -618,7 +618,19 @@ fun runDesktopApp(args: Array<String> = emptyArray()) {
|
|||
window.toFront()
|
||||
window.requestFocus()
|
||||
} else {
|
||||
window.toFront()
|
||||
javax.swing.SwingUtilities.invokeLater {
|
||||
isAwtIconified = false
|
||||
isOccluded = false
|
||||
if (!window.isVisible) {
|
||||
window.isVisible = true
|
||||
}
|
||||
if ((window.extendedState and Frame.ICONIFIED) != 0) {
|
||||
window.extendedState = window.extendedState and Frame.ICONIFIED.inv()
|
||||
}
|
||||
window.toFront()
|
||||
window.requestFocus()
|
||||
DesktopGpuManager.onRestored(window)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import com.sun.jna.Native
|
|||
import com.sun.jna.Pointer
|
||||
import com.sun.jna.Structure
|
||||
import com.sun.jna.WString
|
||||
import com.sun.jna.platform.win32.BaseTSD
|
||||
import com.sun.jna.platform.win32.Guid
|
||||
import com.sun.jna.platform.win32.Ole32
|
||||
import com.sun.jna.platform.win32.User32
|
||||
|
|
@ -25,6 +26,7 @@ import java.awt.Graphics2D
|
|||
import java.awt.RenderingHints
|
||||
import java.awt.Window
|
||||
import java.awt.image.BufferedImage
|
||||
import javax.swing.SwingUtilities
|
||||
|
||||
/**
|
||||
* Native Windows Taskbar Thumbnail Toolbar Controller (ITaskbarList3).
|
||||
|
|
@ -55,6 +57,15 @@ object WindowsTaskbarThumbnailController {
|
|||
private const val ID_PLAY_PAUSE = 102
|
||||
private const val ID_NEXT = 103
|
||||
|
||||
private val SUBCLASS_ID = BaseTSD.ULONG_PTR(9001L)
|
||||
|
||||
// Strong reference to prevent Garbage Collection of JNA native callbacks
|
||||
@Volatile
|
||||
private var activeSubclassProc: SubclassProcCallback? = null
|
||||
|
||||
@Volatile
|
||||
private var activeWndProc: WindowProcCallback? = null
|
||||
|
||||
@Structure.FieldOrder("dwMask", "iId", "iBitmap", "hIcon", "szTip", "dwFlags")
|
||||
open class THUMBBUTTON : Structure {
|
||||
@JvmField var dwMask: Int = 0
|
||||
|
|
@ -98,6 +109,34 @@ object WindowsTaskbarThumbnailController {
|
|||
}
|
||||
}
|
||||
|
||||
private interface CustomComctl32 : Library {
|
||||
fun SetWindowSubclass(
|
||||
hWnd: WinDef.HWND,
|
||||
pfnSubclass: SubclassProcCallback,
|
||||
uIdSubclass: BaseTSD.ULONG_PTR,
|
||||
dwRefData: BaseTSD.DWORD_PTR,
|
||||
): Boolean
|
||||
|
||||
fun RemoveWindowSubclass(
|
||||
hWnd: WinDef.HWND,
|
||||
pfnSubclass: SubclassProcCallback,
|
||||
uIdSubclass: BaseTSD.ULONG_PTR,
|
||||
): Boolean
|
||||
|
||||
fun DefSubclassProc(
|
||||
hWnd: WinDef.HWND,
|
||||
uMsg: Int,
|
||||
wParam: WinDef.WPARAM,
|
||||
lParam: WinDef.LPARAM,
|
||||
): WinDef.LRESULT
|
||||
|
||||
companion object {
|
||||
val INSTANCE: CustomComctl32 by lazy {
|
||||
Native.load("comctl32", CustomComctl32::class.java, W32APIOptions.UNICODE_OPTIONS)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private interface CustomGdi32 : Library {
|
||||
fun CreateBitmap(nWidth: Int, nHeight: Int, nPlanes: Int, nBitCount: Int, lpBits: IntArray): WinDef.HBITMAP?
|
||||
fun CreateBitmap(nWidth: Int, nHeight: Int, nPlanes: Int, nBitCount: Int, lpBits: ByteArray): WinDef.HBITMAP?
|
||||
|
|
@ -110,6 +149,17 @@ object WindowsTaskbarThumbnailController {
|
|||
}
|
||||
}
|
||||
|
||||
private interface SubclassProcCallback : Callback {
|
||||
fun callback(
|
||||
hWnd: WinDef.HWND,
|
||||
uMsg: Int,
|
||||
wParam: WinDef.WPARAM,
|
||||
lParam: WinDef.LPARAM,
|
||||
uIdSubclass: BaseTSD.ULONG_PTR,
|
||||
dwRefData: BaseTSD.DWORD_PTR,
|
||||
): WinDef.LRESULT
|
||||
}
|
||||
|
||||
private interface WindowProcCallback : Callback {
|
||||
fun callback(
|
||||
hwnd: WinDef.HWND,
|
||||
|
|
@ -212,15 +262,24 @@ object WindowsTaskbarThumbnailController {
|
|||
buttons[2].setTooltip("Next")
|
||||
buttons[2].dwFlags = THBF_ENABLED
|
||||
|
||||
fun addButtons() {
|
||||
var buttonsAdded = false
|
||||
|
||||
fun addButtonsSafe() {
|
||||
if (buttonsAdded) return
|
||||
buttons[0].write()
|
||||
buttons[1].write()
|
||||
buttons[2].write()
|
||||
val res = taskbar.thumbBarAddButtons(hwnd, 3, buttons[0].pointer)
|
||||
Logger.d(TAG, "thumbBarAddButtons result: $res")
|
||||
if (res == 0) {
|
||||
buttonsAdded = true
|
||||
}
|
||||
}
|
||||
|
||||
fun updateButtons(isPlaying: Boolean, hasPrev: Boolean, hasNext: Boolean) {
|
||||
fun updateButtonsSafe(isPlaying: Boolean, hasPrev: Boolean, hasNext: Boolean) {
|
||||
if (!buttonsAdded) {
|
||||
addButtonsSafe()
|
||||
}
|
||||
buttons[0].dwFlags = if (hasPrev) THBF_ENABLED else THBF_DISABLED
|
||||
buttons[1].hIcon = if (isPlaying) pauseIcon else playIcon
|
||||
buttons[1].setTooltip(if (isPlaying) "Pause" else "Play")
|
||||
|
|
@ -233,58 +292,114 @@ object WindowsTaskbarThumbnailController {
|
|||
taskbar.thumbBarUpdateButtons(hwnd, 3, buttons[0].pointer)
|
||||
}
|
||||
|
||||
addButtons()
|
||||
|
||||
val taskbarCreatedMsg = CustomUser32.INSTANCE.RegisterWindowMessageW(WString("TaskbarButtonCreated"))
|
||||
|
||||
var oldWndProc: Pointer? = null
|
||||
val wndProc = object : WindowProcCallback {
|
||||
fun handleCommandMessage(wParam: WinDef.WPARAM): Boolean {
|
||||
val hiWord = (wParam.toLong() shr 16) and 0xFFFF
|
||||
if (hiWord == THBN_CLICKED.toLong()) {
|
||||
val id = (wParam.toLong() and 0xFFFF).toInt()
|
||||
when (id) {
|
||||
ID_PREV -> coroutineScope.launch { mediaPlayerHandler.onPlayerEvent(PlayerEvent.Previous) }
|
||||
ID_PLAY_PAUSE -> coroutineScope.launch { mediaPlayerHandler.onPlayerEvent(PlayerEvent.PlayPause) }
|
||||
ID_NEXT -> coroutineScope.launch { mediaPlayerHandler.onPlayerEvent(PlayerEvent.Next) }
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Attempt safe window subclassing via comctl32 first
|
||||
val subclassProc = object : SubclassProcCallback {
|
||||
override fun callback(
|
||||
hwnd: WinDef.HWND,
|
||||
hWnd: WinDef.HWND,
|
||||
uMsg: Int,
|
||||
wParam: WinDef.WPARAM,
|
||||
lParam: WinDef.LPARAM,
|
||||
uIdSubclass: BaseTSD.ULONG_PTR,
|
||||
dwRefData: BaseTSD.DWORD_PTR,
|
||||
): WinDef.LRESULT {
|
||||
if (uMsg == taskbarCreatedMsg) {
|
||||
addButtons()
|
||||
} else if (uMsg == WM_COMMAND) {
|
||||
val hiWord = (wParam.toLong() shr 16) and 0xFFFF
|
||||
if (hiWord == THBN_CLICKED.toLong()) {
|
||||
val id = (wParam.toLong() and 0xFFFF).toInt()
|
||||
when (id) {
|
||||
ID_PREV -> coroutineScope.launch { mediaPlayerHandler.onPlayerEvent(PlayerEvent.Previous) }
|
||||
ID_PLAY_PAUSE -> coroutineScope.launch { mediaPlayerHandler.onPlayerEvent(PlayerEvent.PlayPause) }
|
||||
ID_NEXT -> coroutineScope.launch { mediaPlayerHandler.onPlayerEvent(PlayerEvent.Next) }
|
||||
}
|
||||
return WinDef.LRESULT(0)
|
||||
}
|
||||
SwingUtilities.invokeLater { addButtonsSafe() }
|
||||
return CustomComctl32.INSTANCE.DefSubclassProc(hWnd, uMsg, wParam, lParam)
|
||||
}
|
||||
val prev = oldWndProc
|
||||
return if (prev != null) {
|
||||
CustomUser32.INSTANCE.CallWindowProc(prev, hwnd, uMsg, wParam, lParam)
|
||||
} else {
|
||||
User32.INSTANCE.DefWindowProc(hwnd, uMsg, wParam, lParam)
|
||||
if (uMsg == WM_COMMAND && handleCommandMessage(wParam)) {
|
||||
return WinDef.LRESULT(0)
|
||||
}
|
||||
return CustomComctl32.INSTANCE.DefSubclassProc(hWnd, uMsg, wParam, lParam)
|
||||
}
|
||||
}
|
||||
|
||||
oldWndProc = CustomUser32.INSTANCE.SetWindowLongPtr(hwnd, GWLP_WNDPROC, wndProc)
|
||||
// Keep strong reference to prevent GC
|
||||
activeSubclassProc = subclassProc
|
||||
val usedSubclass = runCatching {
|
||||
CustomComctl32.INSTANCE.SetWindowSubclass(hwnd, subclassProc, SUBCLASS_ID, BaseTSD.DWORD_PTR(0L))
|
||||
}.getOrDefault(false)
|
||||
|
||||
var oldWndProc: Pointer? = null
|
||||
var fallbackWndProc: WindowProcCallback? = null
|
||||
|
||||
if (!usedSubclass) {
|
||||
Logger.w(TAG, "comctl32 SetWindowSubclass failed, falling back to SetWindowLongPtr")
|
||||
fallbackWndProc = object : WindowProcCallback {
|
||||
override fun callback(
|
||||
hwnd: WinDef.HWND,
|
||||
uMsg: Int,
|
||||
wParam: WinDef.WPARAM,
|
||||
lParam: WinDef.LPARAM,
|
||||
): WinDef.LRESULT {
|
||||
if (uMsg == taskbarCreatedMsg) {
|
||||
SwingUtilities.invokeLater { addButtonsSafe() }
|
||||
} else if (uMsg == WM_COMMAND && handleCommandMessage(wParam)) {
|
||||
return WinDef.LRESULT(0)
|
||||
}
|
||||
val prev = oldWndProc
|
||||
return if (prev != null) {
|
||||
CustomUser32.INSTANCE.CallWindowProc(prev, hwnd, uMsg, wParam, lParam)
|
||||
} else {
|
||||
User32.INSTANCE.DefWindowProc(hwnd, uMsg, wParam, lParam)
|
||||
}
|
||||
}
|
||||
}
|
||||
activeWndProc = fallbackWndProc
|
||||
oldWndProc = CustomUser32.INSTANCE.SetWindowLongPtr(hwnd, GWLP_WNDPROC, fallbackWndProc)
|
||||
}
|
||||
|
||||
// If the window is already showing when attach() is invoked, initialize buttons on EDT
|
||||
SwingUtilities.invokeLater {
|
||||
if (window.isShowing) {
|
||||
addButtonsSafe()
|
||||
}
|
||||
}
|
||||
|
||||
val stateJob = coroutineScope.launch {
|
||||
mediaPlayerHandler.controlState.collectLatest { state ->
|
||||
updateButtons(
|
||||
isPlaying = state.isPlaying,
|
||||
hasPrev = state.isPreviousAvailable,
|
||||
hasNext = state.isNextAvailable,
|
||||
)
|
||||
SwingUtilities.invokeLater {
|
||||
updateButtonsSafe(
|
||||
isPlaying = state.isPlaying,
|
||||
hasPrev = state.isPreviousAvailable,
|
||||
hasNext = state.isNextAvailable,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val cleanup: () -> Unit = {
|
||||
stateJob.cancel()
|
||||
val prev = oldWndProc
|
||||
if (prev != null) {
|
||||
CustomUser32.INSTANCE.SetWindowLongPtr(hwnd, GWLP_WNDPROC, prev)
|
||||
if (usedSubclass) {
|
||||
runCatching {
|
||||
CustomComctl32.INSTANCE.RemoveWindowSubclass(hwnd, subclassProc, SUBCLASS_ID)
|
||||
}
|
||||
if (activeSubclassProc === subclassProc) {
|
||||
activeSubclassProc = null
|
||||
}
|
||||
} else {
|
||||
val prev = oldWndProc
|
||||
if (prev != null) {
|
||||
CustomUser32.INSTANCE.SetWindowLongPtr(hwnd, GWLP_WNDPROC, prev)
|
||||
}
|
||||
if (activeWndProc === fallbackWndProc) {
|
||||
activeWndProc = null
|
||||
}
|
||||
}
|
||||
prevIcon?.let { CustomUser32.INSTANCE.DestroyIcon(it) }
|
||||
playIcon?.let { CustomUser32.INSTANCE.DestroyIcon(it) }
|
||||
|
|
|
|||
|
|
@ -278,7 +278,7 @@ actual object PlatformAppUpdater {
|
|||
val msix = downloadedMsixPath
|
||||
try {
|
||||
if (msix != null && File(msix).exists()) {
|
||||
val psScript = "Start-Sleep -Milliseconds 800; Add-AppxPackage -Path '$msix' -ForceApplicationShutdown -ForceUpdateFromAnyVersion; start 'shell:appsFolder\\Simpmusic_ejp2bhxmz1qq6!Simpmusic'"
|
||||
val psScript = "Start-Sleep -Milliseconds 800; try { Add-AppxPackage -Path '$msix' -ForceApplicationShutdown -ForceUpdateFromAnyVersion -ErrorAction Stop } catch { Get-AppxPackage -Name '*Simpmusic*' -ErrorAction SilentlyContinue | Remove-AppxPackage -ErrorAction SilentlyContinue; Add-AppxPackage -Path '$msix' -ForceApplicationShutdown -ErrorAction SilentlyContinue }; start 'shell:appsFolder\\Simpmusic_ejp2bhxmz1qq6!Simpmusic'"
|
||||
ProcessBuilder("powershell", "-NoProfile", "-WindowStyle", "Hidden", "-Command", psScript).start()
|
||||
} else {
|
||||
val psScript = "Start-Sleep -Milliseconds 800; start 'shell:appsFolder\\Simpmusic_ejp2bhxmz1qq6!Simpmusic'"
|
||||
|
|
|
|||
|
|
@ -56,9 +56,10 @@ app {
|
|||
// Release for this repo (Conveyor 22.0+ behaviour, per the March 2024
|
||||
// blog update).
|
||||
//
|
||||
// updates = background → Conveyor wires the background .appinstaller
|
||||
// update check for Windows so that Windows checks for updates silently.
|
||||
updates = background
|
||||
// updates = none → Conveyor does not wire Sparkle (Mac) or the
|
||||
// background .appinstaller update check (Windows). Releases are
|
||||
// handled by SimpMusic's native in-app updater (AppUpdater.jvm.kt).
|
||||
updates = none
|
||||
|
||||
site {
|
||||
consistency-checks = warn
|
||||
|
|
@ -165,14 +166,6 @@ app {
|
|||
windows {
|
||||
start-menu.group = "SimpMusic"
|
||||
|
||||
manifests.msix.app-installer {
|
||||
hours-between-update-checks = 4
|
||||
show-prompt = false
|
||||
update-blocks-activation = false
|
||||
automatic-background-task = true
|
||||
check-on-launch = true
|
||||
}
|
||||
|
||||
// DEBUG ONLY — remove before shipping a release.
|
||||
// A Windows GUI binary has no console attached, so everything the app writes to
|
||||
// stdout/stderr is discarded and a startup failure leaves nothing to look at.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
[versions]
|
||||
# App version
|
||||
version-name = "2.3.4"
|
||||
version-code = "64"
|
||||
version-name = "2.3.5"
|
||||
version-code = "65"
|
||||
|
||||
android = "9.4.1"
|
||||
kotlin = "2.4.20"
|
||||
|
|
|
|||
|
|
@ -1,86 +1,113 @@
|
|||
@echo off
|
||||
REM SimpMusic offline installer for Windows.
|
||||
REM SimpMusic offline installer for Windows (x64 / ARM64 via Prism emulation).
|
||||
REM Double-click this file. UAC will prompt for admin (needed for cert + sideload).
|
||||
REM
|
||||
REM Bundle requirement (same folder as this .bat):
|
||||
REM - simpmusic.crt
|
||||
REM - simpmusic-<version>.msix (any .msix matching simpmusic-*.msix)
|
||||
REM
|
||||
REM Only x64 MSIX is shipped — Windows 11 ARM64 hosts run it under Prism
|
||||
REM emulation. ARM64 native build is blocked upstream by a missing
|
||||
REM androidx.sqlite-bundled windows-arm64 native binary.
|
||||
REM - simpmusic-<version>.x64.msix
|
||||
|
||||
setlocal EnableExtensions
|
||||
cd /d "%~dp0"
|
||||
set "SIMPMUSIC_DIR=%~dp0"
|
||||
|
||||
REM --- 0. Pre-flight check (ensure files were extracted from ZIP) --------------
|
||||
if not exist "%SIMPMUSIC_DIR%simpmusic.crt" (
|
||||
echo.
|
||||
echo [ERRO / ERROR]
|
||||
echo Os arquivos nao foram encontrados nesta pasta!
|
||||
echo Certifique-se de EXTRAIR o conteudo do arquivo ZIP antes de executar o instalador.
|
||||
echo (Nao execute o arquivo diretamente de dentro do ZIP compactado).
|
||||
echo.
|
||||
echo Files not found next to install.bat.
|
||||
echo Please EXTRACT all files from the ZIP before running install.bat.
|
||||
echo.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
set "SIMPMUSIC_MSIX="
|
||||
for %%f in ("%SIMPMUSIC_DIR%simpmusic-*.msix") do set "SIMPMUSIC_MSIX=%%f"
|
||||
|
||||
if not defined SIMPMUSIC_MSIX (
|
||||
echo.
|
||||
echo [ERRO / ERROR]
|
||||
echo Nenhum pacote simpmusic-*.msix foi encontrado nesta pasta.
|
||||
echo Extraia todos os arquivos do instalador ZIP para uma pasta comum e tente novamente.
|
||||
echo.
|
||||
echo No simpmusic-*.msix package found in this folder.
|
||||
echo.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM --- 1. Self-elevate to admin -----------------------------------------------
|
||||
net session >nul 2>&1
|
||||
if %errorlevel% neq 0 (
|
||||
echo Requesting admin elevation...
|
||||
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||
echo Solicitando elevacao de administrador / Requesting admin elevation...
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -Command "Start-Process -FilePath '%comspec%' -ArgumentList '/c `\"`\"%~f0`\"`\"' -Verb RunAs"
|
||||
exit /b
|
||||
)
|
||||
|
||||
echo.
|
||||
echo === SimpMusic offline installer ===
|
||||
echo ===========================================
|
||||
echo SimpMusic Offline Installer
|
||||
echo ===========================================
|
||||
echo.
|
||||
|
||||
REM --- 2. Install cert to Trusted People (idempotent via certutil) -----------
|
||||
if not exist "%~dp0simpmusic.crt" (
|
||||
echo [ERROR] simpmusic.crt not found next to install.bat
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo [1/3] Importing simpmusic.crt to LocalMachine\TrustedPeople ...
|
||||
certutil -addstore -f "TrustedPeople" "%~dp0simpmusic.crt"
|
||||
echo [1/3] Importando certificado simpmusic.crt para TrustedPeople...
|
||||
certutil -addstore -f "TrustedPeople" "%SIMPMUSIC_DIR%simpmusic.crt"
|
||||
if %errorlevel% neq 0 (
|
||||
echo [ERROR] Certificate import failed.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM --- 3. Find the bundled MSIX ----------------------------------------------
|
||||
set "MSIX="
|
||||
for %%f in ("%~dp0simpmusic-*.msix") do set "MSIX=%%f"
|
||||
|
||||
if not defined MSIX (
|
||||
echo [ERROR] No simpmusic-*.msix found in this folder.
|
||||
echo.
|
||||
echo [ERRO] Falha ao importar o certificado de assinatura / Certificate import failed.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM --- 3. Close lingering processes and install MSIX -------------------------
|
||||
echo.
|
||||
echo [2/3] Installing/updating SimpMusic...
|
||||
set "APPINSTALLER=%~dp0simpmusic.appinstaller"
|
||||
if exist "%APPINSTALLER%" (
|
||||
echo Registering with online update support ^(AppInstaller^)...
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -Command ^
|
||||
"try { Add-AppxPackage -AppInstallerFile '%APPINSTALLER%' -ForceApplicationShutdown -ForceUpdateFromAnyVersion -ErrorAction Stop; exit 0 } catch { Write-Host 'AppInstaller registration failed, falling back to direct MSIX...'; try { Add-AppxPackage -Path '%MSIX%' -ForceApplicationShutdown -ForceUpdateFromAnyVersion -ErrorAction Stop; exit 0 } catch { Write-Host $_; exit 1 } }"
|
||||
) else (
|
||||
echo Installing MSIX package: "%MSIX%" ...
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -Command ^
|
||||
"try { Add-AppxPackage -Path '%MSIX%' -ForceApplicationShutdown -ForceUpdateFromAnyVersion -ErrorAction Stop; exit 0 } catch { Write-Host 'In-place update failed; removing existing SimpMusic and reinstalling...'; Get-AppxPackage -Name 'Simpmusic' | Remove-AppxPackage -ErrorAction SilentlyContinue; try { Add-AppxPackage -Path '%MSIX%' -ForceApplicationShutdown -ErrorAction Stop; exit 0 } catch { Write-Host $_; exit 1 } }"
|
||||
)
|
||||
echo [2/3] Instalando/atualizando o SimpMusic...
|
||||
set "SIMPMUSIC_CRT=%SIMPMUSIC_DIR%simpmusic.crt"
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -Command ^
|
||||
"$msix = $env:SIMPMUSIC_MSIX; " ^
|
||||
"Get-Process -Name 'SimpMusic','updatecheck' -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue; " ^
|
||||
"try { " ^
|
||||
" Add-AppxPackage -Path $msix -ForceApplicationShutdown -ForceUpdateFromAnyVersion -ErrorAction Stop; " ^
|
||||
" Write-Host 'Pacote MSIX instalado/atualizado com sucesso.'; " ^
|
||||
" exit 0 " ^
|
||||
"} catch { " ^
|
||||
" Write-Host 'Atualizacao direta falhou. Removendo versao anterior e reinstalando...'; " ^
|
||||
" Get-AppxPackage -Name '*Simpmusic*' -ErrorAction SilentlyContinue | Remove-AppxPackage -ErrorAction SilentlyContinue; " ^
|
||||
" try { " ^
|
||||
" Add-AppxPackage -Path $msix -ForceApplicationShutdown -ErrorAction Stop; " ^
|
||||
" Write-Host 'Instalacao limpa concluida com sucesso.'; " ^
|
||||
" exit 0 " ^
|
||||
" } catch { " ^
|
||||
" Write-Host $_; " ^
|
||||
" exit 1 " ^
|
||||
" } " ^
|
||||
"}"
|
||||
|
||||
if %errorlevel% neq 0 (
|
||||
echo.
|
||||
echo [ERROR] Add-AppxPackage failed. Common fixes:
|
||||
echo - Enable 'Install apps from any source, including loose files'
|
||||
echo ^(Settings -^> Privacy ^& security -^> For developers^)
|
||||
echo - Restart Windows and run install.bat again
|
||||
echo [ERRO] Falha ao instalar o aplicativo via Add-AppxPackage.
|
||||
echo Sugestoes para resolver:
|
||||
echo 1. Ative o 'Modo de Desenvolvedor' no Windows:
|
||||
echo Configuracoes -^> Privacidade e Seguranca -^> Para desenvolvedores -^> Modo de Desenvolvedor
|
||||
echo 2. Verifique se o Windows Update esta ativo
|
||||
echo 3. Reinicie o computador e execute install.bat novamente
|
||||
echo.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
REM --- 4. Launch app ---------------------------------------------------------
|
||||
echo.
|
||||
echo [3/3] Launching SimpMusic ...
|
||||
echo [3/3] Iniciando o SimpMusic / Launching SimpMusic ...
|
||||
start "" "shell:appsFolder\Simpmusic_ejp2bhxmz1qq6!Simpmusic"
|
||||
|
||||
echo.
|
||||
echo SimpMusic installed successfully.
|
||||
echo To uninstall: Settings -^> Apps -^> Installed apps -^> SimpMusic -^> Uninstall
|
||||
echo SimpMusic instalado com sucesso! / SimpMusic installed successfully.
|
||||
echo.
|
||||
pause
|
||||
endlocal
|
||||
|
|
|
|||
Loading…
Reference in a new issue