X Tutup
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information. #nullable enable #if FEATURE_PROCESS using System; using System.Numerics; using System.Runtime.InteropServices; using System.Text; using IronPython.Runtime; using IronPython.Runtime.Operations; [assembly: PythonModule("_winapi", typeof(IronPython.Modules.PythonWinApi), PlatformsAttribute.PlatformFamily.Windows)] namespace IronPython.Modules { public static class PythonWinApi { #region Public API public static object? ConnectNamedPipe(BigInteger handle, bool overlapped = false) { if (overlapped) throw new NotImplementedException(); if (overlapped) { throw new NotImplementedException(); } else { var result = ConnectNamedPipe(checked((IntPtr)(long)handle), IntPtr.Zero); if (!result) throw PythonNT.GetLastWin32Error(); return null; } } public static BigInteger CreateFile([NotNone] string file_name, int desired_access, int share_mode, int security_attributes, int creation_disposition, int flags_and_attributes, BigInteger template_file) { if (security_attributes != 0) throw new NotImplementedException(); if (template_file != 0) throw new NotImplementedException(); var handle = CreateFile(file_name, desired_access, share_mode, IntPtr.Zero, creation_disposition, flags_and_attributes, IntPtr.Zero); if (handle == new IntPtr(-1)) throw PythonNT.GetLastWin32Error(); return (long)handle; } public static BigInteger CreateNamedPipe([NotNone] string name, int open_mode, int pipe_mode, int max_instances, int out_buffer_size, int in_buffer_size, int default_timeout, int security_attributes) { if (security_attributes != 0) throw new NotImplementedException(); var handle = CreateNamedPipePI(name, (uint)open_mode, (uint)pipe_mode, (uint)max_instances, (uint)out_buffer_size, (uint)in_buffer_size, (uint)default_timeout, IntPtr.Zero); if (handle == new IntPtr(-1)) throw PythonNT.GetLastWin32Error(); return (long)handle; } public static PythonTuple CreatePipe(object? pipe_attrs, int size) { SECURITY_ATTRIBUTES pSecA = new SECURITY_ATTRIBUTES(); pSecA.nLength = Marshal.SizeOf(pSecA); if (pipe_attrs != null) { /* If pSec passed in from Python is not NULL * there needs to be some conversion done here...*/ throw new NotImplementedException(); } var result = CreatePipePI(out IntPtr hReadPipe, out IntPtr hWritePipe, ref pSecA, (uint)size); if (!result) throw PythonNT.GetLastWin32Error(); return PythonTuple.MakeTuple((BigInteger)(long)hReadPipe, (BigInteger)(long)hWritePipe); } public static PythonTuple CreateProcess( CodeContext context, string? application_name, string? command_line, object? proc_attrs /*subprocess.py passes None*/, object? thread_attrs /*subprocess.py passes None*/, int? inherit_handles, uint? creation_flags, object? env_mapping, string? current_directory, object? startup_info /* subprocess.py passes STARTUPINFO*/) { PythonOps.TryGetBoundAttr(context, startup_info, "dwFlags", out object? dwFlags); //public Int32 dwFlags; PythonOps.TryGetBoundAttr(context, startup_info, "hStdInput", out object? hStdInput); //public IntPtr hStdInput; PythonOps.TryGetBoundAttr(context, startup_info, "hStdOutput", out object? hStdOutput); //public IntPtr hStdOutput; PythonOps.TryGetBoundAttr(context, startup_info, "hStdError", out object? hStdError); //public IntPtr hStdError; PythonOps.TryGetBoundAttr(context, startup_info, "wShowWindow", out object? wShowWindow); //Int16 wShowWindow; int dwFlagsInt32 = dwFlags != null ? Converter.ConvertToInt32(dwFlags) : 0; IntPtr hStdInputIntPtr = hStdInput != null ? new IntPtr(Converter.ConvertToInt32(hStdInput)) : IntPtr.Zero; IntPtr hStdOutputIntPtr = hStdOutput != null ? new IntPtr(Converter.ConvertToInt32(hStdOutput)) : IntPtr.Zero; IntPtr hStdErrorIntPtr = hStdError != null ? new IntPtr(Converter.ConvertToInt32(hStdError)) : IntPtr.Zero; short wShowWindowInt16 = wShowWindow != null ? Converter.ConvertToInt16(wShowWindow) : (short)0; STARTUPINFO startupInfo = new STARTUPINFO { dwFlags = dwFlagsInt32, hStdInput = hStdInputIntPtr, hStdOutput = hStdOutputIntPtr, hStdError = hStdErrorIntPtr, wShowWindow = wShowWindowInt16 }; // No special security SECURITY_ATTRIBUTES pSecSA = new SECURITY_ATTRIBUTES(); pSecSA.nLength = Marshal.SizeOf(pSecSA); SECURITY_ATTRIBUTES tSecSA = new SECURITY_ATTRIBUTES(); tSecSA.nLength = Marshal.SizeOf(tSecSA); if (proc_attrs != null) { /* If pSec paseed in from Python is not NULL * there needs to be some conversion done here...*/ } if (thread_attrs != null) { /* If tSec paseed in from Python is not NULL * there needs to be some conversion done here...*/ } // If needed convert lpEnvironment Dictionary to lpEnvironmentIntPtr string? lpEnvironment = EnvironmentToNative(context, env_mapping); bool result = CreateProcessPI( string.IsNullOrEmpty(application_name) ? null : application_name/*applicationNameHelper*//*processStartInfo.FileName*/, string.IsNullOrEmpty(command_line) ? null : command_line/*commandLineArgsHelper*//*processStartInfo.Arguments*/, ref pSecSA, ref tSecSA, inherit_handles.HasValue && inherit_handles.Value > 0, creation_flags ?? 0, lpEnvironment, current_directory, ref startupInfo, out PROCESS_INFORMATION lpProcessInformation); if (!result) throw PythonNT.GetLastWin32Error(); IntPtr hp = lpProcessInformation.hProcess; IntPtr ht = lpProcessInformation.hThread; int pid = lpProcessInformation.dwProcessId; int tid = lpProcessInformation.dwThreadId; return PythonTuple.MakeTuple((BigInteger)(long)hp, (BigInteger)(long)ht, pid, tid); static string? EnvironmentToNative(CodeContext context, object? environment) { if (environment == null) { return null; } var dict = environment as PythonDictionary ?? new PythonDictionary(context, environment); var res = new StringBuilder(); foreach (var keyValue in dict) { res.Append(keyValue.Key); res.Append('='); res.Append(keyValue.Value); res.Append('\0'); } return res.ToString(); } } public static void CloseHandle(BigInteger handle) { CloseHandle(new IntPtr((long)handle)); } public static BigInteger DuplicateHandle( BigInteger source_process_handle, BigInteger source_handle, BigInteger target_process_handle, int desired_access, bool inherit_handle, object? DUPLICATE_SAME_ACCESS) { IntPtr currentProcessIntPtr = new IntPtr((long)source_process_handle); IntPtr handleIntPtr = new IntPtr((long)source_handle); IntPtr currentProcess2IntPtr = new IntPtr((long)target_process_handle); bool sameAccess = DUPLICATE_SAME_ACCESS != null && Converter.ConvertToBoolean(DUPLICATE_SAME_ACCESS); var result = DuplicateHandlePI( currentProcessIntPtr, handleIntPtr, currentProcess2IntPtr, out IntPtr lpTargetHandle, Converter.ConvertToUInt32(desired_access), inherit_handle, sameAccess ? (uint)DuplicateOptions.DUPLICATE_SAME_ACCESS : (uint)DuplicateOptions.DUPLICATE_CLOSE_SOURCE ); if (!result) throw PythonNT.GetLastWin32Error(); return (long)lpTargetHandle; } public static void ExitProcess(int exit_code) => Environment.Exit(exit_code); public static BigInteger GetCurrentProcess() => (long)GetCurrentProcessPI(); public static int GetExitCodeProcess(BigInteger process) { GetExitCodeProcessPI(new IntPtr((long)process), out int exitCode); return exitCode; } public static int GetLastError() => Marshal.GetLastWin32Error(); public static string? GetModuleFileName(int module_handle) { // Alternative Managed API: System.Diagnostics.ProcessModule.FileName or System.Reflection.Module.FullyQualifiedName. return System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName; } public static object? GetStdHandle(int std_handle) { var handle = GetStdHandlePI(std_handle); if (handle == IntPtr.Zero) return null; return handle.ToPython(); } public static int GetVersion() { return GetVersionPI(); } public static BigInteger OpenProcess(int desired_access, bool inherit_handle, int process_id) { return OpenProcessPI(desired_access, inherit_handle, process_id).ToInt64(); } public static void TerminateProcess(BigInteger handle, object? exit_code) { uint uExitCodeUint = Converter.ConvertToUInt32(exit_code); bool result = TerminateProcessPI(new IntPtr((long)handle), uExitCodeUint); if (!result) throw PythonNT.GetLastWin32Error(); } public static int WaitForSingleObject(BigInteger handle, int dwMilliseconds) { return WaitForSingleObjectPI(new IntPtr((long)handle), dwMilliseconds); } #endregion #region struct's and enum's [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] internal struct STARTUPINFO { public int cb; public string lpReserved; public string lpDesktop; public string lpTitle; public int dwX; public int dwY; public int dwXSize; public int dwYSize; public int dwXCountChars; public int dwYCountChars; public int dwFillAttribute; public int dwFlags; public short wShowWindow; public short cbReserved2; public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput; public IntPtr hStdError; } [StructLayout(LayoutKind.Sequential)] internal struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public int dwProcessId; public int dwThreadId; } [StructLayout(LayoutKind.Sequential)] internal /*class*/ struct SECURITY_ATTRIBUTES { public int nLength; public IntPtr lpSecurityDescriptor; public int bInheritHandle; } [Flags] internal enum DuplicateOptions : uint { DUPLICATE_CLOSE_SOURCE = (0x00000001),// Closes the source handle. This occurs regardless of any error status returned. DUPLICATE_SAME_ACCESS = (0x00000002), //Ignores the dwDesiredAccess parameter. The duplicate handle has the same access as the source handle. } #endregion #region Privates / PInvokes [DllImport("kernel32.dll", SetLastError = true)] private static extern bool ConnectNamedPipe(IntPtr hNamedPipe, IntPtr lpOverlapped); [DllImport("kernel32.dll", EntryPoint = "CreateFileW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false)] private static extern IntPtr CreateFile( string lpFileName, int dwDesiredAccess, int dwShareMode, IntPtr securityAttrs, int dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile); [DllImport("kernel32.dll", EntryPoint = "CreateNamedPipe", SetLastError = true, CharSet = CharSet.Unicode)] private static extern IntPtr CreateNamedPipePI(string lpName, uint dwOpenMode, uint dwPipeMode, uint nMaxInstances, uint nOutBufferSize, uint nInBufferSize, uint nDefaultTimeOut, IntPtr lpSecurityAttributes); [return: MarshalAs(UnmanagedType.Bool)] [DllImport("kernel32.dll", EntryPoint = "CreateProcess", SetLastError = true)] private static extern bool CreateProcessPI(string? lpApplicationName, string? lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes, [MarshalAs(UnmanagedType.Bool)]bool bInheritHandles, uint dwCreationFlags, string? lpEnvironment, string? lpCurrentDirectory, [In] ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); [DllImport("kernel32.dll", EntryPoint = "CreatePipe")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool CreatePipePI(out IntPtr hReadPipe, out IntPtr hWritePipe, ref SECURITY_ATTRIBUTES lpPipeAttributes, uint nSize); [DllImport("kernel32.dll", SetLastError = true, EntryPoint = "DuplicateHandle")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool DuplicateHandlePI(IntPtr hSourceProcessHandle, IntPtr hSourceHandle, IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle, uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwOptions); [DllImport("kernel32.dll", EntryPoint = "GetCurrentProcess")] private static extern IntPtr GetCurrentProcessPI(); [DllImport("kernel32.dll", SetLastError = true, EntryPoint = "GetExitCodeProcess")] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool GetExitCodeProcessPI(IntPtr hProcess, out /*uint*/ int lpExitCode); [DllImport("kernel32.dll", SetLastError = true, EntryPoint = "GetStdHandle")] private static extern IntPtr GetStdHandlePI(int nStdHandle); [DllImport("kernel32.dll", EntryPoint = "GetVersion")] private static extern int GetVersionPI(); [return: MarshalAs(UnmanagedType.Bool)] [DllImport("kernel32.dll", SetLastError = true, EntryPoint = "CloseHandle")] internal static extern bool CloseHandle(IntPtr hObject); [DllImport("kernel32.dll", SetLastError = true, EntryPoint = "OpenProcess")] private static extern IntPtr OpenProcessPI(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); [DllImport("kernel32.dll", SetLastError = true, EntryPoint = "TerminateProcess")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool TerminateProcessPI(IntPtr hProcess, uint uExitCode); [DllImport("kernel32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true, EntryPoint = "WaitForSingleObject")] internal static extern int WaitForSingleObjectPI(IntPtr hHandle, int dwMilliseconds); #endregion #region Constants public const int CREATE_NEW_CONSOLE = 0x10; public const int CREATE_NEW_PROCESS_GROUP = 0x200; public const int DUPLICATE_CLOSE_SOURCE = 0x1; public const int DUPLICATE_SAME_ACCESS = 0x2; public const int ERROR_ALREADY_EXISTS = 0xb7; public const int ERROR_BROKEN_PIPE = 0x6d; public const int ERROR_IO_PENDING = 0x3e5; public const int ERROR_MORE_DATA = 0xea; public const int ERROR_NETNAME_DELETED = 0x40; public const int ERROR_NO_DATA = 0xe8; public const int ERROR_NO_SYSTEM_RESOURCES = 0x5aa; public const int ERROR_OPERATION_ABORTED = 0x3e3; public const int ERROR_PIPE_BUSY = 0xe7; public const int ERROR_PIPE_CONNECTED = 0x217; public const int ERROR_SEM_TIMEOUT = 0x79; public const int FILE_FLAG_FIRST_PIPE_INSTANCE = 0x80000; public const int FILE_FLAG_OVERLAPPED = 0x40000000; public const int FILE_GENERIC_READ = 0x120089; public const int FILE_GENERIC_WRITE = 0x120116; public const int GENERIC_READ = unchecked((int)0x80000000); public const int GENERIC_WRITE = 0x40000000; public const int INFINITE = unchecked((int)0xffffffff); public const int NMPWAIT_WAIT_FOREVER = unchecked((int)0xffffffff); public const int NULL = 0x0; public const int OPEN_EXISTING = 0x3; public const int PIPE_ACCESS_DUPLEX = 0x3; public const int PIPE_ACCESS_INBOUND = 0x1; public const int PIPE_READMODE_MESSAGE = 0x2; public const int PIPE_TYPE_MESSAGE = 0x4; public const int PIPE_UNLIMITED_INSTANCES = 0xff; public const int PIPE_WAIT = 0x0; public const int PROCESS_ALL_ACCESS = 0x1f0fff; public const int PROCESS_DUP_HANDLE = 0x40; public const int STARTF_USESHOWWINDOW = 0x1; public const int STARTF_USESTDHANDLES = 0x100; public const int STD_ERROR_HANDLE = -12; public const int STD_INPUT_HANDLE = -10; public const int STD_OUTPUT_HANDLE = -11; public const int STILL_ACTIVE = 0x103; public const int SW_HIDE = 0x0; public const int WAIT_ABANDONED_0 = 0x80; public const int WAIT_OBJECT_0 = 0x0; public const int WAIT_TIMEOUT = 0x102; #endregion } } #endif
X Tutup