2008-09-19 7 views
122

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

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

Répondre

77

Extrait de: a Geekpedia post

Cette méthode utilise WMI aux fenêtres d'arrêt.

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); 
    } 
} 
+2

aide WMI rend plus facile de suivre les erreurs. Que se passe-t-il si la commande shutdown ne fonctionne pas pour une raison quelconque? –

+2

J'utilise cette méthode pour fermer les fenêtres, et deux fois sur trois ça me dira que je n'ai pas les permissions, mais la troisième fois, ça va "abandonner" et redémarrer l'ordinateur quand même. Qu'est-ce qui se passe avec ça? –

+1

Cette solution ne fonctionne pas pour moi. Je reçois l'exception "Privilege not held" même si j'exécute un programme sous un utilisateur administrateur. – Fanda

5

Vous pouvez lancer le processus d'arrêt:

  • shutdown -s -t 0 - Arrêt
  • shutdown -r -t 0 - Redémarrez
11

Courte et douce. Appeler un programme externe:

using System.Diagnostics; 

    void Shutdown() 
    { 
     Process.Start("shutdown.exe", "-s -t 00"); 
    } 

Note: Ce programme appelle le Shutdown.exe Windows, donc ça va ne fonctionnera que si ce programme est disponible. Vous pouvez rencontrer des problèmes sous Windows 2000 (où shutdown.exe est uniquement disponible dans le kit de ressources) ou XP Embedded.

31

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

Vous pouvez lire ce que les autres convertisseurs EWX font ici: http://msdn.microsoft.com/en-us/library/windows/desktop/aa376868%28v=vs.85%29.aspx – TripleAntigen

+0

Lors du portage de constantes numériques C#, la meilleure pratique consiste à utiliser une énumération. C'est ce que veut dire une énumération. Il donne une forte typage autour des constantes numériques, supporte facultativement les drapeaux/masques de bits, et renvoie facilement le type numérique sous-jacent. –

+0

Excellente réponse. Nitpicking ci-dessus ... –

2

Ther e n'est pas une méthode native .net pour éteindre l'ordinateur. Vous devez appeler/appeler l'appel de l'API ExitWindows ou ExitWindowsEx.

12

La vieille méthode moche. Utilisez la fonction 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 le code de production, vous devriez vérifier les valeurs de retour des appels API, mais je reste à faire que sur l'exemple plus clair.

148

Works à partir de Windows XP, non disponible dans la victoire 2000 ou moins:

Ceci est la meilleure façon de le faire:

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

Sinon, utilisez P/Invoke ou WMI comme d'autres 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); 
+1

+1: Cela va me faire très bien, merci –

+1

Cela semble fonctionner à partir de services aussi (au moins dans les scénarios que je suis concerné). Je n'ai jamais réussi à obtenir les méthodes WMI ou ExitWindowsEx à partir d'un service. – James

+1

@James C'est parce qu'un service n'a généralement pas les permissions pour cela. –

26

méthodes différentes:

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

B. Windows Management Instrumentation (WMI)

C. System.Runtime.InteropServices Pinvoke

D. Système de gestion

Après mon avis, j'ai vu tant d'autres ont également affiché ...

+2

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

+0

E. Powershell exécuter le script à partir du code https://blogs.msdn.microsoft.com/kebab/2014/04/28/executing-powershell-scripts-from-c/ – user1785960

0

Si vous voulez arrêter l'ordinateur à distance, vous pouvez utiliser

Using System.Diagnostics; 

sur un bouton cliquez

{ 
    Process.Start("Shutdown","-i"); 
} 
2

J'ai essayé roomaroo's WMI method d'arrêter Windows 2003 Server, mais cela ne fonctionnerait pas jusqu'à ce que j'ai ajouté `[STAThread] '(ie « Single Threaded Apartment » modèle de thread) à la déclaration principale():

[STAThread] 
public static void Main(string[] args) { 
    Shutdown(); 
} 

J'ai ensuite essayé d'arrêter d'un fil, et d'obtenir que de travailler je devais définir le « Appartement État » du fil à STA comme bien:

using System.Management; 
using System.Threading; 

public static class Program { 

    [STAThread] 
    public static void Main(string[] args) { 
     Thread t = new Thread(new ThreadStart(Program.Shutdown)); 
     t.SetApartmentState(ApartmentState.STA); 
     t.Start(); 
     ... 
    } 

    public static void Shutdown() { 
     // roomaroo's code 
    } 
} 

Je suis un C# noob, donc je ne suis pas tout à fait sûr de l'importance des threads STA en termes d'arrêt du système (même après avoir lu le lien I posté ci-dessus). Peut-être que quelqu'un d'autre peut élaborer ...?

+0

En fait, seul le thread appelant WMI doit être un thread STA. Si ce n'est pas le thread principal, 'Main()' n'a pas besoin de '[STAThread]'. – SLaks

2

** Élaboré réponse ...

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Text; 
using System.Windows.Forms; 
// Remember to add a reference to the System.Management assembly 
using System.Management; 
using System.Diagnostics; 

