/*++

Copyright (c) 1996  Microsoft Corporation

Module Name:

    faxui.c

Abstract:

    Common routines for fax driver user interface

Environment:

    Fax driver user interface

Revision History:

    01/09/96 -davidx-
        Created it.

    mm/dd/yy -author-
        description

--*/

#include "faxui.h"
#include "forms.h"
#include <shlobj.h>


CRITICAL_SECTION    faxuiSemaphore;     // Semaphore for protecting critical sections
HANDLE              ghInstance;         // DLL instance handle
PUSERMEM            gUserMemList;       // Global list of user mode memory structures
INT                 _debugLevel = 1;    // for debuggping purposes

PVOID
PrMemAlloc(
    DWORD size
    )
{
    return (PVOID)LocalAlloc(LPTR, size);
}

VOID
PrMemFree(
    PVOID ptr
    )
{
    if (ptr) {
        LocalFree((HLOCAL) ptr);
    }
}



BOOL
DllEntryPoint(
    HANDLE      hModule,
    ULONG       ulReason,
    PCONTEXT    pContext
    )

/*++

Routine Description:

    DLL initialization procedure.

Arguments:

    hModule - DLL instance handle
    ulReason - Reason for the call
    pContext - Pointer to context (not used by us)

Return Value:

    TRUE if DLL is initialized successfully, FALSE otherwise.

--*/

{
    WCHAR       DllName[MAX_PATH];
    INITCOMMONCONTROLSEX CommonControlsEx = {sizeof(INITCOMMONCONTROLSEX),
                                             ICC_WIN95_CLASSES|ICC_DATE_CLASSES };

    switch (ulReason) {

    case DLL_PROCESS_ATTACH:

        //
        // Keep our driver UI dll always loaded in memory
        //

        if (! GetModuleFileName(hModule, DllName, MAX_PATH) ||
            ! LoadLibrary(DllName))
        {
            return FALSE;
        }

        ghInstance = hModule;
        gUserMemList = NULL;

        HeapInitialize( NULL, PrMemAlloc, PrMemFree, HEAPINIT_NO_VALIDATION | HEAPINIT_NO_STRINGS );

        InitializeCriticalSection(&faxuiSemaphore);
        InitCommonControlsEx(&CommonControlsEx);
        break;

    case DLL_PROCESS_DETACH:

        while (gUserMemList != NULL) {

            PUSERMEM    pUserMem;

            pUserMem = gUserMemList;
            gUserMemList = gUserMemList->pNext;
            FreePDEVUserMem(pUserMem);
        }

        DeleteCriticalSection(&faxuiSemaphore);
        break;
    }

    return TRUE;
}



LONG
CallCompstui(
    HWND            hwndOwner,
    PFNPROPSHEETUI  pfnPropSheetUI,
    LPARAM          lParam,
    PDWORD          pResult
    )

/*++

Routine Description:

    Calling common UI DLL entry point dynamically

Arguments:

    hwndOwner, pfnPropSheetUI, lParam, pResult - Parameters passed to common UI DLL

Return Value:

    Return value from common UI library

--*/

{
    HINSTANCE   hInstCompstui;
    FARPROC     pProc;
    LONG        Result = ERR_CPSUI_GETLASTERROR;

    //
    // Only need to call the ANSI version of LoadLibrary
    //

    static const CHAR szCompstui[] = "compstui.dll";
    static const CHAR szCommonPropSheetUI[] = "CommonPropertySheetUIW";

    if ((hInstCompstui = LoadLibraryA(szCompstui)) &&
        (pProc = GetProcAddress(hInstCompstui, szCommonPropSheetUI)))
    {
        Result = (LONG)(*pProc)(hwndOwner, pfnPropSheetUI, lParam, pResult);
    }

    if (hInstCompstui)
        FreeLibrary(hInstCompstui);

    return Result;
}



VOID
GetCombinedDevmode(
    PDRVDEVMODE     pdmOut,
    PDEVMODE        pdmIn,
    HANDLE          hPrinter,
    PPRINTER_INFO_2 pPrinterInfo2,
    BOOL            publicOnly
    )

/*++

Routine Description:

    Combine DEVMODE information:
     start with the driver default
     then merge with the system default
     then merge with the user default
     finally merge with the input devmode

Arguments:

    pdmOut - Pointer to the output devmode buffer
    pdmIn - Pointer to an input devmode
    hPrinter - Handle to a printer object
    pPrinterInfo2 - Point to a PRINTER_INFO_2 structure or NULL
    publicOnly - Only merge the public portion of the devmode

Return Value:

    TRUE

--*/

{
    PPRINTER_INFO_2 pAlloced = NULL;
    PDEVMODE        pdmUser;

    //
    // Get a PRINTER_INFO_2 structure if one is not provided
    //

    if (! pPrinterInfo2)
        pPrinterInfo2 = pAlloced = MyGetPrinter(hPrinter, 2);

    //
    // Start with driver default devmode
    //

    if (! publicOnly) {

        DriverDefaultDevmode(pdmOut,
                             pPrinterInfo2 ? pPrinterInfo2->pPrinterName : NULL,
                             hPrinter);
    }

    //
    // Merge with the system default devmode and user default devmode
    //

    if (pPrinterInfo2) {

        #if 0

        //
        // Since we have per-user devmode and there is no way to
        // change the printer's default devmode, there is no need
        // to merge it here.
        //

        if (! MergeDevmode(pdmOut, pPrinterInfo2->pDevMode, publicOnly))
            Error(("Invalid system default devmode\n"));

        #endif

        if (pdmUser = GetPerUserDevmode(pPrinterInfo2->pPrinterName)) {

            if (! MergeDevmode(pdmOut, pdmUser, publicOnly))
                Error(("Invalid user devmode\n"));

            MemFree(pdmUser);
        }
    }

    MemFree(pAlloced);

    //
    // Merge with the input devmode
    //

    if (! MergeDevmode(pdmOut, pdmIn, publicOnly))
        Error(("Invalid input devmode\n"));
}



PUIDATA
FillUiData(
    HANDLE      hPrinter,
    PDEVMODE    pdmInput
    )

/*++

Routine Description:

    Fill in the data structure used by the fax driver user interface

Arguments:

    hPrinter - Handle to the printer
    pdmInput - Pointer to input devmode, NULL if there is none

Return Value:

    Pointer to UIDATA structure, NULL if error.

--*/

{
    PRINTER_INFO_2 *pPrinterInfo2 = NULL;
    PUIDATA         pUiData = NULL;
    HANDLE          hheap = NULL;

    //
    // Create a heap to manage memory
    // Allocate memory to hold UIDATA structure
    // Get printer info from the spooler
    // Copy the driver name
    //

    if (! (hheap = HeapCreate(0, 4096, 0)) ||
        ! (pUiData = HeapAlloc(hheap, HEAP_ZERO_MEMORY, sizeof(UIDATA))) ||
        ! (pPrinterInfo2 = MyGetPrinter(hPrinter, 2)))
    {
        if (hheap)
            HeapDestroy(hheap);

        MemFree(pPrinterInfo2);
        return NULL;
    }

    pUiData->startSign = pUiData->endSign = pUiData;
    pUiData->hPrinter = hPrinter;
    pUiData->hheap = hheap;

    //
    // Combine various devmode information
    //

    GetCombinedDevmode(&pUiData->devmode, pdmInput, hPrinter, pPrinterInfo2, FALSE);

    //
    // Validate the form requested by the input devmode
    //

    if (! ValidDevmodeForm(hPrinter, &pUiData->devmode.dmPublic, NULL))
        Error(("Invalid form specification\n"));

    MemFree(pPrinterInfo2);
    return pUiData;
}



INT
DisplayMessageDialog(
    HWND    hwndParent,
    UINT    type,
    INT     titleStrId,
    INT     formatStrId,
    ...
    )

/*++

Routine Description:

    Display a message dialog box

Arguments:

    hwndParent - Specifies a parent window for the error message dialog
    titleStrId - Title string (could be a string resource ID)
    formatStrId - Message format string (could be a string resource ID)
    ...

Return Value:

    NONE

--*/

{
    LPTSTR  pTitle, pFormat, pMessage;
    INT     result;
    va_list ap;

    pTitle = pFormat = pMessage = NULL;

    if ((pTitle = AllocStringZ(MAX_TITLE_LEN)) &&
        (pFormat = AllocStringZ(MAX_STRING_LEN)) &&
        (pMessage = AllocStringZ(MAX_MESSAGE_LEN)))
    {
        //
        // Load dialog box title string resource
        //

        if (titleStrId == 0)
            titleStrId = IDS_ERROR_DLGTITLE;

        LoadString(ghInstance, titleStrId, pTitle, MAX_TITLE_LEN);

        //
        // Load message format string resource
        //

        LoadString(ghInstance, formatStrId, pFormat, MAX_STRING_LEN);

        //
        // Compose the message string
        //

        va_start(ap, formatStrId);
        wvsprintf(pMessage, pFormat, ap);
        va_end(ap);

        //
        // Display the message box
        //

        if (type == 0)
            type = MB_OK | MB_ICONERROR;

        result = MessageBox(hwndParent, pMessage, pTitle, type);

    } else {

        MessageBeep(MB_ICONHAND);
        result = 0;
    }

    MemFree(pTitle);
    MemFree(pFormat);
    MemFree(pMessage);
    return result;
}



BOOL
DevQueryPrintEx(
    PDEVQUERYPRINT_INFO pDQPInfo
    )

/*++

Routine Description:

    Implementation of DDI entry point DevQueryPrintEx. Even though we don't
    really need this entry point, we must export it so that the spooler
    will load our driver UI.

Arguments:

    pDQPInfo - Points to a DEVQUERYPRINT_INFO structure

Return Value:

    TRUE if there is no conflicts, FALSE otherwise

--*/

{
    return TRUE;
}