You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
640 lines
16 KiB
640 lines
16 KiB
/*++
|
|
|
|
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 <delayimp.h>
|
|
|
|
|
|
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;
|
|
}
|
|
|