Skip to content

Commit 3534391

Browse files
author
Eve Le
committed
Adding highlighted overlay for webview2, works on Win32 sample app for both visual hosting and windowed hosting mode
1 parent ab5a92d commit 3534391

8 files changed

+291
-12
lines changed

wv2util/HostAppList.cs

+40-10
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ public HostAppEntry(
5050
string runtimePath, // Path to the WebView2 client DLL
5151
string userDataPath, // Path to the user data folder
5252
string[] interestingLoadedDllPaths, // a list of full paths of DLLs that are related to WebView2 in some way
53-
int browserProcessPid) // PID of the browser process
53+
int browserProcessPid,
54+
IntPtr[] hwnds) // PID of the browser process
5455
{
5556
Kind = kind;
5657
ExecutablePath = exePath == null ? "Unknown" : exePath;
@@ -61,6 +62,7 @@ public HostAppEntry(
6162
UserDataPath = userDataPath == null ? "Unknown" : userDataPath;
6263
InterestingLoadedDllPaths = interestingLoadedDllPaths;
6364
BrowserProcessPID = browserProcessPid;
65+
Hwnds = hwnds == null ? new IntPtr[0] : hwnds;
6466
}
6567

6668
public string DisplayLabel
@@ -98,6 +100,7 @@ public string DisplayLabel
98100
public string UserDataPath { get; private set; }
99101
public string[] InterestingLoadedDllPaths { get; private set; }
100102
public int BrowserProcessPID { get; private set; } = 0;
103+
public IntPtr[] Hwnds { get; private set; }
101104
public string IntegrityLevel
102105
{
103106
get
@@ -401,7 +404,8 @@ private static IEnumerable<HostAppEntry> AddRuntimeProcessInfoToHostAppEntriesBy
401404
msedgewebview2Process.MainModule.FileName,
402405
userDataPathAndProcessType.Item1,
403406
null,
404-
0);
407+
0,
408+
null);
405409
}
406410

407411
if (parentProcess != null)
@@ -426,7 +430,8 @@ private static IEnumerable<HostAppEntry> AddRuntimeProcessInfoToHostAppEntriesBy
426430
hostAppEntry.Runtime.ExePath,
427431
userDataFolder,
428432
hostAppEntry.InterestingLoadedDllPaths,
429-
msedgewebview2Process.Id);
433+
msedgewebview2Process.Id,
434+
hostAppEntry.Hwnds);
430435
newHostAppEntry.Children.AddRange(hostAppEntry.Children);
431436
newHostAppEntry.Children.Add(currentProcessEntry);
432437

@@ -470,7 +475,8 @@ private static IEnumerable<HostAppEntry> GetHostAppEntriesFromMachineByProcessMo
470475
ClientDllPathToRuntimePath(interestingDllPaths.Item1),
471476
null,
472477
interestingDllPaths.Item3,
473-
0));
478+
0,
479+
null));
474480
}
475481
}
476482
return results;
@@ -531,7 +537,8 @@ public static IEnumerable<HostAppEntry> GetHostAppEntriesFromMachineByPipeEnumer
531537
ClientDllPathToRuntimePath(clientDllPath),
532538
null,
533539
interestingDllPaths,
534-
0));
540+
0,
541+
null));
535542
}
536543
}
537544
};
@@ -566,6 +573,7 @@ private static IEnumerable<HostAppEntry> AddRuntimeProcessInfoToHostAppEntriesBy
566573
if (hostAppEntry.BrowserProcessPID == 0)
567574
{
568575
HashSet<int> runtimePids = new HashSet<int>();
576+
Dictionary<int, HashSet<IntPtr>> runtimePidToHwndMap = new Dictionary<int, HashSet<IntPtr>>();
569577

570578
// And find corresponding top level windows for just this PID.
571579
if (pidToTopLevelHwndsMap.TryGetValue(hostAppEntry.PID, out var topLevelHwnds))
@@ -584,9 +592,17 @@ private static IEnumerable<HostAppEntry> AddRuntimeProcessInfoToHostAppEntriesBy
584592
{
585593
childHwnd = PInvoke.User32.GetProp(hostAppLeafHwnd, "CrossProcessChildHWND");
586594
}
595+
587596
if (childHwnd != IntPtr.Zero)
588597
{
589-
runtimePids.Add(HwndUtil.GetWindowProcessId(childHwnd));
598+
int runtimePid = HwndUtil.GetWindowProcessId(childHwnd);
599+
runtimePids.Add(runtimePid);
600+
601+
if (!runtimePidToHwndMap.TryGetValue(runtimePid, out HashSet<IntPtr> runtimeHwnds))
602+
{
603+
runtimePidToHwndMap[runtimePid] = runtimeHwnds = new HashSet<IntPtr>();
604+
}
605+
runtimeHwnds.Add(childHwnd);
590606
}
591607
}
592608
}
@@ -602,6 +618,8 @@ private static IEnumerable<HostAppEntry> AddRuntimeProcessInfoToHostAppEntriesBy
602618
var userDataPathAndProcessType = GetUserDataPathAndProcessTypeFromProcessViaCommandLine(runtimeProcess);
603619
userDataFolder = userDataPathAndProcessType.Item1;
604620

