/*++

Copyright (c) 1990-1995  Microsoft Corporation


Module Name:

    handle.c


Abstract:

    This module contains all function which deal with handle table for the
    common UI


Author:

    30-Jan-1996 Tue 16:28:56 created  -by-  Daniel Chou (danielc)


[Environment:]

    NT Windows - Common Printer Driver UI DLL


[Notes:]


Revision History:


--*/



#include "precomp.h"
#pragma  hdrstop


#define DBG_CPSUIFILENAME   DbgHandle


#define DBG_CPSUI_HTABLE    0x00000001
#define DBG_FINDHANDLE      0x00000002
#define DBG_ADD_DATA        0x00000004
#define DBG_HANDLE_DESTROY  0x00000008
#define DBG_GET_HPSPINFO    0x00000010
#define DBG_SEM             0x00000020

DEFINE_DBGVAR(0);


HANDLE              hCPSUIMutex = NULL;
CPSUIHANDLETABLE    CPSUIHandleTable = { NULL, 0, 0, 0, 0 };
extern DWORD        TlsIndex;




BOOL
LOCK_CPSUI_HANDLETABLE(
    VOID
    )

/*++

Routine Description:

    This function get the lock the object


Arguments:

    VOID

Return Value:

    BOOL


Author:

    27-Mar-1996 Wed 11:27:26 created  -by-  Daniel Chou (danielc)


Revision History:


--*/

{
    BOOL    Ok = FALSE;


    if (hCPSUIMutex) {

        WORD    Idx;

        switch (WaitForSingleObject(hCPSUIMutex, MAX_SEM_WAIT)) {

        case WAIT_OBJECT_0:

            //
            // Signaled, and own it now
            //

            if (!CPSUIHandleTable.cWait++) {

                CPSUIHandleTable.ThreadID = GetCurrentThreadId();
            }

            Idx = TLSVALUE_2_IDX(TlsGetValue(TlsIndex));

            TlsSetValue(TlsIndex,
                        ULongToPtr(MK_TLSVALUE(CPSUIHandleTable.cWait, Idx)));

            CPSUIDBG(DBG_SEM, ("LOCK_CPSUI_HANDLETABLE: ThreadID=%ld, cWait=%ld",
                        GetCurrentThreadId(), CPSUIHandleTable.cWait));

            Ok = TRUE;

            break;

        case WAIT_ABANDONED:

            CPSUIERR(("LockCPSUIObject()= WAIT_ABANDONED"));
            break;

        case WAIT_TIMEOUT:

            CPSUIERR(("LockCPSUIObject()= WAIT_TIMEOUT"));
            break;

        default:

            CPSUIERR(("LockCPSUIObject()= UNKNOWN"));
            break;
        }
    }

    return(Ok);
}



BOOL
UNLOCK_CPSUI_HANDLETABLE(
    VOID
    )

/*++

Routine Description:




Arguments:




Return Value:




Author:

    27-Mar-1996 Wed 11:39:37 created  -by-  Daniel Chou (danielc)


Revision History:


--*/

{
    BOOL    Ok = FALSE;


    if (hCPSUIMutex) {

        DWORD   ThreadID = GetCurrentThreadId();
        WORD    Idx;


        CPSUIDBG(DBG_SEM, ("UNLOCK_CPSUI_HANDLETABLE: ThreadID=%ld, cWait=%ld",
                    ThreadID, CPSUIHandleTable.cWait));

        if (ThreadID == CPSUIHandleTable.ThreadID) {

            if (CPSUIHandleTable.cWait) {

                if (--CPSUIHandleTable.cWait == 0) {

                    CPSUIHandleTable.ThreadID = NO_THREADID;
                }


                Idx = TLSVALUE_2_IDX(TlsGetValue(TlsIndex));

                TlsSetValue(TlsIndex,
                            ULongToPtr(MK_TLSVALUE(CPSUIHandleTable.cWait, Idx)));

                ReleaseMutex(hCPSUIMutex);
                Ok = TRUE;

            } else {

                CPSUIERR(("The Thread ID does not match=%ld",
                            CPSUIHandleTable.ThreadID));
            }

        } else {

            CPSUIERR(("The ThreadID=%ld does not own the mutex", ThreadID));
        }
    }

    return(Ok);
}




PCPSUIPAGE
HANDLETABLE_GetCPSUIPage(
    HANDLE      hTable
    )

/*++

Routine Description:

    This function take a handle table and return the pData assoicated with it,
    the pData must already added by HANDLETABLE_AddCPSUIPage()


Arguments:




Return Value:

    pCPSUIPage, NULL if FAILED


Author:

    28-Dec-1995 Thu 17:05:11 created  -by-  Daniel Chou (danielc)


Revision History:


--*/

