Skip to content
Closed
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
25 changes: 25 additions & 0 deletions src/System.Management.Automation/CoreCLR/CorePsStub.cs
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,31 @@ public override bool IsInvalid
}
}

/// <summary>
/// Stub for SafeHandleMinusOneIsInvalid
/// </summary>
public abstract class SafeHandleMinusOneIsInvalid : SafeHandle
{
/// <summary>
/// Constructor
/// </summary>
protected SafeHandleMinusOneIsInvalid(bool ownsHandle)
: base(new IntPtr(-1), ownsHandle)
{
}

/// <summary>
/// IsInvalid
/// </summary>
public override bool IsInvalid
{
get
{
return handle == new IntPtr(-1);
}
}
}

#endregion SafeHandle_Related

#region Misc_Types
Expand Down
6 changes: 6 additions & 0 deletions src/System.Management.Automation/utils/PInvokeDllNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ internal static class PinvokeDllNames
internal const string ReadConsoleInputDllName = "api-ms-win-core-console-l1-1-0.dll"; /*117*/
internal const string GetVersionExDllName = "api-ms-win-core-sysinfo-l1-1-0.dll"; /*118*/
internal const string FormatMessageDllName = "api-ms-win-core-localization-l1-2-0.dll"; /*119*/
internal const string CreateToolhelp32SnapshotDllName = "api-ms-win-core-toolhelp-l1-1-0"; /*120*/
internal const string Process32FirstDllName = "api-ms-win-core-toolhelp-l1-1-0"; /*121*/
internal const string Process32NextDllName = "api-ms-win-core-toolhelp-l1-1-0"; /*122*/
#else
internal const string QueryDosDeviceDllName = "kernel32.dll"; /*1*/
internal const string CreateSymbolicLinkDllName = "kernel32.dll"; /*2*/
Expand Down Expand Up @@ -251,6 +254,9 @@ internal static class PinvokeDllNames
internal const string ReadConsoleInputDllName = "kernel32.dll"; /*117*/
internal const string GetVersionExDllName = "kernel32.dll"; /*118*/
internal const string FormatMessageDllName = "wevtapi.dll"; /*119*/
internal const string CreateToolhelp32SnapshotDllName = "kernel32.dll"; /*120*/
internal const string Process32FirstDllName = "kernel32.dll"; /*121*/
internal const string Process32NextDllName = "kernel32.dll"; /*122*/
#endif
}
}
62 changes: 62 additions & 0 deletions src/System.Management.Automation/utils/PlatformInvokes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,68 @@ internal enum StandardHandleId : uint
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr GetStdHandle(uint handleId);

#endif

#endregion

#region CreateToolhelp32Snapshot

#if !UNIX

[DllImport(PinvokeDllNames.CreateToolhelp32SnapshotDllName, SetLastError = true)]
internal static extern SafeSnapshotHandle CreateToolhelp32Snapshot(SnapshotFlags flags, uint id);
[DllImport(PinvokeDllNames.Process32FirstDllName, SetLastError = true)]
internal static extern bool Process32First(SafeSnapshotHandle hSnapshot, ref PROCESSENTRY32 lppe);
[DllImport(PinvokeDllNames.Process32NextDllName, SetLastError = true)]
internal static extern bool Process32Next(SafeSnapshotHandle hSnapshot, ref PROCESSENTRY32 lppe);