621+
runtimePidToHwndMap.TryGetValue(runtimePid, out HashSet<IntPtr> runtimeHwnds);
622+
605623
var runtimeEntry = new HostAppEntry(
606624
"host",
607625
hostAppEntry.ExecutablePath,
@@ -611,7 +629,8 @@ private static IEnumerable<HostAppEntry> AddRuntimeProcessInfoToHostAppEntriesBy
611629
hostAppEntry.Runtime.ExePath,
612630
userDataFolder,
613631
hostAppEntry.InterestingLoadedDllPaths,
614-
runtimePid);
632+
runtimePid,
633+
runtimeHwnds?.ToArray());
615634
runtimeEntry.Children.AddRange(hostAppEntry.Children);
616635
runtimeEntry.Children.Add(new HostAppEntry(
617636
userDataPathAndProcessType.Item2,
@@ -622,7 +641,8 @@ private static IEnumerable<HostAppEntry> AddRuntimeProcessInfoToHostAppEntriesBy
622641
runtimeProcess.MainModule.FileName,
623642
userDataFolder,
624643
null,
625-
0));
644+
0,
645+
runtimeEntry.Hwnds));
626646
hostAppEntriesWithRuntimePID.Add(runtimeEntry);
627647
added = true;
628648
}
@@ -653,6 +673,7 @@ private static IEnumerable<HostAppEntry> AddRuntimeProcessInfoToHostAppEntriesBy
653673
List<HostAppEntry> hostAppEntriesResults = new List<HostAppEntry>();
654674
Dictionary<int, HashSet<int>> parentPidToChildPidsMap = new Dictionary<int, HashSet<int>>();
655675
var topLevelHwnds = HwndUtil.GetTopLevelHwnds(null, true);
676+
Dictionary<int, HashSet<IntPtr>> childPidToHwnd = new Dictionary<int, HashSet<IntPtr>>();
656677

657678
// Then find all child (and child of child of...) windows that have appropriate class name
658679
foreach (var topLevelHwnd in topLevelHwnds)
@@ -681,6 +702,12 @@ private static IEnumerable<HostAppEntry> AddRuntimeProcessInfoToHostAppEntriesBy
681702
}
682703
childPids.Add(childPid);
683704
}
705+
706+
if (!childPidToHwnd.TryGetValue(childPid, out HashSet<IntPtr> childHwnds))
707+
{
708+
childPidToHwnd[childPid] = childHwnds = new HashSet<IntPtr>();
709+
}
710+
childHwnds.Add(childHwnd);
684711
}
685712
}
686713
}
@@ -702,6 +729,7 @@ private static IEnumerable<HostAppEntry> AddRuntimeProcessInfoToHostAppEntriesBy
702729
{
703730
var userDataPathAndProcessType = GetUserDataPathAndProcessTypeFromProcessViaCommandLine(runtimeProcess);
704731
string userDataFolder = userDataPathAndProcessType.Item1;
732+
childPidToHwnd.TryGetValue(childPid, out HashSet<IntPtr> runtimeHwnds);
705733

706734
var runtimeEntry = new HostAppEntry(
707735
"host",
@@ -712,7 +740,8 @@ private static IEnumerable<HostAppEntry> AddRuntimeProcessInfoToHostAppEntriesBy
712740
hostAppEntry.Runtime.ExePath,
713741
userDataFolder,
714742
hostAppEntry.InterestingLoadedDllPaths,
715-
childPid);
743+
childPid,
744+
runtimeHwnds?.ToArray());
716745
runtimeEntry.Children.Add(new HostAppEntry(
717746
userDataPathAndProcessType.Item2,
718747
runtimeProcess.MainModule.FileName,
@@ -722,7 +751,8 @@ private static IEnumerable<HostAppEntry> AddRuntimeProcessInfoToHostAppEntriesBy
722751
runtimeProcess.MainModule.FileName,
723752
userDataFolder,
724753
null,
725-
0));
754+
0,
755+
runtimeEntry.Hwnds));
726756
runtimeEntry.Children.AddRange(hostAppEntry.Children);
727757
hostAppEntriesResults.Add(runtimeEntry);
728758
added = true;

wv2util/HwndUtil.cs

