|
При нажатии на Сумма в примере ArbitraryMethod из Лекция 7, VS 2013 выдается ошибка: Необработанное исключение типа "System.InvalidOperationException" в System.Windows.Forms.dll Дополнительные сведения: Недопустимая операция в нескольких потоках: попытка доступа к элементу управления "lblResult" не из того потока, в котором он был создан. Затем: Необработанное исключение типа "System.InvalidOperationException" в mscorlib.dll Дополнительные сведения: Для каждой асинхронной операции метод EndInvoke может вызываться только один раз. |
Использование библиотек кода в windows-формах
Получение имени пользователя. Библиотека secur32.dll
Итак, приступим к практике. Создайте новое Windows-приложение и назовите его GetUserName. Перетаскиваем на форму из окна ToolBox кнопку и надпись. Устанавливаем следующие свойства формы и элементов управления:
В окне Solution Explorer щелкаем правой кнопкой на названии проекта и выбираем Add\Add New Item…. В появившемся окне шаблонов выбираем класс и называем его WinAPIClass.cs. Переходим в его код и добавляем пространство имен для работы с библиотеками dll и объектом StringBuilder:
using System; using System.Runtime.InteropServices; using System.Text;
Обращаемся к библиотеке secur32.dll и создаем метод GetUserNameEx (привожу пространство имен класса полностью 11Конструктор класса был удален ):
namespace GetUserName
{
public class WinAPIClass
{
#region Получение имени текущего пользователя
/// <summary>
/// Получение имени текущего пользователя.
/// </summary>
/// <param name="nameFormat">Формат имени из перечисления NameFormat.</param>
/// <param name="userName">Выходной параметр — имя.пользователя</param>
/// <param name="userNameSize">Количество символов в имени.</param>
/// <returns></returns>
//Подключение библиотеки secur32.dll
[DllImport("secur32.dll", CharSet=CharSet.Auto)]
public static extern int GetUserNameEx (int nameFormat, StringBuilder userName, ref uint userNameSize);
/// <summary>
/// Формат имени.
/// </summary>
public enum NameFormat:int
{
NameUnknown = 0,
NameFullyQualifiedDN = 1,
NameSamCompatible = 2,
NameDisplay = 3,
NameUniqueId = 6,
NameCanonical = 7,
NameUserPrincipal = 8,
NameCanonicalEx = 9,
NameServicePrincipal = 10,
NameDnsDomain = 12
};
#endregion
}
}
Листинг
5.1.
Все! Класс, использующий функцию WinAPI, готов. В обработчике кнопки btnGetUserName обращаемся к созданному классу:
private void btnGetUserName_Click(object sender, System.EventArgs e)
{
StringBuilder builder = new StringBuilder(100);
uint size = 100;
WinAPIClass.GetUserNameEx((int)WinAPIClass.NameFormat.NameSamCompatible, builder, ref size);
lblGetUserName.Text = String.Format("Имя пользователя: {0}", builder.ToString());
}Обратите внимание на то, что в качестве значения перечисления идет тип данных int, объект StringBuilder передается в качестве строки и к последнему параметру добавляется ключевое слово ref, т.к. параметр передается по ссылке. Результатом запуска приложения будет определение имени текущего пользователя (рис. 5.1).
Класс WinAPIClass, в котором происходит обращение к библиотеке secur32.dll, мог быть написан на другом, C-подобном языке, в оригинале он был реализован именно на C. Интересно сравнить типы данных двух листингов объявления методов:
- Метод GetUserNameEx на языке С
BOOLEAN GetUserNameEx( EXTENDED_NAME_FORMAT // формат имени NameFormat, // буфер для названия LPTSTR lpNameBuffer, // размер буфера для названия PULONG nSize );
- Метод GetUserNameEx на языке С#
[DllImport("secur32.dll", CharSet=CharSet.Auto)] public static extern int GetUserNameEx (int nameFormat, StringBuilder userName, ref uint userNameSize);
Выбор типа данных может повлиять на выполнение преобразования входящих и исходящих параметров. Например, в библиотеках WinAPI тип данных long — 32-битный, в то время как в C# тип данных long — 64-битный.
На диске, прилагаемом к книге, вы найдете приложение GetUserName (Code\Glava5\GetUserName).
Диалоговые окна. Библиотека user32.dll
Всякий раз, когда мы начинаем изучать новый язык программирования, в число первых примеров входит вывод текстовой строки на экран. Операционная система Windows содержит определенное число типов диалоговых окон, с помощью которых пользователь получает уведомления о различных событиях. Создайте новое Windows-приложение и назовите его MessageBox. Располагаем на форме четыре кнопки и устанавливаем следующие свойства формы и кнопок:
| Button1, свойство | Значение |
|---|---|
| Name | btnABORTRETRYIGNORE |
| Location | 8; 8 |
| Size | 200; 23 |
| Text | Прервать Повторить Пропустить |
Снова добавляем к проекту класс и называем его WinAPIClass.cs.
Листинг этого класса:
using System;
using System.Runtime.InteropServices;
namespace MessageBox
{
public class WinAPIClass
{
#region Вызов диалогового окна MessageBox
/// <summary>
/// Вызов диалогового окна MessageBox.
/// </summary>
/// <param name="handle">Родительская форма окна</param>
/// <param name="text">Текст окна.</param>
/// <param name="title">Заголовок окна.</param>
/// <param name="type">Тип окна.</param>
/// <returns></returns>
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern int MessageBox(IntPtr handle, string text, string title, uint type);
/// <summary>
/// Тип диалогового окна.
/// </summary>
public enum MessageBoxType:int
{
/// <summary>
/// Три кнопки — Abort, Retry, Ignore
/// </summary>
MB_ABORTRETRYIGNORE = 2,
/// <summary>
/// Три кнопки — Cancel, Try, Continue
/// </summary>
MB_CANCELTRYCONTINUE = 6,
/// <summary>
/// Одна кнопка — Ok.
/// </summary>
MB_OK = 0,
/// <summary>
/// Две кнопки — Ok, Cancel.
/// </summary>
MB_OKCANCEL = 1,
/// <summary>
/// Две кнопки — Retry, Cancel
/// </summary>
MB_RETRYCANCEL = 5,
/// <summary>
/// Две кнопки — Yes, No
/// </summary>
MB_YESNO = 4,
/// <summary>
/// Три кнопки — Yes, No, Cancel
/// </summary>
MB_YESNOCANCEL = 3,
/// <summary>
/// Иконка-восклицание
/// </summary>
MB_ICONEXCLAMATION = 0x30,
/// <summary>
/// Иконка-предупреждение
/// </summary>
MB_ICONWARNING = 0x30,
/// <summary>
/// Иконка-информация
/// </summary>
MB_ICONINFORMATION = 0x40,
/// <summary>
/// Иконка-вопрос
/// </summary>
MB_ICONQUESTION = 0x20,
/// <summary>
/// Иконка-стоп
/// </summary>
MB_ICONSTOP = 0x10,
/// <summary>
/// Иконка-ошибка
/// </summary>
MB_ICONERROR = 0x10,
}
/// <summary>
/// Тип возвращаемого значения.
/// </summary>
public enum MessageBoxReturnType:int
{
IDABORT = 3,
IDCANCEL = 2,
IDCONTINUE = 11,
IDIGNORE = 5,
IDNO = 7,
IDOK = 1,
IDRETRY = 4,
IDTRYAGAIN = 10,
IDYES = 6
}
#endregion
}
}
Листинг
5.2.
В перечислении MessageBoxType приводятся различные типы стандартных окон и иконок. В обработчиках кнопок выбираем несколько вариантов окон и иконок:
private void btnABORTRETRYIGNORE_Click(object sender, System.EventArgs e)
{
//Текст сообщения
string text = "Hello World";
//Заголовок окна
string title = "From WinApi";
// Тип данных IntPtr — указатель на объект.
WinAPIClass.MessageBox(IntPtr.Zero, text, title, (uint)(WinAPIClass.MessageBoxType.MB_ABORTRETRYIGNORE | WinAPIClass.MessageBoxType.MB_ICONQUESTION));
}
private void btnYESNOCANCEL_Click(object sender, System.EventArgs e)
{
string text = "Hello World";
string title = "From WinApi";
WinAPIClass.MessageBox(IntPtr.Zero, text, title, (uint)(WinAPIClass.MessageBoxType.MB_YESNOCANCEL | WinAPIClass.MessageBoxType.MB_ICONINFORMATION));
}
private void btnOK_Click(object sender, System.EventArgs e)
{
string text = "Hello World";
string title = "From WinApi";
WinAPIClass.MessageBox(IntPtr.Zero, text, title, (uint)(WinAPIClass.MessageBoxType.MB_OK | WinAPIClass.MessageBoxType.MB_ICONSTOP));
}
private void btnYESNO_Click(object sender, System.EventArgs e)
{
string text = "Hello World";
string title = "From WinApi";
WinAPIClass.MessageBox(IntPtr.Zero, text, title, (uint)(WinAPIClass.MessageBoxType.MB_YESNO | WinAPIClass.MessageBoxType.MB_ICONEXCLAMATION));
}
Листинг
5.3.
Запускаем приложение. При нажатии на кнопки появляются соответствующие диалоговые окна (рис. 5.2).
На языке С метод в обработчике будет выглядеть следующим образом (сравните преобразование типов данных!):
INT MessageBox(HWND hWnd, LPCTSTR lpText, LPCTSTR lpCaption, UINT uType);
На диске, прилагаемом к книге, вы найдете приложение MessageBox. (Code\Glava5\MessageBox).


