Опубликован: 11.09.2006 | Уровень: специалист | Доступ: платный
Лекция 5:

Использование библиотек кода в windows-формах

< Лекция 4 || Лекция 5: 123456 || Лекция 6 >

Завершение работы Windows, перезагрузка, выход пользователя из системы

Использование функций WinAPI позволяет добавлять в свои приложения даже такую функциональность, как завершение работы системы и ее перезагрузка. Создайте новое Windows- приложение и назовите его StartTurnOff. Добавляем на форму пять кнопок и устанавливаем следующие значения формы и кнопок:

Form1, форма, свойство Значение
BackgroundImage WindowCode\Glava5\StartTurnOff\Image\Window.bmp
FormBorderStyle None
Size 314; 400
StartPosition CenterScreen
Button1, свойство Значение
Name BtnCancel
Location 243; 169
Size 61; 19
Text Отмена
Button2, свойство Значение
Name btnCancel2
Location 245; 369
Size 61; 19
Text Отмена
Button3, свойство Значение
Name BtnTurnOff
Image TurnOffCode\Glava5\StartTurnOff\Image\TurnOff.bmp
Location 140; 80
Size 34; 34
Text
Button4, свойство Значение
Name BtnRestart
Image RestartCode\Glava5\StartTurnOff\Image\Restart.bmp
Location 238; 81
Size 34; 34
Text
Button5, свойство Значение
Name BtnUserOut
Image UserOutCode\Glava5\StartTurnOff\Image\UserOut.bmp
Location 198; 280
Size 34; 34
Text

Добавляем класс WinAPIClass:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Text;
namespace StartTurnOff
{
		
		public class WinAPIClass
		{
			
			#region Завершение работы Windows. 
			/// <summary>
			/// Завершение работы.
			/// </summary>
			/// <param name="shutDownType">Тип завершения работы.</param>
			/// <param name="reason">Причина</param>		
			/// <returns></returns>
			[DllImport("user32.dll")]
			public static extern bool ExitWindowsEx(uint shutDownType, string reason);

			//To shut down or restart the system, the calling process must use the 
			//AdjustTokenPrivileges function to enable the SE_SHUTDOWN_NAME privilege.
			// Для выключения или перезагрузки системы вызываемый процесс 
			//должен использовать функцию AdjustTokenPrivileges для получения 
			//определенного уровня доступа (привилегии)

			/// <summary>
			/// Тип завершения работы.
			/// </summary>
			public enum ShutdownType:int
			{
				LogOf = 0,
				Shutdown = 0x00000001,
				Reboot = 0x00000002,
				PowerOf = 0x00000008			
			}

			#endregion
			// Дополнительные переменные
			public const int SE_PRIVILEGE_ENABLED = 2;
			public const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";
			public const int ANYSIZE_ARRAY = 1;
			public const int TOKEN_QUERY = 8;
			public const int TOKEN_ADJUST_PRIVILEGES = 32;//0x00000020;


			
			// Структура, используемая  для передачи в метод AdjustTokenPrivileges
			//  в качестве необходимой привилегии.
			[StructLayout(LayoutKind.Sequential, Pack=1)]
			internal struct TokPriv1Luid
			{
				// Количество привилегий в наборе.
				public int Count;
				public long Luid;
				// Тип привилегии.
				public int Attr;
			}

