Добрый день, сегодняшняя статья будет описывать реализацию класса для выключения или перезагрузки компьютера пользователя. Вы возможно думаете, зачем это нужно. Я вам скажу что в некоторых весьма специфичных моментах нужно, например: после изменения реестра перезагрузить машину, все надо будет сделать это показать сообщение пользователю и по результату ответа, вызвать или не вызвать метод который мы напишем сегодня чуть позже.
Кстати, выполнить эту задачу на 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 функций в соответствии с MSDN
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";ОК, все что нужно у нас есть, хотя не хватает одной мелочи - функции повышения привилегий нашего процесса. Давайте ее напишем, но сначала объявим для нее структуру:
[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 я опишу будущей статье, когда будет время.