Advertisement
heinrich23

Win32.NativeApi.InternalWrapper

Sep 18th, 2024
2,590
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 67.13 KB | Source Code | 0 0
  1. #define CLR2COMPATIBILITY
  2. using Microsoft.Win32.SafeHandles;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Diagnostics.CodeAnalysis;
  6. using System.Diagnostics;
  7. using System.Globalization;
  8. using System.IO;
  9. using System.Reflection;
  10. using System.Runtime.InteropServices;
  11. using System.Security;
  12. using System.Text;
  13. using System.Threading;
  14. using System.Threading.Tasks;
  15.  
  16. namespace Win32.NativeApi
  17. {
  18.  
  19.     /// <summary>
  20.     /// InternalWrapper contains wrapper methods and inner classes for User32, Kernel32 and GDI32 Windows Core API calls
  21.     /// </summary>
  22.     [SuppressUnmanagedCodeSecurityAttribute]
  23.     internal static class InternalWrapper
  24.     {
  25.  
  26.         #region Constants
  27.  
  28.         internal const uint ERROR_INSUFFICIENT_BUFFER = 0x8007007A;
  29.         internal const uint STARTUP_LOADER_SAFEMODE = 0x10;
  30.         internal const uint S_OK = 0x0;
  31.         internal const uint S_FALSE = 0x1;
  32.         internal const uint ERROR_ACCESS_DENIED = 0x5;
  33.         internal const uint ERROR_FILE_NOT_FOUND = 0x80070002;
  34.         internal const uint FUSION_E_PRIVATE_ASM_DISALLOWED = 0x80131044; // Tried to find unsigned assembly in GAC
  35.         internal const uint RUNTIME_INFO_DONT_SHOW_ERROR_DIALOG = 0x40;
  36.         internal const uint FILE_TYPE_CHAR = 0x0002;
  37.         internal const Int32 STD_OUTPUT_HANDLE = -11;
  38.         internal const uint RPC_S_CALLPENDING = 0x80010115;
  39.         internal const uint E_ABORT = (uint)0x80004004;
  40.  
  41.         internal const int FILE_ATTRIBUTE_READONLY = 0x00000001;
  42.         internal const int FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
  43.         internal const int FILE_ATTRIBUTE_REPARSE_POINT = 0x00000400;
  44.  
  45.         private const string kernel32Dll = "kernel32.dll";
  46.         private const string mscoreeDLL = "mscoree.dll";
  47.  
  48. #if FEATURE_HANDLEREF
  49.         internal static HandleRef NullHandleRef = new HandleRef(null, IntPtr.Zero);
  50. #endif
  51.  
  52.         internal static IntPtr NullIntPtr = new IntPtr(0);
  53.  
  54.         // As defined in winnt.h:
  55.         internal const ushort PROCESSOR_ARCHITECTURE_INTEL = 0;
  56.         internal const ushort PROCESSOR_ARCHITECTURE_ARM = 5;
  57.         internal const ushort PROCESSOR_ARCHITECTURE_IA64 = 6;
  58.         internal const ushort PROCESSOR_ARCHITECTURE_AMD64 = 9;
  59.  
  60.         internal const uint INFINITE = 0xFFFFFFFF;
  61.         internal const uint WAIT_ABANDONED_0 = 0x00000080;
  62.         internal const uint WAIT_OBJECT_0 = 0x00000000;
  63.         internal const uint WAIT_TIMEOUT = 0x00000102;
  64.  
  65. #if FEATURE_CHARSET_AUTO
  66.         internal const CharSet AutoOrUnicode = CharSet.Auto;
  67. #else
  68.         internal const CharSet AutoOrUnicode = CharSet.Unicode;
  69. #endif
  70.  
  71.         #endregion
  72.  
  73.         #region Enums
  74.  
  75.         /// <summary>
  76.         /// enum PROCESSINFOCLASS
  77.         /// </summary>
  78.         private enum PROCESSINFOCLASS : int
  79.         {
  80.  
  81.             ProcessBasicInformation = 0,
  82.             ProcessQuotaLimits,
  83.             ProcessIoCounters,
  84.             ProcessVmCounters,
  85.             ProcessTimes,
  86.             ProcessBasePriority,
  87.             ProcessRaisePriority,
  88.             ProcessDebugPort,
  89.             ProcessExceptionPort,
  90.             ProcessAccessToken,
  91.             ProcessLdtInformation,
  92.             ProcessLdtSize,
  93.             ProcessDefaultHardErrorMode,
  94.             ProcessIoPortHandlers, // Note: this is kernel mode only
  95.             ProcessPooledUsageAndLimits,
  96.             ProcessWorkingSetWatch,
  97.             ProcessUserModeIOPL,
  98.             ProcessEnableAlignmentFaultFixup,
  99.             ProcessPriorityClass,
  100.             ProcessWx86Information,
  101.             ProcessHandleCount,
  102.             ProcessAffinityMask,
  103.             ProcessPriorityBoost,
  104.             MaxProcessInfoClass
  105.  
  106.         };
  107.  
  108.         /// <summary>
  109.         /// enum eDesiredAccess process accessing flags
  110.         /// </summary>
  111.         private enum eDesiredAccess : int
  112.         {
  113.  
  114.             DELETE = 0x00010000,
  115.             READ_CONTROL = 0x00020000,
  116.             WRITE_DAC = 0x00040000,
  117.             WRITE_OWNER = 0x00080000,
  118.             SYNCHRONIZE = 0x00100000,
  119.             STANDARD_RIGHTS_ALL = 0x001F0000,
  120.  
  121.             PROCESS_TERMINATE = 0x0001,
  122.             PROCESS_CREATE_THREAD = 0x0002,
  123.             PROCESS_SET_SESSIONID = 0x0004,
  124.             PROCESS_VM_OPERATION = 0x0008,
  125.             PROCESS_VM_READ = 0x0010,
  126.             PROCESS_VM_WRITE = 0x0020,
  127.             PROCESS_DUP_HANDLE = 0x0040,
  128.             PROCESS_CREATE_PROCESS = 0x0080,
  129.             PROCESS_SET_QUOTA = 0x0100,
  130.             PROCESS_SET_INFORMATION = 0x0200,
  131.             PROCESS_QUERY_INFORMATION = 0x0400,
  132.             PROCESS_ALL_ACCESS = SYNCHRONIZE | 0xFFF
  133.  
  134.         }
  135.  
  136.         /// <summary>
  137.         /// Flags for CoWaitForMultipleHandles
  138.         /// </summary>
  139.         [Flags]
  140.         internal enum COWAIT_FLAGS : int
  141.         {
  142.  
  143.             /// <summary>
  144.             /// Exit when a handle is signaled.
  145.             /// </summary>
  146.             COWAIT_NONE = 0,
  147.  
  148.             /// <summary>
  149.             /// Exit when all handles are signaled AND a message is received.
  150.             /// </summary>
  151.             COWAIT_WAITALL = 0x00000001,
  152.  
  153.             /// <summary>
  154.             /// Exit when an RPC call is serviced.
  155.             /// </summary>
  156.             COWAIT_ALERTABLE = 0x00000002
  157.  
  158.         }
  159.  
  160.         /// <summary>
  161.         /// Processor architecture values
  162.         /// </summary>
  163.         internal enum ProcessorArchitectures
  164.         {
  165.  
  166.             // Intel 32 bit
  167.             X86,
  168.  
  169.             // AMD64 64 bit
  170.             X64,
  171.  
  172.             // Itanium 64
  173.             IA64,
  174.  
  175.             // ARM
  176.             ARM,
  177.  
  178.             // Who knows
  179.             Unknown
  180.  
  181.         }
  182.  
  183.         internal enum CopyProgressResult : uint
  184.         {
  185.             PROGRESS_CONTINUE = 0,
  186.             PROGRESS_CANCEL = 1,
  187.             PROGRESS_STOP = 2,
  188.             PROGRESS_QUIET = 3
  189.         }
  190.  
  191.         internal enum CopyProgressCallbackReason : uint
  192.         {
  193.             CALLBACK_CHUNK_FINISHED = 0x00000000,
  194.             CALLBACK_STREAM_SWITCH = 0x00000001
  195.         }
  196.  
  197.         [Flags]
  198.         internal enum CopyFileFlags : uint
  199.         {
  200.             COPY_FILE_FAIL_IF_EXISTS = 0x00000001,
  201.             COPY_FILE_RESTARTABLE = 0x00000002,
  202.             COPY_FILE_OPEN_SOURCE_FOR_WRITE = 0x00000004,
  203.             COPY_FILE_ALLOW_DECRYPTED_DESTINATION = 0x00000008
  204.         }
  205.  
  206.         #endregion
  207.  
  208.         #region Member_Properties_Data
  209.  
  210.         /// <summary>
  211.         /// Default buffer size to use when dealing with the Windows API.
  212.         /// </summary>
  213.         /// <remarks>
  214.         /// This member is intentionally not a constant because we want to allow
  215.         /// unit tests to change it.
  216.         /// </remarks>
  217.         internal static int MAX_PATH = 260;
  218.  
  219.         private static readonly object IsMonoLock = new object();
  220.  
  221.         /// <summary>
  222.         /// Gets a flag indicating if we are running under some version of Windows
  223.         /// </summary>
  224.         internal static bool IsWindows
  225.         {
  226. #if CLR2COMPATIBILITY
  227.             get { return true; }
  228. #else
  229.             get { return RuntimeInformation.IsOSPlatform(OSPlatform.Windows); }
  230. #endif
  231.         }
  232.  
  233.         /// <summary>
  234.         /// Gets a string for the current OS. This matches the OS env variable
  235.         /// for Windows (Windows_NT).
  236.         /// </summary>
  237.         internal static string OSName
  238.         {
  239.             get { return IsWindows ? "Windows_NT" : "Unix"; }
  240.         }
  241.  
  242.         /// <summary>
  243.         /// System information, initialized when required.
  244.         /// </summary>
  245.         /// <remarks>
  246.         /// Initially implemented as <see cref="Lazy{SystemInformationData}"/>, but
  247.         /// that's .NET 4+, and this is used in MSBuildTaskHost.
  248.         /// </remarks>
  249.         private static SystemInformationData SystemInformation
  250.         {
  251.             get
  252.             {
  253.                 if (!_systemInformationInitialized)
  254.                 {
  255.                     lock (SystemInformationLock)
  256.                     {
  257.                         if (!_systemInformationInitialized)
  258.                         {
  259.                             _systemInformation = new SystemInformationData();
  260.                             _systemInformationInitialized = true;
  261.                         }
  262.                     }
  263.                 }
  264.                 return _systemInformation;
  265.             }
  266.         }
  267.  
  268.         private static SystemInformationData _systemInformation;
  269.         private static bool _systemInformationInitialized;
  270.         private static readonly object SystemInformationLock = new object();
  271.  
  272.         /// <summary>
  273.         /// Architecture getter
  274.         /// </summary>
  275.         internal static ProcessorArchitectures ProcessorArchitecture => SystemInformation.ProcessorArchitectureType;
  276.  
  277.         /// <summary>
  278.         /// Native architecture getter
  279.         /// </summary>
  280.         internal static ProcessorArchitectures ProcessorArchitectureNative => SystemInformation.ProcessorArchitectureTypeNative;
  281.  
  282.         private static int pbCancel;
  283.  
  284.         #endregion Member_Properties_Data
  285.  
  286.         #region delegates
  287.  
  288.         internal delegate CopyProgressResult CopyProgressRoutine(
  289.            long TotalFileSize,
  290.            long TotalBytesTransferred,
  291.            long StreamSize,
  292.            long StreamBytesTransferred,
  293.            uint dwStreamNumber,
  294.            CopyProgressCallbackReason dwCallbackReason,
  295.            IntPtr hSourceFile,
  296.            IntPtr hDestinationFile,
  297.            IntPtr lpData);
  298.  
  299.         #endregion delegates
  300.  
  301.         #region InnerClasses_Structs
  302.  
  303.         /// <summary>
  304.         /// Helper class containing kernel32 functions
  305.         /// </summary>
  306.         internal class Kernel32
  307.         {
  308.             internal const int ATTACH_PARENT_PROCESS = -1;
  309.  
  310.             /// <summary>
  311.             /// AttachConsole to Windows Form App
  312.             /// </summary>
  313.             /// <param name="dwProcessId"></param>
  314.             /// <returns></returns>
  315.             [DllImport("kernel32.dll")]
  316.             internal static extern bool AttachConsole(int dwProcessId);
  317.         }
  318.  
  319.         /// <summary>
  320.         /// Helper class containing Gdi32 API functions
  321.         /// </summary>
  322.         internal class GDI32
  323.         {
  324.  
  325.             internal const int SRCCOPY = 0x00CC0020; // BitBlt dwRop parameter            
  326.  
  327.             [DllImport("gdi32.dll")]
  328.             internal static extern bool BitBlt(IntPtr hObject, int nXDest, int nYDest,
  329.                 int nWidth, int nHeight, IntPtr hObjectSource,
  330.                 int nXSrc, int nYSrc, int dwRop);
  331.             [DllImport("GDI32.dll")]
  332.             internal static extern bool BitBlt(int hdcDest, int nXDest, int nYDest,
  333.                 int nWidth, int nHeight, int hdcSrc,
  334.                 int nXSrc, int nYSrc, int dwRop);
  335.  
  336.             [DllImport("gdi32.dll")]
  337.             internal static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int nWidth, int nHeight);
  338.             [DllImport("GDI32.dll")]
  339.             internal static extern int CreateCompatibleBitmap(int hdc, int nWidth, int nHeight);
  340.  
  341.             [DllImport("gdi32.dll")]
  342.             internal static extern IntPtr CreateCompatibleDC(IntPtr hDC);
  343.             [DllImport("GDI32.dll")]
  344.             internal static extern int CreateCompatibleDC(int hdc);
  345.  
  346.             [DllImport("gdi32.dll")]
  347.             internal static extern int CreateDC(string lpszDriver, string lpszDevice, string lpszOutput, IntPtr lpInitData);
  348.  
  349.  
  350.             [DllImport("gdi32.dll")]
  351.             internal static extern bool DeleteDC(IntPtr hDC);
  352.             [DllImport("GDI32.dll")]
  353.             internal static extern bool DeleteDC(int hdc);
  354.  
  355.  
  356.             [DllImport("gdi32.dll")]
  357.             internal static extern bool DeleteObject(IntPtr hObject);
  358.             [DllImport("GDI32.dll")]
  359.             internal static extern bool DeleteObject(int hObject);
  360.  
  361.             [DllImport("GDI32.dll")]
  362.             internal static extern int GetDeviceCaps(int hdc, int nIndex);
  363.  
  364.             [DllImport("GDI32.dll")]
  365.             internal static extern int SelectObject(int hdc, int hgdiobj);
  366.  
  367.             [DllImport("gdi32.dll")]
  368.             internal static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
  369.  
  370.         }
  371.  
  372.         /// <summary>
  373.         /// User class containing simplified User32 API functions with int instead of IntPtr
  374.         /// </summary>
  375.         internal class User
  376.         {
  377.  
  378.             [DllImport("user32.dll")]
  379.             internal static extern int GetDesktopWindow();
  380.  
  381.             [DllImport("user32.dll")]
  382.             internal static extern IntPtr GetTopWindow(IntPtr hWnd);
  383.  
  384.         }
  385.  
  386.         /// <summary>
  387.         /// Helper class containing User32 API functions
  388.         /// </summary>
  389.         internal class User32
  390.         {
  391.  
  392.             internal const int HT_CAPTION = 0x2;
  393.  
  394.             internal const uint GW_HWNDFIRST = 0x000;
  395.             internal const uint GW_HWNDLAST = 0x001;
  396.             internal const uint GW_HWNDNEXT = 0x002;
  397.             internal const uint GW_HWNDPREV = 0x003;
  398.             internal const uint GW_OWNER = 0x004;
  399.             internal const uint GW_CHILD = 0x005;
  400.             internal const uint GW_ENABLEDPOPUP = 0x006;
  401.  
  402.             internal const uint WM_PRINT = 0x317;
  403.             internal const int WM_NCLBUTTONDOWN = 0xA1;
  404.             internal const int WM_APPCOMMAND = 0x319;
  405.  
  406.             [StructLayout(LayoutKind.Sequential)]
  407.             internal struct RECT
  408.             {
  409.                 internal int left;
  410.                 internal int top;
  411.                 internal int right;
  412.                 internal int bottom;
  413.             }
  414.  
  415.             [Flags]
  416.             internal enum PRF_FLAGS : uint
  417.             {
  418.                 CHECKVISIBLE = 0x01,
  419.                 CHILDREN = 0x02,
  420.                 CLIENT = 0x04,
  421.                 ERASEBKGND = 0x08,
  422.                 NONCLIENT = 0x10,
  423.                 OWNED = 0x20
  424.             }
  425.  
  426.  
  427.             [DllImport("user32.dll")]
  428.             internal static extern IntPtr GetDesktopWindow();
  429.  
  430.  
  431.             [DllImport("user32.dll")]
  432.             internal static extern IntPtr GetWindowDC(IntPtr hWnd);
  433.  
  434.             [DllImport("user32.dll")]
  435.             internal static extern IntPtr GetWindowRect(IntPtr hWnd, ref RECT rect);
  436.  
  437.             [DllImport("user32.dll")]
  438.             internal static extern IntPtr GetTopWindow(IntPtr hWnd);
  439.  
  440.             [DllImport("user32.dll")]
  441.             internal static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
  442.             [DllImport("User32.dll")]
  443.             internal static extern int GetWindowDC(int hWnd);
  444.  
  445.             [System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
  446.             internal static extern bool ReleaseCapture();
  447.  
  448.             [DllImport("user32.dll")]
  449.             internal static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);
  450.             [DllImport("User32.dll")]
  451.             internal static extern int ReleaseDC(int hWnd, int hDC);
  452.  
  453.  
  454.             [System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
  455.             internal static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
  456.  
  457.             [System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
  458.             internal static extern IntPtr SendMessageW(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
  459.  
  460.             [DllImport("user32.dll")]
  461.             internal static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr hdc, PRF_FLAGS drawingOptions);
  462.  
  463.         }
  464.  
  465.  
  466.         /// <summary>
  467.         /// Wrap the intptr returned by OpenProcess in a safe handle.
  468.         /// </summary>
  469.         internal class SafeProcessHandle : SafeHandleZeroOrMinusOneIsInvalid
  470.         {
  471.  
  472.             // Create a SafeHandle, informing the base class
  473.             // that this SafeHandle instance "owns" the handle,
  474.             // and therefore SafeHandle should call
  475.             // our ReleaseHandle method when the SafeHandle
  476.             // is no longer in use
  477.             private SafeProcessHandle() : base(true)
  478.             {
  479.             }
  480.             protected override bool ReleaseHandle()
  481.             {
  482.                 return CloseHandle(handle);
  483.             }
  484.  
  485.             [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  486.             [DllImport("KERNEL32.DLL")]
  487.             private static extern bool CloseHandle(IntPtr hObject);
  488.  
  489.         }
  490.  
  491.         /// <summary>
  492.         /// Contains information about the current state of both physical and virtual memory, including extended memory
  493.         /// </summary>
  494.         [StructLayout(LayoutKind.Sequential, CharSet = AutoOrUnicode)]
  495.         internal class MemoryStatus
  496.         {
  497.  
  498.             /// <summary>
  499.             /// Initializes a new instance of the <see cref="T:MemoryStatus"/> class.
  500.             /// </summary>
  501.             internal MemoryStatus()
  502.             {
  503. #if (CLR2COMPATIBILITY)
  504.                 _length = (uint)Marshal.SizeOf(typeof(InternalWrapper.MemoryStatus));
  505. #else
  506.                 _length = (uint)Marshal.SizeOf<NativeMethods.MemoryStatus>();
  507. #endif
  508.             }
  509.  
  510.             /// <summary>
  511.             /// Size of the structure, in bytes. You must set this member before calling GlobalMemoryStatusEx.
  512.             /// </summary>
  513.             private uint _length;
  514.  
  515.             /// <summary>
  516.             /// Number between 0 and 100 that specifies the approximate percentage of physical
  517.             /// memory that is in use (0 indicates no memory use and 100 indicates full memory use).
  518.             /// </summary>
  519.             internal uint MemoryLoad;
  520.  
  521.             /// <summary>
  522.             /// Total size of physical memory, in bytes.
  523.             /// </summary>
  524.             internal ulong TotalPhysical;
  525.  
  526.             /// <summary>
  527.             /// Size of physical memory available, in bytes.
  528.             /// </summary>
  529.             internal ulong AvailablePhysical;
  530.  
  531.             /// <summary>
  532.             /// Size of the committed memory limit, in bytes. This is physical memory plus the
  533.             /// size of the page file, minus a small overhead.
  534.             /// </summary>
  535.             internal ulong TotalPageFile;
  536.  
  537.             /// <summary>
  538.             /// Size of available memory to commit, in bytes. The limit is ullTotalPageFile.
  539.             /// </summary>
  540.             internal ulong AvailablePageFile;
  541.  
  542.             /// <summary>
  543.             /// Total size of the user mode portion of the virtual address space of the calling process, in bytes.
  544.             /// </summary>
  545.             internal ulong TotalVirtual;
  546.  
  547.             /// <summary>
  548.             /// Size of unreserved and uncommitted memory in the user mode portion of the virtual
  549.             /// address space of the calling process, in bytes.
  550.             /// </summary>
  551.             internal ulong AvailableVirtual;
  552.  
  553.             /// <summary>
  554.             /// Size of unreserved and uncommitted memory in the extended portion of the virtual
  555.             /// address space of the calling process, in bytes.
  556.             /// </summary>
  557.             internal ulong AvailableExtendedVirtual;
  558.  
  559.         }
  560.  
  561.         /// <summary>
  562.         /// Contains the security descriptor for an object and specifies whether
  563.         /// the handle retrieved by specifying this structure is inheritable.
  564.         /// </summary>
  565.         [StructLayout(LayoutKind.Sequential)]
  566.         internal class SecurityAttributes
  567.         {
  568.  
  569.             internal SecurityAttributes()
  570.             {
  571. #if (CLR2COMPATIBILITY)
  572.                 _nLength = (uint)Marshal.SizeOf(typeof(InternalWrapper.SecurityAttributes));
  573. #else
  574.                 _nLength = (uint)Marshal.SizeOf<NativeMethods.SecurityAttributes>();
  575. #endif
  576.             }
  577.  
  578.             private uint _nLength;
  579.  
  580.             internal IntPtr lpSecurityDescriptor;
  581.  
  582.             internal bool bInheritHandle;
  583.  
  584.         }
  585.  
  586.         private class SystemInformationData
  587.         {
  588.  
  589.             /// <summary>
  590.             /// Architecture as far as the current process is concerned.
  591.             /// It's x86 in wow64 (native architecture is x64 in that case).
  592.             /// Otherwise it's the same as the native architecture.
  593.             /// </summary>
  594.             internal readonly ProcessorArchitectures ProcessorArchitectureType;
  595.  
  596.             /// <summary>
  597.             /// Actual architecture of the system.
  598.             /// </summary>
  599.             internal readonly ProcessorArchitectures ProcessorArchitectureTypeNative;
  600.  
  601.             /// <summary>
  602.             /// Convert SYSTEM_INFO architecture values to the internal enum
  603.             /// </summary>
  604.             /// <param name="arch"></param>
  605.             /// <returns></returns>
  606.             private static ProcessorArchitectures ConvertSystemArchitecture(ushort arch)
  607.             {
  608.                 switch (arch)
  609.                 {
  610.                     case PROCESSOR_ARCHITECTURE_INTEL:
  611.                         return ProcessorArchitectures.X86;
  612.                     case PROCESSOR_ARCHITECTURE_AMD64:
  613.                         return ProcessorArchitectures.X64;
  614.                     case PROCESSOR_ARCHITECTURE_ARM:
  615.                         return ProcessorArchitectures.ARM;
  616.                     case PROCESSOR_ARCHITECTURE_IA64:
  617.                         return ProcessorArchitectures.IA64;
  618.                     default:
  619.                         return ProcessorArchitectures.Unknown;
  620.                 }
  621.             }
  622.  
  623.             /// <summary>
  624.             /// Read system info values
  625.             /// </summary>
  626.             internal SystemInformationData()
  627.             {
  628.                 ProcessorArchitectureType = ProcessorArchitectures.Unknown;
  629.                 ProcessorArchitectureTypeNative = ProcessorArchitectures.Unknown;
  630.  
  631.                 if (IsWindows)
  632.                 {
  633.                     var systemInfo = new SYSTEM_INFO();
  634.  
  635.                     GetSystemInfo(ref systemInfo);
  636.                     ProcessorArchitectureType = ConvertSystemArchitecture(systemInfo.wProcessorArchitecture);
  637.  
  638.                     GetNativeSystemInfo(ref systemInfo);
  639.                     ProcessorArchitectureTypeNative = ConvertSystemArchitecture(systemInfo.wProcessorArchitecture);
  640.                 }
  641.                 else
  642.                 {
  643.                     try
  644.                     {
  645.                         // On Unix run 'uname -m' to get the architecture. It's common for Linux and Mac
  646.                         using (
  647.                             var proc =
  648.                                 Process.Start(
  649.                                     new ProcessStartInfo("uname")
  650.                                     {
  651.                                         Arguments = "-m",
  652.                                         UseShellExecute = false,
  653.                                         RedirectStandardOutput = true,
  654.                                         CreateNoWindow = true
  655.                                     }))
  656.                         {
  657.                             string arch = null;
  658.                             if (proc != null)
  659.                             {
  660.                                 // Since uname -m simply returns kernel property, it should be quick.
  661.                                 // 1 second is the best guess for a safe timeout.
  662.                                 proc.WaitForExit(1000);
  663.                                 arch = proc.StandardOutput.ReadLine();
  664.                             }
  665.  
  666.                             if (!string.IsNullOrEmpty(arch))
  667.                             {
  668.                                 if (arch.StartsWith("x86_64", StringComparison.OrdinalIgnoreCase))
  669.                                 {
  670.                                     ProcessorArchitectureType = ProcessorArchitectures.X64;
  671.                                 }
  672.                                 else if (arch.StartsWith("ia64", StringComparison.OrdinalIgnoreCase))
  673.                                 {
  674.                                     ProcessorArchitectureType = ProcessorArchitectures.IA64;
  675.                                 }
  676.                                 else if (arch.StartsWith("arm", StringComparison.OrdinalIgnoreCase))
  677.                                 {
  678.                                     ProcessorArchitectureType = ProcessorArchitectures.ARM;
  679.                                 }
  680.                                 else if (arch.StartsWith("i", StringComparison.OrdinalIgnoreCase)
  681.                                          && arch.EndsWith("86", StringComparison.OrdinalIgnoreCase))
  682.                                 {
  683.                                     ProcessorArchitectureType = ProcessorArchitectures.X86;
  684.                                 }
  685.                             }
  686.                         }
  687.                     }
  688.                     catch
  689.                     {
  690.                         ProcessorArchitectureType = ProcessorArchitectures.Unknown;
  691.                     }
  692.  
  693.                     ProcessorArchitectureTypeNative = ProcessorArchitectureType;
  694.                 }
  695.             }
  696.  
  697.         }
  698.  
  699.         /// <summary>
  700.         /// InternalError Exception derived from <see cref="System.ComponentModel.Win32Exception"/>
  701.         /// </summary>
  702.         internal class InternalErrorException : System.ComponentModel.Win32Exception
  703.         {
  704.  
  705.             /// <summary>
  706.             /// InternalErrorException parameterless constructor
  707.             /// </summary>
  708.             internal InternalErrorException() : base() { }
  709.  
  710.             /// <summary>
  711.             /// InternalErrorException constructor with simple msg
  712.             /// </summary>
  713.             /// <param name="msg"><see cref="string">string msg</see> a message to describe the <see cref="EnablerSpoolerException"/></param>
  714.             internal InternalErrorException(string msg) : base(msg)
  715.             {
  716.             }
  717.  
  718.             /// <summary>
  719.             /// InternalErrorException constructor with simple msg and innerException
  720.             /// </summary>
  721.             /// <param name="msg"><see cref="string">string msg</see> a message to describe the <see cref="EnablerSpoolerException"/></param>
  722.             /// <param name="innerEx"><see cref="Exception">Exception innerEx</see> inner Exception, that was previously thrown</param>        
  723.             internal InternalErrorException(string msg, System.Exception innerEx) : base(msg, innerEx)
  724.             {
  725.             }
  726.  
  727.         }
  728.  
  729.         #region Structs
  730.  
  731.         /// <summary>
  732.         /// Structure that contain information about the system on which we are running
  733.         /// </summary>
  734.         [StructLayout(LayoutKind.Sequential)]
  735.         internal struct SYSTEM_INFO
  736.         {
  737.  
  738.             // This is a union of a DWORD and a struct containing 2 WORDs.
  739.             internal ushort wProcessorArchitecture;
  740.             internal ushort wReserved;
  741.  
  742.             internal uint dwPageSize;
  743.             internal IntPtr lpMinimumApplicationAddress;
  744.             internal IntPtr lpMaximumApplicationAddress;
  745.             internal IntPtr dwActiveProcessorMask;
  746.             internal uint dwNumberOfProcessors;
  747.             internal uint dwProcessorType;
  748.             internal uint dwAllocationGranularity;
  749.             internal ushort wProcessorLevel;
  750.             internal ushort wProcessorRevision;
  751.  
  752.         }
  753.  
  754.         [StructLayout(LayoutKind.Sequential)]
  755.         private struct PROCESS_BASIC_INFORMATION
  756.         {
  757.  
  758.             internal IntPtr ExitStatus;
  759.             internal IntPtr PebBaseAddress;
  760.             internal IntPtr AffinityMask;
  761.             internal IntPtr BasePriority;
  762.             internal IntPtr UniqueProcessId;
  763.             internal IntPtr InheritedFromUniqueProcessId;
  764.  
  765.             internal int Size
  766.             {
  767.                 get { return (6 * IntPtr.Size); }
  768.             }
  769.  
  770.         };
  771.  
  772.         /// <summary>
  773.         /// Contains information about a file or directory; used by GetFileAttributesEx.
  774.         /// </summary>
  775.         [StructLayout(LayoutKind.Sequential)]
  776.         internal struct WIN32_FILE_ATTRIBUTE_DATA
  777.         {
  778.  
  779.             internal int fileAttributes;
  780.             internal uint ftCreationTimeLow;
  781.             internal uint ftCreationTimeHigh;
  782.             internal uint ftLastAccessTimeLow;
  783.             internal uint ftLastAccessTimeHigh;
  784.             internal uint ftLastWriteTimeLow;
  785.             internal uint ftLastWriteTimeHigh;
  786.             internal uint fileSizeHigh;
  787.             internal uint fileSizeLow;
  788.  
  789.         }
  790.  
  791.         #endregion
  792.  
  793.         #endregion InnerClasses_Structs
  794.  
  795.         #region SetErrorMode_[copied_from_BCL]
  796.  
  797.         private static readonly Version s_threadErrorModeMinOsVersion = new Version(6, 1, 0x1db0);
  798.  
  799.         internal static int SetErrorMode(int newMode)
  800.         {
  801. #if FEATURE_OSVERSION
  802.             if (Environment.OSVersion.Version < s_threadErrorModeMinOsVersion)
  803.             {
  804.                 return SetErrorMode_VistaAndOlder(newMode);
  805.             }
  806. #endif
  807.             int num;
  808.             SetErrorMode_Win7AndNewer(newMode, out num);
  809.             return num;
  810.         }
  811.  
  812.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  813.         [DllImport("kernel32.dll", EntryPoint = "SetThreadErrorMode", SetLastError = true)]
  814.         private static extern bool SetErrorMode_Win7AndNewer(int newMode, out int oldMode);
  815.  
  816.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  817.         [DllImport("kernel32.dll", EntryPoint = "SetErrorMode", ExactSpelling = true)]
  818.         private static extern int SetErrorMode_VistaAndOlder(int newMode);
  819.  
  820.         #endregion SetErrorMode_[copied_from_BCL]
  821.  
  822.         #region static wrapper methods
  823.  
  824.         /// <summary>
  825.         /// Get the last write time of the fullpath to a directory. If the pointed path is not a directory, or
  826.         /// if the directory does not exist, then false is returned and fileModifiedTimeUtc is set DateTime.MinValue.
  827.         /// </summary>
  828.         /// <param name="fullPath">Full path to the file in the filesystem</param>
  829.         /// <param name="fileModifiedTimeUtc">The UTC last write time for the directory</param>
  830.         internal static bool GetLastWriteDirectoryUtcTime(string fullPath, out DateTime fileModifiedTimeUtc)
  831.         {
  832.             // This code was copied from the reference manager, if there is a bug fix in that code, see if the same fix should also be made
  833.             // there
  834.  
  835.             fileModifiedTimeUtc = DateTime.MinValue;
  836.  
  837.             if (IsWindows)
  838.             {
  839.                 WIN32_FILE_ATTRIBUTE_DATA data = new WIN32_FILE_ATTRIBUTE_DATA();
  840.                 bool success = false;
  841.  
  842.                 success = GetFileAttributesEx(fullPath, 0, ref data);
  843.                 if (success)
  844.                 {
  845.                     if ((data.fileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
  846.                     {
  847.                         long dt = ((long)(data.ftLastWriteTimeHigh) << 32) | ((long)data.ftLastWriteTimeLow);
  848.                         fileModifiedTimeUtc = DateTime.FromFileTimeUtc(dt);
  849.                     }
  850.                     else
  851.                     {
  852.                         // Path does not point to a directory
  853.                         success = false;
  854.                     }
  855.                 }
  856.  
  857.                 return success;
  858.             }
  859.  
  860.             fileModifiedTimeUtc = Directory.GetLastWriteTimeUtc(fullPath);
  861.             return true;
  862.         }
  863.  
  864.         /// <summary>
  865.         /// Takes the path and returns the short path
  866.         /// </summary>
  867.         internal static string GetShortFilePath(string path)
  868.         {
  869.             if (!IsWindows)
  870.             {
  871.                 return path;
  872.             }
  873.  
  874.             if (path != null)
  875.             {
  876.                 int length = GetShortPathName(path, null, 0);
  877.                 int errorCode = Marshal.GetLastWin32Error();
  878.  
  879.                 if (length > 0)
  880.                 {
  881.                     StringBuilder fullPathBuffer = new StringBuilder(length);
  882.                     length = GetShortPathName(path, fullPathBuffer, length);
  883.                     errorCode = Marshal.GetLastWin32Error();
  884.  
  885.                     if (length > 0)
  886.                     {
  887.                         string fullPath = fullPathBuffer.ToString();
  888.                         path = fullPath;
  889.                     }
  890.                 }
  891.  
  892.                 if (length == 0 && errorCode != 0)
  893.                 {
  894.                     ThrowExceptionForErrorCode(errorCode);
  895.                 }
  896.             }
  897.  
  898.             return path;
  899.         }
  900.  
  901.         /// <summary>
  902.         /// Takes the path and returns a full path
  903.         /// </summary>
  904.         /// <param name="path"></param>
  905.         /// <returns></returns>
  906.         internal static string GetLongFilePath(string path)
  907.         {
  908.             if (path != null)
  909.             {
  910.                 int length = GetLongPathName(path, null, 0);
  911.                 int errorCode = Marshal.GetLastWin32Error();
  912.  
  913.                 if (length > 0)
  914.                 {
  915.                     StringBuilder fullPathBuffer = new StringBuilder(length);
  916.                     length = GetLongPathName(path, fullPathBuffer, length);
  917.                     errorCode = Marshal.GetLastWin32Error();
  918.  
  919.                     if (length > 0)
  920.                     {
  921.                         string fullPath = fullPathBuffer.ToString();
  922.                         path = fullPath;
  923.                     }
  924.                 }
  925.  
  926.                 if (length == 0 && errorCode != 0)
  927.                 {
  928.                     ThrowExceptionForErrorCode(errorCode);
  929.                 }
  930.             }
  931.  
  932.             return path;
  933.         }
  934.  
  935.         /// <summary>
  936.         /// Retrieves the current global memory status.
  937.         /// </summary>
  938.         internal static MemoryStatus GetMemoryStatus()
  939.         {
  940.             if (InternalWrapper.IsWindows)
  941.             {
  942.                 MemoryStatus status = new MemoryStatus();
  943.                 bool returnValue = InternalWrapper.GlobalMemoryStatusEx(status);
  944.                 if (!returnValue)
  945.                 {
  946.                     return null;
  947.                 }
  948.  
  949.                 return status;
  950.             }
  951.  
  952.             return null;
  953.         }
  954.  
  955.         /// <summary>
  956.         /// Get the last write time of the content pointed to by a file path.
  957.         /// </summary>
  958.         /// <param name="fullPath">Full path to the file in the filesystem</param>
  959.         /// <returns>The last write time of the file, or DateTime.MinValue if the file does not exist.</returns>
  960.         /// <remarks>
  961.         /// This is the most accurate timestamp-extraction mechanism, but it is too slow to use all the time.
  962.         /// See https://github.com/Microsoft/msbuild/issues/2052.
  963.         /// </remarks>
  964.         private static DateTime GetContentLastWriteFileUtcTime(string fullPath)
  965.         {
  966.             DateTime fileModifiedTime = DateTime.MinValue;
  967.  
  968.             using (SafeFileHandle handle =
  969.                 CreateFile(fullPath,
  970.                     GENERIC_READ,
  971.                     FILE_SHARE_READ,
  972.                     IntPtr.Zero,
  973.                     OPEN_EXISTING,
  974.                     FILE_ATTRIBUTE_NORMAL, /* No FILE_FLAG_OPEN_REPARSE_POINT; read through to content */
  975.                     IntPtr.Zero))
  976.             {
  977.                 if (!handle.IsInvalid)
  978.                 {
  979.                     System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime, ftLastAccessTime, ftLastWriteTime;
  980.                     if (!GetFileTime(handle, out ftCreationTime, out ftLastAccessTime, out ftLastWriteTime) != true)
  981.                     {
  982.                         long fileTime = ((long)(uint)ftLastWriteTime.dwHighDateTime) << 32 |
  983.                                         (long)(uint)ftLastWriteTime.dwLowDateTime;
  984.                         fileModifiedTime =
  985.                             DateTime.FromFileTimeUtc(fileTime);
  986.                     }
  987.                 }
  988.             }
  989.  
  990.             return fileModifiedTime;
  991.         }
  992.  
  993.         /// <summary>
  994.         /// Did the HRESULT succeed
  995.         /// </summary>
  996.         internal static bool HResultSucceeded(int hr)
  997.         {
  998.             return (hr >= 0);
  999.         }
  1000.  
  1001.         /// <summary>
  1002.         /// Did the HRESULT Fail
  1003.         /// </summary>
  1004.         internal static bool HResultFailed(int hr)
  1005.         {
  1006.             return (hr < 0);
  1007.         }
  1008.  
  1009.         /// <summary>
  1010.         /// Given an error code, converts it to an HRESULT and throws the appropriate exception.
  1011.         /// </summary>
  1012.         /// <param name="errorCode"></param>
  1013.         internal static void ThrowExceptionForErrorCode(int errorCode)
  1014.         {
  1015.             // See ndp\clr\src\bcl\system\io\__error.cs for this code as it appears in the CLR.
  1016.  
  1017.             // Something really bad went wrong with the call
  1018.             // translate the error into an exception
  1019.  
  1020.             // Convert the errorcode into an HRESULT (See MakeHRFromErrorCode in Win32Native.cs in
  1021.             // ndp\clr\src\bcl\microsoft\win32)
  1022.             errorCode = unchecked(((int)0x80070000) | errorCode);
  1023.  
  1024.             // Throw an exception as best we can
  1025.             Marshal.ThrowExceptionForHR(errorCode);
  1026.         }
  1027.  
  1028.         /// <summary>
  1029.         /// Kills the specified process by id and all of its children recursively.
  1030.         /// </summary>
  1031.         internal static void KillTree(int processIdToKill)
  1032.         {
  1033.             // Note that GetProcessById does *NOT* internally hold on to the process handle.
  1034.             // Only when you create the process using the Process object
  1035.             // does the Process object retain the original handle.
  1036.  
  1037.             Process thisProcess = null;
  1038.             try
  1039.             {
  1040.                 thisProcess = Process.GetProcessById(processIdToKill);
  1041.             }
  1042.             catch (ArgumentException)
  1043.             {
  1044.                 // The process has already died for some reason.  So shrug and assume that any child processes
  1045.                 // have all also either died or are in the process of doing so.
  1046.                 return;
  1047.             }
  1048.  
  1049.             try
  1050.             {
  1051.                 DateTime myStartTime = thisProcess.StartTime;
  1052.  
  1053.                 // Grab the process handle.  We want to keep this open for the duration of the function so that
  1054.                 // it cannot be reused while we are running.
  1055.                 SafeProcessHandle hProcess = OpenProcess(eDesiredAccess.PROCESS_QUERY_INFORMATION, false, processIdToKill);
  1056.                 if (hProcess.IsInvalid)
  1057.                 {
  1058.                     return;
  1059.                 }
  1060.  
  1061.                 try
  1062.                 {
  1063.                     try
  1064.                     {
  1065.                         // Kill this process, so that no further children can be created.
  1066.                         thisProcess.Kill();
  1067.                     }
  1068.                     catch (System.ComponentModel.Win32Exception e)
  1069.                     {
  1070.                         // Access denied is potentially expected -- it happens when the process that
  1071.                         // we're attempting to kill is already dead.  So just ignore in that case.
  1072.                         if (e.NativeErrorCode != ERROR_ACCESS_DENIED)
  1073.                         {
  1074.                             throw;
  1075.                         }
  1076.                     }
  1077.  
  1078.                     // Now enumerate our children.  Children of this process are any process which has this process id as its parent
  1079.                     // and which also started after this process did.
  1080.                     List<KeyValuePair<int, SafeProcessHandle>> children = GetChildProcessIds(processIdToKill, myStartTime);
  1081.  
  1082.                     try
  1083.                     {
  1084.                         foreach (KeyValuePair<int, SafeProcessHandle> childProcessInfo in children)
  1085.                         {
  1086.                             KillTree(childProcessInfo.Key);
  1087.                         }
  1088.                     }
  1089.                     finally
  1090.                     {
  1091.                         foreach (KeyValuePair<int, SafeProcessHandle> childProcessInfo in children)
  1092.                         {
  1093.                             childProcessInfo.Value.Dispose();
  1094.                         }
  1095.                     }
  1096.                 }
  1097.                 finally
  1098.                 {
  1099.                     // Release the handle.  After this point no more children of this process exist and this process has also exited.
  1100.                     hProcess.Dispose();
  1101.                 }
  1102.             }
  1103.             finally
  1104.             {
  1105.                 thisProcess.Dispose();
  1106.             }
  1107.         }
  1108.  
  1109.         /// <summary>
  1110.         /// Returns the parent process id for the specified process.
  1111.         /// Returns zero if it cannot be gotten for some reason.
  1112.         /// </summary>
  1113.         internal static int GetParentProcessId(int processId)
  1114.         {
  1115.             int ParentID = 0;
  1116. #if !CLR2COMPATIBILITY
  1117.             //if (IsUnixLike)
  1118.             //{
  1119.             //    string line = null;
  1120.  
  1121.             //    try
  1122.             //    {
  1123.             //        // /proc/<processID>/stat returns a bunch of space separated fields. Get that string
  1124.             //        using (var r = FileUtilities.OpenRead("/proc/" + processId + "/stat"))
  1125.             //        {
  1126.             //            line = r.ReadLine();
  1127.             //        }
  1128.             //    }
  1129.             //    catch // Ignore errors since the process may have terminated
  1130.             //    {
  1131.             //    }
  1132.  
  1133.             //    if (!string.IsNullOrWhiteSpace(line))
  1134.             //    {
  1135.             //        // One of the fields is the process name. It may contain any characters, but since it's
  1136.             //        // in parenthesis, we can finds its end by looking for the last parenthesis. After that,
  1137.             //        // there comes a space, then the second fields separated by a space is the parent id.
  1138.             //        string[] statFields = line.Substring(line.LastIndexOf(')')).Split(new[] { ' ' }, 4);
  1139.             //        if (statFields.Length >= 3)
  1140.             //        {
  1141.             //            ParentID = Int32.Parse(statFields[2]);
  1142.             //        }
  1143.             //    }
  1144.             //}
  1145.             //else
  1146. #endif
  1147.             {
  1148.                 SafeProcessHandle hProcess = OpenProcess(eDesiredAccess.PROCESS_QUERY_INFORMATION, false, processId);
  1149.  
  1150.                 if (!hProcess.IsInvalid)
  1151.                 {
  1152.                     try
  1153.                     {
  1154.                         // UNDONE: NtQueryInformationProcess will fail if we are not elevated and other process is. Advice is to change to use ToolHelp32 API's
  1155.                         // For now just return zero and worst case we will not kill some children.
  1156.                         PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION();
  1157.                         int pSize = 0;
  1158.  
  1159.                         if (0 == NtQueryInformationProcess(hProcess, PROCESSINFOCLASS.ProcessBasicInformation, ref pbi, pbi.Size, ref pSize))
  1160.                         {
  1161.                             ParentID = (int)pbi.InheritedFromUniqueProcessId;
  1162.                         }
  1163.                     }
  1164.                     finally
  1165.                     {
  1166.                         hProcess.Dispose();
  1167.                     }
  1168.                 }
  1169.             }
  1170.  
  1171.             return (ParentID);
  1172.         }
  1173.  
  1174.         /// <summary>
  1175.         /// Returns an array of all the immediate child processes by id.
  1176.         /// NOTE: The IntPtr in the tuple is the handle of the child process.  CloseHandle MUST be called on this.
  1177.         /// </summary>
  1178.         internal static List<KeyValuePair<int, SafeProcessHandle>> GetChildProcessIds(int parentProcessId, DateTime parentStartTime)
  1179.         {
  1180.             List<KeyValuePair<int, SafeProcessHandle>> myChildren = new List<KeyValuePair<int, SafeProcessHandle>>();
  1181.  
  1182.             foreach (Process possibleChildProcess in Process.GetProcesses())
  1183.             {
  1184.                 using (possibleChildProcess)
  1185.                 {
  1186.                     // Hold the child process handle open so that children cannot die and restart with a different parent after we've started looking at it.
  1187.                     // This way, any handle we pass back is guaranteed to be one of our actual children.
  1188.                     SafeProcessHandle childHandle = OpenProcess(eDesiredAccess.PROCESS_QUERY_INFORMATION, false, possibleChildProcess.Id);
  1189.                     if (childHandle.IsInvalid)
  1190.                     {
  1191.                         continue;
  1192.                     }
  1193.  
  1194.                     bool keepHandle = false;
  1195.                     try
  1196.                     {
  1197.                         if (possibleChildProcess.StartTime > parentStartTime)
  1198.                         {
  1199.                             int childParentProcessId = GetParentProcessId(possibleChildProcess.Id);
  1200.                             if (childParentProcessId != 0)
  1201.                             {
  1202.                                 if (parentProcessId == childParentProcessId)
  1203.                                 {
  1204.                                     // Add this one
  1205.                                     myChildren.Add(new KeyValuePair<int, SafeProcessHandle>(possibleChildProcess.Id, childHandle));
  1206.                                     keepHandle = true;
  1207.                                 }
  1208.                             }
  1209.                         }
  1210.                     }
  1211.                     finally
  1212.                     {
  1213.                         if (!keepHandle)
  1214.                         {
  1215.                             childHandle.Dispose();
  1216.                         }
  1217.                     }
  1218.                 }
  1219.             }
  1220.  
  1221.             return myChildren;
  1222.         }
  1223.  
  1224.         /// <summary>
  1225.         /// Internal, optimized GetCurrentDirectory implementation that simply delegates to the native method
  1226.         /// </summary>
  1227.         /// <returns></returns>
  1228.         internal static string GetCurrentDirectory()
  1229.         {
  1230.             if (IsWindows)
  1231.             {
  1232.                 StringBuilder sb = new StringBuilder(MAX_PATH);
  1233.                 int pathLength = GetCurrentDirectory(MAX_PATH, sb);
  1234.  
  1235.                 return pathLength > 0 ? sb.ToString() : null;
  1236.             }
  1237.  
  1238.             return Directory.GetCurrentDirectory();
  1239.         }
  1240.  
  1241.         internal static void XCopy(string oldFile, string newFile)
  1242.         {
  1243.             CopyFileEx(oldFile, newFile, new CopyProgressRoutine(CopyProgressHandler), IntPtr.Zero, ref pbCancel, CopyFileFlags.COPY_FILE_RESTARTABLE);
  1244.         }
  1245.  
  1246.         internal static CopyProgressResult CopyProgressHandler(long total, long transferred, long streamSize, long StreamByteTrans, uint dwStreamNumber, CopyProgressCallbackReason reason, IntPtr hSourceFile, IntPtr hDestinationFile, IntPtr lpData)
  1247.         {
  1248.             return CopyProgressResult.PROGRESS_CONTINUE;
  1249.         }
  1250.  
  1251.         #region helper methods
  1252.  
  1253.         internal static void VerifyThrowInternalError(bool condition, string message, params object[] args)
  1254.         {
  1255.             if (!condition)
  1256.             {
  1257.                 ThrowInternalError(message, args);
  1258.             }
  1259.         }
  1260.  
  1261.         /// <summary>
  1262.         /// This method should be used in places where one would normally put
  1263.         /// an "assert". It should be used to validate that our assumptions are
  1264.         /// true, where false would indicate that there must be a bug in our
  1265.         /// code somewhere. This should not be used to throw errors based on bad
  1266.         /// user input or anything that the user did wrong.
  1267.         /// </summary>
  1268.         internal static void VerifyThrow(bool condition, string unformattedMessage)
  1269.         {
  1270.             if (!condition)
  1271.             {
  1272.                 ThrowInternalError(unformattedMessage, null, null);
  1273.             }
  1274.         }
  1275.  
  1276.         /// <summary>
  1277.         /// Overload for one string format argument.
  1278.         /// </summary>
  1279.         internal static void VerifyThrow(bool condition, string unformattedMessage, object arg0)
  1280.         {
  1281.             if (!condition)
  1282.             {
  1283.                 ThrowInternalError(unformattedMessage, arg0);
  1284.             }
  1285.         }
  1286.  
  1287.         /// <summary>
  1288.         /// Overload for two string format arguments.
  1289.         /// </summary>
  1290.         internal static void VerifyThrow(bool condition, string unformattedMessage, object arg0, object arg1)
  1291.         {
  1292.             if (!condition)
  1293.             {
  1294.                 ThrowInternalError(unformattedMessage, arg0, arg1);
  1295.             }
  1296.         }
  1297.  
  1298.         /// <summary>
  1299.         /// Overload for three string format arguments.
  1300.         /// </summary>
  1301.         internal static void VerifyThrow(bool condition, string unformattedMessage, object arg0, object arg1, object arg2)
  1302.         {
  1303.             if (!condition)
  1304.             {
  1305.                 ThrowInternalError(unformattedMessage, arg0, arg1, arg2);
  1306.             }
  1307.         }
  1308.  
  1309.         /// <summary>
  1310.         /// Overload for four string format arguments.
  1311.         /// </summary>
  1312.         internal static void VerifyThrow(bool condition, string unformattedMessage, object arg0, object arg1, object arg2, object arg3)
  1313.         {
  1314.             if (!condition)
  1315.             {
  1316.                 ThrowInternalError(unformattedMessage, arg0, arg1, arg2, arg3);
  1317.             }
  1318.         }
  1319.  
  1320.         /// <summary>
  1321.         /// Throws InternalErrorException.
  1322.         /// This is only for situations that would mean that there is a bug in MSBuild itself.
  1323.         /// </summary>]
  1324.         internal static void ThrowInternalError(string message, params object[] args)
  1325.         {
  1326.             throw new InternalErrorException(FormatString(message, args));
  1327.         }
  1328.  
  1329.         internal static bool FileExists(string path)
  1330.         {
  1331.             WIN32_FILE_ATTRIBUTE_DATA data = new WIN32_FILE_ATTRIBUTE_DATA();
  1332.             return GetFileAttributesEx(path, 0, ref data);
  1333.         }
  1334.  
  1335.         /// <summary>
  1336.         /// Formats the given string using the variable arguments passed in.
  1337.         ///
  1338.         /// PERF WARNING: calling a method that takes a variable number of arguments is expensive, because memory is allocated for
  1339.         /// the array of arguments -- do not call this method repeatedly in performance-critical scenarios
  1340.         ///
  1341.         /// Thread safe.
  1342.         /// </summary>
  1343.         /// <param name="unformatted">The string to format.</param>
  1344.         /// <param name="args">Optional arguments for formatting the given string.</param>
  1345.         /// <returns>The formatted string.</returns>
  1346.         internal static string FormatString(string unformatted, params object[] args)
  1347.         {
  1348.             string formatted = unformatted;
  1349.  
  1350.             // NOTE: String.Format() does not allow a null arguments array
  1351.             if ((args?.Length > 0))
  1352.             {
  1353. #if DEBUG
  1354.                 // If you accidentally pass some random type in that can't be converted to a string,
  1355.                 // FormatResourceString calls ToString() which returns the full name of the type!
  1356.                 foreach (object param in args)
  1357.                 {
  1358.                     // Check it has a real implementation of ToString() and the type is not actually System.String
  1359.                     if (param != null)
  1360.                     {
  1361.                         if (string.Equals(param.GetType().ToString(), param.ToString(), StringComparison.Ordinal) &&
  1362.                             param.GetType() != typeof(string))
  1363.                         {
  1364.                             formatted += string.Format("Invalid resource parameter type, was {0}", param.GetType().FullName);
  1365.                         }
  1366.                     }
  1367.                 }
  1368. #endif
  1369.                 // Format the string, using the variable arguments passed in.
  1370.                 // NOTE: all String methods are thread-safe
  1371.                 formatted = String.Format(CultureInfo.CurrentCulture, unformatted, args);
  1372.             }
  1373.  
  1374.             return formatted;
  1375.         }
  1376.  
  1377.         #endregion helper methods
  1378.  
  1379.         #region extension methods
  1380.  
  1381.         /// <summary>
  1382.         /// Waits while pumping APC messages.  This is important if the waiting thread is an STA thread which is potentially
  1383.         /// servicing COM calls from other threads.
  1384.         /// </summary>
  1385.         [SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Runtime.InteropServices.SafeHandle.DangerousGetHandle", Scope = "member", Target = "Microsoft.Build.Shared.NativeMethods.#MsgWaitOne(System.Threading.WaitHandle,System.Int32)", Justification = "This is necessary and it has been used for a long time. No need to change it now.")]
  1386.         internal static bool MsgWaitOne(this WaitHandle handle)
  1387.         {
  1388.             return handle.MsgWaitOne(Timeout.Infinite);
  1389.         }
  1390.  
  1391.         /// <summary>
  1392.         /// Waits while pumping APC messages.  This is important if the waiting thread is an STA thread which is potentially
  1393.         /// servicing COM calls from other threads.
  1394.         /// </summary>
  1395.         internal static bool MsgWaitOne(this WaitHandle handle, TimeSpan timeout)
  1396.         {
  1397.             return MsgWaitOne(handle, (int)timeout.TotalMilliseconds);
  1398.         }
  1399.  
  1400.         /// <summary>
  1401.         /// Waits while pumping APC messages.  This is important if the waiting thread is an STA thread which is potentially
  1402.         /// servicing COM calls from other threads.
  1403.         /// </summary>
  1404.         [SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods", MessageId = "System.Runtime.InteropServices.SafeHandle.DangerousGetHandle", Justification = "Necessary to avoid pumping")]
  1405.         internal static bool MsgWaitOne(this WaitHandle handle, int timeout)
  1406.         {
  1407.             // CoWaitForMultipleHandles allows us to wait in an STA apartment and still service RPC requests from other threads.
  1408.             // VS needs this in order to allow the in-proc compilers to properly initialize, since they will make calls from the
  1409.             // build thread which the main thread (blocked on BuildSubmission.Execute) must service.
  1410.             int waitIndex;
  1411. #if FEATURE_HANDLE_SAFEWAITHANDLE
  1412.             IntPtr handlePtr = handle.SafeWaitHandle.DangerousGetHandle();
  1413. #else
  1414.             IntPtr handlePtr = handle.GetSafeWaitHandle().DangerousGetHandle();
  1415. #endif
  1416.             int returnValue = CoWaitForMultipleHandles(COWAIT_FLAGS.COWAIT_NONE, timeout, 1, new IntPtr[] { handlePtr }, out waitIndex);
  1417.             VerifyThrow(returnValue == 0 || ((uint)returnValue == RPC_S_CALLPENDING && timeout != Timeout.Infinite), "Received {0} from CoWaitForMultipleHandles, but expected 0 (S_OK)", returnValue); return returnValue == 0;
  1418.         }
  1419.  
  1420.         #endregion extension methods
  1421.  
  1422.         #endregion static wrapper methods
  1423.  
  1424.         #region PInvoke
  1425.  
  1426.         /// <summary>
  1427.         /// Gets the current OEM code page which is used by console apps
  1428.         /// (as opposed to the Windows/ANSI code page used by the normal people)
  1429.         /// Basically for each ANSI code page (set in Regional settings) there's a corresponding OEM code page
  1430.         /// that needs to be used for instance when writing to batch files
  1431.         /// </summary>
  1432.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  1433.         [DllImport(kernel32Dll)]
  1434.         internal static extern int GetOEMCP();
  1435.  
  1436.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  1437.         [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
  1438.         [return: MarshalAs(UnmanagedType.Bool)]
  1439.         internal static extern bool GetFileAttributesEx(String name, int fileInfoLevel, ref WIN32_FILE_ATTRIBUTE_DATA lpFileInformation);
  1440.  
  1441.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  1442.         [DllImport(kernel32Dll, SetLastError = true, CharSet = CharSet.Unicode)]
  1443.         private static extern uint SearchPath
  1444.         (
  1445.             string path,
  1446.             string fileName,
  1447.             string extension,
  1448.             int numBufferChars,
  1449.             [Out] StringBuilder buffer,
  1450.             int[] filePart
  1451.         );
  1452.  
  1453.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  1454.         [DllImport("kernel32.dll", PreserveSig = true, SetLastError = true)]
  1455.         [return: MarshalAs(UnmanagedType.Bool)]
  1456.         internal static extern bool FreeLibrary([In] IntPtr module);
  1457.  
  1458.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  1459.         [DllImport("kernel32.dll", PreserveSig = true, BestFitMapping = false, ThrowOnUnmappableChar = true, CharSet = CharSet.Ansi, SetLastError = true)]
  1460.         internal static extern IntPtr GetProcAddress(IntPtr module, string procName);
  1461.  
  1462.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  1463.         [DllImport("kernel32.dll", CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true)]
  1464.         internal static extern IntPtr LoadLibrary(string fileName);
  1465.  
  1466.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  1467.         [DllImport(mscoreeDLL, SetLastError = true, CharSet = CharSet.Unicode)]
  1468.         internal static extern uint GetRequestedRuntimeInfo(String pExe,
  1469.                                                 String pwszVersion,
  1470.                                                 String pConfigurationFile,
  1471.                                                 uint startupFlags,
  1472.                                                 uint runtimeInfoFlags,
  1473.                                                 [Out] StringBuilder pDirectory,
  1474.                                                 int dwDirectory,
  1475.                                                 out uint dwDirectoryLength,
  1476.                                                 [Out] StringBuilder pVersion,
  1477.                                                 int cchBuffer,
  1478.                                                 out uint dwlength);
  1479.  
  1480.         /// <summary>
  1481.         /// Gets the fully qualified filename of the currently executing .exe
  1482.         /// </summary>
  1483.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  1484.         [DllImport(kernel32Dll, SetLastError = true, CharSet = CharSet.Unicode)]
  1485.         internal static extern int GetModuleFileName(
  1486. #if FEATURE_HANDLEREF
  1487.             HandleRef hModule,
  1488. #else
  1489.             IntPtr hModule,
  1490. #endif
  1491.             [Out] StringBuilder buffer, int length);
  1492.  
  1493.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  1494.         [DllImport("kernel32.dll")]
  1495.         internal static extern IntPtr GetStdHandle(int nStdHandle);
  1496.  
  1497.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  1498.         [DllImport("kernel32.dll")]
  1499.         internal static extern uint GetFileType(IntPtr hFile);
  1500.  
  1501.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  1502.         [SuppressMessage("Microsoft.Usage", "CA2205:UseManagedEquivalentsOfWin32Api", Justification = "Using unmanaged equivalent for performance reasons")]
  1503.         [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
  1504.         internal static extern int GetCurrentDirectory(int nBufferLength, [Out] StringBuilder lpBuffer);
  1505.  
  1506.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  1507.         [SuppressMessage("Microsoft.Usage", "CA2205:UseManagedEquivalentsOfWin32Api", Justification = "Using unmanaged equivalent for performance reasons")]
  1508.         [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "SetCurrentDirectory")]
  1509.         [return: MarshalAs(UnmanagedType.Bool)]
  1510.         internal static extern bool SetCurrentDirectoryWindows(string path);
  1511.  
  1512.         internal static bool SetCurrentDirectory(string path)
  1513.         {
  1514.             if (IsWindows)
  1515.             {
  1516.                 return SetCurrentDirectoryWindows(path);
  1517.             }
  1518.  
  1519.             // Make sure this does not throw
  1520.             try
  1521.             {
  1522.                 Directory.SetCurrentDirectory(path);
  1523.             }
  1524.             catch
  1525.             {
  1526.             }
  1527.             return true;
  1528.         }
  1529.  
  1530.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  1531.         [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
  1532.         internal static unsafe extern int GetFullPathName(string target, int bufferLength, char* buffer, IntPtr mustBeZero);
  1533.  
  1534.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  1535.         [DllImport("KERNEL32.DLL")]
  1536.         private static extern SafeProcessHandle OpenProcess(eDesiredAccess dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId);
  1537.  
  1538.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  1539.         [DllImport("NTDLL.DLL")]
  1540.         private static extern int NtQueryInformationProcess(SafeProcessHandle hProcess, PROCESSINFOCLASS pic, ref PROCESS_BASIC_INFORMATION pbi, int cb, ref int pSize);
  1541.  
  1542.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  1543.         [return: MarshalAs(UnmanagedType.Bool)]
  1544.         [DllImport("kernel32.dll", CharSet = AutoOrUnicode, SetLastError = true)]
  1545.         private static extern bool GlobalMemoryStatusEx([In, Out] MemoryStatus lpBuffer);
  1546.  
  1547.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  1548.         [DllImport("kernel32.dll", CharSet = CharSet.Unicode, BestFitMapping = false)]
  1549.         internal static extern int GetShortPathName(string path, [Out] StringBuilder fullpath, [In] int length);
  1550.  
  1551.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  1552.         [DllImport("kernel32.dll", CharSet = CharSet.Unicode, BestFitMapping = false)]
  1553.         internal static extern int GetLongPathName([In] string path, [Out] StringBuilder fullpath, [In] int length);
  1554.  
  1555.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  1556.         [DllImport("kernel32.dll", CharSet = AutoOrUnicode, SetLastError = true)]
  1557.         internal static extern bool CreatePipe(out SafeFileHandle hReadPipe, out SafeFileHandle hWritePipe, SecurityAttributes lpPipeAttributes, int nSize);
  1558.  
  1559.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  1560.         [DllImport("kernel32.dll", CharSet = AutoOrUnicode, SetLastError = true)]
  1561.         internal static extern bool ReadFile(SafeFileHandle hFile, byte[] lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped);
  1562.  
  1563.         /// <summary>
  1564.         /// CoWaitForMultipleHandles allows us to wait in an STA apartment and still service RPC requests from other threads.
  1565.         /// VS needs this in order to allow the in-proc compilers to properly initialize, since they will make calls from the
  1566.         /// build thread which the main thread (blocked on BuildSubmission.Execute) must service.
  1567.         /// </summary>
  1568.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  1569.         [DllImport("ole32.dll")]
  1570.         internal static extern int CoWaitForMultipleHandles(COWAIT_FLAGS dwFlags, int dwTimeout, int cHandles, [MarshalAs(UnmanagedType.LPArray)] IntPtr[] pHandles, out int pdwIndex);
  1571.  
  1572.         internal const uint GENERIC_READ = 0x80000000;
  1573.         internal const uint FILE_SHARE_READ = 0x1;
  1574.         internal const uint FILE_ATTRIBUTE_NORMAL = 0x80;
  1575.         internal const uint FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000;
  1576.         internal const uint OPEN_EXISTING = 3;
  1577.  
  1578.         [DllImport("kernel32.dll", CharSet = AutoOrUnicode, CallingConvention = CallingConvention.StdCall,
  1579.             SetLastError = true)]
  1580.         internal static extern SafeFileHandle CreateFile(
  1581.             string lpFileName,
  1582.             uint dwDesiredAccess,
  1583.             uint dwShareMode,
  1584.             IntPtr lpSecurityAttributes,
  1585.             uint dwCreationDisposition,
  1586.             uint dwFlagsAndAttributes,
  1587.             IntPtr hTemplateFile
  1588.             );
  1589.  
  1590.         [DllImport("kernel32.dll", SetLastError = true)]
  1591.         internal static extern bool GetFileTime(
  1592.             SafeFileHandle hFile,
  1593.             out System.Runtime.InteropServices.ComTypes.FILETIME lpCreationTime,
  1594.             out System.Runtime.InteropServices.ComTypes.FILETIME lpLastAccessTime,
  1595.             out System.Runtime.InteropServices.ComTypes.FILETIME lpLastWriteTime
  1596.             );
  1597.  
  1598.  
  1599.         /// <summary>
  1600.         /// Really truly non pumping wait.
  1601.         /// Raw IntPtrs have to be used, because the marshaller does not support arrays of SafeHandle, only
  1602.         /// single SafeHandles.
  1603.         /// </summary>
  1604.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  1605.         [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
  1606.         internal static extern Int32 WaitForMultipleObjects(uint handle, IntPtr[] handles, bool waitAll, uint milliseconds);
  1607.  
  1608.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  1609.         [DllImport("kernel32.dll", SetLastError = true)]
  1610.         internal static extern void GetSystemInfo(ref SYSTEM_INFO lpSystemInfo);
  1611.  
  1612.         [SuppressMessage("Microsoft.Design", "CA1060:MovePInvokesToNativeMethodsClass", Justification = "Class name is NativeMethodsShared for increased clarity")]
  1613.         [DllImport("kernel32.dll", SetLastError = true)]
  1614.         internal static extern void GetNativeSystemInfo(ref SYSTEM_INFO lpSystemInfo);
  1615.  
  1616.         [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
  1617.         [return: MarshalAs(UnmanagedType.Bool)]
  1618.         internal static extern bool CopyFileEx(string lpExistingFileName, string lpNewFileName,
  1619.             CopyProgressRoutine lpProgressRoutine, IntPtr lpData, ref Int32 pbCancel,
  1620.             CopyFileFlags dwCopyFlags);
  1621.  
  1622.         [DllImport("kernel32.dll")]
  1623.         internal static extern uint GetCurrentThreadId();
  1624.  
  1625.         [DllImport("kernel32.dll")]
  1626.         internal static extern uint GetCurrentProcessId();
  1627.  
  1628.         #endregion
  1629.  
  1630.     }
  1631.  
  1632. }
  1633.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement