.net - 在 Microsoft Teams 上共享主窗口时,透明子窗口呈现为黑色
问题描述
问题描述
我有一个WPF子窗口和一个WPF主窗口。主窗口设置为子窗口的所有者。子窗口具有透明背景并位于主窗口的顶部。
当我共享我的整个屏幕时,会议客人可以看到主窗口和子窗口以及两个窗口的所有内容都很好。当我只共享主窗口时,会议客人会看到子窗口的背景为黑色而不是透明。
在我自己的屏幕上,两个窗口都渲染得很好——不管它们是如何共享的。
该问题可在 Microsoft Teams 上重现,但不能在 Zoom 上重现。
这是应用程序在我的计算机上呈现的方式 - 无论我如何共享我的屏幕:
这是我共享整个屏幕时会议参与者看到应用程序的方式(屏幕截图仅说明应用程序,但显然参与者可以看到整个屏幕):
这是当我只共享主窗口时会议参与者看到应用程序的方式(黑色部分是子窗口的背景,它应该真正显示为透明而不是黑色):
如果我将子窗口的背景更改为 egBrushes.Green
而不是Brushes.Transparent
,它会正确呈现,如参与者所见:
很明显,在传输透明子窗口的捕获时存在问题。
使用
C#、WPF、.NET Framework 4.8 的技术(尚未测试是否在其他目标框架(例如 .NET Core)上出现相同的问题,但不能选择更改目标框架)。
重现问题的最小示例代码
MainWindow.xaml
:
<Window x:Class="MyApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="MainWindow" Height="600" Width="600"
Background="LightBlue"
WindowStartupLocation="CenterScreen">
<Grid Height="500" Width="500" Background="CornflowerBlue" />
</Window>
MainWindow.xaml.cs
:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace MyApp
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
ContentRendered += delegate { CreateChildWindow(); };
}
private void CreateChildWindow()
{
var childWindow = new Window
{
WindowStyle = WindowStyle.None,
AllowsTransparency = true,
Background = Brushes.Transparent,
WindowStartupLocation = WindowStartupLocation.CenterScreen,
Height = 400,
Width = 400,
ShowInTaskbar = false,
Content = new Grid {Background = Brushes.Red, Height = 100, Width = 100},
Owner = this
};
childWindow.Show();
}
}
}
约束
- 在实际应用程序中,主窗口是一个 3rd 方原生 Win32 应用程序。但是,子窗口与主窗口位于同一进程空间中。
- 子窗口必须以透明背景显示,并且能够具有完全不透明的内容。
- 我必须为子窗口使用 WPF/.NET。如果可以解决任何问题,WPF 内容可能会托管在
Form
带有ElementHost
或原始的 WinForms 中。HwndSource
- 我不在乎是否必须使用 PInvoke、Windows 挂钩等。我已经广泛使用了。
- 在屏幕共享时不显示子窗口(如参与者所见)是可以接受的。
我尝试过的事情无济于事
我尝试不使主窗口成为子窗口的所有者,但这消除了您通过所有者关系获得的良好行为:例如,子窗口始终位于所有者之上(不使用
TopMost
),子窗口最小化,最大化,恢复并与主窗口一起关闭。此外,共享主窗口时,子窗口根本不会出现。作为最后的手段,这可能是可以接受的,因为我宁愿不让子窗口出现在屏幕共享会话上,也不愿它显示为黑色。我曾尝试使用 PInvoke
SetWindowLong
手动GWL_HWNDPARENT
设置所有者关系(我猜这就是这样window.Owner
做的)。参考:https ://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowlonga#remarks我试图 PInvoke
SetWindowLong
并清除WS_POPUP
andWS_OVERLAPPED
标志并设置WS_CHILD
,然后调用 toSetParent
以创建“视觉”父/子关系,而不是window.Owner
创建的逻辑所有者关系。这在文档中指定为SetParent
:https ://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setparent#remarks 。这实际上解决了问题,但在其他情况下会产生视觉故障。我尝试
SetLayeredWindowAttributes
在子窗口上使用PInvokeLWA_COLORKEY
,然后将子窗口的背景设置为例如洋红色,然后将该颜色代码指定为透明颜色键。这实际上修复了黑色背景,但窗口呈现没有内容和奇怪的边框。我已经读到这可能会发生,因为 WPF 是基于 Direct3D 构建的,并且SetLayeredWindowAttributes
实际上是用于使用 GDI 呈现的窗口。根据这个博客(但是,很老所以可能无法反映当今世界),也可能是因为SetLayeredWindowAttributes
会将窗口置于所谓的“系统重定向内容模式”,WPF https://dwayneneed 不支持这种模式。 github.io/wpf/2008/09/08/transparent-windows-in-wpf.html我试图 PInvoke
SetWindowDisplayAffinity
将子窗口显示关联设置为WDA_MONITOR
和WDA_EXCLUDEFROMCAPTURE
。就我的目的而言,从捕获中排除子窗口可能是一个可行的选择,但是,Microsoft Teams 似乎使用忽略此设置的方法来捕获窗口。我试图通过设置来禁用硬件加速
RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly
。当从具有不同硬件的不同机器共享时,该问题是可重现的。
坦率地说,我对如何解决这个问题有点茫然。可能主要是因为我不明白为什么会出现这个问题。我搜索了互联网,没有发现有类似问题的人。我希望有人能阐明一点——如果不是解决方案,那么至少是为什么会出现问题。
解决方案
推荐阅读
- sql - Postgres 列的任意字符串名称
- perl - PDF::FromHTML - 文件损坏且无输出
- android - Fail to use custom model in tensorflow lite object detection android app
- html - 无法发布/注册
- python-3.x - 在 for 循环函数内部和外部声明变量的区别
- sql-server-2012 - 案例语句大于登录在 SQL 中的 else 部分
- java - 如何在顶部回收器视图中隐藏浮动操作按钮并在向下滚动时显示?
- tensorflow - 如何在 Keras 中使用 flow_from_directory 重复数据
- google-bigquery - Bigquery Does not cache subqueries?
- laravel - If relationship doesn't exist use parent's relationship