			/// <summary>
			/// Возвращение указателя на текущий процесс.
			/// </summary>
			/// <returns></returns>
			[DllImport("kernel32.dll", ExactSpelling=true) ]
			internal static extern IntPtr GetCurrentProcess();
			/// <summary>
			/// Открывание процесса  access token, который содержит информацию о 
///безопасности текущего пользователя, 
			/// привязанного  к заданному процессу.
			/// </summary>
			/// <param name="h">Указатель на процесс.</param>
			/// <param name="acc">Тип access token.</param>
			/// <param name="phtok">Указатель на access token.</param>
			/// <returns></returns>
			[DllImport("advapi32.dll", ExactSpelling=true) ]
			internal static extern bool OpenProcessToken( IntPtr h, int acc, ref IntPtr phtok );
			/// <summary>
			/// Возвращение значения переменной в текущей сессии ОС.
			/// </summary>
			/// <param name="host">Название системы. Если значение  null,  
			///поиск осуществляется
			///  в локальной системе.</param>
			/// <param name="name">Название переменной.</param>
			/// <param name="pluid">Указатель на значение переменной.</param>
			/// <returns></returns>
			[DllImport("advapi32.dll") ]
			internal static extern bool LookupPrivilegeValue( string host, string name, ref long pluid );
			/// <summary>
			/// Включение  указанной привилегии.
			/// </summary>
			/// <param name="htok">Указатель на access token</param>
			/// <param name="disall">Необходимость выключения  всех привилегий.</param>
			/// <param name="newst">Новое значение привилегии. Если предыдущее
			/// значение установлено в true, 
			/// то это значение не учитывается.</param>
			/// <param name="len">Размер буфера для следующего значения.</param>
			/// <param name="prev">Предыдущая привилегия.</param>
			/// <param name="relen">Указатель на  размер полученных привилегий.</param>
			/// <returns></returns>
			[DllImport("advapi32.dll", ExactSpelling=true) ]
			internal static extern bool AdjustTokenPrivileges( IntPtr htok, bool disall,
				ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen );
		}
	}
Листинг 5.8.

В коде формы добавляем обработчики кнопок:

private void btnCancel_Click(object sender, System.EventArgs e)
		{
			this.Close();
		}

		private void btnUserOut_Click(object sender, System.EventArgs e)
		{
			WinAPIClass.ExitWindowsEx((uint)WinAPIClass.ShutdownType.LogOf, "Win Api test");
		}

		private void btnTurnOff_Click(object sender, System.EventArgs e)
		{
			RestartOrShotDown(WinAPIClass.ShutdownType.Shutdown);
		}
		
		private void btnRestart_Click(object sender, System.EventArgs e)
		{			
			RestartOrShotDown(WinAPIClass.ShutdownType.Reboot);
		}
		void RestartOrShotDown(WinAPIClass.ShutdownType type)
		{				
			WinAPIClass.TokPriv1Luid tp;
			IntPtr hproc = WinAPIClass.GetCurrentProcess();
			IntPtr hToken = IntPtr.Zero;
			WinAPIClass.OpenProcessToken( hproc, WinAPIClass.TOKEN_ADJUST_PRIVILEGES | WinAPIClass.TOKEN_QUERY, ref hToken );
			tp.Count = 1;
			tp.Luid = 0;
			tp.Attr = WinAPIClass.SE_PRIVILEGE_ENABLED;
			WinAPIClass.LookupPrivilegeValue(null, WinAPIClass.SE_SHUTDOWN_NAME, ref tp.Luid );
			WinAPIClass.AdjustTokenPrivileges(hToken, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero );
			WinAPIClass.ExitWindowsEx((uint)type, "Win Api test");

		}

		private void btnCancel2_Click(object sender, System.EventArgs e)
		{
			this.Close();
		}
Листинг 5.9.

При запуске приложения появляется совмещенное окно завершения работы и смены пользователя (рис. 5.6). Кнопки "Выключение", "Перезагрузка" и "Выход" лучше всего проверять, завершив работу со средой Visual Studio .NET.

Приложение StartTurnOff

Рис. 5.6. Приложение StartTurnOff

На диске, прилагаемом к книге, вы найдете приложение StartTurnOff (Code\Glava5\StartTurnOff).

Как использовать другие функции WinAPI?

Рассмотренные примеры позволяют сделать вывод: использование функций WinAPI относится к одному из самых быстрых способов разработки приложений. При этом основная трудность заключается не в добавлении функции к приложению, а в ее поиске. В самом деле, операционная система Windows представляет чрезвычайно большой набор функций. Библиотека MSDN содержит подробное описание практически всех функций — для просмотра их списка в алфавитном порядке выбираем Пуск\Все программы\Microsoft Visual Studio .NET 2003\Microsoft Visual Studio .NET 2003 Documentation, переходим на вкладку Поиск (Search) и в строке поиска набираем WinAPI functions. В списке статей появится заголовок Functions in Alphabetical Order (Функции в алфавитном порядке) — это и есть то, что нам нужно (рис. 5.7).

Список функций WinAPI в алфавитном порядке в библиотеке MSDN

увеличить изображение
Рис. 5.7. Список функций WinAPI в алфавитном порядке в библиотеке MSDN

Я привел методику поиска, а не расположение в содержании, — в зависимости от версии структура библиотеки может меняться, но она неизменно будет содержать список функций.

