Страница 2 из 2 Удаление объектов DirectDraw Перед уничтожением главного окна приложения нужно удалить созданные объекты DirectDraw, чтобы освободить занимаемые ими системные ресурсы. Обычно все делается в обработчике события WM_DESTROY. Главное, о чем всегда следует помнить при работе с COM-объектами, - это то, что недопустимо применять метод delete() непосредственно. Дело в том, что удаляемый объект может использоваться другим приложением, ведь мы работаем в многозадачной среде. С подобной проблемой легко справляется метод Release(), который просто уменьшает счетчик ссылок на объект (reference count) и вызывает метод delete() лишь тогда, когда значение этого счетчика равно нулю. Это свидетельствует о том, что удаляемый объект не используется ни одним приложением. В данном примере мы создали два COM-объекта, причем указатели на них содержатся в переменных lpDDraw и lpPrimarySurface. Значит, при обработке системного события WM_DESTROY нам требуется применить всего два метода: lpPrimarySurface->Release(); lpDDraw->Release();
Простейшая программа, демонстрирующая прямой доступ к видеопамяти средствами DirectDraw, приведена в листинге. Листинг #include <windows.h> #include <ddraw.h>
const PHYSICAL_WIDTH = 800; const PHYSICAL_HEIGHT = 600;
LPDIRECTDRAW lpDDraw; LPDIRECTDRAWSURFACE lpPrimarySurface;
LRESULT CALLBACK DDrawWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); BOOL DDrawInit(HWND hWnd); void DDrawDone(); void DrawScreen();
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
WNDCLASS wndClass; HWND hWnd; MSG msg;
ZeroMemory(&wndClass, sizeof(wndClass)); wndClass.style = CS_HREDRAW | CS_VREDRAW; wndClass.lpfnWndProc = DDrawWndProc; wndClass.hInstance = hInstance; wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); wndClass.lpszClassName = <DDrawApp>;
RegisterClass(&wndClass);
hWnd = CreateWindowEx( WS_EX_TOPMOST, wndClass.lpszClassName, <DirectDraw Application>, WS_POPUP | WS_MAXIMIZE, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd);
while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); }
return msg.wParam; }
LRESULT CALLBACK DDrawWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_CREATE: DDrawInit(hWnd); SetTimer(hWnd, 1, 50, 0); return 0;
case WM_TIMER: DrawScreen(); return 0;
case WM_KEYDOWN: if (wParam == VK_ESCAPE) SendMessage(hWnd, WM_CLOSE, 0, 0); return 0;
case WM_DESTROY: KillTimer(hWnd, 1); DDrawDone(); PostQuitMessage(0); return 0;
default: return DefWindowProc(hWnd, message, wParam, lParam); } }
BOOL DDrawInit(HWND hWnd) { DDSURFACEDESC ddsd; DDSCAPS ddsc;
if (DirectDrawCreate(NULL, &lpDDraw, NULL) != DD_OK) return FALSE;
if (lpDDraw->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN) != DD_OK) return FALSE;
if (lpDDraw->SetDisplayMode(PHYSICAL_WIDTH, PHYSICAL_HEIGHT, 8) != DD_OK) return FALSE;
ZeroMemory(&ddsd, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; ddsd.dwFlags = DDSD_CAPS; if (lpDDraw->CreateSurface(&ddsd, &lpPrimarySurface, NULL) != DD_OK) return FALSE;
return TRUE; }
void DDrawDone() { if (lpPrimarySurface != NULL) lpPrimarySurface->Release();
if (lpDDraw != NULL) lpDDraw->Release(); }
void DrawScreen() { DDSURFACEDESC ddsd; static int pos;
ZeroMemory(&ddsd, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd);
if (lpPrimarySurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) == DD_OK) { char* buffer = (char*)ddsd.lpSurface; for (int i = 0; i < PHYSICAL_HEIGHT / 2; i++) { memset(buffer + (i * ddsd.lPitch), i + pos, PHYSICAL_WIDTH); memset(buffer + ((PHYSICAL_HEIGHT / 2 + i) * ddsd.lPitch), i - pos, PHYSICAL_WIDTH); }
pos++;
lpPrimarySurface->Unlock(ddsd.lpSurface); } }
Cтандарт VESA/VBE отображает видеопамять в виде отдельных окон (банков) размерами не более 64 Кбайт, причем только одно из них может быть активным в заданный момент времени. Переключение таких окон значительно усложняет алгоритмы обработки графики, а также замедляет скорость работы всего приложения. Стандарт VESA/VBE, начиная с версии 2.0, позволяет добиться линейного доступа к видеопамяти в режиме LFB (Linear Flat-frame Buffer) аналогично тому, как это делает DirectDraw. К сожалению, приложения MS-DOS, использующие режим LFB, не могут работать под управлением ОС семейства Windows NT (Windows NT/2000/XP). Это значительно ограничивает область применения LFB и практически сводит на нет все его преимущества перед обычными "оконными" режимами VESA/VBE. В отличие от упомянутых режимов компонент DirectDraw представляет видеопамять в виде непрерывного линейного массива (вектора), напрямую определяющего цвета отображаемых пикселов. Таким образом, программирование графики в режиме прямого доступа к видеопамяти в Win32-приложениях гораздо более простая задача, чем использование средств VESA/VBE в среде MS-DOS. |