namespace ShutDown 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void btnShutDown_Click(object sender, EventArgs e) 
     { 
      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 
      mboShutdownParams["Flags"] = "1"; 
      mboShutdownParams["Reserved"] = "0"; 

      foreach (ManagementObject manObj in mcWin32.GetInstances()) 
      { 
       mboShutdown = manObj.InvokeMethod("Win32Shutdown", mboShutdownParams, null); 
      } 
     } 
    } 
} 
5

J'ai eu du mal à essayer d'utiliser la méthode WMI accepté ci-dessus parce que j'ai toujours obtenu privilège pas tenu d'exceptions malgré l'exécution du programme en tant qu'administrateur.

La solution était que le processus demande le privilège pour lui-même. J'ai trouvé la réponse au http://www.dotnet247.com/247reference/msgs/58/292150.aspx écrit par un gars appelé Richard Hill.

J'ai collé mon utilisation basique de sa solution ci-dessous au cas où ce lien vieillirait.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Management; 
using System.Runtime.InteropServices; 
using System.Security; 
using System.Diagnostics; 

namespace PowerControl 
{ 
    public class PowerControl_Main 
    { 


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

      if (!TokenAdjuster.EnablePrivilege("SeShutdownPrivilege", true)) 
      { 
       Console.WriteLine("Could not enable SeShutdownPrivilege"); 
      } 
      else 
      { 
       Console.WriteLine("Enabled SeShutdownPrivilege"); 
      } 

      // 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 
      mboShutdownParams["Flags"] = "1"; 
      mboShutdownParams["Reserved"] = "0"; 

