2008-09-19 64 views
122

¿Cuál es la mejor manera de apagar la computadora desde un programa C#?Cómo apagar la computadora desde C#

He encontrado algunos métodos que funcionan, los voy a publicar a continuación, pero ninguno de ellos es muy elegante. Estoy buscando algo que sea más simple y nativo .net.

Respuesta

77

Tomado de: a Geekpedia post

Este método utiliza WMI de apagado de Windows.

Deberá agregar una referencia a System.Management a su proyecto para usar esto.

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

mediante WMI hace que sea fácil el seguimiento de errores. ¿Qué sucede si el comando de apagado no funciona por alguna razón? –

+2

estoy usando este método para cerrar las ventanas, y dos de cada tres veces que me dice que me falta permisos, pero la tercera vez, que Sot de "renuncia" y reinicia el ordenador de todos modos. ¿Que pasa con eso? –

+1

Esta solución no funciona para mí. Obtengo la excepción de "Privilegio no retenido" incluso si ejecuto el programa en usuario administrador. – Fanda

5

puede iniciar el proceso de apagado:

  • shutdown -s -t 0 - apagado
  • shutdown -r -t 0 - Arranque de nuevo
11

Corto y dulce. Llamar a un programa externo:

using System.Diagnostics; 

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

Nota: Este programa llama Shutdown.exe de Windows, por lo que sólo funcionará si ese programa está disponible. Puede tener problemas en Windows 2000 (donde shutdown.exe solo está disponible en el kit de recursos) o XP Embedded.

31

Este hilo proporciona el código necesario: http://bytes.com/forum/thread251367.html

pero aquí está el código relevante:

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

Uso:

DoExitWin(EWX_SHUTDOWN); 

o

DoExitWin(EWX_REBOOT); 
+0

Usted puede leer acerca de lo que los otros hacen contstants EWX_ aquí: http://msdn.microsoft.com/en-us/library/windows/desktop/aa376868%28v=vs.85%29.aspx – TripleAntigen

+0

Al trasladar a las constantes numéricas C#, la mejor práctica es usar una enumeración. Para eso está diseñada una enumeración. Proporciona un tipado fuerte en torno a las constantes numéricas, opcionalmente admite banderas/máscaras de bits, y se envía fácilmente de un lado a otro al tipo numérico subyacente. –

+0

Excelente respuesta. Nitpicking anterior ... –

2

Ther e no es un método nativo de .net para apagar la computadora. Necesita P/Invocar la llamada a la API ExitWindows o ExitWindowsEx.

12

El método feo de la vieja escuela. Use la función ExitWindowsEx de la 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); 

En el código de producción que debe comprobar los valores de retorno de las llamadas a la API, pero dejó que fuera para hacer el ejemplo más claro.

148

obras a partir de Windows XP, no disponible en la victoria de 2000 o inferior:

Ésta es la forma más rápida de hacerlo:

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

utilizan de alguna manera P/Invoke o WMI como otros han dicho.

Editar: cómo evitar la creación de una ventana

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

1: Eso haré yo bastante bien, gracias –

+1

Esto parece funcionar de los servicios también (al menos en los escenarios que me preocupa). Nunca pude obtener los métodos WMI o ExitWindowsEx para trabajar desde un servicio. – James

+1

@James Es porque un servicio generalmente no tiene los permisos para ello. –

26

diferentes métodos:

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

B. administración de Windows (WMI)

C. System.Runtime.InteropServices Gestión Pinvoke

D. Sistema

Después de enviar, he visto que muchos otros también han publicado ...

+2

B y D son del mismo método (WMI) – Lucas

+0

E. Powershell ejecuta el script desde el código https://blogs.msdn.microsoft.com/kebab/2014/04/28/executing-powershell-scripts-from-c/ – user1785960

0

Si desea apagar el ordenador de forma remota, puede utilizar

Using System.Diagnostics; 

en cualquier botón de clic

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

