//----------------------------------------------------------------------------- // File: FSWindow // // Desc: This code will allow you to update a window in DirectDraw full-screen // exclusive mode on a device that doesn't support GDI. They will also // handle devices that do support GDI. // // // Copyright (c) 1998-1999 Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif //----------------------------------------------------------------------------- // Include files //----------------------------------------------------------------------------- #include "dconfigp.h" //----------------------------------------------------------------------------- // Local definitions //----------------------------------------------------------------------------- static IDirectDraw7 *ddObject = NULL; static IDirectDrawSurface7 *ddFrontBuffer = NULL; static IDirectDrawSurface7 *ddBackBuffer = NULL; static IDirectDrawClipper *ddClipper = NULL; static SIZE structSurfaceSize = {0, 0}; static BOOL bNonGDI = FALSE; static HWND hwndFSWindow = NULL; static HBITMAP hwndFSWindowBMP = NULL; static HWND hwndAppWindow = NULL; //----------------------------------------------------------------------------- // Name: CreateDibBMP() // Desc: Created an empty bitmap, used exclusively in CreateBMPFromWindow(). // Note that this is an internal (not exported) function. //----------------------------------------------------------------------------- static HBITMAP CreateDibBMP(HDC hdc, int w, int h, unsigned short bpp) { LPVOID lpBits; struct { BITMAPINFOHEADER bi; DWORD ct[256]; } dib; dib.bi.biSize = sizeof(BITMAPINFOHEADER); dib.bi.biWidth = w; dib.bi.biHeight = h; dib.bi.biBitCount = bpp; dib.bi.biPlanes = 1; dib.bi.biCompression = 0; dib.bi.biSizeImage = 0; dib.bi.biClrUsed = 0; if (bpp == 15) { dib.bi.biBitCount = 16; } else if (bpp == 16) { dib.bi.biCompression = BI_BITFIELDS; dib.ct[0] = 0xF800; dib.ct[1] = 0x07E0; dib.ct[2] = 0x001F; } return CreateDIBSection(hdc, (LPBITMAPINFO) & dib, DIB_RGB_COLORS, &lpBits, NULL, 0); } //----------------------------------------------------------------------------- // Name: CreateBMPFromWindow() // Desc: Takes the hwnd of the content window, and returns a bitmap handle. // Note that this is an internal (not exported) function. //----------------------------------------------------------------------------- static HBITMAP CreateBMPFromWindow(HWND hwnd) { RECT rc; int x; int y; int cx; int cy; HDC hdcScreen; HDC hdcMemory; HBITMAP hbmBitmap; // Create a bitmap of the window passed in GetWindowRect(hwnd, &rc); x = rc.left; y = rc.top; cx = rc.right - rc.left; cy = rc.bottom - rc.top; hdcScreen = GetDC(NULL); hdcMemory = CreateCompatibleDC(NULL); hbmBitmap = CreateDibBMP(hdcScreen, cx, cy, 16); // BLT the image from screen to bitmap SelectObject(hdcMemory, hbmBitmap); BitBlt(hdcMemory, 0, 0, cx, cy, hdcScreen, x, y, SRCCOPY); DeleteDC(hdcMemory); ReleaseDC(NULL, hdcScreen); return hbmBitmap; } //----------------------------------------------------------------------------- // Name: FSWindow_Init() // Desc: Does preliminary setup of global values for FSWindow. It should get // called each time DirectDraw surfaces are altered (i.e. changes to the // device that the client application is running under). //----------------------------------------------------------------------------- void FSWindow_Init(HWND hwndApp, IDirectDraw7 *dd, IDirectDrawSurface7 *FrontBuffer, IDirectDrawSurface7 *BackBuffer) { DDSURFACEDESC2 ddsd; DDCAPS ddcaps; // Save handle to application window hwndAppWindow = hwndApp; ZeroMemory(&ddcaps, sizeof(ddcaps)); ddcaps.dwSize = sizeof(ddcaps); dd->GetCaps(&ddcaps, NULL); if (ddcaps.dwCaps2 & DDCAPS2_CANRENDERWINDOWED) bNonGDI = FALSE; else bNonGDI = TRUE; // Save DirectDraw object passed in ddObject = dd; // Save buffers passed in ddFrontBuffer = FrontBuffer; ddBackBuffer = BackBuffer; // Get DirectDraw surface dimensions ZeroMemory(&ddsd, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH; ddBackBuffer->GetSurfaceDesc(&ddsd); structSurfaceSize.cx = ddsd.dwWidth; structSurfaceSize.cy = ddsd.dwHeight; } //----------------------------------------------------------------------------- // Name: FSWindow_Begin() // Desc: Prepairs the DirectDraw surface depending on 3D hardware. It should // get called whenever a window (represented by the hwnd parameter) needs // to be displayed under DirectDraw. FSWindow_Begin() should also get // called if the window changes its content (if its static content // becomes dynamic, and vice-versa). //----------------------------------------------------------------------------- HWND FSWindow_Begin(HWND hwnd, BOOL bStaticContent) { RECT rc; // If no handle passed in, assume existing content window if (hwnd == NULL) hwnd = hwndFSWindow; if (hwnd == NULL) return NULL; if (bNonGDI) { // Constrain cursor to DirectDraw surface rc.left =0; rc.top = 0; rc.right = structSurfaceSize.cx; rc.bottom = structSurfaceSize.cy; ClipCursor(&rc); // Clear out lingering content if (hwndFSWindowBMP) DeleteObject(hwndFSWindowBMP); hwndFSWindowBMP = NULL; // Need to create an image of content window just once if (bStaticContent) { if (!FSWindow_IsActive()) UpdateWindow(hwnd); // Assign content window image to global hwndFSWindowBMP = CreateBMPFromWindow(hwnd); } } else { //Create a clipper (used in IDirectDrawSurface::Blt call) if (ddObject->CreateClipper(0, &ddClipper, NULL) == DD_OK) ddClipper->SetHWnd(0, hwndAppWindow); // Normal GDI device, so just flip to GDI so content window can be seen ddObject->FlipToGDISurface(); } hwndFSWindow = hwnd; return hwndFSWindow; } //----------------------------------------------------------------------------- // Name: FSWindow_End() // Desc: Deletes objects associated with the content window. Note that these // are objects created within this module, not objects created by the // calling client (e.g. content window). Call this function whenever the // content window is destroyed (e.g. WM_CLOSE). //----------------------------------------------------------------------------- void FSWindow_End() { if (hwndFSWindow) hwndFSWindow = NULL; if (hwndFSWindowBMP) DeleteObject(hwndFSWindowBMP); hwndFSWindowBMP = NULL; if (bNonGDI) ClipCursor(NULL); // Get rid of clipper object if (ddClipper) { ddClipper->Release(); ddClipper = NULL; } } //----------------------------------------------------------------------------- // Name: FSWindow_Update() // Desc: Is responsible for the actual rendering of the content window // (held in global hwndFSWindow). This function must be called each // time a DirectDraw frame gets rendered and FSWindow_IsActive() returns // TRUE, so it should be placed in the main application's DirectDraw // rendering routine. An example of this might look like the following: // // void RenderFrame() // { // if (FSWindow_IsActive()) // FSWindow_Update(); // else // FrontBuffer->Blt(...); // } //----------------------------------------------------------------------------- void FSWindow_Update() { POINT pt; RECT rc; int x; int y; int cx; int cy; HDC hdcScreen; HDC hdcBackBuffer; HRGN hrgn; HDC hdcMemory; static HCURSOR MouseCursor; static ICONINFO IconInfo; HCURSOR MouseCursorCur; if (bNonGDI) { GetWindowRect(hwndFSWindow, &rc); x = rc.left; y = rc.top; cx = rc.right - rc.left; cy = rc.bottom - rc.top; // Get a DC to the screen (where our window is) and // Get a DC to the backbuffer on the non-GDI device (where we need to copy it) hdcScreen = GetDC(NULL); ddBackBuffer->GetDC(&hdcBackBuffer); // If window has a complex region associated with it, be sure to include it in the draw hrgn = CreateRectRgn(0, 0, 0, 0); if (GetWindowRgn(hwndFSWindow, hrgn) == COMPLEXREGION) { OffsetRgn(hrgn, rc.left, rc.top); SelectClipRgn(hdcBackBuffer, hrgn); } // If content window is static (no animations, roll-overs, etc.) then // create a dc for the bitmap and blt to the back buffer if (FSWindow_IsStatic()) { hdcMemory = CreateCompatibleDC(NULL); SelectObject(hdcMemory, hwndFSWindowBMP); BitBlt(hdcBackBuffer, x, y, cx, cy, hdcMemory, 0, 0, SRCCOPY); DeleteDC(hdcMemory); } else { // Special case for potentially quirky non-GDI drivers #if 0 // If content is dynamic (updated each frame), always grab the screen copy // by calling CreateBMPFromWindow to update image held in Bitmap HDC hdcMemory = CreateCompatibleDC(NULL); HBITMAP Bitmap = CreateBMPFromWindow(hwndFSWindow); SelectObject(hdcMemory, Bitmap); BitBlt(hdcBackBuffer, x, y, cx, cy, hdcMemory, 0, 0, SRCCOPY); DeleteDC(hdcMemory); DeleteObject(Bitmap); #else // Do a blt directly from the windows screen to the backbuffer BitBlt(hdcBackBuffer, x, y, cx, cy, hdcScreen, x, y, SRCCOPY); #endif } // Remove clipping region and clean up SelectClipRgn(hdcBackBuffer, NULL); DeleteObject(hrgn); // Now draw the mouse on the backbuffer MouseCursorCur = GetCursor(); if (MouseCursorCur != MouseCursor) { MouseCursor = MouseCursorCur; GetIconInfo(MouseCursor, &IconInfo); if (IconInfo.hbmMask) DeleteObject(IconInfo.hbmMask); if (IconInfo.hbmColor) DeleteObject(IconInfo.hbmColor); } GetCursorPos(&pt); pt.x -= IconInfo.xHotspot; pt.y -= IconInfo.yHotspot; DrawIcon(hdcBackBuffer, pt.x, pt.y, MouseCursor); ddBackBuffer->ReleaseDC(hdcBackBuffer); ReleaseDC(NULL, hdcScreen); ddFrontBuffer->Flip(NULL, DDFLIP_WAIT); } else { // GDI hardware // Update the surface with a blt ddFrontBuffer->SetClipper(ddClipper); ddFrontBuffer->Blt(NULL, ddBackBuffer, NULL, DDBLT_WAIT, NULL); } } //----------------------------------------------------------------------------- // Name: FSWindow_IsActive() // Desc: Simply checks to see if there's a content window displayed. This check // should be made prior to calling FSWindow_Update(). //----------------------------------------------------------------------------- BOOL FSWindow_IsActive(void) { return (hwndFSWindow != NULL); } //----------------------------------------------------------------------------- // Name: FSWindow_IsStatic() // Desc: Checks to see whether or not the content window needs to be regularly // updated (its content is dynamic, such as an animation or text entry // field). A static window is created (an image of the window created // with a call to CreateBMPFromWindow()) once and used over and over. //----------------------------------------------------------------------------- BOOL FSWindow_IsStatic(void) { return (hwndFSWindowBMP != NULL); }