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

.NET Core 3.1 WPF中GraphicsCapturePicker跨线程调用异常求助

问题:.NET Core 3.1 WPF中GraphicsCapturePicker引发跨线程异常

我正在开发基于.NET Core 3.1的WPF解决方案,需求是选择多个捕获窗口,在窗口聚焦时进行共享。目前已通过列表实现基础功能,但想通过带窗口预览的GraphicsCapturePicker优化用户体验,却遇到以下异常:

The application called an interface that was marshalled for a different thread

错误截图


相关代码

打开选择器的方法代码

public async void OpenCapturePicker(object sender, RoutedEventArgs e)
{
    Console.WriteLine("OpenCapturePicker");
    await Dispatcher.InvokeAsync(OpenCapturePicker);

}
private async void OpenCapturePicker()
{
    var picker = new GraphicsCapturePicker();

    picker.SetWindow(_capturableWindowHandle);
    var item = await picker.PickSingleItemAsync();
    if (item == null) return;
    //rest of code
}

_capturableWindowHandle的构造函数定义

public SomeClass(){
 _capturableWindowHandle = new WindowInteropHelper(this).Handle;
}

支持SetWindow方法的扩展类

public  static class CaptureHelper
{
    static readonly Guid GraphicsCaptureItemGuid = new Guid("79C3F95B-31F7-4EC2-A464-632EF5D30760");
    public static GraphicsCaptureItem CreateItemForWindow(IntPtr windowInteropHandler)
    {
        var factory = WindowsRuntimeMarshal.GetActivationFactory(typeof(GraphicsCaptureItem));
        var interop = (IGraphicsCaptureItemInterop) factory;
        var itemPointer = interop.CreateForWindow(windowInteropHandler, GraphicsCaptureItemGuid);
        var item = Marshal.GetObjectForIUnknown(itemPointer) as GraphicsCaptureItem;
        Marshal.Release(itemPointer);

        return item;
    }
    public static void SetWindow(this GraphicsCapturePicker picker, IntPtr hwnd)
    {
        var interop = (IInitializeWithWindow)(object)picker;
        interop.Initialize(hwnd);
    }
}

更新

功能开发分支链接:GitHub分支


解决思路

  • 修复递归调用问题:当前事件处理方法OpenCapturePicker(sender, e)中调用Dispatcher.InvokeAsync(OpenCapturePicker)会触发无限制递归,这是线程混乱的核心原因之一。应拆分核心逻辑,明确线程调度:

    public async void OpenCapturePicker(object sender, RoutedEventArgs e)
    {
        Console.WriteLine("OpenCapturePicker");
        if (!Dispatcher.CheckAccess())
        {
            await Dispatcher.InvokeAsync(OpenCapturePickerCore);
            return;
        }
        await OpenCapturePickerCore();
    }
    
    private async Task OpenCapturePickerCore()
    {
        var picker = new GraphicsCapturePicker();
        picker.SetWindow(_capturableWindowHandle);
        var item = await picker.PickSingleItemAsync();
        if (item == null) return;
        // 后续处理逻辑
    }
    
  • 强制UI线程执行COM操作:GraphicsCapturePicker及相关COM接口(如IInitializeWithWindow)必须在UI线程调用。通过Dispatcher.CheckAccess()判断当前线程,确保所有选择器相关操作都在UI线程执行。

  • 避免滥用async void:除事件处理方法外,异步逻辑尽量返回Task而非void,便于控制异步流程,减少线程上下文混乱。

  • 延迟获取窗口句柄:构造函数阶段窗口HWND可能未完全初始化,应在窗口加载完成后获取句柄:

    protected override void OnSourceInitialized(EventArgs e)
    {
        base.OnSourceInitialized(e);
        _capturableWindowHandle = new WindowInteropHelper(this).Handle;
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 14:21:02