Класс String Builder

При изучении синтаксиса языка C# вы проходили класс String (пространство имен System.String) и, возможно, класс StringBuilder (пространство имен System.Text). Если эти понятия не совсем вам ясны, освежите материал — класс String описывается в любом учебнике по C#. Здесь же мы кратко рассмотрим класс StringBuilder — в следующем примере этот класс в качестве примера при вызове очередной функции WinAPI.

Одним из основных преимуществ использования этого класса является скорость работы. Упрощенно говоря, при изменении строки, созданной как экземпляр класса String, у нас создается каждый раз новый экземпляр класса, а старый уничтожается; при использовании же класса StringBuilder мы всегда работаем с одним экземпляром.

Экземпляр String Builder создается так же, как и другие экземпляры классов:

StringBuilder sb1=new StringBuilder("Hello");

Класс StringBuilder содержит только динамические методы. Рассмотрим на практике некоторые свойства и методы этого класса. Создайте новое консольное приложение и назовите его SBuilder

У класса StringBuilder нет статических методов. Все его методы — динамические. Ниже перечислены основные свойства и методы класса StringBuilder.

Свойство Length. Возвращает длину строки. Пример (здесь и далее см. рис. 5.8):

StringBuilder sb1=new StringBuilder("Hello"); 
int k=sb1.Length;
Console.WriteLine("Длина строки sb1 "+k);

Свойство только для чтения MaxCapacity. Возвращает максимальное количество символов, которые можно записать в экземпляр класса StringBuilder. Пример:

StringBuilder sb1=new StringBuilder("Hello"); 
System.Console.WriteLine("Максимальное количество символов "+sb1.MaxCapacity);

Метод Append. Добавляет значение новой строки к существующему значению. Пример:

StringBuilder sb1=new StringBuilder("Hello"); 
StringBuilder sb2=new StringBuilder(" World ");
sb1.Append(sb2);
sb1.Append("!!!");
System.Console.WriteLine(sb1);

Метод Equals. Служит для сравнения двух строк. Возвращает true или false. Пример использования:

StringBuilder sb1=new StringBuilder("Hello"); 
StringBuilder sb2=new StringBuilder(" World ");       
if(sb1.Equals(sb2))
			System.Console.WriteLine("Строки равны");
else
			System.Console.WriteLine("Строки не равны");

Метод Insert. Вставляет символы в заданную позицию (нумерация начинается с нуля). Пример использования:

StringBuilder sb3=new StringBuilder("Пртствие!");
sb3.Insert(2, "иве");
System.Console.WriteLine(sb3);

Метод Remove. Удаляет символы из строки. Первый параметр метода Remove — номер позиции, с которой начинается удаление, второй — количество удаляемых символов. Пример:

StringBuilder sb4=new StringBuilder("Казнить нельзя, помиловать");
sb4.Insert(7, ",");
sb4.Remove(15, 1);
System.Console.WriteLine(sb4);

Метод Replace. Заменяет символы. Пример:

StringBuilder sb5=new StringBuilder("Internet");
sb5.Replace("er", "ra");
System.Console.WriteLine(sb5);
Результаты приложения SBuilder

Рис. 5.8. Результаты приложения SBuilder

На диске, прилагаемом к книге, вы найдете приложение SBuilder (Code\Glava5\SBuilder).

< Лекция 4 || Лекция 5: 123456 || Лекция 6 >
Елена Дьяконова
Елена Дьяконова

При нажатии на Сумма в примере ArbitraryMethod из Лекция 7, VS 2013 выдается ошибка: 

Необработанное исключение типа "System.InvalidOperationException" в System.Windows.Forms.dll

Дополнительные сведения: Недопустимая операция в нескольких потоках: попытка доступа к элементу управления "lblResult" не из того потока, в котором он был создан.

Затем:

Необработанное исключение типа "System.InvalidOperationException" в mscorlib.dll

Дополнительные сведения: Для каждой асинхронной операции метод EndInvoke может вызываться только один раз.

Александр Сороколет
Александр Сороколет

Свойство WindowState формы blank Maximized. Не открывается почемуто на всё окно, а вот если последующую форму бланк открыть уже на макс открывается :-/

Иван Циферблат
Иван Циферблат
Россия, Таганрог, 36, 2000