+18
Original file line numberDiff line numberDiff line change
@@ -175,5 +175,23 @@ public static string GetClassName(IntPtr hwnd)
175175
}
176176
return className;
177177
}
178+
179+
public static System.Windows.Rect ToSystemWindowsRect(this PInvoke.RECT rectAsPInvokeRect)
180+
{
181+
System.Windows.Rect rectAsSystemWindowsRect = new System.Windows.Rect();
182+
rectAsSystemWindowsRect.X = rectAsPInvokeRect.left;
183+
rectAsSystemWindowsRect.Y = rectAsPInvokeRect.top;
184+
rectAsSystemWindowsRect.Width = rectAsPInvokeRect.right - rectAsPInvokeRect.left;
185+
rectAsSystemWindowsRect.Height = rectAsPInvokeRect.bottom - rectAsPInvokeRect.top;
186+
return rectAsSystemWindowsRect;
187+
}
188+
public static System.Windows.Rect GetWindowRect(IntPtr hwnd)
189+
{
190+
if (!PInvoke.User32.GetWindowRect(hwnd, out var rect))
191+
{
192+
throw new PInvoke.Win32Exception(PInvoke.Kernel32.GetLastError());
193+
}
194+
return rect.ToSystemWindowsRect();
195+
}
178196
}
179197
}

wv2util/MainWindow.xaml

+2-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@
6565
<RowDefinition Height="*"/>
6666
</Grid.RowDefinitions>
6767
<CheckBox Grid.Row="0" Grid.Column="0" Margin="5 5 5 5" Content="Discover more Host Apps information (slower)" IsChecked="{Binding Source={StaticResource HostAppList}, Path=ShouldDiscoverSlowly, Mode=TwoWay}" x:Name="HostAppsDiscoverSlowlyCheckbox" Checked="HostAppsDiscoverSlowlyCheckbox_Checked" Unchecked="HostAppsDiscoverSlowlyCheckbox_Checked"/>
68-
<TreeView Grid.Row="1" Grid.Column="0" Grid.RowSpan="20" Margin="5 5 5 5" x:Name="HostAppTreeView" ItemsSource="{Binding .}" SelectedValuePath="Model">
68+
<CheckBox Grid.Row="0" Grid.Column="1" Margin="5 5 5 5" Content="Highlight WebView2 (experimental)" IsChecked="False" x:Name="HostAppsVisuallyHighlightWebView2sCheckbox" Checked="HostAppsVisuallyHighlightWebView2sCheckbox_Checked" Unchecked="HostAppsVisuallyHighlightWebView2sCheckbox_Checked"/>
69+
<TreeView Grid.Row="1" Grid.Column="0" Grid.RowSpan="20" Margin="5 5 5 5" x:Name="HostAppTreeView" ItemsSource="{Binding .}" SelectedValuePath="Model" SelectedItemChanged="HostAppTreeViewSelectionChanged">
6970
<TreeView.ItemContainerStyle>
7071
<Style TargetType="{x:Type TreeViewItem}">
7172
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />

wv2util/MainWindow.xaml.cs

+34
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,40 @@ private void RuntimeListViewSelectionChanged(object sender, SelectionChangedEven
143143
}
144144
}
145145
}
146+
private List<OverlayWindow> m_openOverlayWindows = new List<OverlayWindow>();
147+
private void UpdateOverlayWindows()
148+
{
149+
foreach (var overlayWindow in m_openOverlayWindows)
150+
{
151+
overlayWindow.CloseOverlay();
152+
}
153+
m_openOverlayWindows.Clear();
154+
155+
if (this.HostAppsVisuallyHighlightWebView2sCheckbox.IsChecked.GetValueOrDefault(true))
156+
{
157+
158+
HostAppEntry selection = HostAppTreeViewSelectedItem;
159+
if (selection != null)
160+
{
161+
foreach (var hwnd in selection?.Hwnds)
162+
{
163+
m_openOverlayWindows.Add(
164+
OverlayWindow.OpenOverlayForHwnd(hwnd));
165+
}
166+
}
167+
168+
}
169+
}
170+
private void HostAppTreeViewSelectionChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
171+
{
172+
UpdateOverlayWindows();
173+
}
146174

175+
private void HostAppsVisuallyHighlightWebView2sCheckbox_Checked(object sender, RoutedEventArgs e)
176+
{
177+
UpdateOverlayWindows();
178+
}
179+
147180
private void AppOverrideRuntimePathButton_Click(object sender, RoutedEventArgs e)
148181
{
149182
FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog
@@ -427,5 +460,6 @@ private void NewsBlock_Click(object sender, MouseButtonEventArgs e)
427460
: Visibility.Visible;
428461
}
429462
}
463+
430464
}
431465
}

wv2util/OverlayWindow.xaml

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Window x:Class="wv2util.OverlayWindow"
2+
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6+
xmlns:local="clr-namespace:wv2util"
7+
mc:Ignorable="d"
8+
Title="Overlay" Height="450" Width="800" WindowStyle="None" AllowsTransparency="True" Opacity="0.25" ResizeMode="NoResize" ShowInTaskbar="False" Topmost="False" Focusable="False" IsHitTestVisible="False" IsTabStop="False" Background="#FF84B9FF" MouseUp="Window_MouseUp">
9+
</Window>

0 commit comments

Comments
 (0)