Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable nullable on AttachVS #3671

Merged
merged 3 commits into from
May 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 52 additions & 40 deletions src/AttachVS/AttachVs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
using System.Runtime.InteropServices.ComTypes;
using System.Threading;

#nullable disable

namespace Microsoft.TestPlatform.AttachVS;

internal class DebuggerUtility
Expand All @@ -25,20 +23,23 @@ internal static bool AttachVSToProcess(int? pid, int? vsPid)
Trace($"FAIL: Pid is null.");
return false;
}

var process = Process.GetProcessById(pid.Value);
Trace($"Starting with pid '{pid}({process?.ProcessName})', and vsPid '{vsPid}'");
Trace($"Starting with pid '{pid}({process.ProcessName})', and vsPid '{vsPid}'");
Trace($"Using pid: {pid} to get parent VS.");
var vs = GetVsFromPid(Process.GetProcessById(vsPid ?? process.Id));

if (vs != null)
{
Trace($"Parent VS is {vs.ProcessName} ({vs.Id}).");
AttachTo(process, vs);
return true;
}
else
{
Trace($"Parent VS not found, finding the first VS that started.");
var processes = Process.GetProcesses().Where(p => p.ProcessName == "devenv").Select(p =>

Trace($"Parent VS not found, finding the first VS that started.");
var firstVs = Process.GetProcesses()
.Where(p => p.ProcessName == "devenv")
.Select(p =>
{
try
{
Expand All @@ -48,19 +49,26 @@ internal static bool AttachVSToProcess(int? pid, int? vsPid)
{
return null;
}
}).Where(p => p != null && !p.HasExited).OrderBy(p => p.StartTime).ToList();
})
.Where(p => p != null && !p.HasExited)
.OrderBy(p => p!.StartTime)
.FirstOrDefault();

var firstVs = processes.FirstOrDefault();
if (firstVs != null)
{
Trace($"Found VS {firstVs.Process.Id}");
AttachTo(process, firstVs.Process);
return true;
}
return true;

Trace("Could not find any started VS.");
}
catch (Exception ex)
{
Trace($"ERROR: {ex}, {ex.StackTrace}");
return false;
}

return false;
}

private static void AttachTo(Process process, Process vs)
Expand All @@ -79,9 +87,9 @@ private static void AttachTo(Process process, Process vs)

private static bool AttachVs(Process vs, int pid)
{
IBindCtx bindCtx = null;
IRunningObjectTable runninObjectTable = null;
IEnumMoniker enumMoniker = null;
IBindCtx? bindCtx = null;
IRunningObjectTable? runninObjectTable = null;
IEnumMoniker? enumMoniker = null;
try
{
var r = CreateBindCtx(0, out bindCtx);
Expand Down Expand Up @@ -183,18 +191,18 @@ private static bool AttachVs(Process vs, int pid)
}
}

private static Process GetVsFromPid(Process process)
private static Process? GetVsFromPid(Process process)
{
var parent = process;
while (!IsVsOrNull(parent))
{
parent = GetParentProcess(parent);
parent = GetParentProcess(parent!);
}

return parent;
}

private static bool IsVsOrNull(Process process)
private static bool IsVsOrNull(Process? process)
{
if (process == null)
{
Expand All @@ -219,57 +227,61 @@ private static bool IsCorrectParent(Process currentProcess, Process parent)
{
try
{
// Parent needs to start before the child, otherwise it might be a different process
// Parent needs to start before the child, otherwise it might be a different process
// that is just reusing the same PID.
if (parent.StartTime <= currentProcess.StartTime)
{
return true;
}

Trace($"Process {parent.ProcessName} ({parent.Id}) is not a valid parent because it started after the current process.");
return false;
}
catch
{
// Access denied or process exited while we were holding the Process object.
return false;
}

return false;
}

private static Process GetParentProcess(Process process)
private static Process? GetParentProcess(Process process)
{
int id;
try
{
var handle = process.Handle;
var res = NtQueryInformationProcess(handle, 0, out var pbi, Marshal.SizeOf<PROCESS_BASIC_INFORMATION>(), out int size);

var p = res != 0 ? -1 : pbi.InheritedFromUniqueProcessId.ToInt32();

id = p;
}
catch
{
id = -1;
}

Process parent = null;
int id = GetParentProcessId(process);
if (id != -1)
{
try
{
parent = Process.GetProcessById(id);
var parent = Process.GetProcessById(id);
if (IsCorrectParent(process, parent))
return parent;
}
catch
{
// throws when parent no longer runs
Evangelink marked this conversation as resolved.
Show resolved Hide resolved
}
}

return IsCorrectParent(process, parent) ? parent : null;
Evangelink marked this conversation as resolved.
Show resolved Hide resolved
return null;

static int GetParentProcessId(Process process)
{
try
{
var handle = process.Handle;
var res = NtQueryInformationProcess(handle, 0, out var pbi, Marshal.SizeOf<PROCESS_BASIC_INFORMATION>(), out int size);

var p = res != 0 ? -1 : pbi.InheritedFromUniqueProcessId.ToInt32();

return p;
}
catch
{
return -1;
}
}
}

private static void Trace(string message, [CallerMemberName] string methodName = null)
private static void Trace(string message, [CallerMemberName] string? methodName = null)
{
System.Diagnostics.Trace.WriteLine($"[AttachVS]{methodName}: {message}");
}
Expand Down
4 changes: 1 addition & 3 deletions src/AttachVS/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@
using System.Diagnostics;
using System.Linq;

#nullable disable

namespace Microsoft.TestPlatform.AttachVS;

internal class Program
{
static void Main(string[] args)
static void Main(string[] args!!)
{
Trace.Listeners.Add(new ConsoleTraceListener());

Expand Down