{
    PDATATABLE  pDataTable;
    PCPSUIPAGE  pFoundPage = NULL;
    PCPSUIPAGE  pCPSUIPage;
    WORD        Idx;


    LOCK_CPSUI_HANDLETABLE();

    if ((hTable)                                                    &&
        (pDataTable = CPSUIHandleTable.pDataTable)                  &&
        (HANDLE_2_PREFIX(hTable) == HANDLE_TABLE_PREFIX)            &&
        ((Idx = HANDLE_2_IDX(hTable)) < CPSUIHandleTable.MaxCount)  &&
        (pCPSUIPage = pDataTable[Idx].pCPSUIPage)) {

        if (pCPSUIPage->ID != CPSUIPAGE_ID) {

            CPSUIERR(("HANDLETABLE_FindpCPSUIPage(%08lx), pCPSUIPage=%08lx INVALID Internal ID",
                        hTable, pCPSUIPage));

        } else if (pCPSUIPage->hCPSUIPage != hTable) {

            CPSUIERR(("HANDLETABLE_FIndpCPSUIPage(%08lx), pCPSUIPagePage=%08lx, HANDLE not matched",
                    hTable, pCPSUIPage));

        } else {

            pCPSUIPage->cLock++;
            pFoundPage = pCPSUIPage;
        }
    }

    UNLOCK_CPSUI_HANDLETABLE();

    return(pFoundPage);
}



DWORD
HANDLETABLE_LockCPSUIPage(
    PCPSUIPAGE  pCPSUIPage
    )

/*++

Routine Description:

    This function decrement the cLock for the Page currently in USE


Arguments:

    pCPSUIPage  - Pointer to the CPSUIPAGE


Return Value:

    BOOL, true if decrment successfully


Author:

    05-Apr-1996 Fri 16:41:46 created  -by-  Daniel Chou (danielc)


Revision History:


--*/

{
    DWORD   cLock = 0;


    if (pCPSUIPage) {

        LOCK_CPSUI_HANDLETABLE();

        cLock = ++(pCPSUIPage->cLock);

        UNLOCK_CPSUI_HANDLETABLE();
    }

    return(cLock);
}



BOOL
HANDLETABLE_UnGetCPSUIPage(
    PCPSUIPAGE  pCPSUIPage
    )

/*++

Routine Description:

    This function decrement the cLock for the Page currently in USE


Arguments:

    pCPSUIPage  - Pointer to the CPSUIPAGE


Return Value:

    BOOL, true if decrment successfully


Author:

    05-Apr-1996 Fri 16:41:46 created  -by-  Daniel Chou (danielc)


Revision History:


--*/

{
    BOOL    Ok;


    if (pCPSUIPage) {

        LOCK_CPSUI_HANDLETABLE();

        if (Ok = (BOOL)pCPSUIPage->cLock) {

            --(pCPSUIPage->cLock);

        } else {

            CPSUIERR(("HANDLETABLE_UnlockpCPSUIPage(%08lx), cLock is ZERO",
                            pCPSUIPage));
        }

        UNLOCK_CPSUI_HANDLETABLE();

    } else {

        Ok = FALSE;
    }

    return(Ok);
}



BOOL
HANDLETABLE_IsChildPage(
    PCPSUIPAGE  pChildPage,
    PCPSUIPAGE  pParentPage
    )

/*++

Routine Description:

    This function check if pChildPage is one of the pParentPage's child or
    its decedent child


Arguments:

    pChildPage  - Pointer to the CPSUIPAGE for child

    pParentPage - Pointer to the CPSUIPAGE for parent to be checked

Return Value:

    TRUE, if this is child, otherwise FALSE


Author:

    08-Apr-1996 Mon 12:52:51 created  -by-  Daniel Chou (danielc)


Revision History:


--*/

{
    BOOL    Ok = FALSE;


    LOCK_CPSUI_HANDLETABLE();


    if (pChildPage) {

        while (pChildPage->pParent) {

            if (pChildPage->pParent == pParentPage) {

                Ok = TRUE;
                break;

            } else {

                pChildPage = pChildPage->pParent;
            }
        }
    }

    UNLOCK_CPSUI_HANDLETABLE();

    return(Ok);
}






PCPSUIPAGE
HANDLETABLE_GetRootPage(
    PCPSUIPAGE  pCPSUIPage
    )

/*++

Routine Description:

    This function find the root page for pCPSUIPage

Arguments:

    pCPSUIPage  - Pointer to the CPSUIPAGE who's root page to be searched


Return Value:

    PCPSUIPAGE  - Pointer to root page, NULL if failed


Author:

    08-Apr-1996 Mon 12:49:42 created  -by-  Daniel Chou (danielc)


Revision History:


--*/

{
    PCPSUIPAGE  pPage;
    PCPSUIPAGE  pRootPage = NULL;


    LOCK_CPSUI_HANDLETABLE();


    pPage = pCPSUIPage;

    //
    // If we need to search for the root page, then try it now
    //

    while ((pPage) && (pPage->pParent)) {

        pPage = pPage->pParent;
    }

    if ((pPage) && (pPage->Flags & CPF_ROOT)) {

        pPage->cLock++;
        pRootPage = pPage;

    } else {

        CPSUIERR(("HANDLETABLE_FindpRootPage(%08lx): No ROOT Page found",
                    pCPSUIPage));
    }

    UNLOCK_CPSUI_HANDLETABLE();

    return(pRootPage);
}




HANDLE
HANDLETABLE_AddCPSUIPage(
    PCPSUIPAGE  pCPSUIPage
    )

/*++

Routine Description:

    This function add pData to the handle table, if new


Arguments:

    pCPSUIPage  - Pointer to the CPSUIPAGE to be add to the handle table


Return Value:

    HANDLE, if NULL then it failed, the handle already exists


Author:

    28-Dec-1995 Thu 16:03:25 created  -by-  Daniel Chou (danielc)


Revision History:


--*/

{
    HANDLE      hTable;
    PDATATABLE  pDataTable;


    LOCK_CPSUI_HANDLETABLE();

    if ((!CPSUIHandleTable.pDataTable) ||
        (CPSUIHandleTable.CurCount >= CPSUIHandleTable.MaxCount)) {

        if (!CPSUIHandleTable.pDataTable) {

            CPSUIHandleTable.CurCount =
            CPSUIHandleTable.MaxCount = 0;
        }

        CPSUIDBG(DBG_ADD_DATA,
                ("HANDLETABLE_AddCPSUIPage(%08lx): Table reach LIMIT, Expanded=%ld->%ld",
                CPSUIHandleTable.pDataTable,
                CPSUIHandleTable.CurCount,
                CPSUIHandleTable.CurCount + DATATABLE_BLK_COUNT));

        //
        // Reallocate Table
        //

        if ((CPSUIHandleTable.MaxCount <= DATATABLE_MAX_COUNT)  &&
            (pDataTable = LocalAlloc(LPTR,
                                    (CPSUIHandleTable.MaxCount +
                                                DATATABLE_BLK_COUNT) *
                                                        sizeof(DATATABLE)))) {

            if (CPSUIHandleTable.pDataTable) {

                CopyMemory(pDataTable,
                           CPSUIHandleTable.pDataTable,
                           CPSUIHandleTable.MaxCount * sizeof(DATATABLE));

                LocalFree((HLOCAL)CPSUIHandleTable.pDataTable);
            }

            CPSUIHandleTable.pDataTable  = pDataTable;
            CPSUIHandleTable.MaxCount   += DATATABLE_BLK_COUNT;

        } else {

            CPSUIERR(("HANDLETABLE_AddCPSUIPage(): Expand TABLE failed"));
        }
    }

    hTable = NULL;

    if (pDataTable = CPSUIHandleTable.pDataTable) {

        WORD    Idx;

        for (Idx = 0; Idx < CPSUIHandleTable.MaxCount; Idx++, pDataTable++) {

            if (!pDataTable->pCPSUIPage) {

                hTable                 = WORD_2_HANDLE(Idx);
                pDataTable->pCPSUIPage = pCPSUIPage;
                pCPSUIPage->cLock      = 1;

                CPSUIHandleTable.CurCount++;

                CPSUIDBG(DBG_ADD_DATA, ("HANDLETABLE_AddCPSUIPage(%08lx): Idx=%ld, Cur=%ld, Max=%ld",
                            pCPSUIPage, Idx,
                            CPSUIHandleTable.CurCount,
                            CPSUIHandleTable.MaxCount));

                break;

            } else if (pDataTable->pCPSUIPage == pCPSUIPage) {

                CPSUIERR(("HANDLETABLE_AddCPSUIPage(%08lx): pCPSUIPage exists, Idx=%ld",
                            pCPSUIPage, Idx));
            }
        }
    }

    if (!hTable) {

        CPSUIERR(("HANDLETABLE_AddCPSUIPage(%08lx:%ld) Cannot find empty entry",
                CPSUIHandleTable.pDataTable,
                CPSUIHandleTable.MaxCount));
    }

    UNLOCK_CPSUI_HANDLETABLE();

    return(hTable);
}




BOOL
HANDLETABLE_DeleteHandle(
    HANDLE  hTable
    )

