Чтение онлайн

ЖАНРЫ

Графика DirectX в Delphi

Краснов Михаил

Шрифт:

if Lib > 32 then begin

// Получаем адрес точки входа

SVSSPFunc := GetProcAddress(Lib, 'VerifyScreenSavePwd');

// На время работы диалога включаем курсор

ShowCursor (True) ;

// Запускаем системный диалог

if @VSSPFunc <> nil then Result := VSSPFunc(Handle);

ShowCursor(False); // Это можно, в принципе, не делать

FreeLibrary(Lib); // Освобождаем память

end;

end;

end;

RegCloseKey(Key);

end;

end;

И теперь самое главное: диалоговое окно должно

работать "поверх" первичной поверхности (рис. 5.10).

Чтобы пользователь увидел его, перед вызовом нашей пользовательской функции TestPassword нужно переключиться на воспроизведение в режиме GDI:

FDD.FlipTcGDISurface;

To есть в такой ситуации обязан вызываться метод главного объекта FlipToGDisurface, а перерисовка экрана не должна осуществляться. К сожалению, мне встречались хранители экрана, написанные профессионалами, авторы которых не позаботились о корректной работе системного диалога: пароль приходится вводить "вслепую", не видя окно ввода пароля, закрытое картинкой первичной поверхности. Памятуя об этом, я многократно проверял работу своего хранителя на самых разных видеокартах, и могу сказать, что не встретил ничего подобного.

Чтобы отключить клавиатуру, точнее, запретить работу комбинаций клавиш <Alt>+<Tab> и <CtrI>+<Alt>+<Del>, на время работы приложения информируем систему о том, что работает хранитель экрана, при запуске приложения выполняется следующая строка кода:

SystemParametersInfo(SPI SCREENSAVERRUNNING, 1, nil, 0);

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

Переключение на GDI-воспроизведение, надеюсь, сделает видимым диалоговое окно у каждого читателя книги, но полноценным такое решение назвать нельзя. При перемещении окна по экрану оно оставляет следы, расчищая первичную поверхность и обнажая окно приложения (поэтому экран становится серым).

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

Учтите, что наш хранитель экрана требует небольших доработок, для оконного режима следует различать установленное разрешение рабочего стола. т. к. при 32-битной глубине возможно искаженное масштабирование образов.

Использование отсечения в полноэкранном приложении

Имея дело с Delphi, вам наверняка жалко будет потерять все ее прелести и мощь разработки диалоговых средств, расстаться с визуальными компонентами только потому, что при перемещении окна могут остаться серые пятна.

Специально для этого случая я подготовил пример, иллюстрирующий, как можно эффектно комбинировать обычный вывод средствами GDI и DirectDraw. Это проект каталога Ex11, где посередине экрана отображается репродукция самого популярного шедевра живописи, а по бокам разбросаны стандартные интерфейсные элементы (рис. 5.11).

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

поверхности, а для того, чтобы воспроизведение осуществлялось только в пределах центральной области экрана, я использую отсечение, знакомое нам по оконным приложениям. Но теперь оно ограничивает строго определенную область экрана, а не связывается с окном приложения. Если ранее для связывания отсечения с окном использовался метод SetHWnd, то в этом примере вызывается метод SetciipList. В общем случае последний метод может применяться для создания и непрямоугольных областей вывода, для описания их служат регионы:

var

rgn : TRgnData; // Вспомогательная переменная, описьшает набор регионов

wrk : TRECT; // Прямоугольник, описывающий наш единственный регион

...

SetRect {wrk, 230, 0, 620, 600); // Задаем область вывода на экране

with rgn.rdh do begin // Заполняем поля структуры

dwSize := SizeOf (RGNDATAHEADER); // Это обязательно, как всегда

iType := RDH_RECTANGLES; // Единственно возможное значение поля

nCount := 1; // Количество задействованных регионов

nRgnSize := Sizeof(TRECT); // Размер единицы информации

end;

PRECT(@rgn.Buffer)Л := wrk; // Заносим в буфер наш единственный регион

if FDD.CreateClipper(0, FDDClipper, nil) = DD_OK then begin

FDDClipper.SetClipList (@rgn, 0); // Задаем область отсечения

FDDSPrimary.SetClipper (FDDClipper) ;

end;

Замечу, что вспомогательная структура, представленная здесь, является системной и не связана исключительно с DirectX. Заполняя поле buffer этой структуры, вы можете получить холсты замысловатой формы.

Приведу еще один способ работы с методом SetciipList. Вот код, который способствует отсечению, аналогичному отсечению предыдущего примера:

var

hrg : HRGN; // Регион

rgnDataBuffer: Array [0..1023] of BYTE; // Массив списка регионов

...

hrg := CreateRectRgn (230, 0, 620, 600); // Создание нужного региона

// Заполняем массив данными

GetRegionData(hrg, SizeOf(rgnDataBuffer), @rgnDataBuffer);

DeleteObject(hrg);

if FDD.CreateClipper(0, FDDClipper, nil) = DD_OK then begin

FDDClipper.SetClipList (@rgnDataBuffer, 0); // Задаем отсечение

FDDSPrimary.SetClipper(FDDClipper);

end;

Отсечение для полноэкранных приложений может использоваться и для того, чтобы полностью решить проблему с выводом образов вблизи границ. В проекте каталога Ех12 курсор заменен логотипом DirectX, динамически меняющим свой размер. Для такой ситуации задание положения курсора становится трудной задачей. Мы не можем пользоваться решениями предыдущих примеров с замененным курсором приложения. Присовокупление отсечения к экрану позволяет совершенно не задумываться о текущем размере образа курсора и его положении, при его воспроизведении вблизи границ образ отсекается совершенно корректно (рис. 5.12).

Аналогично предыдущему примеру, объект отсечения строится на основе региона, но здесь регион представляет собой простой прямоугольник, связанный с размерами экрана:

SetRect (wrk, О, О, 800, 600);

with rgn.rdh do begin

dwSize := SizeOf (RGNDATAHEADER);

Type := RDH_RECTANGLES;

nCount := 1;

nRgnSize := Sizeof(TRECT);

end;

PRECT(@rgn.Buffer)Л := wrk;

Поделиться с друзьями: