Student.gomel.by
На главную ... Контакты ... Университеты ... Частые вопросы ...
Заказать курсовую в Гомеле ...
Репетитор по информатике ...
Условия ...
Так сколько же стоит?


Курсовой проект по ОСиСП



Форма отчётности в 7 семестре – курсовой проект. Тематика курсовых проектов в обязательном порядке согласовывается с преподавателем.

Курсовой проект должен состоять из следующих разделов:
  • Введение
  • Описание используемых инструментов и технологии
  • Описание программной реализации приложения
  • Заключение
  • Приложения
Во введении описываются цели и задачи проекта, актуальность темы, а также дается характеристика разделов курсового проекта.
Второй раздел представляет собой теоретическую часть курсового проекта и содержит описание использованных в ходе выполнения работы инструментов и технологий.
Третий раздел содержит программную документацию по реализованному приложению. Обратите внимание, что в тексте не должно быть исходного кода (за исключением небольших фрагментов, если это требуется для пояснения логики реализации) - исходный код должен приводится в приложениях.
В заключении делаются выводы по проделанной работе, описывается, какой результат был получен, что в дальнейшем можно улучшить, какие навыки и новые знания были получены в ходе выполнения работы и т.д.
В приложениях приводится программный код, а при необходимости – графический материал и таблицы.


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




Рис 1 Внешний интерфейс приложения Навигация осуществляется посредством информативного меню, удобного в работе. Для того, чтобы запустить программу на выполнение достаточно выбрать пункт “Запустить службу”. Чтобы остановить действие программы: пункт “Остановить службу”. В пункте “Параметры” предоставляется возможность установить программу в “Автозагрузку” Windows. После выполнения программы, можно просмотреть полученные результаты с помощью пункта меню “Журнал” ( Рис 2).




Рис 2 Журнал Пункт меню “Выход” предназначен для выхода из приложения.
2. Разработка сетевого клиента для ОС Windows.
Windows Networking. Разработать программу, которая сканирует доступные ресурсы указанного компьютера в сети. Перед тем как сканировать программа должна проверить есть ли в сети такой компьютер. Программа должна позволять подключать сетевые диски.
Как перечислить сетевые подключения Из командной строки MS-DOS, для просмотра сетевых ресурсов (дисков), к которым подключён компьютер, используется следующая команда: net use Программно, для того, чтобы начать перечисление подключённых сетевых ресурсов необходимо вызвать функцию WNetOpenEnum() и WNetEnumResources() для продолжения перечисления.
Следующий пример перечисляет сетевые соединения.
ЗАМЕЧАНИЕ: Необходимо включить в проект библиотеку mpr.lib, в которой хранятся функции WNet*. Пример кода #include #include void main() { DWORD dwResult; HANDLE hEnum; DWORD cbBuffer = 16384; DWORD cEntries = 0xFFFFFFFF; LPNETRESOURCE lpnrDrv; DWORD i;

dwResult = WNetOpenEnum( RESOURCE_CONNECTED, RESOURCETYPE_ANY, 0, NULL, &hEnum );

if (dwResult != NO_ERROR) { printf( "\nCannot enumerate network drives.\n" ); return; }

printf( "\nNetwork drives:\n\n" );

do { lpnrDrv = (LPNETRESOURCE) GlobalAlloc( GPTR, cbBuffer );

dwResult = WNetEnumResource( hEnum, &cEntries, lpnrDrv, &cbBuffer );

if (dwResult == NO_ERROR) { for( i = 0; i < cEntries; i++ ) { if( lpnrDrv[i].lpLocalName != NULL ) { printf( "%s\t%s\n", lpnrDrv[i].lpLocalName, lpnrDrv[i].lpRemoteName ); } } } else if( dwResult != ERROR_NO_MORE_ITEMS ) { printf( "Cannot complete network drive enumeration" ); GlobalFree( (HGLOBAL) lpnrDrv ); break; } GlobalFree( (HGLOBAL) lpnrDrv ); } while( dwResult != ERROR_NO_MORE_ITEMS );

WNetCloseEnum(hEnum); }

Как программно подключить сетевой диск.
Для подключения сетевого диска можно воспользоваться примером: NETRESOURCE netResource;

ZeroMemory(&netResource, sizeof(NETRESOURCE)); netResource.dwType = RESOURCETYPE_DISK; netResource.lpLocalName = "Q:"; netResource.lpRemoteName = "\\\\SPIKE\\homedir";

if(WNetAddConnection2(&netResource, "firebird", "djf", NULL) != NO_ERROR) { LPVOID lpMsgBuf;

FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL);

MessageBox(Application->Handle, (const char *)lpMsgBuf, "GetLastError", MB_OK | MB_ICONINFORMATION);

LocalFree(lpMsgBuf); }

3. Разработка приложения мониторинга изменений файлов и каталогов.
File I/O. Разработать программу, которая позволяет следить за изменениями (создание, запись, удаление файлов) указанного пользователем каталога.
Когда изменяются папки Есть несколько простых вызовов API, с помощью которых Вы можете запросить у файловой системы, чтобы она избирательно сообщила Вам о изменениях для файлов и папок. Как только Вы устанавливаете такую вахту, ваш поток может отправляться спать, ожидая прихода событий. Файловая система отреагирует на событие, как только она обнаружит вид изменения, за которым вы наблюдаете.
Унаследуем FolderWatcher из ActiveObject. Зададим в качестве источника уведомления - событие, а в каяестве приемника уведомления - дескриптор к окна, отвечающего на уведомление. Исходное событие установлено в конструкторе FolderWatcher. Важно также запустить удерживаемый поток в конце конструктора.
class FolderWatcher : public ActiveObject { public:

FolderWatcher (char const * folder, HWND hwnd) : _notifySource (folder), _hwndNotifySink (hwnd) { strcpy (_folder, folder); _thread.Resume (); } ~FolderWatcher () { Kill (); }

private: void InitThread () {} void Loop (); void FlushThread () {} FolderChangeEvent _notifySource; HWND _hwndNotifySink; char _folder [MAX_PATH]; }; Все действия в ActiveObject происходят внутри метода Loop. Здесь мы устанавливаем "бесконечный" цикл, в котором поток должен ожидать событие. Когда событие происходит, мы проверяем флажок _isDying (как обычно) и посылаем специальное сообщение WM_FOLDER_CHANGE окну, которое имеет дело с уведомлениями. Это - не предопределенное сообщение Windows. Оно специально определено нами для передачи уведомления о папке от одного потока другому.
Происходит следующее: удерживаемый поток делает другой вызов API, чтобы позволить файловой системе, узнать, что она нуждается в большем количестве уведомлений. Затем управление возвращается к ожидающему потоку, находящемуся в состоянии сна. Одновременно Windows получает наше сообщение WM_FOLDER_CHANGE из очереди сообщений и посылает его оконной процедуре принимающего окна.
UINT const WM_FOLDER_CHANGE = WM_USER;