internal sealed class SafeSnapshotHandle : SafeHandleMinusOneIsInvalid
{
internal SafeSnapshotHandle() : base(true)
{
}

[SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
internal SafeSnapshotHandle(IntPtr handle) : base(true)
{
base.SetHandle(handle);
}

protected override bool ReleaseHandle()
{
return CloseHandle(base.handle);
}
}

[Flags]
internal enum SnapshotFlags : uint
{
HeapList = 0x00000001,
Process = 0x00000002,
Thread = 0x00000004,
Module = 0x00000008,
Module32 = 0x00000010,
All = (HeapList | Process | Thread | Module),
Inherit = 0x80000000,
NoHeaps = 0x40000000
}
[StructLayout(LayoutKind.Sequential)]
internal struct PROCESSENTRY32
{
public uint dwSize;
public uint cntUsage;
public uint th32ProcessID;
public IntPtr th32DefaultHeapID;
public uint th32ModuleID;
public uint cntThreads;
public uint th32ParentProcessID;
public int pcPriClassBase;
public uint dwFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szExeFile;
};

internal const int ERROR_NO_MORE_FILES = 0x12;

#endif

#endregion
Expand Down
87 changes: 47 additions & 40 deletions src/System.Management.Automation/utils/PsUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
Expand All @@ -16,7 +15,10 @@
using Microsoft.Win32;
using System.Collections.Generic;
using System.Management.Automation.Language;
using Microsoft.Management.Infrastructure;
#if CORECLR
// Use stubs for SerializableAttribute, SecurityPermissionAttribute, ReliabilityContractAttribute and ISerializable related types.
using Microsoft.PowerShell.CoreClr.Stubs;
#endif

namespace System.Management.Automation
{
Expand Down Expand Up @@ -91,57 +93,62 @@ internal static ProcessModule GetMainModule(Process targetProcess)
/// <summary>
/// Retrieve the parent process of a process.
///
/// This is an extremely expensive operation, as WMI
/// needs to work with an ugly Win32 API. The Win32 API
/// creates a snapshot of every process in the system, which
/// you then need to iterate through to find your process and
/// its parent PID.
///
/// Also, since this is PID based, this API is only reliable
/// when the process has not yet exited.
/// Previously this code used WMI, but WMI is causing a CPU spike whenever the query gets called as it results in
/// tzres.dll and tzres.mui.dll being loaded into every process to conver the time information to local format.
/// For perf reasons, we result to P/Invoke.
/// </summary>
///
/// <param name="current">The process we want to find the
/// parent of</param>
internal static Process GetParentProcess(Process current)
{
string wmiQuery = String.Format(CultureInfo.CurrentCulture,
"Select * From Win32_Process Where Handle='{0}'",
current.Id);

using (CimSession cimSession = CimSession.Create(null))
{
IEnumerable<CimInstance> processCollection =
cimSession.QueryInstances("root/cimv2", "WQL", wmiQuery);

int parentPid =
processCollection.Select(
cimProcess =>
Convert.ToInt32(cimProcess.CimInstanceProperties["ParentProcessId"].Value,
CultureInfo.CurrentCulture)).FirstOrDefault();
int parentPid = 0;

if (parentPid == 0)
return null;
PlatformInvokes.PROCESSENTRY32 pe32 = new PlatformInvokes.PROCESSENTRY32 { };
pe32.dwSize = (uint)ClrFacade.SizeOf<PlatformInvokes.PROCESSENTRY32>();

try
using (PlatformInvokes.SafeSnapshotHandle hSnapshot = PlatformInvokes.CreateToolhelp32Snapshot(PlatformInvokes.SnapshotFlags.Process, (uint)current.Id))
{
if (!PlatformInvokes.Process32First(hSnapshot, ref pe32))
{
Process returnProcess = Process.GetProcessById(parentPid);

// Ensure the process started before the current
// process, as it could have gone away and had the
// PID recycled.
if (returnProcess.StartTime <= current.StartTime)
return returnProcess;
else
int errno = Marshal.GetLastWin32Error();
if (errno == PlatformInvokes.ERROR_NO_MORE_FILES)
{
return null;
}
}
catch (ArgumentException)
do
{
// GetProcessById throws an ArgumentException when
// you reach the top of the chain -- Explorer.exe
// has a parent process, but you cannot retrieve it.
if (pe32.th32ProcessID == (uint)current.Id)
{
parentPid = (int)pe32.th32ParentProcessID;
break;
}

} while (PlatformInvokes.Process32Next(hSnapshot, ref pe32));
}

if (parentPid == 0)
return null;

try
{
Process returnProcess = Process.GetProcessById(parentPid);

// Ensure the process started before the current
// process, as it could have gone away and had the
// PID recycled.
if (returnProcess.StartTime <= current.StartTime)
return returnProcess;
else
return null;
}
}
catch (ArgumentException)
{
// GetProcessById throws an ArgumentException when
// you reach the top of the chain -- Explorer.exe
// has a parent process, but you cannot retrieve it.
return null;
}
}

Expand Down