Bilgisayarı C # 'dan kapatma


138

Bilgisayarı bir C # programından kapatmanın en iyi yolu nedir?

İşe yarayan birkaç yöntem buldum - onları aşağıda göndereceğim - ancak hiçbiri çok zarif değil. Daha basit ve doğal bir şekilde .net arıyorum.

Yanıtlar:


171

Windows XP ile başlayan çalışır, win 2000 veya daha düşük sürümlerde mevcut değildir:

Bunu yapmanın en hızlı yolu:

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

Aksi takdirde, diğerlerinin söylediği gibi P / Invoke veya WMI kullanın.

Düzenleme: pencere oluşturmama

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

2
Bu, hizmetlerden de işe yarıyor gibi görünüyor (en azından ilgilendiğim senaryolarda). Asla bir hizmetten çalışmak için WMI veya ExitWindowsEx yöntemleri elde edebildi.
James

1
@James Bir hizmet genellikle bunun için izinlere sahip olmadığından.
AK_

Makinenin güç tüketimi durumu, bunu kullandıktan sonra, geleneksel kapatma iletişim kutusu penceresinden sonrakinden farklıdır. Yeniden başlatmak için güç düğmesine basmak, standart 300 + ish yerine yaklaşık 80-85 miliamper çeker. Nedenini bulursam buraya geri göndereceğim. Bu, çoğu kullanıcıyı etkilememelidir.
samuelesque

Bu harika çalışıyor, ancak WPF'deyseniz, bu tam olarak profesyonel görünümlü değil, bir saniye için bir konsol penceresi oluşturacak.
Dustin Jensen

80

Den alınan: a Geekpedia post

Bu yöntem WMI kullanır pencereleri kapatmak .

Bunu kullanmak için projenize System.Management'a bir başvuru eklemeniz gerekir.

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
WMI kullanmak hataları izlemeyi kolaylaştırır. Kapatma komutu herhangi bir nedenden dolayı çalışmazsa ne olur?
Rob Walker

2
Pencereleri kapatmak için bu yöntemi kullanıyorum ve üç kez iki izinleri yok, ama üçüncü kez, "pes" sot ve yine de bilgisayarı yeniden başlatır bana söyleyecektir. Bunun nesi var?
DTI-Matt

1
Bu çözüm benim için işe yaramıyor. Yönetici kullanıcısı altında programı çalıştırsam bile "Ayrıcalık tutulmadı" özel durumu alıyorum.
Fanda

@roomaroo Bu yöntem işe yaramıyor. Bir istisna atar: Yönetim istisnası, ayrıcalık elde edilmez.
somethingSomething

Zorla kapatmak istiyorsanız mboShutdownParams ["Flags"] = "5" kullanmalısınız; Değer 5, zorunlu kapatma anlamına gelir.
SaneDeveloper

32

Bu iş parçacığı gerekli kodu sağlar: http://bytes.com/forum/thread251367.html

ama işte ilgili kod:

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

Kullanımı:

DoExitWin( EWX_SHUTDOWN );

veya

DoExitWin( EWX_REBOOT );

Diğer EWX_ katılımcılarının burada ne yaptığını okuyabilirsiniz: msdn.microsoft.com/en-us/library/windows/desktop/…
TripleAntigen

1
Sayısal sabitleri C # olarak taşırken, en iyi uygulama bir numaralandırma kullanmaktır. Bir enum bunu yapmak için tasarlandı. Sayısal sabitler etrafında güçlü yazım sağlar, isteğe bağlı olarak bayrakları / bit maskeleri destekler ve altta yatan sayısal türe kolayca ileri geri yayınlar.
Andrew Rondeau

26

Farklı yöntemler:

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

B. Windows Yönetim Araçları (WMI)

C. System.Runtime.InteropServices Pinvoke

D. Sistem Yönetimi

Gönderdikten sonra, başkalarının da yayınladığını gördüm ...


2
B ve D aynı yöntemdir (WMI)
Lucas


14

Eski okul çirkin yöntemi. ExitWindowsExWin32 API'sindeki işlevi kullanın .

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

Üretim kodunda API çağrılarının dönüş değerlerini kontrol etmelisiniz, ancak örneği daha net hale getirmek için bunu bıraktım.


