vazhnoe


1. Модель программного интерфейса операционной системы Windows. Нотация программного интерфейса. Понятие объекта ядра и описателя объекта ядра операционной системы Windows. Модель архитектуры ОС Windows.
Интерфейс прикладного программирования Windows API (application programming interface) является интерфейсом системного программирования в пользовательском режиме для семейства операционных систем Windows.
API - набор готовых классов, процедур, функций, структур и констант, предоставляемых приложением (библиотекой, сервисом) для использования во внешних программных продуктах.
API определяет функциональность, которую предоставляет программа (модуль, библиотека), при этом API позволяет абстрагироваться от того, как именно эта функциональность реализована.
Программные компоненты взаимодействуют друг с другом посредством API. При этом обычно компоненты образуют иерархию — высокоуровневые компоненты используют API низкоуровневых компонентов, а те, в свою очередь, используют API ещё более низкоуровневых компонентов.
n  Процедурный API. Единая точка доступа к службе – за вызовом процедуры стоит программное прерывание.
n  Объектный подход. Отсутствие указателей на внутренние структуры данных ОС. Применение описателей (дескрипторов) вместо указателей.
n  «Венгерская» нотация в идентификаторах.
Суть венгерской нотации сводится к тому, что имена идентификаторов предваряются заранее оговорёнными префиксами, состоящими из одного или нескольких символов. При этом, как правило, ни само наличие префиксов, ни их написание не являются требованием языков программирования, и у каждого программиста (или коллектива программистов) они могут быть своими. 
Понятие объекта ядра и описателя объекта ядра операционной системы Windows.
Система позволяет создавать и оперировать с несколькими типами объектов ядра, в том числе: маркерами доступа (access token objects), файлами (file objects), проекциями файлов (file-mapping objects), портами завершения ввода-вывода (I/O completion port objects), заданиями (job objects), почтовыми ящиками (mailslot objects), мьютексами (mutex objects), каналами (pipe objects), процессами (process objects), семафорами (semaphore objects), потоками (thread objects) и ожидаемыми таймерами (waitable timer objects). Эти объекты создаются Windows-функциями. Каждый объект ядра — на самом деле просто блок памяти, выделенный ядром и доступный только ему. Этот блок представляет собой структуру данных, в элементах которой содержится информация об объекте. Некоторые элементы (дескриптор защиты, счетчик числа пользователей и др.) присутствуют во всех объектах, но большая их часть специфична для объектов конкретного типа. Например, у объекта «процесс» есть идентификатор, базовый приоритет и
код завершения, а у объекта «файл» — смещение в байтах, режим разделения и режим открытия. Поскольку структуры объектов ядра доступны только ядру, приложение не может самостоятельно найти эти структуры в памяти и напрямую модифицировать их содержимое. Такое ограничение Microsoft ввела намеренно, чтобы ни одна программа не нарушила целостность структур объектов ядра. Это же ограничение позволяет Microsoft вводить, убирать или изменять элементы структур, не нарушая работы каких-либо приложений. Но вот вопрос: если мы не можем напрямую модифицировать эти структуры, то как же наши приложения оперируют с объектами ядра? Ответ в том, что в Windows  предусмотрен набор функций, обрабатывающих структуры объектов ядра по строго определенным правилам. Мы получаем доступ к объектам ядра только через эти функции. Когда Вы вызываете функцию, создающую объект ядра, она возвращает описатель, идентифицирующий созданный объект. Описатель следует рассматривать как «непрозрачное» значение, которое может быть использовано любым потоком Вашего процесса. Этот описатель Вы передаете Windows-функциям, сообщая системе, какой объект ядра Вас интересует.
В Windows входят следующие компоненты, работающие в режиме ядра: 1.        Исполняющая система 2.      Ядро Windows 3.        драйверам устройств  4.        Уровень аппаратных абстракций 5.        Система организации многооконного интерфейса и графики,
2. Понятие пользовательского режима и режима ядра операционной системы Windows. Модель виртуальной памяти процесса в пользовательском режиме и в режиме ядра операционной системы Windows. Архитектура приложения в пользовательском режиме работы и в режиме ядра ОС Windows. Основные модули ОС Windows. 
Чтобы защитить жизненно важные системные данные от доступа и (или) внесения изменений со стороны пользовательских приложений, в Windows используются два процессорных режима доступа (даже если процессор, на котором работает Windows, поддерживает более двух режимов): пользовательский режим и режим ядра. Код пользовательского приложения запускается в пользовательском режиме, а код операционной системы (например, системные службы и драйверы устройств) запускается в режиме ядра. Режим ядра — такой режим работы процессора, в котором предоставляется доступ ко всей системной памяти и ко всем инструкциям центрального процессора. Предоставляя программному обеспечению операционной системы более высокий уровень привилегий, нежели прикладному программному обеспечению, процессор гарантирует, что приложения с неправильным поведением не смогут в целом нарушить стабильность работы системы. Хотя у каждого Windows-процесса есть свое собственное закрытое адресное пространство, код операционной системы и код драйвера устройства, используют одно и то же общее виртуальное адресное пространство. Каждая страница в виртуальной памяти имеет пометку, показывающую, в каком режиме доступа должен быть процессор для чтения и (или) записи страницы. Доступ к страницам в системном пространстве может быть осуществлен только из режима ядра, тогда как доступ ко всем страницам в пользовательском адресном пространстве может быть осуществлен из пользовательского режима 
Виртуальная память
В Windows реализована система виртуальной памяти, которая образует плоское (линейное) адресное пространство. Она создает каждому процессу иллюзию того, что у него есть достаточно большое и закрытое от других процессов адресное пространство. Виртуальная память дает логическое представление, которое не обязательно соответствует структуре физической памяти. В период выполнения диспетчер памяти, используя аппаратную поддержку, транслирует, или проецирует (maps), виртуальные адреса на физические, по которым реально хранятся данные.
Размер виртуального адресного пространства зависит от конкретной аппаратной платформы. На 32-разрядных системах теоретический максимум для общего виртуального адресного пространства составляет 4 Гб. По умолчанию Windows выделяет нижнюю половину этого пространства (в диапазоне адресов от x00000000 к x7FFFFFFF) процессам, а вторую половину (в диапазоне адресов от x80000000 к xFFFFFFFF) использует в своих целях
 
Виртуальная память процесса:
От 2 ГБ до 2 ТБ.
Кратна 64 КБ – гранулярность памяти пользовательского режима. Информацию о гранулярности можно получить с помощью GetSystemInfo().
Часть виртуальной памяти процесса, которая находится резидентно в физической памяти, называется рабочим набором – Working Set. Диапазон рабочего набора устанавливается функцией SetProcessWorkingSetSize(). Стандартный минимальный рабочий набор – 50 страниц по 4 КБ (200 КБ), стандартный максимальный рабочий набор – 345 страниц по 4 КБ (1380 КБ).
Архитектура приложения в пользовательском режиме работы и в режиме ядра ОС Windows. Основные модули ОС Windows.

3. Системный реестр операционной системы Windows. Структура и главные разделы. Точки автозапуска программ. Средства редактирования реестра Windows. Функции работы с реестром из приложения.
Реестр Windows— иерархически построенная база данных параметров и настроек, состоящая из ульев.
В Windows элементы реестра хранятся в виде раздельных структур. Реестр подразделяется на составные части, которые разработчики этой операционной системы назвали ульями (hives) по аналогии с ячеистой структурой пчелиного улья. Улей представляет собой совокупность вложенных ключей и параметров, берущую начало в вершине иерархии реестра. Отличие ульев от других групп ключей состоит в том, что они являются постоянными компонентами реестра. Ульи не создаются динамически при загрузке операционной системы и не удаляются при ее остановке.
Реестр содержит данные, к которым Windows постоянно обращается во время загрузки, работы и её завершения, а именно:
·         профили всех пользователей, то есть их настройки;
·         конфигурация оборудования, установленного в операционной системе.
·         данные об установленных программах и типах документов, создаваемых каждой программой;
·         свойства папок и значков программ;
·         данные об используемых портах.
Корневой раздел HKCU содержит данные, относящиеся к персональным настройкам и программной конфигурации локально вошедшего в систему пользователя.
Он указывает на пользовательский профиль текущего вошедшего в систему
пользователя, находящийся на жестком диске в файле \Users\<имя_пользователя>\Ntuser.dat
Внутреннее устройство реестра Кусты
На диске реестр не является обычным большим файлом, а представляет собой набор отдельных файлов, которые называются кустами. Каждый куст содержит дерево реестра, у которого есть раздел, служащий ему корнем или отправной точкой дерева. Подразделы и их параметры находятся ниже корня. Можно подумать, что корневые разделы, отображаемые в редакторе реестра, соответствуют корневым разделам в кустах, но так бывает не всегда. Путевые имена всех кустов, за исключением тех, которые используются для профилей пользователей, кодируются в диспетчере конфигурации. По мере того как диспетчер конфигурации загружает кусты, включая профили системы, он записывает путь к каждому кусту в параметрах подраздела HKLM\SYSTEM\CurrentControlSet\Control\Hivelist, удаляя путь при выгрузке куста. Он создает корневые разделы, связывает эти кусты вместе, чтобы построить структуру реестра, с которой вы знакомы и которая показывается редактором реестра.
Вы заметите, что некоторые из этих кустов, перечисленные в табл. 4.5, могут изменяться и не имеют связанных с ними файлов. Система создает эти кусты и управляет ими целиком в памяти, поэтому такие кусты являютсявременными.
Система создает непостоянные кусты при каждой своей загрузке. В качестве примера непостоянного куста можно привести HKLM\HARDWARE, в котором хранится информация о физических устройствах и выделенных этим устройствам ресурсах. Выделение ресурсов и определение установленного оборудования проводятся при каждой загрузке системы, поэтому хранить эти данные на диске
было бы нелогично. 
Средства редактирования: regedit.exe, reg.exe.
regedit.exe – редактор реестра (в виде проводника).
reg.exe - редактирования системного реестра из командной строки.
Одна из многих возможностей реестра – это возможность задать автозапуск программ при старте ОС. Можно сделать автозапуск как для одного пользователя, так и для всех.
Функции для работы с реестром
Нашел ряд функций-членов класса CWinApp для работы среестром: SetRegistryKey, GetProfileInt,GetProfileString, WriteProfileInt, WriteProfileString.
4. Понятие окна в ОС Windows. Основные элементы окна. Понятие родительского и дочернего окна. Структура программы с событийным управлением. Минимальная программа для ОС Windows с окном на экране. Создание и отображение окна.
 
Понятие окна в ОС Windows.
Окно — графически выделенная часть экрана, принадлежащая какому-либо объекту, с которым работает пользователь. Окна могут иметь как произвольные, так и фиксированные (это характерно для диалоговых окон) размеры. Окно может занимать весь экран или только его часть. При этом на экране может быть одновременно выведено несколько (любое количество) окон.
Понятие родительского и дочернего окна.
Каждое окно, создаваемое приложением, имеет родительское окно. При этом само оно по отношению к родительскому является дочерним. Какое окно является "основателем рода", т. е. родительским для всех остальных окон? Окна всех приложений располагаются в окне, представляющем собой поверхность рабочего стола Workplace Shell . Это окно, которое называется Desktop Window , создается автоматически при запуске операционной системы. Однако окно Desktop Window само по себе является дочерним по отношению к другому окну - окну Object Window . Это окно не отображается и используется системой Presentation Manager для собственных нужд. 
 
Отображение окна:
Сперва мы вызываем функцию ShowWindow и передаем ей дескриптор только что созданного окна, чтобы Windows знала, какое окно должно быть показано. Мы также передаем число, определяющее в каком виде будет показано окно (обычным, свернутым, развернутым на весь экран и т.д.). После отображения окна мы должны обновить его. Это делает функция UpdateWindow; она получает один аргумент, являющийся дескриптором обновляемого окна.
ShowWindow(MainWindowHandle, show);
UpdateWindow(MainWindowHandle);
5. Структура программы с событийным управлением. Структура события – оконного сообщения Windows. Очередь сообщений. Цикл приема и обработки сообщений. Процедура обработки сообщений. Процедуры посылки сообщений. Синхронные и асинхронные сообщения.
Источники сообщений:
Пользователь генерирует сообщения воздействуя на внешние устройства(мышь…); cама ОС посылает сообщения для уведомления ПО о событиях; Программа может вызывать функции ОС, результатом которой может являться посылка сообщения ПО; ПО может посылать сообщение самой себе; ПО может посылать сообщения другим прикладным программам
Оконная функция обрабатывает WM_DESTROY. Сообщение вызывается в результате функции DestroyWindow(). Эту функцию вызывает ОС. Если сообщение WM_DESTROY обрабатывается в главной оконной функции программы, то необходимо вызвать функцию:VOID PostQuitMessage(int exitCode), которая генерирует WM_QUIT.
Все необработанные оконной функцией сообщения должны быть обработаны стандартной оконной функцией, вызываемой по умолчанию LRESULT DefWindwProc(HWND hWnd, UINT message).
Для посылки сообщений из программы существуют следующие функции:
PostQuitMessage(int);
BOOL PostMessage(HWND, UINT, WPARAM, LPARAM); Помещает сообщение в очередь прикладной программы и возвращает управление не дожидаясь его обработки. Такое сообщение будет обработано при подходе очереди. TRUE - сообщение успешно поставлено в очередь.
LRESULT SendMessage(HWND, UINT, WPARAM, LPARAM); Она фактически вызывает оконную функцию, дожидается ее выполнения и возвращает значение, которое вернула оконная функция.
События, поступающие от внешнего устройства, обрабатываются драйвером и помещаются в очередь. Далее они распределяются по приложениям. Для каждого приложения ОС организует прикладную очередь. В процессе распределения сообщений по прикладным очередям ОС извлекает очередное приложение системной очереди, определяет с каким окном связано это сообщение, помещает это сообщение в очередь того приложения, которому принадлежит окно. Для клавиатурных сообщений и сообщений от мыши является разным. Только одно окно в данный момент времени может получать сообщение от клавиатуры. Принято говорить, что это окно имеет фокус ввода. Приложение, окно которого имеет фокус ввода – активное. Сообщения от клавиатуры помещаются в очередь активного приложения. Сообщения от мыши обрабатываются по-другому. Они помещаются в очередь того приложения, в окне которого находится указатель мыши. Сообщения передаются приложению, а обрабатываются оконными функциями приложения. Часто говорят, что сообщения передаются окнам и обрабатываются окнами.
Синхронными сообщениями называются сообщения, которые Windows помещает в очередь сообщений приложения. Такие сообщения извлекаются и диспетчеризуются в цикле обработки сообщений. , к ним относятся сообщения о событиях пользовательского ввода, таких как нажатие клавиш (WM_KEYDOWN и WM_KEYUP), перемещение мыши (WM_M0USEM0VE) или щелчок левой кнопкой мыши (WM_LBUTT0ND0WN). Асинхронные сообщения передаются непосредственно окну, когда Windows вызывает оконную процедуру. Остальные сообщения, как правило, являются асинхронными. Приложение также может послать асинхронное сообщение, вызвав функцию SendMessage.
6. Ввод данных с манипулятора «мышь». Обработка сообщений мыши. Ввод данных с клавиатуры. Понятие фокуса ввода. Обработка сообщений от клавиатуры.
При каждом нажатии и отпускании левой кнопки мыши ОС посылает программе сообщение WM_LBUTTONDOWN и WM_LBUTTONUP. При перемещении мыши ОС помещает в очередь сообщение WM_MOUSEMOVE. Если в оконном классе окна над которым находится указатель мыши установлен стиль CS_DBLCLKS, то окно способно получать сообщение двукратного щелчка. Когда двукратные щелчки разрешены, ОС устанавливает один из внутренних таймеров заданный в CotrolPanel. Если пользователь в пределах этого интервала совершает двойное нажатие, то ОС вместо сообщения о нажатии посылает сообщение двукратного щелчка WM_LBUTTONDBLCLK.В сообщении от мыши параметры имеют следующий смысл: WPARAM – определяет состояние кнопок мыши и клавиш Ctrl & Shift. LPARAM – младшие 2 байта кодируют координату X, старшие – Y.
При нажатии и отпускании обычной клавиши ОС генерирует сообщение WM_KEYDOWN & WM_KEYUP. Если нажаты системные клавиши WM_SYSKEYDOWN & WM_SYSKEYUP (Они соответствуют системному нажатию и отпусканию. Системное нажатие происходит с клавишей Alt !!!). Если пользователь нажал клавишу и удерживает ее, То происходит автоповтор клавиатуры. ОС автоматически начинает помещать в очередь сообщений WM_KEYUP. В результате на 1 сообщение WM_KEYDOWN может быть несколько WM_KEYUP. Если очередь сообщений забивается, то в параметре сообщений WM_KEYDOWN ОС начинает увеличивать счетчик повторов. wParam – код виртуальный. Для символьных сообщений там символьный код. При отпускании клавиши TranslateMessage помещает в очередь сообщений WM_DEADCHAR (WM_SYSDEADCHAR). lParam во всех типах – набор битовых флагов:
Счетчик повтора; Индикатор расширенной клавиши; Индикатор системной клавиши (удерживался ли Alt); Индикатор предыдущего состояния, который показывает - была ли до этого нажата эта клавиша; Индикатор текущего состояния
Параметры клавиатурных сообщений не несут информацию о состоянии Ctrl & Shift. Чтобы ее получить нужно вызвать функцию GetKeyState(UINT virtkKey). Она принимает код клавиши и возвращает ее состояние нажата/отпущена (включена/выключена). Эта функция синхронизирована с моментом посылки последнего клавиатурного сообщения. Т.е. она возвращает состояние клавиши не на момент ее вызова, а на момент последнего сообщения от клавиатуры. GetAsyncKeyState – позволяет определить состояние клавиатуры на момент вызова функции.
Фокусом ввода всегда владеет либо активное окно, либо одно из его дочерних окон. Часто дочерними окнами являются элементы управления — кнопки, переключатели, флажки, текстовые поля и списки, которые обычно размещаются в окне диалога. Обрабатывая сообщения WNLSETFOCUS и WM_KILLFOCUS, оконная процедура может определить текущий статус связанного с ней окна. Первое сообщение показывает, что окно получило фокус ввода, второе — что окно потеряло фокус ввода.Для работы с фокусом ввода предусмотрены следующие функции:
Функция HWND SetFocus(HWND hWnd) устанавливает фокус ввода на окно hWnd, возвращая дескриптор окна, которое располагало фокусом до вызова функции.Функция HWND GetFocus() возвращает дескриптор окна, имеющего фокус ввода в текущий момент.

7. Вывод информации в окно. Механизм перерисовки окна. Понятие области обновления окна. Операции с областью обновления окна.
Разделение дисплея между прикладными программами осуществляется с помощью окон.
Видимая площадь окна может изменяться, что требует постоянного контроля за отображаемой в окне информацией и своевременного восстановления утраченных частей изображения.
ОС не хранит графическую копию рабочей (пользовательской) части каждого окна. Она возлагает ответственность за правильное отображения окна на прикладную программу, посылая ей WM_PAINT каждый раз, когда все окно или его часть требует перерисовки.
При операциях с окнами система помечает разрушенные части окна, как подлежащие обновлению и помещает информацию о них, в специальную область:
область обновления - UPDATEREGION
На основании содержимого этой области и происходит восстановление. ОС посылает окну сообщение WM_PAINTвсякий раз, когда область обновления окна оказывается не пустой и при условии, что в очереди сообщений приложения нет ни одного сообщения.
При получении сообщения WM_PAINT, окно должно перерисовать лишь свою внутреннюю часть, называемуюрабочей областью(ClientArea). Все остальные области окна перерисовывает ОС поWM_NCPAINT.
Для ускорения графического вывода Windowsосуществляет отсечение. На экране перерисовываются лишь те области окна, которые действительно требуют обновления. Вывод за границами области отсечения игнорируется. Это дает право прикладной программе перерисовывать всю рабочую область в ответ на сообщениеWM_PAINT. Лишний вывод ОС отсекает.
Инициатором сообщения WM_PAINTможет выступать не только ОС, но и прикладная программа. Чтобы спровоцировать перерисовку окна необходимо вызвать функцию:
void InvalidateRect( HWND, //handleокна
RECT* //эта область требует перерисовки,
BOOL//нужно ли перед перерисовкой очищать область обновления);Очистка производится сообщением WM_ERASE_BACKGROUND.
После вызова функции InvalidateRect, окно не перерисовывается сразу (доWM_PAINT). Перерисовка произойдет только при опросе программой очереди сообщений. Когда перерисовка требуется немедленно, то вслед заInvalidateRectвызывается функция:
voidUpdateWindow(HWND);
Перерисовка содержимого окна основана на получении контекста устройства, связанного с окном, рисование (вывод графических примитивов) в этом контексте устройства, и освобождение контекста устройства.
В разных случаях получение контекста устройства осуществляется разными функциями ОС. В ответ на сообщение WM_PAINTконтекст устройства получается с помощью функции:
HDCBeginPaint(HWND,PAINTSTRUCT*);
//рисование
voidEndPaint(HWND,PAINTSTRUCT*);
Между вызовами этих 2х функций заключаются вызовы графических примитивов (Rectangle(),Line()).
Функции BeginPainиEndPaintможно вызывать только на сообщениеWM_PAINT.
Иногда бывает необходимо выполнить перерисовку окна в какой-то другой момент времени (по сообщению от таймера). В этом случае контекст дисплея получается с помощью функции:
HDC GetDC(HWND);
А освобождается функцией:
int ReleaseDC(HWND, HDC);
Вызовы этих функций обязательно должны быть сбалансированы, иначе возникнут сбои в работе ОС.
В Windows передача сообщения в окно всегда осуществляется синхронно: отправитель не может продолжить работу, пока окно не обработает полученное сообщение.

8. Принципы построения графической подсистемы ОС Windows. Понятие контекста устройства. Вывод графической информации на физическое устройство. Управление цветом. Палитры цветов. Графические инструменты. Рисование геометрических фигур.
Подмножество Функций ОС Windows для вывода графической информации на экран и другие внешние устройства называется GDI (Graphic Device Interface). Принципы: 1)GDI - аппаратно независим (работаем с виртуальным устройством). Качество выводимого изображения определяется физическими свойствами адаптера. 2)Зависимость от устройств отображения достигается за счет использования драйверов. При смене драйверов только меняем драйвер и программа работает нормально 3)Все элементы графического изображения описываются в рамках логической системы координат, которая может отличаться от физической. На экране изображение является плоским. Значения координат по обоим осям изменяется в пределах (зависит от ОС) (-32768..32767).4)3 основные цвета: RGB. Каждому из цветов отводится по 1 байту.5)GDI позволяет строить изображение по принципу WYSIWYG (What You See Is What You Get). Это обеспечивается не только применение логической системы координат, но и масштабируемых шрифтов TrueType. КОНТЕКСТ УСТРОЙСТВА - логический объект ОС, который связан с физическим устройством и заменяет его в функциях вывода. Структура DC не доступна, но доступны функции создающие/получающие дескриптор контекста устройства по каким-то входным параметрам. Дескриптор передается первым параметром в функцию осуществляющую вывод графического примитива. Специальные функции вывода позволяют интерпретировать каждое окно на экране как отдельное устройство. Приложение которое запрашивает контекст устройства для конкретного окна, получает DC внутри этого окна и не может осуществлять доступ за его пределы.
ВЫВОД ИНФОРМАЦИИ Разделение дисплея между прикладными программами осуществляется с помощью окон. Видимая площадь окна может изменятся. ОС не хранит графическую копию каждого окна. Она возлагает ответственность за правильное отображения окна на прикладную программу, посылая ей WM_PAINT каждый раз, когда все окно или его часть требует перерисовки. При операциях с окнами система помечает разрушенные части окна, как подлежащие обновлению и помещает информацию о них, в специальную область: область обновления UPDATE REGION. На основании содержимого этой области и происходит восстановление. ОС посылает окну сообщение WM_PAINT всякий раз, когда область обновления окна оказывается не пустой и при условии, что в очереди сообщений приложения нет ни одного сообщения. При получении сообщения WM_PAINT окно должно перерисовать лишь свою внутреннюю часть, называемую рабочей областью (Client Area). Все остальные области окна перерисовывает ОС по WM_NCPAINT.
Для ускорения графического вывода Windows осуществляет отсечение. На экране перерисовываются лишь те области окна, которые действительно требуют обновления. Вывод за границами области отсечения игнорируется. Это дает право прикладной программе перерисовывать всю рабочую область в ответ на сообщение WM_PAINT. Инициатором сообщения WM_PAINT может выступать не только ОС, но и прикладная программа. Чтобы спровоцировать перерисовку окна необходимо вызвать функцию void InvalidateRect(HWND, RECT*, BOOL). Очистка производится сообщением WM_ERASE_BACKGROUND. После вызова InvalidateRect окно не перерисовывается сразу (до WM_PAINT). Перерисовка произойдет только при опросе программой очереди сообщений. Когда перерисовка требуется немедленно, то вслед за InvalidateRect вызывается функция void UpdateWindow(HWND). РЕАКЦИЯ НА СООБЩЕНИЕ WM_PAINT. Перерисовка содержимого окна основана на получении контекста устройства (экрана), связанного с окном. В разных случаях получение контекста устройства осуществляется разными функциями ОС. В ответ на сообщение WM_PAINT контекст устройства получается с помощью функции HDC BeginPaint(HWND, PAINTSTRUCT*). Void EndPaint(HWND, PAINTSTRUCT*); Между вызовами этих 2х функций заключаются вызовы графических примитивов. Функции BeginPain & EndPaint можно вызывать только на сообщение WM_PAINT. Иногда бывает необходимо выполнить перерисовку окна в какой-то другой момент времени (по сообщению от таймера). В этом случае контекст дисплея получается с помощью функции HDC GetDC(HWND), а освобождается функцией int ReleaseDC(HWND, HDC). Вызовы этих функций обязательно должны быть сбалансированы, иначе возникнут сбои в работе ОС.

9. Растровые изображения. Виды растровых изображений. Значки и курсоры. Способ вывода растровых изображений с эффектом прозрачного фона. Аппаратно-зависимые и аппаратно-независимые растровые изображения. Операции с растровыми изображениями. Вывод растровых изображений.
Типы растровых изображений:
Bitmap – базовый формат растрового изображения.
Icon – значок: AND-маска и XOR-маска.
Cursor – курсор: две маски и точка касания – Hot Spot.
 Значки – это небольшая картинка, ассоциируемая с некоторой программой, файлом на экране. Значок является частным случаем растровых изображений.
На экране значки могут иметь не прямоугольную форму, что достигается за счет описания значка двумя точечными рисунками:
AND-mask. Монохромная.
XOR-mask. Цветная.
При выводе значков, ОС комбинирует маски по следующему правилу:
Экран = (Экран ANDМонохромная маска)XORЦветная маска.
 Накладывая AND-mask, ОС вырезает на экране пустую область с заданным контуром. ВAND-maskфигура кодируется с помощью 0, а прозрачный фон с помощью 1.
После вывода AND-maskОС накладываетXOR-mask, содержащую изображения фигур. Изображение фигуры является цветным.
На диске значки сохраняются в *.icoформате. В ОС существует несколько форматов значков, которые отличаются по размеру и цвету (16х16, 32х32, 16х32, 64х64).
Курсоры. Указатели мыши. Небольшой образ. По своему представлению в файле и памяти курсор напоминает значки, но существуют некоторые значки. Курсоры могут быть размером 16х16 и 32х32. Важным существенным отличием является наличие в нем горячей точки (hotspot), которая ассоциируется с позицией указателя мыши на экране. *.CUR.
Точечные рисунки – это изображение, представление графической информации, ориентированное на матричное устройство вывода. Точечный рисунок состоит из пикселей, организованных в матрицу. ОС позволяет использовать точечные рисунки двух видов:
Аппаратно-зависимые. Device Dependent Bitmpap. Рассчитаны только на определенный тип графического адаптера или принтера. Их точки находятся в прямом соответствии с пикселями экрана или другой поверхности отображения.
Если это экран – то информация о пикселях представляется битовыми планами в соответствии с особенностями устройства. Он наименее удобен при операциях с точечным рисунком, но обеспечивает наибольшую скорость графического вывода. Он хорошо подходит для работы с точечными рисунками в оперативной памяти.
При хранении на диске используется аппаратно-независимый формат - BMP,DIB.
Аппаратно-независимые. Device Independent Bitmpap. Формат хранения аппаратно-независимых точечных рисунков не зависит от используемой аппаратуры. Здесь информация о цвете и самом изображении хранится раздельно.
Цвета собраны в таблицу, а точки изображения кодируют номера цветов таблицы. Под каждую точку изображения может отводиться 1,4,8,16,24 битов изображения. Они могут храниться на диске в сжатом виде.
Для сжатия применяется алгоритм RunLengthEncoding(RLE). Разжатие производится автоматически. Недостаток: обеспечивается более низкая скорость работы.
Вывод растрового изображения с эффектом прозрачного фона: AND-маска – монохромная. Фигура кодируется нулем, прозрачный фон – единицей. Вырезает на экране «черную дыру» там, где должна быть фигура.
Растровая операция – способ комбинирования пикселей исходного изображения с пикселями поверхности отображения целевого контекста устройства. При масштабировании в сторону сжатия некоторые цвета могут пропадать. При растяжении, таких проблем не существует. При сжатии возможно 3 способа сжатия.

10. Библиотека работы с двумерной графикой Direct2D. Инициализация библиотеки. Фабрика графических объектов библиотеки Direct2D. Вывод графики средствами библиотеки Direct2D. (потом переведу)
Direct2D is a hardware-accelerated, immediate-mode 2-D graphics API that provides high performance and high-quality rendering for 2-D geometry, bitmaps, and text. The Direct2D API is designed to interoperate with existing code that uses GDI, GDI+, or Direct3D.
Developers of large, enterprise-scale, native applications.
Developers who create control toolkits and libraries for consumption by downstream developers.
Developers who require server-side rendering of 2-D graphics.
Developers who use Direct3D graphics and need simple, high-performance 2-D and text rendering for menus, user interface (UI) elements, and Heads-up Displays (HUDs).
Инициализация библиотеки
Фабрика графических объектов библиотеки Direct2D
The ID2D1Factory interface is the starting point for using Direct2D; use an ID2D1Factory to create Direct2D resources.
When you create a factory, you can specify whether it is multi- or single-threaded. (For more information about multi-threaded factories, see the remarks on the ID2D1Factory reference page.) This example creates a single-threaded factory.
In general, your application should create the factory once and retain it for the life of the application.
Direct2D является аппаратное ускорение, в непосредственном режиме 2-D графики API, который обеспечивает высокую производительность и качественную визуализацию для 2-D геометрии, растровых изображений и текста.Direct2D API предназначен для взаимодействия с существующим кодом, который использует GDI, GDI + или Direct3D.
• Разработчики крупных, предприятий масштаба, родные приложения.
• разработчиков, которые создают управляющие инструментальных средств и библиотек для потребления ниже по течению разработчиков.
• Разработчики, которые требуют стороне сервера визуализации 2-D графики.
• Разработчики, которые используют Direct3D графики и нужно просто, высокопроизводительный 2-D и визуализации текста для меню, пользовательский интерфейс (UI) элементов, и Heads-Up дисплеи (Huds).
Интерфейс ID2D1Factory является отправной точкой для использования Direct2D; использовать ID2D1Factory создать Direct2D ресурсов.
При создании фабрики, вы можете указать, будет ли это много- или однопоточных. (Для получения более подробной информации о многопоточных заводов, увидеть замечания по ID2D1Factory справочной странице). Этот пример создает однопоточных завод.
В общем, ваше приложение должно создать фабрику раз и сохранить его для жизни приложения.

11. Вывод текста в ОС Windows. Понятие шрифта. Характеристики шрифта. Понятия физического и логического шрифта. Операции с физическими шрифтами. Операции с логическими шрифтами. Параметры ширины и высоты логического шрифта.
1) BOOL TextOut
 Функция TextOut записывает строку символов в заданном месте, используя текущий выбранный шрифт, цвет фона и цвет текста.
Если функция завершается с ошибкой, величина возвращаемого значения – ноль, иначе – не ноль.
SetTextAlign - устанавливает флажки выравнивания текста для заданного контекста устройства.
GetTextAlign - извлекает настройки выравнивания текста для заданного контекста устройства.
SetTextColor - function sets the text color for the specified device context to the specified color.
GetTextColor - function retrieves the current text color for the specified device context.
2) BOOL ExtTextOut
 Выводит текст используя текущий выбранный шрифт, цвета фона и текста.
Если строка рисуется, возвращаемое значение является отличным от нуля.
3) BOOL PolyTextOut
 рисует несколько строк, используя шрифт и цвета текста, в настоящее время выбранные в заданном контексте устройства. При ошибке – 0, иначе – не ноль.
4)LONG TabbedTextOut
Пишет строку символов в заданном месте, разворачивая позиции табуляции в значения, указанные в массиве позиций табуляции. Текст пишется в текущем выбранном шрифте, цвете фона и цвете текста.
Если функция завершается ошибкой, возвращаемое значение – нуль.
5) int DrawText
Рисует отформатированный текст в заданном прямоугольнике. Если функция завершается успешно, возвращаемое значение - высота текста в логических единицах измерения.
 6) int DrawTextEx
Рисует форматированный текст в заданном прямоугольнике.
Если функция завершается с ошибкой, величина возвращаемого значения - ноль.
Шрифт – множество символов со сходными размерами и начертанием контуров. Семейство шрифта – набор шрифтов со сходной шириной символов и гарнитурой:
Шрифты в программе:
Физические – устанавливаемые в операционную систему, файлы.
Логические – запрашиваемые программой у операционной системы, LOGFONT.
Существуют 2 типа шрифтов:
        Растровые (масштабируемые шрифты TrueType)
        Векторные (в чистом виде в Windows таких нет)
Масштабируемые шрифты TrueTypeописываются сплайнами 3 порядка.PostScript– описываются сплайнами 2ого порядка.
Сплайны третьего порядка позволяют более тонко управлять шрифтом. В сплайнах третьего порядка классная 2ая производная, так же при работе с графикой имеются свои преимущества.
PostScript– быстрее.


12. Системы координат. Трансформации. Матрица трансформаций. Виды трансформаций и их представление в матрице трансформаций. Преобразования в страничной системе координат. Режимы масштабирования.
Мировая – world coordinate space (2^32). Обеспечивает параллельный перенос, масштабирование, отражение, поворот, наклон.
Логическая (страничная) – page coordinate space (2^32). Устаревшая система координат, основанная на режимах масштабирования (mapping modes). Обеспечивает параллельный перенос, масштабирование, отражение.
Устройства – device coordinate space (2^27). Обеспечивает параллельный перенос (к началу координат на устройстве).
Физическая – physical device coordinate space. Например, клиентская область окна на экране.
Трансформации
Включить расширенный графический режим:
int SetGraphicsMode(HDC hdc, int iMode); GM_ADVANCED
Матрица трансформации:
Struct XFORM
{FLOAT eM11,eM12,eM21,eM22, eDx,eDy}
|eM11eM120|
|eM21eM220|
|eDxeDy1| (ris_1)
Применение матрицы трансформации:
|x`y`1|=|xy1| * (ris_1)
Формулы:
x' = x * eM11 + y * eM21 + eDx
y' = x * eM12 + y * eM22 + eDy
Страничная система координат
Преобразования в страничной системе координат:
DX = (LX – XWO) * XVE/XWE + XVO
DY = (LY – YWO) * YVE/YWE + YVO
LX, LY – координаты в логической системе
DX, DY – координаты в физической системе
Функции:
bool LPtoDP(HDC hdc, POINT* lpPoints, int nCount), DPtoLP.
SetWindowOrgEx, SetViewportOrgEx – смещения.
SetViewportExtEx, SetWindowExtEx – масштабные коэффициенты. Взятые отдельно, эти функции смысла не имеют.
Режимы масштабирования:
int SetMapMode(HDC hdc, int fnMapMode), GetMapMode.

