C#如何获取窗体启动的UWP进程的退出时长?
解决UWP应用(如“电影和电视”)运行时长统计问题
嘿,这个坑我之前踩过!UWP应用的进程模型和传统Win32程序完全不一样,你现有的代码只能捕获普通exe的生命周期,对UWP根本不生效——因为你用Process.Start启动媒体文件时,实际启动的只是一个短暂的shell关联进程,真正的UWP应用进程是在应用容器里启动的,而且可能有多个,普通的Process对象根本抓不到它的Exited事件。
下面给你两个可行的解决方案,都是我实际测试过的:
方案一:通过WMI追踪UWP进程
UWP进程的命令行里会包含它的包名,我们可以通过WMI查询找到对应的进程,再订阅它的退出事件。
步骤:
- 先获取“电影和电视”的包名:打开PowerShell,执行
Get-AppxPackage *ZuneVideo*,输出里的PackageFullName就是我们要的(通常是Microsoft.ZuneVideo_8wekyb3d8bbwe,但不同系统版本可能略有差异)。 - 启动文件后,等待几秒让UWP应用完全启动,然后用WMI查询筛选出对应包名的进程。
- 订阅该进程的
Exited事件,记录启动和退出时间差。
代码示例:
using System; using System.Diagnostics; using System.Management; using System.Threading.Tasks; class UwpProcessTimer { static async Task Main(string[] args) { var targetFile = new System.IO.FileInfo(@"D:\test.mp4"); // 替换成你的媒体文件路径 var startTime = DateTime.Now; // 启动文件(此时返回的process是临时关联进程,很快会退出) Process.Start(new ProcessStartInfo(targetFile.FullName) { CreateNoWindow = true }); // 等待UWP应用启动完成(根据实际情况调整延迟时间) await Task.Delay(2000); // 替换成你查到的"电影和电视"包名 var uwpPackageFullName = "Microsoft.ZuneVideo_8wekyb3d8bbwe"; var wmiQuery = new ObjectQuery($"SELECT * FROM Win32_Process WHERE CommandLine LIKE '%{uwpPackageFullName}%'"); using (var searcher = new ManagementObjectSearcher(wmiQuery)) { foreach (var processObj in searcher.Get()) { var processId = Convert.ToInt32(processObj["ProcessId"]); try { var uwpProcess = Process.GetProcessById(processId); uwpProcess.EnableRaisingEvents = true; uwpProcess.Exited += (sender, e) => { var runDuration = DateTime.Now - startTime; Console.WriteLine($"应用运行时长:{runDuration.TotalMinutes:F2}分钟({runDuration.TotalSeconds:F0}秒)"); // 这里添加你的业务逻辑 }; } catch (ArgumentException) { // 进程可能已经退出,直接忽略即可 } } } // 保持程序运行,等待事件触发 Console.WriteLine("等待UWP应用退出..."); Console.ReadLine(); } }
方案二:用Windows Runtime API监控UWP生命周期
这个方案更贴合UWP的原生模型,通过AppDiagnosticInfo来监控应用的运行状态(包括挂起和终止),准确性更高。
代码示例:
using System; using System.Linq; using System.Threading.Tasks; using Windows.ApplicationModel; using Windows.System; using Windows.Storage; class UwpAppLifecycleTimer { static async Task Main(string[] args) { var targetFile = new System.IO.FileInfo(@"D:\test.mp4"); var startTime = DateTime.Now; // 转换为UWP可识别的StorageFile var storageFile = await StorageFile.GetFileFromPathAsync(targetFile.FullName); var launchSuccess = await Launcher.LaunchFileAsync(storageFile); if (launchSuccess) { var uwpPackageFullName = "Microsoft.ZuneVideo_8wekyb3d8bbwe"; // 替换为你的包名 var targetPackage = Package.FindPackage(uwpPackageFullName); if (targetPackage != null) { // 获取应用诊断信息 var diagnosticInfos = await AppDiagnosticInfo.RequestInfoForPackageAsync(targetPackage.Id.FullName); foreach (var diagInfo in diagnosticInfos) { // 订阅状态变化事件 diagInfo.StateChanged += async (sender, e) => { // UWP应用可能被挂起或终止,两种状态都视为"退出" if (e.NewState.State == AppExecutionState.Suspended || e.NewState.State == AppExecutionState.Terminated) { var runDuration = DateTime.Now - startTime; Console.WriteLine($"应用运行时长:{runDuration.TotalMinutes:F2}分钟"); } }; } } } Console.WriteLine("等待UWP应用退出或挂起..."); Console.ReadLine(); } }
注意事项:
- 方案二需要你的项目是.NET Core 3.0+或.NET 5+,并且启用Windows兼容(右键项目→属性→应用程序→目标框架选择带Windows的版本)。
- UWP应用不会像Win32程序那样直接触发"退出",系统会在后台把它挂起,所以要同时监控
Suspended和Terminated状态。 - 包名一定要和当前系统的一致,用PowerShell命令确认最稳妥。
内容的提问来源于stack exchange,提问作者J. Hajjar
相关产品推荐
相关产品推荐