Probé roomaroo's WMI method para cerrar Windows 2003 Server, pero no funcionó hasta que agregué `[STAThread] '(es decir, "Single Threaded Apartment" modelo de hilos) a la() declaración principal:

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

Luego trató de parada de un hilo, y para conseguir que funcione tenía que establecer el "Estado de apartamentos" de la rosca a STA así:

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

soy un novato C#, así que no estoy del todo seguro de la importancia de subprocesos STA en términos de apagar el sistema (incluso después de leer el enlace que he publicado anteriormente). Tal vez alguien más puede elaborar ...

+0

En realidad, solo el hilo que llama a WMI necesita ser hilo STA. Si ese no es el hilo principal, 'Main()' no necesita '[STAThread]'. – SLaks

4

Tenga en cuenta que Shutdown.exe es sólo una envoltura alrededor de InitiateSystemShutdownEx, que ofrece algunas sutilezas que faltan en ExitWindowsEx

2

** Elaborado respuesta ...

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

tuve problemas tratando de utilizar el método de WMI aceptado anteriormente porque siempre recibí privilegios no tenía excepciones a pesar de ejecutar el programa como administrador.

La solución fue que el proceso solicitara el privilegio por sí mismo. Encontré la respuesta en http://www.dotnet247.com/247reference/msgs/58/292150.aspx escrita por un tipo llamado Richard Hill.

He pegado el uso básico de su solución a continuación en caso de que el enlace envejezca.

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

Esto funcionó, aunque no me gusta saber por qué. Honestamente, me pregunto si debería haber ido con el comando "shutdown" ... –

-1

Si se agrega la referencia System.Windows.Forms a su proyecto, entonces usted puede encontrar en este espacio de nombres de la clase de aplicación que tiene métodos estáticos. Uno de ellos es lo que quiere/necesita/busca, y se llama "SetSuspendState". Utilicé esta función en el pasado, y con ella logro cerrar mi computadora fácilmente. Hay opciones sobre cómo quiere apagar su computadora con esta función. Toma 3 parámetros. Primero, el enum PowerState (Hibernate o Suspend), luego el bool force y el bool disableWakeEvent. Puede leer más acerca de esta función en Internet. La siguiente línea de ejecución se apague el equipo como se esperaba (eso espero):

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

Por favor use el formato del código mientras publica las respuestas. Para el código en línea, enciérrelo dentro del símbolo '. Para código de varias líneas, (a) sangría las líneas de código en 4 espacios o (b) seleccione el bloque de código y haga clic en el botón '{}' en la barra de botones o (c) seleccione el código y haga Ctrl + K. – Harry

+4

Solo un recordatorio, el OP quiere código C#, ¡usted publicó C++! – Trontor

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

debería funcionar.

Para reiniciar, es/r

Esto reiniciará la caja de la PC directamente y limpiamente, sin diálogos.

+0

Esta es la respuesta perfecta en sistemas modernos (2015+). – Fattie

+0

gracias, ¿podría explicar lo que hacen el/s y el/t 0? –

+1

@Peterverleg Sure. El argumento "/ s" le dice a la computadora que se apague y la "/ t" le dice a la computadora que espere x segundos antes de apagarse. Sé por experiencia personal que el argumento "/ t" no hace nada en Windows 8.1, pero funciona en 7 con seguridad. También puede usar estas funciones: 'shutdown/s/t 0 // Para shutdown' ' shutdown/r/t 0 // Para reiniciar' 'shutdown/h/t 0 // Para hibernate' Además, intente tipeándolos en CMD para el mismo resultado. –

0

Uso Shutdown.exe. Para evitar problemas con argumentos que pasan, ejecución compleja, la ejecución de WindowForms usar PowerShell en ejecutar un 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 debe estar instalado en el sistema operativo y disponible en GAC.

Lo siento por mi Inglés.

0

Sólo para añadir a la respuesta de Pop Catalin, aquí está un forrouna que apaga el equipo sin mostrar ninguna ventana:

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