summaryrefslogblamecommitdiffstats
path: root/private/mvdm/wow32/wreldc.c
blob: f7a124d367bf5c7cd704854c533ed9a96d8edc4a (plain) (tree)
































































































































































































































































































                                                                                              
//*****************************************************************************
//
// DC Cacheing -
//
//     Support for misbehaved apps - which continue to use a DC that has been
//     Released. Well the problem is WIN30 allows it, so we need to be
//     compatible.
//
//
// 03-Feb-92  NanduriR   Created.
//
//*****************************************************************************

#include "precomp.h"
#pragma hdrstop

MODNAME(wreldc.c);

BOOL GdiCleanCacheDC (HDC hdc16);

//*****************************************************************************
// count of currently cached DCs so that we can quickly check whether any
// ReleasedDCs are pending.
//
//*****************************************************************************

INT  iReleasedDCs = 0;


//*****************************************************************************
// The head of the linked list of the DCs Info.
//
//*****************************************************************************

LPDCCACHE lpDCCache = NULL;


//*****************************************************************************
// ReleaseCachedDCs -
//        ReleaseDC's a cached DC if it meets the 'search criterion'.
//        The Search flag indicates which input arguments will be used.
//        Unused arguments can be NULL or pure garbage.
//
//        NOTE: this does not free the memory that has been allocated for
//              the list.
//
//              We reset the flag 'flState' and thus will be able to
//              reuse the structure.
//
//        Returns TRUE
//*****************************************************************************

BOOL ReleaseCachedDCs(HAND16 htask16, HAND16 hwnd16, HAND16 hdc16,
                            HWND hwnd32, UINT flSearch)
{
    HAND16 hdcTemp;
    LPDCCACHE lpT;

    UNREFERENCED_PARAMETER(hdc16);

    if (iReleasedDCs) {
        for (lpT = lpDCCache; lpT != NULL; lpT = lpT->lpNext) {

             if (!(lpT->flState & DCCACHE_STATE_RELPENDING))
                 continue;

             hdcTemp = (HAND16)NULL;

             if (flSearch & SRCHDC_TASK16_HWND16) {

                 if (lpT->htask16 == htask16 &&
                         lpT->hwnd16 == hwnd16)
                     hdcTemp = lpT->hdc16;

             }
             else if (flSearch & SRCHDC_TASK16) {

                 if (lpT->htask16 == htask16)
                     hdcTemp = lpT->hdc16;

             }
             else {
                 LOGDEBUG(0, ("ReleaseCachedDCs:Invalid Search Flag\n"));
             }

             if (hdcTemp) {
                 if (ReleaseDC(lpT->hwnd32, HDC32(hdcTemp))) {
                     LOGDEBUG(6,
                         ("ReleaseCachedDCs: success hdc16 %04x - count %04x\n",
                                                   hdcTemp, (iReleasedDCs-1)));
                 }
                 else {
                     LOGDEBUG(7, ("ReleaseCachedDCs: FAILED hdc16 %04x\n",
                                                                    hdcTemp));
                 }

                 // reset the state evenif ReleaseDC failed

                 lpT->flState = 0;
                 FREEHDC16(hdcTemp);
                 if (!(--iReleasedDCs))
                     break;
             }
        }
    }

    return TRUE;
}


//*****************************************************************************
// FreeCachedDCs -
//        ReleaseDC's a cached DC - Normally called during taskexit.
//
//        NOTE: this does not free the memory that has been allocated for
//              the list.
//
//              We reset the flag 'flState' and thus will be able to
//              reuse the structure.
//
//        Returns TRUE
//*****************************************************************************

BOOL FreeCachedDCs(HAND16 htask16)
{
    HAND16 hdcTemp;
    LPDCCACHE lpT;

    for (lpT = lpDCCache; lpT != NULL; lpT = lpT->lpNext) {

         if ((lpT->flState & DCCACHE_STATE_INUSE) &&
                                               lpT->htask16 == htask16) {

             hdcTemp = lpT->hdc16;
             if (lpT->flState & DCCACHE_STATE_RELPENDING) {

                 if (ReleaseDC(lpT->hwnd32, HDC32(hdcTemp))) {
                     LOGDEBUG(6,
                         ("FreeCachedDCs: success hdc16 %04x - task %04x\n",
                                                               hdcTemp, htask16));
                 }
                 else {
                     LOGDEBUG(7, ("FreeCachedDCs: FAILED hdc16 %04x - task %04x\n",
                                                             hdcTemp, htask16));
                 }

                 WOW32ASSERT(iReleasedDCs != 0);
                 --iReleasedDCs;
             }

             lpT->flState = 0;
             FREEHDC16(hdcTemp);
         }
    }

    return TRUE;
}


