using System;
using System.IO;
using System.Management;
using System.Runtime.InteropServices;
using System.Text;
using Developpez.Dotnet.System.Providers.Windows;
using Microsoft.Win32;
namespace Developpez.Dotnet.System.Providers
{
///
/// Fournisseur d'informations systèmes sur l'environnement Windows
///
public class WindowsProvider : NullSystemProvider
{
///
/// Initialise une nouvelle instance de WindowsProvider
///
protected internal WindowsProvider()
{
}
#region Display name
///
/// Obtient le nom du système grâce aux WMI, sans jamais lever d'exception
///
protected virtual string OSName
{
get
{
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("root\\CIMV2",
"SELECT * FROM Win32_OperatingSystem");
foreach (ManagementObject queryObj in searcher.Get())
{
return queryObj["Caption"] as string;
}
/* non trouvé */
return null;
}
}
///
/// Renvoi le nom du système. Equivalent à dans la plupart
/// des cas
///
public override string PlatformDisplayName
{
get
{
string val = OSName;
if (String.IsNullOrEmpty(val))
return Environment.OSVersion.VersionString;
return val;
}
}
#endregion
#region Reboot
///
/// Accorde au processus actuel le droit d'effectuer un redémarrage du système
///
/// true si l'opération est un succès, false sinon
protected virtual bool AdjustShutdownTokenPrivileges()
{
IntPtr hToken;
LUID luidRestore;
TOKEN_PRIVILEGES tokenPriviliges;
// get the current current process security token
IntPtr hProc = global::System.Diagnostics.Process.GetCurrentProcess().Handle;
bool ret = Win32Api.OpenProcessToken(hProc, Win32Api.TOKEN_ADJUST_PRIVILEGES | Win32Api.TOKEN_QUERY, out hToken);
if (!ret)
return false;
// lookup the LUID for the shutdown privilege
ret = Win32Api.LookupPrivilegeValue(String.Empty, Win32Api.SE_SHUTDOWN_NAME, out luidRestore);
if (!ret)
return false;
// adjust the privileges of the current process to include the shutdown privilege
tokenPriviliges.PrivilegeCount = 1;
tokenPriviliges.Luid = luidRestore;
tokenPriviliges.Attributes = Win32Api.SE_PRIVILEGE_ENABLED;
//TOKEN_PRIVILEGES tokenTemp = new TOKEN_PRIVILEGES();
ret = Win32Api.AdjustTokenPrivileges(hToken, false, ref tokenPriviliges, 0, IntPtr.Zero, IntPtr.Zero);
if (!ret)
return false;
return true;
}
///
/// Convertit une valeur RebootReason en ShutdownReason équivalent
///
/// Infrastructure
/// Raison du redémarrage
/// Valeur convertie
internal virtual ShutdownReason ParseRebootReason(RebootReason reason)
{
switch (reason)
{
case RebootReason.InstallApplication:
return ShutdownReason.MajorApplication | ShutdownReason.MinorInstallation;
case RebootReason.UnInstallApplication:
return ShutdownReason.MajorApplication | ShutdownReason.MinorMaintenance;
case RebootReason.UpdateApplication:
return ShutdownReason.MajorApplication | ShutdownReason.MinorUpgrade;
default:
//case RebootReason.None:
return ShutdownReason.MajorOther | ShutdownReason.MinorOther;
}
}
///
/// Redémarre le système avec la raison spécifiée
///
/// Raison du redémarrage
/// true si le redémarrage a été initialisé, false sinon
public override bool Reboot(RebootReason reason)
{
// Ajuster les privilèges
if (!AdjustShutdownTokenPrivileges())
return false;
// Et on ferme windows
return Win32Api.ExitWindowsEx(ShutdownMethod.Reboot, ParseRebootReason(reason));
}
#endregion
#region Framework version
///
/// Obtient la version installée du Framework .NET
///
/// Version du Framework
public override FrameworkVersion GetFrameworkVersion()
{
FrameworkVersion baseVersion = new FrameworkVersion();
if (FrameworkVersionRegistryHelper.IsFX35Installed())
{
baseVersion.Version = new Version(3, 5);
baseVersion.ServicePack = FrameworkVersionRegistryHelper.GetFX35SPLevel();
}
else if (FrameworkVersionRegistryHelper.IsFX30Installed())
{
baseVersion.Version = new Version(3, 0);
baseVersion.ServicePack = FrameworkVersionRegistryHelper.GetFX30SPLevel();
}
else if (FrameworkVersionRegistryHelper.IsFX20Installed())
{
baseVersion.Version = new Version(2, 0);
baseVersion.ServicePack = FrameworkVersionRegistryHelper.GetFX20SPLevel();
}
else
{
baseVersion.Version = new Version(0, 0); /* inconnu */
baseVersion.ServicePack = 0;
}
return baseVersion;
}
#endregion
#region DirectX Version
///
/// Classe d'obtention des informations sur DirectX
///
/// Infrastructure
internal static class DirectXVersionInfo
{
///
/// Obtient un tableau de 4 ints représentant la version de DirectX
///
///
public static int[] GetLiteralDirectXVersion()
{
int[] result = new[] { 0, 0, 0, 0 };
try
{
using (RegistryKey directXKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\DirectX"))
{
if (directXKey == null)
return result;
string sVersion = directXKey.GetValue("Version", null) as string;
if (sVersion == null)
return result;
string[] parts = sVersion.Split(new[] { "." }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length != 4)
return result;
for (int i = 0; i < 4; i++)
result[i] = int.Parse(parts[i]);
return result;
}
}
catch
{
return new[] { 0, 0, 0, 0 };
}
}
///
/// Désactive la gestion automatique de DirectX sur Vista (renvoi 10 si ce système est détecté)
///
static bool _disableVistaAutoHandler;
///
/// Par défaut la version retournée de DirectX sur Vista est DX 10.
/// Vous pouvez forcer la vérification de la version en spécifiant
/// true à cette propriété ( false par défaut )
///
public static bool DisableVistaAutoHandler
{
get { return _disableVistaAutoHandler; }
set { _disableVistaAutoHandler = value; }
}
///
/// Recharge les informations de version concernant DirectX
///
public static DirectXVersion GetDirectXVersionCore()
{
DirectXVersion version;
try
{
switch (Environment.OSVersion.Platform)
{
case PlatformID.Win32NT:
case PlatformID.Win32S:
case PlatformID.Win32Windows:
case PlatformID.WinCE:
/* a priori, ça marche */
break;
default:
return DirectXVersion.NotSupported;
}
if (!DisableVistaAutoHandler && Environment.OSVersion.Platform == PlatformID.Win32NT &&
Environment.OSVersion.Version.Major >= 6)
{
/* Windows Vista ou plus */
version = DirectXVersion.DirectX_10;
}
else
{
int[] parts = GetLiteralDirectXVersion();
if (parts[0] < 4)
version = DirectXVersion.LessThanDX8;
else if (parts[0] > 4)
version = DirectXVersion.MostRecent;
else
{
if (parts[1] < 8)
version = DirectXVersion.LessThanDX8;
else if (parts[1] == 8)
{
//DirectX 8
if (parts[2] < 1)
version = DirectXVersion.LessThanDX8;
else if (parts[2] == 1)
{
//1, 1a ou 1b
switch (parts[3])
{
default:
{ version = DirectXVersion.Unknown; break; }
case 810:
{ version = DirectXVersion.DirectX_8_1_XP; break; }
case 881:
{ version = DirectXVersion.DirectX_8_1_DO; break; }
case 901:
{ version = DirectXVersion.DirectX_8_1_a_Or_b; break; }
}
}
else if (parts[2] == 2)
{
switch (parts[3])
{
default:
{ version = DirectXVersion.Unknown; break; }
case 134:
{ version = DirectXVersion.DirectX_8_2; break; }
}
}
else
version = DirectXVersion.Unknown;
}
else if (parts[1] == 9)
{
//DirectX 9
if (parts[2] != 0)
version = DirectXVersion.Unknown;
else
{
switch (parts[3])
{
default:
{ version = DirectXVersion.Unknown; break; }
case 900:
{ version = DirectXVersion.DirectX_9; break; }
case 901:
{ version = DirectXVersion.DirectX_9_a; break; }
case 902:
{ version = DirectXVersion.DirectX_9_b; break; }
case 903:
case 904:
{ version = DirectXVersion.DirectX_9_c; break; }
}
}
}
else
version = DirectXVersion.MostRecent;
}
}
}
catch
{
return DirectXVersion.Unknown;
}
return version;
}
///
/// Version actuelle de DirectX
///
static DirectXVersion? _currentVersion;
///
/// Charge la version actuelle de DirectX
///
/// Descriptif de la version actuelle de DirectX
public static DirectXVersion GetDirectXVersion()
{
if (_currentVersion == null)
_currentVersion = GetDirectXVersionCore();
return _currentVersion ?? DirectXVersion.Unknown;
}
}
///
/// Obtient la version détectée de DirectX actuellement installée sur le système
///
public override DirectXVersion DirectXVersion
{
get
{
return DirectXVersionInfo.GetDirectXVersion();
}
}
#endregion
#region Privilege elevation (UAC)
///
/// Indique si le système supporte l'élévation de privilèges
///
public override bool SupportsElevation
{
get
{
return Environment.OSVersion.Platform == PlatformID.Win32NT
&& Environment.OSVersion.Version.Major >= 6;
}
}
///
/// Indique si le processus courant dispose du token complet administrateur (élévation de privilèges)
///
public override bool IsElevated
{
get { return SupportsElevation && IsElevatedCore(); }
}
enum TokenElevationType
{
TokenElevationTypeDefault = 1,
TokenElevationTypeFull,
TokenElevationTypeLimited
}
enum TokenInformationClass
{
TokenUser = 1,
TokenGroups,
TokenPrivileges,
TokenOwner,
TokenPrimaryGroup,
TokenDefaultDacl,
TokenSource,
TokenType,
TokenImpersonationLevel,
TokenStatistics,
TokenRestrictedSids,
TokenSessionId,
TokenGroupsAndPrivileges,
TokenSessionReference,
TokenSandBoxInert,
TokenAuditPolicy,
TokenOrigin,
TokenElevationType,
TokenLinkedToken,
TokenElevation,
TokenHasRestrictions,
TokenAccessInformation,
TokenVirtualizationAllowed,
TokenVirtualizationEnabled,
TokenIntegrityLevel,
TokenUIAccess,
TokenMandatoryPolicy,
TokenLogonSid,
MaxTokenInfoClass
}
const UInt32 TokenQuery = 0x0008;
[DllImport("kernel32.dll")]
static extern IntPtr GetCurrentProcess();
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool OpenProcessToken(
IntPtr processHandle,
uint desiredAccess,
out IntPtr tokenHandle);
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool GetTokenInformation(
IntPtr tokenHandle,
TokenInformationClass tokenInformationClass,
IntPtr tokenInformation,
uint tokenInformationLength,
out uint returnLength);
static bool IsElevatedCore()
{
IntPtr hToken;
int sizeofTokenElevationType = Marshal.SizeOf(typeof(TokenElevationType));
IntPtr pElevationType =
Marshal.AllocHGlobal(sizeofTokenElevationType);
if (OpenProcessToken(GetCurrentProcess(), TokenQuery, out hToken))
{
uint dwSize;
if (GetTokenInformation(hToken,
TokenInformationClass.TokenElevationType, pElevationType,
(uint)sizeofTokenElevationType, out dwSize))
{
TokenElevationType elevationType = (TokenElevationType)Marshal.ReadInt32(pElevationType);
Marshal.FreeHGlobal(pElevationType);
switch (elevationType)
{
case TokenElevationType.TokenElevationTypeFull:
return true;
default:
//case TokenElevationType.TokenElevationTypeLimited:
//case TokenElevationType.TokenElevationTypeDefault:
return false;
}
}
}
return false;
}
#endregion
#region Theme info
///
/// Obtient les informations du thème du système
///
public override SystemThemeInfo ThemeInfo
{
get
{
var themeFileNameBuffer = new StringBuilder(260);
var themeColorBuffer = new StringBuilder(260);
var themeSizeBuffer = new StringBuilder(260);
var r = GetCurrentThemeName(
themeFileNameBuffer, themeFileNameBuffer.Capacity,
themeColorBuffer, themeColorBuffer.Capacity,
themeSizeBuffer, themeSizeBuffer.Capacity);
if (r.IsSuccess)
{
string themeName = Path.GetFileNameWithoutExtension(themeFileNameBuffer.ToString()).Capitalize();
return new SystemThemeInfo(
themeFileNameBuffer.ToString(),
themeName,
themeColorBuffer.ToString(),
themeSizeBuffer.ToString());
}
throw r.Exception;
}
}
[DllImport("uxtheme", CharSet = CharSet.Auto)]
static extern HResult GetCurrentThemeName(
StringBuilder pszThemeFileName, int dwMaxNameChars,
StringBuilder pszColorBuff, int cchMaxColorChars,
StringBuilder pszSizeBuff, int cchMaxSizeChars);
#endregion
}
}