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 } }