13. Понятие ресурсов программ Windows. Виды ресурсов. Операции с ресурсами.
Ресурсы – двоичные данные, записываемые в исполняемый модуль приложения. Стандартные типы ресурсов:
Курсор – Cursor,Картинка – Bitmap,Значок – Icon,Меню – Menu,Окно диалога – Dialog Box,Таблица строк – String Table,Таблица сообщений (об ошибках) – Message Table,Шрифт – Font,Таблица горячих клавиш – Accelerator Table
Ресурсы могут быть разделяемыми, когда несколько процессов могут их использовать одновременно или параллельно, и неделимыми.
Cхема выделения ресурсов такова: При необходимости использовать какой-либо ресурс задача обращается к супервизору ОС и сообщает о своем требовании. Директива обращения задачи к операционной системе передает ей управление, переводя процессор в привилегированный режим работы, если такой существует. Получив запрос, операционная система удовлетворяет его и после выполнения запроса ОС возвращает управление задаче, выдавшей данный запрос, или, если ресурс занят, ставит задачу в очередь, переводя ее в состояние ожидания (блокируя).
Ресурс может быть выделен задаче, в следующих случаях:1.) ресурс свободен, и в системе нет запросов от задач более высокого приоритета к запрашиваемому ресурсу;2.) текущий запрос и ранее выданные запросы допускают совместное использование ресурсов;3.) ресурс используется задачей низшего приоритета и может быть временно отобран (разделяемый ресурс).освобождения ресурса: После окончания работы с ресурсом задача с помощью специального вызова супервизора посредством соответствующей директивы сообщает операционной системе об отказе от ресурса, либо операционная система самостоятельно забирает ресурс. Супервизор ОС, получив управление по этому обращению, освобождает ресурс и проверяет, имеется ли очередь к освободившемуся ресурсу. При наличии очереди в соответствии с принятой дисциплиной обслуживания и в зависимости от приоритета заявки он выводит из состояния ожидания ждущую ресурс задачу и переводит ее в состояние готовности к выполнению. После этого управление либо передается данной задаче, либо возвращается той, которая только что освободила ресурс.
Основные функции ядра ОС, распределение ресурсов:
Назначение ядра ОС состоит в распределении ресурсов между задачами (процессами) пользователей и системными процессами (необходимо отличать системные управляющие процессы, представляющие работу супервизора ОС и занимающиеся распределением и управлением ресурсов, от других процессов: системных обрабатывающих, которые не входят в ядро операционной системы, и процессов пользователя).
1)порождение процессов, уничтожение процессов (завершение) и реализация механизмов связи между процессами;2.) обработка прерываний;3.) реализация основных функций распределения ресурсов. Функция BeginUpdateResource возвращает дескриптор, который может быть использован функцией UpdateResource для добавления, удаления или замены ресурсов в исполняемом файле.Процесс записи ресурсов в файл начинается с вызова BeginUpdateResource. При этом флаг bDeleteExistingResources задает режим записи: с удалением существующих ресурсов или без.Заканчивается процесс записи вызовом EndUpdateResource. Если флаг bDiscard установлен в TRUE, то запись ресурсов отменяется, в противном случае ресурсы записываются в файл.
Между вызовами этих двух функций можно обновлять ресурсы с помощью функции UpdateResource, причем вызывать ее можно неоднократно.Функция UpdateResource добавляет, удаляет или заменяет ресурс в исполняемом файле.
Функция FindResource выясняет место ресурса с заданным типом и именем в указанном модуле.
FindResource, поиск любого типа ресурса, но эта функция должна использоваться, только в том случае, если прикладная программа должна получить доступ к двоичным данным ресурса при производстве последующих вызовов функции LockResource.ункция LoadResource загружает указанный ресурс в глобальную память.
Файл ресурсов описывает и диалоговые окна. Все компоненты окна - кнопки, элементы управления и даже статический текст, имеют свои идентификаторы, координаты в окне и номера, как имеют их и элементы меню. Для каждого окна нужная своя функция окна, поэтому в программу помимо WndProc - функции главного окна, придётся включить PifProc() - функцию диалогового окна. Аргументы у неё будут такие же, как и у WndProc.

14. Понятие динамически-загружаемой библиотеки. Создание DLL-библиотеки. Использование DLL-библиотеки в программе методом статического импорта процедур. Соглашения о вызовах процедур DLL-библиотеки. Точка входа-выхода DLL-библиотеки.
Динамически-загружаемая библиотека (DLL) – двоичный модуль операционной системы. Это программа с множеством точек входа. Включает код, данные и ресурсы.
Подключение DLL называется импортом. Существуют статический импорт и динамический импорт. При статическом импорте динамическая библиотека подключается как статическая, но находится в отдельном исполняемом файле и поэтому может быть заменена перед стартом. При динамическом импорте загрузка и получение адресов функций динамической библиотеки происходит вручную во время работы программы.
·  При разработке DLL Вы сначала создаете заголовочный файл, в котором содержатся экспортируемые из нее переменные (типы и имена) и функции (прототипы и имена). В этом же файле надо определить все идентификаторы и структуры данных, используемые экспортируемыми функциями и переменными. Заголовочный файл включается во все модули исходного кода Вашей DLL. Более того, Вы должны поставлять его вместе со своей DLL, чтобы другие разработчики могли включать его в свои модули исходного кода, которые импортируют Ваши функции или переменные. Единый заголовочный файл, используемый при сборке DLL и любых исполняемых модулей, существенно облегчает поддержку приложения.
При компиляции исходного файла DLL, показанного на предыдущем листинге, MYLIBAPI определяется как __declspec(dllexport) до включения заголовочного файла MyLib.h. Такой модификатор означает, что данная переменная, функция или C++􏰀класс экспортируется из DLL. Заметьте, что идентификатор MYLIBAPI помещен в заголовоч􏰀 ный файл до определения экспортируемой переменной или функции.
Также обратите внимание, что в файле MyLibFile1.cpp перед экспортируемой пе􏰀 ременной или функцией не ставится идентификатор MYLIBAPI. Он здесь не нужен: проанализировав заголовочный файл, компилятор запоминает, какие переменные и функции являются экспортируемыми.
Идентификатор MYLIBAPI включает extern. Пользуйтесь этим модификатором только в коде на C++, но ни в коем случае не в коде на стандартном C. Обычно ком􏰀 пиляторы C++ искажают (mangle) имена функций и переменных, что может приво􏰀 дить к серьезным ошибкам при компоновке. Представьте, что DLL написана на C++, а исполняемый код — на стандартном C. При сборке DLL имя функции будет искаже􏰀 но, но при сборке исполняемого модуля — нет. Пытаясь скомпоновать исполняемый модуль, компоновщик сообщит об ошибке: исполняемый модуль обращается к несу􏰀 ществующему идентификатору. Модификатор extern не дает компилятору искажать имена переменных или функций, и они становятся доступными исполняемым моду􏰀 лям, написанным на C, C++ или любом другом языке программирования.
Теперь Вы знаете, как используется заголовочный файл в исходных файлах DLL. А как насчет исходных файлов EXE􏰀модуля? В них MYLIBAPI определять не надо: вклю􏰀 чая заголовочный файл, Вы определяете этот идентификатор как __declspec(dllimport), и при компиляции исходного кода EXE􏰀модуля компилятор поймет, что переменные и функции импортируются из DLL.
Просмотрев стандартные заголовочные файлы Windows (например, WinBase.h), Вы обнаружите, что практически тот же подход исповедует и Microsoft.
Соглашения о вызовах подпрограмм:
-  __declspec(dllimport) int __stdcall Min(int X, int Y);
-  __cdecl – Параметры передаются на стек в обратном порядке. За освобождение стека после вызова под-программы отвечает вызывающая программа.
- __pascal – Передача параметров на стек в прямом порядке. Освобождение стека осуществляет сама вызванная подпрограмма.
-  __stdcall – Соглашение для стандартных DLL ОС Windows. Передача параметров на стек происходит в обратном порядке. Освобождение стека выполняет вызванная подпрограмма.
__register – Передача параметров преимущественно через регистры процессора. Не используется при создании DLL, поскольку не стандартизировано.

15. Понятие динамически-загружаемой библиотеки. Создание DLL-библиотеки. Использование DLL-библиотеки в программе методом динамический импорта процедур.
1 и 2 часть вопроса смотри в вопросе номер 14
DLL представляет собой дополняемый модуль ОС (обычно DLL), код и ресурсы которого могут использоваться в составе других динамических библиотек и приложений. DLL – программа с множеством точек входа. В отличие от статической библиотеки, которая включается в выполняемый exe модуль на этапе сборки, динамическая библиотека собирается в виде отдельно выполняемого модуля. Использование динамической библиотеки выполняется одним из двух способов:
Статического импорта
Динамического импорта
Для создания DLL в разных языках используются разные средства. В C++:
Создание:
Динамический импорт. Если при статическом импорте загрузку DLL в память обеспечивает ОС, то при динамическом импорте это делает программист вручную. Загрузить DLL можно с помощью функции:
HANDLE LoadLibrary(LPCSTR libFileName)
Загрузка DLL-библиотеки в память:
HMODULE LoadLibrary(LPCTSTR lpFileName);
HMODULE LoadLibraryEx(LPCTSTR lpFileName, _Reserved_  HANDLE hFile, DWORD dwFlags);
HMODULE GetModuleHandle(LPCTSTR lpModuleName); GetModuleHandleEx.
DWORD GetModuleFileName(HMODULE hModule, LPTSTR lpFilename, DWORD nSize);
Освобождение DLL-библиотеки:
bool FreeLibrary(HMODULE hModule); FreeLibraryAndExitThread.
Получение адреса функции в DLL-библиотеке:
void* GetProcAddress(HMODULE hModule, LPCSTR lpProcName);
Применение:
typedef int TMin(int x, int y); // добавить __stdcall
TMin* pMin;
pMin = (TMin*)GetProcAddress(hModule, "[email protected]");
int a = pMin(10, 20);

16. Понятие динамически-загружаемой библиотеки. Создание в DLL-библиотеке разделяемых между приложениями глобальных данных. Разделы импорта и экспорта DLL-библиотеки. Переадресация вызовов процедур DLL-библиотек к другим DLL-библиотекам. Исключение конфликта версий DLL.
DLL представляет собой дополняемый модуль ОС (обычно DLL), код и ресурсы которого могут использоваться в составе других динамических библиотек и приложений. DLL – программа с множеством точек входа. В отличие от статической библиотеки, которая включается в выполняемый exe модуль на этапе сборки, динамическая библиотека собирается в виде отдельно выполняемого модуля. Использование динамической библиотеки выполняется одним из двух способов:
Статического импорта
Динамического импорта
Разделяемые данные – shared data:
#pragma section("mysection", read, write, shared)
__declspec(allocate("mysection")) int Number = 0;
Экспорт
Если модификатор __declspec(dllexport) указан перед переменной, прототипом функции или C++классом, компилятор Microsoft С/С++ встраивает в конечный OBJфайл дополнительную информацию. Она понадобится компоновщику при сборке DLL из OBJфайлов.
Обнаружив такую информацию, компоновщик создает LIB-файл со списком идеyтификаторов, экспортируемых из DLL. Этот LIB􏰀файл нужен при сборке любого EXE-модуля, ссылающегося на такие идентификаторы. Компоновщик также вставляет в конечный DLL-файл таблицу экспортируемых идентификаторов — раздел экспорта, в котором содержится список (в алфавитном порядке) идентификаторов экспортируемых функций, переменных и классов. Туда же помещается относительный виртуальный адрес (relative virtual address, RVA) каждого идентификатора внутри DLL-модуля.
Воспользовавшись утилитой DumpBin.exe (с ключом -exports) из состава Microsoft Visual Studio, мы можем увидеть содержимое раздела экспорта в DLL-модуле.
Импорт
Разрешая ссылки на импортируемые идентификаторы, компоновщик создает в конечном EXE-модуле раздел импорта (imports section). В нем перечисляются DLL, необходимые этому модулю, и идентификаторы, на которые есть ссылки из всех используемых DLL.
Воспользовавшись утилитой DumpBin.exe (с ключом -imports), мы можем увидеть содержимое раздела импорта.
Запись о переадресации вызова функции (function forwarder) — это строка в разделе экспорта DLL, которая перенаправляет вызов к другой функции, находящейся в дру􏰀 гой DLL. Например, запустив утилиту DumpBin из Visual C++ для Kernel32.dll в Win􏰀 dows 2000,
   Здесь есть четыре переадресованные функции. Всякий раз, когда Ваше приложе􏰀ние вызывает HeapAlloc, HeapFree, HeapReAlloc или HeapSize, его EXE􏰀модуль динами􏰀 чески связывается с Kernel32.dll. При запуске EXE􏰀модуля загрузчик загружает Ker􏰀 nel32.dll и, обнаружив, что переадресуемые функции на самом деле находятся в NTDLL.dll, загружает и эту DLL. Обращаясь к HeapAlloc, программа фактически вызы􏰀 вает функцию RtlAllocateHeap из NTDLL.dll. А функции HeapAlloc вообще нет!
При вызове HeapAlloc (см. ниже) функция GetProcAddress просмотрит раздел экс􏰀 порта Kernel32.dll и, выяснив, что HeapAlloc — переадресуемая функция, рекурсивно вызовет сама себя для поиска RtlAllocateHeap в разделе экспорта NTDLL.dll. GetProcAddress(GetModuleHandle("Kernel32"), "HeapAlloc");  
Вы тоже можете применять переадресацию вызовов функций в своих DLL. Самый
простой способ — воспользоваться директивой pragma: // переадресация к функции из DllWork
#pragma comment(linker, "/export:SomeFunc=DllWork.SomeOtherFunc")
Эта директива сообщает компоновщику, что DLL должна экспортировать функцию SomeFunc, которая на самом деле реализована как функция SomeOtherFunc в модуле DllWork.dll. Такая запись нужна для каждой переадресуемой функции.
17. Понятие объекта ядра ОС Windows. Виды объектов ядра. Атрибуты защиты объекта ядра. Дескриптор защиты объекта ядра. Создание и удаление объектов ядра.
Виды объектов:
Объекты оконной системы – User ObjectsОбъекты графической системы – GDI ObjectsОбъекты ядра – Kernel ObjectsОбъекты ядра с атрибутами защиты:

Атрибуты защиты – SECURITY_ATTRIBUTES:
struct SECURITY_ATTRIBUTES{ DWORD nLength; void* lpSecurityDescriptor; bool bInheritHandle;};
Дескриптор защиты – SECURITY_DESCRIPTOR:
Owner security identifier (SID)
Primary group SID
Discretionary access control list (DACL)
System access control list (SACL)
Функции создания и редактирования дескриптора защиты:
bool InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD dwRevision);
SetSecurityDescriptorXxx, GetSecurityDescriptorXxx.
Создание объекта ядра:
HANDLE CreateXxx(SECURITY_ATTRIBUTES* lpAttributes, …, LPCTSTR lpName);
HANDLE OpenXxx(DWORD dwDesiredAccess, bool bInheritHandle, LPCTSTR lpName);
bool DuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, HANDLE* lpTargetHandle, DWORD dwDesiredAccess, bool bInheritHandle, DWORD dwOptions);
bool SetHandleInformation(HANDLE hObject, DWORD dwMask, DWORD dwFlags); HANDLE_FLAG_INHERIT, HANDLE_FLAG_PROTECT_FROM_CLOSE.
bool GetHandleInformation(HANDLE hObject, DWORD* lpdwFlags);
Удаление объекта ядра:
bool CloseHandle(HANDLE hObject);

18.Проецирование файлов в память. Отличие в механизме проецирования файлов в память в ОС Windows и UNIX/Linux. Действия по проецированию файла в память.
                  На платформах Win/Unix существуют средства для работы с файлами как с оперативной памятью. Техника работы с ФПВП отличается в ОС Unix (Linux) & Win.
                                        
                   Идея в том, чтобы закрепить за началом файла какой-либо адрес памяти, а дальше выполнять чтение и запись файла методом чтения/записи байтов оперативной памяти. Т.к. файл не может поместится в оперативной памяти целиком, он делится на страницы и в оперативную память подгружаются лишь те страницы, с которыми происходит работа. Адресное пространство файла является виртуальным, оно может значительно превосходить по размерам оперативную память. Для прозрачной поддержки проецирования файлов в память необходимо иметь поддержку виртуальной памяти на уровне процессора и архитектуры компьютера. Оптимальное соотношение Вирт к физ памяти 1:1 – 1:1,25.
                   В ОС Win процессы работают в виртуальном адресном пространстве, для которого создается на диске файл подкачки (swap). При проецировании файлов в память, файл подкачки не затрагивается, хотя проецирование происходит в виртуальное адресное пространство процесса. Такое возможно за счет аппаратной поддержки сложных таблиц страниц. В WIN – File Mapping; Unix – Memory Mapping.
Хотя в Win существует OpenFile, но использовать ее не рекомендуется. Открытие/создание рекомендуется производить CreateFile. Для создания проекции важны первые 4 параметра.
2ой – указывается, будет файл читаться, записываться или и то и другое.
3ий – будет ли файл доступным для совместного использования со стороны других процессов. 0 – запретить сторонним процессам открывать этот файл.
4ый – атрибуты защиты.
                   Шаги:
1.          Открытие файла CreateFile.
2.          Создание объекта ядра под названием «проекция файла».
Основное назначение файлов, проецируемых файлов – работа со сложными структурами данных, загрузка которых в память иным способом требует большого количества времени и сил.

19. Современные многопроцессорные архитектуры SMP и NUMA. Многоуровневое кэширование памяти в современных процессорах. Проблема перестановки операций чтения и записи в архитектурах с ослабленной моделью памяти. Способы решения проблемы перестановки операций чтения и записи.
Производительность достигается за счет правильного проектирования, переноса ключевых функций в режим ядра. ОС Windows поддерживает много аппаратных архитектур. С целью наиболее эффективного использования аппаратных архитектур Windows построена как ОС с симметричной многопроцессорной обработкой (Symmetric MultiProcessing SMP)
-381012065000 ПП –прикладные программы
В системах SMP на любом процессоре может работать поток ОС или прикладной программы. В системах с симметричной многопроцессорной обработкой потоки ОС работают на одном процессоре, а потоки прикладных программ на других процессорах.
NUMA (Non-Uniform Memory Architecture)
Архитектура с неоднородной памятью
-1187452984500В компах с архитектурой NUMA существует возможность наращивать аппаратуру с помощью плат расширения. На каждой плате располагается блок из нескольких процессоров и блок памяти. В компах с такой архитектурой каждый процессор имеет доступ к любому блоку памяти на любой плате, однако доступ к доступ к памяти на своей плате выполняется быстрее. ОС Windows умеет так планировать потоки, что потоки, обращающиеся к общим участкам памяти, размещаются на процессорах одной платы, например потоки одной прикладной программы целесообразно размещать на процессорах одной платы.
Решение проблемы перестановки операций чтения и записи
Синхронизация кэшей – cache coherence;
Барьеры памяти – memory barrier (memory fence).

20. Средства распараллеливания вычислений в ОС Windows. Понятия процесса и потока. Достоинства и недостатки процессов и потоков. Создание и завершение процесса. Запуск процессов по цепочке.
Многозада́чность — свойство операционной системы или среды программирования обеспечивать возможность параллельной (или псевдопараллельной) обработки нескольких процессов.
Существует 2 типа многозадачности:
Процессная многозадачность
Поточная многозадачность 
Процес – выполняемая программа, которая имеет свое виртуальное адресное пространство, выполняемый код, указатели на объекты ядра, данные, уникальный идентификатор, как минимум один выполняющий поток.
Аварийное завершение процесса не приводит к утечке ресурсов или нарушению целостности данных в других процессах. Однако, поскольку процессы работают в разных адресных пространствах, необходимо использовать средства Inter-Process Communication (IPC) для доступа к общим данным.
Создание процесса производится следующим системным вызовом:
bool CreateProcess(LPCTSTR lpAppName, LPTSTR lpCmdLine, SECURITY_ATTRIBUTES* lpProcessAttributes, SECURITY_ATTRIBUTES* lpThreadAttributes, bool bInheritHandles, DWORD dwCreationFlags, void* lpEnvironment, LPCTSTR lpCurrentDirectory, STARTUPINFO* lpStartupInfo, PROCESS_INFORMATION* lpProcessInformation);
Поток – выполняемая подпрограмма процесса, разделяющая с другими потоками общие ресурсы процесса. Все потоки процесса разделяют его вирт. Адресное пространство и системные ресурсы. Каждый поток имеет свой уникальный идентификатор. Расход памяти при распараллеливании минимален. Основные расходы памяти связаны с организацией стека на каждый параллельный поток. Производительность при работе с общими данными максимальна, поскольку потоки работают в общем адресном пространстве. Однако аварийное завершение потока часто приводит к утечке памяти процесса или даже к аварийному завершению процесса. Из-за общей памяти, целостность общих данных может быть нарушена.
Контекст потока - структура, создаваемая Windows для каждого потока. Она содержин информацию о состоянии потока

21. Средства распараллеливания вычислений в ОС Windows. Понятия процесса и потока. Создание и завершение потока. Приостановка и возобновление потока. Контекст потока.
Многозада́чность — свойство операционной системы или среды программирования обеспечивать возможность параллельной (или псевдопараллельной) обработки нескольких процессов.
Существует 2 типа многозадачности:
Процессная многозадачность
Поточная многозадачность 
Процес – выполняемая программа, которая имеет свое виртуальное адресное пространство, выполняемый код, указатели на объекты ядра, данные, уникальный идентификатор, как минимум один выполняющий поток.
Аварийное завершение процесса не приводит к утечке ресурсов или нарушению целостности данных в других процессах. Однако, поскольку процессы работают в разных адресных пространствах, необходимо использовать средства Inter-Process Communication (IPC) для доступа к общим данным.
Поток – выполняемая подпрограмма процесса, разделяющая с другими потоками общие ресурсы процесса. Все потоки процесса разделяют его вирт. Адресное пространство и системные ресурсы. Каждый поток имеет свой уникальный идентификатор. Расход памяти при распараллеливании минимален. Основные расходы памяти связаны с организацией стека на каждый параллельный поток. Производительность при работе с общими данными максимальна, поскольку потоки работают в общем адресном пространстве. Однако аварийное завершение потока часто приводит к утечке памяти процесса или даже к аварийному завершению процесса. Из-за общей памяти, целостность общих данных может быть нарушена.
Контекст потока - структура, создаваемая Windows для каждого потока. Она содержин информацию о состоянии потока.
Создание и завершение потока производится следующим системным вызовом:
HANDLE CreateThread(SECURITY_ATTRIBUTES* lpThreadAttributes, SIZE_T dwStackSize, THREAD_START_ROUTINE* lpStartAddress, void* lpParameter, DWORD dwCreationFlags, DWORD* lpThreadId);
DWORD WINAPI ThreadProc(void* lpParameter);
Завершение потока:
void ExitThread(DWORD dwExitCode);

22. Понятие пула потоков. Архитектура пула потоков. Операции с потоками при работе с пулом потоков.
Архитектура пула потоков:
Рабочие потоки (worker threads) вызывают callback-функции.
Ожидающие потоки ждут на объектах ожидания (wait handles).
Очередь рабочих потоков (work queue).
Стандартный пул потоков на каждый процесс.
Менеджер рабочих потоков (worker factory).
Стандартный размер пула потоков – 500 рабочих потоков.
Pooled Threads: Improve Scalability With New Thread Pool APIsThread PoolingThread Pool APIКласс ThreadPool обеспечивает приложение пулом рабочих потоков, управляемых системой, позволяя пользователю сосредоточиться на выполнении задач приложения, а не на управлении потоками. Если имеются небольшие задачи, которые требуют фоновой обработки, пул управляемых потоков — это самый простой способ воспользоваться преимуществами нескольких потоков. Например, начиная с .NET Framework 4, можно создавать объекты Task и Task<TResult>, выполняющие асинхронные задачи в потоках из пула потоков.
Пропуск проверок безопасности
Пул потоков также предоставляет методы ThreadPool.UnsafeQueueUserWorkItem и ThreadPool.UnsafeRegisterWaitForSingleObject. Используйте эти методы, только когда есть уверенность, что стек вызывающего объекта не зависит от проверок безопасности, выполненных во время выполнения задачи в очереди. Обе перегрузки, QueueUserWorkItem и RegisterWaitForSingleObject, перехватывают стек вызывающего объекта, который объединяется со стеком потока из пула потоков, когда поток начинает выполнять задачу. Если требуется проверка безопасности, проверяется весь стек. Несмотря на обеспечение безопасности, такая проверка влияет также на производительность.

23. Распределение процессорного времени между потоками ОС Windows. Механизм приоритетов. Класс приоритета процесса. Относительный уровень приоритета потока.
Базовый и динамический приоритеты потока. Операции с приоритетами.
Понятие уровня приоритета:
ОС выделяет процессорное время всем активным потокам, исходя из их уровней приоритета (scheduling priority), которые изменяются от 0 (низший) до 31. Уровень 0 присваивается особому потоку, выполняющему обнуление неиспользуемых страниц памяти. Ни один другой поток не может иметь уровень приоритета 0. Для каждого уровня приоритета ОС ведет свою очередь потоков. При появлении потока с более высоким уровнем приоритета, текущий поток приостанавливается (не дожидаясь истечения кванта времени) и квант времени отдается приоритетному потоку. Пока в системе существуют потоки с более высоким приоритетом, потоки с более низкими приоритетами простаивают. Потоки с одинаковым приоритетом обрабатываются как равноправные.
Классы приоритета:
IDLE_PRIORITY_CLASS 4
BELOW_NORMAL_PRIORITY_CLASS
NORMAL_PRIORITY_CLASS 8
ABOVE_NORMAL_PRIORITY_CLASS
HIGH_PRIORITY_CLASS13
REALTIME_PRIORITY_CLASS24
Относительные уровни приоритета:
THREAD_PRIORITY_IDLE 1 // общий результат
THREAD_PRIORITY_LOWEST–2
THREAD_PRIORITY_BELOW_NORMAL–1
THREAD_PRIORITY_NORMAL+0
THREAD_PRIORITY_ABOVE_NORMAL+1
THREAD_PRIORITY_HIGHEST+2
THREAD_PRIORITY_TIME_CRITICAL 15 // общий результат
Уровни приоритета для потоков присваиваются в 2 этапа:1. Процессу присваивается класс приоритета.2. Потоку присваивается относительный уровень приоритета.Результирующий приоритет определяется как сумма этих двух значений (на самом деле результат определяется по таблице).
Функции:
bool SetPriorityClass(HANDLE hProcess, DWORD dwPriorityClass);
DWORD GetPriorityClass(HANDLE hProcess);
bool SetThreadPriority(HANDLE hThread, int nPriority);
int GetThreadPriority(HANDLE hThread);
bool SetProcessPriorityBoost(HANDLE hProcess, bool disablePriorityBoost); SetThreadPriorityBoost.
bool GetProcessPriorityBoost(HANDLE hProcess, bool* pDisablePriorityBoost); GetThreadPriorityBoost.
bool SwitchToThread(); // yield execution to another thread
void Sleep(DWORD dwMilliseconds);
DWORD SleepEx(DWORD dwMilliseconds, bool bAlertable);

24. Механизмы синхронизации потоков одного и разных процессов в ОС Windows. Обзор и сравнительная характеристика механизмов синхронизации.
Между потоками одного процесса:
Критическая секция – Critical Section
Ожидаемое условие – Condition Variable
Атомарная операция – Interlocked (Atomic) Function
Барьер синхронизации – Synchronization Barrier
Между потоками любых локальных процессов:
Блокировка – Mutex
Семафор – Semaphore
Событие – Event
Ожидаемый таймер – Waitable Timer
Между потоками удаленных процессов:
Почтовый ящик – Mailslot
Труба – Named/Unnamed Pipe
Windows Socket

25. Синхронизация потоков в пределах одного процесса ОС Windows. Критическая секция. Операции с критической секцией. Атомарные операции.
Критическая секция – небольшой участок кода, требующий монопольного доступа к каким-то общим данным.
struct CRITICAL_SECTION{ LONG LockCount; LONG RecursionCount; HANDLE OwningThread; HANDLE LockSemaphore; ULONG_PTR SpinCount;};
void InitializeCriticalSection(CRITICAL_SECTION* lpCriticalSection);
void EnterCriticalSection(CRITICAL_SECTION* lpCriticalSection);
void LeaveCriticalSection(CRITICAL_SECTION* lpCriticalSection);
bool TryEnterCriticalSection(CRITICAL_SECTION* lpCriticalSection);
bool InitializeCriticalSectionAndSpinCount(CRITICAL_SECTION* lpCriticalSection, DWORD dwSpinCount); SetCriticalSectionSpinCount.
Атомарная операция – простая операция над машинным словом, которая или выполняется целиком, или не выполняется вообще.
LONG InterlockedIncrement(LONG*Addend); InterlockedDecrement, InterlockedAnd, InterlockedOr, InterlockedXor.
LONG InterlockedExchange(LONG* Target, LONG Value); InterlockedExchangePointer.
LONG InterlockedCompareExchange(LONG* Destination, LONG Exchange, LONG Comparand);InterlockedCompareExchangePointer.
InterlockedBitTestAnd(Set/Reset/Complement).
InterlockedXxx64, InterlockedXxxNoFence, InterlockedXxxAcquire, InterlockedXxxRelease.
Acquire and Release SemanticsInterlocked Singly Linked Lists
26. Синхронизация потоков в пределах одного процесса ОС Windows. Ожидаемое условие (монитор Хора). Операции с ожидаемым условием. Пример использования ожидаемого условия для синхронизации потоков.
Ожидаемое условие – механизм синхронизации, позволяющий потокам дождаться выполнения некоторого (сложного) условия. Состоит из критической секции и переменной условия.
Условные переменные обеспечивают присущую Windows реализацию синхронизации набора потоков, ожидающих конкретного результата проверки условия. Хотя эта операция была возможна и с применением других методов синхронизации в пользовательском режиме, атомарного механизма для проверки результата проверки условия и для начала ожидания изменения этого результата не существовало. Это потребовало использования в отношении таких фрагментов кода этой дополнительной синхронизации. Поток пользовательского режима инициализирует условную переменную путем вызова функции InitializeConditionVariable для установки ее исходного состояния. Когда ему нужно инициировать ожидание, связанное с этой переменной, он вызывает функцию SleepConditionVariableCS, которая использует критический раздел (который поток должен инициализировать) для ожидания изменений переменной. После изменения переменной устанавливающий поток должен использовать функцию WakeConditionVariable (или функцию WakeAllConditionVariable). В результате этого вызова освобождается критический раздел либо одного, либо всех ожидающих потоков, в зависимости от того, которая из этих функция была использована. До условных переменных для отправки сигнала об изменении переменной, например состояния рабочей очереди, часто использовалось либо уведомительное событие, либо синхронизирующее событие (в Windows API они называются авто матическим перезапуском — auto-reset, или ручным перезапуском — manual-reset). Ожидание изменения требует получения, а затем освобождения критического раздела, сопровождаемого ожиданием события. После ожидания критический раздел должен быть получен повторно. Во время этих серий получений и освобождений у потока может быть переключен контекст, вызывая проблемы, если один из потоков называется PulseEvent. При использовании условных переменных получение критического раздела может быть поддержано приложением во время вызова функции SleepConditionVariableCS, и он может быть освобожден только после выполнения работы. Это делает код записи рабочей очереди (и подобных ей реализаций) более простым и предсказуемым. Внутри системы условные переменные могут рассматриваться как порт существующих алгоритмов пуш-блокировок, имеющихся в режиме ядра, с дополнительным усложнением в виде получения и освобождения критических разделов в API-функции SleepConditionVariableCS. Условные переменные по размеру равны указателям (точно так же, как и пуш-блокировки), избегают использования диспетчера, автоматически оптимизируют во время операций ожидания список ожиданий и защищают от сопровождений блокировки. Кроме того, условные переменные полностью используют события с ключом, а не обычный объект события, который бы использовался разработчиками по своему усмотрению, что еще больше оптимизирует код даже в случаях возникновения конкуренции.

27. Синхронизация потоков разных процессов с помощью объектов ядра. Понятие свободного и занятого состояния объекта ядра. Процедуры ожидания освобождения объекта ядра. Перевод объекта ядра в свободное состояние. Объекты синхронизации: блокировки, семафоры, события.
 
Почти все объекты ядра годятся и для решения задач синхронизации. В случае синхронизации потоков о каждом из этих объектов говорят, что он находится либо в свободном (signaled state), либо в занятом состоянии (nonsignaled state). Переход из одного состояния в другое осуществляется по правилам, определенным Microsoft для каждого из объектов ядра. Так, объекты ядра «процесс» сразу после создания всегда находятся в занятом состоянии. В момент завершения процесса операционная система автоматически освобождает его объект ядра «процесс», и он навсегда остается в этом состоянии.
Объект ядра «процесс» пребывает в занятом состоянии, пока выполняется сопоставленный с ним процесс, и переходит в свободное состояние, когда процесс завершается. Внутри этого объекта поддерживается булева переменная, которая при создании объекта инициализируется как FALSE («занято»). По окончании работы процесса операционная система меняет значение этой переменной на TRUE, сообщая тем самым, что объект свободен.
Если Вы пишете код, проверяющий, выполняется ли процесс в данный момент, Вам нужно лишь вызвать функцию, которая просит операционную систему проверить значение булевой переменной, принадлежащей объекту ядра «процесс». Тут нет ничего сложного. Вы можете также сообщить системе, чтобы та перевела Ваш поток в состояние ожидания и автоматически пробудила его при изменении значения булевой переменной с FALSE на TRUE. Тогда появляется возможность заставить поток в родительском процессе, ожидающий завершения дочернего процесса, просто заснуть до освобождения объекта ядра, идентифицирующего дочерний процесс. В дальнейшем Вы увидите, что в Windows есть ряд функций, позволяющих легко решать эту задачу. Я только что описал правила, определенные Microsoft для объекта ядра «процесс». Точно такие же правила распространяются и на объекты ядра «поток». Они тоже сразу после создания находятся в занятом состоянии. Когда поток завершается, операционная система автоматически переводит объект ядра «поток» в свободное состояние. Таким образом, используя те же приемы, Вы можете определить, выполняется ли в данный момент тот или иной поток. Как и объект ядра «процесс», объект ядра «поток» никогда не возвращается в занятое состояние. Следующие объекты ядра бывают в свободном или занятом состоянии:
·         процессы
·         уведомления об изменении файлов
·         потоки
·         события
·         задания
·         ожидаемые таймеры
·         файлы
·         семафоры
·         консольный ввод
·         мьютексы
Потоки могут засыпать и в таком состоянии ждать освобождения какого-либо объекта. Правила, по которым объект переходит в свободное или занятое состояние, зависят от типа этого объекта.
Wait функции позволяют потоку в любой момент приостановиться и ждать освобождения какого-либо объекта ядра. Из всего семейства этих функций чаще всего используется WaitForSingleObject:
DWORD WaitForSingleObject(HANDLE hObject, DWORD dwMilliseconds);
Когда поток вызывает эту функцию, первый параметр, hObject, идентифицирует объект ядра, поддерживающий состояния «свободен занят». (То есть любой объект, упомянутый в списке из предыдущего раздела.) Второй параметр, dwMilliseconds, указывает, сколько времени (в миллисекундах) поток готов ждать освобождения объекта. Следующий вызов сообщает системе, что поток будет ждать до тех пор, пока не завершится процесс, идентифицируемый описателем
Событие – примитивный объект синхронизации, применяемый для уведомления одного или нескольких потоков об окончании какой-либо операции.

