You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#change Adding better (working) versions of Process.GetProcesses(), Process.Name and Process.Modules to BuildHostPlatformAbstraction #change ShouldDoHotReload will now use those new methods to learn if the target is running #change On the Mac, we can't use 'Added' filesystem event to know if new binaries have been compiled as it reports temporary linker files instead of the final binaries which are only reported by 'Modified' event. [CL 2321016 by Robert Manuszewski in Main branch]
419 lines
11 KiB
C#
419 lines
11 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.IO;
|
|
using System.Diagnostics;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace UnrealBuildTool
|
|
{
|
|
/// <summary>
|
|
/// Host platform abstraction
|
|
/// </summary>
|
|
public abstract class BuildHostPlatform
|
|
{
|
|
private static BuildHostPlatform CurrentPlatform;
|
|
private static bool bIsMac = File.Exists("/System/Library/CoreServices/SystemVersion.plist");
|
|
|
|
/// <summary>
|
|
/// Returns the name of platform UBT is running on. Internal use only. If you need access this this enum, use BuildHostPlatform.Current.Platform */
|
|
/// </summary>
|
|
private static UnrealTargetPlatform GetRuntimePlatform()
|
|
{
|
|
PlatformID Platform = Environment.OSVersion.Platform;
|
|
switch (Platform)
|
|
{
|
|
case PlatformID.Win32NT:
|
|
return UnrealTargetPlatform.Win64;
|
|
case PlatformID.Unix:
|
|
return bIsMac ? UnrealTargetPlatform.Mac : UnrealTargetPlatform.Linux;
|
|
case PlatformID.MacOSX:
|
|
return UnrealTargetPlatform.Mac;
|
|
default:
|
|
throw new BuildException("Unhandled runtime platform " + Platform);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Host platform singleton.
|
|
/// </summary>
|
|
static public BuildHostPlatform Current
|
|
{
|
|
get
|
|
{
|
|
if (CurrentPlatform == null)
|
|
{
|
|
switch (GetRuntimePlatform())
|
|
{
|
|
case UnrealTargetPlatform.Win64:
|
|
CurrentPlatform = new WindowsBuildHostPlatform();
|
|
break;
|
|
case UnrealTargetPlatform.Mac:
|
|
CurrentPlatform = new MacBuildHostPlatform();
|
|
break;
|
|
case UnrealTargetPlatform.Linux:
|
|
CurrentPlatform = new LinuxBuildHostPlatform();
|
|
break;
|
|
}
|
|
}
|
|
return CurrentPlatform;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the current host platform type.
|
|
/// </summary>
|
|
abstract public UnrealTargetPlatform Platform { get; }
|
|
|
|
/// <summary>
|
|
/// Checks the API version of a dynamic library
|
|
/// </summary>
|
|
/// <param name="Filename">Filename of the library</param>
|
|
/// <returns>API version of -1 if not found.</returns>
|
|
abstract public int GetDllApiVersion(string Filename);
|
|
|
|
/// <summary>
|
|
/// Class that holds information about a running process
|
|
/// </summary>
|
|
public class ProcessInfo
|
|
{
|
|
/// <summary>
|
|
/// Process ID
|
|
/// </summary>
|
|
public int PID;
|
|
/// <summary>
|
|
/// Name of the process
|
|
/// </summary>
|
|
public string Name;
|
|
/// <summary>
|
|
/// Filename of the process binary
|
|
/// </summary>
|
|
public string Filename;
|
|
|
|
public ProcessInfo(int InPID, string InName, string InFilename, string[] InModules)
|
|
{
|
|
PID = InPID;
|
|
Name = InName;
|
|
Filename = InFilename;
|
|
}
|
|
public ProcessInfo(Process Proc)
|
|
{
|
|
PID = Proc.Id;
|
|
Name = Proc.ProcessName;
|
|
Filename = Path.GetFullPath(Proc.MainModule.FileName);
|
|
}
|
|
public override string ToString()
|
|
{
|
|
return String.Format("{0}, {1}", Name, Filename);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets all currently running processes.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public virtual ProcessInfo[] GetProcesses()
|
|
{
|
|
var AllProcesses = Process.GetProcesses();
|
|
var Result = new List<ProcessInfo>(AllProcesses.Length);
|
|
foreach (var Proc in AllProcesses)
|
|
{
|
|
try
|
|
{
|
|
if (!Proc.HasExited)
|
|
{
|
|
Result.Add(new ProcessInfo(Proc));
|
|
}
|
|
} catch {}
|
|
}
|
|
return Result.ToArray();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a process by name.
|
|
/// </summary>
|
|
/// <param name="Name">Name of the process to get information for.</param>
|
|
/// <returns></returns>
|
|
public virtual ProcessInfo GetProcessByName(string Name)
|
|
{
|
|
var AllProcess = GetProcesses();
|
|
foreach (var Info in AllProcess)
|
|
{
|
|
if (Info.Name == Name)
|
|
{
|
|
return Info;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets processes by name.
|
|
/// </summary>
|
|
/// <param name="Name">Name of the process to get information for.</param>
|
|
/// <returns></returns>
|
|
public virtual ProcessInfo[] GetProcessesByName(string Name)
|
|
{
|
|
var AllProcess = GetProcesses();
|
|
var Result = new List<ProcessInfo>();
|
|
foreach (var Info in AllProcess)
|
|
{
|
|
if (Info.Name == Name)
|
|
{
|
|
Result.Add(Info);
|
|
}
|
|
}
|
|
return Result.ToArray();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the filenames of all modules associated with a process
|
|
/// </summary>
|
|
/// <param name="PID">Process ID</param>
|
|
/// <param name="Filename">Filename of the binary associated with the process.</param>
|
|
/// <returns>An array of all module filenames associated with the process. Can be empty of the process is no longer running.</returns>
|
|
public virtual string[] GetProcessModules(int PID, string Filename)
|
|
{
|
|
List<string> Modules = new List<string>();
|
|
try
|
|
{
|
|
var Proc = Process.GetProcessById(PID);
|
|
if (Proc != null)
|
|
{
|
|
foreach (var Module in Proc.Modules.Cast<System.Diagnostics.ProcessModule>())
|
|
{
|
|
Modules.Add(Path.GetFullPath(Module.FileName));
|
|
}
|
|
}
|
|
}
|
|
catch { }
|
|
return Modules.ToArray();
|
|
}
|
|
}
|
|
|
|
class WindowsBuildHostPlatform : BuildHostPlatform
|
|
{
|
|
public override UnrealTargetPlatform Platform
|
|
{
|
|
get { return UnrealTargetPlatform.Win64; }
|
|
}
|
|
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|
static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags);
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|
static extern IntPtr FindResource(IntPtr hModule, string lpName, string lpType);
|
|
[DllImport("kernel32.dll")]
|
|
static extern IntPtr FindResource(IntPtr hModule, IntPtr lpID, IntPtr lpType);
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|
static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResInfo);
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|
static extern uint SizeofResource(IntPtr hModule, IntPtr hResInfo);
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|
static extern IntPtr LockResource(IntPtr hResData);
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|
static extern void UnlockResource(IntPtr hResInfo);
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|
static extern void FreeLibrary(IntPtr hModule);
|
|
|
|
[Flags]
|
|
enum LoadLibraryFlags : uint
|
|
{
|
|
DONT_RESOLVE_DLL_REFERENCES = 0x00000001,
|
|
LOAD_LIBRARY_AS_DATAFILE = 0x00000002,
|
|
LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008,
|
|
LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010,
|
|
LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020,
|
|
LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040,
|
|
LOAD_LIBRARY_REQUIRE_SIGNED_TARGET = 0x00000080
|
|
}
|
|
|
|
enum ResourceType
|
|
{
|
|
RT_CURSOR = 1,
|
|
RT_BITMAP = 2,
|
|
RT_ICON = 3,
|
|
RT_MENU = 4,
|
|
RT_DIALOG = 5,
|
|
RT_STRING = 6,
|
|
RT_FONTDIR = 7,
|
|
RT_FONT = 8,
|
|
RT_ACCELERATOR = 9,
|
|
RT_RCDATA = 10,
|
|
RT_MESSAGETABLE = 11
|
|
}
|
|
|
|
public override int GetDllApiVersion(string Filename)
|
|
{
|
|
int Result = -1;
|
|
|
|
try
|
|
{
|
|
const int ID_MODULE_API_VERSION_RESOURCE = 191;
|
|
|
|
// Retrieves the embedded API version from a DLL
|
|
IntPtr hModule = LoadLibraryEx(Filename, IntPtr.Zero, (uint)LoadLibraryFlags.LOAD_LIBRARY_AS_DATAFILE);
|
|
if (hModule != IntPtr.Zero)
|
|
{
|
|
IntPtr hResInfo = FindResource(hModule, new IntPtr(ID_MODULE_API_VERSION_RESOURCE), new IntPtr((int)ResourceType.RT_RCDATA));
|
|
if (hResInfo != IntPtr.Zero)
|
|
{
|
|
IntPtr hResGlobal = LoadResource(hModule, hResInfo);
|
|
if (hResGlobal != IntPtr.Zero)
|
|
{
|
|
IntPtr pResData = LockResource(hResGlobal);
|
|
if (pResData != IntPtr.Zero)
|
|
{
|
|
uint Length = SizeofResource(hModule, hResInfo);
|
|
if (Length > 0)
|
|
{
|
|
var Str = Marshal.PtrToStringAnsi(pResData);
|
|
Result = Int32.Parse(Str);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
FreeLibrary(hModule);
|
|
}
|
|
}
|
|
catch (Exception Ex)
|
|
{
|
|
Log.TraceWarning("Failed to get DLL API version for {0}. Exception: {1}", Filename, Ex.Message);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
}
|
|
|
|
class MacBuildHostPlatform : BuildHostPlatform
|
|
{
|
|
public override UnrealTargetPlatform Platform
|
|
{
|
|
get { return UnrealTargetPlatform.Mac; }
|
|
}
|
|
|
|
public override int GetDllApiVersion(string Filename)
|
|
{
|
|
// @TODO: Implement GetDllApiVersion for Mac
|
|
return -1;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Currently Mono returns incomplete process names in Process.GetProcesses() so we need to parse 'ps' output.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public override ProcessInfo[] GetProcesses()
|
|
{
|
|
var Result = new List<ProcessInfo>();
|
|
|
|
var StartInfo = new ProcessStartInfo ();
|
|
StartInfo.FileName = "ps";
|
|
StartInfo.Arguments = "-eaw -o pid,comm";
|
|
StartInfo.CreateNoWindow = true;
|
|
StartInfo.UseShellExecute = false;
|
|
StartInfo.RedirectStandardOutput = true;
|
|
|
|
var Proc = new Process ();
|
|
Proc.StartInfo = StartInfo;
|
|
try
|
|
{
|
|
Proc.Start();
|
|
Proc.WaitForExit();
|
|
for (string Line = Proc.StandardOutput.ReadLine(); Line != null; Line = Proc.StandardOutput.ReadLine())
|
|
{
|
|
Line = Line.Trim();
|
|
int PIDEnd = Line.IndexOf(' ');
|
|
var PIDString = Line.Substring(0, PIDEnd);
|
|
if (PIDString != "PID")
|
|
{
|
|
var Filename = Line.Substring(PIDEnd + 1);
|
|
var Pid = Int32.Parse(PIDString);
|
|
try
|
|
{
|
|
var ExistingProc = Process.GetProcessById(Pid);
|
|
if (ExistingProc != null && ExistingProc.HasExited == false)
|
|
{
|
|
var ProcInfo = new ProcessInfo(ExistingProc);
|
|
ProcInfo.Name = Path.GetFileName(Filename);
|
|
ProcInfo.Filename = Filename;
|
|
Result.Add(ProcInfo);
|
|
}
|
|
} catch {}
|
|
}
|
|
}
|
|
|
|
}
|
|
catch {}
|
|
return Result.ToArray();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Currently Mono returns incomplete list of modules for Process.Modules so we need to parse vmmap output.
|
|
/// </summary>
|
|
/// <param name="PID"></param>
|
|
/// <param name="Filename"></param>
|
|
/// <returns></returns>
|
|
public override string[] GetProcessModules(int PID, string Filename)
|
|
{
|
|
HashSet<string> Modules = new HashSet<string>();
|
|
// Add the process file name to the module list. This is to make it compatible with the results of Process.Modules on Windows.
|
|
Modules.Add(Filename);
|
|
|
|
var StartInfo = new ProcessStartInfo();
|
|
StartInfo.FileName = "vmmap";
|
|
StartInfo.Arguments = String.Format("{0} -w", PID);
|
|
StartInfo.CreateNoWindow = true;
|
|
StartInfo.UseShellExecute = false;
|
|
StartInfo.RedirectStandardOutput = true;
|
|
|
|
var Proc = new Process();
|
|
Proc.StartInfo = StartInfo;
|
|
try
|
|
{
|
|
Proc.Start();
|
|
// Start processing output before vmmap exits otherwise it's going to hang
|
|
while (!Proc.WaitForExit(1))
|
|
{
|
|
ProcessVMMapOutput(Proc, Modules);
|
|
}
|
|
ProcessVMMapOutput(Proc, Modules);
|
|
}
|
|
catch { }
|
|
return Modules.ToArray();
|
|
}
|
|
private void ProcessVMMapOutput(Process Proc, HashSet<string> Modules)
|
|
{
|
|
for (string Line = Proc.StandardOutput.ReadLine(); Line != null; Line = Proc.StandardOutput.ReadLine())
|
|
{
|
|
Line = Line.Trim();
|
|
if (Line.EndsWith(".dylib"))
|
|
{
|
|
const int SharingModeLength = 6;
|
|
int SMStart = Line.IndexOf("SM=");
|
|
int PathStart = SMStart + SharingModeLength;
|
|
string Module = Line.Substring(PathStart).Trim();
|
|
if (!Modules.Contains(Module))
|
|
{
|
|
Modules.Add(Module);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class LinuxBuildHostPlatform : BuildHostPlatform
|
|
{
|
|
public override UnrealTargetPlatform Platform
|
|
{
|
|
get { return UnrealTargetPlatform.Linux; }
|
|
}
|
|
|
|
public override int GetDllApiVersion(string Filename)
|
|
{
|
|
// @TODO: Implement GetDllApiVersion for Linux
|
|
return -1;
|
|
}
|
|
}
|
|
}
|