diff --git a/src/main/core/permissions.ts b/src/main/core/permissions.ts index 0a73882..3bbed91 100644 --- a/src/main/core/permissions.ts +++ b/src/main/core/permissions.ts @@ -256,8 +256,19 @@ export async function restartAsAdmin(forTun: boolean = true): Promise { throw new Error('This function is only available on Windows') } + // 先停止 Core,避免新旧进程冲突 + try { + const { stopCore } = await import('./manager') + managerLogger.info('Stopping core before admin restart...') + await stopCore(true) + // 等待 Core 完全停止 + await new Promise((resolve) => setTimeout(resolve, 500)) + } catch (error) { + managerLogger.warn('Failed to stop core before restart:', error) + } + const exePath = process.execPath - const args = process.argv.slice(1) + const args = process.argv.slice(1).filter((arg) => arg !== '--admin-restart-for-tun') const restartArgs = forTun ? [...args, '--admin-restart-for-tun'] : args const escapedExePath = exePath.replace(/'/g, "''") @@ -279,7 +290,8 @@ export async function restartAsAdmin(forTun: boolean = true): Promise { return } managerLogger.info('PowerShell command executed successfully, quitting app') - setTimeout(() => app.quit(), 500) + // 立即退出,避免竞态 + app.quit() resolve() }) }) diff --git a/src/main/sys/autoRun.ts b/src/main/sys/autoRun.ts index d150c7b..752488a 100644 --- a/src/main/sys/autoRun.ts +++ b/src/main/sys/autoRun.ts @@ -56,10 +56,22 @@ function getTaskXml(asAdmin: boolean): string { export async function checkAutoRun(): Promise { if (process.platform === 'win32') { const execPromise = promisify(exec) + // 先检查任务计划程序 try { const { stdout } = await execPromise( `chcp 437 && %SystemRoot%\\System32\\schtasks.exe /query /tn "${appName}"` ) + if (stdout.includes(appName)) { + return true + } + } catch { + // 任务计划程序中不存在,继续检查注册表 + } + + // 检查注册表备用方案 + try { + const regPath = 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run' + const { stdout } = await execPromise(`reg query "${regPath}" /v "${appName}"`) return stdout.includes(appName) } catch { return false @@ -87,17 +99,45 @@ export async function enableAutoRun(): Promise { const { checkAdminPrivileges } = await import('../core/manager') const isAdmin = await checkAdminPrivileges() await writeFile(taskFilePath, Buffer.from(`\ufeff${getTaskXml(isAdmin)}`, 'utf-16le')) + + let taskCreated = false + if (isAdmin) { - await execPromise( - `%SystemRoot%\\System32\\schtasks.exe /create /tn "${appName}" /xml "${taskFilePath}" /f` - ) + try { + await execPromise( + `%SystemRoot%\\System32\\schtasks.exe /create /tn "${appName}" /xml "${taskFilePath}" /f` + ) + taskCreated = true + } catch (error) { + await managerLogger.warn('Failed to create scheduled task as admin:', error) + } } else { try { await execPromise( - `powershell -NoProfile -Command "Start-Process schtasks -Verb RunAs -ArgumentList '/create', '/tn', '${appName}', '/xml', '${taskFilePath}', '/f' -WindowStyle Hidden"` + `powershell -NoProfile -Command "Start-Process schtasks -Verb RunAs -ArgumentList '/create', '/tn', '${appName}', '/xml', '${taskFilePath}', '/f' -WindowStyle Hidden -Wait"` ) + // 验证任务是否创建成功 + await new Promise((resolve) => setTimeout(resolve, 1000)) + const created = await checkAutoRun() + taskCreated = created + if (!created) { + await managerLogger.warn('Scheduled task creation may have failed or been rejected') + } } catch { - await managerLogger.info('Maybe the user rejected the UAC dialog?') + await managerLogger.info('Scheduled task creation failed, trying registry fallback') + } + } + + // 任务计划程序失败时使用注册表备用方案(适用于 Windows IoT LTSC 等受限环境) + if (!taskCreated) { + await managerLogger.info('Using registry fallback for auto-run') + try { + const regPath = 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run' + const regValue = `"${exePath()}"` + await execPromise(`reg add "${regPath}" /v "${appName}" /t REG_SZ /d ${regValue} /f`) + await managerLogger.info('Registry auto-run entry created successfully') + } catch (regError) { + await managerLogger.error('Failed to create registry auto-run entry:', regError) } } } @@ -137,16 +177,26 @@ export async function disableAutoRun(): Promise { const execPromise = promisify(exec) const { checkAdminPrivileges } = await import('../core/manager') const isAdmin = await checkAdminPrivileges() - if (isAdmin) { - await execPromise(`%SystemRoot%\\System32\\schtasks.exe /delete /tn "${appName}" /f`) - } else { - try { + + // 删除任务计划程序中的任务 + try { + if (isAdmin) { + await execPromise(`%SystemRoot%\\System32\\schtasks.exe /delete /tn "${appName}" /f`) + } else { await execPromise( - `powershell -NoProfile -Command "Start-Process schtasks -Verb RunAs -ArgumentList '/delete', '/tn', '${appName}', '/f' -WindowStyle Hidden"` + `powershell -NoProfile -Command "Start-Process schtasks -Verb RunAs -ArgumentList '/delete', '/tn', '${appName}', '/f' -WindowStyle Hidden -Wait"` ) - } catch { - await managerLogger.info('Maybe the user rejected the UAC dialog?') } + } catch { + // 任务可能不存在,忽略错误 + } + + // 同时删除注册表备用方案 + try { + const regPath = 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run' + await execPromise(`reg delete "${regPath}" /v "${appName}" /f`) + } catch { + // 注册表项可能不存在,忽略错误 } } if (process.platform === 'darwin') {