28. Синхронизация потоков разных процессов с помощью объектов ядра. Понятие свободного и занятого состояния объекта ядра. Процедуры ожидания освобождения объекта ядра. Ожидаемые таймеры. Оконные таймеры.
Почти все объекты ядра годятся и для решения задач синхронизации. В случае синхронизации потоков о каждом из этих объектов говорят, что он находится либо в свободном (signaled state), либо в занятом состоянии (nonsignaled state). Переход из одного состояния в другое осуществляется по правилам, определенным Microsoft для каждого из объектов ядра. Так, объекты ядра «процесс» сразу после создания всегда находятся в занятом состоянии. В момент завершения процесса операционная система автоматически освобождает его объект ядра «процесс», и он навсегда остается в этом состоянии.
Объект ядра «процесс» пребывает в занятом состоянии, пока выполняется сопоставленный с ним процесс, и переходит в свободное состояние, когда процесс завершается. Внутри этого объекта поддерживается булева переменная, которая при создании объекта инициализируется как FALSE («занято»). По окончании работы процесса операционная система меняет значение этой переменной на TRUE, сообщая тем самым, что объект свободен.
Если Вы пишете код, проверяющий, выполняется ли процесс в данный момент, Вам нужно лишь вызвать функцию, которая просит операционную систему проверить значение булевой переменной, принадлежащей объекту ядра «процесс». Тут нет ничего сложного. Вы можете также сообщить системе, чтобы та перевела Ваш поток в состояние ожидания и автоматически пробудила его при изменении значения булевой переменной с FALSE на TRUE. Тогда появляется возможность заставить поток в родительском процессе, ожидающий завершения дочернего процесса, просто заснуть до освобождения объекта ядра, идентифицирующего дочерний процесс. В дальнейшем Вы увидите, что в Windows есть ряд функций, позволяющих легко решать эту задачу. Я только что описал правила, определенные Microsoft для объекта ядра «процесс». Точно такие же правила распространяются и на объекты ядра «поток». Они тоже сразу после создания находятся в занятом состоянии. Когда поток завершается, операционная система автоматически переводит объект ядра «поток» в свободное состояние. Таким образом, используя те же приемы, Вы можете определить, выполняется ли в данный момент тот или иной поток. Как и объект ядра «процесс», объект ядра «поток» никогда не возвращается в занятое состояние.
Ожидаемые таймеры (waitable timers) — это объекты ядра, которые самостоятельно переходят в свободное состояние в определенное время или через регулярные промежутки времени. Чтобы создать ожидаемый таймер, достаточно вызвать функцию CreateWaitableTimer:
HANDLE CreateWaitableTimer(PSECURITY_ATTRIBUTES psa, BOOL fManualReset, PCTSTR pszName);
О параметрах psa и pszName я уже рассказывал в главе 3. Разумеется, любой процесс может получить свой («процессо зависимый») описатель существующего объекта «ожидаемый таймер», вызвав OpenWaitableTimer:
HANDLE OpenWaitableTimer(DWORD dwDesiredAccess, BOOL bInheritHandle, PCTSTR pszName);
По аналогии с событиями параметр fManualReset определяет тип ожидаемого таймера: со сбросом вручную или с автосбросом. Когда освобождается таймер со сбросом вручную, возобновляется выполнение всех потоков, ожидавших этот объект, а когда в свободное состояние переходит таймер с автосбросом — лишь одного из потоков.
Объекты «ожидаемый таймер» всегда создаются в занятом состоянии. Чтобы сообщить таймеру, в какой момент он должен перейти в свободное состояние, вызовите функцию SetWaitableTimer:
BOOL SetWaitableTimer(HANDLE hTimer, const LARGE_INTEGER *pDueTime, LONG lPeriod, PTIMERAPCROUTINE pfnCompletionRoutine, PVOID pvArgToCompletionRoutine, BOOL fResume);
Эта функция принимает несколько параметров, в которых легко запутаться. Очевидно, что hTimer определяет нужный таймер. Следующие два параметра (pDueTime и lPeriod) используются совместно: первый из них задает, когда таймер должен сработать в первый раз, второй определяет, насколько часто это должно происходить в дальнейшем.

29. Структура системного программного интерфейса ОС Windows (Native API). Nt-функции и Zw-функции в пользовательском режиме и режиме ядра ОС Windows.
Все функции ядра Windows, доступные пользовательским приложениям, экспортируются библиотекой NtDll.dll. Системные функции называются Native API.
Native API - в основном недокументированный интерфейс программирования приложений (API), предназначенный для внутреннего использования в операционных системах семейства Windows NT, выпущенных Microsoft. В основном он используется во время загрузки системы, когда другие компоненты Windows недоступны, а также функциями системных библиотек (например, kernel32.dll), которые реализуют функциональность Windows API. Точкой входа программ, использующих Native API является функция DriverEntry(), так же как и в драйверах устройств Windows.
Как уже ранее упоминалось, пользовательские приложения не вызывают напрямую системные службы Windows. Вместо этого ими используется одна или несколько DLL-библиотек подсистемы. Эти библиотеки экспортируют документированный интерфейс, который может быть использован программами, связанными с данной подсистемой. Например, API-функции Windows реализованы в DLL-библиотеках подсистемы Windows, таких, как Kernel32.dll, Advapi32.dll, User32.dll и Gdi32.dll.
Ntdll.dll является специальной библиотекой системной поддержки, предназначенной, главным образом, для использования DLL-библиотек подсистем. В ней содержатся функции двух типов:
функции-заглушки, обеспечивающие переходы от диспетчера системных служб к системным службам исполняющей системы Windows;
вспомогательные внутренние функции, используемые подсистемами, DLL-библиотеками подсистем и другими исходными образами.
Первая группа функций предоставляет интерфейс к службам исполняющей системы Windows, которые могут быть вызваны из пользовательского режима. К этой группе относятся более чем 400 функций, среди которых NtCreateFile, NtSetEvent и т. д. Как уже отмечалось, основная часть возможностей, присущих данным функциям, доступна через Windows API. Но некоторые возможности недоступны и предназначены для использования только внутри операционной системы.
Для каждой из этих функций в Ntdll содержится точка входа с именем, совпадающим с именем функции. Код внутри функции содержит зависящую от конкретной архитектуры инструкцию, осуществляющую переход в режим ядра для вызова диспетчера системных служб, который после проверки ряда параметров вызывает настоящую системную службу режима ядра, реальный код которой содержится в файле Ntoskrnl.exe.
Исполняющая система Windows находится на верхнем уровне файла Ntoskrnl.exe. (Ядро составляет его нижний уровень.)
Системные функции имеют префикс Nt, например NtReadFile. В режиме ядра дополнительно существуют парные функции с  префиксом Zw, например ZwReadFile. Они вызываются  драйверами вместо Nt-функций. В пользовательском режиме Zw-имена тоже объявлены, но эквивалентны Nt-именам.
Если Nt-функция вызывается внутри ядра:
Проверка параметров не выполняется.
Такая функция может быть недоступна в ядре, т.е. может не экспортироваться модулем Ntoskrnl.exe.
Вызов Nt-функции с передачей ей указателей на память ядра закончится ошибкой.
Вместо Nt-функций модули ядра вызывают Zw-функции.
Zw-функция делает следующее:
Загружает в регистр EAX номер функции.
Загружает в регистр EDX указатель на вершину параметров в стеке ядра.
Вызывает соответствующую ей Nt-функцию. При этом проверка параметров не выполняется.

30. Системный вызов ОС Windows. Алгоритм системного вызова. Особенность системного вызова из режима ядра.
Систе́мный вы́зов (англ. system call) - обращение прикладной программы к ядру операционной системы для выполнения какой-либо операции (механизм, позволяющий пользовательским программам обращаться к услугам ядра ОС; интерфейс между операционной системой и пользовательской программой). С точки зрения программиста, системный вызов обычно выглядит, как вызов подпрограммы или функции из системной библиотеки. Ядро ОС исполняется в привилегированном режиме работы процессора. Для выполнения межпроцессорной операции или операции, требующей доступа к оборудованию, программа обращается к ядру, которое, в зависимости от полномочий вызывающего процесса, исполняет либо отказывает в исполнении такого вызова.
Алгоритм системного вызова:
1. Загрузить в регистр EAX номер Nt-функции.
2. Загрузить в регистр EDX указатель на вершину параметров в стеке (ESP).
3. Вызвать прерывание для перехода процессора в режим ядра
4. Если используется прерывание, то вызывается обработчик прерывания
5. Если используется специальная инструкция (sysenter или syscall), то происходит вызов функции, адрес которой хранится в специальном внутреннем регистре процессора
6. После перехода в режим ядра все параметры, передаваемые в Nt-функцию, находятся на стеке ПР.
7. По номеру функции в регистре EAX отыскать в nt!KiArgumentTable количество байтов, занимаемое параметрами на стеке.
8. Скопировать параметры со стека ПР на стек ядра.
9. По номеру функции в регистре EAX отыскать в nt!KiServiceTable адрес функции для вызова. 10. Выполнить вызов функции..
11. Если функция вызвана из ПР, выполняется проверка параметров.
12. Вернуться из режима ядра в ПР Процессор восстанавливает из стека сохраненные значения регистров ПР и продолжает исполнение со следующей инструкции.
Системный вызов внутри ядра
Если Nt-функция вызывается внутри ядра: 1. Проверка параметров не выполняется. 2. Такая функция может быть недоступна в ядре, т.е. может не экспортироваться модулем Ntoskrnl.exe. 3. Вызов Nt-функции с передачей ей указателей на память ядра закончится ошибкой.
Если вместо Nt-функций модули ядра вызывают Zw-функцию, она: 1. Загружает в регистр EAX номер функции. 2. Загружает в регистр EDX указатель на вершину параметров в стеке ядра. 3. Вызывает соответствующую ей Nt-функцию. При этом проверка параметров не выполняется.

31. Отладка драйверов ОС Windows. Средства отладки драйверов. Посмертный анализ. Живая отладка.
Средства отладки драйверов:
Поддержка отладки ядра обеспечивается самим ядром Windows. Включается: bcdedit /debug on
В процессорах архитектуры x86 имеются специальные отладочные регистры DR0-DR7. Они позволяют отладчику ставить контрольные точки на чтение и запись памяти, а также на порты ввода-вывода.
Традиционный отладчик с пользовательским интерфейсом – windbg.exe.
Отладчик командной строки – kd.exe.
Современное средство отладки: Visual Studio 2013 Professional + WDK 8.1.Начиная с Windows Vista, обеспечивается создание ряда драйверов, работающих в пользовательском режиме. Для отладки применяется Visual Studio.
Посмертный анализ (postmortem analysis):
Включить в операционной системе создание дампов памяти:Start->Control Panel->System->Advanced system settings->Advanced tab->Startup and Recovery->Settings->Write debugging information: Small memory dump (256 KB) или Kernel memory dump.
Включить отладку в ядре: bcdedit /debug on
Настроить канал связи отладчика с ядром: bcdedit /dbgsettings
В отладчике включить загрузку символьной информации о ядре Windows: Tools->Options->Debugging->Symbols->[x] Microsoft Symbol Servers.
Открыть файл C:\Windows\MEMORY.DMP в отладчике.Живая отладка (live debugging):
Соединить два компьютера через один из следующих интерфейсов: Serial, IEEE 1394, USB 2.0.Включить отладку в ядре: bcdedit /debug on
Настроить канал связи отладчика с ядром: bcdedit /dbgsettings
В отладчике включить загрузку символьной информации о ядре Windows: Tools->Options->Debugging->Symbols->[x] Microsoft Symbol Servers.
В Visual Studio собрать драйвер.
Поставить контрольную точку в исходном коде и установить драйвер.

32.Структуры данных общего назначения в режиме ядра ОС Windows. Представление строк стандарта Unicode. Представление двусвязных списков.
UNICODE_STRING: Ядро Windows хранит строки в формате Unicode. Строки, передаваемые функциям ядра, находятся почти всегда в формате Unicode.
struct UNICODE_STRING{ USHORT Length; USHORT MaximumLength; PWSTR Buffer; };
Буфер, на который указывает поле Buffer, обычно выделяется из пула подкачиваемой страничной памяти.
Поле Length содержит число байтов (не WCHARS). Завершающий символ UNICODE_NULL в это число не включен.

LIST_ENTRY:Большинство структур данных ядра хранятся как части двусвязных списков.
struct LIST_ENTRY{ LIST_ENTRY* Flink; LIST_ENTRY* Blink;};
Поля Flink и Blink в структуре LIST_ENTRY указывают на вложенную структуру LIST_ENTRY, а не на начало элемента списка.
Структуры LIST_ENTRY никогда не содержат нулевых указателей. Когда список пуст, поля Flink и Blink в голове списка ListHead указывают непосредственно на ListHead.

33. Механизм прерываний ОС Windows. Аппаратные и программные прерывания. Понятие прерывания, исключения и системного вызова. Таблица векторов прерываний (IDT).
Прерывания представляют собой механизм позволяющий координировать параллельное функционирование отдельных устройств вычислительной системы и реагировать на особые состояния возникающие при работе процессора. Прерывания– это принудительная передача управления от выполняющейся программы к системе, а через неё к соответствующей программе обработки прерываний,происходящая при определенном событии. Основная цель введения прерываний –реализация асинхронного режима работы и распараллеливания работы отдельных устройств вычислительного комплекса. Механизм прерываний реализуется аппаратно-программными средствами. В зависимости от источника возникновения сигнала прерывания делятся на: асинхронные или внешние (аппаратные) — события, которые исходят от внешних источников (например, периферийных устройств) и могут произойти в любой произвольный момент: сигнал от таймера, сетевой карты или дискового накопителя, нажатие клавиш клавиатуры, движение мыши; внутренние — события в самом процессоре как результат нарушения каких-то условий при исполнении машинного кода: деление на ноль или переполнение, обращение к недопустимым адресам или недопустимый код операции; программные (частный случай внутреннего прерывания) — инициируются исполнением специальной инструкции в коде программы. Программные прерывания как правило используются для обращения к функциям встроенного программного обеспечения Структуры систем прерываний могут быть самыми различными, но все они имеют общую особенность – прерывание непременно ведет за собой изменение порядка выполнения команд процессором. Механизм обработки прерываний включает в себя следующие элементы 1. Установление факта прерывания (прием и идентификация сигнала на прерывание). 2. Запоминание состояния прерванного процесса (состояние процесса определяется значением счетчика команд, содержимым регистра процессора, спецификацией режима: пользовательский или привилегированный) 3. Управление аппаратно передается программе обработки прерывания. В этом случае, в счетчик команд заносится начальный адрес подпрограммы обработки прерывания, а в соответствующие регистры из слова состояния. 4. Сохранение информации прерванной программе, которую не удалось спасти с помощью действий аппаратуры. 5. Обработка прерывания. Работа может быть выполнена той же подпрограммой, которой было передано управление на 3-ем шаге, но в ОС чаще всего эта обработка реализуется путем вызова соотв. подпрограммы. 6. восстановление информации относящейся к прерванному процессу. 7. Возврат в прерванную программу. Первые 3 шага реализуются аппаратными средствами, а остальные – программно. Главные функции механизма прерывания: 1. Распознавание или классификация прерывания. 2. Передача управления обработчику прерывания. 3. Корректное возвращение к прерванной программе Переход от прерванной программе к обработчику и обратно должен производится как можно быстрее. Одним из быстрых методов является использование таблицы сод.перечень всех допустимых для компьютера прерываний и адреса соотв.обработчиков. Для корректного возвращения к прерванной программе, перед передачей управления обработчику, содержимое регистров процессора запоминается либо в памяти с прямым доступом либо в системном стеке. Исключительная ситуация (exception) - событие, возникающее в результате попытки выполнения программой команды, которая по каким-то причинам не может быть выполнена до конца. Системные вызовы (system calls) - механизм, позволяющий пользовательским программам обращаться к услугам ядра ОС, то есть это интерфейс между операционной системой и пользовательской программой.

34.Аппаратные прерывания. Программируемый контроллер прерываний. Механизм вызова прерываний. Обработка аппаратных прерываний. Понятие приоритета прерываний (IRQL). Понятие процедуры обработки прерываний (ISR).
Таблица прерываний - Для того чтобы связать адрес обработчика прерывания с номером прерывания, используется таблица векторов прерываний, занимающая первый килобайт оперативной памяти - адреса от 0000:0000 до 0000:03FF. Таблица состоит из 256 элементов - FAR-адресов обработчиков прерываний. Эти элементы называются векторами прерываний. В первом слове элемента таблицы записано смещение, а во втором - адрес сегмента обработчика прерывания.Прерыванию с номером 0 соответствует адрес 0000:0000, прерыванию с номером 1 - 0000:0004 и т.д. Для программиста, использующего язык Си, таблицу можно описать следующим образом: void (* interrupt_table[256])(); Инициализация таблицы происходит частично BIOS после тестирования аппаратуры и перед началом загрузки операционной системой, частично при загрузке DOS. DOS может переключить на себя некоторые прерывания BIOS.
0 – ошибка деления. 1 – пошаговое прерывание(для отладки). 2 – аппаратное немаскируемое прерывание. 3 – для трассировки(обычно отладчиками для установки точки прерыв.). 4 – Переполнение. 5 – печать копии экрана(prtScr). 6 – неопред. код операции. 7 – отсутсвие мат.сопроцессора(особ.случай). 8 – IRQ0-интервальный таймер(18.2 раза/сек). 9-IRQ1 – клавиатурные прерывания. A – IRQ2- каскадирование аппаратных прерываний для AT-машин. B – IRQ3 – Com2 прерывания. C – IRQ4 – COM1 прерывания. D – IRQ5 – прер. От контроллера жесткого диска для XT. E – IRQ6 – прер. флоппи-диск после завершения. F – принтер-прер. 10 – обслуж. Видеоадаптера. 11 – определение конфиг.устройств в системе. 12 – Определ.размера RAM. 13 – обслуж.дисков. 14 – послед I/O. 16 – клавиатура. 17 – принтер. 18 – запуск бейсика в ПЗУ, если есть. 19 – загрузка ОС.
Прерывание (Interrupt) – сигнал, сообщающий процессору о наступлении какого-либо события. При этом выполнение текущей последовательности команд приостанавливается и управление передаётся процедуре обработки прерывания, соответствующая данному событию, после чего исполнение кода продолжается ровно с того места где он был прерван (возвращение управления). Процедура обработки прерывания (Interrupt Service Routine) – это ни что иное как функция/подпрограмма, которую следует выполнить при возникновении определенного события. Будем использовать именно слово “процедура”, для того чтобы подчеркнуть ее отличие от всех остальных функций.
Главное отличие процедуры от простых функций состоит в том что вместо обычного “возврата из функции” (ассемблерная команда RET), следует использовать “возврат из прерывания” (ассемблерная команда RETI) – “RETurn from Interrupt“.Прототип процедуры обработки прерывания
Чтобы объявить некоторую функцию в качестве процедуры обработки того или иного прерывания, необходимо следовать определенным правилам прототипирования, чтобы компилятор/компоновщик смогли правильно определить и связать нужное вам прерывание с процедурой ее обработки. Во первых процедура обработки прерывания не может ничего принимать в качестве аргумента (void), а также не может ничего возвращать (void). Это связано с тем что все прерывания в AVR асинхронные, поэтому не известно в каком месте будет прервано исполнение программы, у кого принимать и кому возвращать значение, а также для минимизации времени входа и выхода из прерывания. void isr(void) Во вторых, перед прототипом функции следует указать что она является процедурой обработки прерывания. Как вам известно, в языке Си исполняется только тот код что используется в функции main. Поскольку процедура обработки прерывания в функции main нигде не используется, то для того чтобы компилятор не “выкинул” ее за ненадобностью, перед прототипом процедуры следует указать что эта функция является процедурой обработки прерывания.

