问题描述
问题描述
我有一个 WPF 子窗口和一个 WPF 主窗口。主窗口被设置为子窗口的所有者。子窗口具有透明背景,位于主窗口的顶部。
当我共享我的整个屏幕时,与会者可以看到主窗口和子窗口以及两个窗口的所有内容。 当我只共享主窗口时,来宾看到子窗口的背景是黑色而不是透明。
在我自己的屏幕上,两个窗口都呈现得很好 - 无论它们是如何共享的。
该问题可在 Microsoft Teams 上重现 - 但在 Zoom 上无法重现。
这是应用程序在我的计算机上呈现的方式 - 无论我如何共享我的屏幕:
当我分享我的整个屏幕时,会议参与者看到应用程序的方式(截图仅说明应用程序,但显然参与者可以看到整个屏幕):
当我只共享主窗口时,与会者看到应用程序的方式是这样的(黑色部分是子窗口的背景,它应该真正显示为透明而不是黑色):
如果我将子窗口的背景更改为例如Brushes.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
的 WinFormsHwndSource
中。 - 我不在乎是否必须使用 PInvoke、Windows 钩子等。我已经广泛使用了。
- 在屏幕共享时不显示子窗口(如参与者所见)是可以接受的。
我尝试过无济于事的事情
-
我尝试不让主窗口成为子窗口的所有者,但这会消除您在所有者关系中获得的良好行为:例如子窗口总是在所有者之上(不使用
TopMost
),子窗口与主窗口一起最小化、最大化、恢复和关闭。此外,共享主窗口时根本不会出现子窗口。这作为最后的手段是可以接受的,因为我宁愿不让子窗口出现在屏幕共享会话中,也不愿让它显示为黑色。 -
我尝试使用
SetwindowLong
手动设置所有者关系来 PInvokeGWL_HWNDPARENT
(我猜这就是window.Owner
所做的)。参考:https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowlonga#remarks -
我尝试 PInvoke
SetwindowLong
并清除WS_POPUP
和WS_OVERLAPPED
标志并设置WS_CHILD
,然后调用 {{1} } 以创建“视觉”父/子关系,而不是SetParent
创建的逻辑所有者关系。这在window.Owner
: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setparent#remarks 的文档中指定。这实际上解决了问题,但在其他情况下会产生视觉故障。 -
我尝试使用
SetParent
在子窗口上 PInvokeSetlayeredWindowAttributes
然后将子窗口的背景设置为例如品红色,然后将该颜色代码指定为透明颜色键。这实际上修复了黑色背景,但窗口渲染时没有内容和奇怪的边框。我已经读到这可能发生,因为 WPF 是基于 Direct3D 构建的,而LWA_COLORKEY
实际上用于使用 GDI 呈现的窗口。根据此博客(但是,很旧,因此可能无法反映当今世界),这也可能是因为SetlayeredWindowAttributes
会将窗口置于所谓的“系统重定向内容模式”,WPF 不支持该模式SetlayeredWindowAttributes
{3}} -
我尝试通过 PInvoke
SetwindowdisplayAffinity
将子窗口显示关联设置为WDA_MONITOR
和WDA_EXCLUDEFROMCAPTURE
。为了我的目的,排除子窗口可能是一个可行的选择,但是,Microsoft Teams 似乎使用忽略此设置的方法来捕获窗口。 -
我尝试通过设置
RenderOptions.ProcessRenderMode = RenderMode.softwareOnly
来禁用硬件加速。 -
从具有不同硬件的不同机器共享时,该问题可重现。
坦率地说,我对如何解决这个问题有点不知所措。可能主要是因为我无法理解为什么会首先出现这个问题。我在互联网上搜索过,没有发现有类似问题的人。我希望有人能解释一下 - 如果没有解决方案,那么至少可以说明问题可能发生的原因。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)