PowerShell录屏脚本While循环致GUI无响应,无法终止录屏
解决PowerShell录屏GUI无响应问题(FFmpeg分段录制)
问题根源
你的代码里Start-Recording函数的while循环会阻塞WinForms的UI线程:WaitForExit是同步等待FFmpeg进程结束的操作,加上循环持续执行,导致UI无法处理按钮点击等消息,所以Stop按钮完全没反应。
解决方案:用后台线程执行录制逻辑
把录制的循环逻辑放到独立的后台线程里,让UI线程保持响应。同时完善停止逻辑,确保能立即终止当前正在运行的FFmpeg进程。
修改后的完整代码
Add-Type -AssemblyName System.Windows.Forms $ffmpegPath = "C:\ffmpeg\bin\ffmpeg.exe" $outputFilePrefix = "output" $recordDuration = 10 $global:ffmpegProcess = $null $global:recordingInProgress = $false $global:recordingThread = $null function Start-Recording { $global:recordingInProgress = $true $recordIndex = 1 while ($global:recordingInProgress) { $outputFile = "$outputFilePrefix$recordIndex.mp4" $processStartInfo = New-Object System.Diagnostics.ProcessStartInfo $processStartInfo.FileName = $ffmpegPath $processStartInfo.Arguments = "-f gdigrab -framerate 30 -i desktop -c:v mpeg4 -q:v 2 -r 30 -t $recordDuration -y $outputFile" $processStartInfo.UseShellExecute = $false $processStartInfo.RedirectStandardOutput = $true $processStartInfo.CreateNoWindow = $false $global:ffmpegProcess = New-Object System.Diagnostics.Process $global:ffmpegProcess.StartInfo = $processStartInfo try { $global:ffmpegProcess.Start() | Out-Null # 异步等待进程退出,避免阻塞线程 $exitEvent = $global:ffmpegProcess.WaitForExitAsync() # 同时检查录制状态,允许中途停止 while (-not $exitEvent.IsCompleted -and $global:recordingInProgress) { Start-Sleep -Milliseconds 100 } if (-not $global:ffmpegProcess.HasExited) { $global:ffmpegProcess.Kill() $global:ffmpegProcess.WaitForExit() } $recordIndex++ } catch { Write-Host "录制出错: $_" } } } function Stop-Recording { $global:recordingInProgress = $false # 终止当前正在运行的FFmpeg进程 if ($global:ffmpegProcess -and -not $global:ffmpegProcess.HasExited) { $global:ffmpegProcess.Kill() $global:ffmpegProcess.WaitForExit() } } # 创建UI界面 $form = New-Object System.Windows.Forms.Form $form.Text = "分段录屏工具" $form.Size = New-Object System.Drawing.Size(300,150) $form.StartPosition = "CenterScreen" $startBtn = New-Object System.Windows.Forms.Button $startBtn.Text = "Start Recording" $startBtn.Location = New-Object System.Drawing.Point(20,30) $startBtn.Add_Click({ if (-not $global:recordingInProgress) { # 在后台线程启动录制 $global:recordingThread = [System.Threading.Thread]::new({Start-Recording}) $global:recordingThread.IsBackground = $true $global:recordingThread.Start() } }) $stopBtn = New-Object System.Windows.Forms.Button $stopBtn.Text = "Stop Recording" $stopBtn.Location = New-Object System.Drawing.Point(160,30) $stopBtn.Add_Click({Stop-Recording}) $form.Controls.Add($startBtn) $form.Controls.Add($stopBtn) $form.ShowDialog() | Out-Null
关键改进点
- 使用后台线程执行录制循环,UI线程不再被阻塞,Stop按钮可以正常响应
- 替换
WaitForExit为异步等待+状态检查,允许中途终止当前录制片段 - 完善停止逻辑,立即杀掉当前运行的FFmpeg进程,而不是等它录完10秒
替代工具建议
如果不想自己维护PowerShell代码,可以考虑这些工具:
- OBS Studio:支持命令行模式,可以通过脚本控制分段录制,功能强大且稳定
- ShareX:开源录屏工具,自带PowerShell/命令行接口,支持自定义分段规则
- FFmpeg直接批处理脚本:放弃WinForms GUI,用控制台脚本+快捷键控制启停(比如用
Set-PSReadlineKeyHandler绑定快捷键)
内容的提问来源于stack exchange,提问作者Baswaraj
相关产品推荐
相关产品推荐

