/// <summary> /// Creates a file stream with the given filename that is deleted when either the /// stream is closed, or the application is terminated. /// </summary> /// <remarks> /// If the file already exists, it is overwritten without any error (CREATE_ALWAYS). /// </remarks> /// <param name="fileName">The full path to the file to create.</param> /// <returns>A Stream with read and write access.</returns> public static FileStream CreateTempFile(string fileName) { IntPtr hFile = SafeNativeMethods.CreateFileW( fileName, NativeConstants.GENERIC_READ | NativeConstants.GENERIC_WRITE, NativeConstants.FILE_SHARE_READ, IntPtr.Zero, NativeConstants.CREATE_ALWAYS, NativeConstants.FILE_ATTRIBUTE_TEMPORARY | NativeConstants.FILE_FLAG_DELETE_ON_CLOSE | NativeConstants.FILE_ATTRIBUTE_NOT_CONTENT_INDEXED, IntPtr.Zero); if (hFile == NativeConstants.INVALID_HANDLE_VALUE) { NativeMethods.ThrowOnWin32Error("CreateFileW returned INVALID_HANDLE_VALUE"); } SafeFileHandle sfhFile = new SafeFileHandle(hFile, true); FileStream stream; try { stream = new FileStream(sfhFile, FileAccess.ReadWrite); } catch (Exception) { SafeNativeMethods.CloseHandle(hFile); hFile = IntPtr.Zero; throw; } return(stream); }
/// <summary> /// Opens the requested directory in the shell's file/folder browser. /// </summary> /// <param name="parent">The window that is currently in the foreground.</param> /// <param name="folderPath">The folder to open.</param> /// <remarks> /// This UI is presented modelessly, in another process, and in the foreground. /// Error handling and messaging (error dialogs) will be handled by the shell, /// and these errors will not be communicated to the caller of this method. /// </remarks> public static void BrowseFolder(IWin32Window parent, string folderPath) { NativeStructs.SHELLEXECUTEINFO sei = new NativeStructs.SHELLEXECUTEINFO(); sei.cbSize = (uint)Marshal.SizeOf(typeof(NativeStructs.SHELLEXECUTEINFO)); sei.fMask = NativeConstants.SEE_MASK_NO_CONSOLE; sei.lpVerb = "open"; sei.lpFile = folderPath; sei.nShow = NativeConstants.SW_SHOWNORMAL; sei.hwnd = parent.Handle; bool bResult = NativeMethods.ShellExecuteExW(ref sei); if (bResult) { if (sei.hProcess != IntPtr.Zero) { SafeNativeMethods.CloseHandle(sei.hProcess); sei.hProcess = IntPtr.Zero; } } else { NativeMethods.ThrowOnWin32Error("ShellExecuteW returned FALSE"); } GC.KeepAlive(parent); }
private void Dispose(bool disposing) { if (disposing) { UnregisterWindow(); } if (this.hFileMapping != IntPtr.Zero) { SafeNativeMethods.CloseHandle(this.hFileMapping); this.hFileMapping = IntPtr.Zero; } }
private static bool EnableCompression(string filePath) { IntPtr hFile = IntPtr.Zero; try { hFile = SafeNativeMethods.CreateFileW( filePath, NativeConstants.GENERIC_READ | NativeConstants.GENERIC_WRITE, NativeConstants.FILE_SHARE_READ | NativeConstants.FILE_SHARE_WRITE | NativeConstants.FILE_SHARE_DELETE, IntPtr.Zero, NativeConstants.OPEN_EXISTING, NativeConstants.FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero); if (hFile == NativeConstants.INVALID_HANDLE_VALUE) { int dwError = Marshal.GetLastWin32Error(); return(false); } ushort cType = NativeConstants.COMPRESSION_FORMAT_DEFAULT; uint dwBytes = 0; bool bResult; unsafe { bResult = NativeMethods.DeviceIoControl( hFile, NativeConstants.FSCTL_SET_COMPRESSION, new IntPtr(&cType), sizeof(ushort), IntPtr.Zero, 0, ref dwBytes, IntPtr.Zero); } return(bResult); } finally { if (hFile != IntPtr.Zero) { SafeNativeMethods.CloseHandle(hFile); hFile = IntPtr.Zero; } } }
/// <summary> /// Opens a file for streaming. This stream should be read from or written /// to sequentially for best performance. Random I/O is still permissible, /// but may not perform as well. /// This file is created in such a way that is it NOT indexed by the system's /// file indexer (e.g., Windows Desktop Search). /// </summary> /// <param name="fileName">The file to open.</param> /// <returns>A Stream object that may be used to read from or write to the file, depending on the fileMode parameter.</returns> public static FileStream OpenStreamingFile(string fileName, FileAccess fileAccess) { uint dwDesiredAccess; uint dwCreationDisposition; switch (fileAccess) { case FileAccess.Read: dwDesiredAccess = NativeConstants.GENERIC_READ; dwCreationDisposition = NativeConstants.OPEN_EXISTING; break; case FileAccess.ReadWrite: dwDesiredAccess = NativeConstants.GENERIC_READ | NativeConstants.GENERIC_WRITE; dwCreationDisposition = NativeConstants.OPEN_ALWAYS; break; case FileAccess.Write: dwDesiredAccess = NativeConstants.GENERIC_WRITE; dwCreationDisposition = NativeConstants.CREATE_NEW; break; default: throw new InvalidEnumArgumentException(); } uint dwFlagsAndAttributes = NativeConstants.FILE_ATTRIBUTE_TEMPORARY | NativeConstants.FILE_FLAG_SEQUENTIAL_SCAN | NativeConstants.FILE_ATTRIBUTE_NOT_CONTENT_INDEXED; IntPtr hFile = SafeNativeMethods.CreateFileW( fileName, dwDesiredAccess, NativeConstants.FILE_SHARE_READ, IntPtr.Zero, dwCreationDisposition, dwFlagsAndAttributes, IntPtr.Zero); if (hFile == NativeConstants.INVALID_HANDLE_VALUE) { NativeMethods.ThrowOnWin32Error("CreateFileW returned INVALID_HANDLE_VALUE"); } FileStream stream; try { SafeFileHandle sfh = new SafeFileHandle(hFile, true); stream = new FileStream(sfh, fileAccess, 512, false); } catch { SafeNativeMethods.CloseHandle(hFile); hFile = IntPtr.Zero; throw; } return(stream); }
private static int ExecRequireNonAdmin(IWin32Window parent, string exePath, string args, out IntPtr hProcess) { int nError = NativeConstants.ERROR_SUCCESS; string commandLine = "\"" + exePath + "\"" + (args == null ? "" : (" " + args)); string dir; try { dir = Path.GetDirectoryName(exePath); } catch (Exception) { dir = null; } IntPtr hWndShell = IntPtr.Zero; IntPtr hShellProcess = IntPtr.Zero; IntPtr hShellProcessToken = IntPtr.Zero; IntPtr hTokenCopy = IntPtr.Zero; IntPtr bstrExePath = IntPtr.Zero; IntPtr bstrCommandLine = IntPtr.Zero; IntPtr bstrDir = IntPtr.Zero; NativeStructs.PROCESS_INFORMATION procInfo = new NativeStructs.PROCESS_INFORMATION(); try { hWndShell = SafeNativeMethods.FindWindowW("Progman", null); if (hWndShell == IntPtr.Zero) { NativeMethods.ThrowOnWin32Error("FindWindowW() returned NULL"); } uint dwThreadId = SafeNativeMethods.GetWindowThreadProcessId(hWndShell, out uint dwPID); if (0 == dwPID) { NativeMethods.ThrowOnWin32Error("GetWindowThreadProcessId returned 0", NativeErrors.ERROR_FILE_NOT_FOUND); } hShellProcess = NativeMethods.OpenProcess(NativeConstants.PROCESS_QUERY_INFORMATION, false, dwPID); if (IntPtr.Zero == hShellProcess) { NativeMethods.ThrowOnWin32Error("OpenProcess() returned NULL"); } bool optResult = NativeMethods.OpenProcessToken( hShellProcess, NativeConstants.TOKEN_ASSIGN_PRIMARY | NativeConstants.TOKEN_DUPLICATE | NativeConstants.TOKEN_QUERY, out hShellProcessToken); if (!optResult) { NativeMethods.ThrowOnWin32Error("OpenProcessToken() returned FALSE"); } bool dteResult = NativeMethods.DuplicateTokenEx( hShellProcessToken, NativeConstants.MAXIMUM_ALLOWED, IntPtr.Zero, NativeConstants.SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, NativeConstants.TOKEN_TYPE.TokenPrimary, out hTokenCopy); if (!dteResult) { NativeMethods.ThrowOnWin32Error("DuplicateTokenEx() returned FALSE"); } bstrExePath = Marshal.StringToBSTR(exePath); bstrCommandLine = Marshal.StringToBSTR(commandLine); bstrDir = Marshal.StringToBSTR(dir); bool cpwtResult = NativeMethods.CreateProcessWithTokenW( hTokenCopy, 0, bstrExePath, bstrCommandLine, 0, IntPtr.Zero, bstrDir, IntPtr.Zero, out procInfo); if (cpwtResult) { hProcess = procInfo.hProcess; procInfo.hProcess = IntPtr.Zero; nError = NativeConstants.ERROR_SUCCESS; } else { hProcess = IntPtr.Zero; nError = Marshal.GetLastWin32Error(); } } catch (Win32Exception ex) { Tracing.Ping(ex.ToString()); nError = ex.ErrorCode; hProcess = IntPtr.Zero; } finally { if (bstrExePath != IntPtr.Zero) { Marshal.FreeBSTR(bstrExePath); bstrExePath = IntPtr.Zero; } if (bstrCommandLine != IntPtr.Zero) { Marshal.FreeBSTR(bstrCommandLine); bstrCommandLine = IntPtr.Zero; } if (bstrDir != IntPtr.Zero) { Marshal.FreeBSTR(bstrDir); bstrDir = IntPtr.Zero; } if (hShellProcess != IntPtr.Zero) { SafeNativeMethods.CloseHandle(hShellProcess); hShellProcess = IntPtr.Zero; } if (hShellProcessToken != IntPtr.Zero) { SafeNativeMethods.CloseHandle(hShellProcessToken); hShellProcessToken = IntPtr.Zero; } if (hTokenCopy != IntPtr.Zero) { SafeNativeMethods.CloseHandle(hTokenCopy); hTokenCopy = IntPtr.Zero; } if (procInfo.hThread != IntPtr.Zero) { SafeNativeMethods.CloseHandle(procInfo.hThread); procInfo.hThread = IntPtr.Zero; } if (procInfo.hProcess != IntPtr.Zero) { SafeNativeMethods.CloseHandle(procInfo.hProcess); procInfo.hProcess = IntPtr.Zero; } } return(nError); }
/// <summary> /// Uses the shell to execute the command. This method must only be used by Paint.NET /// and not by plugins. /// </summary> /// <param name="parent"> /// The window that is currently in the foreground. This may be null if requireAdmin /// is false and the executable that exePath refers to is not marked (e.g. via a /// manifest) as requiring administrator privilege. /// </param> /// <param name="exePath"> /// The path to the executable to launch. /// </param> /// <param name="args"> /// The command-line arguments for the executable. /// </param> /// <param name="execPrivilege"> /// The privileges to execute the new process with. /// If the executable is already marked as requiring administrator privilege /// (e.g. via a "requiresAdministrator" UAC manifest), this parameter should be /// set to AsInvokerOrAsManifest. /// </param> /// <remarks> /// If administrator privilege is required, a consent UI may be displayed asking the /// user to approve the action. A parent window must be provided in this case so that /// the consent UI will know where to position itself. Administrator privilege is /// required if execPrivilege is set to RequireAdmin, or if the executable being launched /// has a manifest declaring that it requires this privilege and if the operating /// system recognizes the manifest. /// </remarks> /// <exception cref="ArgumentException"> /// execPrivilege was RequireAdmin, but parent was null. /// </exception> /// <exception cref="SecurityException"> /// execPrivilege was RequireAdmin, but the user does not have this privilege, nor do they /// have the ability to acquire or elevate to obtain this privilege. /// </exception> /// <exception cref="Win32Exception"> /// There was an error launching the program. /// </exception> public static void Execute( IWin32Window parent, string exePath, string args, ExecutePrivilege execPrivilege, ExecuteWaitType execWaitType) { if (exePath == null) { throw new ArgumentNullException("exePath"); } if (execPrivilege == ExecutePrivilege.RequireAdmin && parent == null) { throw new ArgumentException("If requireAdmin is true, a parent window must be provided"); } // If this action requires admin privilege, but the user does not have this // privilege and is not capable of acquiring this privilege, then we will // throw an exception. if (execPrivilege == ExecutePrivilege.RequireAdmin && !Security.IsAdministrator && !Security.CanElevateToAdministrator) { throw new SecurityException("Executable requires administrator privilege, but user is not an administrator and cannot elevate"); } ExecuteHandOff executeHandOff = null; switch (execPrivilege) { case ExecutePrivilege.AsInvokerOrAsManifest: executeHandOff = new ExecuteHandOff(ExecAsInvokerOrAsManifest); break; case ExecutePrivilege.RequireAdmin: executeHandOff = new ExecuteHandOff(ExecRequireAdmin); break; case ExecutePrivilege.RequireNonAdminIfPossible: if (Security.CanLaunchNonAdminProcess) { executeHandOff = new ExecuteHandOff(ExecRequireNonAdmin); } else { executeHandOff = new ExecuteHandOff(ExecAsInvokerOrAsManifest); } break; default: throw new InvalidEnumArgumentException("ExecutePrivilege"); } string updateMonitorExePath = null; if (execWaitType == ExecuteWaitType.RelaunchPdnOnExit) { RelaunchPdnHelperPart1(out updateMonitorExePath); } IntPtr hProcess = IntPtr.Zero; int nResult = executeHandOff(parent, exePath, args, out hProcess); if (nResult == NativeConstants.ERROR_SUCCESS) { if (execWaitType == ExecuteWaitType.WaitForExit) { SafeNativeMethods.WaitForSingleObject(hProcess, NativeConstants.INFINITE); } else if (execWaitType == ExecuteWaitType.RelaunchPdnOnExit) { bool bResult2 = SafeNativeMethods.SetHandleInformation( hProcess, NativeConstants.HANDLE_FLAG_INHERIT, NativeConstants.HANDLE_FLAG_INHERIT); RelaunchPdnHelperPart2(updateMonitorExePath, hProcess); // Ensure that we don't close the process handle right away in the next few lines of code. // It must be inherited by the child process. Yes, this is technically a leak but we are // planning to terminate in just a moment anyway. hProcess = IntPtr.Zero; } else if (execWaitType == ExecuteWaitType.ReturnImmediately) { } if (hProcess != IntPtr.Zero) { SafeNativeMethods.CloseHandle(hProcess); hProcess = IntPtr.Zero; } } else { if (nResult == NativeConstants.ERROR_CANCELLED || nResult == NativeConstants.ERROR_TIMEOUT) { // no problem } else { NativeMethods.ThrowOnWin32Error("ExecuteHandoff failed", nResult); } if (updateMonitorExePath != null) { try { File.Delete(updateMonitorExePath); } catch (Exception) { } updateMonitorExePath = null; } } GC.KeepAlive(parent); }
/// <summary> /// Uses the shell to execute the command. This method must only be used by Paint.NET /// and not by plugins. /// </summary> /// <param name="parent"> /// The window that is currently in the foreground. This may be null if requireAdmin /// is false and the executable that exePath refers to is not marked (e.g. via a /// manifest) as requiring administrator privilege. /// </param> /// <param name="exePath"> /// The path to the executable to launch. /// </param> /// <param name="args"> /// The command-line arguments for the executable. /// </param> /// <param name="requireAdmin"> /// Whether or not administrator privilege is required to launch this. However, /// if the executable is already marked as requiring administrator privilege /// (e.g. via a "requiresAdministrator" UAC manifest), this parameter should be /// set to false. /// </param> /// <remarks> /// If administrator privilege is required, a consent UI may be displayed asking the /// user to approve the action. A parent window must be provided in this case so that /// the consent UI will know where to position itself. Administrator privilege is /// required if requireAdmin is set to true, or if the executable being launched /// has a manifest declaring that it requires this privilege and if the operating /// system recognizes the manifest. /// </remarks> /// <exception cref="ArgumentException"> /// requireAdmin was true, but parent was null. /// </exception> /// <exception cref="SecurityException"> /// requireAdmin was true, but the user does not have this privilege, nor do they /// have the ability to acquire or elevate to obtain this privilege. /// </exception> /// <exception cref="Win32Exception"> /// There was an error launching the program. /// </exception> public static void Execute( IWin32Window parent, string exePath, string args, bool requireAdmin, ExecuteWaitType executeWaitType) { const string runAs = "runas"; if (exePath == null) { throw new ArgumentNullException("exePath"); } if (requireAdmin && parent == null) { throw new ArgumentException("If requireAdmin is true, a parent window must be provided"); } // If this action requires admin privilege, but the user does not have this // privilege and is not capable of acquiring this privilege, then we will // throw an exception. if (requireAdmin && !Security.IsAdministrator && !Security.CanElevateToAdministrator) { throw new SecurityException("Executable requires administrator privilege, but user is not an administrator and cannot elevate"); } NativeStructs.SHELLEXECUTEINFO sei = new NativeStructs.SHELLEXECUTEINFO(); sei.cbSize = (uint)Marshal.SizeOf(typeof(NativeStructs.SHELLEXECUTEINFO)); sei.fMask = NativeConstants.SEE_MASK_NOCLOSEPROCESS | NativeConstants.SEE_MASK_NO_CONSOLE | NativeConstants.SEE_MASK_FLAG_DDEWAIT; if (requireAdmin && !Security.IsAdministrator) { sei.lpVerb = runAs; } string dir; try { dir = Path.GetDirectoryName(exePath); } catch (Exception) { dir = null; } sei.lpDirectory = dir; sei.lpFile = exePath; sei.lpParameters = args; sei.nShow = NativeConstants.SW_SHOWNORMAL; if (parent != null) { sei.hwnd = parent.Handle; } string updateMonitorExePath = null; if (executeWaitType == ExecuteWaitType.RelaunchPdnOnExit) { RelaunchPdnHelperPart1(out updateMonitorExePath); } bool bResult = NativeMethods.ShellExecuteExW(ref sei); if (bResult) { if (executeWaitType == ExecuteWaitType.WaitForExit) { SafeNativeMethods.WaitForSingleObject(sei.hProcess, NativeConstants.INFINITE); } else if (executeWaitType == ExecuteWaitType.RelaunchPdnOnExit) { bool bResult2 = SafeNativeMethods.SetHandleInformation( sei.hProcess, NativeConstants.HANDLE_FLAG_INHERIT, NativeConstants.HANDLE_FLAG_INHERIT); RelaunchPdnHelperPart2(updateMonitorExePath, sei.hProcess); // Ensure that we don't close the process handle right away in the next few lines of code. // It must be inherited by the child process. sei.hProcess = IntPtr.Zero; } else if (executeWaitType == ExecuteWaitType.ReturnImmediately) { } if (sei.hProcess != IntPtr.Zero) { SafeNativeMethods.CloseHandle(sei.hProcess); sei.hProcess = IntPtr.Zero; } } else { int dwError = Marshal.GetLastWin32Error(); if (dwError != NativeConstants.ERROR_CANCELLED) { NativeMethods.ThrowOnWin32Error("ShellExecuteW returned FALSE"); } if (updateMonitorExePath != null) { try { File.Delete(updateMonitorExePath); } catch (Exception) { } updateMonitorExePath = null; } } GC.KeepAlive(parent); }