Московский физико-технический институт
Опубликован: 12.12.2007 | Доступ: свободный | Студентов: 5489 / 1826 | Оценка: 4.34 / 4.14 | Длительность: 13:57:00
ISBN: 978-5-94774-827-7
Лекция 2:

Разработка Win32 приложений. Инструментальные средства изучения системы

< Лекция 1 || Лекция 2: 12 || Лекция 3 >

Разработка приложений с использованием Unicode

Чтобы снизить зависимость приложения от используемой кодировки, целесообразно в программе определить два макроса - UNICODE и _UNICODE. Также рекомендуется использовать новый набор данных и функций, обрабатывающих строки и описанных в стандартных заголовочных файлах.

Обычно, имена Unicode данных и функций содержат префикс "wc" (от wide character), "w". Например, WCHAR - Unicode символ, wcscmp - функция сравнения Unicode строк. Можно также поставить префикс "L" перед текстовой строкой, например, L"Текстовая строка" - строка в формате Unicode.

Чтобы реализовать возможности компиляции двойного назначения, нужно включить в состав программы заголовочный файл tchar.h. Он состоит из макросов, которые ссылаются на Unicode данные и функции, если в программе определен макрос UNICODE, и на ANSI - в противном случае. Так, для объявления символьного массива универсального назначения применяется тип TCHAR, который транслируется в WCHAR, если UNICODE определен, и в CHAR, если не определен. Аналогичным образом макросы с префиксом "l" переопределяют строковые функции ( lstrlen вместо strlen и т.д.), а для определения символьных и строковых литералов применяется макрос _TEXT (или просто _T ). Более подробно этот материал описан в [ Рихтер ] .

Прогон программы вывода строки в формате Unicode

В качестве упражнения рекомендуется реализовать программу вывода строки "Hello, world".

#define UNICODE
#ifdef UNICODE
#define _UNICODE
#endif
#include <windows.h>
#include <tchar.h>
#include <stdio.h>

void main() {
PTCHAR TextString = _T("Hello, world");
_tprintf(_T("String -  %s\n"), TextString);
}

Необходимо убедиться, что программа одинаково работает в случае применения и отключения Unicode.

Прогон программы записи в файл в Unicode и обычном формате

Приведенная программа может вывести строку "Hello, world" в файл MyFile.txt в обычном формате и в формате Unicode.

#define UNICODE
#ifdef UNICODE
#define _UNICODE
#endif
#include <windows.h>
#include <tchar.h>
#include <stdio.h>

void main() {

HANDLE hFile;
PTCHAR  FileName = _T("MyFile.txt");
PTCHAR TextString = _T("Hello, world.");
DWORD iWrite, StringLength = lstrlen(TextString);

_tprintf(_T("There are %ld symbols in text string  %s\n"),  StringLength, TextString);


hFile = CreateFile(FileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | 0, NULL); 

iWrite = StringLength;
#ifdef UNICODE
 iWrite = 2*StringLength;
#endif

WriteFile(hFile, TextString, iWrite, &iWrite, NULL);
printf("%d bytes are written to file\n", iWrite);
CloseHandle(hFile); 
}

Рекомендуется оба варианта получившегося файла просмотреть с помощью блокнота Nоtepad.

Обработка ошибок

Профессиональная разработка программных приложений предполагает включение кода для корректного восстановления после потенциальных ошибок. В случае возникновения ошибки система может справиться с ней самостоятельно, но в экстремальных ситуациях может потребоваться вмешательство пользователя.

Вызываемая Win32-функция может возвратить значение, свидетельствующее об ошибке (например, NULL для функций типа HANDLE или ноль для функций типа BOOL). В таких случаях можно попытаться выявить тип ошибки при помощи функции GetLastError - она возвращает код последней ошибки, который хранится в локальной памяти потока, вызвавшего ошибку. Коды ошибок (а их более 10 тысяч), представляющие собой 32-битные числа, находятся в заголовочном файле WinError.h.

Если приложение содержит функции, к которым обращаются другие программы, то желательно, чтобы эти функции синтезировали код ошибки в случае возникновения ошибочных ситуаций, то есть вели себя подобно функциям Win32 API. Это можно сделать при помощи функции SetLastError.

Для преобразования кода ошибки в ее содержательное описание предназначена Win32-функция FormatMessage. Получить описание ошибки по ее коду можно также с помощью утилиты errlook.exe, поставляемой в составе Visual Studio. Аналогичная информация содержится в справочной системе MSDN.

В тех случаях, когда об ошибке необходимо оповестить пользователя, можно использовать звуковой сигнал (функция MessageBeep ). Для обработки ошибок также активно применяется структурная обработка исключений (Structured Exception Handling, см., [ Рихтер ] , [ Харт ] ).

