#region CPL License /* Nuclex.NAnt.Tasks Copyright (C) 2009 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #endregion using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using System.ComponentModel; namespace Nuclex.NAnt.Tasks.Helpers { /// Provides access to the known folders of the operating system internal static class KnownFolders { #region class Vista /// Helper class for working with system paths on windows private class Vista { /// Path of the program files folder public static string ProgramFilesPath { get { return getKnownFolderPath(programFiles); } } /// /// Path of the 32 bit program files folder, even in a 64 bit environment /// public static string ProgramFilesPathX86 { get { return getKnownFolderPath(programFilesX86); } } /// /// Path of the 64 bit program files folder, even in a WOW32 environment /// public static string ProgramFilesPathX64 { get { return getKnownFolderPath(programFilesX64); } } /// Obtains the path of a system folder on windows /// /// ID of the system folder whose path will be obtained /// /// The path to the requested system folder private static string getKnownFolderPath(Guid knownFolderId) { IntPtr pathMemory; int result = SHGetKnownFolderPath(knownFolderId, 0, IntPtr.Zero, out pathMemory); if(result != 0) { // result != S_OK throw new System.ComponentModel.Win32Exception( result, "SHGetKnownFolderPath() failed unexpectedly" ); } try { return Marshal.PtrToStringUni(pathMemory); } finally { Marshal.FreeCoTaskMem(pathMemory); } } /// /// "Program Files" folder, depending on the running application's bitness /// private static readonly Guid programFiles = new Guid( "905e63b6-c1bf-494e-b29c-65b732d3d21a" ); /// /// "Program Files" folder on x64 systems, undefined on x86 systems /// private static readonly Guid programFilesX64 = new Guid( "6d809377-6af0-444b-8957-a3773f02200e" ); /// /// "Program Files (x86)" folder on x64 systems and "Program Files" folder /// on x86 systems. /// private static readonly Guid programFilesX86 = new Guid( "7c5a40ef-a0fb-4bfc-874a-c0f2e0b9fa8e" ); /// /// Retrieves the full path of a known folder identified by the folder's KNOWNFOLDERID /// /// KNOWNFOLDERID that identifies the folder /// /// Retrieval options. This value can be 0; otherwise, one or more of /// the KNOWN_FOLDER_FLAG values /// /// /// An access token that represents a particular user. If this parameter is NULL, /// which is the most common usage, the function requests the known folder for /// the current user /// /// /// When this method returns, contains the address of a pointer to a null-terminated /// Unicode string that specifies the path of the known folder. The calling process /// is responsible for freeing this resource once it is no longer needed by /// calling CoTaskMemFree() /// /// Returns S_OK if successful, or an error value otherwise [DllImport("shell32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)] private static extern int SHGetKnownFolderPath( [MarshalAs(UnmanagedType.LPStruct)] Guid folderId, uint flags, IntPtr token, out IntPtr path ); } #endregion // class Vista /// Initializes the KnownFolders class static KnownFolders() { if(OsHelper.IsWindows) { ProgramFilesPath = findProgramFilesPath(); ProgramFiles32Path = findProgramFiles32Path(); if(EnvironmentHelper.RunningOn64BitOS) { ProgramFiles64Path = findProgramFiles64Path(); } } } /// Finds the path to the program files folder private static string findProgramFilesPath() { Debug.Assert(OsHelper.IsWindows); return Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles); } /// Finds the path of the 64 bit program files folder private static string findProgramFiles64Path() { Debug.Assert(OsHelper.IsWindows); Debug.Assert(EnvironmentHelper.RunningOn64BitOS); // If on Vista or later, try to query directly from the operating system string programFilesPath; if(OsHelper.IsVistaOrLater) { try { programFilesPath = Vista.ProgramFilesPathX64; if(isPathValid(programFilesPath)) { return programFilesPath; } } catch(Win32Exception) { } } // Next, try the environment variable programFilesPath = Environment.GetEnvironmentVariable("ProgramW6432"); if(isPathValid(programFilesPath)) { return programFilesPath; } // All failed, we give up throw new Exception("Could not determine path to 64 bit program files folder"); } /// Finds the path of the 32 bit program files folder private static string findProgramFiles32Path() { Debug.Assert(OsHelper.IsWindows); // If we're on a 32 bit os, the program files folder can be queried normally if(!EnvironmentHelper.RunningOn64BitOS) { return findProgramFilesPath(); } // If on Vista or later, try to query directly from the operating system string programFilesPath; if(OsHelper.IsVistaOrLater) { programFilesPath = Vista.ProgramFilesPathX86; if(isPathValid(programFilesPath)) { return programFilesPath; } } // Next, try the environment variable programFilesPath = Environment.GetEnvironmentVariable("ProgramFiles(x86)"); if(isPathValid(programFilesPath)) { return programFilesPath; } // All failed, we give up throw new Exception("Could not determine path to 32 bit program files folder"); } /// Checks whether the provided path is valid /// Path that will be checked /// True if the provided path is valid private static bool isPathValid(string path) { return (path != null) && (path != string.Empty) && Directory.Exists(path); } /// /// Path to the program files folder, depending on the architecture of /// the operating system /// public static readonly string ProgramFilesPath; /// Path to the 32 bit program files folder public static readonly string ProgramFiles32Path; /// Path to the 64 bit program files folder public static readonly string ProgramFiles64Path; } } // namespace Nuclex.NAnt.Tasks.Helpers