123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769 |
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Diagnostics;
- using System.Drawing;
- using System.Globalization;
- using System.IO;
- using System.Runtime.InteropServices;
- using System.Security;
- using System.Text;
- using System.Threading;
- using System.Windows.Forms;
- namespace PaintDotNet.SystemLayer
- {
- public static class Shell
- {
- public static bool ReplaceMissingFiles(string[] missingFiles)
- {
- StringBuilder missingFilesSB = new StringBuilder();
- for (int i = 0; i < missingFiles.Length; ++i)
- {
- missingFilesSB.Append(missingFiles[i]);
- if (i != missingFiles.Length - 1)
- {
- missingFilesSB.Append(", ");
- }
- }
- try
- {
- // If they are not an admin and have no possibility of elevating, such as for a standard User
- // in XP, then give them an error. Unfortunately we do not know if we can even load text
- // resources at this point, and so must provide an English-only error message.
- if (!Security.IsAdministrator && !Security.CanElevateToAdministrator)
- {
- MessageBox.Show(
- null,
- "Metis Vision has detected that some important installation files are missing. Repairing " +
- "this requires administrator privilege. Please run the 'PdnRepair.exe' program in the installation " +
- "directory after logging in with a user that has administrator privilege." + Environment.NewLine +
- Environment.NewLine +
- "The missing files are: " + missingFilesSB.ToString(),
- "Metis Vision",
- MessageBoxButtons.OK,
- MessageBoxIcon.Error);
- return false;
- }
- const int hMargin = 8;
- const int vMargin = 8;
- Form form = new Form();
- form.Text = "Metis Vision";
- form.ClientSize = new Size(400, 10);
- form.StartPosition = FormStartPosition.CenterScreen;
- Label infoLabel = new Label();
- form.Controls.Add(infoLabel);
- infoLabel.Text =
- "Metis Vision has detected that some important installation files are missing. If you click " +
- "the Repair button it will attempt to repair this and then continue loading." + Environment.NewLine +
- Environment.NewLine +
- "The missing files are: " + missingFilesSB.ToString();
- #if DEBUG
- infoLabel.Text += Environment.NewLine + Environment.NewLine +
- "*** Since this is a DEBUG build, you should probably add /skipRepairAttempt to the command-line.";
- #endif
- infoLabel.Location = new Point(hMargin, vMargin);
- infoLabel.Width = form.ClientSize.Width - hMargin * 2;
- infoLabel.Height = infoLabel.GetPreferredSize(new Size(infoLabel.Width, 1)).Height;
- Button repairButton = new Button();
- form.Controls.Add(repairButton);
- repairButton.Text = "&Repair";
- Exception exception = null;
- repairButton.Click +=
- delegate (object sender, EventArgs e)
- {
- form.DialogResult = DialogResult.Yes;
- repairButton.Enabled = false;
- try
- {
- Shell.Execute(form, "PdnRepair.exe", "/noPause", ExecutePrivilege.AsInvokerOrAsManifest, ExecuteWaitType.WaitForExit);
- }
- catch (Exception ex)
- {
- exception = ex;
- }
- };
- repairButton.AutoSize = true;
- repairButton.PerformLayout();
- repairButton.Width += 20;
- repairButton.Location = new Point((form.ClientSize.Width - repairButton.Width) / 2, infoLabel.Bottom + vMargin * 2);
- repairButton.FlatStyle = FlatStyle.System;
- UI.EnableShield(repairButton, true);
- form.FormBorderStyle = FormBorderStyle.FixedDialog;
- form.MinimizeBox = false;
- form.MaximizeBox = false;
- form.ShowInTaskbar = true;
- form.Icon = null;
- form.ClientSize = new Size(form.ClientRectangle.Width, repairButton.Bottom + vMargin);
- DialogResult result = form.ShowDialog(null);
- form.Dispose();
- form = null;
- if (result == DialogResult.Yes)
- {
- return true;
- }
- else if (exception == null)
- {
- return false;
- }
- else
- {
- throw new Exception("", exception); // ("Error while attempting to repair", exception);
- }
- }
- catch (Exception ex)
- {
- throw new Exception("", ex); //
- //("Could not repair installation after it was determined that the following files are missing: " +
- //missingFilesSB.ToString(), ex);
- }
- }
- /// <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);
- }
- #if false
- [Obsolete("Do not use this method.", true)]
- public static void Execute(
- IWin32Window parent,
- string exePath,
- string args,
- bool requireAdmin)
- {
- Execute(parent, exePath, args, requireAdmin ? ExecutePrivilege.RequireAdmin : ExecutePrivilege.AsInvokerOrAsManifest, ExecuteWaitType.ReturnImmediately);
- }
- #endif
- private const string updateExeFileName = "UpdateMonitor.exe";
- private delegate int ExecuteHandOff(IWin32Window parent, string exePath, string args, out IntPtr hProcess);
- /// <summary>
- /// Uses the shell to execute the command.
- /// 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);
- }
- private static int ExecAsInvokerOrAsManifest(IWin32Window parent, string exePath, string args, out IntPtr hProcess)
- {
- return ExecShellExecuteEx(parent, exePath, args, null, out hProcess);
- }
- private static int ExecRequireAdmin(IWin32Window parent, string exePath, string args, out IntPtr hProcess)
- {
- const string runAs = "runas";
- string verb;
- if (Security.IsAdministrator)
- {
- verb = null;
- }
- else
- {
- verb = runAs;
- }
- return ExecShellExecuteEx(parent, exePath, args, verb, out hProcess);
- }
- 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 dwPID;
- uint dwThreadId = SafeNativeMethods.GetWindowThreadProcessId(hWndShell, out 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;
- }
- private static int ExecShellExecuteEx(IWin32Window parent, string exePath, string args, string verb, out IntPtr hProcess)
- {
- string dir;
- try
- {
- dir = Path.GetDirectoryName(exePath);
- }
- catch (Exception)
- {
- dir = null;
- }
- 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;
- sei.lpVerb = verb;
- sei.lpDirectory = dir;
- sei.lpFile = exePath;
- sei.lpParameters = args;
- sei.nShow = NativeConstants.SW_SHOWNORMAL;
- if (parent != null)
- {
- sei.hwnd = parent.Handle;
- }
- bool bResult = NativeMethods.ShellExecuteExW(ref sei);
- hProcess = sei.hProcess;
- sei.hProcess = IntPtr.Zero;
- int nResult = NativeConstants.ERROR_SUCCESS;
- if (!bResult)
- {
- nResult = Marshal.GetLastWin32Error();
- }
- return nResult;
- }
- private static void RelaunchPdnHelperPart1(out string updateMonitorExePath)
- {
- string srcDir = Application.StartupPath;
- string srcPath = Path.Combine(srcDir, updateExeFileName);
- string srcPath2 = srcPath + ".config";
- string dstDir = Environment.ExpandEnvironmentVariables(@"%TEMP%\PdnSetup");
- string dstPath = Path.Combine(dstDir, updateExeFileName);
- string dstPath2 = dstPath + ".config";
- if (!Directory.Exists(dstDir))
- {
- Directory.CreateDirectory(dstDir);
- }
- File.Copy(srcPath, dstPath, true);
- File.Copy(srcPath2, dstPath2, true);
- updateMonitorExePath = dstPath;
- }
- private static void RelaunchPdnHelperPart2(string updateMonitorExePath, IntPtr hProcess)
- {
- string args = hProcess.ToInt64().ToString(CultureInfo.InstalledUICulture);
- ProcessStartInfo psi = new ProcessStartInfo(updateMonitorExePath, args);
- psi.UseShellExecute = false;
- psi.WindowStyle = ProcessWindowStyle.Hidden;
- Process process = Process.Start(psi);
- process.Dispose();
- }
- /// <summary>
- /// 用默认浏览器打开Url
- /// </summary>
- /// <param name="url">url地址,最长长度512</param>
- public static bool LaunchUrl(IWin32Window owner, string url)
- {
- if (url.Length > 512)
- {
- throw new ArgumentOutOfRangeException("url.Length must be <= 512");
- }
- bool success = false;
- string quotedUrl = "\"" + url + "\"";
- ExecutePrivilege executePrivilege;
- if (!Security.IsAdministrator || (Security.IsAdministrator && !Security.CanLaunchNonAdminProcess))
- {
- executePrivilege = ExecutePrivilege.AsInvokerOrAsManifest;
- }
- else
- {
- executePrivilege = ExecutePrivilege.RequireNonAdminIfPossible;
- }
- // Method 1. Just launch the url, and hope that the shell figures out the association correctly.
- // This method will not work with ExecutePrivilege.RequireNonAdmin though.
- if (!success && executePrivilege != ExecutePrivilege.RequireNonAdminIfPossible)
- {
- try
- {
- Execute(owner, quotedUrl, null, executePrivilege, ExecuteWaitType.ReturnImmediately);
- success = true;
- }
- catch (Exception ex)
- {
- Tracing.Ping("Exception while using method 1 to launch url, " + quotedUrl + ", :" + ex.ToString());
- success = false;
- }
- }
- // Method 2. Launch the url through explorer
- if (!success)
- {
- const string shellFileLoc = @"%WINDIR%\explorer.exe";
- string shellExePath = "(n/a)";
- try
- {
- shellExePath = Environment.ExpandEnvironmentVariables(shellFileLoc);
- Execute(owner, shellExePath, quotedUrl, executePrivilege, ExecuteWaitType.ReturnImmediately);
- success = true;
- }
- catch (Exception ex)
- {
- Tracing.Ping("Exception while using method 2 to launch url through '" + shellExePath + "', " + quotedUrl + ", : " + ex.ToString());
- success = false;
- }
- }
- return success;
- }
- public static void AddToRecentDocumentsList(string fileName)
- {
- // Apparently SHAddToRecentDocs can block for a very long period of time when certain
- // conditions are met: so we just stick it on "the backburner."
- ThreadPool.QueueUserWorkItem(new WaitCallback(AddToRecentDocumentsListImpl), fileName);
- }
- private static void AddToRecentDocumentsListImpl(object fileNameObj)
- {
- string fileName = (string)fileNameObj;
- IntPtr bstrFileName = IntPtr.Zero;
- try
- {
- bstrFileName = Marshal.StringToBSTR(fileName);
- NativeMethods.SHAddToRecentDocs(NativeConstants.SHARD_PATHW, bstrFileName);
- }
- finally
- {
- if (bstrFileName != IntPtr.Zero)
- {
- Marshal.FreeBSTR(bstrFileName);
- bstrFileName = IntPtr.Zero;
- }
- }
- }
- private static T2 Map<T1, T2>(T1 mapFrom, Pair<T1, T2>[] mappings)
- {
- foreach (Pair<T1, T2> mapping in mappings)
- {
- if (mapping.First.Equals(mapFrom))
- {
- return mapping.Second;
- }
- }
- throw new KeyNotFoundException();
- }
- private static string GetCSIDLPath(int csidl, bool tryCreateIfAbsent)
- {
- // First, try calling SHGetFolderPathW with the "CSIDL_FLAG_CREATE" flag. However, if it
- // returns an error then ignore it. We've had some crash logs with "access denied" coming
- // from this function.
- int csidlWithFlags = csidl | (tryCreateIfAbsent ? NativeConstants.CSIDL_FLAG_CREATE : 0);
- StringBuilder sbWithFlags = new StringBuilder(NativeConstants.MAX_PATH);
- Do.TryBool(() => NativeMethods.SHGetFolderPathW(IntPtr.Zero, csidlWithFlags, IntPtr.Zero, NativeConstants.SHGFP_TYPE_CURRENT, sbWithFlags));
- StringBuilder sb = new StringBuilder(NativeConstants.MAX_PATH);
- NativeMethods.SHGetFolderPathW(IntPtr.Zero, csidl, IntPtr.Zero, NativeConstants.SHGFP_TYPE_CURRENT, sb);
- // If we get back something like 'Z:' then we need to put a backslash on it.
- // Otherwise other path-related functions will freak out.
- if (sb.Length == 2 && sb[1] == ':')
- {
- sb.Append(Path.DirectorySeparatorChar);
- }
- string path = sb.ToString();
- return path;
- }
- private static readonly Pair<VirtualFolderName, int>[] pathMappings = new Pair<VirtualFolderName, int>[]
- {
- Pair.Create(VirtualFolderName.SystemProgramFiles, NativeConstants.CSIDL_PROGRAM_FILES),
- Pair.Create(VirtualFolderName.UserDesktop, NativeConstants.CSIDL_DESKTOP_DIRECTORY),
- Pair.Create(VirtualFolderName.UserDocuments, NativeConstants.CSIDL_PERSONAL),
- Pair.Create(VirtualFolderName.UserLocalAppData, NativeConstants.CSIDL_LOCAL_APPDATA),
- Pair.Create(VirtualFolderName.UserPictures, NativeConstants.CSIDL_MYPICTURES),
- Pair.Create(VirtualFolderName.UserRoamingAppData, NativeConstants.CSIDL_APPDATA)
- };
- public static string GetVirtualPath(VirtualFolderName folderName, bool tryCreateIfAbsent)
- {
- try
- {
- int csidl = Map(folderName, pathMappings);
- string path = GetCSIDLPath(csidl, tryCreateIfAbsent);
- return path;
- }
- catch (KeyNotFoundException)
- {
- throw new InvalidEnumArgumentException("folderName", (int)folderName, typeof(VirtualFolderName));
- }
- }
- }
- }
|