12

Kısa ve güzel. Harici bir programı arayın:

    using System.Diagnostics;

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

Not: Bu, Windows 'Shutdown.exe programını çağırır, bu nedenle yalnızca bu program varsa çalışır. Windows 2000'de (shutdown.exe dosyasının yalnızca kaynak kitinde bulunduğu) veya XP Katıştırılmış uygulamasında sorun yaşayabilirsiniz .


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

Çalışmalı.

Yeniden başlatmak için / r

Bu, PC kutusunu NO iletişim kutuları olmadan doğrudan ve temiz bir şekilde yeniden başlatır.


Modern (2015+) sistemlerde mükemmel cevap budur.
Fattie

teşekkürler, / s ve / t 0'ın ne yaptığını açıklayabilir misiniz?
Vladimir verleg

1
@Peterverleg Elbette. "/ S" bağımsız değişkeni bilgisayara kapanmasını bildirir ve "/ t" bilgisayara kapanmadan önce x saniye beklemesini bildirir. Kişisel deneyimlerden biliyorum ki "/ t" argümanı Windows 8.1'de hiçbir şey yapmadı, ama kesin olarak 7'de çalışıyor. Bu işlevleri de kullanabilirsiniz: shutdown /s /t 0 //For shutdown shutdown /r /t 0 //For restart shutdown /h /t 0 //For hibernateAyrıca, aynı sonuç için CMD'ye yazmayı deneyin.
Micah Vertal

6

Kapatma işlemini başlatabilirsiniz:

  • shutdown -s -t 0 - Kapat
  • shutdown -r -t 0 - Tekrar başlat


5

Yönetici olarak çalışmasına rağmen her zaman istisna tutulan ayrıcalık var çünkü yukarıda kabul edilen WMI yöntemini kullanmaya çalışırken sorun vardı.

Çözüm, sürecin kendisi için ayrıcalık istemesi idi. Cevabı http://www.dotnet247.com/247reference/msgs/58/292150.aspx adresinde Richard Hill adlı bir adam tarafından yazılmış buldum .

Bağlantının eskimesi durumunda temel çözümünü aşağıda yapıştırdım.

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
Nedenini bilmemekten hoşlanmama rağmen bu işe yaradı. Dürüst olmak gerekirse ben sadece "kapatma" komutu ile gitmek gerekir miydi ...
Dan Bailiff

5

Pop Catalin'in cevabına eklemek için , bilgisayarı herhangi bir pencere göstermeden kapatan tek bir astar :

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

2

Windows 2003 Server'ı kapatmak için roomaoro'nun WMI yöntemini denedim , ancak Main () bildirime `[STAThread] 'i (yani" Tek Dişli Daire "iş parçacığı modeli) ekleyene kadar işe yaramaz :

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

Sonra bir iş parçacığından kapatma çalıştı ve işe almak için ben de "Daire devlet" iplik STA için de ayarlamak zorunda kaldı:

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

Ben bir C # çaylak, bu yüzden (hatta yukarıda yayınlanan bağlantıyı okuduktan sonra) sistemi kapatma açısından STA iş parçacıklarının öneminden tamamen emin değilim. Belki birileri daha ayrıntılı ...?


Aslında, yalnızca WMI'yi çağıran iş parçacığının STA iş parçacığı olması gerekir. Bu ana iplik Main()değilse, gerekmez [STAThread].
SLaks

2

** Ayrıntılı Yanıt ...

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

1

Shutdown.exe dosyasını kullanın. Değişkenleri, karmaşık yürütme, WindowForms yürütme sorununu önlemek için PowerShell yürütme komut dosyasını kullanın:

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 işletim sistemine yüklenmeli ve GAC'de mevcut olmalıdır.

İngilizcem için üzgünüm.


0

Bilgisayarı kapatmak için .net yerel yöntemi yoktur. ExitWindows veya ExitWindowsEx API çağrısını P / çağırmanız gerekir.


0

Bilgisayarı uzaktan kapatmak istiyorsanız şunu kullanabilirsiniz:

Using System.Diagnostics;

herhangi bir düğmeye tıklandığında

{
    Process.Start("Shutdown","-i");
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.