You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复PowerShell中.Net Task与WPF线程相关的MediaCapture错误

PowerShell USB摄像头监控:异步调用与线程错误解决方案

预期目标

计划使用PowerShell实时监控USB摄像头的输入视频。

问题描述

  • 问题1:使用自定义await类等待.NET异步函数返回的__ComObject时,首次调用InitializeAsync成功,但第二次调用StartPreviewAsync出现未知错误。
  • 问题2:若不等待StartPreviewAsync执行完成,会触发线程错误(RPC_E_WRONG_THREAD)。

错误信息

错误1

Exception occurred while calling "Wait" with "0" arguments: "One or more errors occurred."

错误2

Exception occurred while calling ".ctor" with "0" arguments: "The application called an interface that was marshaled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))"

补充信息

已将$ui.Content = [CaptureElement]::new()的执行移至UI调度器Invoke中,但无效果。

现有代码

# using namespace
using namespace System.Windows
using namespace Windows.Foundation
using namespace Windows.Media.Capture
using namespace Windows.UI.Xaml.Controls

# using dotnet
using assembly  PresentationFramework
using assembly  System.Runtime.WindowsRuntime

# import Runtime type [TypeName, AssemblyName, ContentType]
[Windows.Foundation.IAsyncAction,         Windows.Foundation,       ContentType=WindowsRuntime]
[Windows.Media.Capture.MediaCapture,      Windows.Media.Capture,    ContentType=WindowsRuntime]
[Windows.UI.Xaml.Controls.CaptureElement, Windows.UI.Xaml.Controls, ContentType=WindowsRuntime]

# init MediaCapture
$capture = [Mediacapture]::new()
[await]::Action($capture.InitializeAsync(), [object])

 # ui
$ui = [Window]::new()
$ui.Dispatcher.Invoke([Action]{
    $ui.Content = [CaptureElement]::new()
    $ui.Content.Source = $capture
    [await]::Action($capture.StartPreviewAsync(), [object])
})
$ui.ShowDialog()

# awaiter class
class await{
    static [object]Action([__ComObject]$async, [type]$type){
        $asTask  = [WindowsRuntimeSystemExtensions].GetMethod("AsTask", [IAsyncAction])
        $netTask = $asTask.Invoke($null, @($async))
        $netTask.Wait()
        return $netTask.Result
    }
}

问题根源

  1. 死锁问题:自定义await类中使用$netTask.Wait()会阻塞当前线程,当在UI线程调用时,StartPreviewAsync需要UI线程完成后续操作,但UI线程已被Wait()卡住,导致异步任务无法完成,抛出"One or more errors occurred"。
  2. 线程封送错误:MediaCapture和CaptureElement的部分操作必须在UI线程执行,若异步任务在非UI线程完成后尝试访问UI线程对象,会触发RPC_E_WRONG_THREAD错误。

修正方案

  1. 替换Wait()为GetAwaiter().GetResult(),避免UI线程死锁;
  2. 将MediaCapture的初始化和预览启动逻辑统一移至UI线程,确保所有UI相关操作在同一线程执行;
  3. 优化await类,适配不同类型的异步操作(IAsyncAction/IAsyncOperation)。

修正后的代码

# using namespace
using namespace System.Windows
using namespace Windows.Foundation
using namespace Windows.Media.Capture
using namespace Windows.UI.Xaml.Controls

# using dotnet
using assembly PresentationFramework
using assembly System.Runtime.WindowsRuntime

# import Runtime type [TypeName, AssemblyName, ContentType]
[Windows.Foundation.IAsyncAction, Windows.Foundation, ContentType=WindowsRuntime]
[Windows.Media.Capture.MediaCapture, Windows.Media.Capture, ContentType=WindowsRuntime]
[Windows.UI.Xaml.Controls.CaptureElement, Windows.UI.Xaml.Controls, ContentType=WindowsRuntime]

# 初始化UI并在UI线程完成所有摄像头操作
$ui = [Window]::new()
$ui.Dispatcher.Invoke([Action]{
    # 初始化MediaCapture
    $capture = [MediaCapture]::new()
    [await]::Action($capture.InitializeAsync())

    # 创建CaptureElement并关联摄像头
    $captureElement = [CaptureElement]::new()
    $captureElement.Source = $capture
    $ui.Content = $captureElement

    # 启动预览
    [await]::Action($capture.StartPreviewAsync())
})

$ui.ShowDialog()

# 优化后的awaiter类
class await{
    static [void]Action([IAsyncAction]$asyncAction){
        # 使用GetAwaiter().GetResult()避免死锁,同时确保在当前线程完成异步操作
        $asyncAction.AsTask().GetAwaiter().GetResult()
    }

    static [object]Operation([IAsyncOperation]$asyncOp){
        return $asyncOp.AsTask().GetAwaiter().GetResult()
    }
}

关键说明

  • UI线程一致性:所有与MediaCapture预览相关的操作(包括初始化、关联CaptureElement、启动预览)都在UI线程执行,避免线程封送错误;
  • 异步等待优化:GetAwaiter().GetResult()相比Wait()更安全,不会导致UI线程死锁,因为它会直接在当前线程完成异步任务的后续逻辑;
  • 拆分await方法:针对IAsyncAction(无返回值)和IAsyncOperation(有返回值)分别提供方法,适配不同的异步操作类型。

内容的提问来源于stack exchange,提问作者WorkshopLilla

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 21:34:52