400 lines
7 KiB
C++
400 lines
7 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (C) Microsoft Corporation, 1995 - 1998
|
||
|
All rights reserved.
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
data.cxx
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Holds VData functions.
|
||
|
|
||
|
Currently hold static pNew function that determines which concrete
|
||
|
VData class should be instantiated (determined at runtime).
|
||
|
|
||
|
Also holds MNotifyWork virtual definition.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Albert Ting (AlbertT) 12-Jun-1995
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "precomp.hxx"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
|
||
|
STATEVAR
|
||
|
VData::
|
||
|
svNew(
|
||
|
MDataClient* pDataClient,
|
||
|
STATEVAR StateVar,
|
||
|
VData*& pData
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
The VData tree uses the abstract class factory idiom. Clients
|
||
|
create a class derived from MDataClient which support pNewNotify
|
||
|
and pNewRefresh. Both these virtual fuctions create derived objects
|
||
|
that are stored as base pointers in this class.
|
||
|
|
||
|
This specific creation of derived VData classes without polluting
|
||
|
VData or it's internals with switch statements or flags to determine
|
||
|
which concrete class should be used.
|
||
|
|
||
|
Create the data object. This will first create a TDataNotify;
|
||
|
if that fails because it's a downlevel server, it will create
|
||
|
a TDataRefresh.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
StateVar - Current state of printer.
|
||
|
|
||
|
pDataClient - Interface to data client.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
VData* on success, NULL on failure.
|
||
|
|
||
|
StateVar - State of printer, either:
|
||
|
|
||
|
kExecReopen | kExecDelay if everything failed or,
|
||
|
0 if everything succeded (refresh already done).
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
STATEVAR StateVarOrg = StateVar;
|
||
|
|
||
|
//
|
||
|
// First attempt an uplevel connection by instantiating a
|
||
|
// TDataNotify. If that fails, then use downlevel.
|
||
|
//
|
||
|
pData = pDataClient->pNewNotify( pDataClient );
|
||
|
|
||
|
//
|
||
|
// If the object failed to initialize, reopen the printer.
|
||
|
// We don't want to try the downlevel case, since we may have
|
||
|
// failed due to lack of memory.
|
||
|
//
|
||
|
if( !VALID_PTR( pData )){
|
||
|
|
||
|
//
|
||
|
// Error, delay and put error message up.
|
||
|
//
|
||
|
goto Fail;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Attempt a refresh if the refresh is successful, then we are
|
||
|
// talking to an uplevel server.
|
||
|
//
|
||
|
StateVar = pData->svNotifyStart( StateVar );
|
||
|
|
||
|
//
|
||
|
// If it's an access denied, then we can't open the printer.
|
||
|
// (The open may succeed because of the spooler's caching.)
|
||
|
//
|
||
|
if( StateVar & TPrinter::kExecDelay &&
|
||
|
GetLastError() == ERROR_ACCESS_DENIED ){
|
||
|
|
||
|
return StateVar;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If a Reopen was not requested, continue trying to use it.
|
||
|
//
|
||
|
if( !( StateVar & TPrinter::kExecReopen )){
|
||
|
|
||
|
StateVar = pData->svRefresh( StateVar );
|
||
|
|
||
|
//
|
||
|
// If a Reopen was not requested, then we succeeded and we can
|
||
|
// use the newly created pData.
|
||
|
//
|
||
|
if( !( StateVar & TPrinter::kExecReopen )){
|
||
|
return StateVar;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// The uplevel case failed; now assume it is downlevel and
|
||
|
// create a TDataRefresh.
|
||
|
//
|
||
|
|
||
|
StateVar = StateVarOrg;
|
||
|
|
||
|
//
|
||
|
// Close notification and delete the notification.
|
||
|
//
|
||
|
pData->svNotifyEnd( StateVar );
|
||
|
|
||
|
delete pData;
|
||
|
|
||
|
pData = pDataClient->pNewRefresh( pDataClient );
|
||
|
|
||
|
if( !VALID_PTR( pData )){
|
||
|
goto Fail;
|
||
|
}
|
||
|
|
||
|
return pData->svNotifyStart( StateVar );
|
||
|
|
||
|
Fail:
|
||
|
|
||
|
delete pData;
|
||
|
pData = NULL;
|
||
|
|
||
|
return StateVar | TPrinter::kExecReopen | TPrinter::kExecDelay;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
VData::
|
||
|
vDelete(
|
||
|
VOID
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Delete the pData. We create a separate utility function to mirror
|
||
|
svNew.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
SPLASSERT( !m_shNotify );
|
||
|
|
||
|
delete this;
|
||
|
}
|
||
|
|
||
|
/********************************************************************
|
||
|
|
||
|
VData ctr, dtr.
|
||
|
|
||
|
********************************************************************/
|
||
|
|
||
|
VData::
|
||
|
VData(
|
||
|
MDataClient* pDataClient,
|
||
|
PFIELD_TABLE pFieldTable
|
||
|
) : _pDataClient( pDataClient ),
|
||
|
_pFieldTable( pFieldTable )
|
||
|
{
|
||
|
SPLASSERT( _pFieldTable );
|
||
|
SPLASSERT( _pDataClient );
|
||
|
|
||
|
UIGuard._cItems = 0;
|
||
|
|
||
|
TStatusB bStatus;
|
||
|
bStatus DBGCHK = pDataClient->bGetPrintLib(_pPrintLib);
|
||
|
|
||
|
if( !bStatus ){
|
||
|
DBGMSG( DBG_WARN, ( "VData::ctor bGetSingleton::ctor Failed %d\n", GetLastError( )));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VData::
|
||
|
~VData(
|
||
|
VOID
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Destroy the VData object.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
//
|
||
|
// Remove all items from the UI now that we are about to delete
|
||
|
// pData. We have shut down the notifications and cleared the
|
||
|
// UI windows message queue, so this is safe.
|
||
|
//
|
||
|
_pDataClient->vContainerChanged( kContainerClearItems, kInfoNull );
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
VData::
|
||
|
bValid(
|
||
|
VOID
|
||
|
) const
|
||
|
{
|
||
|
//
|
||
|
// Valid _pPrintLib pointer is our valid check.
|
||
|
//
|
||
|
return _pPrintLib.pGet() != NULL;
|
||
|
}
|
||
|
|
||
|
/********************************************************************
|
||
|
|
||
|
Add and retrieve hBlocks.
|
||
|
|
||
|
********************************************************************/
|
||
|
|
||
|
VData::
|
||
|
TBlock::
|
||
|
TBlock(
|
||
|
IN DWORD dwParam1,
|
||
|
IN DWORD dwParam2,
|
||
|
IN HANDLE hBlock
|
||
|
) : _dwParam1( dwParam1 ), _dwParam2( dwParam2 ), _hBlock( hBlock )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
VData::
|
||
|
TBlock::
|
||
|
~TBlock(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
VData::
|
||
|
vBlockAdd(
|
||
|
IN DWORD dwParam1,
|
||
|
IN DWORD dwParam2,
|
||
|
IN HANDLE hBlock ADOPT
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Add block to linked list.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
dwParam1 - dwParam to add.
|
||
|
|
||
|
dwParam2 - dwParam to add.
|
||
|
|
||
|
hBlock - hBlock to add.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
TBlock* pBlock = new TBlock( dwParam1, dwParam2, hBlock );
|
||
|
|
||
|
if( !VALID_PTR( pBlock )){
|
||
|
|
||
|
delete pBlock;
|
||
|
|
||
|
INFO Info;
|
||
|
Info.dwData = TPrinter::kExecRefresh;
|
||
|
|
||
|
//
|
||
|
// Request a refresh with a delay, then delete the adopted hBlock.
|
||
|
//
|
||
|
_pDataClient->vContainerChanged( kContainerStateVar, Info );
|
||
|
vBlockDelete( hBlock );
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
{
|
||
|
CCSLock::Locker CSL( csData( ));
|
||
|
Block_vAppend( pBlock );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Notify UI thread that there is more data.
|
||
|
//
|
||
|
_pDataClient->vContainerChanged( kContainerNewBlock, kInfoNull );
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
VData::
|
||
|
vBlockProcess(
|
||
|
VOID
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Retrieve a block from our linked list. Only called from UI thread,
|
||
|
or within a protective critical section.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
TBlock* pBlock;
|
||
|
|
||
|
for( ; ; ){
|
||
|
|
||
|
{
|
||
|
CCSLock::Locker CSL( csData( ));
|
||
|
|
||
|
pBlock = Block_pHead();
|
||
|
|
||
|
if( pBlock ){
|
||
|
Block_vDelink( pBlock );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( !pBlock ){
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
vBlockProcessImp( pBlock->_dwParam1,
|
||
|
pBlock->_dwParam2,
|
||
|
pBlock->_hBlock );
|
||
|
delete pBlock;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/********************************************************************
|
||
|
|
||
|
MNotifyWork virtual functions.
|
||
|
|
||
|
********************************************************************/
|
||
|
|
||
|
HANDLE
|
||
|
VData::
|
||
|
hEvent(
|
||
|
VOID
|
||
|
) const
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Virtual function to return the hNotify object back to MNotifyWork.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
return m_shNotify;
|
||
|
}
|
||
|
|