Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions src/main/core/commandLauncher/windowsLauncher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,34 @@ async function openApplicationViaExplorer(
await openWithElectronShell(appPath, fallback)
}

async function openUwpApplicationViaExplorer(appId: string): Promise<void> {
const target = `shell:AppsFolder\\${appId}`

try {
const result = await WindowsShellLauncher.launch({ target, showCommand: 1 })
if (result.success) {
console.log(`[Launcher] 已通过 Explorer 启动 UWP 应用: ${appId}`)
return
}

console.warn('[Launcher] Explorer COM 启动 UWP 应用失败,回退原生激活 API:', {
appId,
hresult: result.hresult,
stage: result.stage
})
} catch (error) {
console.warn('[Launcher] Explorer COM 启动 UWP 应用异常,回退原生激活 API:', {
appId,
error
})
}

if (!UwpManager.launchUwpApp(appId)) {
throw new Error(`启动 UWP 应用失败: ${appId}`)
}
console.log(`[Launcher] 已通过原生 API 启动 UWP 应用: ${appId}`)
}

/**
* 执行系统命令(不等待进程结束,适用于 GUI 应用)
* @param command 完整命令字符串(如 "rundll32 shell32.dll,Control_RunDLL")或命令名
Expand Down Expand Up @@ -125,8 +153,7 @@ export async function launchApp(
if (appPath.startsWith('uwp:')) {
const appId = appPath.slice(4)
try {
UwpManager.launchUwpApp(appId)
console.log(`[Launcher] 成功启动 UWP 应用: ${appId}`)
await openUwpApplicationViaExplorer(appId)
return
} catch (error) {
console.error('[Launcher] 启动 UWP 应用失败:', error)
Expand Down
43 changes: 43 additions & 0 deletions tests/main/windowsLauncher.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'

const { mockShellLaunch, mockLaunchUwpApp } = vi.hoisted(() => ({
mockShellLaunch: vi.fn(),
mockLaunchUwpApp: vi.fn()
}))

vi.mock('electron', () => ({
dialog: { showMessageBox: vi.fn() },
shell: { openExternal: vi.fn(), openPath: vi.fn() }
}))
vi.mock('../../src/main/core/native', () => ({
UwpManager: { launchUwpApp: mockLaunchUwpApp },
WindowsShellLauncher: { launch: mockShellLaunch }
}))

import { launchApp } from '../../src/main/core/commandLauncher/windowsLauncher'

describe('Windows UWP 应用启动', () => {
beforeEach(() => {
vi.clearAllMocks()
mockShellLaunch.mockResolvedValue({ success: true, hresult: 0, stage: 'test' })
mockLaunchUwpApp.mockReturnValue(true)
})

it('通过 Explorer Shell 启动以获得正常的前台焦点交接', async () => {
await launchApp('uwp:Microsoft.WindowsTerminal_8wekyb3d8bbwe!App')

expect(mockShellLaunch).toHaveBeenCalledWith({
target: 'shell:AppsFolder\\Microsoft.WindowsTerminal_8wekyb3d8bbwe!App',
showCommand: 1
})
expect(mockLaunchUwpApp).not.toHaveBeenCalled()
})

it('Explorer Shell 启动失败时回退原生 UWP API', async () => {
mockShellLaunch.mockResolvedValue({ success: false, hresult: -1, stage: 'execute' })

await launchApp('uwp:Contoso.App_123!App')

expect(mockLaunchUwpApp).toHaveBeenCalledWith('Contoso.App_123!App')
})
})