155 votes

Comment éteindre l'ordinateur à partir de C#

Quelle est la meilleure façon d'éteindre l'ordinateur à partir d'un programme C# ?

J'ai trouvé quelques méthodes qui fonctionnent - je les afficherai ci-dessous - mais aucune n'est très élégante. Je cherche quelque chose de plus simple et de natif en .net.

186voto

Pop Catalin Points 25033

Fonctionne à partir de Windows XP, non disponible en win 2000 ou inférieur :

C'est le moyen le plus rapide de le faire :

Process.Start("shutdown","/s /t 0");

Sinon, utilisez P/Invoke ou WMI comme d'autres l'ont dit.

Edit : comment éviter de créer une fenêtre

var psi = new ProcessStartInfo("shutdown","/s /t 0");
psi.CreateNoWindow = true;
psi.UseShellExecute = false;
Process.Start(psi);

2 votes

Cela semble également fonctionner à partir des services (du moins dans les scénarios qui me concernent). Je n'ai jamais réussi à faire fonctionner les méthodes WMI ou ExitWindowsEx à partir d'un service.

1 votes

James C'est parce qu'un service n'a généralement pas les autorisations nécessaires.

1 votes

L'état de la consommation d'énergie de la machine est différent après avoir utilisé cette méthode, qu'après avoir utilisé la fenêtre de dialogue d'arrêt traditionnelle. Appuyer sur le bouton d'alimentation pour redémarrer consomme environ 80-85 milliampères, plutôt que les 300+ habituels. Je posterai un message ici si je découvre pourquoi. Cela ne devrait pas affecter la plupart des utilisateurs.

85voto

roomaroo Points 2539

Tiré de : un article de Geekpedia

Cette méthode utilise WMI pour arrêter Windows.

Vous devrez ajouter une référence à System.Management à votre projet pour l'utiliser.

using System.Management;

void Shutdown()
{
    ManagementBaseObject mboShutdown = null;
    ManagementClass mcWin32 = new ManagementClass("Win32_OperatingSystem");
    mcWin32.Get();

    // You can't shutdown without security privileges
    mcWin32.Scope.Options.EnablePrivileges = true;
    ManagementBaseObject mboShutdownParams =
             mcWin32.GetMethodParameters("Win32Shutdown");

     // Flag 1 means we want to shut down the system. Use "2" to reboot.
    mboShutdownParams["Flags"] = "1";
    mboShutdownParams["Reserved"] = "0";
    foreach (ManagementObject manObj in mcWin32.GetInstances())
    {
        mboShutdown = manObj.InvokeMethod("Win32Shutdown", 
                                       mboShutdownParams, null);
    }
}

3 votes

L'utilisation de WMI facilite le suivi des erreurs. Que se passe-t-il si la commande d'arrêt ne fonctionne pas pour une raison quelconque ?

2 votes

J'utilise cette méthode pour arrêter Windows, et deux fois sur trois, il me dit que je n'ai pas les autorisations nécessaires, mais la troisième fois, il abandonne et redémarre quand même l'ordinateur. Qu'est-ce qui se passe ?

2 votes

Cette solution ne fonctionne pas pour moi. J'obtiens l'exception "Privilege not held" même si je lance le programme sous l'utilisateur administrateur.

34voto

Stephen Wrighton Points 15904

Ce fil fournit le code nécessaire : http://bytes.com/forum/thread251367.html

mais voici le code correspondant :

using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack=1)]
internal struct TokPriv1Luid
{
    public int Count;
    public long Luid;
    public int Attr;
}

[DllImport("kernel32.dll", ExactSpelling=true) ]
internal static extern IntPtr GetCurrentProcess();

[DllImport("advapi32.dll", ExactSpelling=true, SetLastError=true) ]
internal static extern bool OpenProcessToken( IntPtr h, int acc, ref IntPtr
phtok );

[DllImport("advapi32.dll", SetLastError=true) ]
internal static extern bool LookupPrivilegeValue( string host, string name,
ref long pluid );

[DllImport("advapi32.dll", ExactSpelling=true, SetLastError=true) ]
internal static extern bool AdjustTokenPrivileges( IntPtr htok, bool disall,
ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen );

[DllImport("user32.dll", ExactSpelling=true, SetLastError=true) ]
internal static extern bool ExitWindowsEx( int flg, int rea );

internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
internal const int TOKEN_QUERY = 0x00000008;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
internal const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
internal const int EWX_LOGOFF = 0x00000000;
internal const int EWX_SHUTDOWN = 0x00000001;
internal const int EWX_REBOOT = 0x00000002;
internal const int EWX_FORCE = 0x00000004;
internal const int EWX_POWEROFF = 0x00000008;
internal const int EWX_FORCEIFHUNG = 0x00000010;

private void DoExitWin( int flg )
{
    bool ok;
    TokPriv1Luid tp;
    IntPtr hproc = GetCurrentProcess();
    IntPtr htok = IntPtr.Zero;
    ok = OpenProcessToken( hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok );
    tp.Count = 1;
    tp.Luid = 0;
    tp.Attr = SE_PRIVILEGE_ENABLED;
    ok = LookupPrivilegeValue( null, SE_SHUTDOWN_NAME, ref tp.Luid );
    ok = AdjustTokenPrivileges( htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero );
    ok = ExitWindowsEx( flg, 0 );
    }

Utilisation :

DoExitWin( EWX_SHUTDOWN );

ou

DoExitWin( EWX_REBOOT );

0 votes

Vous pouvez lire ce que font les autres constantes EWX_ ici : msdn.microsoft.com/fr/us/library/Windows/desktop/

1 votes

Lors du portage de constantes numériques en C#, la meilleure pratique consiste à utiliser un enum. C'est ce qu'un enum est conçu pour faire. Il offre un typage fort autour des constantes numériques, supporte optionnellement les drapeaux / bitmasks, et effectue facilement des transferts vers le type numérique sous-jacent.

27voto

lakshmanaraj Points 3145

Différentes méthodes :

A. System.Diagnostics.Process.Start("Shutdown", "-s -t 10");

B. Windows Management Instrumentation (WMI)

C. Pinvoke de System.Runtime.InteropServices

D. Gestion du système

Après avoir soumis, j'ai vu que beaucoup d'autres personnes ont également posté...

2 votes

B et D sont la même méthode (WMI)

0 votes

E. Powershell exécute script depuis le code blogs.msdn.microsoft.com/kebab/2014/04/28/

14voto

roomaroo Points 2539

La méthode laide de la vieille école. Utilisez le ExitWindowsEx de l'API Win32.

using System.Runtime.InteropServices;

void Shutdown2()
{
    const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
    const short SE_PRIVILEGE_ENABLED = 2;
    const uint EWX_SHUTDOWN = 1;
    const short TOKEN_ADJUST_PRIVILEGES = 32;
    const short TOKEN_QUERY = 8;
    IntPtr hToken;
    TOKEN_PRIVILEGES tkp;

    // Get shutdown privileges...
    OpenProcessToken(Process.GetCurrentProcess().Handle, 
          TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, out hToken);
    tkp.PrivilegeCount = 1;
    tkp.Privileges.Attributes = SE_PRIVILEGE_ENABLED;
    LookupPrivilegeValue("", SE_SHUTDOWN_NAME, out tkp.Privileges.pLuid);
    AdjustTokenPrivileges(hToken, false, ref tkp, 0U, IntPtr.Zero, 
          IntPtr.Zero);

    // Now we have the privileges, shutdown Windows
    ExitWindowsEx(EWX_SHUTDOWN, 0);
}

// Structures needed for the API calls
private struct LUID
{
    public int LowPart;
    public int HighPart;
}
private struct LUID_AND_ATTRIBUTES
{
    public LUID pLuid;
    public int Attributes;
}
private struct TOKEN_PRIVILEGES
{
    public int PrivilegeCount;
    public LUID_AND_ATTRIBUTES Privileges;
}

[DllImport("advapi32.dll")]
static extern int OpenProcessToken(IntPtr ProcessHandle, 
                     int DesiredAccess, out IntPtr TokenHandle);

[DllImport("advapi32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool AdjustTokenPrivileges(IntPtr TokenHandle,
    [MarshalAs(UnmanagedType.Bool)]bool DisableAllPrivileges,
    ref TOKEN_PRIVILEGES NewState,
    UInt32 BufferLength,
    IntPtr PreviousState,
    IntPtr ReturnLength);

[DllImport("advapi32.dll")]
static extern int LookupPrivilegeValue(string lpSystemName, 
                       string lpName, out LUID lpLuid);

[DllImport("user32.dll", SetLastError = true)]
static extern int ExitWindowsEx(uint uFlags, uint dwReason);

Dans un code de production, vous devriez vérifier les valeurs de retour des appels d'API, mais j'ai laissé cela de côté pour rendre l'exemple plus clair.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X