#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