35. Понятие приоритета прерываний (IRQL). Приоритеты прерываний для процессора x86 или x64. Процедура обработки прерываний (ISR). Схема обработки аппаратных прерываний.
Приоритеты прерываний – Interrupt Request Levels (IRQLs):
Прерывания обрабатываются в порядке приоритетов. Прерывание с более высоким приоритетом может прервать обработчик прерывания с более низким приоритетом. Все запросы на прерывание более низкого приоритета маскируются контроллером до завершения обработки всех более приоритетных прерываний. Затем, если менее приоритетные прерывания происходили, они материализуются контроллером. Это происходит от более приоритетных прерываний к менее приоритетным.
Когда процессор обслуживает прерывание, считается, что он находится на уровне приоритета прерывания. На много-процессорных системах каждый процессор может находиться на своем IRQL. Текущий Lazy IRQL процессора хранится в области управления процессором – Processor Control Region (PCR) и его расширенной части – Processor Control Block (PRCB). См. структуру KPCR.Prcb.
Для процессоров x86 установлено 32 приоритета, для процессоров x64 –15 приоритетов (см. таблицу IRQL). Низший приоритет 0 (PASSIVE_LEVEL) обозначает работу вне обработчика прерываний.
Код режима ядра может менять IRQL процессора с помощью функций KeRaiseIrql() и KeLowerIrql(), расположенных в HAL. Обычно это происходит неявно при вызове обработчиков прерываний. Обработчик прерывания поднимает уровень прерывания перед началом работы и опускает уровень в конце работы. В реализации функций KeRaiseIrql() и KeLowerIrql() используется оптимизация под названием Lazy IRQL.
Другие полезные функции IRQL API: KeGetCurrentIrql(), KeRaiseIrqlToDpcLevel().

36. Программные прерывания. Понятие отложенной процедуры (DPC). Назначение отложенных процедур. Механизм обслуживания отложенных процедур. Операции с отложенными процедурами.
Процедуры обработки прерываний (ISRs), работающие с высоким уровнем приоритета (IRQL), могут блокировать выполнение других процедур обработки прерываний с более низким приоритетом. Это увеличивает долю системных операций в общем времени работы приложений, т.е. увеличивает задержку (latency) в системе. Для разрешения такого типа проблем, программный код, предназначенный для работы в режиме ядра, должен быть сконструирован таким образом, чтобы избегать продолжительной работы при повышенных уровнях IRQL. Одним из самых важных компонентов этой стратегии являются Deferred Procedure Calls (DPC) — отложенные процедурные вызовы. Они представляется структурой ядра KDPC, в которой хранится адрес callback-процедуры, составляющей подпрограмму DPC.
Схема применения отложенных процедурных вызовов позволяет построить процесс выполнения таким образом, что задача может быть запланирована кодом, работающим на высоком уровне IRQL, но при этом еще не выполняется. Такая отсрочка выполнения применима, когда обработка данной ситуации может быть безболезненно перенесена на более позднее время. В таком случае процедура обработки прерываний выполняет абсолютный минимум работ с высоким уровнем приоритета. Для учета заявок на вызов DPC процедур операционная система поддерживает очередь объектов DPC (т.е. ОС ставит в очередь к процессору отложенную процедуру для выполнения работы на уровне приоритета DPC_LEVEL / DIPATCH_LEVEL; при постановке DPC в очередь, указывается один из трех приоритетов: Low, Medium – в конец очереди, High – в начало очереди), что позволяет системе быстро обработать другие прерывания. Объект DPC для использования в процедурах обработки прерываний создается по вызову IoInitializeDpcRequest, выполняемому обычно в стартовых процедурах драйвера. Данный вызов регистрирует предлагаемую драйвером DpcForIsr процедуру и ассоциирует ее с создаваемым объектом (DPC объект, созданный данным вызовом, останется недоступным разработчику драйвера; отличие DpcForIsr от других DPC-процедур состоит только в том, что работа с последними проходит при помощи вызовов Ke...Dpc , т.е. при вызове KeInitializeDpc(), KeInsertQueueDpc(), KeRemoveQueueDpc(), KeSetTargetProcessorDpc(), KeSetImportanceDpc(), KeFlushQueuedDpcs(); создаваемые для них DPC объекты доступны разработчику драйвера). Если драйвер зарегистрировал свою процедуру DpcForIsr, то во время обработки прерывания ISR процедурой в системную очередь DPC может быть помещен соответствующий DPC объект (запрос на вызов этой DpcForIsr процедуры позже) при помощи вызова IoRequestDpc. Процедура DpcForIsr завершит позже обработку полученного ISR процедурой запроса, что будет выполнено в менее критичных условиях и при низком уровне IRQL.
170815924560Функционирование DPC процедур: 1. Когда некоторый фрагмент программного кода, работающий на высоком (аппаратном) уровне IRQL желает запланировать выполнение части своей работы так, чтобы она была выполнена при низком значении IRQL, то он добавляет DPC объект в системную очередь отложенных процедурных вызовов. 2. Когда значение IRQL процессора падает ниже DISPATCH_LEVEL, работа, которая была отложена прерыванием, обслуживается DPC функцией. Диспетчер DPC извлекает каждый DPC объект из очереди и вызывает соответствующую функцию, указатель на которую хранится в этом объекте (вызов выполняется в то время, когда процессор работает на уровне DISPATCH_LEVEL). 3. Отложенная процедура выполняется на уровне прерываний DPC_LEVEL / DIPATCH_LEVEL на том же процессоре, что и вызывающая ISR, или на заданном процессоре.

37. Понятие асинхронной процедуры (APC). Назначение асинхронных процедур. Типы асинхронных процедур. Операции с асинхронными процедурами.
1)Как и DPC, применяется для выполнения отложенных действий.
2)Выполняется на уровне прерываний APC_LEVEL или PASSIVE_LEVEL в контексте заданного потока, и соотв., в виртуальном адресном пространстве процесса, которому принадлежит поток.
3)не подвержена ограничениям DPC-процедур, может захватывать объекты ядра, выполнять ожидания объектов, обращаться к отсутствующим страницам памяти, делать системные вызовы.
APC-процедура представляется стр-рой ядра KAPC, кот. содержит указатели на 3 подпрограммы:
1) RundownRoutine – выполняется, если из-за удаления потока удаляется структура KAPC.
2) KernelRoutine – выполняется на уровне приоритета APC_LEVEL.
3) NormalRoutine – выполняется на уровне приоритета PASSIVE_LEVEL.
Стр-ра KAPC создается и ставится в одну из двух очередей потока: одна очередь предназначена для APC режима ядра, вторая – для APC пользовательского режима. Начала очередей находятся в массиве из двух элементов: KTHREAD.ApcState.ApcListHead[].
Специальная APC-процедура режима ядра:
- KAPC.KernelRoutine выполняется на уровне приоритета APC_LEVEL.
- KAPC.NormalRoutine == NULL.
- Помещается в очередь APC режима ядра после других специальных APC.
- Вызывается перед нормальными APC режима ядра.
- Вызывается, если IRQL == PASSIVE_LEVEL и поток не находится в защищенной секции (guarded region) – KTHREAD.SpecialApcDisable != 0.
- APC не может захватить блокировку, работающую на IRQL == 0.
- используется для завершения процесса, для передачи результатов ввода-вывода в адресное пространство потока.
Нормальная APC-процедура режима ядра:
- KAPC.NormalRoutine выполняется на уровне приоритета PASSIVE_LEVEL.
- Вызывается, если IRQL == PASSIVE_LEVEL, поток не находится в защищенной или критической секции (critical region) – KTHREAD.KernelApcDisable != 0, и не выполняет специальную APC ядра.
- Нормальной APC разрешено делать все системные вызовы.
- Норм.APC исп-тся ОС для завершения обработки запроса от драйвера – Interrupt Request Packet.
APC-процедура пользовательского режима:
- KAPC.NormalRoutine выполняется на уровне приоритета PASSIVE_LEVEL.
- Вызывается, только если поток ожидает объект ядра в alertable-режиме, например WaitForSingleObjectEx(…, true), WaitForMultipleObjectsEx(…, true), SleepEx(…, true).
- Создается вызовом процедуры QueueUserApc().
- Используется ОС, чтобы выполнить в пользовательском режиме подпрограмму завершения асинхронного ввода-вывода – I/O Completion Routine.
- Поле KAPC.KernelRoutine может содержать адрес дополнительной подпрограммы, выполняемой на уровне приоритета IRQL == APC_LEVEL перед выполнением подпрограммы KAPC.NormalRoutine. Эта подпрограмма выполняется только тогда, когда поток ожидает объект ядра в alertable-режиме.

38. Понятие асинхронной процедуры (APC). Асинхронные процедуры режима ядра: специальная и нормальная APC-процедуры. Асинхронные процедуры пользовательского режима.
1)Как и DPC, применяется для выполнения отложенных действий.
2)Выполняется на уровне прерываний APC_LEVEL или PASSIVE_LEVEL в контексте заданного потока, и соотв., в виртуальном адресном пространстве процесса, которому принадлежит поток.
3)не подвержена ограничениям DPC-процедур, может захватывать объекты ядра, выполнять ожидания объектов, обращаться к отсутствующим страницам памяти, делать системные вызовы.
APC-процедура представляется стр-рой ядра KAPC, кот. содержит указатели на 3 подпрограммы:
1) RundownRoutine – выполняется, если из-за удаления потока удаляется структура KAPC.
2) KernelRoutine – выполняется на уровне приоритета APC_LEVEL.
3) NormalRoutine – выполняется на уровне приоритета PASSIVE_LEVEL.
Стр-ра KAPC создается и ставится в одну из двух очередей потока: одна очередь предназначена для APC режима ядра, вторая – для APC пользовательского режима. Начала очередей находятся в массиве из двух элементов: KTHREAD.ApcState.ApcListHead[].
Специальная APC-процедура режима ядра:
- KAPC.KernelRoutine выполняется на уровне приоритета APC_LEVEL.
- KAPC.NormalRoutine == NULL.
- Помещается в очередь APC режима ядра после других специальных APC.
- Вызывается перед нормальными APC режима ядра.
- Вызывается, если IRQL == PASSIVE_LEVEL и поток не находится в защищенной секции (guarded region) – KTHREAD.SpecialApcDisable != 0.
- APC не может захватить блокировку, работающую на IRQL == 0.
- используется для завершения процесса, для передачи результатов ввода-вывода в адресное пространство потока.
Нормальная APC-процедура режима ядра:
- KAPC.NormalRoutine выполняется на уровне приоритета PASSIVE_LEVEL.
- Вызывается, если IRQL == PASSIVE_LEVEL, поток не находится в защищенной или критической секции (critical region) – KTHREAD.KernelApcDisable != 0, и не выполняет специальную APC ядра.
- Нормальной APC разрешено делать все системные вызовы.
- Норм.APC исп-тся ОС для завершения обработки запроса от драйвера – Interrupt Request Packet.
APC-процедура пользовательского режима:
- KAPC.NormalRoutine выполняется на уровне приоритета PASSIVE_LEVEL.
- Вызывается, только если поток ожидает объект ядра в alertable-режиме, например WaitForSingleObjectEx(…, true), WaitForMultipleObjectsEx(…, true), SleepEx(…, true).
- Создается вызовом процедуры QueueUserApc().
- Используется ОС, чтобы выполнить в пользовательском режиме подпрограмму завершения асинхронного ввода-вывода – I/O Completion Routine.
- Поле KAPC.KernelRoutine может содержать адрес дополнительной подпрограммы, выполняемой на уровне приоритета IRQL == APC_LEVEL перед выполнением подпрограммы KAPC.NormalRoutine. Эта подпрограмма выполняется только тогда, когда поток ожидает объект ядра в alertable-режиме.

39. Понятие элемента работы (Work Item). Назначение элементов работы. Операции с элементами работы. Очереди элементов работы. Обслуживание элементов работы.
Механизм выполнения асинхронных действий в контексте системного потока на уровне приоритета PASSIVE_LEVEL.
Представляется переменной типа IO_WORKITEM. Создается вызовом IoAllocateWorkItem(), освобождается вызовом IoFreeWorkItem().
Если драйвер сам выделяет место под структуру IO_WORKITEM, память должна быть не подкачиваемой (non-paged), и драйвер должен ее инициализировать и де-инициализировать вызовами IoInitializeWorkItem() и IoUninitializeWorkItem(). Размер памяти, требуемой для размещения структуры, возвращает IoSizeofWorkItem().
Чтобы поставить элемент работы в очередь, вызывается IoQueueWorkItem() или IoQueueWorkItemEx(). Один и тот же элемент нельзя ставить в очередь дважды.
void WorkItemEx(void* IoObject, void* Context, IO_WORKITEM* WorkItem) – процедура программиста, вызываемая операционной системой для обработки элемента работы. Когда работает процедура, элемент работы изъят из очереди. Его можно опять поставить в очередь.
Вместо создания элемента работы, драйвер может создать системный поток вызовом PsCreateSystemThread(). Но это затратный способ.
При вызове IoQueueWorkItem указывается очередь:
DelayedWorkQueue – очередь 7-16 обычных потоков с приоритетом 12 и страничным стеком.
CriticalWorkQueue – очередь 5-16 потоков реального времени с приоритетом 13 и резидентным стеком.
HyperCriticalWorkQueue – очередь 1 потока реального времени с приоритетом 15. Применяется для удаления завершенных потоков.
914407048500

40. Управление памятью в ОС Windows. Менеджер памяти. Виртуальная память процесса. Управление памятью в пользовательском режиме. Страничная виртуальная память. Куча (свалка, heap). Проецирование файлов в память.
Менеджер памяти (Memory Manager) выполняет две задачи:
Отображение виртуальных адресов в физические.
Страничная организация памяти с отображением страниц на диск.
Аппаратная поддержка:
В процессоре имеется Memory Management Unit (MMU) – устройство, выполняющее трансляцию виртуальных адресов в физические.
Виртуальная память процесса:
От 2 ГБ до 2 ТБ.
Кратна 64 КБ – гранулярность памяти пользовательского режима. Информацию о гранулярности можно получить с помощью GetSystemInfo().
Часть виртуальной памяти процесса, которая находится резидентно в физической памяти, называется рабочим набором – Working Set. Диапазон рабочего набора устанавливается функцией SetProcessWorkingSetSize(). Стандартный минимальный рабочий набор – 50 страниц по 4 КБ (200 КБ), стандартный максимальный рабочий набор – 345 страниц по 4 КБ (1380 КБ).
Конфигурация менеджера памяти в реестре:
HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management
Страничная виртуальная память:
Выделение: VirtualAlloc(), VirtualAllocEx(), VirtualAllocExNuma(), VirtualFree(), VirtualFreeEx(). Гранулярность в user mode – 64 КБ.
Защита страниц: VirtualProtect(), VirtualProtectEx().
Фиксация страниц в физической памяти: VirtualLock(), VirtualUnlock().
Информация: VirtualQuery(), VirtualQueryEx().
Куча (свалка) – Heap:
Создание: HeapCreate(), HeapDestroy().
Выделение: HeapAlloc(), HeapReAlloc(), HeapSize(), HeapFree(). Гранулярность – 8 байтов на x86, 16 байтов на x64.
Информация: HeapValidate(), HeapWalk(), HeapQueryInformation(), HeapSetInformation().
Кучи процесса: GetProcessHeap() – стандартная куча равная 1 MB, GetProcessHeaps() – все кучи процесса.
Отображение файлов в память – File Mapping:
Объект ядра, описывающий отображение фрагмента файла в диапазон виртуальных адресов, называется разделом (Section Object).

41. Управление памятью в пользовательском режиме ОС Windows. Оптимизация работы кучи с помощью списков предыстории (Look-aside Lists) и низко-фрагментированной кучи (Low Fragmentation Heap).
Списки предыстории – Look-aside Lists:
Применяются менеджером кучи для выделения-освобождения элементов фиксированного размера. В ядре могут явно применяться драйверами.
Представлены в виде 128 связных списков свободных блоков. Каждый список содержит элементы строго определенного размера – от 8 байтов до 1 КБ на x86 и от 16 байтов до 2 КБ на x64.
Когда блок памяти освобождается, он помещается в список предыстории, соответствующий его размеру. Затем, если запрашивается блок памяти такого же размера, он берется из списка предыстории методом LIFO. Для организации списка предыстории используются функции InterlockedPushEntrySList() и InterlockedPopEntrySList().
Раз в секунду ОС уменьшает глубину списков предыстории с помощью функции ядра KiAdjustLookasideDepth().
Низко-фрагментированная куча – Low Fragmentation Heap:
Включается с помощью HeapSetInformation().
Уменьшает фрагментацию памяти за счет хранения в списках предыстории элементов одного размера вместе.
Улучшает масштабируемость на многопроцессорных системах путем поддержания количества внутренних структур данных равным количеству процессоров в системе, умноженному на 2.

42. Структура виртуальной памяти в ОС Windows. Виды страниц. Состояния страниц. Структура виртуального адреса. Трансляция виртуального адреса в физический. Кэширование виртуальных адресов.
Виды и состояния страниц
Виртуальная память состоит из двух типов страниц:
Малые страницы – 4 КБ. Большие страницы – 4 МБ на x86 или 2 МБ на x64. Большие страницы используются для Ntoskrnl.exe, Hal.dll, данных ядра, описывающих резидентную память ядра и состояние физических страниц памяти.
При вызове VirtualAlloc() можно указать флаг MEM_LARGE_PAGE. Для всей страницы применяется единый режим защиты и блокировки памяти.
Страницы в виртуальном адресном пространстве процесса могут быть свободными (free), зарезервированными (reserved), подтвержденными (committed) или общими (shareable).
Подтвержденными и общими являются страницы, при обращении к которым в итоге происходит преобразование с указанием настоящих страниц в физической памяти. Подтвержденные страницы называются также закрытыми (private) — это название отражает тот факт, что они, в отличие от общих страниц, не могут использоваться  совместно с другими процессами (а могут, разумеется, использоваться только одним процессом).
Закрытые страницы выделяются с помощью Windows-функций VirtualAlloc, VirtualAllocEx и VirtualAllocExNuma. Эти функции позволяют программному потоку резервировать адресное пространство, а затем подтверждать части зарезервированного пространства.
Если к подтвержденным (закрытым) страницам до этого еще не было обращений, они создаются во время первого обращения в качестве страниц, подлежащих заполнению нулевыми байтами. Закрытые (подтвержденные) страницы могут быть позже автоматически записаны операционной системой в страничный файл (файл подкачки), если это потребуется для удовлетворения спроса.
При первом обращении к общей странице со стороны какого-нибудь процесса она считывается из связанного отображаемого файла (если только раздел не связан с файлом подкачки, тогда страница создается заполненной нулевыми байтами). Позже, если она все еще находится в физической памяти, то есть является резидентной (resident), при повторном и последующих обращениях процессов можно просто использовать то же самое содержимое страницы, которое уже находится в памяти.
Общие страницы могут также заранее извлекаться из памяти самой системой.
Структура виртуального адреса
Номер таблицы страниц в каталоге таблиц (Page directory index - Page Directory Entry).
Номер страницы в таблице страниц (Page table index - Page Table Entry).
Смещение в странице – Byte index.
Трансляция виртуального адреса в физическийТрансляция виртуального адреса – это определение реального (физического) расположение ячейки памяти с данным виртуальным адресом, т. е. преобразование виртуального адреса в физический.
Информация о соответствии виртуальных адресов физическим хранится в таблицах страниц. В системе для каждого процесса поддерживается множество записей о страницах:
Таблицы страниц хранятся в виртуальной памяти. Информация о расположении каждой из таблиц страниц находится в каталоге страниц (Page Directory), единственном для процесса. Записи этого каталога называются PDE (Page Directory Entry). Таким образом, процесс трансляции является двухступенчатым: сначала по виртуальному адресу определяется запись PDE в каталоге страниц, затем поэтой записи находится соответствующая таблица страниц, запись PTE которой указывает на требуемую страницу в физической памяти.
Кэширование виртуальных адресов
Буфер ассоциативной трансляции (TLB) — это специализированный кэш центрального процессора, используемый для ускорения трансляции адреса виртуальной памяти в адрес физической памяти. TLB используется всеми современными процессорами с поддержкой страничной организации памяти. TLB содержит фиксированный набор записей (от 8 до 4096) и является ассоциативной памятью. Каждая запись содержит соответствие адреса страницы виртуальной памяти адресу физической памяти.