Прогон программы, синтезирующей информацию об ошибке, которая имитирует отсутствие нужного файла

#include <windows.h>
#include <stdio.h>

void GetError() { 
 DWORD dw = GetLastError(); 
 printf("GetLastError returned %u\n", dw); 
} 
void SetError() {
 DWORD dw = ERROR_FILE_NOT_FOUND;
 SetLastError (dw);
}
     
void main() {
 SetError();
 GetError();
}

Рекомендуется реализовать данную программу и сверить номер выдаваемой ошибки с соответствующим перечнем в MSDN или файле заголовка WinError.h.

Инструментальные средства изучения системы

В рамках данного курса изучение внутреннего строения ОС Windows осуществляется, главным образом, путем разработки небольших программ, ориентированных на взаимодействие с различными компонентами системы. Вместе с тем, многие детали реализации рассматриваемой операционной системы можно выявить с помощью разнообразных инструментальных средств, некоторые (depends и errlook) уже упоминались в предыдущих разделах. Ниже приведен приблизительный перечень полезных ресурсов и утилит.

Штатные и встроенные средства

Большое количество полезных инструментов поставляется вместе с системой. Это, во-первых, штатные утилиты, такие, как диспетчер задач, редактор реестра, разнообразные средства настройки и администрирования, информативные панели. Очень много полезной информации можно получить путем интерпретации показаний многочисленных счетчиков производительности, предназначенных для мониторинга системы. Счетчики производительности, а их более сотни для различных объектов, доступны через оснастку "Производительность" административной панели управления, а также через API системы.

Большое количество полезных утилит входит в состав Windows Support Tools, для их установки надо запустить Setup из папки \Support \ Tools в дистрибутиве системы.

Утилиты и программные средства, входящие в состав Platform SDK

В состав Microsoft Platform SDK входит более 100 полезных утилит, находящихся после установки пакета в каталоге Program Files\Microsoft SDK\Bin. Их использование регламентируется встроенными подсказками, а также прилагаемой к Platform SDK гипертекстовой системой контекстной помощи. Кроме того, в состав пакета входит большое количество библиотек, заголовочных файлов, примеров программного кода и полезной документации.

Утилиты, поставляемые в составе Resourse Kit (ресурсы Windows)

В комплект входит большое число утилит. Их состав частично пересекается с утилитами, входящими в комплект Microsoft Platform SDK.

Утилиты с сайта sysinternals.com

На данном сайте имеется много полезных свободно распространяемых утилит, большинство из которых написано М.Руссиновичем.

Помимо перечисленных разработчиками активно используются утилиты, входящие в состав пакетов Visual Studio, DDK (Device Driver Kit), и разнообразные средства отладки. Вместе с тем, обилие инструментальных возможностей никоим образом не исключает необходимости разработки программ для всестороннего изучения ОС. Практическое применение API системы позволяет лучше изучить ее особенности, а также дает возможность создавать гибкие приложения, которые соответствуют сложным сценариям и требованиям, предъявляемым к современному программному обеспечению.

Заключение

В данной лекции рассмотрены вопросы, важные с точки зрения практического освоения ОС Windows и разработки Win32-приложений. Основным источником сведений об API системы является справочная система MSDN. Разработчику приложений необходимо владеть средствами разработки и отладки, знать основные типы данных и форматы хранения текстовых строк, а также правильно обрабатывать ошибки. Дополнительным источником сведений о системе являются разнообразные инструментальные средства.

< Лекция 1 || Лекция 2: 12 || Лекция 3 >
Ирина Оленина
Ирина Оленина
Николай Сергеев
Николай Сергеев

Здравствуйте! Интересует следующий момент. Как осуществляется контроль доступа по тому или иному адресу с точки зрения обработки процессом кода процесса. Насколько я понял, есть два способа: задание через атрибуты сегмента (чтение, запись, исполнение), либо через атрибуты PDE/PTE (чтение, запись). Но как следует из многочисленных источников, эти механизмы в ОС Windows почти не задействованы. Там ключевую роль играет менеджер памяти, задающий регионы, назначающий им атрибуты (PAGE_READWRITE, PAGE_READONLY, PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_NOACCESS, PAGE_GUARD: их гораздо больше, чем можно было бы задать для сегмента памяти) и контролирующий доступ к этим регионам. Непонятно, на каком этапе может включаться в работу этот менеджер памяти? Поскольку процессор может встретить инструкцию: записать такие данные по такому адресу (даже, если этот адрес относится к региону, выделенному менеджером памяти с атрибутом, например, PAGE_READONLY) и ничего не мешает ему это выполнить. Таким образом, менеджер памяти остается в стороне не участвует в процессе...