//*****************************************************************************
// StoredDC -
//
//        Initializes a DCCACHE structure with appropriate values.
//        Uses an empty slot in the linked list if available else
//        allocates a new one and adds to the head of the list.
//
//        Returns TRUE on success, FALSE on failure
//*****************************************************************************

BOOL StoreDC(HAND16 htask16, HAND16 hwnd16, HAND16 hdc16)
{
    HAND16 hdcTemp = (HAND16)NULL;
    LPDCCACHE lpT, lpNew;

    // Check for  an 'inuse' slot that will match the one that will be created
    // or check for an empty slot.
    //
    // An existing 'inuse' slot may match the one that's being created if
    // an app makes multiple calls to GetDC(hwnd) without an intervening
    // ReleaseDC. eg. MathCad.
    //                                                     - Nanduri

    lpNew = (LPDCCACHE)NULL;
    for (lpT = lpDCCache; lpT != NULL; lpT = lpT->lpNext) {
         if (lpT->flState & DCCACHE_STATE_INUSE) {
             if (lpT->hdc16 == hdc16) {
                 if (lpT->hwnd16 == hwnd16 &&
                         lpT->htask16 == htask16  ) {
                     LOGDEBUG(6, ("WOW:An identical second GetDC call without ReleaseDC\n"));
                 }
                 else {
                     LOGDEBUG(6, ("WOW:New DC 0x%04x exists - replacing old cache\n", hdc16));
                 }

                 if (lpT->flState & DCCACHE_STATE_RELPENDING) {
                     WOW32ASSERT(iReleasedDCs != 0);
                     --iReleasedDCs;
                 }

                 lpNew = lpT;
                 break;
             }
         }
         else {
             if (!lpNew)
                 lpNew = lpT;
         }
    }
    lpT = lpNew;

    if (lpT == NULL) {
        lpT = (LPDCCACHE)malloc_w_small(sizeof(DCCACHE));
        if (lpT) {
            lpT->lpNext = lpDCCache;
            lpDCCache = lpT;
        }
        else {
            LOGDEBUG(0, ("StoreDC: malloc_w_small for cache failed\n"));
        }
    }

    if (lpT != NULL) {
        lpT->flState = DCCACHE_STATE_INUSE;
        lpT->htask16 = htask16;
        lpT->hwnd16 = hwnd16;
        lpT->hdc16 = hdc16;
        lpT->hwnd32 = HWND32(hwnd16);
        LOGDEBUG(6, ("StoreDC: Added hdc %04x\n",hdc16));
        return TRUE;
    }
    else
        return FALSE;
}

//*****************************************************************************
// CacheReleasedDC -
//
//        Increments iReleasedDCs to indicate that a ReleaseDC is pending.
//
//        Increments the iReleasedDC only if there was a corresponding GetDC.
//        i.e, only if the DC exists in the DCcache;
//
//        This is to handle the scenrio below:
//                 hdc = BeginPaint(hwnd,..);
//                 ReleaseDC(hwnd, hdc);
//                 EndPaint(hwnd, ..);
//
//
//        Returns TRUE on success, FALSE on failure
//*****************************************************************************

BOOL CacheReleasedDC(HAND16 htask16, HAND16 hwnd16, HAND16 hdc16)
{
    HAND16 hdcTemp = (HAND16)NULL;
    LPDCCACHE lpT;

    for (lpT = lpDCCache; lpT != NULL; lpT = lpT->lpNext) {

         if ((lpT->flState & DCCACHE_STATE_INUSE) &&
                 lpT->htask16 == htask16 &&
                 lpT->hwnd16 == hwnd16 &&
                 lpT->hdc16 == hdc16  ) {


             // the app might do releasedc twice on the same dc by mistake

             if (!(lpT->flState & DCCACHE_STATE_RELPENDING)) {
                 lpT->flState |= DCCACHE_STATE_RELPENDING;
                 iReleasedDCs++;
             }
             LOGDEBUG(6, ("CachedReleasedDC: Pending hdc %04x - count %04x\n",
                                                         hdc16, iReleasedDCs));
             GdiCleanCacheDC (HDC32(hdc16));

             // Fix apps that draw then do lots
             // of disk activity, usually they do
             // a releaseDC.  This flush will syncronize
             // the drawing with the beginning of the
             // disk activity.  Bug #9704 PackRats install program draws text too late

             GdiFlush();

             return TRUE;
         }

    }

    return FALSE;
}