Добрый день, сегодняшняя статья будет описывать реализацию класса для выключения или перезагрузки компьютера пользователя. Вы возможно думаете, зачем это нужно. Я вам скажу что в некоторых весьма специфичных моментах нужно, например: после изменения реестра перезагрузить машину, все надо будет сделать это показать сообщение пользователю и по результату ответа, вызвать или не вызвать метод который мы напишем сегодня чуть позже.
Кстати, выполнить эту задачу на C# можно несколькими способами:
В наш класс добавим API функции:
В данной строчке мы получаем указатель на наш процесс:
Для использования:
P.S. Озвученный тут метод с WMI я опишу будущей статье, когда будет время.
Кстати, выполнить эту задачу на C# можно несколькими способами:
- С помощью WinAPI.
- WMI - инструментарий управления Windows. Кто не знает, вам сюда (рассматривать в данной статье не буду).
- CMD команда.
WinAPI
Для начала рассмотрим самый объемный вариант - WinAPI.В наш класс добавим API функции:
//импортируем API функцию InitiateSystemShutdown
[DllImport("advapi32.dll", EntryPoint = "InitiateSystemShutdownEx")]
static extern int InitiateSystemShutdown(string lpMachineName, string lpMessage, int dwTimeout, bool bForceAppsClosed, bool bRebootAfterShutdown);
//импортируем API функцию AdjustTokenPrivileges
[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);
//импортируем API функцию GetCurrentProcess
[DllImport("kernel32.dll", ExactSpelling = true)]
internal static extern IntPtr GetCurrentProcess();
//импортируем API функцию OpenProcessToken
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
//импортируем API функцию LookupPrivilegeValue
[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
//импортируем API функцию LockWorkStation
[DllImport("user32.dll", EntryPoint = "LockWorkStation")]
static extern bool LockWorkStation();
Теперь инициализируем константы для работы API функций в соответствии с MSDNinternal 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";ОК, все что нужно у нас есть, хотя не хватает одной мелочи - функции повышения привилегий нашего процесса. Давайте ее напишем, но сначала объявим для нее структуру:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct TokPriv1Luid
{
public int Count;
public long Luid;
public int Attr;
}
Ну и сама функция:private static 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);
}
}
Тут много чего не понятного, немного поясню. Этот метод нужен для того чтобы гарантировать выполнения команды включения/выключения. Без нее, может просто ничего не произойти. Для управления конкретными привилегиями в WinAPI существует специальная структура TokPriv1Luid. Заполняя ее поля так:tkp.Count = 1;
tkp.Attr = SE_PRIVILEGE_ENABLED;
tkp.Luid = 0;
Мы указываем на необходимость ВКЛЮЧЕНИЯ привелегии. Какой именно, в данном случае не указывается. Но перед тем как управлять привилегиями процесса, необходимо получить особый указатель на процесс - IntPtr.В данной строчке мы получаем указатель на наш процесс:
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok)Привилегии в системе могут быть самые разнообразные, на нужна одна - позволяющая производить перезагрузку/выключение, ее имя - SeShutdownPrivilege (подробнее о всех привилегиях можно почитать в MSDN). Для того, что бы получить возможность работать с этой привилегией - нужно получить ее идентификатор:
LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tkp.Luid);Ну и на конец, когда мы заполнили структуру "выключателя", получили идентификатор привилегии - применям все это к уже известному идентификатору процесса:
AdjustTokenPrivileges(htok, false, ref tkp, 0, IntPtr.Zero, IntPtr.Zero);Ну вот почти все, почти перезагрузились. Добавьте этот простой код:
//публичный метод для перезагрузки/выключения машины
public static int halt(bool RSh, bool Force)
{
SetPriv(); //получаем привилегия
//вызываем функцию InitiateSystemShutdown, передавая ей необходимые параметры
return InitiateSystemShutdown(null, null, 0, Force, RSh);
}
//публичный метод для блокировки операционной системы
public static int Lock()
{
if (LockWorkStation())
return 1;
else
return 0;
}
Собственно класс имеет два метода: halt() - для выключения/перезагрузки, и не большим бонусом Lock() - для блокировки ОС (но не выходу из системы!)Для использования:
halt(true, false) //мягкая перезагрузка halt(true, true) //жесткая перезагрузка halt(false, false) //мягкое выключение halt(false, true) //жесткое выключение Lock() //блокировка ОСНу вот и все с первым способом разобрались :). Готовую библиотеку реализующую данный метод можно скачать на этой странице под названием AReboot. Поехали дальше...
CMD команда:
Это вариант на любителя, по объему работы он гораздо меньше, давай те я покажу как выключить машину:System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c shutdown -s -t 00";
p.Start();
Перезагрузка:System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/c reboot-s -t 00";
p.Start();
Вот и все :) Используйте тот метод который вам больше нравиться, и отвечает вашей идеологии. Существует еще много способов выполнить поставленную задачу, те что были озвучены - основные. Пробуйте, экспериментируйте, успехов вам.P.S. Озвученный тут метод с WMI я опишу будущей статье, когда будет время.