Displaying a Window in Full-Screen Mode

In full-screen mode, DirectDraw has exclusive control over the display. As a result, dialog boxes and other windows created through GDI are not normally visible. However, by using special techniques you can incorporate a Windows dialog box, HTML Help, or any other kind of window in your application.

The FSWindow Sample illustrates how a dialog box can be displayed and updated in a full-screen application, and how mouse clicks and keystrokes work just as if the dialog box were being displayed by GDI.

In FSWindow, the dialog box is created and "shown" as an ordinary dialog window:

hWndDlg = CreateDialog(g_hInstance,
        MAKEINTRESOURCE(IDD_DIALOG_SAMPLE),
        hWnd, (DLGPROC) SampleDlgProc);
ShowWindow(hWndDlg, SW_SHOWNORMAL);
 

Of course, at this point the dialog box is shown only on the hidden GDI surface. It does not appear on the primary surface, which is controlled by DirectDraw.

If the hardware capabilities include DDCAPS2_CANRENDERWINDOWED (see DDCAPS), displaying and updating the dialog box is easy. The application simply calls the IDirectDraw4::FlipToGDISurface method, which makes the GDI surface the primary surface. From now on, all updates to the dialog box will be displayed automatically, because GDI is now rendering directly to the front buffer. The application continues rendering to the back buffer, and on each pass through the rendering loop the contents of the back buffer are blitted to the front buffer by DirectDraw. The dialog box is not overwritten because the front buffer is clipped to the application window, and the dialog box is obscuring part of that window.

The following code, from the FSWindow_Init function, creates the clipper, associates it with the application window, and brings the GDI surface to the front:

if (ddObject->CreateClipper(0, &ddClipper, NULL) == DD_OK)
    ddClipper->SetHWnd(0, hwndAppWindow);
ddObject->FlipToGDISurface();

Then, in the FSWindow_Update function, the following code blits the rendered contents of the back buffer to the clipping region:

ddFrontBuffer->SetClipper(ddClipper);
ddFrontBuffer->Blt(NULL, ddBackBuffer, NULL, DDBLT_WAIT, NULL);
 

Note that because the GDI surface is the primary surface, Windows continues displaying the mouse cursor. (This would not be the case, however, if the application were using DirectInput with the mouse device at the exclusive cooperative level.)

For hardware that does not have the DDCAPS2_CANRENDERWINDOWED capability, the process of displaying and updating a window in full-screen mode is somewhat more complicated. In this case, the application is responsible for obtaining the image of the window created by GDI and blitting it to the back buffer after the full-screen rendering has been done. The entire back buffer is then flipped to the front in the usual way.

The FSWindow sample provides two different methods for accessing the display memory of the window, depending on whether the content is static or dynamic. The method for static content is faster because it involves blitting from a memory device context rather than a screen device context. This method should be used for windows that do not change, such as informational dialog boxes. (Remember, though, that unless you manually update the bitmap in response to events, even basic animations such as a button press will not be visible to the user.)

If the content is static, FSWindow calls the CreateBMPFromWindow function when the window is initialized. This function creates a bitmap and blits the contents of the window into it. The bitmap handle is stored in the global variable hwndFSWindowBMP. Whenever the primary surface is about to be updated, this bitmap is blitted to the back buffer, as follows:

if (FSWindow_IsStatic)
{
    hdcMemory = CreateCompatibleDC(NULL);
    SelectObject(hdcMemory, hwndFSWindowBMP);
    BitBlt(hdcBackBuffer, x, y, cx, cy, hdcMemory, 0, 0, SRCCOPY);
    DeleteDC(hdcMemory);
}
 

If, on the other hand, the content of the window is dynamic, the following code is executed. It blits the image directly from the GDI surface (represented by the hdcScreen device context) to the back buffer.

BitBlt(hdcBackBuffer, x, y, cx, cy, hdcScreen, x, y, SRCCOPY);
 

The coordinates represent the position and dimensions of the window on the GDI surface, as retrieved through a call to GetWindowRect.

When the FSWindow application is running on hardware that does not have the DDCAPS2_CANRENDERWINDOWED capability, it does not use the GDI surface, so Windows cannot display the mouse cursor. The application takes over this task by obtaining information about the cursor and displaying it on the back buffer just before the flip.