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