windows-nt/Source/XPSP1/NT/printscan/print/spooler/spoolss/client/prnstrm.cxx

4836 lines
108 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (C) Microsoft Corporation, 1998 - 1999
All rights reserved.
Module Name:
Stream.cxx
Abstract:
implements TPrnStream class methods
Author:
Adina Trufinescu (AdinaTru) 4-Nov-1998
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
#include "prnprst.hxx"
static
FieldInfo PrinterInfo2Fields[]={
{offsetof(PRINTER_INFO_2, pServerName), sizeof(ULONG_PTR),sizeof(DWORD), PTR_TYPE },
{offsetof(PRINTER_INFO_2, pPrinterName), sizeof(ULONG_PTR),sizeof(DWORD), PTR_TYPE },
{offsetof(PRINTER_INFO_2, pShareName), sizeof(ULONG_PTR),sizeof(DWORD), PTR_TYPE },
{offsetof(PRINTER_INFO_2, pPortName), sizeof(ULONG_PTR),sizeof(DWORD), PTR_TYPE },
{offsetof(PRINTER_INFO_2, pDriverName), sizeof(ULONG_PTR),sizeof(DWORD), PTR_TYPE },
{offsetof(PRINTER_INFO_2, pComment), sizeof(ULONG_PTR),sizeof(DWORD), PTR_TYPE },
{offsetof(PRINTER_INFO_2, pLocation), sizeof(ULONG_PTR),sizeof(DWORD), PTR_TYPE },
{offsetof(PRINTER_INFO_2, pDevMode), sizeof(ULONG_PTR),sizeof(DWORD), PTR_TYPE },
{offsetof(PRINTER_INFO_2, pSepFile), sizeof(ULONG_PTR),sizeof(DWORD), PTR_TYPE },
{offsetof(PRINTER_INFO_2, pPrintProcessor), sizeof(ULONG_PTR),sizeof(DWORD), PTR_TYPE },
{offsetof(PRINTER_INFO_2, pDatatype), sizeof(ULONG_PTR),sizeof(DWORD), PTR_TYPE },
{offsetof(PRINTER_INFO_2, pParameters), sizeof(ULONG_PTR),sizeof(DWORD), PTR_TYPE },
{offsetof(PRINTER_INFO_2, pSecurityDescriptor), sizeof(ULONG_PTR),sizeof(DWORD), PTR_TYPE },
{offsetof(PRINTER_INFO_2, Attributes), sizeof(DWORD), sizeof(DWORD), DATA_TYPE },
{offsetof(PRINTER_INFO_2, Priority), sizeof(DWORD), sizeof(DWORD), DATA_TYPE },
{offsetof(PRINTER_INFO_2, DefaultPriority), sizeof(DWORD), sizeof(DWORD), DATA_TYPE },
{offsetof(PRINTER_INFO_2, StartTime), sizeof(DWORD), sizeof(DWORD), DATA_TYPE },
{offsetof(PRINTER_INFO_2, UntilTime), sizeof(DWORD), sizeof(DWORD), DATA_TYPE },
{offsetof(PRINTER_INFO_2, Status), sizeof(DWORD), sizeof(DWORD), DATA_TYPE },
{offsetof(PRINTER_INFO_2, cJobs), sizeof(DWORD), sizeof(DWORD), DATA_TYPE },
{offsetof(PRINTER_INFO_2, AveragePPM), sizeof(DWORD), sizeof(DWORD), DATA_TYPE },
{0xFFFFFFFF, 0, 0, DATA_TYPE}
};
static
FieldInfo PrinterInfo7Fields[]={
{offsetof(PRINTER_INFO_7, pszObjectGUID), sizeof(ULONG_PTR),sizeof(DWORD), PTR_TYPE },
{offsetof(PRINTER_INFO_7, dwAction), sizeof(DWORD), sizeof(DWORD), DATA_TYPE },
{0xFFFFFFFF, 0, 0, DATA_TYPE}
};
/*++
Title:
TPrnStream
Routine Description:
Initialize class members.
Initialise m_pIStream to NULL.
TPrnStream Read/write/Seek functionality is implemented through this object methods call.
m_pIStream is created when BindPrnStream is called. If this function fails,
any subsequent method call will fail too.
Arguments:
None
Return Value:
Nothing
--*/
TPrnStream::
TPrnStream(
IN LPCTSTR pszPrnName,
IN LPCTSTR pszFileName
) : m_pIStream(NULL),
m_strFileName(pszFileName),
m_strPrnName(pszPrnName),
m_hPrinterHandle(INVALID_HANDLE_VALUE),
m_bHeaderWritten(FALSE),
m_cIndex(0),
m_ResolveCase(0),
m_pPrnBinItem(NULL),
m_EnumColorProfiles(NULL),
m_AssociateColorProfileWithDevice(NULL),
m_DisassociateColorProfileFromDevice(NULL),
m_pColorProfileLibrary(NULL)
{
m_cPrnDataItems.QuadPart = 0;
m_uliSeekPtr.QuadPart = 0;
}
/*++
Title:
~TPrnStream
Routine Description:
Close printer if opened ; free TStream if created
Arguments:
None
Return Value:
Nothing
--*/
TPrnStream::
~TPrnStream(
)
{
if(m_hPrinterHandle != INVALID_HANDLE_VALUE)
{
ClosePrinter(m_hPrinterHandle);
}
if(m_pIStream)
{
delete m_pIStream;
}
if(m_pPrnBinItem)
{
FreeMem(m_pPrnBinItem);
}
if (m_pColorProfileLibrary)
{
delete m_pColorProfileLibrary;
}
}
/*++
Title:
BindPrnStream
Routine Description:
Open Printer , bind prinyter handle to WalkPrinter and create an TStream
WalkPrinter can take a printer name or printer handle at constructing time
It has also a default constructor explicit defined ; Printer handle can be binded later
Arguments:
Return Value:
S_OK if succeeded,
E_OUTOFMEMORY if failed to alloc mem
an error code maped to a storage hresult
--*/
HRESULT
TPrnStream::
BindPrnStream(
)
{
TStatusB bStatus;
TStatus Status;
HRESULT hr;
DWORD dwAccess = 0;
Status DBGCHK = sOpenPrinter( m_strPrnName,
&dwAccess,
&m_hPrinterHandle );
DBGMSG( DBG_TRACE, ( "Printer Name : %x "TSTR" File: "TSTR" \n" , m_hPrinterHandle , (LPCTSTR)m_strPrnName , (LPCTSTR)m_strFileName) );
if(dwAccess == PRINTER_ALL_ACCESS)
{
DBGMSG( DBG_TRACE, ( "Printer ALL Access Granted!!!\n" ) );
}
else
{
DBGMSG( DBG_TRACE, ( "Printer READ Access Granted!!!\n" ) );
}
if(Status == 0)
{
BindToPrinter(m_hPrinterHandle);
m_pIStream = new TStream(m_strFileName);
bStatus DBGCHK = (m_pIStream != NULL);
if(bStatus)
{
DBGMSG( DBG_TRACE, ( "BINDING SUCCEEDED!!!\n "));
hr = S_OK;
}
else
{
m_pIStream = NULL;
m_hPrinterHandle = INVALID_HANDLE_VALUE;
hr = E_OUTOFMEMORY;
}
}
else
{
hr = TStream::MapWin32ErrorCodeToHRes(GetLastError());
}
if (SUCCEEDED(hr))
{
hr = InitalizeColorProfileLibrary();
}
return hr;
}
/*++
Title:
UnBindPrnStream
Routine Description:
Close printer if opened , removefile if created , delete
Arguments:
None
Return Value:
S_OK if succeeded,
a Win32 Error (generated by DeleteFile) mapped to a HRESULT if failed
--*/
HRESULT
TPrnStream::
UnBindPrnStream(
)
{
TStatusH hr;
hr DBGNOCHK = S_OK;
if(m_hPrinterHandle != INVALID_HANDLE_VALUE)
{
ClosePrinter(m_hPrinterHandle);
m_hPrinterHandle = INVALID_HANDLE_VALUE;
}
if(m_pIStream)
{
hr DBGCHK = m_pIStream->DestroyFile();
}
return hr;
}
/*++
Title:
SetEndOfPrnStream
Routine Description:
Set the end of PrnStream; In the case when overwrite an existing file, EOF must be set in order to trubcate the file at
the actual dimension of the info written
Arguments:
None
Return Value:
TRUE if succeeded,
--*/
BOOL
TPrnStream::
SetEndOfPrnStream(
)
{
return m_pIStream->bSetEndOfFile();
}
/*++
Title:
CheckPrinterNameIntegrity
Routine Description:
Read printer name from file and compare with name specified at binding
If they are different , depending on how FORCE or RESOLVE flags are set the new name will be resolved or forced.
If no name solving is specified , return error
Func called at restoring time
Arguments:
Flags - flags specified at restoring time ; should specify who printer name conflicts are handles
Return Value:
S_OK if succeeded
PRN_PERSIST_ERROR error code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
CheckPrinterNameIntegrity(
IN DWORD Flags
)
{
TStatusB bStatus;
TString strStoredPrnName;
TStatusH hr;
//
// m_ResolveCase will indicate how to solve printer name conflicts
// if one of <printer name resolving> flags are set, set m_ResolveCase
//
if(Flags & PRST_RESOLVE_NAME)
{
m_ResolveCase |= TPrnStream::kResolveName;
}
else if(Flags & PRST_FORCE_NAME)
{
m_ResolveCase |= TPrnStream::kForceName;
}
hr DBGCHK = ReadPrnName(strStoredPrnName);
if(SUCCEEDED(hr))
{
if(_tcsicmp( m_strPrnName, strStoredPrnName) != 0)
{
if(m_ResolveCase & TPrnStream::kResolveName)
{
DBGMSG(DBG_TRACE , ("RESOLVE for "TSTR"\n" , (LPCTSTR)m_strPrnName));
hr DBGNOCHK = S_OK;
}
else if(m_ResolveCase & TPrnStream::kForceName)
{
DBGMSG(DBG_TRACE , ("FORCE to "TSTR"\n" , (LPCTSTR)strStoredPrnName));
m_strPrnName.bUpdate(strStoredPrnName);
hr DBGNOCHK = S_OK;
}
else
{
hr DBGNOCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_PRN_NAME_CONFLICT);
}
}
}
return hr;
}
/*++
Title:
PortNameCase
Routine Description:
Set m_ResolveCase to TPrnStream::kResolvePort if resolve port option is set
Arguments:
Flags - this function is called with flags specified for RestorePrinterInfo at restoring time
Return Value:
Nothing
--*/
VOID
TPrnStream::
PortNameCase(
IN DWORD Flags
)
{
if(Flags & PRST_RESOLVE_PORT)
{
m_ResolveCase |= TPrnStream::kResolvePort;
}
}
/*++
Title:
ShareNameCase
Routine Description:
Set m_ResolveCase to TPrnStream::kGenerateShare if resolve port option is set
Arguments:
Flags - this function is called with flags specified for RestorePrinterInfo at restoring time
Return Value:
Nothing
--*/
VOID
TPrnStream::
ShareNameCase(
IN DWORD Flags
)
{
if(Flags & PRST_RESOLVE_SHARE)
{
m_ResolveCase |= TPrnStream::kGenerateShare;
}
else if(Flags & PRST_DONT_GENERATE_SHARE)
{
m_ResolveCase |= TPrnStream::kUntouchShare;
}
}
/*++
Title:
StorePrinterInfo
Routine Description:
Define restoring function table and calls storing functions based on flag value
Arguments:
flags - flags that specifies that functions should be called
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR error code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
StorePrinterInfo(
IN DWORD Flags,
OUT DWORD& StoredFlags
)
{
TStatusH hr;
hr DBGNOCHK = S_OK;
static PrstFunctEntry StoreFunctTable [] = {
{PRST_PRINTER_INFO_2, &TPrnStream::StorePrnInfo2},
{PRST_PRINTER_INFO_7, &TPrnStream::StorePrnInfo7},
{PRST_COLOR_PROF, &TPrnStream::StoreColorProfiles},
{PRST_PRINTER_DATA, &TPrnStream::StorePrnData},
{PRST_PRINTER_SEC, &TPrnStream::StorePrnSecurity},
{PRST_PRINTER_DEVMODE, &TPrnStream::StorePrnDevMode},
{PRST_USER_DEVMODE, &TPrnStream::StoreUserDevMode},
{0, NULL}};
hr DBGCHK = WriteHeader(Flags);
//
// initialize the flags that were successfully stored with 0
//
StoredFlags = 0;
for(int idx = 0 ; StoreFunctTable[idx].iKeyWord && SUCCEEDED(hr); idx++)
{
if(Flags & StoreFunctTable[idx].iKeyWord)
{
hr DBGCHK = (this->*StoreFunctTable[idx].pPrstFunc)();
if(SUCCEEDED(hr))
{
StoredFlags |= StoreFunctTable[idx].iKeyWord;
}
}
}
if(SUCCEEDED(hr))
{
//
// Truncate file; maybe the file was overwrited
//
SetEndOfPrnStream();
}
else
{
//
//delete file if storing didn't succeed
//
UnBindPrnStream();
}
return hr;
}
/*++
Title:
QueryPrinterInfo
Routine Description:
query a file for stored settings
Arguments:
Flags - specify what settings to query
PrstInfo - Structure where read settings will be dumped
Return Value:
S_OK if succeeded
PRN_PERSIST_ERROR error code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
QueryPrinterInfo(
IN PrinterPersistentQueryFlag Flags,
OUT PersistentInfo *pPrstInfo
)
{
TStatusH hr;
BOOL bInsidePI2;
static QueryFunctEntry QueryFunctTable [] = {
{PRST_PRINTER_INFO_2, &TPrnStream::ReadPrnInfo2},
{PRST_PRINTER_INFO_7, &TPrnStream::ReadPrnInfo7},
{PRST_COLOR_PROF, &TPrnStream::ReadColorProfiles},
{PRST_PRINTER_SEC, &TPrnStream::ReadPrnSecurity},
{PRST_PRINTER_DEVMODE, &TPrnStream::ReadPrnInfo8},
{0, NULL}};
//
// delete in case QueryPrinterInfo was previously called
// m_pPrnBinItem store a PrnBinInfo block when Query ;
// it has to be deleted between to Querys and at destruction time
//
if(m_pPrnBinItem)
{
delete m_pPrnBinItem;
}
hr DBGNOCHK = S_OK;
for(int idx = 0 ; QueryFunctTable[idx].iKeyWord && SUCCEEDED(hr); idx++)
{
if(Flags & QueryFunctTable[idx].iKeyWord)
{
hr DBGCHK = (this->*QueryFunctTable[idx].pReadFunct)(&m_pPrnBinItem);
if(SUCCEEDED(hr))
{
DBGMSG( DBG_TRACE, ( "QueryPrinterInfo: pReadFunct OK \n"));
pPrstInfo->pi2 = reinterpret_cast<PRINTER_INFO_2*>(reinterpret_cast<LPBYTE>(m_pPrnBinItem) + m_pPrnBinItem->pData);
}
else
{
DBGMSG( DBG_TRACE, ( "QueryPrinterInfo: pReadFunct FAILED \n"));
}
}
}
return hr;
}
/*++
Title:
RestorePrinterInfo
Routine Description:
Handle port name conflicts by calling PortNameCase before any restoring
Define restoring function table and calls restoring functions based on flag value
Arguments:
flags - flags that specifies that functions should be called
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR error code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
RestorePrinterInfo(
IN DWORD Flags,
OUT DWORD& RestoredFlags
)
{
TStatusH hr;
hr DBGNOCHK = S_OK;
static PrstFunctEntry RestoreFunctTable [] = {
{PRST_PRINTER_INFO_2, &TPrnStream::RestorePrnInfo2},
{PRST_COLOR_PROF, &TPrnStream::RestoreColorProfiles},
{PRST_PRINTER_DEVMODE, &TPrnStream::RestorePrnDevMode},
{PRST_PRINTER_INFO_7, &TPrnStream::RestorePrnInfo7},
{PRST_PRINTER_DATA, &TPrnStream::RestorePrnData},
{PRST_PRINTER_SEC, &TPrnStream::RestorePrnSecurity},
{PRST_USER_DEVMODE, &TPrnStream::RestoreUserDevMode},
{0, NULL}};
//
// initialize the flags that were successfully stored with 0
//
RestoredFlags = 0;
//
// if PRST_RESOLVE_PORT is set , update m_ResolveCase so RestorePrnInfo2 can act properly
//
PortNameCase(Flags);
//
// if PRST_RESOLVE_SHARE is set , update m_ResolveCase so RestorePrnInfo2 can act properly
//
ShareNameCase(Flags);
for(int idx = 0 ; RestoreFunctTable[idx].iKeyWord && SUCCEEDED(hr); idx++)
{
if(Flags & RestoreFunctTable[idx].iKeyWord)
{
hr DBGCHK = (this->*RestoreFunctTable[idx].pPrstFunc)();
if(SUCCEEDED(hr))
{
RestoredFlags |= RestoreFunctTable[idx].iKeyWord;
}
}
}
return hr;
}
/*++
Title:
bStorePrnInfo2
Routine Description:
Build an item based on P_I_2 and write it into the stream
Arguments:
None
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
StorePrnInfo2(
VOID
)
{
DWORD cbSize;
TStatusH hr;
TStatusB bStatus;
LPPRINTER_INFO_2 lpPrinterInfo2 = NULL;
//
// Get P_I_2
//
cbSize = 1;
if(bStatus DBGCHK = bGetPrinter(m_hPrinter,
2,
reinterpret_cast<PVOID*>(&lpPrinterInfo2),
&cbSize))
{
DBGMSG( DBG_TRACE, ("StorePrnInfo2 %d \n" , cbSize) );
hr DBGCHK = WritePrnInfo2(lpPrinterInfo2, cbSize);
FreeMem(lpPrinterInfo2);
}
else
{
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_GET_PI2);
}
return hr;
}
/*++
Title:
bRestorePrnInfo2
Routine Description:
Apply P_I_2 settings read from stream to binded printer
Arguments:
None
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
RestorePrnInfo2(
VOID
)
{
PrnBinInfo* pSourcePI2 = NULL;
TStatusH hr;
TStatusB bStatus;
PRINTER_INFO_2* pDestinationPI2 = NULL;
DWORD cbSize = 0;
//
// Reads settings stored in stream
//
hr DBGCHK = ReadPrnInfo2(&pSourcePI2);
if(SUCCEEDED(hr))
{
cbSize = 1;
bStatus DBGCHK = bGetPrinter(m_hPrinter,
2,
reinterpret_cast<PVOID*>(&pDestinationPI2),
&cbSize);
if(bStatus)
{
LPTSTR* ppszStoredPrnName = &(reinterpret_cast<PRINTER_INFO_2*>(
reinterpret_cast<LPBYTE>(pSourcePI2) + pSourcePI2->pData)->pPrinterName
);
LPTSTR* ppShareName = &(reinterpret_cast<PRINTER_INFO_2*>(
reinterpret_cast<LPBYTE>(pSourcePI2) + pSourcePI2->pData)->pShareName
);
LPTSTR* ppPortName = &(reinterpret_cast<PRINTER_INFO_2*>(
reinterpret_cast<LPBYTE>(pSourcePI2) + pSourcePI2->pData)->pPortName
);
LPTSTR* ppPrintProcessor = &(reinterpret_cast<PRINTER_INFO_2*>(
reinterpret_cast<LPBYTE>(pSourcePI2) + pSourcePI2->pData)->pPrintProcessor
);
LPDWORD pAttributes = &(reinterpret_cast<PRINTER_INFO_2*>(
reinterpret_cast<LPBYTE>(pSourcePI2) + pSourcePI2->pData)->Attributes
);
DBGMSG(DBG_TRACE , (" Stored Prn Name: "TSTR" Share:"TSTR"\n" , *ppszStoredPrnName , *ppShareName));
//
// check against printer name
//
if( _tcsicmp( pDestinationPI2->pPrinterName, *ppszStoredPrnName ) != 0)
{
if(m_ResolveCase & kResolveName)
{
// RESOLVE!!!
// if printer name differs from printer name stored into file ,
// update read structure with open printer
//
DBGMSG(DBG_TRACE , (" RESOLVE Printer : "TSTR" Share:"TSTR" old : "TSTR"\n" , *ppszStoredPrnName , *ppShareName , pDestinationPI2->pShareName));
*ppszStoredPrnName = pDestinationPI2->pPrinterName;
}
else if(m_ResolveCase & kForceName)
{
// FORCE!!!
// if printer name differs from printer name stored into file ,
// let printer name and share name as they are in the stored file
//
DBGMSG(DBG_TRACE , (" FORCE Printer : "TSTR" Share:"TSTR"\n" , *ppszStoredPrnName , *ppShareName));
}
else
{
//
// if printer name differs from printer name stored into file ,
// return error ; printer names are different but the flags are not used
//
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_RESTORE_PI2);
goto End;
}
}
//
// if resolve port option was set , port name from the printer configuration settings to be ignored in lieu of
// the port name that printer curently has
//
if(m_ResolveCase & kResolvePort)
{
*ppPortName = pDestinationPI2->pPortName;;
}
//
// if the print processor from the printer configuration settings differs from the curent installed print processor
// just ignore it
//
if( _tcsicmp( pDestinationPI2->pPrintProcessor, *ppPrintProcessor) != 0 )
{
*ppPrintProcessor = pDestinationPI2->pPrintProcessor;
}
if((reinterpret_cast<PRINTER_INFO_2*>(reinterpret_cast<LPBYTE>(pSourcePI2) + pSourcePI2->pData))->pDevMode)
{
(reinterpret_cast<PRINTER_INFO_2*>(reinterpret_cast<LPBYTE>(pSourcePI2) + pSourcePI2->pData))->pDevMode = NULL;
DBGMSG(DBG_TRACE , (" Reset devmode to NULL!\n" ));
}
//
// Set printer with read settings
//
bStatus DBGCHK = SetPrinter(m_hPrinter,
2,
reinterpret_cast<LPBYTE>(pSourcePI2) + pSourcePI2->pData,
0);
//
// If SetPrinter failed with ERROR_INVALID_SHARENAME and a resolve share flag is set,
// retry call SetPrinter with a new generated share name
//
if(!bStatus &&
(m_ResolveCase & ( kUntouchShare | kGenerateShare )) &&
GetLastError() == ERROR_INVALID_SHARENAME)
{
TString strShareName;
TString strPrinterName( pDestinationPI2->pPrinterName );
//
// If already shared, use the current share name
// Even if generating share flag is set, don't create a new share name
// as long as the printer is shared. The whole point of this share name generation is
// to allow the printer to be shared, but since it is , don't waist any time.
//
if( pDestinationPI2->Attributes & PRINTER_ATTRIBUTE_SHARED &&
pDestinationPI2->pShareName &&
pDestinationPI2->pShareName[0] )
{
*ppShareName = pDestinationPI2->pShareName;
*pAttributes |= PRINTER_ATTRIBUTE_SHARED;
}
else
{
//
// Resolve share name by generating a new share name
//
if(m_ResolveCase & kGenerateShare)
{
if( VALID_OBJ( strPrinterName ) )
{
bStatus DBGCHK = bNewShareName(pDestinationPI2->pServerName, strPrinterName, strShareName);
*ppShareName = (LPTSTR)(LPCTSTR)(strShareName);
*pAttributes |= PRINTER_ATTRIBUTE_SHARED;
//
// *ppShareName is NULL if bNewShareName fails
//
DBGMSG( DBG_TRACE, ( "Created share name for " TSTR " " TSTR "\n", (LPCTSTR)strPrinterName, (LPCTSTR)strShareName ) );
}
}
//
// Don't share it at all
//
if(m_ResolveCase & kUntouchShare)
{
*pAttributes &= ~PRINTER_ATTRIBUTE_SHARED;
*ppShareName = NULL;
}
}
//
// Set printer with read settings
//
bStatus DBGCHK = SetPrinter(m_hPrinter,
2,
reinterpret_cast<LPBYTE>(pSourcePI2) + pSourcePI2->pData,
0);
DBGMSG(DBG_TRACE , (" RESOLVE Printer : "TSTR" Share:"TSTR"\n" , *ppszStoredPrnName , *ppShareName));
}
End:
if(bStatus)
{
hr DBGNOCHK = S_OK;
DBGMSG(DBG_TRACE , (" SetPrinter on level 2 succeeded!\n" ));
}
else
{
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_RESTORE_PI2);
}
FreeMem(pSourcePI2);
if(pDestinationPI2 != NULL)
{
FreeMem(pDestinationPI2);
}
}
else
{
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_RESTORE_PI2);
}
}
return hr;
}
/*++
Title:
bStorePrnInfo7
Routine Description:
Build an item based on P_I_7 and write it into the stream
Arguments:
None
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
StorePrnInfo7(
VOID
)
{
DWORD cbSize;
TStatusH hr;
TStatusB bStatus;
LPPRINTER_INFO_7 lpPrinterInfo7 = NULL;
//
// Get P_I_7
//
cbSize = 1;
bStatus DBGCHK = bGetPrinter(m_hPrinter,
7,
reinterpret_cast<PVOID*>(&lpPrinterInfo7),
&cbSize);
if(bStatus)
{
//
// remove DSPRINT_PENDING flags
//
lpPrinterInfo7->dwAction &= ~DSPRINT_PENDING;
hr DBGCHK = WritePrnInfo7(lpPrinterInfo7, cbSize);
FreeMem(lpPrinterInfo7);
}
else
{
if(GetLastError() == ERROR_INVALID_LEVEL)
{
hr DBGNOCHK = S_OK;
}
else
{
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_GET_PI7);
}
}
return hr;
}
/*++
Title:
RestorePrnInfo7
Routine Description:
Apply P_I_7 settings read from stream to binded printer
Arguments:
None
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR error code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
RestorePrnInfo7(
VOID
)
{
DWORD cbSize;
PrnBinInfo* lpPrnBinItem = NULL;
TStatusH hr;
TStatusB bStatus;
DWORD LastError;
//
// Reads settings stored in stream
//
hr DBGCHK = ReadPrnInfo7(&lpPrnBinItem);
if(SUCCEEDED(hr) && lpPrnBinItem)
{
//
// Set printer with read settings
//
bStatus DBGCHK = SetPrinter( m_hPrinter,
7,
reinterpret_cast<LPBYTE>(lpPrnBinItem) + lpPrnBinItem->pData,
0);
LastError = GetLastError();
if(LastError == ERROR_IO_PENDING ||
LastError == ERROR_DS_UNAVAILABLE)
{
//
// If the error is io pending the spooler
// will publish in the background therefore we will silently fail.
// and
// The server must be stand alone and/or DirectoryService is not available.
// Just continue.
//
hr DBGNOCHK = S_OK;
}
else
{
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_RESTORE_PI7);
}
FreeMem(lpPrnBinItem);
}
return hr;
}
/*++
Title:
StorePrnSecurity
Routine Description:
Build an item based on security descriptor and write it into the stream
Arguments:
None
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR_GET_SEC error code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
StorePrnSecurity(
VOID
)
{
DWORD cbSize;
TStatusH hr;
TStatusB bStatus;
PRINTER_INFO_2* lpPrinterInfo2 = NULL;
//
// Get P_I_2
//
cbSize = 1;
bStatus DBGCHK = bGetPrinter(m_hPrinter,
2,
reinterpret_cast<PVOID*>(&lpPrinterInfo2),
&cbSize);
if(bStatus)
{
hr DBGCHK = WritePrnSecurity(lpPrinterInfo2, cbSize);
FreeMem(lpPrinterInfo2);
}
else
{
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_GET_SEC);
}
return hr;
}
/*++
Title:
RestorePrnSecurity
Routine Description:
Apply security descriptor read from stream to binded printer
Arguments:
None
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
RestorePrnSecurity(
VOID
)
{
DWORD cbSize;
PRINTER_INFO_3 PrinterInfo3;
PrnBinInfo* lpPrnBinItem = NULL;
TStatusH hr;
TStatusB bStatus;
//
// Reads settings stored in stream
//
hr DBGCHK = ReadPrnSecurity(&lpPrnBinItem);
if(SUCCEEDED(hr))
{
PrinterInfo3.pSecurityDescriptor = reinterpret_cast<PSECURITY_DESCRIPTOR>(
reinterpret_cast<LPBYTE>(lpPrnBinItem) + lpPrnBinItem->pData
);
//
// Set printer with read settings
//
bStatus DBGCHK = SetPrinter( m_hPrinter,
3,
reinterpret_cast<LPBYTE>(&PrinterInfo3),
0);
if(bStatus)
{
hr DBGNOCHK = S_OK;
}
else
{
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_RESTORE_SEC);
}
FreeMem(lpPrnBinItem);
}
return hr;
}
/*++
Title:
StoreUserDevMode
Routine Description:
Build an item based on user dev mode and write it into the stream
Arguments:
None
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
StoreUserDevMode(
VOID
)
{
DWORD cbSize;
TStatusH hr;
TStatusB bStatus;
LPPRINTER_INFO_9 lpPrinterInfo9 = NULL;
//
// Get P_I_9
//
cbSize = 1;
bStatus DBGCHK = bGetPrinter(m_hPrinter,
9,
reinterpret_cast<PVOID*>(&lpPrinterInfo9),
&cbSize);
if(bStatus)
{
//
// call WritePrnInfo9 even if lpPrinterInfo9 is null ;
// usually, when printer doesn't have a user mode attached ,is lpPrinterInfo9->pDevMode who is null
// but still call it and check lpPrinterInfo9 == NULL on WritePrnInfo9, to act similar as lpPrinterInfo9->pDevMode == NULL
//
hr DBGCHK = WritePrnInfo9(lpPrinterInfo9, cbSize);
FreeMem(lpPrinterInfo9);
}
else
{
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_GET_USR_DEVMODE);
}
return hr;
}
/*++
Title:
RestoreUserDevMode
Routine Description:
Apply user dev mode read from stream to binded printer
Arguments:
None
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
RestoreUserDevMode(
VOID
)
{
PrnBinInfo* lpPrnBinItem = NULL;
PRINTER_INFO_9 PrinterInfo9;
TStatusH hr;
TStatusB bStatus;
DWORD cbSize;
hr DBGNOCHK = E_FAIL;
//
// Reads settings stored in stream
//
hr DBGCHK = ReadPrnInfo9(&lpPrnBinItem);
if(SUCCEEDED(hr))
{
if(lpPrnBinItem != NULL)
{
PrinterInfo9.pDevMode = reinterpret_cast<DEVMODE*>(
reinterpret_cast<LPBYTE>(lpPrnBinItem) + lpPrnBinItem->pData
);
}
else
{
//
// User dev mode can be null if there are no Printer prefferences set at the time the file is created
// We remove per user devmode by calling SetPrinter with pDevMode equal with NULL
//
DBGMSG(DBG_TRACE , ("NO USER DEVMODE STORED!!!\n"));
PrinterInfo9.pDevMode = NULL;
}
//
// Set printer with read settings
//
bStatus DBGCHK = SetPrinter( m_hPrinter,
9,
reinterpret_cast<LPBYTE>(&PrinterInfo9),
0);
if(bStatus)
{
hr DBGNOCHK = S_OK;
}
else
{
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_RESTORE_USR_DEVMODE);
}
FreeMem(lpPrnBinItem);
}
return hr;
}
/*++
Title:
StorePrnDevMode
Routine Description:
Build an item based on printer dev mode and write it into the stream
Arguments:
None
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
StorePrnDevMode(
VOID
)
{
DWORD cbSize;
TStatusH hr;
TStatusB bStatus;
LPPRINTER_INFO_8 lpPrinterInfo8 = NULL;
hr DBGNOCHK = E_FAIL;
//
// Get P_I_8
//
cbSize = 1;
bStatus DBGCHK = bGetPrinter(m_hPrinter,
8,
reinterpret_cast<PVOID*>(&lpPrinterInfo8),
&cbSize);
if(bStatus)
{
bStatus DBGCHK = (lpPrinterInfo8->pDevMode != NULL);
if(bStatus)
{
hr DBGCHK = WritePrnInfo8(lpPrinterInfo8, cbSize);
}
FreeMem(lpPrinterInfo8);
}
if(FAILED(hr))
{
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_GET_PRN_DEVMODE);
}
return hr;
}
/*++
Title:
RestorePrnDevMode
Routine Description:
Apply printer dev mode read from stream to binded printer
Arguments:
None
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
RestorePrnDevMode(
VOID
)
{
DWORD cbSize;
PRINTER_INFO_8 PrinterInfo8;
PrnBinInfo* lpPrnBinItem = NULL;
TStatusH hr;
TStatusB bStatus;
BOOL bInsidePI2;
hr DBGNOCHK = E_FAIL;
//
// Reads settings stored in stream
//
hr DBGCHK = ReadPrnInfo8(&lpPrnBinItem);
if(SUCCEEDED(hr))
{
PrinterInfo8.pDevMode = reinterpret_cast<DEVMODE*>(
reinterpret_cast<LPBYTE>(lpPrnBinItem) + lpPrnBinItem->pData
);
//
// Set printer with read settings
//
bStatus DBGCHK = SetPrinter( m_hPrinter,
8,
reinterpret_cast<LPBYTE>(&PrinterInfo8),
0);
if(bStatus)
{
hr DBGNOCHK = S_OK;
}
else
{
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_RESTORE_PRN_DEVMODE);
}
FreeMem(lpPrnBinItem);
}
return hr;
}
/*++
Title:
StoreColorProfiles
Routine Description:
strore a multi zero string with color profiles into stream
Arguments:
None
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
StoreColorProfiles(
VOID
)
{
TStatusH hr;
TStatusB bStatus;
DWORD cbSize;
DWORD dwProfiles;
ENUMTYPE EnumType;
LPTSTR mszProfileNames;
ZeroMemory(&EnumType, sizeof(EnumType));
EnumType.dwSize = sizeof(EnumType);
EnumType.dwVersion = ENUM_TYPE_VERSION;
EnumType.dwFields = ET_DEVICENAME | ET_DEVICECLASS;
EnumType.pDeviceName = static_cast<LPCTSTR>(m_strPrnName);
EnumType.dwDeviceClass = CLASS_PRINTER;
cbSize = 0;
m_EnumColorProfiles(NULL, &EnumType, NULL, &cbSize, &dwProfiles);
mszProfileNames = (LPTSTR)AllocMem(cbSize);
bStatus DBGCHK = (mszProfileNames != NULL);
if(bStatus)
{
bStatus DBGCHK = m_EnumColorProfiles( NULL,
&EnumType,
reinterpret_cast<LPBYTE>(mszProfileNames),
&cbSize,
&dwProfiles);
if(bStatus)
{
hr DBGCHK = WriteColorProfiles(reinterpret_cast<LPBYTE>(mszProfileNames), cbSize);
}
else
{
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_GET_COLOR_PRF);
}
FreeMem(mszProfileNames);
}
else
{
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_GET_COLOR_PRF);
}
return hr;
}
/*++
Title:
DeleteColorProfiles
Routine Description:
deletes all profiles associated with printer
it is called on restoring color settings; needed because if a new color profile is added ,
settings from file will be restored on top ( #bug 274657)
it could work Ok without calling this function when P_I_2 is also restored, because there color profiles are "somehow" restored,
but even so, success was depending on the order of calls,which is bogus
Arguments:
None
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR code mapped to HRESULT(FACILITY_ITF) if failed
--*/
BOOL
TPrnStream::
DeleteColorProfiles(
VOID
)
{
TStatusB bStatus;
DWORD cbSize;
DWORD cbPrfSize;
DWORD dwProfiles;
ENUMTYPE EnumType;
LPTSTR mszProfileNames;
ZeroMemory(&EnumType, sizeof(EnumType));
EnumType.dwSize = sizeof(EnumType);
EnumType.dwVersion = ENUM_TYPE_VERSION;
EnumType.dwFields = ET_DEVICENAME | ET_DEVICECLASS;
EnumType.pDeviceName = static_cast<LPCTSTR>(m_strPrnName);
EnumType.dwDeviceClass = CLASS_PRINTER;
cbSize = 0;
m_EnumColorProfiles(NULL, &EnumType, NULL, &cbSize, &dwProfiles);
mszProfileNames = (LPTSTR)AllocMem(cbSize);
bStatus DBGCHK = (mszProfileNames != NULL);
if(bStatus)
{
bStatus DBGCHK = m_EnumColorProfiles( NULL,
&EnumType,
reinterpret_cast<LPBYTE>(mszProfileNames),
&cbSize,
&dwProfiles);
if(bStatus)
{
LPTSTR pszProfileName = mszProfileNames;
for(bStatus DBGNOCHK = TRUE ,cbPrfSize = 0; (cbPrfSize < cbSize) && bStatus;)
{
//
// skip last two zeros
//
if(_tcsclen(pszProfileName) > 0)
{
DBGMSG( DBG_TRACE, ( "DisassociateColorProfileWithDevice "TSTR" :: " TSTR " \n" ,
static_cast<LPCTSTR>(m_strPrnName) , pszProfileName ));
bStatus DBGCHK = m_DisassociateColorProfileFromDevice(NULL, pszProfileName, m_strPrnName);
}
cbPrfSize += (_tcsclen(pszProfileName) + 2) * sizeof(TCHAR);
pszProfileName = pszProfileName + _tcsclen(pszProfileName) + 1;
}
}
FreeMem(mszProfileNames);
}
return bStatus;
}
/*++
Title:
RestoreColorProfiles
Routine Description:
Reads multi zero string from stream and for every sz calls AssociateColorProfileWithDevice
Arguments:
NONE
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
RestoreColorProfiles(
VOID
)
{
DWORD cSize;
DWORD i;
LPTSTR pszProfileName;
LPTSTR aszProfileNames;
PrnBinInfo* lpPrnBinItem = NULL;
TStatusH hr;
TStatusB bStatus(DBG_WARN, ERROR_INSUFFICIENT_BUFFER);
hr DBGCHK = ReadColorProfiles(&lpPrnBinItem);
if(SUCCEEDED(hr))
{
//
// first delete color profiles assoc with printer; fix for bug 274657
//
bStatus DBGCHK = DeleteColorProfiles();
if(bStatus)
{
aszProfileNames = reinterpret_cast<LPTSTR>(reinterpret_cast<LPBYTE>(lpPrnBinItem) + lpPrnBinItem->pData);
cSize = lpPrnBinItem->cbData/sizeof(TCHAR);
//
// Traverse multisz string from tail to head starting with the first zero.
// I relay on the fact that multisz is terminated by 2 zeros.
// Default color profile is last color profile associated and we should preserve this setting.
//
for( bStatus DBGNOCHK = TRUE, i = 2; i <= cSize && bStatus; )
{
pszProfileName = aszProfileNames + cSize - i;
if( *(pszProfileName - 1) == 0 || (i == cSize) )
{
DBGMSG( DBG_TRACE, ( "AssociateColorProfileWithDevice "TSTR" :: " TSTR " \n" ,
static_cast<LPCTSTR>(m_strPrnName) , pszProfileName ));
bStatus DBGCHK = m_AssociateColorProfileWithDevice(NULL, pszProfileName, m_strPrnName);
hr DBGCHK = bStatus ? S_OK : MakePrnPersistHResult(PRN_PERSIST_ERROR_RESTORE_COLOR_PRF);
}
i++;
}
}
FreeMem(lpPrnBinItem);
}
return hr;
}
/*++
Title:
WritePrnData
Routine Description:
Build an PrnBinInfo item from key and value and write it into stream, at current position
steps:
WriteHeader: if header is not wrriten into file , write it down
Read from header number of items currently written
Read from header where prn data items begins
If no other items where written,get current position and after items storing, update header with start position
Build an PrnBinInfo item and write it into stream, at current position
Increase number of written items and Update header
Arguments:
pKey - key name ;
pValueName - key value ;
cbValueName - count bytes of pValueName
dwType - type
pData - actually data
cbData - count bytes of pData
Return Value:
S_OK if succeded
--*/
HRESULT
TPrnStream::
WritePrnData(
IN LPCTSTR pKey,
IN LPCTSTR pValueName,
IN DWORD cbValueName,
IN DWORD dwType,
IN LPBYTE pData,
IN DWORD cbData
)
{
ULARGE_INTEGER culiPrnDataItems;
ULARGE_INTEGER uliCurrentPos;
ULARGE_INTEGER uliPrnDataRoot;
TStatusB bStatus;
TStatusH hr;
bStatus DBGNOCHK = TRUE;
//
// Read from header number of items currently written
//
hr DBGCHK = ReadFromHeader(kcItems, &culiPrnDataItems);
if(SUCCEEDED(hr))
{
//
// Read from header where info begins in stream
//
hr DBGCHK = ReadFromHeader(kPrnDataRoot, &uliPrnDataRoot);
if(SUCCEEDED(hr))
{
if(uliPrnDataRoot.QuadPart == 0)
{
// Get current seek position ; it will be stored in header
//
DBGMSG( DBG_TRACE, ( "TPrnStream::bWritePrnData:: First prn data item!\n " ));
hr DBGCHK = GetCurrentPosition(uliCurrentPos);
}
if(SUCCEEDED(hr))
{
//
// Store item
//
hr DBGCHK = WriteItem( pKey,
pValueName,
cbValueName,
ktREG_TYPE + dwType,
pData,
cbData);
if(SUCCEEDED(hr))
{
//
// Updates number of items and start position in case that bWritePrnData succeded
// and it was the first prn data item written
//
culiPrnDataItems.QuadPart++;
hr DBGCHK = UpdateHeader(TPrnStream::kcItems, culiPrnDataItems);
if(SUCCEEDED(hr) && uliPrnDataRoot.QuadPart == 0)
{
//
// Update header with position where item begins if it was the first prn data item written
//
hr DBGCHK = UpdateHeader(TPrnStream::kPrnDataRoot, uliCurrentPos);
}
}
}
}
}
return hr;
}
/*++
Title:
ReadNextPrnData
Routine Description:
Read a printer data item from stream
Arguments:
Param pointers will point inside of lpBuffer:
pKey - key name ;not null
pValueName - key value ;not null
cbValueName - count bytes of pValueName
dwType - type
pData - actually data
cbData - count bytes of pData
lpBuffer - a null ptr that will contain ptr to read item;
must be deallocated by the caller if function succeed
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
ReadNextPrnData(
OUT LPTSTR& lpszKey,
OUT LPTSTR& lpszVal,
OUT DWORD& dwType,
OUT LPBYTE& lpbData,
OUT DWORD& cbSize,
OUT LPBYTE& lpBuffer ORPHAN
)
{
TStatusH hr;
PrnBinInfo* lpPrnBinItem = NULL;
lpszKey = NULL;
lpszVal = NULL;
lpbData = NULL;
lpBuffer = NULL;
cbSize = 0;
//
// Initialization!!!
// m_cIndex is current item for reading ; m_cPrnDataItems is number of items in stream ( entry in header )
// chesk to see if no items where read or if all itemes where read and m_cIndex passed the printers data area in stream
//
if((m_cPrnDataItems.QuadPart == 0) || (m_cIndex > m_cPrnDataItems.QuadPart))
{
//
// Read from header number of printer data items in stream
//
hr DBGCHK = ReadFromHeader(kcItems, &m_cPrnDataItems);
if(FAILED(hr))
{
goto End;
}
//
// Read from header where info begins in stream
// m_uliSeekPtr seek ptr will be always positioned where item begins
//
hr DBGCHK = ReadFromHeader(kPrnDataRoot, &m_uliSeekPtr);
if(FAILED(hr))
{
goto End;
}
m_cIndex = 0;
}
if(m_cIndex == m_cPrnDataItems.QuadPart)
{
DBGMSG( DBG_TRACE, ( "bReadNextPrnData :: Reach end of prn data items \n" ));
hr DBGNOCHK = STG_E_SEEKERROR;
//
// this way I indicate that I reached the end ;
// next call will see that m_cIndex > m_cPrnDataItems.QuadPart and will do the same as if
// I call this first time
//
m_cIndex++;
}
else
{
//
// dwSeekPtr will be set to the position where next prn data item begins
//
hr DBGCHK = ReadItemFromPosition(m_uliSeekPtr, lpPrnBinItem);
if(SUCCEEDED(hr))
{
m_cIndex++;
lpszKey = reinterpret_cast<LPTSTR>(reinterpret_cast<LPBYTE>(lpPrnBinItem) + lpPrnBinItem->pKey);
lpszVal = reinterpret_cast<LPTSTR>(reinterpret_cast<LPBYTE>(lpPrnBinItem) + lpPrnBinItem->pValue);
lpbData = reinterpret_cast<LPBYTE>(lpPrnBinItem) + lpPrnBinItem->pData;
cbSize = lpPrnBinItem->cbData;
dwType = lpPrnBinItem->dwType - ktREG_TYPE;
}
}
End:
if(FAILED(hr) && hr != STG_E_SEEKERROR)
{
//
// build my own result ; it will override STG_ results
//
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_READ_PRNDATA);
}
return hr;
}
/*++
Title:
WritePrnInfo2
Routine Description:
Build an item based on P_I_2 and write it into the stream
Convert P_I_2 into a flat buffer( LPTSTR -> offsets)
Build a PrnBinInfo item and write it into stream
Arguments:
lpPrinterInfo2 - ptr to P_I_2
cbPI2Size - P_I_2 buff size
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR error code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
WritePrnInfo2(
IN PRINTER_INFO_2* lpPrinterInfo2,
IN DWORD cbPI2Size
)
{
DWORD dwWritten;
ULARGE_INTEGER uliCurrentPos;
TStatusH hr;
TStatusB bStatus;
hr DBGNOCHK = E_FAIL;
bStatus DBGCHK = (lpPrinterInfo2 != NULL);
if(bStatus)
{
//
// Get item's start position
//
hr DBGCHK = GetCurrentPosition(uliCurrentPos);
if(SUCCEEDED(hr))
{
//
// Convert P_I_2 to flat buffer
//
lpPrinterInfo2->pSecurityDescriptor = 0;
MarshallDownStructure(reinterpret_cast<LPBYTE>(lpPrinterInfo2),
PrinterInfo2Fields,
sizeof(PRINTER_INFO_2),
RPC_CALL);
//
// Writes flat buffer into stream (WriteItem builds PrnBinInfo)
//
hr DBGCHK = WriteItem(NULL, NULL, 0, ktPrnInfo2 ,reinterpret_cast<LPBYTE>(lpPrinterInfo2), cbPI2Size);
if(SUCCEEDED(hr))
{
//
// Update header entry with start position in stream
//
hr DBGCHK = UpdateHeader(kPrnInfo2, uliCurrentPos);
//
// Printer name entry in header will point inside PI2
// if PI2 is not stored , printer name will be stored like an usual item
//
if(SUCCEEDED(hr))
{
//uliCurrentPos.QuadPart += OFFSETOF(PRINTER_INFO_2, pPrinterName);
hr DBGCHK = UpdateHeader(kPrnName, uliCurrentPos);
}
}
}
}
if(FAILED(hr))
{
//
// build my own result
//
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_WRITE_PI2);
}
return hr;
}
/*++
Title:
WritePrnName
Routine Description:
Build a PrnBinInfo item from printer name and write it into stream
Arguments:
None
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR error code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
WritePrnName(
VOID
)
{
ULARGE_INTEGER uliCurrentPos;
TStatusH hr;
hr DBGNOCHK = E_FAIL;
//
// Get item's start position
//
hr DBGCHK = GetCurrentPosition(uliCurrentPos);
if(SUCCEEDED(hr))
{
//
// Writes flat buffer into stream (WriteItem builds PrnBinInfo)
//
hr DBGCHK = WriteItem( NULL,
NULL,
0,
ktPrnName ,
reinterpret_cast<LPBYTE>(const_cast<LPTSTR>(static_cast<LPCTSTR>(m_strPrnName))),
(m_strPrnName.uLen() + 1) * sizeof(TCHAR));
if(SUCCEEDED(hr))
{
hr DBGCHK = UpdateHeader(kPrnName, uliCurrentPos);
}
}
if(FAILED(hr))
{
//
// build my own result
//
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_WRITE_PI2);
}
return hr;
}
/*++
Title:
ReadPrnInfo2
Routine Description:
Reads the P_I_2 entry in stream ;
Arguments:
lppPrnBinItem - pointer to readed item; NULL if no settings stored ;
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR error code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
ReadPrnInfo2(
OUT PrnBinInfo** lppPrnBinItem
)
{
PrnBinInfo* lpPrnBinItem = NULL;
ULARGE_INTEGER uliSeekPtr;
TStatusH hr;
TStatusB bStatus;
hr DBGNOCHK = E_FAIL;
bStatus DBGCHK = TRUE;
//
// Read from header where info begins in stream
//
hr DBGCHK = ReadFromHeader(kPrnInfo2, &uliSeekPtr);
if(SUCCEEDED(hr))
{
//
// if ReadFromHeader returns a S_OK and dwSeekPtr is zero, it means that nothing is stored
//
if(uliSeekPtr.QuadPart > 0)
{
//
// Read an item from specified position
//
hr DBGCHK = ReadItemFromPosition(uliSeekPtr, lpPrnBinItem);
if(SUCCEEDED(hr))
{
hr DBGCHK = MarshallUpItem(lpPrnBinItem);
}
}
else
{
hr DBGCHK = E_FAIL;
}
}
if(FAILED(hr))
{
if( lpPrnBinItem )
{
FreeMem(lpPrnBinItem);
}
*lppPrnBinItem = NULL;
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_READ_PI7);
}
else
{
*lppPrnBinItem = lpPrnBinItem;
}
return hr;
}
/*++
Title:
ReadPrnName
Routine Description:
Reads the P_I_2 entry in stream; if not P_I_2 settings stored , reads PrnName entry
Arguments:
strPrnName - printer name read from file
Return Value:
S_OK if succeded
An error code from an API converted to HRESULT
--*/
HRESULT
TPrnStream::
ReadPrnName(
OUT TString& strPrnName
)
{
PrnBinInfo* lpPrnBinItem = NULL;
TStatusH hr;
ULARGE_INTEGER uliSeekPtr;
LPTSTR lpszPrnName;
//
// Reads PRINTER_INFO_2 settings stored in stream.
// Printer Name is not stored if PRINTER_INFO_2 are stored.
//
hr DBGCHK = ReadPrnInfo2(&lpPrnBinItem);
if(SUCCEEDED(hr))
{
//
// printer name points inside P_I_2
//
DBGMSG( DBG_TRACE, ( "PrnName inside P_I2 \n"));
lpszPrnName = (reinterpret_cast<PRINTER_INFO_2*>(reinterpret_cast<LPBYTE>(lpPrnBinItem) + lpPrnBinItem->pData)->pPrinterName);
hr DBGCHK = strPrnName.bUpdate(lpszPrnName) ? S_OK : E_FAIL;
DBGMSG( DBG_TRACE, ( "PrnName "TSTR" \n" , static_cast<LPCTSTR>(strPrnName)));
}
else
{
//
// Reads the Header entry for Printer name.
//
hr DBGCHK = ReadFromHeader(kPrnName, &uliSeekPtr);
if(SUCCEEDED(hr))
{
//
// if ReadFromHeader returns a S_OK and dwSeekPtr is zero, it means that nothing is stored
//
if(uliSeekPtr.QuadPart > 0)
{
//
// Read an item from specified position
//
hr DBGCHK = ReadItemFromPosition(uliSeekPtr, lpPrnBinItem);
if(SUCCEEDED(hr))
{
DBGMSG( DBG_TRACE, ( "ReadPrnName from %d %d \n" , uliSeekPtr.HighPart, uliSeekPtr.LowPart));
hr DBGCHK = strPrnName.bUpdate(reinterpret_cast<LPTSTR>(reinterpret_cast<LPBYTE>(lpPrnBinItem) + lpPrnBinItem->pData)) ?
S_OK : E_FAIL;
DBGMSG( DBG_TRACE, ( "PrnName "TSTR" \n" , static_cast<LPCTSTR>(strPrnName)));
}
else
{
hr DBGCHK = E_FAIL;
}
}
else
{
hr DBGCHK = E_FAIL;
}
}
}
if (lpPrnBinItem)
{
FreeMem(lpPrnBinItem);
}
return hr;
}
/*++
Title:
WritePrnInfo7
Routine Description:
Build an item based on P_I_7 and write it into the stream
PRINTER_INFO_7.pszObjectGUID set on NULL because at restoring it has to be null -> no flat pointer conversion needed
Arguments:
lpPrinterInfo7 - ptr to P_I_7
cbPI7Size - P_I_7 buff actual size
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR error code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
WritePrnInfo7(
IN PRINTER_INFO_7* lpPrinterInfo7,
IN DWORD cbPI7Size
)
{
DWORD dwWritten;
ULARGE_INTEGER uliCurrentPos;
TStatusB bStatus;
TStatusH hr;
hr DBGNOCHK = E_FAIL;
bStatus DBGCHK = (lpPrinterInfo7 != NULL);
if(bStatus)
{
//
// Get item's start position
//
hr DBGCHK = GetCurrentPosition(uliCurrentPos);
if(SUCCEEDED(hr))
{
//
// Convert P_I_7 to flat buffer
//
lpPrinterInfo7->pszObjectGUID = NULL;
MarshallDownStructure(reinterpret_cast<LPBYTE>(lpPrinterInfo7),
PrinterInfo7Fields,
sizeof(PRINTER_INFO_7),
RPC_CALL);
//
// Writes flat buffer into stream (WriteItem builds PrnBinInfo)
//
hr DBGCHK = WriteItem(NULL, NULL, 0, ktPrnInfo7 ,reinterpret_cast<LPBYTE>(lpPrinterInfo7), cbPI7Size);
//
// Update header entry with start position in stream
//
if(SUCCEEDED(hr))
{
hr DBGCHK = UpdateHeader(kPrnInfo7, uliCurrentPos);
}
}
}
if(FAILED(hr))
{
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_WRITE_PI7);
}
return hr;
}
/*++
Title:
ReadPrnInfo7
Routine Description:
Reads the P_I_7 entry in stream
Arguments:
lppPrnBinItem - pointer to readed item; NULL if no settings stored
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR error code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
ReadPrnInfo7(
OUT PrnBinInfo** lppPrnBinItem
)
{
PrnBinInfo* lpPrnBinItem = NULL;
ULARGE_INTEGER uliSeekPtr;
TStatusB bStatus;
TStatusH hr;
hr DBGNOCHK = E_FAIL;
//
// Read from header where info begins in stream
//
hr DBGCHK = ReadFromHeader(kPrnInfo7, &uliSeekPtr);
if(SUCCEEDED(hr))
{
//
// if ReadFromHeader returns a S_OK and dwSeekPtr is zero, it means that nothing is stored
// function will succeed
//
if(uliSeekPtr.QuadPart > 0)
{
//
// Read an item from specified position
//
hr DBGCHK = ReadItemFromPosition(uliSeekPtr, lpPrnBinItem);
if(SUCCEEDED(hr))
{
hr DBGCHK = MarshallUpItem(lpPrnBinItem);
}
}
else
{
hr DBGCHK = E_FAIL;
}
}
if(FAILED(hr))
{
*lppPrnBinItem = NULL;
if( lpPrnBinItem )
{
FreeMem(lpPrnBinItem);
}
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_READ_PI7);
}
else
{
*lppPrnBinItem = lpPrnBinItem;
}
return hr;
}
/*++
Title:
WritePrnSecurity
Routine Description:
Build an item based on SecurityDescriptor and write it into the stream
Arguments:
lpPrinterInfo2 - ptr to P_I_2
cbPI2Size - P_I_2 buff size
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR error code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
WritePrnSecurity(
IN PRINTER_INFO_2* lpPrinterInfo2,
IN DWORD cbPI2Size
)
{
DWORD cbSize;
DWORD dwWritten;
ULARGE_INTEGER uliCurrentPos;
TStatusB bStatus;
TStatusH hr;
hr DBGNOCHK = E_FAIL;
bStatus DBGCHK = (lpPrinterInfo2 != NULL);
if(bStatus)
{
//
// Get item's start position
//
hr DBGCHK = GetCurrentPosition(uliCurrentPos);
if(SUCCEEDED(hr))
{
if(lpPrinterInfo2->pSecurityDescriptor != NULL)
{
cbSize = GetSecurityDescriptorLength(lpPrinterInfo2->pSecurityDescriptor);
bStatus DBGCHK =( cbSize >= SECURITY_DESCRIPTOR_MIN_LENGTH);
//
// alloc mem for flat buffer
//
if(bStatus)
{
//
// Writes flat buffer into stream (WriteItem builds PrnBinInfo)
//
hr DBGCHK = WriteItem( NULL,
NULL,
0,
ktSecurity ,
reinterpret_cast<LPBYTE>(lpPrinterInfo2->pSecurityDescriptor),
cbSize);
if(SUCCEEDED(hr))
{
//
// Update header entry with start position in stream
//
hr DBGCHK = UpdateHeader(kSecurity, uliCurrentPos);
}
}
else
{
hr DBGCHK = E_FAIL;
}
}
}
}
if(FAILED(hr))
{
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_WRITE_SEC);
}
return hr;
}
/*++
Title:
ReadPrnSecurity
Routine Description:
Reads the Security entry in stream
Arguments:
lppPrnBinItem - pointer to readed item; NULL if no settings stored ;
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR error code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
ReadPrnSecurity(
OUT PrnBinInfo** ppPrnBinItem
)
{
PrnBinInfo* lpPrnBinItem;
ULARGE_INTEGER uliSeekPtr;
TStatusH hr;
hr DBGNOCHK = E_FAIL;
//
// Read from header where info begins in stream
//
hr DBGCHK = ReadFromHeader(kSecurity, &uliSeekPtr);
if(SUCCEEDED(hr))
{
//
// if ReadFromHeader returns a S_OK and dwSeekPtr is zero, it means that nothing is stored
//
if(uliSeekPtr.QuadPart > 0)
{
//
// Read an item from specified position
//
hr DBGCHK = ReadItemFromPosition(uliSeekPtr, lpPrnBinItem);
}
else
{
hr DBGCHK = E_FAIL;
}
}
if(FAILED(hr))
{
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_READ_SEC);
*ppPrnBinItem = NULL;
}
else
{
*ppPrnBinItem = lpPrnBinItem;
}
return hr;
}
/*++
Title:
WritePrnInfo8
Routine Description:
Call WriteDevMode to write devmode into stream
Arguments:
lpPrinterInfo8 - ptr to P_I_8
cbSize - P_I_8 buffer actual size
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR error code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
WritePrnInfo8(
IN PRINTER_INFO_8* lpPrinterInfo8,
IN DWORD cbSize
)
{
TStatusB bStatus;
TStatusH hr;
hr DBGNOCHK = E_FAIL;
bStatus DBGCHK = (lpPrinterInfo8 != NULL) && (lpPrinterInfo8->pDevMode != NULL);
if(bStatus)
{
hr DBGCHK = WriteDevMode( lpPrinterInfo8->pDevMode,
lpPrinterInfo8->pDevMode->dmSize + lpPrinterInfo8->pDevMode->dmDriverExtra,
kPrnDevMode);
}
if(FAILED(hr))
{
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_WRITE_PRN_DEVMODE);
}
return hr;
}
/*++
Title:
ReadPrnInfo8
Routine Description:
Reads the Printer Dev Mode entry in stream
Arguments:
lppPrnBinItem - pointer to readed item; NULL if no settings stored ;
bInsidePI2 - TRUE if global dev mode was inside P_I_2 item
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR error code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
ReadPrnInfo8(
OUT PrnBinInfo** lppPrnBinItem
)
{
PrnBinInfo* lpPrnBinItem;
ULARGE_INTEGER uliSeekPtr;
TStatusH hr;
hr DBGNOCHK = E_FAIL;
//
// Read from header where info begins in stream
//
hr DBGCHK = ReadFromHeader(kPrnDevMode, &uliSeekPtr);
if(SUCCEEDED(hr))
{
if(uliSeekPtr.QuadPart == 0)
{
//
// no dev mode stored
//
hr DBGCHK = E_FAIL;
}
else
{
//
// Read an item from specified position
//
hr DBGCHK = ReadItemFromPosition(uliSeekPtr, lpPrnBinItem);
}
}
if(FAILED(hr))
{
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_READ_PRN_DEVMODE);
*lppPrnBinItem = NULL;
}
else
{
*lppPrnBinItem = lpPrnBinItem;
}
return hr;
}
/*++
Title:
WritePrnInfo9
Routine Description:
Call WriteDevMode to write devmode into stream
Arguments:
lpPrinterInfo9 - ptr to P_I_9
cbSize - P_I_9 buff size
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR error code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
WritePrnInfo9(
IN PRINTER_INFO_9* lpPrinterInfo9,
IN DWORD cbSize
)
{
TStatusB bStatus;
TStatusH hr;
ULARGE_INTEGER uliCurrentPos;
hr DBGNOCHK = E_FAIL;
bStatus DBGCHK = (lpPrinterInfo9 != NULL) && (lpPrinterInfo9->pDevMode != NULL);
if(bStatus)
{
hr DBGCHK = WriteDevMode( lpPrinterInfo9->pDevMode,
lpPrinterInfo9->pDevMode->dmSize + lpPrinterInfo9->pDevMode->dmDriverExtra,
kUserDevMode);
}
else
{
//
// set entry in header to a dummy value to show that dev mode was null
//
DBGMSG(DBG_TRACE , ("WritePrnInfo9 NO USER DEVMODE\n"));
//
// fix for bug 273541
// For the case when per user dev mode is null , update the header with a special value ,
// to signal that per user dev mode was stored in file.
//
uliCurrentPos.HighPart = -1;
uliCurrentPos.LowPart = -1;
hr DBGCHK = UpdateHeader(kUserDevMode, uliCurrentPos);
}
if(FAILED(hr))
{
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_WRITE_USR_DEVMODE);
}
return hr;
}
/*++
Title:
ReadPrnInfo9
Routine Description:
Reads the User Dev Mode entry in stream
Arguments:
lppPrnBinItem - pointer to readed item; NULL if no settings stored ;
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR error code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
ReadPrnInfo9(
OUT PrnBinInfo** ppPrnBinItem
)
{
PrnBinInfo* lpPrnBinItem = NULL;
ULARGE_INTEGER uliSeekPtr;
TStatusH hr;
hr DBGNOCHK = E_FAIL;
//
// Read from header where info begins in stream
//
hr DBGCHK = ReadFromHeader(kUserDevMode, &uliSeekPtr);
if(SUCCEEDED(hr))
{
if(uliSeekPtr.QuadPart == 0)
{
//
// no dev mode stored because no flags were specified
//
hr DBGCHK = E_FAIL;
}
else if(uliSeekPtr.LowPart == -1 && uliSeekPtr.HighPart == -1)
{
//
// dev mode was null at the time it was stored ( no Printing Prefferences set )
//
hr DBGNOCHK = S_OK;
*ppPrnBinItem = NULL;
}
else
{
//
// Read an item from specified position
//
hr DBGCHK = ReadItemFromPosition(uliSeekPtr, lpPrnBinItem);
}
}
if(FAILED(hr))
{
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_READ_USR_DEVMODE);
*ppPrnBinItem = NULL;
}
else
{
*ppPrnBinItem = lpPrnBinItem;
}
return hr;
}
/*++
Title:
WriteColorProfiles
Routine Description:
Build a PrnBinInfo item from a multi sz string that contains color profiles names
Arguments:
lpProfiles - ptr to multi zero string
cbSize - multi zero string size
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR error code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
WriteColorProfiles(
IN LPBYTE lpProfiles,
IN DWORD cbSize
)
{
ULARGE_INTEGER uliCurrentPos;
TStatusB bStatus;
TStatusH hr;
hr DBGNOCHK = E_FAIL;
bStatus DBGCHK = (lpProfiles != NULL);
if(bStatus)
{
//
// Get item's start position
//
hr DBGCHK = GetCurrentPosition(uliCurrentPos);
if(SUCCEEDED(hr))
{
//
// Writes profiles(MULTI_SZ) into stream (WriteItem builds PrnBinInfo)
//
hr DBGCHK = WriteItem(NULL, NULL, 0, ktColorProfile, lpProfiles, cbSize);
//
// Update header entry with start position in stream
//
if(SUCCEEDED(hr))
{
hr DBGCHK = UpdateHeader(kColorProfile, uliCurrentPos);
}
}
}
if(FAILED(hr))
{
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_WRITE_COLOR_PRF);
}
return hr;
}
/*++
Title:
ReadColorProfiles
Routine Description:
Reads the color profile entry in stream
Arguments:
lppPrnBinItem - pointer to readed item; NULL if no settings stored ;
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR error code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
ReadColorProfiles(
OUT PrnBinInfo** ppPrnBinItem
)
{
PrnBinInfo* lpPrnBinItem;
ULARGE_INTEGER uliSeekPtr;
TStatusH hr;
//
// Read from header where info begins in stream
//
hr DBGCHK = ReadFromHeader(kColorProfile, &uliSeekPtr);
if(SUCCEEDED(hr))
{
if(uliSeekPtr.QuadPart > 0)
{
//
// Read an item from specified position
//
hr DBGCHK = ReadItemFromPosition(uliSeekPtr, lpPrnBinItem);
}
else
{
hr DBGCHK = E_FAIL;
}
}
if(FAILED(hr))
{
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_READ_COLOR_PRF);
*ppPrnBinItem = NULL;
}
else
{
*ppPrnBinItem = lpPrnBinItem;
}
return hr;
}
/*++
Title:
WriteHeader
Routine Description:
Write header at the begining of file ; the header is null initialized
steps:
Write header into the stream; this is the very first writing operation
It reserves space at the beginning of stream for writing info about items inside the stream
StorePrintreInfo function will call WriteHeader before any other writing operation
If P_I_2 flag is NOT specified , write printre name as item ; if it is , printe name will be stored with P_I_2
Arguments:
Flags - flags specified at storing time ; needed for printer name handling
Return Value:
S_OK if succeded
An error code from an API converted to HRESULT
--*/
HRESULT
TPrnStream::
WriteHeader(
IN DWORD Flags
)
{
PrnHeader PrinterHeader;
DWORD dwSize = 0;
LARGE_INTEGER liStart = {0};
TStatusH hr;
TStatusB bStatus;
// Init hr with S_OK;if header is already written in stream, this will be the return value
//
hr DBGNOCHK = S_OK;
//
// m_bHeaderWritten indicates if header was written into file
//
if(!m_bHeaderWritten)
{
//
// Output the header. This basically reserves
// space at the beginning of the stream to store
// the item-count.
//
PrinterHeader.pPrnName.QuadPart = 0;
PrinterHeader.pPrnDataRoot.QuadPart = 0;
PrinterHeader.cItems.QuadPart = 0;
PrinterHeader.pUserDevMode.QuadPart = 0;
PrinterHeader.pPrnDevMode.QuadPart = 0;
PrinterHeader.pPrnInfo2.QuadPart = 0;
PrinterHeader.pPrnInfo7.QuadPart = 0;
PrinterHeader.pSecurity.QuadPart = 0;
PrinterHeader.pColorProfileSettings.QuadPart = 0;
//
// Make sure our header is positioned at the beginning of the stream.
//
hr DBGCHK = m_pIStream->Seek( liStart, STREAM_SEEK_SET, NULL );
//
// Write the header
//
if(SUCCEEDED(hr))
{
hr DBGCHK = m_pIStream->Write((LPBYTE)&PrinterHeader, sizeof(PrnHeader), &dwSize);
//
// indicates if header was written into file
//
m_bHeaderWritten = TRUE;
//
// write printer info into an entry if P_I_2 is not stored.
// if it is , prn name in header will point inside P_I_2
//
if(SUCCEEDED(hr) && !(Flags & PRST_PRINTER_INFO_2))
{
hr DBGCHK = WritePrnName();
}
}
DBGMSG( DBG_TRACE ,( "WriteHeader %x !!!\n" , hr));
}
return hr;
}
#if DBG
VOID
TPrnStream::
CheckHeader (
IN TPrnStream::EHeaderEntryType eHeaderEntryType,
IN ULARGE_INTEGER uliInfo
)
{
TStatusH hr;
ULARGE_INTEGER uliPtr;
EHeaderEntryType HeaderEntries[] = { kPrnDataRoot,
kcItems,
kUserDevMode,
kPrnDevMode,
kPrnInfo2,
kPrnInfo7,
kSecurity,
kColorProfile };
for( DWORD i = 0; i < sizeof (HeaderEntries) / sizeof (DWORD); i++ )
{
hr DBGCHK = ReadFromHeader(HeaderEntries[i], &uliPtr);
if (SUCCEEDED(hr)) {
//
// PI2 and Printer Name can point to the same location. Don't do this check!
//
if ( ! ( HeaderEntries[i] == kPrnInfo2 && eHeaderEntryType == kPrnName ) ||
( HeaderEntries[i] == kPrnName && eHeaderEntryType == kPrnInfo2) ) {
if( (uliPtr.LowPart && uliPtr.LowPart == uliInfo.LowPart ) || (uliPtr.HighPart && uliPtr.HighPart == uliInfo.HighPart) ) {
DBGMSG( DBG_TRACE,("*******CheckHeader: %d overwrites %d\n" , eHeaderEntryType , HeaderEntries[i]));
}
}
}
}
}
#endif
/*++
Title:
UpdateHeader
Routine Description:
Write Info at specified entry in header
Current position in stream in not modified after this call
Arguments:
eHeaderEntryType - Specify entry in header
uliInfo - Can be a pointer inside stream or a number of items
Return Value:
S_OK if succeded
An error code from an API converted to HRESULT
--*/
HRESULT
TPrnStream::
UpdateHeader(
IN TPrnStream::EHeaderEntryType eHeaderEntryType,
IN ULARGE_INTEGER uliInfo
)
{
DWORD dwSize;
ULARGE_INTEGER uliCurrentPosition;
ULARGE_INTEGER uliLastCurrentPosition;
LARGE_INTEGER liStart;
TStatusH hr;
#if DBG
CheckHeader(eHeaderEntryType, uliInfo);
#endif
// Saves current position into stream
//
hr DBGCHK = GetCurrentPosition(uliCurrentPosition);
if(SUCCEEDED(hr))
{
//
// Position stream pointer into the header on the specified entry
//
liStart.LowPart = eHeaderEntryType * sizeof(LARGE_INTEGER);
liStart.HighPart = 0;
hr DBGCHK = m_pIStream->Seek( liStart , STREAM_SEEK_SET, NULL );
DBGMSG( DBG_TRACE,("TPrnStream::UpdateHeader\n Update at %d with %d\n" , liStart.LowPart , uliInfo));
//
// Setup the header information.
//
if(SUCCEEDED(hr))
{
hr DBGCHK = m_pIStream->Write(reinterpret_cast<LPVOID>(&uliInfo), sizeof(LARGE_INTEGER), &dwSize);
}
//
// Restore stream current pointer (even if writing failed)
//
liStart.QuadPart = uliCurrentPosition.QuadPart;
hr DBGCHK = m_pIStream->Seek( liStart, STREAM_SEEK_SET, &uliLastCurrentPosition );
SPLASSERT( uliCurrentPosition.LowPart == uliLastCurrentPosition.LowPart );
SPLASSERT( uliCurrentPosition.HighPart == uliLastCurrentPosition.HighPart );
}
return hr;
}
/*++
Title:
ReadFromHeader
Routine Description:
Read Info from specified entry in header
Current position in stream in not modified after this call
Arguments:
eHeaderEntryType - Specify entry in header
puliInfo - holds the value found in header at position kHeaderEntryType
Return Value:
S_OK if succeded
An error code from an API converted to HRESULT
--*/
HRESULT
TPrnStream::
ReadFromHeader(
IN TPrnStream::EHeaderEntryType kHeaderEntryType,
OUT ULARGE_INTEGER* puliInfo
)
{
DWORD dwSize;
ULARGE_INTEGER uliEntryInfo;
ULARGE_INTEGER uliCurrentPos;
LARGE_INTEGER liStart;
TStatusH hr;
DBGMSG( DBG_NONE, ( "Read Header!\n"));
//
// Save current pos
//
hr DBGCHK = GetCurrentPosition(uliCurrentPos);
if(SUCCEEDED(hr))
{
//
// seek pointer has to point to kHeaderEntryType into IStream
//
liStart.LowPart = kHeaderEntryType * sizeof(LARGE_INTEGER);
liStart.HighPart = 0;
hr DBGCHK = m_pIStream->Seek( liStart , STREAM_SEEK_SET, NULL );
//
// Read from header entry a DWORD
//
if(SUCCEEDED(hr))
{
hr DBGCHK = m_pIStream->Read(&uliEntryInfo, sizeof(LARGE_INTEGER), &dwSize);
if(SUCCEEDED(hr))
{
puliInfo->QuadPart = uliEntryInfo.QuadPart;
}
else
{
DBGMSG( DBG_TRACE, ( "Read Header! FAILED !!!\n"));
}
//
// Restore stream current pointer (even if reading failed)
//
liStart.QuadPart = uliCurrentPos.QuadPart;
hr DBGCHK = m_pIStream->Seek( liStart , STREAM_SEEK_SET, NULL );
}
}
return hr;
}
/*++
Title:
WriteDevMode
Routine Description:
Build a PrnBinInfo item from ->DevMode and write it into stream
Arguments:
lpDevMode - ptr to DEVMODE
cbSize - buff size
eDevModeType - type : user / printer
Return Value:
S_OK if succeded
An error code from an API converted to HRESULT
--*/
HRESULT
TPrnStream::
WriteDevMode(
IN PDEVMODE lpDevMode,
IN DWORD cbSize,
IN EHeaderEntryType eDevModeType
)
{
ULARGE_INTEGER uliCurrentPos;
TStatusB bStatus;
TStatusH hr;
//
// Get item's start position
//
hr DBGCHK = GetCurrentPosition(uliCurrentPos);
if(SUCCEEDED(hr))
{
//
// Writes devmode into stream (WriteItem builds PrnBinInfo)
//
hr DBGCHK = WriteItem( NULL,
NULL,
0,
ktDevMode,
reinterpret_cast<LPBYTE>(lpDevMode),
cbSize);
//
// Update header entry with start position in stream
//
if(SUCCEEDED(hr))
{
hr DBGCHK = UpdateHeader(eDevModeType, uliCurrentPos);
}
}
return hr;
}
/*++
Title:
AdjustItemSizeForWin64
Routine Description:
The item will be reallocated on Win64.
When the file is generated on Win32, the item's size must be adjusted
so that the 64bit stucture will fit in.
The design doesn't allow to differenciate between files generated on Win32
and Win64, therefore the adjustment will be always performed for
Win64 up marshalling .
Arguments:
lpPrnBinItem -- reference to a pointer to the item to be adjusted.
Return Value:
S_OK if succeded
A Win32 error code converted to HRESULT
--*/
HRESULT
TPrnStream::
AdjustItemSizeForWin64(
IN OUT PrnBinInfo *&lpPrnBinItem,
IN FieldInfo *pFieldInfo,
IN SIZE_T cbSize,
OUT SIZE_T &cbDifference
)
{
TStatusB bStatus;
TStatusH hr(DBG_WARN, HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
SIZE_T cbWin32Size = 0;
SIZE_T cbWin64Size = cbSize;
PrnBinInfo *lpNewPrnBinItem = NULL;
switch (kPointerSize)
{
case kSpl32Ptr:
{
cbDifference = 0;
hr DBGNOCHK = S_OK;
break;
}
case kSpl64Ptr:
{
//
// Adjust item only on Win64
//
lpNewPrnBinItem = NULL;
bStatus DBGCHK = GetShrinkedSize(pFieldInfo, &cbWin32Size);
if ( bStatus )
{
//
// Calculate the quantity the item must grow with.
// It it the difference between the PRINTER_INFO_n size on
// Win64 and Win32.
//
cbDifference = cbWin64Size - cbWin32Size;
//
// Allocate a bufer that will hold the adjusted item.
//
lpNewPrnBinItem = (PrnBinInfo*)AllocMem(lpPrnBinItem->cbSize + (DWORD)cbDifference);
bStatus DBGCHK = !!lpNewPrnBinItem;
if ( bStatus )
{
//
// Copy the old item's content in the new buffer.
//
CopyMemory( lpNewPrnBinItem, lpPrnBinItem, lpPrnBinItem->cbSize);
//
// This memory move will make room for Win64 PRINTER_INFO_n to grow
// without corrupting data.
// Source: the spot right after flatened Win32 structure, which will
// contain data for items generated on Win32.
// Destination: the spot righ after Win64 structure. PRINTER_INFO_n data
// comes after this spot on Win64.
//
MoveMemory( (LPBYTE)lpNewPrnBinItem + lpNewPrnBinItem->pData + cbWin64Size,
(LPBYTE)lpNewPrnBinItem + lpNewPrnBinItem->pData + cbWin32Size,
lpNewPrnBinItem->cbData - cbWin32Size);
//
// Adjust new item's size.
//
lpNewPrnBinItem->cbData += (DWORD)cbDifference;
//
// Free the memory for the old item.
//
FreeMem(lpPrnBinItem);
lpPrnBinItem = lpNewPrnBinItem;
}
}
if(bStatus)
{
hr DBGNOCHK = S_OK;
}
else
{
hr DBGCHK = HRESULT_FROM_WIN32(GetLastError());
}
break;
}
default:
{
//
// Invalid pointer size; should not occur.
//
hr DBGCHK = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
break;
}
}
return hr;
}
/*++
Title:
MarshallUpItem
Routine Description:
Convert a "flat" PRINTER_INFO_2 item to an "alive" item.
Pointers inside PRINTER_INFO_2 data be converted to offsets before the item
is persisted in the file. The format of the flatened item must be the same
between Win64 and Win32,since the file will roam across TS servers.
Arguments:
lpPrnBinItem -- reference to a pointer to the item to be converted;
Return Value:
S_OK if succeded
A Win32 error code converted to HRESULT
--*/
HRESULT
TPrnStream::
MarshallUpItem (
IN OUT PrnBinInfo*& lpPrnBinItem
)
{
TStatusB bStatus;
TStatusH hr(DBG_WARN, HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
SIZE_T cbDifference = 0;
SIZE_T cbSize;
FieldInfo *pPrinterInfoFields;
bStatus DBGCHK = !!lpPrnBinItem;
if(bStatus)
{
switch (lpPrnBinItem->dwType)
{
case ktPrnInfo2:
{
cbSize = sizeof(PRINTER_INFO_2);
pPrinterInfoFields = PrinterInfo2Fields;
break;
}
case ktPrnInfo7:
{
cbSize = sizeof(PRINTER_INFO_7);
pPrinterInfoFields = PrinterInfo7Fields;
break;
}
default:
{
bStatus DBGCHK = FALSE;
break;
}
}
if(bStatus)
{
//
// This item will be reallocated when marshalled on Win64.
// On Win64, the item's size must be increased with
// the difference between strcuture's size on Win64 and Win32.
// The item could have been generated on Win32 and there is no room
// left for the structure to expand.
//
hr DBGCHK = AdjustItemSizeForWin64(lpPrnBinItem, pPrinterInfoFields, cbSize, cbDifference);
if(SUCCEEDED(hr))
{
bStatus DBGCHK = MarshallUpStructure((LPBYTE)lpPrnBinItem + lpPrnBinItem->pData,
pPrinterInfoFields,
cbSize,
RPC_CALL);
if(bStatus)
{
hr DBGNOCHK = S_OK;
}
else
{
hr DBGCHK = HRESULT_FROM_WIN32(GetLastError());
}
//
// If the item was adjusted, the pointers inside PRINTER_INFO_2 must be adjusted as well.
// AdjustPointers cannot be executed before marshalling because the structure is still flat
// as on Win32 and the pointers are not in their Win64 location.
//
if ( bStatus && cbDifference )
{
AdjustPointers ( (LPBYTE)lpPrnBinItem + lpPrnBinItem->pData,
pPrinterInfoFields,
cbDifference);
}
}
}
}
return hr;
}
/*++
Title:
AlignSize
Routine Description:
align a sice to DWORD size
Arguments:
cbSize - size to align
Return Value:
cbSize - value to align
--*/
DWORD
TPrnStream::
AlignSize(
IN DWORD cbSize
)
{
return((cbSize)+3)&~3;
}
/*++
Title:
StorePrnData
Routine Description:
Writes into stream printer data;
calls bInternalWalk that browse the registry key and to store the printer(registry) settings
WalkIn and WalkPost virtual methods of WalkPrinterData over-rided to store value data
Arguments:
None
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR error code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
StorePrnData(
VOID
)
{
TString strNullKey(_T(""));
DWORD cItems = 0;
TStatusB bStatus;
//
// Proceed bInternalWalk for NULL key
//
bStatus DBGCHK = strNullKey.bValid();
if(bStatus)
{
cItems = 0;
bStatus DBGCHK = bInternalWalk(strNullKey, &cItems);
}
return bStatus ? S_OK : MakePrnPersistHResult(PRN_PERSIST_ERROR_WRITE_PRNDATA);
}
/*++
Title:
bRestorePrnData
Routine Description:
Restore printer data from file;
Call ReadNextPrnData until all items are browsed in stream
Arguments:
None
Return Value:
S_OK if succeded
PRN_PERSIST_ERROR error code mapped to HRESULT(FACILITY_ITF) if failed
--*/
HRESULT
TPrnStream::
RestorePrnData(
VOID
)
{
LPTSTR lpszKey;
LPTSTR lpszVal;
DWORD dwType;
LPBYTE lpbData;
DWORD cDataSize;
LPBYTE lpPrinterBinInfo;
TStatusB bStatus;
TStatus Status;
TStatusH hr(DBG_WARN, STG_E_SEEKERROR);
bStatus DBGNOCHK = TRUE;
while(bStatus)
{
hr DBGCHK = ReadNextPrnData(lpszKey, lpszVal, dwType, lpbData, cDataSize, lpPrinterBinInfo);
DBGMSG( DBG_TRACE, ( "bReadNextPrnData :: key " TSTR " value " TSTR " \n" ,(LPCTSTR)lpszKey , (LPCTSTR)lpszVal ));
bStatus DBGCHK = SUCCEEDED(hr);
if(bStatus)
{
Status DBGCHK = SetPrinterDataExW(m_hPrinter,
lpszKey,
lpszVal,
dwType,
lpbData,
cDataSize);
if(Status != ERROR_SUCCESS)
{
hr DBGCHK = MakePrnPersistHResult(PRN_PERSIST_ERROR_RESTORE_PRNDATA);
}
FreeMem(lpPrinterBinInfo);
}
if(hr == STG_E_SEEKERROR)
{
//
// End of Prn Data
//
hr DBGNOCHK = S_OK;
}
}
return hr;
}
/*++
Title:
bWalkPost
Routine Description:
call bWriteKeyData : store key values into stream
Arguments:
strKey - name of the key to walk
lpcItems - if not null , outs number of items actually written
Return Value:
TRUE if succeded
--*/
BOOL
TPrnStream::
bWalkPost (
IN TString& strKey,
OUT LPDWORD lpcItems
)
{
DBGMSG( DBG_TRACE, ( "WALK POST :: " TSTR "\n" , (LPCTSTR)strKey ));
return bWriteKeyData(strKey, lpcItems);
}
/*++
Title:
bWalkIn
Routine Description:
call bWriteKeyData : store key values into stream
Arguments:
strKey - name of the key to walk
lpcItems - if not null , outs number of items actually written
Return Value:
TRUE if succeded
--*/
BOOL
TPrnStream::
bWalkIn (
IN TString& strKey,
OUT LPDWORD lpcItems
)
{
DBGMSG( DBG_TRACE, ( "WALK IN :: " TSTR "\n" , (LPCTSTR)strKey ));
return bWriteKeyData(strKey, lpcItems);
}
/*++
Title:
WriteKeyData
Routine Description:
Writes into stream all values for a given key name;
calls EnumPrinterDataEx and browse PRINTER_ENUM_VALUES array
Arguments:
strKey - name of the key to write
lpcItems - if not null , outs number of items actually written
Return Value:
TRUE if succeded
--*/
BOOL
TPrnStream::
bWriteKeyData(
IN LPCTSTR lpszKey,
OUT LPDWORD lpcItems OPTIONAL
)
{
*lpcItems = 0;
LPPRINTER_ENUM_VALUES apevData;
UINT idx;
DWORD dwRet;
DWORD cbSize;
DWORD cbNeededSize;
DWORD cItems = 0;
TStatus Status(ERROR_MORE_DATA);
TStatusB bStatus;
//
// Only write data if we are given a valid-key.
//
if((lpszKey == NULL) || (*lpszKey == _T('\0')))
{
bStatus DBGNOCHK = TRUE;
goto End;
}
//
// Determine the size necessary to store the enumerated data.
//
cbSize = 0;
Status DBGCHK = EnumPrinterDataEx(m_hPrinter, lpszKey, NULL, 0, &cbNeededSize, &cItems);
//
// Current key has no values
//
if(cbNeededSize == 0 && Status == ERROR_MORE_DATA)
{
bStatus DBGNOCHK = TRUE;
goto End;
}
//
// If current key has values, then proceed to enumerate and write the values into stream
//
if(cbNeededSize && (Status == ERROR_MORE_DATA))
{
if(apevData = (LPPRINTER_ENUM_VALUES)AllocMem(cbNeededSize)) //AllocBytes
{
//
// Enumerate all values for the specified key. This
// returns an array of value-structs.
//
Status DBGCHK = EnumPrinterDataExW( m_hPrinter,
lpszKey,
reinterpret_cast<LPBYTE>(apevData),
cbNeededSize,
&cbSize,
&cItems);
bStatus DBGCHK = (Status == ERROR_SUCCESS) && (cbNeededSize == cbSize);
//
// Enumerate all data for the specified key and write to the stream.
//
// Write all the values for this key.
//
for(idx = 0; (idx < cItems) && bStatus; idx++)
{
bStatus DBGCHK = bWriteKeyValue(static_cast<LPCTSTR>(lpszKey), apevData + idx);
}
*lpcItems = bStatus ? cItems : 0;
FreeMem(apevData);
}
}
End:
return bStatus;
}
/*++
Title:
bWriteKeyValue
Routine Description:
Writes into stream a value with it's data for a given key name
(Write key/value name and PRINTER_ENUM_VALUES into stream)
Arguments:
lpszKey - Key name
lpPEV - pointer to PRINTER_ENUM_VALUES assoc with key
Return Value:
TRUE if succeded
--*/
BOOL
TPrnStream::
bWriteKeyValue(
IN LPCTSTR lpszKey,
IN LPPRINTER_ENUM_VALUES lpPEV
)
{
TStatusB bStatus;
TStatusH hr;
hr DBGCHK = WritePrnData( lpszKey,
lpPEV->pValueName,
lpPEV->cbValueName,
lpPEV->dwType,
lpPEV->pData,
lpPEV->cbData);
bStatus DBGCHK = SUCCEEDED(hr);
return bStatus;
}
/*++
Title:
WriteItem
Routine Description:
Build a PrnBinInfo item and write it into stream, at current position
Arguments:
pKey - key name ; null for items other than printer data
pValueName - key value ; null for items other than printer data
cbValueName - count bytes of pValueName
dwType - type
pData - actually data
cbData - count bytes of pData
Return Value:
S_OK if succeded
An error code from an API converted to HRESULT
--*/
HRESULT
TPrnStream::
WriteItem(
IN LPCTSTR pKey,
IN LPCTSTR pValueName,
IN DWORD cbValueName,
IN DWORD dwType,
IN LPBYTE pData,
IN DWORD cbData
)
{
DWORD cbKeySize;
DWORD cbKey;
DWORD cbName;
DWORD cbSize;
DWORD dwWritten;
PrnBinInfo* lppbi;
TStatusH hr;
TStatusB bStatus;
// Calculate aligned sizes for the key-name and key-value strings.
//
DBGMSG( DBG_TRACE, ( "TPrnStream::WriteItem\n KEY: " TSTR "" , pKey ));
DBGMSG( DBG_TRACE, ( "VALUE: " TSTR "\n" , pValueName ));
cbKeySize = (pKey != NULL) ? (_tcslen(pKey) + 1) * sizeof(TCHAR) : 0;
cbKey = AlignSize(cbKeySize);
cbName = AlignSize(cbValueName);
// Calculate size necessary to hold our PrnBinInfo information
// which is written into stream.
//
cbSize = sizeof(PrnBinInfo) + cbKey + cbName + cbData;
cbSize = AlignSize(cbSize);
//
// Allocate space for the structure.
//
lppbi = (PrnBinInfo*)AllocMem(cbSize);
bStatus DBGCHK = (lppbi != NULL);
if(bStatus)
{
//
// Initialize the structure elements. Since this information
// is written to file, we must take care to convert the
// pointers to byte-offsets.
//
lppbi->cbSize = cbSize;
lppbi->dwType = dwType;
lppbi->pKey = sizeof(PrnBinInfo);
lppbi->pValue = lppbi->pKey + cbKey;
lppbi->pData = lppbi->pValue + cbName;
lppbi->cbData = cbData;
CopyMemory(reinterpret_cast<LPBYTE>(lppbi) + lppbi->pKey , pKey , cbKeySize);
CopyMemory(reinterpret_cast<LPBYTE>(lppbi) + lppbi->pValue, pValueName, cbValueName);
CopyMemory(reinterpret_cast<LPBYTE>(lppbi) + lppbi->pData , pData , cbData);
hr DBGCHK = m_pIStream->Write(lppbi, lppbi->cbSize, &dwWritten);
FreeMem(lppbi);
}
else
{
hr DBGCHK = E_OUTOFMEMORY;
}
return hr ;
}
/*++
Title:
ReadItem
Routine Description:
Read an item from a current position in stream
Arguments:
Param pointers will point inside of lpBuffer:
pKey - key name ; null for items other than printer data
pValueName - key value ; null for items other than printer data
cbValueName - count bytes of pValueName
dwType - type
pData - actually data
cbData - count bytes of pData
lpBuffer - a null ptr that will contain ptr to read item;
must be deallocated by the caller if function succeed
Return Value:
S_OK if succeded
An error code from an API converted to HRESULT
--*/
HRESULT
TPrnStream::
ReadItem(
OUT LPTSTR& lpszKey,
OUT LPTSTR& lpszVal,
OUT DWORD& dwType,
OUT LPBYTE& lpbData,
OUT DWORD& cbSize,
OUT LPBYTE& lpBuffer
)
{
ULARGE_INTEGER uliSeekPtr;
TStatusH hr;
PrnBinInfo* lpPrnBinItem = NULL;
lpszKey = NULL;
lpszVal = NULL;
lpbData = NULL;
lpBuffer = NULL;
hr DBGCHK = GetCurrentPosition(uliSeekPtr);
if(SUCCEEDED(hr))
{
hr DBGCHK = ReadItemFromPosition(uliSeekPtr, lpPrnBinItem);
if(SUCCEEDED(hr))
{
lpszKey = reinterpret_cast<LPTSTR>(reinterpret_cast<LPBYTE>(lpPrnBinItem) + lpPrnBinItem->pKey);
lpszVal = reinterpret_cast<LPTSTR>(reinterpret_cast<LPBYTE>(lpPrnBinItem) + lpPrnBinItem->pValue);
lpbData = reinterpret_cast<LPBYTE>(lpPrnBinItem) + lpPrnBinItem->pData;
cbSize = lpPrnBinItem->cbData;
dwType = lpPrnBinItem->dwType - ktREG_TYPE;
lpBuffer = reinterpret_cast<LPBYTE>(lpPrnBinItem);
}
}
else
{
hr DBGNOCHK = E_UNEXPECTED;
}
return hr;
}
/*++
Title:
ReadItemFromPosition
Routine Description:
Read an item from a given position in stream
Set seek pointer at the begining of the item
Read item's size
Set seek pointer at the begining of the item
Read item
uliSeekPtr will contain the seek pointer value after item's reading
Arguments:
uliSeekPtr - in start of item ; outs current seek ptr
lpPrnBinItem - ptr to read item
Return Value:
S_OK if succeded
An error code from an API converted to HRESULT
--*/
HRESULT
TPrnStream::
ReadItemFromPosition(
IN OUT ULARGE_INTEGER& uliSeekPtr,
OUT PrnBinInfo *& pPrnBinItem
)
{
DWORD cbReadedSize;
DWORD cbSize = 0;
LARGE_INTEGER liStart = {0};
TStatusH hr;
pPrnBinItem = NULL;
//
// Position seek pointer to where the item begins
//
liStart.QuadPart = uliSeekPtr.QuadPart;
hr DBGCHK = m_pIStream->Seek(liStart, STREAM_SEEK_SET, NULL);
if(SUCCEEDED(hr))
{
//
// Read size of item
//
hr DBGCHK = m_pIStream->Read(&cbSize, sizeof(DWORD), &cbReadedSize);
DBGMSG( DBG_TRACE, ("TPrnStream::ReadItemFromPosition\n Read item's size %d\n" ,cbSize) );
if(SUCCEEDED(hr))
{
//
// Go for start position again
//
hr DBGCHK = m_pIStream->Seek( liStart , STREAM_SEEK_SET, NULL );
if(SUCCEEDED(hr))
{
pPrnBinItem = (PrnBinInfo*)AllocMem(cbSize);
hr DBGCHK = pPrnBinItem ? S_OK : E_OUTOFMEMORY;
if(SUCCEEDED(hr))
{
hr DBGCHK = m_pIStream->Read(reinterpret_cast<LPBYTE>(pPrnBinItem), cbSize, &cbReadedSize);
SUCCEEDED(hr) ? GetCurrentPosition(uliSeekPtr) : FreeMem(pPrnBinItem);
}
}
}
}
return hr;
}
/*++
Title:
GetCurrentPosition
Routine Description:
Gets the current value of seek pointer into IStream
Arguments:
uliCurrentPosition - outs current seek ptr
Return Value:
TRUE if succeded
--*/
HRESULT
TPrnStream::
GetCurrentPosition(
OUT ULARGE_INTEGER& uliCurrentPosition
)
{
LARGE_INTEGER liMove = {0};
TStatusH hr;
uliCurrentPosition.QuadPart = 0;
hr DBGCHK = m_pIStream->Seek( liMove , STREAM_SEEK_CUR, &uliCurrentPosition );
return hr;
}
/*++
Title:
GetItemSize
Routine Description:
read item's size from stream
Arguments:
kHeaderEntryType - specify entry in header associated with item
Return Value:
item's size if succeeded or -1 if failed
--*/
DWORD
TPrnStream::
GetItemSize(
IN TPrnStream::EHeaderEntryType kHeaderEntryType
)
{
DWORD cbItemSize;
PrnBinInfo* lpPrnBinItem;
ULARGE_INTEGER uliSeekPtr;
TStatusH hr;
TStatusB bStatus;
cbItemSize = 0;
//
// Read from header where info begins in stream
//
hr DBGCHK = ReadFromHeader(kHeaderEntryType, &uliSeekPtr);
//
// if ReadFromHeader returns a S_OK and dwSeekPtr is zero, it means that nothing is stored
//
if(FAILED(hr))
{
cbItemSize = -1;
}
else
{
if(uliSeekPtr.QuadPart > 0)
//
// Read an item from specified position
//
hr DBGCHK = ReadItemFromPosition(uliSeekPtr, lpPrnBinItem);
if(FAILED(hr))
{
cbItemSize = -1;
}
else
{
cbItemSize = lpPrnBinItem->cbSize;
}
}
return cbItemSize;
}
/*++
Title:
InitalizeColorProfileLibrary
Routine Description:
Loads and gets the needed procedure address for the color profile related
functions. This library is explicitly loaded and un loaded to impove
load performce for winspool.drv. Note winspool.drv is a common dll loaded
by many applications so loading less libraries is a good thing.
Arguments:
None.
Return Value:
An HRESULT
--*/
HRESULT
TPrnStream::
InitalizeColorProfileLibrary(
VOID
)
{
HRESULT hRetval = E_FAIL;
m_pColorProfileLibrary = new TLibrary(L"mscms.dll");
hRetval = m_pColorProfileLibrary && m_pColorProfileLibrary->bValid() ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hRetval))
{
m_EnumColorProfiles = (pfnEnumColorProfilesW)m_pColorProfileLibrary->pfnGetProc("EnumColorProfilesW");
m_AssociateColorProfileWithDevice = (pfnAssociateColorProfileWithDeviceW)m_pColorProfileLibrary->pfnGetProc("AssociateColorProfileWithDeviceW");
m_DisassociateColorProfileFromDevice = (pfnDisassociateColorProfileFromDeviceW)m_pColorProfileLibrary->pfnGetProc("DisassociateColorProfileFromDeviceW");
if (!m_EnumColorProfiles || !m_AssociateColorProfileWithDevice || !m_DisassociateColorProfileFromDevice)
{
hRetval = HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);
}
}
return hRetval;
}
/*++
Routine Description:
Opens printer for specified access.
Arguments:
pszPrinter - Name of printer to open. szNULL or NULL implies local server.
pdwAccess - On entry, holds desired access (pointer to 0 indicates
maximal access). On successful exit, holds access granted.
If the call fails, this value is undefined.
phPrinter - Returns the open printer handle. On failure, this value
is set to NULL.
Return Value:
STATUS - win32 error code or ERROR_SUCCESS if successful.
--*/
STATUS
TPrnStream::
sOpenPrinter(
LPCTSTR pszPrinter,
PDWORD pdwAccess,
PHANDLE phPrinter
)
{
STATUS Status = ERROR_SUCCESS;
TStatusB bOpen( DBG_WARN,
ERROR_ACCESS_DENIED,
RPC_S_SERVER_UNAVAILABLE,
ERROR_INVALID_PRINTER_NAME );
bOpen DBGNOCHK = FALSE;
static const DWORD adwAccessPrinter[] = {
PRINTER_ALL_ACCESS,
PRINTER_READ,
READ_CONTROL,
0,
};
static const DWORD adwAccessServer[] = {
SERVER_ALL_ACCESS,
SERVER_READ,
0,
};
PRINTER_DEFAULTS Defaults;
Defaults.pDatatype = NULL;
Defaults.pDevMode = NULL;
if( pszPrinter && !pszPrinter[0] ){
//
// szNull indicates local server also; change it to
// NULL since OpenPrinter only likes NULL.
//
pszPrinter = NULL;
}
//
// Now determine whether we are opening a server or a printer.
// This is very messy. Look for NULL or two beginning
// backslashes and none thereafter to indicate a server.
//
PDWORD pdwAccessTypes;
if( !pszPrinter ||
( pszPrinter[0] == TEXT( '\\' ) &&
pszPrinter[1] == TEXT( '\\' ) &&
!_tcschr( &pszPrinter[2], TEXT( '\\' )))){
pdwAccessTypes = (PDWORD)adwAccessServer;
} else {
pdwAccessTypes = (PDWORD)adwAccessPrinter;
}
if( *pdwAccess ){
Defaults.DesiredAccess = *pdwAccess;
bOpen DBGCHK = OpenPrinter( (LPTSTR)pszPrinter,
phPrinter,
&Defaults );
if( !bOpen ){
Status = GetLastError();
}
} else {
//
// If no access is specified, then attempt to retrieve the
// maximal access.
//
UINT i;
for( i = 0; !bOpen && pdwAccessTypes[i]; ++i ){
Defaults.DesiredAccess = pdwAccessTypes[i];
bOpen DBGCHK = OpenPrinter( (LPTSTR)pszPrinter,
phPrinter,
&Defaults );
if( bOpen ){
//
// Return the access requested by the successful OpenPrinter.
// On failure, this value is 0 (*pdwAccess undefined).
//
*pdwAccess = pdwAccessTypes[i];
break;
}
Status = GetLastError();
if( ERROR_ACCESS_DENIED != Status )
break;
}
}
if( !bOpen ){
SPLASSERT( Status );
*phPrinter = NULL;
return Status;
}
SPLASSERT( *phPrinter );
return ERROR_SUCCESS;
}
/*++
Routine Description:
Gets printer information, reallocing as necessary.
Arguments:
hPrinter - Printer to query.
dwLevel - PRINTER_INFO_x level to retrieve.
ppvBuffer - Buffer to store information. If *ppvBuffer is
NULL, then it is allocated. On failure, this buffer is
freed and NULLed
pcbBuffer - Initial buffer size. On exit, actual.
Return Value:
TRUE = success, FALSE = fail.
--*/
BOOL
TPrnStream::
bGetPrinter(
IN HANDLE hPrinter,
IN DWORD dwLevel,
IN OUT PVOID* ppvBuffer,
IN OUT PDWORD pcbBuffer
)
{
DWORD cbNeeded;
enum
{
kMaxPrinterInfo2 = 0x1000,
kExtraPrinterBufferBytes = 0x80
};
//
// Pre-initialize *pcbPrinter if it's not set.
//
if( !*pcbBuffer ){
*pcbBuffer = kMaxPrinterInfo2;
}
Retry:
SPLASSERT( *pcbBuffer < 0x100000 );
if( !( *ppvBuffer )){
*ppvBuffer = (PVOID)AllocMem( *pcbBuffer );
if( !*ppvBuffer ){
*pcbBuffer = 0;
return FALSE;
}
}
if( !GetPrinter( hPrinter,
dwLevel,
(PBYTE)*ppvBuffer,
*pcbBuffer,
&cbNeeded )){
FreeMem( *ppvBuffer );
*ppvBuffer = NULL;
if( GetLastError() != ERROR_INSUFFICIENT_BUFFER ){
*pcbBuffer = 0;
return FALSE;
}
*pcbBuffer = cbNeeded + kExtraPrinterBufferBytes;
SPLASSERT( *pcbBuffer < 0x100000 );
goto Retry;
}
return TRUE;
}
BOOL
TPrnStream::
bNewShareName(
IN LPCTSTR lpszServer,
IN LPCTSTR lpszBaseShareName,
OUT TString &strShareName
)
{
BOOL bReturn = FALSE;
if( lpszServer && lpszBaseShareName )
{
HRESULT hr = CoInitialize(NULL);
BOOL bInitializedCOM = SUCCEEDED(hr);
TCHAR szBuffer[255];
IPrintUIServices *pPrintUI = NULL;
if( SUCCEEDED(hr) &&
SUCCEEDED(hr = CoCreateInstance(CLSID_PrintUIShellExtension, 0, CLSCTX_INPROC_SERVER,
IID_IPrintUIServices, (void**)&pPrintUI)) &&
pPrintUI &&
SUCCEEDED(hr = pPrintUI->GenerateShareName(lpszServer, lpszBaseShareName, szBuffer, COUNTOF(szBuffer))) )
{
strShareName.bUpdate(szBuffer);
bReturn = TRUE;
}
else
{
SetLastError(HRESULT_CODE(hr));
}
if( pPrintUI )
{
pPrintUI->Release();
}
if( bInitializedCOM )
{
CoUninitialize();
}
}
return bReturn;
}