43. Управление памятью в режиме ядра ОС Windows. Пулы памяти. Выделение и освобождение памяти в пулах памяти. Структура описателя пула памяти. Доступ к описателям пулов памяти на однопроцессорной и многопроцессорной системах. 
Пул памяти (Memory Pool) – динамически расширяемая область виртуальной памяти в режиме ядра, в которой драйверы и ядро выделяют для себя память.
Существуют два типа пулов памяти:
1.       Пул резидентной памяти (Non-Paged Pool), в ядре один.
2.       Пул страничной памяти (Paged Pool). На многопроцессорных системах в ядре 5 страничных пулов, на однопроцессорных системах – 3 пула.
Дополнительно операционная система создает и поддерживает:
1.       Страничный пул сеансовой памяти (Session Pool).
2.       Специальный отладочный пул (Special Pool), состоящий из резидентной и страничной памяти.
3.       Пул резидентной памяти, защищенный от исполнения кода (No-Execute Non-Paged Pool – NX Pool). Начиная с Windows 8, все драйверы должны держать резидентные данные именно в этом пуле.
Резидентный и страничные пулы растут до установленного максимума:
1.           Non-Paged Pool – 256 МБ на x86, 128 ГБ на x64.
2.       Paged Pool – 2 ГБ на x86, 128 ГБ на x64.
Выделение памяти в пуле:
1.       ExAllocatePoolWithTag(POOL_TYPE PoolType, SIZE_T NumberOfBytes, ULONG Tag);
PoolType – тип выделяемого пула памяти. Определяется с помощью структуры POOL_TYPE.
NumberOfBytes – число выделяемыTag – тэг пула, использующийся для выделенной памяти. Представляет из себя строковый литерал не более 4 символов, заключённых в одиночные кавычки. Например ‘Tag1’, хранится как строка в обратном порядке “1gaT”. Каждый ASCII символ, входящий в тэг должен иметь значение от 0х20 (пробел) до 0х126 (тильда).
ExAllocatePoolWithTag возвращает NULL если в полу недостаточно свободной памяти для удовлетворения запроса. Иначе возвращает указатель на выделенную память.
Если NumberOfBytes имеет значение PAGE_SIZE или большее, то выделяется выровненный по границе страницы буфер. Если меньше, то выделяется буфер без выравнивания по границе страницы и без пересечения границ страниц. Выделение памяти меньше чем PAGE_SIZE не требует выравнивание по границе страницы, но выравнивается по 8-байтовой границе для х32 систем и по 16-байтовой границе для х64 систем.
2.       ExAllocatePoolWithQuota(POOL_TYPE PoolType, SIZE_T NumberOfBytes);
ExAllocatePoolWithQuota возвращает указатель на выделенный участок памяти. Если запрос удовлетворить не удаётся выбрасывается исключение.
При NumberOfBytes больше, меньше или равном PAGE_SIZE работает аналогично с ExAllocatePoolWithTag.
Эта функция вызывается высокоуровневыми драйверами, которые выделяют память для удовлетворения запросов в контексте процесса, выполняющего I/O запрос. Низкоуровневые драйвера используют ExAllocatePoolWithTag.
3.       ExAllocatePoolWithQuotaTag(POOL_TYPE PoolType, SIZE_T NumberOfBytes, ULONG Tag);Возвращает указатель на выделенную память и выбрасывает исключение в случае неудачи, если не определена POOL_QUOTA_FAIL_INSTEAD_OF_RAISE.Используется высокоуровневыми драйверами, которые выделяют память для удовлетворения запросов в контексте процесса, выполняющего I/O запрос. Низкоуровневые драйвера используют ExAllocatePoolWithTag.
4.       ExAllocatePool(POOL_TYPE PoolType, SIZE_T NumberOfBytes);
Возвращает NULL, если невозможно выделить память. В случае успеха возвращает указатель на выделенную память.
5.           ExAllocatePoolWithTagPriority(POOL_TYPE PoolType, SIZE_T NumberOfBytes, ULONG Tag, EX_POOL_PRIORITY Priority);

44. Пулы памяти ОС Windows. Пул подкачиваемой памяти, пул неподкачиваемой памяти, пул сессии, особый пул. Тегирование пулов. Структура данных пула. Выделение и освобождение памяти в пулах памяти. Организация списков свободных блоков в пуле памяти. Заголовок блока пула памяти.
 
Пул памяти (Memory Pool) – динамически расширяемая область виртуальной памяти в режиме ядра, в которой драйверы и ядро выделяют для себя память.
Существуют два типа пулов памяти:
1.       Пул резидентной памяти (пул не подкачиваемой памяти, Non-Paged Pool), в ядре один. Ядро и драйвера устройств используют пул не подкачиваемой памяти для хранения информации, к которой можно получить доступ, если система не может обработать paged fault.
2.       Пул страничной памяти (пул подкачиваемой памяти, Paged Pool). На многопроцессорных системах в ядре 5 страничных пулов, на однопроцессорных системах – 3 пула. Пул подкачиваемой памяти получил своё название из-за того, что Windows может записывать хранимую информацию в файл подкачки, тем самым позволяя повторно использовать занимаемую физическую память. Для пользовательского режима виртуальной памяти, когда драйвер или система ссылается на пул подкачиваемой памяти, который находится в файле подкачки, операция вызывает прерывание и менеджер памяти читает информацию назад в физическую память.
Дополнительно операционная система создает и поддерживает:
1.       Страничный пул сеансовой памяти (Session Pool). Особый страничный пул, в котором располагаются данные сессии.
2.       Специальный отладочный пул (Special Pool), состоящий из резидентной и страничной памяти. Страничный/не страничный с возможностью обнаружения нарушения целостности данных (используется для отладки).
3.       Пул резидентной памяти, защищенный от исполнения кода (No-Execute Non-Paged Pool – NX Pool). Начиная с Windows 8, все драйверы должны держать резидентные данные именно в этом пуле.
Резидентный и страничные пулы растут до установленного максимума:
1.           Non-Paged Pool – 256 МБ на x86, 128 ГБ на x64.
2.       Paged Pool – 2 ГБ на x86, 128 ГБ на x64.
Выделение памяти в пуле:
1.           ExAllocatePoolWithTag(POOL_TYPE PoolType, SIZE_T NumberOfBytes, ULONG Tag);
PoolType – тип выделяемого пула памяти. Определяется с помощью структуры POOL_TYPE.
NumberOfBytes – число выделяемыTag – тэг пула, использующийся для выделенной памяти. Представляет из себя строковый литерал не более 4 символов, заключённых в одиночные кавычки. Например ‘Tag1’, но определяется она обычно в обратном порядке, т. е. ‘1gaT’. Каждый ASCII символ, входящий в тэг должен иметь значение от 0х20 (пробел) до 0х126 (тильда).
ExAllocatePoolWithTag возвращает NULL если в полу недостаточно свободной памяти для удовлетворения запроса. Иначе возвращает указатель на выделенную память.
Если NumberOfBytes имеет значение PAGE_SIZE или большее, то выделяется выровненный по границе страницы буфер. Если меньше, то выделяется буфер без выравнивания по границе страницы и без пересечения границ страниц. Выделение памяти меньше чем PAGE_SIZE не требует выравнивание по границе страницы, но выравнивается по 8-байтовой границе для х32 систем и по 16-байтовой границе для х64 систем.
2.       ExAllocatePoolWithQuota(POOL_TYPE PoolType, SIZE_T NumberOfBytes);
ExAllocatePoolWithQuota возвращает указатель на выделенный участок памяти. Если запрос удовлетворить не удаётся выбрасывается исключение.
При NumberOfBytes больше, меньше или равном PAGE_SIZE работает аналогично с ExAllocatePoolWithTag.

45. Управление памятью в режиме ядра ОС Windows. Оптимизация использования оперативной памяти с помощью списков предыстории – Look-aside Lists.
Пул памяти (Memory Pool) – динамически расширяемая область виртуальной памяти в режиме ядра, в которой драйверы и ядро выделяют для себя память.
Существуют два типа пулов памяти:
1.       Пул резидентной памяти (Non-Paged Pool), в ядре один.
2.       Пул страничной памяти (Paged Pool). На многопроцессорных системах в ядре 5 страничных пулов, на однопроцессорных системах – 3 пула.
Дополнительно операционная система создает и поддерживает:
1.       Страничный пул сеансовой памяти (Session Pool).
2.       Специальный отладочный пул (Special Pool), состоящий из резидентной и страничной памяти.
3.       Пул резидентной памяти, защищенный от исполнения кода (No-Execute Non-Paged Pool – NX Pool). Начиная с Windows 8, все драйверы должны держать резидентные данные именно в этом пуле.
Выделение памяти в пуле:
1.           ExAllocatePoolWithTag(POOL_TYPE PoolType, SIZE_T NumberOfBytes, ULONG Tag);
2.           ExAllocatePoolWithQuota(POOL_TYPE PoolType, SIZE_T NumberOfBytes);
3.           ExAllocatePoolWithQuotaTag(POOL_TYPE PoolType, SIZE_T NumberOfBytes, ULONG Tag);
4.           ExAllocatePool(POOL_TYPE PoolType, SIZE_T NumberOfBytes);
5.           ExAllocatePoolWithTagPriority(POOL_TYPE PoolType, SIZE_T NumberOfBytes, ULONG Tag, EX_POOL_PRIORITY Priority);
Освобождение памяти в пуле:
1.           ExFreePoolWithTag(void* P, ULONG Tag);
2.       ExFreePool(void* P).
Списки предыстории:

На каждый процессор создается набор списков предыстории:
1.           32 списка предыстории на процессор.
2.       В каждом списке – свободные блоки строго определенного размера
от 8 до 256 байтов с гранулярностью 8 (x86).

46. Представление объекта ядра в памяти. Менеджер объектов.
Представление объектов ядра в памяти:
Таблица указателей на объекты ядра размещается в страничном пуле. Каждый элемент таблицы описывается структурой HANDLE_TABLE_ENTRY, в которой содержится режим доступа к объекту и указатель на объект.
Объект хранится в резидентном пуле.
В заголовке объекта хранится указатель на дескриптор защиты объекта, размещающийся в страничном пуле.
Заголовок блока резидентного пула содержит тег, в котором закодирован тип объекта. Например, у файловых объектов тег называется "File". Это удобно при отладке.
(Пул памяти (Memory Pool) – динамически расширяемая область виртуальной памяти в режиме ядра, в которой драйверы и ядро выделяют для себя память. Пул резидентной памяти (Non-Paged Pool), в ядре один.
1524051244500Пул страничной памяти (Paged Pool). На многопроцессорных системах в ядре 5 страничных пулов, на однопроцессорных системах – 3 пул
228600571500Разница их в том что страничный состоит из вирутальной памяти которая мб выгружена в/из системы а резидентный пул состоит из адрессов виртуальной памяти, которые гарантированно находятся в физич. всё время, пока выделен соответсвующий объект ядра)

Менеджер объектов.
Так как структура всех объектов одинакова (объект имеет стандартный заголовок и атрибуты), в ОС Windows, который осуществляет поддержку всех объектов. Заголовок объекта включает в себя имя этого объекта, так что другие процессы могут ссылаться на него по имени, а также дескриптор защиты, с помощью которого менеджер объектов может контролировать какие процессы получили доступ к системному ресурсу.
Задачи, выполняемые менеджером объектов:
Создание объектов
Проверка того, что процесс имеет право на использование объекта
Создание доступа к объекту ядра и возвращение их к вызывающему
Поддержание квоты ресурсов
Закрытие доступа к объектам ядра

47. Фиксация данных в физической памяти ОС Windows. Таблица описания памяти (MDL) и ее использование.
Драйверам необходимо фиксировать данные в физической памяти, чтобы работать с ними на высоких уровнях прерываний. Способы получения физической памяти:
Выделить физически непрерывный блок в резидентном пуле. Дорого!
Выделить физически прерывающийся блок в резидентном пуле.
Выделить блок в страничном пуле и зафиксировать его страницы в физической памяти.
Создать таблицу описания памяти, которая отображает непрерывный блок виртуальной памяти в прерывающийся блок физической памяти. Таблица описания памяти называется Memory Descriptor List (MDL).
Функции для работы с физической памятью:
MmAllocateContiguousMemory(), MmGetPhysicalAddress(), MmLockPageableCodeSection(), MmLockPageableDataSection(), MmLockPageableSectionByHandle(), MmUnlockPageableImageSection(), MmPageEntireDriver(), MmResetDriverPaging(), MmMapIoSpace().
Таблица описания памяти (Memory Descriptor List – MDL) - Структура данных, описывающая отображение буфера виртуальной памяти (Virtual Address Space) в физическую память (Physical Address Space).


48. Понятие драйвера ОС Windows. Виды драйверов. Типы драйверов в режиме ядра. Точки входа в драйвер.
В Windows существуют два вида драйверов:
Драйвер режима ядра (kernel-mode driver). Такой драйвер существует в любой версии Windows. Поскольку он подчиняется модели драйверов ядра (Windows Driver Model), его еще называют WDM-драйвер. Правильно написанный WDM-драйвер совместим на уровне исходного кода со всеми версиями ОС. Он имеет деление по типам (см. ниже).
Драйвер пользовательского режима (user-mode driver). Появился, начиная с Windows Vista. Разрабатывается с применением библиотеки Windows Driver Framework (WDF).
Типы драйвера режима ядра:
Драйвер файловой системы (NTFS, FAT, CDFS)
Функциональный драйвер – Functional Driver. Существуют драйверы для классов устройств – Class Drivers. Они предоставляют интерфейсы для расширяющих драйверов – Miniclass Drivers (Minidrivers). Пара Class-Minidriver соответствует полноценному Functional Driver.
Фильтрующий драйвер – Filter Driver. Обеспечивает фильтрацию I/O-запросов между шинным драйвером, функциональным драйвером, драйвером файловой системы.
Шинный драйвер – Bus Driver. Обслуживает физическое устройство с шинной архитектурой (SCSI, PCI, parallel ports, serial ports, i8042 ports).
Объекты в драйвере
DRIVER_OBJECT
Объект, описывающий драйвер. Соответствует программному модулю драйвера. Содержит список создаваемых драйвером устройств.
DEVICE_OBJECT
Контролируемое драйвером физическое или логическое устройство. Содержит указатель на объект, описывающий драйвер. Входит в список устройств драйвера.
FILE_OBJECT
Открытый на устройстве файл. Содержит указатель на устройство.

49. Объект, описывающий драйвер. Объект, описывающий устройство. Объект, описывающий файл. Структура и взаимосвязь объектов.
Объект DRIVER_OBJECT:
Представляет загруженный в память драйвер. Создается в единственном экземпляре в момент загрузки модуля драйвера в память операционной системой. Уничтожается в момент выгрузки модуля драйвера из памяти.Передается в главную точку входа DriverEntry и процедуру XxxAddDevice. Хранит состояние, общее для всех обслуживаемых драйвером устройств.
Содержит:
Имя драйвера в структуре имен операционной системы. Начальный адрес и размер драйвера в памяти.Таблицу точек входа в драйвер.Указатель на область расширенных данных драйвера, в которой хранится точка входа в процедуру XxxAddDevice.Список созданных драйвером объектов DEVICE_OBJECT, представляющих обслуживаемые драйвером устройства.
Объект DEVICE_OBJECT:
Представляет физическое или логическое устройство.Создается драйвером с помощью процедуры IoCreateDevice(). Уничтожается с помощью процедуры IoDeleteDevice().Передается в процедуру XxxAddDevice. Может не иметь имени. Тогда оно автоматически генерируется операционной системой – FILE_AUTOGENERATED_DEVICE_NAME.
Содержит:
Фиксированную (DEVICE_OBJECT) и переменную часть данных устройства. Размер и содержимое переменной части определяются драйвером.Указатель на область расширенных данных объекта – DEVOBJ_EXTENSION. Таким образом, расширений получается два.Указатель на владельца – объект драйвера – DriverObject. Указатель на такой же объект устройства в драйвере верхнего уровня – AttachedDevice. Получающийся список образует стек драйверов.Указатель на следующее устройство в списке драйвера – NextDevice.Указатель на очередь I/O-запросов к устройству – DeviceQueue, и текущий запрос к устройству – CurrentIrp.
Объект FILE_OBJECT:
Представляет файл, открытый на устройстве.Создается вызовом CreateFile()/ZwCreateFile().Удаляется вызовом CloseHandle()/ZwClose().
Содержит:
Указатель на владельца – объект устройства – DeviceObject.Относительное имя файла, интерпретируемое драйвером устройства или драйвером файловой системы, – FileName.Дополнительные данные, необходимые драйверам для работы с файлом, – FsContext и FsContext2.Указатель на блок параметра тома, устанавливающий соответствие между файловой системой и смонтированным томом на устройстве, – Vpb.Объект синхронизации Event, который блокирует потоки, осуществляющие синхронные запросы к устройству. Обработка запросов выполняется асинхронно.