void FolderWatcher::Loop () { for (;;) { // Wait for change notification DWORD waitStatus = WaitForSingleObject(_notifySource, INFINITE); if (WAIT_OBJECT_0 == waitStatus) { // If folder changed if (_isDying) return;

PostMessage (_hwndNotifySink, WM_FOLDER_CHANGE, 0, (LPARAM) _folder);

// Continue change notification if (!_notifySource.ContinueNotification ()) { // Error: Continuation failed return; } } else { // Error: Wait failed return; } } } Рассмотрим, что происходит в оконной процедуре в ответ на наше специальное сообщение. Мы вызываем метод Контроллера OnFolderChange. Этот метод может делать все, что мы захотим. В Проводнике (Explorer) он регенерирует отображение содержимого папки, которую мы наблюдаем. В нашем примере он только вызывает простое окно сообщения. Обратите внимание, что мы передаем имя измененной папки как LPARAM. Совершенно неважно, как определить WPARAM и LPARAM, в сообщении, определяемом пользователем.
Между прочим, Наблюдатель Папки - только часть Контроллера.
case WM_FOLDER_CHANGE: pCtrl->OnFolderChange (hwnd, (char const *) lParam); return 0;

void Controller::OnFolderChange (HWND hwnd, char const * folder) { MessageBox (hwnd, "Change Detected, "Folder Watcher", MB_SETFOREGROUND | MB_ICONEXCLAMATION | MB_OK); }

class Controller { public: Controller(HWND hwnd, CREATESTRUCT * pCreate); ~Controller (); void OnFolderChange (HWND hwnd, char const *folder); private: FolderWatcher _folderWatcher; }; Теперь, когда мы знаем, как иметь дело с уведомлением, давайте взглянем на их источники, События изменяющие файлы. Объект события создан файловой системой в ответ на FindFirstChangeNotification. Дескриптор этого события возвращен из вызова. Мы запоминаем этот дескриптор и используем его позже, чтобы или осуществить восстанавление или отказаться от нашего интереса к дальнейшим уведомлениям. Обратите внимание, что мы можем устанавливать наблююдение рекурсивно, то есть, наблюдать данную папку и все ее подпапки и под-подпапки. Мы можем также выражать интерес к специфическим изменениям, передавая поразрядное ИЛИ для любой комбинации следующих флажков: FILE_NOTIFY_CHANGE_FILE_NAME (переименование, создание или удаление файла) FILE_NOTIFY_CHANGE_DIR_NAME (создание или удаление каталога (папки)) FILE_NOTIFY_CHANGE_ATTRIBUTES FILE_NOTIFY_CHANGE_SIZE FILE_NOTIFY_CHANGE_LAST_WRITE (сохранение файла) FILE_NOTIFY_CHANGE_SECURITY Для удобства мы определили несколько подклассов от FileChangeEvent, которые соответствуют к некоторым полезным комбинациям этих флажков. Один из них - FolderChangeEvent, который мы использовали в нашем FolderWatcher.
class FileChangeEvent { public: FileChangeEvent(char const *folder, BOOL recursive, DWORD notifyFlags) { _handle = FindFirstChangeNotification (folder, recursive, notifyFlags); if (INVALID_HANDLE_VALUE == _handle) throw WinException("Cannot create change notification handle"); } ~FileChangeEvent () { if (INVALID_HANDLE_VALUE != _handle) FindCloseChangeNotification (_handle); }

operator HANDLE () const { return _handle; } BOOL ContinueNotification () { return FindNextChangeNotification (_handle); } private: HANDLE _handle; };

class FolderChangeEvent : public FileChangeEvent { public: FolderChangeEvent (char const * folder) : FileChangeEvent (folder, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME) {} };

class TreeChangeEvent : public FileChangeEvent { public: TreeChangeEvent (char const * root) : FileChangeEvent (root, TRUE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME) {} }; Должно быть теперь просто обобщить этот пример, чтобы сделать некоторую действительно полезную работу в ваших программах. 4. Разработка редактора системного реестра Windows.
Разработать программу, которая отображает следующую информацию из реестра: список форматов файлов и связанные с ними приложения. Программа должна позволять создавать новые типы файлов и связывать их с программами.
Системный реестр - база данных, которая сохраняет параметры настройки для 32 разрядных версий Microsoft Windows включая; Windows 95, 98 и NT. Он содержит информацию и параметры настройки для всех аппаратных средств, программ, пользователей, и свойств PC. Каждый раз, когда пользователь делает изменения в параметрах настройки Панели управления, или в ассоциациях файлов, системной настройке, или в установленном программном обеспечении, изменения отражаются и сохраняются в системном реестре.
Редактор системного реестра (REGEDIT.EXE) включен в большинство версий Windows (хотя Вы не найдете его в меню "Пуск") он дает возможность просматривать, искать и редактировать данные в пределах системного реестра. Имеется несколько методов для запуска редактора, самый простой - нажать на кнопку "Пуск", затем выбрать Выполнить, и в поле 'Открыть:' напечатать "regedit", и если редактор системного реестра установлен, он должен открыться.
Программа отображающая ключи реестра, позволяющая добавлять и изменять ключи, добавлять и изменять значения, может быть представлена следующим образом (Рис 3).


Рис 3 Главное окно программы Например, для просмотра подключей ветви «HKEY_CURRENT_CONFIG», необходимо щелкнуть левой кнопкой мыши по названию ветви «HKEY_CURRENT_CONFIG».
Если пользователю необходимо просмотреть подключи ключа «Software», необходимо щелкнуть левой кнопкой мыши по подключу «Software».
Для отображения значений подключа «Fonts» необходимо дважды щелкнуть левой кнопкой мыши по подключу «Fonts» (Рис. 4).


Для добавления подключа к данному ключу необходимо щелкнуть правой кнопкой мыши по ключу, к которому необходимо добавить подключ (вследствие чего появится меню) и нажать пункт меню «Создать» - «Раздел». Рядом с ключом, к которому добавили новый подключ, появляется знак «+» (плюс) (Рис. 5).




Для просмотра созданного подключа необходимо щелкнуть левой кнопкой мыши по ключу (Рис. 6)



После нажатия правой кнопкой мыши по подключу «New» (вызвав этим меню) можно переименовать ключ или удалить его. Также можно для него добавить новое значение (Рис. 7).




После нажатия правой кнопкой мыши по какому-нибудь значению, программа позволяет изменить значение, переименовать его, либо совсем удалить (Рис. 9).


Основные функции системного реестра Функции Назначение RegCloseKey Закрывает дескриптор данного открытого ключа. При этом освобождаются любые связанные с данным ключом системные ресурсы. Закрытие ключа отнюдь не вызывает задержку операций записи, происходящих непосредственно после выполнения данной функции.
RegCreateKeyEx Создает или открывает подключ указанного ключа.
RegDeleteKey Удаляет подключ заданного ключа RegDeleteValue Удаляет значение из подключа RegEnumKeyEx Перечисляет подключи указанного открытого ключа системного реестра.
RegEnumValue Перечисляет значения указанного ключа, открытого в системном реестре RegOpenKeyEx Открывает подключ системного реестра с требуемым типом доступа.
RegQueryInfoKey Возвращает информацию, которая описывает данный ключ системного реестра.
RegQueryValueEx Возвращает тип и данные для указанного имени значения, связанного с открытым ключом системного реестра.
RegSetValueEx Устанавливает именованное значение любого подключа системного реестра

5. Механизмы межпроцессного взаимодействия.
IPC. Разработать программу, реализующую функции обмена сообщениями с другой такой же программой посредством динамически подключаемых библиотек (DLL).
Динамически загружаемые библиотеки (DLL) - выполняемый программный модуль Microsoft Windows, загружаемый только при необходимости (по запросу).
Процесс создания динамической библиотеки проходит в два этапа. Первый из них заключается в создании файла-заголовка (*.h), который определяет основные свойства проекта. Для этого необходимо создать новый проект, выбрав в качестве типа проекта Dinamic Linked Library , после чего определить "пустой проект" ( empty project ). Затем создать файлы проекта. Пусть имя проекта будет funlib.
Далее создать файл заголовка – funlib . h (при помощи меню File\New..., выбрав файл-заголовок). В этот файл включить следующий текст : // File funlib.h #define EXPORT extern "C" __declspec(dllexport) EXPORT BOOL CALLBACK return333(); EXPORT int CALLBACK MyInc(int i); Первая строка файла определяет некоторую директиву EXPORT , которая будет использоваться для подключения сервисов, необходимых для создания ссылок на экспортируемые функции (то есть функции, которые могут быть использованы или импортированы другими программами). Следующие две строки являются предварительным объявлением функций, директива EXPORT и делает их динамическими функциями.
Теперь осталось написать текст программы *. cpp: //funlib.cpp #include #include #include "fulib.h"

int WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved) { return TRUE; }

EXPORT BOOL CALLBACK EdrCenterText() { return 333; }

EXPORT int CALLBACK MyInc(int i) { return ++i; } DllMain - аналог функции main для консольных приложений и функции WinMain для приложений, написанный под Windows . Эта функция автоматически вызывается при загрузке любой dll . Возвращаемое значение TRUE свидетельствует об успешной загрузке и инициализации внутренних ресурсов. Создадим обычное консольное приложение Win 32 и назовем его usedll . Для использования funlib . dll необходимо выполнить следующие: поместить в каталог проекта файлы funlib . h и funlib . lib . Второй файл является результатом компиляции предыдущего проекта и его можно найти в каталоге Debug . Кроме этого, в меню Project\Settings \ Link, Категория General, поле Object\library modules необходимо вписать имя файла-библиотеки для организации настроек связывания. Текст программы usedll.cpp приведен ниже.
// usedll.cpp : Defines the entry point for the console application.

#include "stdafx.h" #include "iostream.h" #include "funlib.h"

int main(int argc, char* argv[]) { cout << return333() << endl; cout << MyInc(5) << endl; return 0; } Данная программа выполнится если в каталоге, где располагается файл usedll.exe расположен файл динамической библиотеки funlib.dll . В результате выполнения данной программы на экране вы увидите следующую картину: 333 6 В заключении следует отметить, что используя механизмы динамического связывания, можно определять не только функции, но переменные и даже классы.
Второй способ использования DLL.


Рассмотренный выше способ написания программы, использующей динамически подключаемые библиотеки пригоден только в том случае, когда вы сами создали библиотеки, или, по крайней мере, вы имеете в наличии файл библиотеки *. lib . Однако, очень часто случается так, что есть только *. dll (или она только планируется). В этом случае можно использовать другой способ, который не требует для компиляции проекта наличия файлов, связанных с вызываемой *. dll .
Применение данного способа заключается в следующем: • Создаются прототипы функций, имеющие те же параметры, что и необходимые функции внутри *. dll . Для нашего примера это будет выглядеть так: typedef BOOL (WINAPI * Inc)(int i); • Объявляется переменная типа указателя на данную функцию: Inc pI ; • В программе осуществляется загрузка библиотеки: HINSTANCE hL; hL=LoadLibrary("funlib.dll"); • объявленному указателю на функцию присваивается адрес функции из *. dll : pI=(Inc)GetProcAddress(hL,(LPCSTR)2); • Функция используется по назначению: cout << pI(6); • После использования выгружается из памяти: FreeLibrary(hL); Целиком рассмотренный пример выглядит следующим образом: #include "stdafx.h" #include "iostream.h" #include "windows.h"

HINSTANCE hL; typedef int (CALLBACK * Inc)(int i); Inc pI;

int main(int argc, char* argv[]) { hL=LoadLibrary("1111.dll"); pI=(Inc)GetProcAddress(hL,(LPCSTR)2); cout << pI(6); FreeLibrary(hL); return 0; } Наличие *. dll требуется только во время запуска *. exe файла.
6. Реализация сервиса протоколирования событий в ОС Windows.
Программа должна уметь создавать и просматривать различные типы событий.
Event Logging Многие приложения записывают информацию об ошибках и событиях в различные собственные протоколы. Эти протоколы различаются форматами и поэтому с ними неудобно работать. Windows предоставляет приложениям стандартный и централизованный путь для записи важных программных и аппаратных событий. Этот сервис называется - Event Logging. Он позволяет сохранять события из различных источников в единственном списке, называемом протокол событий (event log). Для просмотра протокола используется приложение Event Viewer. Существует пять типов событий, которые могут быть запротоколированы. Каждое событие может принадлежать только одному типу событий. В Event Viewer эти типы используются для определения иконки, связанной с событием. Значение Описание Information Операция выполнена успешно. Warning Предупреждает, что в ходе выполнения операции возникла проблема, но она не требует немедленного вмешательства, хотя в будущем может привести к серьезным сбоям. Error Сообщает об значительных проблемах. События типа Error обычно отражают потерю функциональности или данных. Success audit Событие системы защиты. Информирует, что операция, требующая прав доступа, выполнена успешна. Failure audit Сбой получения прав на выполнение операции. Поскольку протокол событий является общедоступным сервисом, то вы должны подумать какие сообщения записывать в него. Рекомендуется сохранять в нем сообщения, которые могут оказаться полезными при решении аппаратных или программных проблем. Не рекомендуется его использовать в качестве инструмента для трассировки. Сообщение должно содержать полную и понятную информацию, необходимую, для определения ситуации, вызвавшей проблему и что необходимо сделать, чтобы эту проблему исправить.

В тексте сообщений не используйтесимволы табуляция и запятая.
При использовании UNC имен, или других ссылок, которые содержат пробелы, заключайте имя в угловые скобки. Например: <\\sharename\servername>.

Незабывайте, протоколирование событий потребляет ресурсы компьютера - дисковое пространство и процессорное время. Сервис протоколирования событий использует информацию из системного реестра, из ключа EventLog. Этот ключ содержит несколько подключей, называемых logfiles. В этих logfiles содержится информация о расположении ресурсов, необходимых сервису, когда приложение пишет или читает протокол. По умолчанию определены протоколы Application, System и Security.

Приложения и службы используют протокол - Application. Драйвера - System. Система безопастности пишет события в протокол Security. Записи о событиях содержат время, тип и категорию события. Каждая запись имеет структуру EVENTLOGRECORD. Записи нумеруются начиная с 1. Но если в Event Viewer установить свойство Overwrite events as needed, то при достижении максимального размера файла протокола, новые записи будут писаться поверху старых. Поэтому не факт, что самая старая запись будет иметь номер 1. Для получения самой старой записи надо использовать функцию GetOldestEventLogRecord, а для получения последующих - GetNumberOfEventLogRecords. Каждый протокол содержит подключи, называемые источниками сообщений (event source). Источник сообщений - это обычно имя приложения или его компонента. Приложения и службы должны регистрироваться в протоколе Application. Драйверы устройств - в System. Источникам сообщений нельзя давать имена, уже используемые для именование файлов протоколов. Источники сообщений содержат следущую информацию: Значение Описание CategoryCount Определяет количество поддерживаемых категорий событий. Тип - REG_DWORD. CategoryMessageFile Определяет путь к файлу категории. Этот файл должен содержать описания категорий. Тип - REG_EXPAND_SZ. DisplayNameFile Windows 2000/XP: указывает файл, содержащий имя источника событий. Это имя будет отображаться в Event Viewer. Если это значение не указано, то в качестве имени используется имя ключа реестра, в котором записан источник событий. Тип - REG_EXPAND_SZ. DisplayNameID Windows 2000/XP: Содержит числовой идентификатор строки с именем источника из файла, указанного в поле DisplayNameFile. Тип - REG_DWORD. EventMessageFile Указывает файл сообщений событий. В этом поле можно указать несколько файлов, разделенных точкой с запятой. Файл сообщений содержит строки, описывающие события. Тип - REG_EXPAND_SZ. ParameterMessageFile Указывает файл параметров сообщений. Файл параметров сообщений содержит параметры, которые будут вставляться в строки описаний событий. Тип - REG_EXPAND_SZ. TypesSupported Комбинация поддерживаемых типов событий. Тип - REG_DWORD. Может содержать одно или несколько из следущих значений: EVENTLOG_ERROR_TYPE EVENTLOG_WARNING_TYPE EVENTLOG_INFORMATION_TYPE EVENTLOG_AUDIT_SUCCESS EVENTLOG_AUDIT_FAILURE Когда приложение вызывает функцию RegisterEventSource или OpenEventLog, для получения указателя на протокол, служба протоколирования ищет указанное имя в реестре. Если источник с таким именем не найден, то используется источник по умолчанию Application. Но так как он не содержит файла сообщений, произойдет ошибка. Поэтому вы должны добавить свой источник. Категории позволяют организовать события, таким образом Event Viewer может их фильтровать. В каждом источнике можно определить свои собственные категории. Категории должны быть пронумерованы последовательно начиная с 1. Максимальное число категорий содержится в поле CategoryCount. Категории могут храниться в отдельном файле или же в файле с сообщениями. Для каждого источника сообщений определяются свои пронумерованные события и их текстовые описания. Описания должны быть доступны понимнию обычного пользователя. Рассмотрим формат идентификатора события. 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +---+-+-+-----------------------+-------------------------------+ |Sev|C|R| Facility | Code | +---+-+-+-----------------------+-------------------------------+ Sev Тип события. Может принимать одно из следующих значений: 00 - Success 01 - Informational 10 - Warning 11 - Error C Indicates a customer code (1) or a system code (0). (Уж затрудняюсь складно перевести.) R Резерв. Facility Категория сообщения. Может быть FACILITY_NULL или одним из следующих значений: FACILITY_ACS FACILITY_AAF FACILITY_CERT FACILITY_COMPLUS FACILITY_CONTROL FACILITY_DISPATCH FACILITY_INTERNET FACILITY_ITF FACILITY_MEDIASERVER FACILITY_MSMQ FACILITY_RPC FACILITY_SCARD FACILITY_SECURITY FACILITY_SETUPAPI FACILITY_SSPI FACILITY_STORAGE FACILITY_URT FACILITY_WIN32 FACILITY_WINDOWS Code Код события. 7. Методика обнаружения присутствия отладчика.
Разработать программу, которая позволяет отслеживать запущена она в среде отладчика или работает в обычном режиме. Если обнаружен отладчик, программа должна выводить соответствующее сообщение и пытаться завершить свое выполнение.
Во-первых, надо знать как отладчик попадает в процесс. Сделать это он может двумя методами: создать ваш процесс CreateProcess с флагом DEBUG_PROCESS или вызвать DebugActiveProcess, чтобы присоединиться к уже выполняемому процессу. В любом случае, он оставляет «следы» в вашем процессе, которыми пользуется функция IsDebuggerPresent.
Функция IsDebuggerPresent показывает, запущен ли вызывающий ее процесс в контексте отладчика. Эта функция экспортируется из KERNEL32.DLL.
BOOL IsDebuggerPresent(VOID) - Аргументы: У этой функции нет аргументов.
- Возвращаемое значение: Если текущий процесс запущен в контексте отладчика, возвращаемое значение не равно нулю. Если текущий процесс не запущен в контексте отладчика, возвращаемое значение равно нулю. Для прекращения работы отладчика служит функция VOID DebugBreak(VOID) - Аргументы: У этой функции нет аргументов.
- Возвращаемое значение: Эта функция не возращает никакое значение 8. Алгоритмы управления памятью в ОС Windows.
Разработать программу, демонстрирующую механизмы управления виртуальной памятью.
Microsoft Win32 API предоставляет набор функций, которые позволяют процессу манипулировать либо определять статус страниц виртуального адресного пространства. При этом поддерживается выполнение следующих операций: • Резервирование области виртуального адресного пространства. При резервировании адресного пространства не происходит передача физической памяти, но только предотвращается другие операции выделения памяти, которые используют указанную область. Эта операция никак не затрагивает виртуальное адресное пространство другого процесса. Резервирование памяти предовращает излишние расходы физической памяти, и предоставляют процессу возможность заранее зарезервировать адресное пространство для таких динамических структур данных, которые имеют свойство расти во времени. Для них процесс получает возможность выделять ровно столько физической памяти, сколько необходимо.
• Передавать зарезервированной области виртуального адресного пространства процесса физиескую память (в RAM или на винчестере), которая доступна только вызвавшему процессу.
• Указывать атрибуты чтения/записи, только чтения или отсутствия доступа для области памяти, которая имеет под собой физическую память. Это отличает функции по работе с виртуальной памятью от соответствующих стандартных функций выделения памяти, которые всегда выделяют фрагмент памяти доступом как для чтения, так и для записи.
• Снимать резервирование страниц, делая область виртуальной памяти доступной для последующих операций выделения памяти вызывающим процессом.
• Освобождения страниц, под которыми находилась физическая память, с соответствующим освобождением физической памяти, которая становиться доступной для последующего выделения памяти другими процессами.
• Фиксирование расположения одной или нескольких страниц, под которыми расположена физическая память, в оперативной памяти (RAM), что запрещает системе перемещать указанные страницы в файл подкачки.
• Получать информацию о диапазоне страниц виртуального адресного протранства вызывающего или указанного процесса.
• Изменять атрибуты защиты страниц указанного диапазона, под которыми расположена физическая память, для вызывающего или указанного процесса.
Выделение виртуальной памяти Функции для работы с виртуальной памятью обращаются со страницами памяти. Эти функции используют размер страницы на текущем компьютере для округления (с избытком) указанных размеров и адресов. Функция VirtualAlloc используется для выполнения одной из следующих операций: • Резервирование одной или более свободных страниц памяти.
• Передача физической памяти одной или более резервированных страницам.
• Резервирование и передача физической памяти одной или более свободных страниц памяти.
Вы можете либо указать системе стартовый адрес страниц памяти, с которого вы хотели бы зарезервировать или по которому вы хотите выделить физическую память, либо предоставить системе самой определить этот адрес. Функция производит выравнивание переданного адреса на границу страниц. Зарезервированные страницы недоступны программе, но при передаче физичесокой памяти страницам вы можете указать атрибуты доступа PAGE_READWRITE, PAGE_READONLY или PAGE_NOACCESS. При передаче физической памяти странице для нее выделяется место в файле подкачки. Страница инициализируется и перемещается в оперативную память только при первой попытке чтения или записи по адресу, принадлежащему странице. Вы можете использовать обычные указатели для получения доступа к виртуальной памяти, для которой была передана физическая память постредством вызова функции VirtualAlloc.
Освобождение виртуальной памяти Функция VirtualFree предназначена для выполнения одной из следующих операций: • Освобождение физической памяти, занимаемой одной или несколькими страницами. Состояние страниц изменяется на зарезервированное. Освобожденные страницы оперативной памяти становяться доступными для выделения любым процессом. Освобождение физической памяти может быть произведено для любого блока страниц.
• Освобождение блока, состоящего из одной или более страниц зарезарвированной памяти, с изменением состояния страниц на свободное. Освобождение блока страниц делает их доступными для выделения процессом. Страницы могут быть освобождены только в том случае, если они предарительно были зарезервированы вызовом VirtualAlloc.
• Освобождение физической памяти, занимаемой одной или несколькими страницами и снятие с этого блока резервирвания. При этом состояние страницы изменяется на свободное. Указанный блок должен содержать блоки, которые были зарезервированы путем вызова VirtualAlloc, а также блоки, которым была передана физическая память и никакие более.
После того, как блок был освобожден, или его физическая память была передана системе, вы не должны никогда обращаться к нему. Вся информация, которая находилась в блоке является навсегда потерянной. Попытка чтения или записи по адресам, приналежащих освобожденным страницам приводит к исключению нарушения доступа (access violation). Если вы нуждаетесь в информации, которая храиться в блоке, никогда не освобождайте из под него физическую память или не снимайте с него резервирование.
Для того, чтобы указать, что данные в некотором диапазоне памяти долгое время не будут представлять для вас интереса, следует вызвать функция VirtualAlloc, передав ей в качестве одного из параметров флаг MEM_RESET. В этом случае указанные страницы при первом же удобном случае будут перещены в файл подкачки. Тем не менее, блок памяти можно будет использовать в дальнейшем.
Работа со страницами Для того, чтобы определить размер страницы на текущем компьютере, необходимо использовать функцию GetSystemInfo Функции VirtualQuery и VirtualQueryEx позволяют получить информацию о регионе, состоящем из некольких последовательно расположенных страниц памяти, начинающихся с указанного адреса в виртуальном адресном пространстве процесса. При этом функция VirtualQuery позволяет получить информацию о памяти в вызывающем процессе, а VirtualQueryEx в указанном процессе и обычно используется для поддежки отладчиков, которые нуждаются в информации об отлаживаемом процессе. Если указанный адрес не попадает на границу страницы, то он округляется вниз до первого граничного значения. Указанный блок расширяется за счет следующих страниц, если они имеют следующие одинаковые атрибуты: • Все страницы имеют одинаковое состояние: им передана физическая память, или они зарезервированы, или они свободны.
• Если начальная страница памяти не является свободной, то будет дана информация только о тех страницах, которые были зерезервированы тем вызовом VirtualAlloc, который и зарезервировал начальную страницу диапазона.
• Защита доступа у всех страниц должна быть одна и та же (такая, как PAGE_READONLY, PAGE_READWRITE или PAGE_NOACCESS).
Функция VirtualLock позволяет зафиксировать одну или несколько страниц, которые имют под собой физическую память, в оперативной памяти (RAM), предотвращая сбрасвание этих страниц ситемой в файл подкачки. Эта функция гарантирует, что обращение к указанным критическим страницам пройдет без обращения к диску. Фиксирование страниц в памяти является опасным, так как оно ограничивает возможности системы по управлению памятью. Чрезмерное использование функции VirtualLock может понизить работоcпособность системы из-за частого сбрасывания страниц с выполняющимся кодом в файл подкачки. Функия VirtualUnlock снимает фиксацию с памяти, которая была зафиксирована вызовом VirtualLock.
Функция VirtualProtect позволяет процессу изменить права доступа к любой странице памяти, которая имеет под собой физическую память в адресном простанстве процесса. Например, процесс может выделить страницы с доступом как для чтения, так и для записи, а после того, как он изменит в них данные, установить для них доступ только для чтения, или вообще запретить всякий к ним доступ с целью предотвратить случайную перезапись. Функция VirtualProtect обычно используется при работе с памятью, которая была выделена функцией VirtualAlloc, но она может также работать и с памятью, которая выделила любая другая функция. Однако вызов функции VirtualProtect изменяет атрибуты доступа сразу у целой странице, а указатели, которые возвращают другие функции, не обязательно выравнены по границе страницы. Функция VirtualProtectEx подобна функции VirtualProtect, за исключение того, что она позволяет менять атрибуты доступа к памяти указанного процесса. Такие изменения атрибутов доступа обычно требуются отладчикам при доступе к памяти отлаживаемого процесса.
9. Использование инструментальной библиотеки Tool Help для ОС Windows Библиотека Tool Help для Windows Программа должна получать различную информацию о состоянии работающих на локальном компьютере приложений. Снимки системы В основе THL лежит понятие «snapshot» – мгновенного снимка состояния запущенных приложений. Перед вызовом всех функций библиотеки необходимо создать snapshot. Это осуществляется вызовом функции HANDLE WINAPI CreateToolhelp32Snapshot (DWORD dwFlags, DWORD th32ProcessID ); Параметр dwFlags указывает, какая именно информация интересует пользователя.
Параметр th32ProcessID идентифицирует процесс, состояние которого исследуется. Он необходим при использовании dwFlags со значениями TH32CS_SNAPHEAPLIST, TH32CS_SNAPMODULE и TH32CS_SNAP-THREAD. В остальных случаях этот параметр игнорируется.
Так, например, для получения списка модулей процесса dwProcessID необходим следующий вызов: hSnapshot = CreateToolhelp32Snapshot ( TH32CS_SNAPMODULE,dwProcessID ); Уничтожается объект snapshot стандартным вызовом CloseHandle( hSnapshot ); Все ошибки, возникающие при выполнении функций THL, возвращаются стандартным вызовом GetLast-Error и FormatMesssage.
Список процессов В примере используются две функции: BOOL WINAPI Process32First( HANDLE hSnapshot, LPPROCESSENTRY32 lppe ) и BOOL WINAPI Process32Next( HANDLE hSnapshot, LPPROCESSENTRY32 lppe ).
В обеих функциях два параметра. Первый – дескриптор, возвращаемый предыдущим вызовом CreateToolhelp-32Snapshot, а второй указывает на структуру PROCESSENTRY32, в которой возвращается результат выполнения функции. Перед вызовом Process32First необходимо установить в поле dwSize структуры PROCES-SENTRY32 значение, равное размеру самой структуры – sizeof(PROCES-SENTRY32), иначе функция вернет ошибку. Список модулей, загруженных процессом В процессе работы практически любого приложения Win32 загружаются те или иные библиотеки, компоненты и другие программные модули. Естественно, возникает желание получить список загруженных модулей. Для этого в THL также предусмотрен простой механизм.
В нем, в первую очередь, вызывается CreateToolhelp32Snapshot с параметрами TH32CS_SNAPMODULE и идентификатором процесса, модули которого нас интересуют. Далее, как и в предыдущем примере, в поле dwSize, но теперь уже структуры MODULEENTRY32, устанавливается значение, равное ее размеру. Кстати, это необходимо делать для всех функций перечисления THL. Цикл перебора ничем не отличается от рассмотренного в предыдущем примере. Разве что он использует структуру MODULEENTRY32, в которую возвращается информация о модуле.
Потоки процесса Механизм работы с потоками процесса идентичен механизму, описанному для модулей, только вызываются функции Thread32First и Thread32Next, а вместо структуры MODULEENTRY32 используется THREADENTRY32.
Доступ к памяти процесса Известно, что в Win32 получить доступ к памяти одного процесса из другого невозможно. Тем не менее в THL есть функция, позволяющая получить копию блока памяти другого процесса: BOOL WINAPI Toolhelp32Read ProcessMemory ( DWORD th32ProcessID, LPCVOID lpBaseAddress, LPVOID lpBuffer, DWORD cbRead, LPDWORD lpNumberOfBytesRead ); Параметры у этой замечательной функции следующие: th32ProcessID [in] Идентификатор процесса, блок памяти которого необходимо скопировать. Если этот параметр равен нулю, то копируется память из текущего процесса. lpBaseAddress [in] Адрес в адресном пространстве указанного процесса, начиная с которого копируется информация. Перед выполнением операционная система проверяет, вся ли указанная память доступна для чтения. Если это не так, возвращается FALSE. lpBuffer [out] Указатель на буфер, в который должны быть скопированы данные. cbRead [in] Размер буфера в байтах. lpNumberOfBytesRead [out] Количество скопированных байтов.
А как узнать, где в адресном пространстве процесса находятся данные? В самом общем случае на этот вопрос ответить невозможно. Но для динамически распределяемой памяти (heap) THL предоставляет функции, эту проблему решающие.
Исследование динамической памяти процесса Для выделения области в виртуальной памяти используется функция HeapCreate, которая создает соответствующий объект (heap) в адресном пространстве процесса. Для выделения памяти внутри этого блока используется функция HeapAlloc. Все остальные функции работы с динамической памятью (GlobalAlloc, malloc, calloc и т. д.) сводятся к использованию этого механизма, который мы не будем здесь подробно рассматривать.
Очевидно, что нужно уметь находить список выделенных областей виртуальной памяти и для каждого из них – список выделенных блоков. Посмотрим, как это делается с помощью функций THL. В терминах THL область памяти называется heap, множество областей памяти – heap list, а выделенному внутри нее блоку соответствует термин «block of a heap».
Первый цикл с помощью функций Heap32ListFirst и Heap32ListNext возвращает список блоков памяти, которые были распределены. Зная идентификатор процесса и идентификатор области виртуальной памяти, который возвращается в поле th32HeapID структуры HEAPLIST32, можно просмотреть, как распределяется память внутри этого блока. Выделенные области памяти можно получить с помощью функций Heap32First и Heap32-Next. Они возвращают структуру HEAPENTRY32.
Зная значения полей dwAddress и dwBlockSize, с помощью функции Toolhelp32ReadProcessMemory нетрудно получить данные, находящиеся в динамической памяти процесса.
________________________________________ Значения параметра dwFlags-функции. CreateToolhelp32Snapshot.
TH32CS_INHERIT показывает, что snapshot был унаследован.
TH32CS_SNAPHEAPLIST получает список блоков динамически распределенной памяти в адресном пространстве процесса.
TH32CS_SNAPMODULE получает список модулей, загруженных процессом.
TH32CS_SNAPPROCESS получает список запущенных на локальном компьютере процессов.
TH32CS_SNAPTHREAD получает список потоков процесса.
TH32CS_SNAPALL включает в себя предыдущие четыре флага, т. е. snapshot будет содержать списки процессов, потоков, модулей и областей динамической памяти.
________________________________________ Описание полей структуры MODULEENTRY32.
DWORD dwSize размер структуры в байтах DWORD th32ModuleID ID модуля DWORD th32ProcessID ID процесса модуля DWORD GlblcntUsage общее для системы количество обращений к модулю DWORD ProccntUsage количество обращений к модулю, сделанных из текущего процесса BYTE * modBaseAddr адрес модуля в адресном пространстве процесса DWORD modBaseSize размер модуля HMODULE hModule дескриптор модуля в контексте процесса TCHAR szModule [MAX_MODULE_NAME32 + 1] имя модуля TCHAR szExePath[MAX_PATH] полный путь к файлу ________________________________________ Описание полей структуры HEAPENTRY32.
SIZE_T dwSize размер структуры HEAPENTRY32 в байтах.
HANDLE hHandle дескриптор блока памяти в адресном пространстве процесса.
ULONG_PTR dwAddress адрес начала блока памяти.
SIZE_T dwBlockSize размер блока памяти.; DWORD dwFlags флаги, описывающие область памяти. Этот параметр может принимать следующие значения: LF32_FIXED область памяти не может быть перемещена операционной системой; LF32_FREE блок памяти не используется; LF32_MOVEABLE область памяти выделена и может перемещаться.
DWORD dwLockCount количество вызовов функции GlobalLock (в Win32 LocalLock синоним функции GlobalLock), которые были сделаны для этого блока памяти.
DWORD dwResvd зарезервировано.
DWORD th32ProcessID ID процесса, в контексте которого выделена память.
ULONG_PTR th32HeapID идентификатор блока памяти, выделенного функцией HeapCreate.


10. Реализация менеджера виртуальных столов для ОС Windows.
Разработать программу, которая создает несколько рабочих столов и предоставляет возможность переключаться между ними.
Создание, удаление, переключение Существует множество программ, создающих виртуальные рабочие столы и работающие как в Windows NT, так и в Win9x. Такие программы прибегают к различным ухищрениям, например, скрывают окна программ,находящихся на "другом рабочем столе". Но в Windows NT существует стандартный способ создания рабочих столов, который мы и рассмотрим.
Создадим рабочий стол "NewDesktop".
THandle hDesktop: ; (или HDESK) {...} hDesktop=CreateDesktop('NewDesktop',null,null,DF_ALLOWOTHERACCOUNTHOOK, DESKTOP_CREATEMENU + DESKTOP_CREATEWINDOW + DESKTOP_ENUMERATE + DESKTOP_HOOKCONTROL + DESKTOP_READOBJECTS + DESKTOP_SWITCHDESKTOP + DESKTOP_WRITEOBJECTS,null); if hDesktop<>0 then Рабочий стол создан else ошибка; Далее на созданном столе надо запустить оболочку (shell). По умолчанию оболочкой у нас будет являться explorer.exe. Его мы и запустим.
var _PROCESS_INFORMATION; _STARTUPINFOA si; {...} Запуск программы с помощью CreateProcess.
FillMemory( @si, sizeof( si ), 0 ); si.cb = sizeof( si ); si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_SHOWMAXIMIZED; Но запускаем программу не на обычном рабочем столе, а на вновь созданом Si.lpDesktop = PChar('Winsta0\NewDesktop'); CreateProcess(null,'explorer.exe',null,null,false,NORMAL_PRIORITY_CLASS,null,null,Si,pi); Вообще-то вместо explorer.exe лучше запускать userinit.exe. Эта программа запускает оболочку.
Теперь у нас на новом рабочем столе запущен shell и можно переключаться на новый рабочий стол (на него можно переключаться и без запуска программы, но смотреть там нечего :)) Переключение производится функцией SwitchDesktop.
if SwitchDesktop(hDesktop) then переключились на новый рабочий стол else ошибка; но переключиться обратно мы не сможем, если не запустим на этом столе другую программу , которая бы переключила нас на "родной" десктоп. Но об этом позже, а пока сделаем так: Sleep(10000); HDesk hOldDesktop; И через 10 секунд переключимся назад. Для этого нам нужен дескриптор "Winsta0\Default". Но где его взять? А получить его можно 2 способами: 1) Т.к. наш потом был запущен на "родном"("Winsta0\Default") столе, то можно вызвать функцию GetThreadDesktop: hOldDesktop = GetThreadDesktop(GetCurrentThreadId); 2) Нам известно название первоначального рабочего стола - "Default". Выполняем OpenDesktop: hOldDesktop = OpenDesktop('Default', DF_ALLOWOTHERACCOUNTHOOK, false, DESKTOP_CREATEMENU, DESKTOP_CREATEWINDOW, DESKTOP_ENUMERATE, DESKTOP_HOOKCONTROL, DESKTOP_JOURNALPLAYBACK, DESKTOP_JOURNALRECORD, DESKTOP_READOBJECTS, DESKTOP_SWITCHDESKTOP, DESKTOP_WRITEOBJECTS); if hOldDesktop<>0 then Все отлично else Ошибка; Перед переключением выведем например сообщение об этом. Просто MessageBox выведет сообщение на старый рабочий стол и мы его не увидим :(. Поэтому сделаем так: Переключим вывод на новый рабочий стол: SetThreadDesktop(hDesktop); Для удачного выполнения этой функции у нашего потока не должно быть открыто никаких окон. Если окна есть, то или закрываем их или создаем новый поток. Итак, функция выполнилась удачно. Теперь посылаем сообщние MessageBox(0,'Переключение рабочего стола','Hello',mb_ok); Окошко должно вывестись на видимом рабочем столе! Т.к. окно не модальное, то дадим пользователю еще 10 секунд и после этого переключим его на старый рабочий стол.
Sleep(10000); За это время желательно, чтобы пользователь нажал на OK в сообщении - оставлять окна на убиваемом рабочем столе - плохая примета :) SetThreadDesktop(hOldDesktop); SwitchDesktop(hOldDesktop); Теперь завершаем explorer на NewDesktop и закрываем этот рабочий стол.
TerminateProcess(pi.hProcess,1); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); if CloseDesktop(hDesktop) then закрыли рабочий стол else ошибка; Ну и стоит удалить дескриптор hOldDesktop CloseHandle(hOldDesktop); 11. Реализация программного средства отображения информации о конфигурации компьютера
Разработать программу, которая отображает следующие сведения о конфигурации компьютера.
Программа должна отображать основные сведения о конфигурации компьютера по следующим позициям: 1. Процессор 2. Память 3. Видео 4. Накопители 5. Устройства ввода 6. Сетевая информация 7. Операционная система 8. Системная информация Процессор – информация о названии процессора, его типе, тактовой частоте, поддерживаемых инструкциях.
Память – информация о занятости памяти, полном и доступном объеме физической и виртуальной памяти.
Видео – информация о типе и драйвере видеокарты, типе монитора, разрешении экрана, цветовой палитре, частоте обновления.
Накопители – информация о всех присутствующих накопителях (жестких дисках, CDROM, и т.д.).
Устройства ввода – информация об устройствах ввода (клавиатура, мышь).
Сетевая информация – информация о сетевом имени компьютера и его IP-адресе.
Операционная система – информация о типе операционной системы установленной на компьютере.
Системная информация – информация об имени компьютера, текущем пользователе, системном и Windows каталогах.
Внешний вид программы может быть представлен следующим образом:



Рис 10 Внешний вид программы.
В левой части главного окна находятся кнопки. Надписи на кнопках указывают на ту информацию, которая будет выведена при нажатии на кнопку. В нижнем левом углу находится кнопка выход. Нажатие на нее приводит к завершению программы.
В правой части главного окна находится область, куда выводится вся информация. Текст из этой области может быть скопирован в буфет обмена. При необходимости, в правой стороне этой области автоматически появляется полоса прокрутки.
Интерфейс программы написан с использованием Win32 API. Рассмотрим основные функции: Функция DlgProc - функция инициализации окна.Сообщение WM_INITDIALOG приводит к инициализации диалогового окна на котором размещены все необходимые элементы. Сообщение WM_COMMAND посылается оконной процедуре всеми стандартными элементами (в нашем случае – кнопками). В элементе wParam посылаемых сообщений хранится информация достаточная для того, чтобы программа смогла определить, какие действия ей необходимо выполнить при нажатии той или иной кнопки.
Функция GetSysInfo - предназначена для получения системной информации, а именно: имени компьютера, имени текущего пользователя, системного и Windows каталога.
Всю эту информацию возвращают стандартные функции Win32: GetComputerName – функция возвращающая имя компьютера.
GetUserName – функция возвращающая имя текущего пользователя.
GetSystemDirectory – функция возвращающая имя системного каталога.
GetWindowsDirectory – функция возвращающая имя каталога в который установлена операционная система.
Вся информация сохраняется в строке Info. В дальнейшем стандартная функция SendMessage посылает элементу Edit (данный элемент непосредственно выводит информацию в окне) сообщение WM_SETTEXT и с ним передает строку Info.
Функция GetCPUInfo - служит для получения информации о процессоре, а именно: типе процессора, его тактовой частоты, поддерживаемых инструкциях. Информацию об имени, типе процессора, а также его тактовой частоте программа берет из реестра Windows. Для этого при помощи Win32 функции (в дальнейшем все стандартные Win32 функции будут помечены знаком ) RegOpenKeyEx*. Далее при помощи функции RegQueryValueEx* проводится выборка значений по следующим ключам: - ProcessorNameString – имя процессора - Identifier – тип процессора - ~Mhz – частота процессора Для определения поддерживаемых инструкций используется функция IsProcessorFeaturePresent*. Это логическая функция, которая возвращает значение true при поддержки процессором данной инструкции. Используются следующие входные параметры: - PF_MMX_INSTRUCTIONS_AVAILABLE – поддержка инструкций MMX - PF_XMMI_INSTRUCTIONS_AVAILABLE – поддержка инструкций SSE Как и в предыдущей функции, вся полученная информация сохраняется в строке Info, которая потом передается элементу Edit при помощи функции SendMessage*.
Функция GetMemoryStatus - предназначена для получения информации о памяти, а именно: занятости памяти, полном и доступном объеме физической и виртуальной памяти. Всю эту информацию возвращает функция GlobalMemoryStatus* параметром которой является указатель на структуру MEMORYSTATUS. В результате поля структуры будут содержать следующую информацию: - dwMemoryLoad – процент занятости физической памяти - dwTotalPhys – полный объем физической памяти (в байтах) - dwAvailPhys – объем доступной физической памяти (в байтах) - dwTotalVirtual – полный объем виртуальной памяти (в байтах) - dwAvailVirtual – доступный объем виртуальной памяти (в байтах) Как и в предыдущей функции, вся полученная информация сохраняется в строке Info, которая потом передается элементу Edit при помощи функции SendMessage*.
Функция GetInpDev - предназначена для получения информации об устройствах ввода, а именно о клавиатуре и мыши.Информация о клавиатуре программа получает с помощью функции GetKeyboardType*, результатом которой является значение, в зависимости от которого определяется тип клавиатуры.Информацию о мыши дает функция GetSystemMetrics () с входным параметром SM_CMOUSEBUTTONS. В результате, функция возвращает количество кнопок мыши, либо значение 0, если мышь не подключена.
Bся полученная информация сохраняется в строке Info, которая потом передается элементу Edit при помощи функции SendMessage*.
Функция GetWinVer - предназначена для получения информации об операционной системе установленной на компьютере.Всю необходимую информацию для определения операционной системы возвращает функция GetVersionEx*, параметром которой является указатель на структуру OSVERSIONINFOEX. В результате поле dwMajorVersion в сочетании с полем dwMinorVersion структуры дают возможность определить тип операционной системы. Поле wServicePackMajor содержит информацию об установленных Service Pack’ах, а поле dwBuildNumber – номер сборки ОС.
Вся полученная информация сохраняется в строке Info, которая потом передается элементу Edit при помощи функции SendMessage*.
Функция GetDisks - предназначена для получения информации о всех присутствующих в системе накопителях (жестких дисках, CDROM, и т.д.) их типах и т.д.Для определения имен дисков используется функция GetLogicalDrives* результатом которой является переменная типа DWORD. Далее используя побитовые сдвиги и накладывая битовую маску получаем информацию о присутствии того, или иного имени в системе (допустим если значение переменной равно 000…00011101, то это означает что в системе присутствуют диски A, C, D, E).
Для определения типа диска используется функция GetDriveType* входным параметром которой является имя диска, а в зависимости от значения, которое вернула функция определяется тип диска. Функция GetDriveType* может вернуть следующие значения: - DRIVE_UNKNOWN – тип диска неизвестен - DRIVE_FIXED – жесткий диск - DRIVE_CDROM – CDROM - DRIVE_REMOVABLE – съемный накопитель - DRIVE_REMOTE – съемный диск - DRIVE_RAMDISK – RAM диск Информация об имени диска, типе файловой системы, метке тома определяется при помощи функции GetVolumeInformation*, а информация об общем объеме диска, свободном и занятом пространстве при помощи GetDiskFreeSpaceEx*. Надо отметить ту особенность, что функция GetDiskFreeSpaceEx* возвращает значения объема диска, свободного и занятого пространства в байтах, поэтому для хранения таких больших чисел используется тип __int64 (64-бита).
Вся полученная информация сохраняется в строке Info, которая потом передается элементу Edit при помощи функции SendMessage*.
Функция GetNetInfo - предназначена для получения сетевой информации, а именно: сетевого имени компьютера и IP-адреса. Сетевое имя компьютера получаем при использовании функции GetHostName*, а IP-адрес при использовании GetHostByName. Входным параметром этой функции служит сетевое имя компьютера, а выходным структура HOSTENT, которая в списке h_addr_list содержит все IP-адреса компьютера.
Вся полученная информация сохраняется в строке Info, которая потом передается элементу Edit при помощи функции SendMessage*.
Функция GetVideo - предназначена для получения информация о типе и драйвере видеокарты, типе монитора, разрешении экрана, цветовой палитре, частоте обновления. Для получения информации о типе видеокарты и монитора использовалась функция EnumDisplayDevices*. В результате выполнения функции получаем структуру DISPLAY_DEVICE которая, в зависимости от входных параметров, в поле DeviceString содержит тип видеокарты, или монитора.Информацию о драйвере видеокарты, разрешении экрана, цветовой гамме и частоте обновления дает функция EnumDisplaySettings, в результате выполнения которой получаем структуру DEVMODE. Поля данной структуры будут содержать следующую информацию: dmDeviceName – информация о драйвере видеокарты dmPelsWidth – ширина экрана (в пикселях) dmPelsHeight – высота экрана (в пикселях) dmBitsPerPel – количество бит цвета на один пиксель dmDisplayFrequency – частота обновления (в герцах) Вся полученная информация сохраняется в строке Info, которая потом передается элементу Edit при помощи функции SendMessage*.
12. Использование механизма почтовых ящиков в ОС Windows.
MailSlots. Разработать программу-сервер и программу клиент для обмена сообщениями между двумя компьютерами при помощи почтовых слотов. Клиент посылает серверу запрос на выполнение одной из команд: DIR, MKDIR, CD. Сервер принимает команду, выполняет ее, а результат отправляет клиенту.
Почтовые слоты (mailslots) — это механизм односторонней пересылки данных между процессами по сети. Почтовые слоты по своим свойствам отличаются от каналов.
Через почтовые слоты можно посылать только не слишком важные данные, потеря или запаздывание которых не приносит особого вреда.
Например, их можно использовать для циркулярной рассылки кодов обновления состояния какого-нибудь процесса через каждые пять минут. Если эти данные однажды случайно не попадут к одному из пользователей, ничего страшного не случится, а вот в случае посылки таких данных, как учетные транзакции, это совершенно неприемлемо.
Любой процесс, который создает почтовый слот для приема данных, называется сервером слота. Даже если само по себе приложение является клиентом и получает данные от приложения-сервера, по отношению к созданному почтовому слоту оно представляет собой сервер. Для данного слота любой компьютер сети может быть сервером, но читать из слота данные (или обращаться к нему другими способами, т.е. через наследование) может только процесс, который его создал.
Всякий процесс, которому известно имя слота, может посылать ему данные. Процессы, которые посылают данные на почтовый слот, называются клиентами слота.
Для создания слота в приложениях используется функция CreateMailSlot. Ее первый параметр — это указатель на ASCII-строку, содержащую имя создаваемого почтового слота. Слоты создаются только на локальном компьютере, поэтому полное имя слота выглядит следующим образом:

\\ .\mailslot\[Путь]Имя.


В именах почтовых слотов поддерживается псевдокаталоговая структура. Для лучшей организации почтовых слотов в их именах можно указывать пути в каталогах.
Функция CreateMailslot также принимает в качестве параметров максимальный размер сообщений, время задержки для операций чтения и необязательную защитную структуру. Вместо значения задержки можно указать константу для режима для блокирования операций чтения на слоте до получения сообщения без ограничения времени.
Если функция CreateMailslot завершается успешно, она возвращает ключ для нового слота.
Для изменения времени задержки операций чтения после создания слота используется функция SetMailslot. Кроме того, для получения такой информации о слоте, как максимальный размер сообщения, размер следующего сообщения в очереди и количество сообщений в очереди, можно использовать функцию GetMailslotInfo.
Для чтения из слота используется функция ReadFile, которая завершает свою работу после получения сообщения, независимо от того, сколько байтов необходимо прочитать.
Кроме того, с помощью функции GetMailslotInfo можно узнать количество сообщений, ожидающих в очереди слота, и размер следующего сообщения.
Для записи сообщения в слот вначале необходимо открыть его ключ с помощью функции CreateFile, а затем воспользоваться функцией WriteFile для посылки сообщения. Ключ слота закрывается функцией CloseHandle. При вызове CreateFile необходимо указать имя слота, которому посылается сообщение. Указанное имя допускает циркулярную рассылку данных всем слотам с такими же именами на компьютерах домена.
Для локального компьютера имя слота выглядит следующим образом:

\\ .\mailslot\[Путь]Имя

Для удаленного компьютера имя слота имеет следующий вид:

\\ИмяУдаленногоКомпьютера\mailslot\[Путь]Имя

Для рассылки сообщения всем слотам с одинаковыми именами на компьютерах домена необходимо указать следующее имя:

\\ИмяДомена\mailslot\[Путь]Имя

Для рассылки сообщения всем компьютерам в домене более высокого иерархического уровня используется следующее имя:

\\*\mailslot\[Путь]Имя

После успешного завершения функции CreateFile ключ, который она возвращает, можно использовать в функции WriteFile для посылки сообщений на слот.
По окончании работы с почтовым слотом его необходимо закрыть вызовом функции CloseHandle для освобождения ассоциированных с ним системных ресурсов.
По завершении процесса все ключи слотов, ассоциированных с процессом, закрываются автоматически. После их закрытия почтовый слот уничтожается, а все данные в его буфере теряются.
13. Использование механизма именованных каналов в ОС Windows.
Pipes. Разработать программу-сервер и программу клиент для обмена сообщениями между двумя компьютерами при помощи именованных каналов. Клиент посылает серверу запрос на выполнение одной из команд: DIR, MKDIR, CD. Сервер принимает команду, выполняет ее, а результат отправляет клиенту.
Именованные каналы PIPE используются для гарантированной передачи данных по сети. Создать именованный канал можно только на NT, в операционной среде Windows 95 можно использовать именованный канал только со стороны клиента. Поэтому для проверки данных примеров вам нужен NT. Можно сказать, что это выделенная линия для обмена данными между процессами. В NT можно посмотреть подобные выделенные линии. То есть их количество. Зайдите в Control Panel, выберите Server и щелкните на нем. Появится окно как ниже:



