Dryad/CommonCode/NativeMethods.cs

454 lines
19 KiB
C#

/*
Copyright (c) Microsoft Corporation
All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License
at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER
EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions and
limitations under the License.
*/
//------------------------------------------------------------------------------
// <summary>
// Wrapped native methods
// </summary>
//------------------------------------------------------------------------------
namespace Microsoft.Research.Dryad
{
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.ConstrainedExecution;
using System.Security;
using System.Security.Permissions;
using Microsoft.Win32.SafeHandles;
[SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
public sealed class SafeThreadHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeThreadHandle() : base(true) { }
public SafeThreadHandle(IntPtr handle)
: base(false)
{
this.SetHandle(handle);
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
return NativeMethods.CloseHandle(this.handle);
}
}
[SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
public sealed class SafeProcessHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeProcessHandle() : base(true) { }
public SafeProcessHandle(IntPtr handle)
: base(false)
{
this.SetHandle(handle);
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
return NativeMethods.CloseHandle(this.handle);
}
}
[SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
public sealed class SafeImpersonationToken : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeImpersonationToken() : base(true) { }
public SafeImpersonationToken(IntPtr token)
: base(false)
{
this.SetHandle(token);
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle()
{
return NativeMethods.CloseHandle(this.handle);
}
}
/// <summary>
/// Wrapped native methods
/// </summary>
[SuppressUnmanagedCodeSecurity]
public static class NativeMethods
{
public static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
// Create process
public const uint CREATE_UNICODE_ENVIRONMENT = 0x00000400;
public const uint CREATE_SUSPENDED = 0x00000004;
public const uint CREATE_BREAKAWAY_FROM_JOB = 0x01000000;
public const uint CREATE_NO_WINDOW = 0x08000000;
// LogonUser
public const uint LOGON32_LOGON_INTERACTIVE = 0x00000002;
public const uint LOGON32_LOGON_NETWORK = 0x00000003;
public const uint LOGON32_LOGON_BATCH = 0x00000004;
public const uint LOGON32_LOGON_NETWORK_CLEARTEXT = 0x00000008;
public const uint LOGON32_PROVIDER_DEFAULT = 0x00000000;
/// <summary>
/// Error flag for "no error"
/// </summary>
public const int ERROR_OK = 0;
/// <summary>
/// Error flag for insufficient buffer
/// </summary>
public const int ERROR_INSUFFICIENT_BUFFER = 122;
// Job object
public const int JobObjectExtendedLimitInformationClass = 9;
public const uint JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE = 0x00002000;
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STARTUPINFO
{
public Int32 cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwYSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
public struct JobObjectExtendedLimitInformation
{
public Int64 PerProcessUserTimeLimit;
public Int64 PerJobUserTimeLimit;
public UInt32 LimitFlags;
public UIntPtr MinimumWorkingSetSize;
public UIntPtr MaximumWorkingSetSize;
public UInt32 ActiveProcessLimit;
public IntPtr Affinity;
public UInt32 PriorityClass;
public UInt32 SchedulingClass;
public UInt64 ReadOperationCount;
public UInt64 WriteOperationCount;
public UInt64 OtherOperationCount;
public UInt64 ReadTransferCount;
public UInt64 WriteTransferCount;
public UInt64 OtherTransferCount;
public UIntPtr ProcessMemoryLimit;
public UIntPtr JobMemoryLimit;
public UIntPtr PeakProcessMemoryUsed;
public UIntPtr PeakJobMemoryUsed;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public UInt32 nLength;
public UIntPtr lpSecurityAttributes;
}
[DllImport("Kernel32.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CreateProcess([MarshalAs(UnmanagedType.LPTStr)]string lpApplicationName,
StringBuilder lpCommandLine, IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes, bool bInheritHandles,
uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory,
[In] ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("Advapi32.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CreateProcessAsUser(SafeImpersonationToken hToken, [MarshalAs(UnmanagedType.LPTStr)]string lpApplicationName,
StringBuilder lpCommandLine, IntPtr lpProcessAttributes,
IntPtr lpThreadAttributes, bool bInheritHandles,
uint dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory,
[In] ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("Advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public extern static bool LogonUser(string lpszUserName, string lpszDomain, string lpszPassword,
uint dwLogonType, uint dwLogonProvider, out SafeImpersonationToken phToken
);
[DllImport("Kernel32.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetExitCodeProcess(SafeProcessHandle hProcess, out uint lpExitCode);
[DllImport("Kernel32.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool TerminateProcess(SafeProcessHandle hProcess, int uExitCode);
[DllImport("Kernel32.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
public static extern uint ResumeThread(SafeThreadHandle hThread);
[DllImport("kernel32.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr CreateJobObject(IntPtr lpJobAttributes, string lpName);
public const int JobObjectExtendedLimitInformationQuery = 9;
public const int JobObjectExtendedLimitInformationSet = 9;
public const int QueryJobObjectBasicProcessIdList = 3;
[StructLayout(LayoutKind.Sequential)]
public struct JobObjectBasicProcessIdListHeader
{
public UInt32 NumberOfAssignedProcesses;
public UInt32 NumberOfProcessIdsInList;
}
[DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public extern static bool QueryInformationJobObject(
IntPtr hJob,
int query,
out JobObjectExtendedLimitInformation info,
int size,
out int returnedSize
);
[DllImport("kernel32.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public extern static bool SetInformationJobObject(IntPtr hJob, int informationClass, [In] ref JobObjectExtendedLimitInformation info, int size);
[DllImport("kernel32.dll", CallingConvention = CallingConvention.Winapi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public extern static bool AssignProcessToJobObject(IntPtr hJob, SafeProcessHandle hProcess);
[DllImport("kernel32.dll", SetLastError = true)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public extern static bool CloseHandle(IntPtr handle);
[DllImport("kernel32.dll", SetLastError = true)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public extern static bool CloseHandle(HandleRef handleRef);
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public static void SafeCloseValidHandle(HandleRef handleRef)
{
if (handleRef.Handle != IntPtr.Zero && handleRef.Handle != INVALID_HANDLE_VALUE)
{
try
{
CloseHandle(handleRef);
}
catch
{
// Swallow exception
}
}
}
/// <summary>
/// contains information about the current state of both physical and virtual memory, including extended memory
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class MEMORYSTATUSEX
{
/// <summary>
/// Size of the structure, in bytes. You must set this member before calling GlobalMemoryStatusEx.
/// </summary>
public uint dwLength;
/// <summary>
/// Number between 0 and 100 that specifies the approximate percentage of physical memory that is in use (0 indicates no memory use and 100 indicates full memory use).
/// </summary>
public uint dwMemoryLoad;
/// <summary>
/// Total size of physical memory, in bytes.
/// </summary>
public ulong ullTotalPhys;
/// <summary>
/// Size of physical memory available, in bytes.
/// </summary>
public ulong ullAvailPhys;
/// <summary>
/// Size of the committed memory limit, in bytes. This is physical memory plus the size of the page file, minus a small overhead.
/// </summary>
public ulong ullTotalPageFile;
/// <summary>
/// Size of available memory to commit, in bytes. The limit is ullTotalPageFile.
/// </summary>
public ulong ullAvailPageFile;
/// <summary>
/// Total size of the user mode portion of the virtual address space of the calling process, in bytes.
/// </summary>
public ulong ullTotalVirtual;
/// <summary>
/// Size of unreserved and uncommitted memory in the user mode portion of the virtual address space of the calling process, in bytes.
/// </summary>
public ulong ullAvailVirtual;
/// <summary>
/// Size of unreserved and uncommitted memory in the extended portion of the virtual address space of the calling process, in bytes.
/// </summary>
public ulong ullAvailExtendedVirtual;
/// <summary>
/// Initializes a new instance of the <see cref="T:MEMORYSTATUSEX"/> class.
/// </summary>
public MEMORYSTATUSEX()
{
this.dwLength = (uint)Marshal.SizeOf(typeof(NativeMethods.MEMORYSTATUSEX));
}
}
/// <summary>
/// Retrieves information about the system's current usage of both physical and virtual memory.
/// </summary>
/// <param name="lpBuffer">A pointer to a MEMORYSTATUSEX structure that receives information about current memory availability</param>
/// <returns>If the function succeeds, the return value is nonzero. Error code otherwise.</returns>
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer);
/// <summary>
/// Retrieves information about the amount of space that is available on a disk volume, which is the total amount of space,
/// the total amount of free space, and the total amount of free space available to the user that is associated with the calling thread.
/// </summary>
/// <param name="lpDirectoryName">A directory on the disk.</param>
/// <param name="lpFreeBytesAvailable">A pointer to a variable that receives the total number of free bytes on a disk that are available to the user who is associated with the calling thread.</param>
/// <param name="lpTotalNumberOfBytes">A pointer to a variable that receives the total number of bytes on a disk that are available to the user who is associated with the calling thread.</param>
/// <param name="lpTotalNumberOfFreeBytes">A pointer to a variable that receives the total number of free bytes on a disk.</param>
/// <returns></returns>
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern bool GetDiskFreeSpaceEx(string lpDirectoryName,
out ulong lpFreeBytesAvailable,
out ulong lpTotalNumberOfBytes,
out ulong lpTotalNumberOfFreeBytes);
/// <summary>
/// SID Usage Enum
/// </summary>
public enum SID_NAME_USE
{
SidTypeUser = 1,
SidTypeGroup,
SidTypeDomain,
SidTypeAlias,
SidTypeWellKnownGroup,
SidTypeDeletedAccount,
SidTypeInvalid,
SidTypeUnknown,
SidTypeComputer
}
/// <summary>
/// Get SID for account name
/// </summary>
/// <param name="lpSystemName">Compute name</param>
/// <param name="lpAccountName">Account name</param>
/// <param name="Sid">Security ID</param>
/// <param name="cbSid">Number of bytes needed to hold the SID</param>
/// <param name="ReferencedDomainName">Domain name reference by SID</param>
/// <param name="cchReferencedDomainName">Number of bytes needed to hold the domain</param>
/// <param name="peUse">Account type</param>
/// <returns>error flag</returns>
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool LookupAccountName(
string lpSystemName,
string lpAccountName,
[MarshalAs(UnmanagedType.LPArray)] byte[] Sid,
ref uint cbSid,
StringBuilder ReferencedDomainName,
ref uint cchReferencedDomainName,
out SID_NAME_USE peUse);
/// <summary>
/// Retrieves the name of the account for this SID and the name of the first domain on which this SID is found
/// </summary>
/// <param name="lpSystemName">string that specifies the target computer</param>
/// <param name="Sid">the SID to look up</param>
/// <param name="lpName">buffer that receives the account name that corresponds to the Sid parameter</param>
/// <param name="cchName">On input, specifies the size of the lpName buffer. If the function fails because
/// the buffer is too small or if cchName is zero, cchName receives the required buffer size</param>
/// <param name="ReferencedDomainName">buffer that receives the name of the domain where the account name was found.</param>
/// <param name="cchReferencedDomainName">Same as cchName, but for the domain string buffer</param>
/// <param name="peUse">pointer to a variable that receives a SID_NAME_USE value that indicates the type of the account</param>
/// <returns>If the function succeeds, the function returns nonzero.If the function fails, it returns zero</returns>
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool LookupAccountSid(
string lpSystemName,
[MarshalAs(UnmanagedType.LPArray)] byte[] Sid,
StringBuilder lpName,
ref uint cchName,
StringBuilder ReferencedDomainName,
ref uint cchReferencedDomainName,
out SID_NAME_USE peUse);
/// <summary>
/// Converts a security ID pointer to the string value
/// </summary>
/// <param name="pSID">pointer to SID</param>
/// <param name="ptrSid">string value</param>
/// <returns>error flag</returns>
[DllImport("advapi32", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool ConvertSidToStringSid(
[MarshalAs(UnmanagedType.LPArray)] byte[] pSID,
out IntPtr ptrSid);
/// <summary>
/// Frees a pointer
/// </summary>
/// <param name="hMem">pointer to free</param>
/// <returns>error flag</returns>
[DllImport("kernel32.dll")]
public static extern IntPtr LocalFree(IntPtr hMem);
}
}