50. Понятие пакета ввода-вывода (IRP). Структура пакета ввода-вывода. Схема обработки пакета ввода-вывода при открытии файла.
Пакет ввода-вывода – Input-Output Request Packet (IRP) РИС 1
IRP пакет (I/O request packet) — структура данных ядра Windows, обеспечивающая обмен данными между приложениями и драйвером, а также между драйвером и драйвером. Представляет запрос ввода-вывода.
Создается с помощью IoAllocateIrp() или IoMakeAssociatedIrp() или
IoBuildXxxRequest(). Память выделяется из списка предыстории в резидентном пуле.
Удаляется вызовом IoCompleteRequest().
Диспетчируется драйверу на обработку с помощью IoCallDriver().
Структура IRP:
Фиксированную (IRP) и переменную часть в виде массива записей IO_STACK_LOCATION. Количество элементов массива – поле StackCount. На каждый драйвер в стеке драйверов создается отдельная запись IO_STACK_LOCATION.
Объект FILE_OBJECT, с которым осуществляется работа, – Tail.Overlay.OriginalFileObject.
Буфер данных в пользовательской памяти – UserBuffer.
Буфер данных в системной памяти – AssociatedIrp.SystemBuffer.
Соответствующая буферу таблица описания памяти – MdlAddress.
Указатель на поток (ETHREAD), в очереди которого находится IRP, – Tail.Overlay.Thread. Список IRP потока хранится в ETHREAD.IrpList.
Схема обработки пакета ввода-вывода при открытии файла РИС21.Подсистема ОС вызывает функцию открытия файла в ядре. Эта функция реализована в менеджере ввода-вывода.
2.Менеджер ввода-вывода обращается к менеджеру объектов, чтобы по имени файла создать FILE_OBJECT. При этом осуществляется проверка прав пользователя на обращение к файлу.
3.При открытии файл может находиться на еще не смонтированном томе. В таком случае открытие файла приостанавливается, выполняется монтирование тома на внешнем устройстве и обработка продолжается.
4.Менеджер ввода-вывода создает и инициализирует IRP-пакет с помощью IoAllocateIrp(). В IRP-пакете инициализируется IO_STACK_LOCATION верхнего драйвера в стеке драйверов.
5.Менеджер ввода-вывода вызывает процедуру XxxDispatchCreate() верхнего драйвера. Процедура драйвера вызывает IoGetCurrentIrpStackLocation(), чтобы получить доступ к параметрам запроса. Она проверяет, не кэширован ли файл. Если нет, то вызывает IoCopyCurrentIrpStackLocationToNext() для создания IO_STACK_LOCATION следующего драйвера в стеке, затем IoSetCompletionRoutine() для получения уведомления о завершении обработки IRP-пакета и вызывает IoCallDriver(), делегируя обработку процедуре YyyDispatchCreate() следующего драйвера в стеке.
6.Каждый драйвер в стеке выполняет свою часть обработки IRP-пакета.
7.Последний драйвер в стеке в своей процедуре YyyDispatchCreate() устанавливает в IRP поле IoStatus и вызывает у менеджера ввода-вывода процедуру IoCompleteRequest(), чтобы завершить обработку IRP-пакета. Она проходит в IRP по массиву записей IO_STACK_LOCATION и в каждой вызывает процедуру CompletionRoutine (указывает на XxxIoCompletion() драйвера).
8.Менеджер ввода-вывода проверяет в IRP.IoStatus и копирует соответствующий код возврата в адресное пространство подсистемы ОС (пользовательского процесса).
9.Менеджер ввода-вывода удаляет IRP-пакет с помощью IoFreeIrp().
10.В адресном пространстве пользователя создается описатель для FILE_OBJECT и возвращается подсистеме ОС как результат открытия файла. В случае ошибки возвращается ее код.

РИСУНОК 1 ВОПРОС 50
16700511049000
РИСУНОК 2 ВОПРОС 50
-161226513208000
51. Понятие пакета ввода-вывода (IRP). Структура пакета ввода-вывода. Схема обработки пакета ввода-вывода при выполнении чтения-записи файла.
Понятие пакета IRP и его структура
Берём из предыдущего вопроса…
Схема обработки IRP при выполнении чтения-записи файла
1.Менеджер ввода-вывода обращается к драйверу файловой системы с IRP-пакетом, созданным для выполнения чтения-записи файла. Драйвер обращается к своей записи IO_STACK_LOCATION и определяет, какую именно операцию он должен выполнить.
2.Драйвер файловой системы для выполнения операции с файлом может создавать свои IRP с помощью IoAllocateIrp(). Или же он может в уже имеющемся IRP сформировать IO_STACK_LOCATION для драйвера более низкого уровня с помощью IoGetNextIrpStackLocation().
3.Если драйвер создает собственные IRP-пакеты, он должен зарегистрировать в них свою процедуру ZzzIoCompletion(), которая выполнит удаление IRP-пакетов после обработки драйверами нижнего уровня. За удаление своих IRP каждый драйвер отвечает сам. Менеджер ввода-вывода отвечает за удаление своего IRP, созданного для выполнения ввода-вывода.
Драйвер файловой системы устанавливает в IO_STACK_LOCATION указатель CompletionRoutine на свою процедуру XxxIoCompletion(), формирует IO_STACK_LOCATION для драйвера более низкого уровня с помощью IoGetNextIrpStackLocation(), вписывая нужные значения параметров, и обращается к драйверу более низкого уровня с помощью IoCallDriver().
4.Управление передается драйверу устройства процедуре YyyDispatchRead/Write(), зарегистрированной в объекте DRIVER_OBJECT под номером IRP_MJ_XXX. Драйвер устройства не может выполнить операцию ввода-вывода в синхронном режиме. Он помечает IRP-пакет с помощью IoMarkIrpPending() как требующий ожидания обработки или передачи другой процедуре YyyDispatch().
5.Менеджер ввода-вывода получает информацию, что драйвер устройства занят, и ставит IRP в очередь к объекту DEVICE_OBJECT драйвера.
6.Когда устройство освобождается, в драйвере устройства вызывается процедура обработки прерываний (ISR). Она обнаруживает IRP в очереди к устройству и с помощью IoRequestDpc() создает DPC-процедуру для обработки IRP на более низком уровне приоритета прерываний.
7.DPC-процедура с помощью IoStartNextPacket() извлекает из очереди IRP и выполняет ввод-вывод. Наконец, она устанавливает статус-код в IRP и вызывает IoCompleteRequest().
8.В каждом драйвере в стеке вызывается процедура завершения XxxIoCompletion(). В драйвере файловой системы она проверяет статус-код и либо повторяет запрос (в случае сбоя), либо завершает его удалением всех собственных IRP (если они были). В конце, IRP-пакет оказывается в распоряжении менеджера ввода-вывода, который возвращает вызывающему потоку результат в виде NTSTATUS.

РИСУНОК К ВОПРОСУ 51


52. Перехват API-вызовов ОС Windows в пользовательском режиме. Внедрение DLL с помощью реестра. Внедрение DLL с помощью ловушек. Внедрение DLL с помощью дистанционного потока.
Перехват API-вызовов ОС Windows в пользовательском режиме.
Задача – изменить поведение окна:
HWND hwnd = FindWindow(ClassName, WindowName);
SetClassLongPtr(hwnd, GWLP_WNDPROC, MyWindowProc);
Изменяемый оконный класс может находиться в адресном пространстве другого процесса, и адрес процедуры MyWindowProc будет не валиден.
Внедрение DLL с помощью реестра:
Зарегистрировать DLL в реестре (имя не должно содержать пробелы):HKLM\Software\Microsoft\Windows_NT\CurrentVersion\Windows\AppInit_DLLs
Выполнить API-перехват в DllMain (reason == DLL_PROCESS_ATTACH). Функции Kernel32.dll можно вызывать смело. С вызовами функций из других DLL могут быть проблемы.
Внедрение DLL с помощью ловушек:
HHOOK SetWindowsHookEx(int idHook, HOOKPROC lpfn, INSTANCE hMod, DWORD dwThreadId); UnhookWindowsHookEx().
Процедура ловушки:
LRESULT MyHookProc(int code, WPARAM wParam, LPARAM lParam);code: если HC_ACTION, надо обработать, если меньше нуля, – вызвать:
LRESULT CallNextHookEx(HHOOK hhook, int code, WPARAM wParam, LPARAM lParam);
Внедрение DLL с помощью дистанционного потока:
HANDLE CreateRemoteThread(HANDLE hProcess, SECURITY_ATTRIBUTES* securityAttributes, DWORD dwStackSize, THREAD_START_ROUTTNE* startAddress, void* parameter, DWORD dwCreationFlags, DWORD* pThreadId);
DWORD ThreadProc(void* parameter);
HINSTANCE LoadLibrary(PCTSTR fileName);
void* p = GetProcAddress(GetModuleHandle("Kernel32"), "LoadLibraryW");
Передача данных в дистанционный поток:
void* VirtualAllocEx (HANDLE hProcess, void* lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
bool VirtualFreeEx(HANDLE hProcess, void* lpAddress, SIZE_T dwSize, DWORD dwFreeType);
bool WriteProcessMemory(HANDLE hProcess, void* lpBaseAddress, const void* lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesWritten);
bool ReadProcessMemory(HANDLE hProcess, void* lpBaseAddress, const void* lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesRead);

53. Перехват API-вызовов ОС Windows в пользовательском режиме. Замена адреса в таблице импорта. Перехват в точке входа в процедуру с помощью подмены начальных инструкций (Microsoft Detours).
Задача – изменить поведение окна:
HWND hwnd = FindWindow(ClassName, WindowName);
SetClassLongPtr(hwnd, GWLP_WNDPROC, MyWindowProc);
Изменяемый оконный класс может находиться в адресном пространстве другого процесса, и адрес процедуры MyWindowProc будет не валиден.
Замена адреса в таблице импорта:
void* ImageDirectoryEntryToDataEx(void* Base, // hModulebool MappedAsImage, USHORT DirectoryEntry, ULONG* Size, IMAGE_SECTION_HEADER** FoundHeader);
DirectoryEntry: IMAGE_DIRECTORY_ENTRY_IMPORT

54. Перехват API-вызовов ОС Windows в режиме ядра. Таблица системных функций KeServiceDescriptorTable. Таблица системных функций KeServiceDescriptorTableShadow. Понятие UI-потока. Защита от перехвата (Kernel Patch Protection) в 64-разрядной ОС Windows.
KeServiceDescriptorTable:
Переменная, указывающая на таблицу API-функций ядра.
Экспортируется ядром и видна драйверам.
Номер функции может зависеть от версии ОС.
По номеру функции можно заменить адрес функции в этой таблице.
Таблица защищена от модификации, поэтому перед заменой нужно или отключить бит защиты страницы, или создать доступное для записи отображение таблицы (writable Kernel Virtual Address (KVA) mapping).
KeServiceDescriptorTableShadow:
Переменная, указывающая на таблицы API-функций ядра и Win32k.sys.
Не экспортируется ядром и не видна драйверам. Это осложняет перехват функций работы с окнами и графикой.
UI-потоки содержат указатель на эту таблицу в ETHREAD.Tcb.ServiceTable, но смещение до этого поля отличается в каждой ОС.UI-поток должен обращаться к драйверу за перехватом UI-функций.Перехват UI-функций во время загрузки ОС становится проблематичен.
Защита от перехвата – Kernel Patch Protection:
Реализована на 64-разрядной платформе.
Не дает модифицировать:
GDT – Global Descriptor Table
IDT – Interrupt Descriptor Table
MSRs – Model-Specific Registers
Kernel Service Table
В случае модификации вызывается KeBugCheckEx() с кодом CRITICAL_STRUCTURE_CORRUPTION. При этом стек зачищается, чтобы осложнить реверс-инжиниринг.
Инвестиции в обход механизма Kernel Patch Protection себя не окупают. Microsoft изменяет работу этого механизма в новых обновлениях.
55. Перехват API-вызовов менеджера объектов ОС Windows в режиме ядра.
Установка разрешенного набора callback-процедур для некоторых подсистем ядра:
Object Manager Callbacks
Process Callbacks
Thread Callbacks
Module Load Callbacks
Registry Callbacks
File System Mini-Filters
Win32k.sys такого механизма не имеет
Требования к драйверам, применяющим эти механизмы:
Драйвер должен быть скомпонован с ключом /integritycheck.
Драйвер должен быть подписан сертификатом производителя ПО.
При разработке драйвера должен быть включен режим действия тестовых сертификатов:C:\> bcdedit.exe –set TESTSIGNING ON
Несколько драйверов могут устанавливать callback-процедуры на конкурентной основе. Для них Windows применяет уровни перехвата, за исключением Process, Thread и Module Load Callbacks.

56. Перехват API-вызовов создания и уничтожения процессов и потоков ОС Windows в режиме ядра.
Процедура перехвата создания и уничтожения процесса:
NTSTATUS PsSetCreateProcessNotifyRoutineEx(CREATE_PROCESS_NOTIFY_ROUTINE_EX* NotifyRoutine, bool Remove);параметр Remove выбирает между регистрацией и удалением.
void ProcessNotifyEx(EPROCESS* Process, HANDLE ProcessId, PS_CREATE_NOTIFY_INFO* CreateInfo) – формат NotifyRoutine.
Процедура вызываются на уровне приоритета прерываний PASSIVE_LEVEL в контексте потока, вызывающего создание описателя.
struct PS_CREATE_NOTIFY_INFO { SIZE_T Size; union { ULONG Flags; struct { ULONG FileOpenNameAvailable :1; ULONG Reserved :31; }; }; HANDLE ParentProcessId; CLIENT_ID CreatingThreadId; FILE_OBJECT* FileObject; const UNICODE_STRING* ImageFileName; const UNICODE_STRING* CommandLine; NTSTATUS CreationStatus; };
Процедура программиста может запретить создание процесса, если установит в поле CreateInfo->CreationStatus ненулевой код ошибки.
ОС позволяет зарегистрировать не более 12 таких процедур перехвата.
Устаревшая процедура перехвата в версиях до Windows Vista:
PsSetCreateProcessNotifyRoutine() – по формату аналогична.
void ProcessNotify(HANDLE ParentId, HANDLE ProcessId, bool Create);Уведомление без возможности запретить создание/удаление процесса.
Процедура перехвата создания и уничтожения потока:
NTSTATUS PsSetCreateThreadNotifyRoutine(CREATE_THREAD_NOTIFY_ROUTINE* NotifyRoutine);
NTSTATUS PsRemoveCreateThreadNotifyRoutine(CREATE_THREAD_NOTIFY_ROUTINE* NotifyRoutine);
void ThreadNotify(HANDLE ProcessId, HANDLE ThreadId, bool Create);
Создание и удаление потока отменить нельзя.
Обычно используется драйверами для очистки создаваемых для потоков ресурсов.
ОС позволяет зарегистрировать не более 8 таких процедур перехвата.

57. Перехват операций с реестром в ОС Windows в режиме ядра.
Процедура перехвата операций с реестром Windows:
NTSTATUS CmRegisterCallbackEx(EX_CALLBACK_FUNCTION* Function, const UNICODE_STRING* Altitude, void* Driver, void* Context,LARGE_INTEGER* Cookie, void* Reserved); CmRegisterCallback() устарела.
NTSTATUS CmUnRegisterCallback(LARGE_INTEGER Cookie);
NTSTATUS RegistryCallback(void* Context, REG_NOTIFY_CLASS Argument1, void* Argument2); // Argument2 – указатель на REG_XXX_INFORMATION.
Процедура перехвата операций с реестром может выполнять:мониторинг, блокировку (XP и выше) и модификацию (Vista и выше).
Если операция предотвращается с помощью STATUS_CALLBACK_BYPASS, вызывающий поток получает STATUS_SUCCESS. Если операция предотвращается с помощью кода ошибки, поток получает ее код.
В процедуре перехвата при создании ключа реестра можно назначить ключу отдельный контекст, который будет передаваться в процедуру с уведомлениями REG_XXX_KEY_INFORMATION:
NTSTATUS CmSetCallbackObjectContext(void* Object, LARGE_INTEGER* Cookie, void* NewContext, void** OldContext);
При ассоциации контекста с ключом реестра, процедуре перехвата будет послано уведомление об уничтожении ключа.

58. Перехват операций с файлами в ОС Windows в режиме ядра. Мини-фильтры файловой системы.
Перехват процедур взаимодействия программ с файловой системой возможен в двух вариантах:
Установка фильтрующего драйвера – File System Filter Driver. Устаревший способ, унаследованный от предыдущих версий Windows (до Win 2000).
Установка фильтрующего мини-драйвера (мини-фильтра) – File System Mini-Filter. Способ основан на запуске компонента Filter Manager (fltmgr.sys) как фильтрующего драйвера, запускающего и контролирующего мини-фильтры.
Filter Manager: Активизируется при загрузке первого же мини-фильтра. Обеспечивает работу множества мини-фильтров. Может загружать и выгружать мини-фильтры без перезагрузки системы.
Устанавливается в стеке драйверов между менеджером ввода-вывода и драйверами файловой системы (NTFS, FAT и др.). Умеет устанавливаться в обхват других фильтрующих драйверов (см. рисунок). При установке мини-фильтров применяет параметр высоты установки (Altitude).
Скрывает сложность модели ввода-вывода на основе IRP-пакетов и предоставляет интерфейс для регистрации функций перехвата. Параметры в функции перехвата приходят разобранными (не IRP).
Предоставляет API и для ядра, и для пользовательского режима.
Mini-Filter: Загружается и управляется как из kernel mode, так и из user mode. Функции режима ядра – FltXxxYyy(), функции приложений – FilterXxx().
Перехватчики устанавливаются мини-фильтром в режиме ядра.
Для каждого тома файловой системы и присоединенного к нему мини-фильтра Filter Manager создает ассоциированный объект, называемый Instance. Мини-фильтр может перехватывать создание и удаление таких объектов.
Загрузка и выгрузка мини-фильтра:
NTSTATUS FltLoadFilter(PCUNICODE_STRING FilterName);
NTSTATUS FltUnloadFilter(PCUNICODE_STRING FilterName);
HRESULT FilterLoad(LPCWSTR lpFilterName); // user mode
HRESULT FilterUnload(LPCWSTR lpFilterName); // user mode
Регистрация процедур перехвата в мини-фильтре:
NTSTATUS FltRegisterFilter(DRIVER_OBJECT* Driver, const FLT_REGISTRATION* Registration, PFLT_FILTER* RetFilter);
NTSTATUS FltStartFiltering(PFLT_FILTER Filter);
void FltUnregisterFilter(PFLT_FILTER Filter);

Приложенные файлы

  • docx 18175626
    Размер файла: 824 kB Загрузок: 0

Добавить комментарий