/*++ 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 CRITICAL_SECTION faxuiSemaphore; // Semaphore for protecting critical sections HANDLE g_hModule; // DLL instance handle HANDLE g_hResource; // Resource DLL instance handle HANDLE g_hFxsApiModule = NULL; // FXSAPI.DLL instance handle PDOCEVENTUSERMEM gDocEventUserMemList = NULL; // Global list of user mode memory structures INT _debugLevel = 1; // for debuggping purposes static BOOL gs_bfaxuiSemaphoreInit = FALSE; // Flag for faxuiSemaphore CS initialization BOOL g_bSHFusionInitialized = FALSE; // Fusion initialized flag CRITICAL_SECTION g_csInitializeDll; // DLL initialization critical sections BOOL g_bInitDllCritSection = FALSE; // Critical sections initialization flag BOOL g_bDllInitialied = FALSE; // TRUE if the DLL successfuly initialized char g_szDelayLoadFxsApiName[64] = {0}; // Case sensitive name of FxsApi.dll for delay load mechanism static HMODULE gs_hShlwapi = NULL; // Shlwapi.dll handle PPATHISRELATIVEW g_pPathIsRelativeW = NULL; PPATHMAKEPRETTYW g_pPathMakePrettyW = NULL; PSHAUTOCOMPLETE g_pSHAutoComplete = NULL; // // Blocks the re-entrancy of FxsWzrd.dll // TRUE when there is running Fax Send Wizard instance // FALSE otherwise // BOOL g_bRunningWizard = FALSE; // // Protects the g_bRunningWizard global variable from being accessed by multiple threads simultaneously // CRITICAL_SECTION g_csRunningWizard; BOOL g_bInitRunningWizardCS = FALSE; PVOID PrMemAlloc( SIZE_T size ) { return (PVOID)LocalAlloc(LPTR, size); } PVOID PrMemReAlloc( HLOCAL hMem, SIZE_T size ) { return (PVOID)LocalReAlloc(hMem, size, LMEM_ZEROINIT); } VOID PrMemFree( PVOID ptr ) { if (ptr) { LocalFree((HLOCAL) ptr); } } FARPROC WINAPI DelayLoadHandler(unsigned dliNotify,PDelayLoadInfo pdli) { switch (dliNotify) { case dliNotePreLoadLibrary: if (_strnicmp(pdli->szDll, FAX_API_MODULE_NAME_A, strlen(FAX_API_MODULE_NAME_A))==0) { // // Save the sensitive name DLL name for later use // strncpy(g_szDelayLoadFxsApiName, pdli->szDll, ARR_SIZE(g_szDelayLoadFxsApiName)-1); // trying to load FXSAPI.DLL if(!g_hFxsApiModule) { Assert(FALSE); } return g_hFxsApiModule; } } return 0; } PfnDliHook __pfnDliNotifyHook = DelayLoadHandler; BOOL DllMain( 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. --*/ { switch (ulReason) { case DLL_PROCESS_ATTACH: { DWORD dwVersion = GetVersion(); if(4 == (LOBYTE(LOWORD(dwVersion))) && 0 == (HIBYTE(LOWORD(dwVersion)))) { // // The current OS is NT4 // // Keep our driver UI dll always loaded in memory // We need this for NT4 clients // TCHAR szDllName[MAX_PATH+1] = {0}; if (!GetModuleFileName(hModule, szDllName, ARR_SIZE(szDllName)-1)) { Error(("GetModuleFileName() failed with %d\n", GetLastError())); return FALSE; } if(!LoadLibrary(szDllName)) { Error(("LoadLibrary() failed with %d\n", GetLastError())); return FALSE; } } // NT4 if (!InitializeCriticalSectionAndSpinCount (&faxuiSemaphore, (DWORD)0x80000000)) { return FALSE; } gs_bfaxuiSemaphoreInit = TRUE; if (!InitializeCriticalSectionAndSpinCount (&g_csInitializeDll, (DWORD)0x80000000)) { return FALSE; } g_bInitDllCritSection = TRUE; if (!InitializeCriticalSectionAndSpinCount(&g_csRunningWizard, (DWORD)0x80000000)) { Error(("InitializeCriticalSectionAndSpinCount(&g_csRunningWizard) failed with %d\n", GetLastError())); return FALSE; } g_bInitRunningWizardCS = TRUE; g_hModule = hModule; g_hResource = GetResInstance(hModule); if(!g_hResource) { return FALSE; } HeapInitialize( NULL, PrMemAlloc, PrMemFree, PrMemReAlloc ); DisableThreadLibraryCalls(hModule); break; } case DLL_PROCESS_DETACH: while (gDocEventUserMemList != NULL) { PDOCEVENTUSERMEM pDocEventUserMem; pDocEventUserMem = gDocEventUserMemList; gDocEventUserMemList = gDocEventUserMemList->pNext; FreePDEVUserMem(pDocEventUserMem); } if (gs_bfaxuiSemaphoreInit) { DeleteCriticalSection(&faxuiSemaphore); gs_bfaxuiSemaphoreInit = FALSE; } if (g_bInitDllCritSection) { DeleteCriticalSection(&g_csInitializeDll); g_bInitDllCritSection = FALSE; } if (g_bInitRunningWizardCS) { DeleteCriticalSection(&g_csRunningWizard); g_bInitRunningWizardCS = FALSE; } UnInitializeDll(); HeapCleanup(); FreeResInstance(); break; } return TRUE; } // DllMain BOOL InitializeDll() { BOOL bRet = TRUE; INITCOMMONCONTROLSEX CommonControlsEx = {sizeof(INITCOMMONCONTROLSEX), ICC_WIN95_CLASSES|ICC_DATE_CLASSES}; if(!g_bInitDllCritSection) { Assert(FALSE); return FALSE; } EnterCriticalSection(&g_csInitializeDll); if(g_bDllInitialied) { // // The DLL already initialized // goto exit; } if (!InitCommonControlsEx(&CommonControlsEx)) { Verbose(("InitCommonControlsEx failed")); bRet = FALSE; goto exit; } // // Load FXSAPI.DLL // Used by Delay Load mechanism // g_hFxsApiModule = LoadLibraryFromLocalFolder(FAX_API_MODULE_NAME, g_hModule); if(!g_hFxsApiModule) { bRet = FALSE; goto exit; } if (IsWinXPOS()) { // // We use fusion only for WinXP/.NET operating systems // We also explictly link against shlwapi.dll for these operating systems. // if (!SHFusionInitializeFromModuleID(g_hModule, SXS_MANIFEST_RESOURCE_ID)) { Verbose(("SHFusionInitializeFromModuleID failed")); } else { g_bSHFusionInitialized = TRUE; } gs_hShlwapi = LoadLibrary (TEXT("shlwapi.dll")); if (gs_hShlwapi) { g_pPathIsRelativeW = (PPATHISRELATIVEW)GetProcAddress (gs_hShlwapi, "PathIsRelativeW"); g_pPathMakePrettyW = (PPATHMAKEPRETTYW)GetProcAddress (gs_hShlwapi, "PathMakePrettyW"); g_pSHAutoComplete = (PSHAUTOCOMPLETE) GetProcAddress (gs_hShlwapi, "SHAutoComplete"); if (!g_pPathIsRelativeW || !g_pPathMakePrettyW || !g_pSHAutoComplete) { Verbose (("Failed to link with shlwapi.dll - %d", GetLastError())); } } else { Verbose (("Failed to load shlwapi.dll - %d", GetLastError())); } } g_bDllInitialied = TRUE; exit: LeaveCriticalSection(&g_csInitializeDll); return bRet; } // InitializeDll VOID UnInitializeDll() { if(!g_bDllInitialied) { // // The DLL is not initialized // return; } if(g_hFxsApiModule) { // // Explicitly Unloading a Delay-Loaded DLL // if(!__FUnloadDelayLoadedDLL2(g_szDelayLoadFxsApiName)) { // // The DLL wasn't used by delay load // FreeLibrary(g_hFxsApiModule); } g_hFxsApiModule = NULL; } if (IsWinXPOS()) { // // We use fusion only for WinXP/.NET operating systems // We also explictly link against shlwapi.dll for these operating systems. // ReleaseActivationContext(); if (g_bSHFusionInitialized) { SHFusionUninitialize(); g_bSHFusionInitialized = FALSE; } if (gs_hShlwapi) { FreeLibrary (gs_hShlwapi); gs_hShlwapi = NULL; g_pPathIsRelativeW = NULL; g_pPathMakePrettyW = NULL; g_pSHAutoComplete = NULL; } } g_bDllInitialied = FALSE; } // UnInitializeDll 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 //@ not done then merge with the user default //@ not done finally merge with the input devmode //@ The end result of this merge operation is a dev mode with default values for all the public //@ fields that are not specified or not valid. Input values for all the specified fields in the //@ input dev mode that were specified and valid. And default (or per user in W2K) values for the private fields. 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) { //@ Generates the driver default dev mode by setting default values for the public fields //@ and loading per user dev mode for the private fields (W2K only for NT4 it sets default //@ values for the private fields too). 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 // //@ The merge process wil copy the private data as is. //@ for public data it will only consider the fields which are of interest to the fax printer. //@ it will copy them to the destination if they are specified and valid. //@ The end result of this merge operation is a dev mode with default values for all the public //@ fields that are not specified or not valid. Input values for all the specified fields in the //@ input dev mode that were specified and valid. And default (or per user in W2K) values for the private fields. 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; } 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 --*/ { // // Do not execute any code before this initialization // if(!InitializeDll()) { return FALSE; } return TRUE; }