.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
相关产品推荐
相关产品推荐

