|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
prnevent.c
Abstract:
This file handles the DrvPrinterEvent spooler API.
Environment:
Win32 subsystem, DriverUI module, user mode
Revision History:
08/30/00 -fengy- Added DrvDocumentEvent support.
02/13/97 -davidx- Implement OEM plugin support.
02/06/97 -davidx- Rewrote it to use common data management functions.
02/04/97 -davidx- Reorganize driver UI to separate ps and uni DLLs.
07/17/96 -amandan- Modified for common UI and shared binary data
05/20/96 -davidx- Created it.
--*/
#include "precomp.h"
//
// DOCUMENTEVENT_QUERYFILTER is introduced in Whistler.
// We need to define it if it's not defined (on Win2K)
// so our code can be built with Win2K DDK.
//
#ifndef DOCUMENTEVENT_QUERYFILTER
#define DOCUMENTEVENT_QUERYFILTER 14
#endif
//
// Private APIs exported by the spooler for printer drivers and port monitors.
// These must be kept in sync with winsplp.h.
//
typedef HANDLE (*LPREVERTTOPRINTERSELF)(VOID); typedef BOOL (*LPIMPERSONATEPRINTERCLIENT)(HANDLE);
//
// Forward and external function declarations
//
BOOL BInitOrUpgradePrinterProperties(PCOMMONINFO); VOID DeleteFontIntallerFile(HANDLE);
PTSTR GetBinaryFileName( PTSTR ptstrDataFileName ) /*++
Routine Description:
This function generates a binary file name from the data file name.
Arguments:
ptstrDataFileName specifies the data file name
Return Value:
TRUE for success and FALSE for failure
Note:
--*/
{
INT iLen; PTSTR ptstrFileName, ptstrExtension; PTSTR ptstrBinaryExt, ptstrFileExt;
ptstrFileName = ptstrExtension = NULL;
#ifdef UNIDRV
ptstrBinaryExt = BUD_FILENAME_EXT; ptstrFileExt = GPD_FILENAME_EXT;
#else
ptstrBinaryExt = BPD_FILENAME_EXT; ptstrFileExt = PPD_FILENAME_EXT;
#endif
iLen = _tcslen(ptstrDataFileName);
if ((ptstrExtension = _tcsrchr(ptstrDataFileName, TEXT('.'))) == NULL || _tcsicmp(ptstrExtension, ptstrFileExt) != EQUAL_STRING) { ptstrExtension = ptstrDataFileName + iLen; iLen += _tcslen(ptstrBinaryExt); }
if (ptstrFileName = MemAlloc((iLen + 1) * sizeof(TCHAR))) { StringCchCopyW(ptstrFileName, iLen + 1, ptstrDataFileName);
//
// The first if-block ensures that (ptstrExtension - ptstrDataFileName) is
// non-negative, and (iLen + 1) is greater than (ptstrExtension - ptstrDataFileName).
//
StringCchCopyW(ptstrFileName + (ptstrExtension - ptstrDataFileName), (iLen + 1) - (ptstrExtension - ptstrDataFileName), ptstrBinaryExt); }
return ptstrFileName; }
BOOL DrvDriverEvent( DWORD dwDriverEvent, DWORD dwLevel, LPBYTE pDriverInfo, LPARAM lParam ) /*++
Routine Description:
This function handles the DrvDriverEvent spooler API
Arguments:
dwDriverEvent specifies the event dwLevel level of DRIVER_INFO_* pDriverInfo pointer to DRIVER_INFO_* lParam event specific parameters.
Return Value:
TRUE for success and FALSE for failure
Note:
--*/
{ BOOL bResult = TRUE;
#ifndef WINNT_40
PDRIVER_INFO_3 pDriverInfo3 = (PDRIVER_INFO_3)pDriverInfo; PTSTR ptstrFileName;
if ((dwLevel != 3) || (pDriverInfo3 == NULL) || (pDriverInfo3->pDataFile == NULL)) return FALSE;
switch (dwDriverEvent) { case DRIVER_EVENT_INITIALIZE: break;
case DRIVER_EVENT_DELETE:
//
// Need to delete the binary data generated by the parsers
//
ptstrFileName = GetBinaryFileName(pDriverInfo3->pDataFile);
if (ptstrFileName) { DeleteFile(ptstrFileName); MemFree(ptstrFileName); } }
//
// Call the OEM to handle DrvDriverEvent
//
{ PFN_OEMDriverEvent pfnOEMDriverEvent; POEM_PLUGINS pOemPlugins; POEM_PLUGIN_ENTRY pOemEntry; DWORD dwOemCount;
if (! (pOemPlugins = PGetOemPluginInfo(NULL, pDriverInfo3->pConfigFile, pDriverInfo3)) || ! BLoadOEMPluginModules(pOemPlugins)) { ERR(("DrvDriverEvent, Cannot load OEM plugins: %d\n", GetLastError())); if (pOemPlugins) { VFreeOemPluginInfo(pOemPlugins); }
return FALSE; }
dwOemCount = pOemPlugins->dwCount; pOemEntry = pOemPlugins->aPlugins;
//
// call OEMDriverEvent entrypoint for each plugin
//
for (; dwOemCount--; pOemEntry++) { if (pOemEntry->hInstance == NULL) continue;
if (HAS_COM_INTERFACE(pOemEntry)) { HRESULT hr;
hr = HComOEMDriverEvent(pOemEntry, dwDriverEvent, dwLevel, pDriverInfo, lParam);
if (hr == E_NOTIMPL) continue;
bResult = SUCCEEDED(hr);
} else { if ((pfnOEMDriverEvent = GET_OEM_ENTRYPOINT(pOemEntry, OEMDriverEvent)) && !pfnOEMDriverEvent(dwDriverEvent, dwLevel, pDriverInfo, lParam)) { ERR(("OEMDriverEvent failed for '%ws': %d\n", CURRENT_OEM_MODULE_NAME(pOemEntry), GetLastError()));
bResult = FALSE; } } }
if (pOemPlugins) VFreeOemPluginInfo(pOemPlugins); }
#endif // WINNT_40
return bResult; }
/*++
Routine Name:
DrvDocumentEvent
Routine Description:
Handle certain events associated with printing a document.
Although our core driver doesn't do anything for any events, this function allows OEM plugins to add their event handling.
Arguments:
hPrinter - printer handle hdc - device contect handle iEsc - escape code identifying the event to be handled cbIn - size in bytes of the array pointed to by pbIn pbIn - pointer to a ULONG array, whose usage depends on iEsc cbOut - only used as cbOutput parameter for ExtEscape pbOut - pointer to an output buffer, whose usage depends on iEsc
Return Value:
DOCUMENTEVENT_FAILURE - iEsc event is supported but a failure occurred DOCUMENTEVENT_SUCCESS - iEsc event is handled successfully DOCUMENTEVENT_UNSUPPORTED - iEsc event is not supported
Last Error:
None
--*/ INT DrvDocumentEvent( HANDLE hPrinter, HDC hdc, int iEsc, ULONG cbIn,
#ifdef WINNT_40
PULONG pbIn, #else
PVOID pbIn, #endif
ULONG cbOut,
#ifdef WINNT_40
PULONG pbOut #else
PVOID pbOut #endif
) { POEM_PLUGINS pOemPlugins = NULL; PDRIVER_INFO_3 pDriverInfo3 = NULL; INT iReturn;
if ((pDriverInfo3 = MyGetPrinterDriver(hPrinter, NULL, 3)) == NULL) { ERR(("Cannot get printer driver info: %d\n", GetLastError())); iReturn = DOCUMENTEVENT_FAILURE; goto docevent_exit; }
if (!(pOemPlugins = PGetOemPluginInfo(hPrinter, pDriverInfo3->pConfigFile, pDriverInfo3)) || !BLoadOEMPluginModules(pOemPlugins)) { ERR(("Cannot get OEM plugin info: %d\n", GetLastError())); iReturn = DOCUMENTEVENT_FAILURE; goto docevent_exit; }
if (pOemPlugins->dwCount) { POEM_PLUGIN_ENTRY pOemEntry = pOemPlugins->aPlugins; DWORD cOemCount = pOemPlugins->dwCount; INT iResult; BOOL bOEMDocEventOK = FALSE;
for ( ; cOemCount--; pOemEntry++) { HRESULT hr;
if (pOemEntry->hInstance == NULL || !HAS_COM_INTERFACE(pOemEntry)) { continue; }
hr = HComOEMDocumentEvent(pOemEntry, hPrinter, hdc, iEsc, cbIn, (PVOID)pbIn, cbOut, (PVOID)pbOut, &iResult);
if (SUCCEEDED(hr)) { bOEMDocEventOK = TRUE;
#ifndef WINNT_40
//
// DOCUMENTEVENT_QUERYFILTER is introduced in Whistler.
//
if (iEsc == DOCUMENTEVENT_QUERYFILTER) { //
// At most one plugin is allowed to handle the event
// DOCUMENTEVENT_QUERYFILTER, and the filter it specifies
// will be used by spooler.
//
// For all other events, we will call every plugin so
// each will have the chance to perform its tasks.
//
break; }
#endif // !WINNT_40
} }
if (bOEMDocEventOK) { //
// At least one plugin handled the event successfully, so
// use the return value specified by the plugin(s).
//
iReturn = iResult; } else { //
// None of the plugins handled the event successfully.
//
iReturn = DOCUMENTEVENT_UNSUPPORTED; } } else { //
// There is no plugin.
//
iReturn = DOCUMENTEVENT_UNSUPPORTED; }
docevent_exit:
if (pDriverInfo3) { MemFree(pDriverInfo3); }
if (pOemPlugins) { VFreeOemPluginInfo(pOemPlugins); }
//
// If there is no plugin, or none of the plugins handles DocumentEvent
// successfully, we return DOCUMENTEVENT_UNSUPPORTED since our driver
// doesn't do anything for DrvDocumentEvent. When spooler sees this
// return value for DOCUMENTEVENT_CREATEDCPRE, it will decide not to
// make any more event calls to the driver.
//
// If the event is handled successfully by the plugins, we will return
// the return value specified by the plugin(s).
//
return iReturn; }
BOOL DrvPrinterEvent( LPWSTR pPrinterName, INT DriverEvent, DWORD Flags, LPARAM lParam ) /*++
Routine Description:
This function handles the DrvPrinterEvent spooler API
Arguments:
pPrinterName name of device DriverEvent specifies the event Flags bits flag lParam event specific parameters.
Return Value:
TRUE for success and FALSE for failure
Note:
--*/
{ LPREVERTTOPRINTERSELF pRevertToPrinterSelf; LPIMPERSONATEPRINTERCLIENT pImpersonatePrinterClient; HINSTANCE hSpoolss = NULL; HANDLE hToken = NULL; PCOMMONINFO pci = NULL; HANDLE hPrinter = NULL; BOOL bResult = TRUE; CACHEDFILE CachedFile;
VERBOSE(("Entering DrvPrinterEvent: %d ...\n", DriverEvent));
switch (DriverEvent) { case PRINTER_EVENT_CACHE_REFRESH:
//
// Open a handle to the printer connection
//
if (! OpenPrinter(pPrinterName, &hPrinter, NULL)) { ERR(("OpenPrinter '%ws' failed: %d\n", pPrinterName, GetLastError())); hPrinter = NULL; break; }
//
// Prepare to copy cached driver files from the server, if any
//
#ifdef PSCRIPT
_BPrepareToCopyCachedFile(hPrinter, &CachedFile, REGVAL_NTFFILENAME); #else
_BPrepareToCopyCachedFile(hPrinter, &CachedFile, REGVAL_FONTFILENAME); #endif
//
// Load spoolss.dll and get address of functions:
// RevertToPrinterSelf - switch to spooler's security context
// ImpersonatePrinterClient - switch to current user's security context
//
if (! (hSpoolss = LoadLibrary(TEXT("spoolss.dll"))) || ! (pRevertToPrinterSelf = (LPREVERTTOPRINTERSELF) GetProcAddress(hSpoolss, "RevertToPrinterSelf")) || ! (pImpersonatePrinterClient = (LPIMPERSONATEPRINTERCLIENT) GetProcAddress(hSpoolss, "ImpersonatePrinterClient"))) { ERR(("Couldn't load spoolss.dll: %d\n", GetLastError()));
if (hSpoolss != NULL) FreeLibrary(hSpoolss);
_VDisposeCachedFileInfo(&CachedFile);
break; }
//
// Switch to spooler security context so that we can create
// binary printer description data file in the driver directory
//
// When we call to load raw printer description data, the parser
// will check its cache. If no binary data file exists or existing
// binary data file is out of date, the parser will regenerate
// an up-to-date binary data file.
//
hToken = pRevertToPrinterSelf(); pci = PLoadCommonInfo(hPrinter, pPrinterName, 0);
//
// Copy cached driver file from the server
//
_BCopyCachedFile(pci, &CachedFile); _VDisposeCachedFileInfo(&CachedFile);
if (hToken) { if (!(bResult = pImpersonatePrinterClient(hToken))) { ERR(("PrinterEvent-ImpersonatePrinterClient failed: %d\n", GetLastError())); } }
FreeLibrary(hSpoolss); break;
case PRINTER_EVENT_INITIALIZE:
//
// Open a printer with administrator privilege, and
// process OEM plugin configuration information
//
pci = PLoadCommonInfo(NULL, pPrinterName, FLAG_OPENPRINTER_ADMIN|FLAG_INIT_PRINTER);
if (pci == NULL) break;
//
// Initialize default printer-sticky properties in registry
// Add printer forms to the spooler's forms database
//
(VOID) BInitOrUpgradePrinterProperties(pci);
#ifndef WINNT_40
VNotifyDSOfUpdate(pci->hPrinter);
#endif // !WINNT_40
break;
case PRINTER_EVENT_ADD_CONNECTION:
//
// Fix the bug where when NT5 client connects to NT4 server, the server registry
// doesn't have the REGVAL_INIDATA entry. Calling PLoadCommonInfo with
// FLAG_PROCESS_INIFILE will write REGVAL_INIDATA to NT4 registry.
//
pci = PLoadCommonInfo(NULL, pPrinterName, FLAG_OPENPRINTER_NORMAL|FLAG_PROCESS_INIFILE); break;
#ifdef UNIDRV
case PRINTER_EVENT_DELETE: case PRINTER_EVENT_DELETE_CONNECTION:
//
// Delete font installer file
//
//
// Open a handle to the printer
//
if (! OpenPrinter(pPrinterName, &hPrinter, NULL)) { ERR(("OpenPrinter '%ws' failed: %d\n", pPrinterName, GetLastError())); hPrinter = NULL; break; }
pci = PLoadCommonInfo(NULL, pPrinterName, FLAG_OPENPRINTER_NORMAL);
DeleteFontIntallerFile(hPrinter);
break;
#endif
default:
pci = PLoadCommonInfo(NULL, pPrinterName, FLAG_OPENPRINTER_NORMAL); break; }
if (pci != NULL) { if (bResult) { PFN_OEMPrinterEvent pfnOEMPrinterEvent;
//
// call OEMPrinterEvent entrypoint for each plugin
//
FOREACH_OEMPLUGIN_LOOP(pci)
if (HAS_COM_INTERFACE(pOemEntry)) { HRESULT hr;
hr = HComOEMPrinterEvent(pOemEntry, pPrinterName, DriverEvent, Flags, lParam);
if (hr == E_NOTIMPL) continue;
bResult = SUCCEEDED(hr);
} else { if ((pfnOEMPrinterEvent = GET_OEM_ENTRYPOINT(pOemEntry, OEMPrinterEvent)) && !pfnOEMPrinterEvent(pPrinterName, DriverEvent, Flags, lParam)) { ERR(("OEMPrinterEvent failed for '%ws': %d\n", CURRENT_OEM_MODULE_NAME(pOemEntry), GetLastError()));
bResult = FALSE; } }
END_OEMPLUGIN_LOOP } VFreeCommonInfo(pci); } else bResult = FALSE;
if (hPrinter != NULL) ClosePrinter(hPrinter);
return (bResult); }
BOOL BInitOrUpgradePrinterData( PCOMMONINFO pci )
/*++
Routine Description:
Initialize the driver's printer-sticky property data or upgrade it to current version if it already exists
Arguments:
pci - Points to basic printer info
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{ DWORD dwSize; BOOL bResult = TRUE;
//
// If the printer property data already exists in the registry
// and it's at least as big as the current PRINTERDATA, then
// we assume it's ok and there is no need to upgrade it.
//
if (!BGetPrinterDataDWord(pci->hPrinter, REGVAL_PRINTER_DATA_SIZE, &dwSize) || dwSize < sizeof(PRINTERDATA)) { //
// Otherwise, upgrade the existing printer property data in the registry
// or save a copy of the default printer property data to registry.
//
bResult = BFillCommonInfoPrinterData(pci) && BSavePrinterProperties(pci->hPrinter, pci->pRawData, pci->pPrinterData, sizeof(PRINTERDATA)); }
return bResult; }
BOOL BAddOrUpgradePrinterForms( PCOMMONINFO pci )
/*++
Routine Description:
Add printer specific forms to the spooler's forms database
Arguments:
pci - Points to basic printer info
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{ PPAGESIZE pPageSize; FORM_INFO_1 FormInfo1; DWORD dwIndex, dwChecksum32, dwForm; PFEATURE pFeature; WCHAR awchBuf[CCHPAPERNAME];
//
// If forms has already been added and printer description
// data hasn't changed, we don't need to do anything
//
if (BGetPrinterDataDWord(pci->hPrinter, REGVAL_FORMS_ADDED, &dwChecksum32) && dwChecksum32 == pci->pRawData->dwChecksum32) { return TRUE; }
if (pci->pSplForms == NULL) pci->pSplForms = MyEnumForms(pci->hPrinter, 1, &pci->dwSplForms);
//
// Get pointer to PageSize feature
//
if ((pFeature = GET_PREDEFINED_FEATURE(pci->pUIInfo, GID_PAGESIZE)) == NULL) { WARNING(("No paper size supported\n")); return FALSE; }
ZeroMemory(&FormInfo1, sizeof(FormInfo1)); FormInfo1.Flags = FORM_PRINTER; FormInfo1.pName = awchBuf;
//
// Go through each printer form
//
for (dwIndex=0; dwIndex < pFeature->Options.dwCount; dwIndex++) { pPageSize = PGetIndexedOption(pci->pUIInfo, pFeature, dwIndex); ASSERT(pPageSize != NULL);
//
// Ignore the custom page size option
//
if (pPageSize->dwPaperSizeID == DMPAPER_USER || pPageSize->dwPaperSizeID == DMPAPER_CUSTOMSIZE) { continue; }
if (pPageSize->szPaperSize.cx <= 0 || pPageSize->szPaperSize.cy <= 0) { ERR(("Paper size is too small\n")); continue; }
if (! LOAD_STRING_PAGESIZE_NAME(pci, pPageSize, awchBuf, CCHPAPERNAME)) { ERR(("Cannot get paper name\n")); continue; }
//
// Check if the paper name is already in the forms database.
// If it's already in the database as a
//
for (dwForm=0; dwForm < pci->dwSplForms; dwForm++) { if (pci->pSplForms[dwForm].Flags == FORM_USER && wcscmp(pci->pSplForms[dwForm].pName, awchBuf) == EQUAL_STRING) { VERBOSE(("Delete user/driver rdefined form: %ws\n", awchBuf)); DeleteForm(pci->hPrinter, awchBuf); } }
//
// Page size:
// remember that FORM_INFO_1 uses micron units while
// PAGESIZE.szPaperSize are in Master units.
//
FormInfo1.Size.cx = MASTER_UNIT_TO_MICRON(pPageSize->szPaperSize.cx, pci->pUIInfo->ptMasterUnits.x);
FormInfo1.Size.cy = MASTER_UNIT_TO_MICRON(pPageSize->szPaperSize.cy, pci->pUIInfo->ptMasterUnits.y);
//
// Imageable area:
// for driver-defined forms, all margins should be set to 0.
//
FormInfo1.ImageableArea.left = FormInfo1.ImageableArea.top = 0; FormInfo1.ImageableArea.right = FormInfo1.Size.cx; FormInfo1.ImageableArea.bottom = FormInfo1.Size.cy;
//
// We'll try to add the form first. If that fails,
// we assume the form is already there and try to
// update the form with the new info.
//
(VOID) AddForm(pci->hPrinter, 1, (PBYTE) &FormInfo1); }
(VOID) BSetPrinterDataDWord(pci->hPrinter, REGVAL_FORMS_ADDED, pci->pRawData->dwChecksum32);
return TRUE; }
BOOL BInitOrUpgradePrinterProperties( PCOMMONINFO pci )
/*++
Routine Description:
Initialize or upgrade printer property information in the registry
Arguments:
pci - Points to basic printer info
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{ BOOL bResult;
//
// Handle PRINTERDATA structure in registry
//
bResult = BInitOrUpgradePrinterData(pci);
//
// Handle driver-defined forms in the spooler's database
//
if (! BAddOrUpgradePrinterForms(pci)) bResult = FALSE;
#ifdef PSCRIPT
//
// pscript specific initializations
//
// Save model-specific NTF filename in registry for NT4 compatibility
if (! BUpdateModelNtfFilename(pci)) bResult = FALSE;
#ifdef WINNT_40
// Also save the current user locale too.
if (! BUpdateVMErrorMessageID(pci)) bResult = FALSE;
#endif // WINNT_40
#endif // PSCRIPT
return bResult; }
PWSTR PGetFileDirectory( PWSTR pServerName )
/*++
Routine Description:
Get the name of the directory used by the font downloader to store NTF information about downloaded fonts
Arguments:
pServerName - Name of the print server
Return Value:
Pointer to the directory used for storing NTF information about downloaded fonts, NULL if there is an error
--*/
{ PWSTR p = NULL, pDir = NULL; DWORD cbNeeded = 0, cbSize = 0; static WCHAR wszDir[] = FONTDIR;
//
// Get the printer driver directory path
//
if (GetPrinterDriverDirectory(pServerName, NULL, 1, NULL, 0, &cbNeeded) || GetLastError() != ERROR_INSUFFICIENT_BUFFER || (pDir = MemAlloc(cbSize = (cbNeeded + sizeof(wszDir)))) == NULL || !GetPrinterDriverDirectory(pServerName, NULL, 1, (PBYTE) pDir, cbNeeded, &cbNeeded)) { ERR(("GetPrinterDriverDirectory failed: %d\n", GetLastError())); MemFree(pDir); return NULL; }
//
// Replace the last component of the directory path (which should be w32...)
// with \psfont\ //
if (p = wcsrchr(pDir, TEXT(PATH_SEPARATOR))) StringCchCopyW(p, cbSize / sizeof(WCHAR) - (p - pDir), wszDir); else { WARNING(("Driver directory is not fully-qualified: %ws\n", pDir)); StringCchCatW(pDir, cbSize / sizeof(WCHAR), wszDir); }
return pDir; }
PWSTR PConcatFilename( PWSTR pDir, PWSTR pFilename )
{ PWSTR pBasename; DWORD cbSize = 0;
//
// Strip any directory prefix from the input filename
//
if (pBasename = wcsrchr(pFilename, TEXT(PATH_SEPARATOR))) pBasename++; else pBasename = pFilename;
//
// Concatenate the input directory with the base filename
//
if (!(pFilename = MemAlloc(cbSize = (SIZE_OF_STRING(pDir) + SIZE_OF_STRING(pBasename))))) { ERR(("Memory allocation failed\n")); return NULL; }
StringCchCopyW(pFilename, cbSize / sizeof(WCHAR), pDir); StringCchCatW(pFilename, cbSize / sizeof(WCHAR), pBasename);
return pFilename; }
BOOL _BPrepareToCopyCachedFile( HANDLE hPrinter, PCACHEDFILE pCachedFile, PWSTR pRegKey )
/*++
Routine Description:
Prepare to copy files from the server during a printer-connection cache refresh event
Arguments:
hPrinter - Handle to the printer connection pCachedFile - Buffer to store information about cached file
Return Value:
TRUE if successful, FALSE if there is an error
Note:
We assume this function is called from within the spooler process and with current user's security context. Specifically, we must be able to access the server's print$ share at this point.
--*/
{ PPRINTER_INFO_2 pPrinterInfo2 = NULL; PWSTR pRemoteFilename; DWORD dwSize;
ZeroMemory(pCachedFile, sizeof(CACHEDFILE)); pCachedFile->hRemoteFile = INVALID_HANDLE_VALUE;
//
// Find out the name of the file to copy
//
#if !defined(PSCRIPT)
pCachedFile->pFilename = PtstrGetPrinterDataString(hPrinter, pRegKey, &dwSize); #else
return TRUE; #endif
if (pCachedFile->pFilename == NULL || *pCachedFile->pFilename == NUL) return TRUE;
//
// Get the remote NTF filename on the server
//
// NOTE: We're really like to use level 4 here. But due to bug in the
// spooler, GetPrinter level 4 doesn't work for printer connections.
//
if (! (pPrinterInfo2 = MyGetPrinter(hPrinter, 2)) || ! pPrinterInfo2->pServerName || ! (pCachedFile->pRemoteDir = PGetFileDirectory(pPrinterInfo2->pServerName)) || ! (pCachedFile->pLocalDir = PGetFileDirectory(NULL)) || ! (pRemoteFilename = PConcatFilename(pCachedFile->pRemoteDir, pCachedFile->pFilename))) { goto exit_prepare_copyfile; }
pCachedFile->hRemoteFile = CreateFile(pRemoteFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN | SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS, NULL);
MemFree(pRemoteFilename);
exit_prepare_copyfile:
MemFree(pPrinterInfo2);
if (pCachedFile->hRemoteFile == INVALID_HANDLE_VALUE) { ERR(("Couldn't open remote NTF/FontInfo file: %d\n", GetLastError())); _VDisposeCachedFileInfo(pCachedFile); }
return (pCachedFile->hRemoteFile != INVALID_HANDLE_VALUE); }
BOOL _BCopyCachedFile( PCOMMONINFO pci, PCACHEDFILE pCachedFile )
/*++
Routine Description:
Copy files from the server during printer-connection cache refresh event
Arguments:
pci - Points to basic printer information pCachedFile - Points to information about cached file
Return Value:
TRUE if successful, FALSE if there is an error
Note:
We assume this function is called from within the spooler process and with system's security context. Specifically, we must be able to write into local machines' printer driver directory.
--*/
#define BUFFER_SIZE 4096
{ HANDLE hLocalFile; PWSTR pLocalFilename = NULL; PVOID pBuffer = NULL; BOOL bResult = FALSE; DWORD dwCount;
//
// We don't have any file to copy
//
if (pCachedFile->hRemoteFile == INVALID_HANDLE_VALUE) return TRUE;
//
// Get the name for the local copy of the NTF file
// and allocate temporary buffer
//
ASSERT(BUFFER_SIZE >= MAX_PATH * sizeof(WCHAR));
if (! (pLocalFilename = PConcatFilename(pCachedFile->pLocalDir, pCachedFile->pFilename)) || ! (pBuffer = MemAlloc(BUFFER_SIZE))) { goto exit_copyfile; }
// Make sure the local directory is created
(VOID) CreateDirectory(pCachedFile->pLocalDir, NULL);
for (dwCount=0; dwCount < 2; dwCount++) { hLocalFile = CreateFile(pLocalFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN | SECURITY_SQOS_PRESENT | SECURITY_ANONYMOUS, NULL);
if (hLocalFile != INVALID_HANDLE_VALUE) break;
if (dwCount == 0) { //
// If this is our first try, then attempt to move
// the existing file to a temporary file and set
// it to be delete-on-reboot.
//
#ifdef PSCRIPT
if (! GetTempFileName(pCachedFile->pLocalDir, L"NTF", 0, pBuffer) || #else
if (! GetTempFileName(pCachedFile->pLocalDir, L"FON", 0, pBuffer) || #endif
! MoveFileEx(pLocalFilename, pBuffer, MOVEFILE_REPLACE_EXISTING) || ! MoveFileEx(pBuffer, NULL, MOVEFILE_DELAY_UNTIL_REBOOT)) { break; } } }
if (hLocalFile != INVALID_HANDLE_VALUE) { while (ReadFile(pCachedFile->hRemoteFile, pBuffer, BUFFER_SIZE, &dwCount, NULL)) { //
// Have we reached end-of-file?
//
if (dwCount == 0) { bResult = TRUE; break; }
if (! WriteFile(hLocalFile, pBuffer, dwCount, &dwCount, NULL)) break; }
CloseHandle(hLocalFile);
//
// If file copying failed, be sure to delete the temporary file
//
if (! bResult) DeleteFile(pLocalFilename); }
exit_copyfile:
MemFree(pLocalFilename); MemFree(pBuffer);
if (! bResult) ERR(("Couldn't copy remote NTF/FontInfo file: %d\n", GetLastError()));
return bResult; }
VOID _VDisposeCachedFileInfo( PCACHEDFILE pCachedFile )
/*++
Routine Description:
Clean up after copying files from the server during printer-connection cache refresh
Arguments:
pCachedFile - Points to information about cached file
Return Value:
NONE
--*/
{ if (pCachedFile->hRemoteFile != INVALID_HANDLE_VALUE) CloseHandle(pCachedFile->hRemoteFile);
MemFree(pCachedFile->pFilename); MemFree(pCachedFile->pRemoteDir); MemFree(pCachedFile->pLocalDir);
ZeroMemory(pCachedFile, sizeof(CACHEDFILE)); pCachedFile->hRemoteFile = INVALID_HANDLE_VALUE; }
#ifdef UNIDRV
VOID DeleteFontIntallerFile( HANDLE hPrinter )
/*++
Routine Description:
Delete font installer file when printer is deleted
Arguments:
hPrinter - Handle to printer
Return Value:
NONE
--*/
{ PWSTR pFilename = NULL; PWSTR pLocalDir = NULL; PWSTR pLocalFilename = NULL;
pFilename = PtstrGetPrinterDataString(hPrinter, REGVAL_FONTFILENAME, NULL);
if (!pFilename) return;
if (!*pFilename) goto exit_deletefile;
if (!(pLocalDir = PGetFileDirectory(NULL))) goto exit_deletefile;
if (!(pLocalFilename = PConcatFilename(pLocalDir, pFilename))) goto exit_deletefile;
DeleteFile(pLocalFilename);
exit_deletefile:
MemFree(pFilename); MemFree(pLocalDir); MemFree(pLocalFilename);
return; }
#endif
|