При нажатии на Сумма в примере 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).