Програмная перезагрузка машины (а также выключение/блокировка)

2 ноября 2010 г.

Недавно столкнулся с необходимостью написания класса для программной перезагрузки машины. Чтобы не перекапывать гугл, решил написать сам. Понятно, что единственный путь тут — использование Win API. И вот спешу делюсь тем, что у меня получилось!

Собственно весь код класса, который в дальнейшем мы будем разбирать:

using System.Runtime.InteropServices;

class reboot
{
[DllImport("advapi32.dll", EntryPoint = "InitiateSystemShutdownEx")]
static extern int InitiateSystemShutdown(string lpMachineName, string lpMessage, int dwTimeout, bool bForceAppsClosed, bool bRebootAfterShutdown);
[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("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("user32.dll", EntryPoint = "LockWorkStation")]
static extern bool LockWorkStation();
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct TokPriv1Luid
{
public int Count;
public long Luid;
public int Attr;
}
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";
private void SetPriv()
{
TokPriv1Luid tkp; //экземпляр структуры TokPriv1Luid
IntPtr htok = IntPtr.Zero;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok))
{
tkp.Count = 1;
tkp.Attr = SE_PRIVILEGE_ENABLED;
tkp.Luid = 0;
LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tkp.Luid);
AdjustTokenPrivileges(htok, false, ref tkp, 0, IntPtr.Zero, IntPtr.Zero);
}
}
public int halt(bool RSh, bool Force)
{
SetPriv(); //получаем привилегия
return InitiateSystemShutdown(null, null, 0, Force, RSh);
}
public int Lock()
{
if (LockWorkStation())
return 1;
else
return 0;
}

Давайте рассмотрим зачем нужны некоторые из функций.
Функция SetPriv() нужна для повышения системных привилегий процесса. Это обеспечивает гарантированное выполнение команды выключения\перезагрузки. Без повышения привилегий, просто может ничего не происходить.
Функции вида internal static extern в представлении думаю не нуждаются — они служат для вызова одноимённых API функций (GetCurrentProcess, penProcessToken & etc).

Ах да, и чуть не забыл :) Описанный класс имеет два метода:
Lock() — вызов этого метода приведет к блокированию ос (но не выходу из системы!)
halt(bool RSh, bool Force) — вызов этого метода приводит к перезагрузке/выключению машины:

halt(true, false) //мягкая перезагрузка
halt(true, true) //жесткая перезагрузка
halt(false, false) //мягкое выключение
halt(false, true) //жесткое выключение

 

Теги:
рубрика C#, Windows