/*++

Routine Description:

    This function delete a handle from the handle table


Arguments:

    hTable  - Handle to the handle table to be deleted


Return Value:

    BOOL


Author:

    28-Dec-1995 Thu 17:42:42 created  -by-  Daniel Chou (danielc)


Revision History:


--*/

{
    PDATATABLE  pDataTable;
    PCPSUIPAGE  pCPSUIPage;
    WORD        Idx;
    BOOL        Ok = FALSE;


    LOCK_CPSUI_HANDLETABLE();

    if ((pDataTable = CPSUIHandleTable.pDataTable)                  &&
        (HANDLE_2_PREFIX(hTable) == HANDLE_TABLE_PREFIX)            &&
        (CPSUIHandleTable.CurCount)                                 &&
        ((Idx = HANDLE_2_IDX(hTable)) < CPSUIHandleTable.MaxCount)  &&
        (pCPSUIPage = (pDataTable += Idx)->pCPSUIPage)) {

        if (pCPSUIPage->cLock) {

            CPSUIERR(("HANDLETABLE_DeleteHandle(%08lx), pCPSUIPage=%08lx, cLock=%ld",
                        hTable, pCPSUIPage, pCPSUIPage->cLock));

        } else {

            // check to release the activation context (if any)
            if (pCPSUIPage->hActCtx && pCPSUIPage->hActCtx != INVALID_HANDLE_VALUE) {

                ReleaseActCtx(pCPSUIPage->hActCtx);
                pCPSUIPage->hActCtx = INVALID_HANDLE_VALUE;
            }

            pDataTable->pCPSUIPage = NULL;
            Ok                     = TRUE;

            //
            // Reduce current count and free the memory
            //

            CPSUIHandleTable.CurCount--;

            LocalFree((HLOCAL)pCPSUIPage);
        }

    } else {

        CPSUIERR(("HANDLETABLE_DeleteHandle(%08lx) not found, Idx=%ld, pDataTable=%08lx",
                        hTable, Idx, pDataTable));
    }

    UNLOCK_CPSUI_HANDLETABLE();

    return(Ok);
}




BOOL
HANDLETABLE_Create(
    VOID
    )

/*++

Routine Description:




Arguments:




Return Value:




Author:

    28-Dec-1995 Thu 16:46:27 created  -by-  Daniel Chou (danielc)


Revision History:


--*/

{
    CPSUIHandleTable.pDataTable = NULL;
    CPSUIHandleTable.MaxCount   =
    CPSUIHandleTable.CurCount   = 0;
    CPSUIHandleTable.ThreadID   = NO_THREADID;
    CPSUIHandleTable.cWait      = 0;

    if (hCPSUIMutex = CreateMutex(NULL, FALSE, NULL)) {

        CPSUIDBG(DBG_CPSUI_HTABLE, ("CREATE: CreateMutex=%08lx", hCPSUIMutex));

        return(TRUE);

    } else {

        CPSUIERR(("CreateMutex() FAILED, Exit"));
        return(FALSE);
    }
}



VOID
HANDLETABLE_Destroy(
    VOID
    )

/*++

Routine Description:




Arguments:




Return Value:




Author:

    28-Dec-1995 Thu 16:48:32 created  -by-  Daniel Chou (danielc)


Revision History:


--*/

{
    PDATATABLE  pDataTable;
    WORD        Idx;

    LOCK_CPSUI_HANDLETABLE();

    if (hCPSUIMutex) {

        if (pDataTable = CPSUIHandleTable.pDataTable) {

            for (Idx = 0;
                 Idx < CPSUIHandleTable.MaxCount;
                 Idx++, pDataTable++) {

                if (pDataTable->pCPSUIPage) {

                    CPSUIERR(("HANDLETABLE_Destroy: Idx=%ld, pPage=%08lx, cLock=%ld is not delete yet",
                                    Idx, pDataTable->pCPSUIPage, pDataTable->pCPSUIPage->cLock));

                    LocalFree((HLOCAL)pDataTable->pCPSUIPage);

                    pDataTable->pCPSUIPage = NULL;

                    if (CPSUIHandleTable.CurCount) {

                        --(CPSUIHandleTable.CurCount);

                    } else {

                        CPSUIERR(("HANDLETABLE_Destroy(): Unmatched CurCount"));
                    }
                }
            }

            LocalFree((HLOCAL)CPSUIHandleTable.pDataTable);

            CPSUIHandleTable.pDataTable = NULL;
            CPSUIHandleTable.MaxCount   =
            CPSUIHandleTable.CurCount   = 0;
        }
    }

    UNLOCK_CPSUI_HANDLETABLE();

    CloseHandle(hCPSUIMutex);
}