Пункт Open Named Pipes может быть и не такой. Дело в том, что данным механизмом пользуются многие серьезные приложения, например, MS SQL Server. Cоздадим две простые консольные программы, которые будут эмулировать клиента и сервера. Итак сервер: // CreateNamedPipe.cpp : Defines the entry point for the console application.
// #include "stdafx.h" #include "windows.h" #include "iostream.h"

void main() { HANDLE hp; hp=CreateNamedPipe("\\\\.\\pipe\\ipctest",PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE | PIPE_NOWAIT,1,0,0,NMPWAIT_USE_DEFAULT_WAIT,NULL); if (hp!=INVALID_HANDLE_VALUE) { int i; cin >> i; } else cout << "Error Create Name Pipe " << endl; } А теперь клиент: // CreateFile.cpp : Defines the entry point for the console application.
// #include "stdafx.h" #include "windows.h" #include "iostream.h"

void main() { HANDLE hp; hp=CreateFile("\\\\Server\\pipe\\ipctest", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hp!=INVALID_HANDLE_VALUE) { int i; cin >> i; } else cout << "Error pipe" << endl; } Как видите для создание канала надо вызвать функцию CreateNamedPipe, а для клиента создать файл указав сервер Server. Вы должны указывать свой сервер. То есть его имя в домене. А имя \\pipe\\ipctest должно совпадать и в клиенте и в сервере. Это имя канала. Вот после запуска прогаммы видно, что количество именованных каналов увеличилось на единицу.



14. Разработка приложения для мониторинга состояния SMART регистров жесткого диска
Windows - приложение для мониторинга состояния SMART регистров жесткого диска. Разработать консольное Windows-приложение для мониторинга состояния SMART регистровжесткого диска. Приложение выводит список всех дисковых устройств в системе и выдает полную информацию об указанном жестком диске как устройстве, его идентификационные данные, модель, состояние SMART регистров и т.д.


15. Разработка приложения для графического представления файловой системы
Оконное Windows-приложение, которое позволяет построить графическую карту раздела диска, посредством которой можно определить какой файл, где находится (какие кластеры занимает). Необходимо разработать оконное Windows-приложение аналогичное Sysinternals DiskView.
16. Разработка приложения для криптографической защиты файлов и каталогов Windows-приложение для криптографической защиты файлов и каталогов с использованием алгоритма AES. Необходимо разработать консольное Windows-приложение, которое позволяет генерировать ключи, зашифровывать и расшифровывать с помощью алгоритма AES файлы и каталоги файловой системы. Доступ к секретному ключу (в файле контейнере), следует организовать посредством пароля. Криптографические преобразования выполнять посредством криптопровайдера Microsoft Windows CSP.