Browse Source

RunProgramAsync

龙腾猫跃 4 tháng trước cách đây
mục cha
commit
934bf1e729
3 tập tin đã thay đổi với 66 bổ sung và 6 xóa
  1. 8 6
      Shared/MeloongCore.csproj
  2. 50 0
      Shared/Utils/TaskUtils.cs
  3. 8 0
      Wpf/MeloongCore.Wpf.csproj

+ 8 - 6
Shared/MeloongCore.csproj

@@ -21,12 +21,6 @@
 		</PackageReference>
 	</ItemGroup>
 
-	<ItemGroup>
-	  <Reference Include="Newtonsoft.Json">
-	    <HintPath>..\..\Plain Craft Launcher 2\Resources\Newtonsoft.Json.dll</HintPath>
-	  </Reference>
-	</ItemGroup>
-
 	<ItemGroup>
 		<Using Include="System.Diagnostics.CodeAnalysis" />
 		<Using Include="System.Collections" />
@@ -35,9 +29,17 @@
 		<Using Include="System.Net" />
 		<Using Include="System.Runtime.CompilerServices" />
 		<Using Include="System.Runtime.InteropServices" />
+		<Using Include="Newtonsoft.Json" />
+		<Using Include="Newtonsoft.Json.Linq" />
 		<Using Include="MeloongCore.Extensions" />
 	</ItemGroup>
 
+	<ItemGroup>
+		<Reference Include="Newtonsoft.Json">
+			<HintPath>..\..\Plain Craft Launcher 2\Resources\Newtonsoft.Json.dll</HintPath>
+		</Reference>
+	</ItemGroup>
+
 	<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
 		<DefineConstants>$(DefineConstants);SNAPSHOT</DefineConstants>
 	</PropertyGroup>

+ 50 - 0
Shared/Utils/TaskUtils.cs

@@ -0,0 +1,50 @@
+using System.Diagnostics;
+
+namespace MeloongCore;
+public static class TaskUtils {
+
+    public static void Run(this Task task) => task.GetAwaiter().GetResult();
+    public static T Run<T>(this Task<T> task) => task.GetAwaiter().GetResult();
+
+    /// <summary>
+    /// 静默运行程序并等待其结束,返回其输出和退出码。
+    /// 支持 notepad、git 等命令。
+    /// 超时或启动失败会抛出异常。
+    /// </summary>
+    public static async Task<(string Output, int ExitCode)> RunProgramAsync(string file, string arguments = "", int? timeoutMs = null, Encoding? encoding = null) {
+        Logger.Info($"运行程序,并返回其输出:{file} {arguments}");
+        var info = new ProcessStartInfo {
+            Arguments = arguments,
+            FileName = PathUtils.ToShortPath(file),
+            UseShellExecute = false,
+            CreateNoWindow = true,
+            RedirectStandardOutput = true, StandardOutputEncoding = encoding,
+            RedirectStandardError = true, StandardErrorEncoding = encoding
+        };
+        using var program = new Process { StartInfo = info, EnableRaisingEvents = true };
+        if (!program.Start()) throw new InvalidOperationException($"运行程序时出现意外错误:{file} {arguments}");
+
+        // 读取输出和错误流
+        var outputTask = program.StandardOutput.ReadToEndAsync();
+        var errorTask = program.StandardError.ReadToEndAsync();
+        var completionSource = new TaskCompletionSource<object?>(TaskCreationOptions.RunContinuationsAsynchronously);
+        program.Exited += (_, _) => completionSource.TrySetResult(null);
+        if (program.HasExited) completionSource.TrySetResult(null);
+        var task = completionSource.Task;
+
+        // 等待超时
+        if (timeoutMs.HasValue && timeoutMs > 0) {
+            Logger.Trace($"等待程序 {program.Id} 完成,超时:{timeoutMs.Value}ms");
+            if (await Task.WhenAny(task, Task.Delay(timeoutMs.Value)) != task) {
+                try {
+                    if (!program.HasExited) program.Kill();
+                } catch (InvalidOperationException) { // 进程已退出,无需处理
+                }
+                throw new TimeoutException($"运行程序超时:{file} {arguments}");
+            }
+        }
+        await task;
+        return (await outputTask + await errorTask, program.ExitCode);
+    }
+
+}

+ 8 - 0
Wpf/MeloongCore.Wpf.csproj

@@ -30,6 +30,8 @@
 		<Using Include="System.Net" />
 		<Using Include="System.Runtime.CompilerServices" />
 		<Using Include="System.Runtime.InteropServices" />
+		<Using Include="Newtonsoft.Json" />
+		<Using Include="Newtonsoft.Json.Linq" />
 		<Using Include="MeloongCore" />
 		<Using Include="MeloongCore.Extensions" />
 	</ItemGroup>
@@ -38,6 +40,12 @@
 		<ProjectReference Include="..\Shared\MeloongCore.csproj" />
 	</ItemGroup>
 
+	<ItemGroup>
+		<Reference Include="Newtonsoft.Json">
+			<HintPath>..\..\Plain Craft Launcher 2\Resources\Newtonsoft.Json.dll</HintPath>
+		</Reference>
+	</ItemGroup>
+
 	<ItemGroup>
 		<Reference Include="System.Windows.Forms" />
 		<Reference Include="PresentationCore" />