      foreach (ManagementObject manObj in mcWin32.GetInstances()) 
      { 
       try 
       { 
        mboShutdown = manObj.InvokeMethod("Win32Shutdown", 
                mboShutdownParams, null); 
       } 
       catch (ManagementException mex) 
       { 
        Console.WriteLine(mex.ToString()); 
        Console.ReadKey(); 
       } 
      } 
     } 


    } 


    public sealed class TokenAdjuster 
    { 
     // PInvoke stuff required to set/enable security privileges 
     [DllImport("advapi32", SetLastError = true), 
     SuppressUnmanagedCodeSecurityAttribute] 
     static extern int OpenProcessToken(
     System.IntPtr ProcessHandle, // handle to process 
     int DesiredAccess, // desired access to process 
     ref IntPtr TokenHandle // handle to open access token 
     ); 

     [DllImport("kernel32", SetLastError = true), 
     SuppressUnmanagedCodeSecurityAttribute] 
     static extern bool CloseHandle(IntPtr handle); 

     [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     static extern int AdjustTokenPrivileges(
     IntPtr TokenHandle, 
     int DisableAllPrivileges, 
     IntPtr NewState, 
     int BufferLength, 
     IntPtr PreviousState, 
     ref int ReturnLength); 

     [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
     static extern bool LookupPrivilegeValue(
     string lpSystemName, 
     string lpName, 
     ref LUID lpLuid); 

     [StructLayout(LayoutKind.Sequential)] 
     internal struct LUID 
     { 
      internal int LowPart; 
      internal int HighPart; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     struct LUID_AND_ATTRIBUTES 
     { 
      LUID Luid; 
      int Attributes; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     struct _PRIVILEGE_SET 
     { 
      int PrivilegeCount; 
      int Control; 
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] // ANYSIZE_ARRAY = 1 
      LUID_AND_ATTRIBUTES[] Privileges; 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     internal struct TOKEN_PRIVILEGES 
     { 
      internal int PrivilegeCount; 
      [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] 
      internal int[] Privileges; 
     } 
     const int SE_PRIVILEGE_ENABLED = 0x00000002; 
     const int TOKEN_ADJUST_PRIVILEGES = 0X00000020; 
     const int TOKEN_QUERY = 0X00000008; 
     const int TOKEN_ALL_ACCESS = 0X001f01ff; 
     const int PROCESS_QUERY_INFORMATION = 0X00000400; 

     public static bool EnablePrivilege(string lpszPrivilege, bool 
     bEnablePrivilege) 
     { 
      bool retval = false; 
      int ltkpOld = 0; 
      IntPtr hToken = IntPtr.Zero; 
      TOKEN_PRIVILEGES tkp = new TOKEN_PRIVILEGES(); 
      tkp.Privileges = new int[3]; 
      TOKEN_PRIVILEGES tkpOld = new TOKEN_PRIVILEGES(); 
      tkpOld.Privileges = new int[3]; 
      LUID tLUID = new LUID(); 
      tkp.PrivilegeCount = 1; 
      if (bEnablePrivilege) 
       tkp.Privileges[2] = SE_PRIVILEGE_ENABLED; 
      else 
       tkp.Privileges[2] = 0; 
      if (LookupPrivilegeValue(null, lpszPrivilege, ref tLUID)) 
      { 
       Process proc = Process.GetCurrentProcess(); 
       if (proc.Handle != IntPtr.Zero) 
       { 
        if (OpenProcessToken(proc.Handle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, 
        ref hToken) != 0) 
        { 
         tkp.PrivilegeCount = 1; 
         tkp.Privileges[2] = SE_PRIVILEGE_ENABLED; 
         tkp.Privileges[1] = tLUID.HighPart; 
         tkp.Privileges[0] = tLUID.LowPart; 
         const int bufLength = 256; 
         IntPtr tu = Marshal.AllocHGlobal(bufLength); 
         Marshal.StructureToPtr(tkp, tu, true); 
         if (AdjustTokenPrivileges(hToken, 0, tu, bufLength, IntPtr.Zero, ref ltkpOld) != 0) 
         { 
          // successful AdjustTokenPrivileges doesn't mean privilege could be changed 
          if (Marshal.GetLastWin32Error() == 0) 
          { 
           retval = true; // Token changed 
          } 
         } 
         TOKEN_PRIVILEGES tokp = (TOKEN_PRIVILEGES)Marshal.PtrToStructure(tu, 
         typeof(TOKEN_PRIVILEGES)); 
         Marshal.FreeHGlobal(tu); 
        } 
       } 
      } 
      if (hToken != IntPtr.Zero) 
      { 
       CloseHandle(hToken); 
      } 
      return retval; 
     } 

    } 
} 
+2

Cela a fonctionné, bien que je n'aime pas ne pas savoir pourquoi. Je me demande honnêtement si je devrais juste allé avec la commande "shutdown" ... –

-1

Si vous ajoutez la System.Windows.Forms référence à votre projet, vous pouvez trouver dans cet espace de noms de la classe d'application qui a des méthodes statiques. L'un d'eux est ce que vous voulez/besoin/recherche, et il est appelé "SetSuspendState". J'ai utilisé cette fonction dans le passé, et avec elle je réussis à éteindre mon ordinateur facilement. Il y a des options comment vous voulez éteindre votre ordinateur avec cette fonction. Il faut 3 paramètres. D'abord l'enum PowerState (Hibernate ou Suspend), seconde la force bool, et le troisième le bool disableWakeEvent. Vous pouvez lire plus à propos de cette fonction sur Internet. La ligne d'exécution suivante fermer votre ordinateur comme prévu (je l'espère):

System.Windows.Forms.Application.SetSuspendState(PowerState.Hibernate, true, false); 
-3
#include<stdio.h> 
#include<stdlib.h> 

int main() 
{ 
    system("C:\\Windows\\System32\\shutdown /s/t 0"); 
    return 0; 
} 
+1

S'il vous plaît utiliser le formatage du code tout en postant des réponses. Pour le code en ligne, placez-le dans le symbole '. Pour le code multiligne, (a) indenter les lignes de code de 4 espaces ou (b) sélectionner le bloc de code et cliquer sur le bouton {}} dans la barre de boutons ou (c) sélectionner le code et faire Ctrl + K. – Harry

+4

Juste un rappel, l'OP veut du code C#, vous avez posté C++! – Trontor

8
System.Diagnostics.Process.Start("shutdown", "/s /t 0") 

devrait fonctionner.

Pour redémarrer, il est/r

Cela va redémarrer le boîtier PC directement et proprement, sans dialogues.

+0

Ceci est la réponse parfaite sur les systèmes modernes (2015+). – Fattie

+0

merci, pourriez-vous expliquer ce que le/s et le/t 0 font? –

+1

@Peterverleg Bien sûr. L'argument "/ s" indique à l'ordinateur de s'éteindre et le "/ t" indique à l'ordinateur d'attendre x secondes avant de s'éteindre. Je sais par expérience personnelle que l'argument "/ t" ne fait rien dans Windows 8.1, mais cela fonctionne dans 7, c'est sûr. Vous pouvez également utiliser ces fonctions: 'shutdown/s/t 0 // Pour shutdown' ' shutdown/r/t 0 // Pour redémarrage' 'shutdown/h/t 0 // Pour hibernate' Aussi, essayez les taper dans CMD pour le même résultat. –

0

Utilisez shutdown.exe. Pour éviter un problème args passant, l'exécution complexe, l'exécution de WindowForms utiliser PowerShell exécuter le script:

using System.Management.Automation; 
... 
using (PowerShell PowerShellInstance = PowerShell.Create()) 
{ 
    PowerShellInstance.AddScript("shutdown -a; shutdown -r -t 100;"); 
    // invoke execution on the pipeline (collecting output) 
    Collection<PSObject> PSOutput = PowerShellInstance.Invoke(); 
} 

System.Management.Automation.dll doit être installé sur OS et disponible dans GAC.

Désolé pour mon anglais.

0

Juste pour ajouter à Pop réponse de Catalin, voici une une doublure qui arrête l'ordinateur sans afficher toutes les fenêtres:

Process.Start(new ProcessStartInfo("shutdown", "/s /t 0"){CreateNoWindow = true, UseShellExecute = false}); 
Questions connexes