Creating the Primary Surface and Clipper Object

The CreatePrimary function creates the primary surface (representing the desktop) and creates and attaches a clipper object. If necessary, this function also creates a palette.

static HRESULT 
CreatePrimary(HWND hwnd) 
{ 
    HRESULT             hRes; 
    DDSURFACEDESC       ddsd; 
    LPDIRECTDRAWCLIPPER lpddClipper; 
    HDC                 hdc; 
    int                 i; 
    PALETTEENTRY        peColorTable[256]; 
 
    ASSERT(NULL != hwnd); 
    ASSERT(NULL != lpdd); 
    ASSERT(NULL == lpddPrimary); 
    ASSERT(NULL == lpddPalette); 
 
    // Create the primary surface. 
 
    ZeroMemory(&ddsd, sizeof(ddsd)); 
    ddsd.dwSize         = sizeof(ddsd); 
    ddsd.dwFlags        = DDSD_CAPS; 
    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; 
    hRes = lpdd->lpVtbl->CreateSurface(lpdd, &ddsd, &lpddPrimary, NULL); 
    if (FAILED(hRes)) 
        return hRes; 
 
    // Create the clipper. We bind the application's window to the 
    // clipper and attach it to the primary. This ensures that when we 
    // blit from the rendering surface to the primary we don't write 
    // outside the visible region of the window. 
 
    hRes = DirectDrawCreateClipper(0, &lpddClipper, NULL); 
    if (FAILED(hRes)) 
        return hRes; 
    hRes = lpddClipper->lpVtbl->SetHWnd(lpddClipper, 0, hwnd); 
    if (FAILED(hRes)) 
    { 
        lpddClipper->lpVtbl->Release(lpddClipper); 
        return hRes; 
    } 
    hRes = lpddPrimary->lpVtbl->SetClipper(lpddPrimary, lpddClipper); 
    if (FAILED(hRes)) 
    { 
        lpddClipper->lpVtbl->Release(lpddClipper); 
        return hRes; 
    } 
 
    // We release the clipper interface after attaching it to the 
    // surface because we don't need to use it again. The surface 
    // holds a reference to the clipper when it has been attached. 
    // The clipper will therefore be released automatically when the 
    // surface is released. 
 
    lpddClipper->lpVtbl->Release(lpddClipper); 
 
    // If the primary surface is palettized, the device will be, too. 
    // (The device surface must have the same pixel format as the 
    // current primary surface if we want to double buffer with 
    // DirectDraw.) Therefore, if the primary surface is palettized we 
    // need to create a palette and attach it to the primary surface 
    // (and to the device surface when we create it). 
 
    ZeroMemory(&ddsd, sizeof(ddsd)); 
    ddsd.dwSize = sizeof(ddsd); 
    hRes = lpddPrimary->lpVtbl->GetSurfaceDesc(lpddPrimary, &ddsd); 
    if (FAILED(hRes)) 
        return hRes; 
    if (ddsd.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) 
    { 
    // Initializing the palette correctly is essential. Since we are 
    // running in a window, we must not change the top ten and bottom 
    // ten static colors. Therefore, we copy them from the system 
    // palette and mark them as read only (D3DPAL_READONLY). The middle 
    // 236 entries are free for use by Direct3D so we mark them free 
    // (D3DPAL_FREE). 
 
    // NOTE: In order that the palette entries are correctly 
    // allocated it is essential that the free entries are 
    // also marked reserved to GDI (PC_RESERVED). 
 
    // NOTE: We don't need to specify the palette caps flag 
    // DDPCAPS_INITIALIZE. This flag is obsolete. CreatePalette 
    // must be given a valid palette-entry array and always 
    // initializes from it. 
 
        hdc = GetDC(NULL); 
        GetSystemPaletteEntries(hdc, 0, 256, peColorTable); 
        ReleaseDC(NULL, hdc); 
 
        for (i = 0; i < 10; i++) 
            peColorTable[i].peFlags = D3DPAL_READONLY; 
        for (i = 10; i < 246; i++) 
            peColorTable[i].peFlags = D3DPAL_FREE | PC_RESERVED; 
        for (i = 246; i < 256; i++) 
            peColorTable[i].peFlags = D3DPAL_READONLY; 
        hRes = lpdd->lpVtbl->CreatePalette(lpdd, 
            DDPCAPS_8BIT, peColorTable, &lpddPalette, NULL); 
 
        if (FAILED(hRes)) 
            return hRes; 
 
        hRes = lpddPrimary->lpVtbl->SetPalette(lpddPrimary, 
                lpddPalette); 
            return hRes; 
    } 
 
    return DD_OK; 
}