Skip to content

Commit ee67a62

Browse files
committed
Perf is bad enumerating runtimes and host apps so make those manual
1 parent 482f539 commit ee67a62

File tree

3 files changed

+158
-21
lines changed

3 files changed

+158
-21
lines changed

wv2util/AppOverrideUi.xaml.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,14 @@ private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs
6161
if (RuntimeList.SelectedIndex >= 0)
6262
{
6363
RuntimeEntry selection = (RuntimeEntry)RuntimeList.SelectedItem;
64-
Clipboard.SetText(selection.RuntimeLocation);
64+
try
65+
{
66+
Clipboard.SetText(selection.RuntimeLocation);
67+
}
68+
catch (System.Runtime.InteropServices.COMException)
69+
{
70+
// We might fail to open clipboard. Just ignore
71+
}
6572
}
6673
}
6774

wv2util/HostAppList.cs

Lines changed: 116 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@ public class HostAppList : ObservableCollection<HostAppEntry>
4141
{
4242
public HostAppList()
4343
{
44-
FromMachine();
44+
// FromMachine();
4545
}
4646

4747
public void FromMachine()
4848
{
4949

50-
IEnumerable<HostAppEntry> newEntries = GetHostAppEntriesFromMachine();
50+
IEnumerable<HostAppEntry> newEntries = GetHostAppEntriesFromMachine().ToList<HostAppEntry>();
5151
// Use ToList to get a fixed collection that won't get angry that we're calling
5252
// Add and Remove on it while enumerating.
5353
foreach (var entry in this.Except(newEntries).ToList<HostAppEntry>())
@@ -85,7 +85,7 @@ private static IEnumerable<HostAppEntry> GetHostAppEntriesFromMachine()
8585
if (processType == null)
8686
{
8787
HostAppEntry entry = new HostAppEntry(
88-
process.Parent().GetMainModuleFileName(),
88+
process.ParentProcess().GetMainModuleFileName(),
8989
process.GetMainModuleFileName(),
9090
userDataPath);
9191
yield return entry;
@@ -148,4 +148,117 @@ public static string GetMainModuleFileName(this Process process, int buffer = 10
148148
null;
149149
}
150150
}
151+
152+
public static class ProcessExtensions2
153+
{
154+
/// <summary>
155+
/// Returns the Parent Process of a Process
156+
/// </summary>
157+
/// <param name="process">The Windows Process.</param>
158+
/// <returns>The Parent Process of the Process.</returns>
159+
public static Process ParentProcess(this Process process)
160+
{
161+
int parentPid = 0;
162+
int processPid = process.Id;
163+
uint TH32CS_SNAPPROCESS = 2;
164+
165+
// Take snapshot of processes
166+
IntPtr hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
167+
168+
if (hSnapshot == IntPtr.Zero)
169+
{
170+
return null;
171+
}
172+
173+
PROCESSENTRY32 procInfo = new PROCESSENTRY32();
174+
175+
procInfo.dwSize = (uint)Marshal.SizeOf(typeof(PROCESSENTRY32));
176+
177+
// Read first
178+
if (Process32First(hSnapshot, ref procInfo) == false)
179+
{
180+
return null;
181+
}
182+
183+
// Loop through the snapshot
184+
do
185+
{
186+
// If it's me, then ask for my parent.
187+
if (processPid == procInfo.th32ProcessID)
188+
{
189+
parentPid = (int)procInfo.th32ParentProcessID;
190+
}
191+
}
192+
while (parentPid == 0 && Process32Next(hSnapshot, ref procInfo)); // Read next
193+
194+
if (parentPid > 0)
195+
{
196+
return Process.GetProcessById(parentPid);
197+
}
198+
else
199+
{
200+
return null;
201+
}
202+
}
203+
204+
/// <summary>
205+
/// Takes a snapshot of the specified processes, as well as the heaps,
206+
/// modules, and threads used by these processes.
207+
/// </summary>
208+
/// <param name="dwFlags">
209+
/// The portions of the system to be included in the snapshot.
210+
/// </param>
211+
/// <param name="th32ProcessID">
212+
/// The process identifier of the process to be included in the snapshot.
213+
/// </param>
214+
/// <returns>
215+
/// If the function succeeds, it returns an open handle to the specified snapshot.
216+
/// If the function fails, it returns INVALID_HANDLE_VALUE.
217+
/// </returns>
218+
[DllImport("kernel32.dll", SetLastError = true)]
219+
private static extern IntPtr CreateToolhelp32Snapshot(uint dwFlags, uint th32ProcessID);
220+
221+
/// <summary>
222+
/// Retrieves information about the first process encountered in a system snapshot.
223+
/// </summary>
224+
/// <param name="hSnapshot">A handle to the snapshot.</param>
225+
/// <param name="lppe">A pointer to a PROCESSENTRY32 structure.</param>
226+
/// <returns>
227+
/// Returns TRUE if the first entry of the process list has been copied to the buffer.
228+
/// Returns FALSE otherwise.
229+
/// </returns>
230+
[DllImport("kernel32.dll")]
231+
private static extern bool Process32First(IntPtr hSnapshot, ref PROCESSENTRY32 lppe);
232+
233+
/// <summary>
234+
/// Retrieves information about the next process recorded in a system snapshot.
235+
/// </summary>
236+
/// <param name="hSnapshot">A handle to the snapshot.</param>
237+
/// <param name="lppe">A pointer to a PROCESSENTRY32 structure.</param>
238+
/// <returns>
239+
/// Returns TRUE if the next entry of the process list has been copied to the buffer.
240+
/// Returns FALSE otherwise.</returns>
241+
[DllImport("kernel32.dll")]
242+
private static extern bool Process32Next(IntPtr hSnapshot, ref PROCESSENTRY32 lppe);
243+
244+
/// <summary>
245+
/// Describes an entry from a list of the processes residing
246+
/// in the system address space when a snapshot was taken.
247+
/// </summary>
248+
[StructLayout(LayoutKind.Sequential)]
249+
private struct PROCESSENTRY32
250+
{
251+
public uint dwSize;
252+
public uint cntUsage;
253+
public uint th32ProcessID;
254+
public IntPtr th32DefaultHeapID;
255+
public uint th32ModuleID;
256+
public uint cntThreads;
257+
public uint th32ParentProcessID;
258+
public int pcPriClassBase;
259+
public uint dwFlags;
260+
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
261+
public string szExeFile;
262+
}
263+
}
151264
}

wv2util/RuntimeList.cs

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,15 @@ public string Version
2121
{
2222
get
2323
{
24-
return FileVersionInfo.GetVersionInfo(ExePath).FileVersion;
24+
try
25+
{
26+
return FileVersionInfo.GetVersionInfo(ExePath).FileVersion;
27+
}
28+
catch (System.IO.FileNotFoundException e)
29+
{
30+
// Somehow this is possible.
31+
return "FileNotFound";
32+
}
2533
}
2634
}
2735
public string Channel
@@ -57,7 +65,7 @@ public class RuntimeList : ObservableCollection<RuntimeEntry>
5765
{
5866
public RuntimeList()
5967
{
60-
FromDisk();
68+
// FromDisk();
6169
}
6270

6371
public void FromDisk()
@@ -76,24 +84,33 @@ public void FromDisk()
7684
}
7785
private static IEnumerable<RuntimeEntry> GetInstalledRuntimes()
7886
{
79-
string microsoftRootPath = Environment.GetEnvironmentVariable("LOCALAPPDATA") + "\\Microsoft\\";
80-
var potentialParents = Directory.GetDirectories(microsoftRootPath).Where(path => path.Contains("Edge"));
81-
82-
foreach (string potentialParent in potentialParents)
87+
string[] rootPaths =
8388
{
84-
string[] foundExes = null;
85-
try
86-
{
87-
foundExes = Directory.GetFiles(potentialParent, "msedgewebview2.exe", SearchOption.AllDirectories);
88-
}
89-
catch (UnauthorizedAccessException e)
90-
{
91-
Debug.WriteLine("Ignoring unauthorized access exception while searching for WebView2 runtimes: " + e.Message);
92-
}
89+
Environment.GetEnvironmentVariable("LOCALAPPDATA") + "\\Microsoft\\",
90+
Environment.GetEnvironmentVariable("ProgramFiles(x86)") + "\\Microsoft\\",
91+
Environment.GetEnvironmentVariable("ProgramFiles") + "\\Microsoft\\"
92+
};
9393

94-
foreach (string path in foundExes)
94+
foreach (string rootPath in rootPaths)
95+
{
96+
var potentialParents = Directory.GetDirectories(rootPath).Where(path => path.Contains("Edge"));
97+
98+
foreach (string potentialParent in potentialParents)
9599
{
96-
yield return new RuntimeEntry(path);
100+
string[] foundExes = null;
101+
try
102+
{
103+
foundExes = Directory.GetFiles(potentialParent, "msedgewebview2.exe", SearchOption.AllDirectories);
104+
}
105+
catch (UnauthorizedAccessException e)
106+
{
107+
Debug.WriteLine("Ignoring unauthorized access exception while searching for WebView2 runtimes: " + e.Message);
108+
}
109+
110+
foreach (string path in foundExes)
111+
{
112+
yield return new RuntimeEntry(path);
113+
}
97114
}
98115
}
99116
}

0 commit comments

Comments
 (0)