Leaked source code of windows server 2003
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.
 
 
 
 
 
 

6022 lines
156 KiB

/*++
Copyright (C) Microsoft Corporation, 1995 - 1999
All rights reserved.
Module Name:
prtprop.cxx
Abstract:
Holds Printer properties.
Author:
Albert Ting (AlbertT) 15-Aug-1995
Revision History:
--*/
#include "precomp.hxx"
#pragma hdrstop
#include "lmerr.h"
#include "prshtp.h"
#include "time.hxx"
#include "psetup.hxx"
#include "drvsetup.hxx"
#include "instarch.hxx"
#include "portdlg.hxx"
#include "sepdlg.hxx"
#include "procdlg.hxx"
#include "portslv.hxx"
#include "driverif.hxx"
#include "driverlv.hxx"
#include "dsinterf.hxx"
#include "prtprop.hxx"
#include "propmgr.hxx"
#include "prtprops.hxx"
#include "drvsetup.hxx"
#include "archlv.hxx"
#include "detect.hxx"
#include "setup.hxx"
#include "tstpage.hxx"
#include "prtshare.hxx"
#include "drvver.hxx"
#include "docdef.hxx"
#include "persist.hxx"
#include "prndata.hxx"
#include "physloc.hxx"
#include "findloc.hxx"
#include <shgina.h> // ILocalMachine, ILogonUser
#if DBG
//#define DBG_PROPSINFO DBG_INFO
#define DBG_PROPSINFO DBG_NONE
#endif
/********************************************************************
Message map used after a set printer call.
********************************************************************/
MSG_ERRMAP gaMsgErrMapSetPrinter[] = {
ERROR_INVALID_PRINTER_STATE, IDS_ERR_INVALID_PRINTER_STATE,
NERR_DuplicateShare, IDS_ERR_DUPLICATE_SHARE,
ERROR_INVALID_SHARENAME, IDS_ERR_INVALID_SHARENAME,
ERROR_ALREADY_EXISTS, IDS_ERR_DUPLICATED_DS_ITEM,
ERROR_IO_PENDING, IDS_ERR_LIST_IN_DIRECTORY,
0, 0
};
/********************************************************************
Forward Decl.
********************************************************************/
INT_PTR
WarningDlgProc(
IN HWND hWnd,
IN UINT msg,
IN WPARAM wParam,
IN LPARAM lParam
);
/********************************************************************
Public interface.
********************************************************************/
VOID
vPrinterPropPagesWOW64(
IN HWND hwnd,
IN LPCTSTR pszPrinterName,
IN INT nCmdShow,
IN LPARAM lParam
)
/*++
Routine Description:
WOW64 version.
see vPrinterPropPages below.
Arguments:
see vPrinterPropPages below.
Return Value:
--*/
{
//
// This function potentially may load the driver UI so we call a private API
// exported by winspool.drv, which will RPC the call to a special 64 bit surrogate
// process where the 64 bit driver can be loaded.
//
CDllLoader dll(TEXT("winspool.drv"));
ptr_PrintUIPrinterPropPages pfnPrintUIPrinterPropPages =
(ptr_PrintUIPrinterPropPages )dll.GetProcAddress(ord_PrintUIPrinterPropPages);
if( pfnPrintUIPrinterPropPages )
{
pfnPrintUIPrinterPropPages( hwnd, pszPrinterName, nCmdShow, lParam );
}
}
VOID
vPrinterPropPagesNative(
IN HWND hwnd,
IN LPCTSTR pszPrinterName,
IN INT nCmdShow,
IN LPARAM lParam
)
/*++
Routine Description:
Native version.
see vPrinterPropPages below.
Arguments:
see vPrinterPropPages below.
Return Value:
--*/
{
BOOL bModal = FALSE;
DWORD dwSheetIndex = (DWORD)-1;
LPCTSTR pszSheetName = NULL;
//
// If this page was launched by name then the lParam points to the tab name.
//
if( HIWORD( lParam ) )
{
pszSheetName = (LPCTSTR)lParam;
}
//
// Only if the sheet is launched by index can optionaly be modal.
//
else
{
dwSheetIndex = LOWORD( lParam ) & 0x00FF;
bModal = LOWORD( lParam ) & 0xFF00;
}
(VOID)dwPrinterPropPagesInternal( hwnd,
pszPrinterName,
pszSheetName,
dwSheetIndex,
nCmdShow,
bModal,
NULL );
}
VOID
vPrinterPropPages(
IN HWND hwnd,
IN LPCTSTR pszPrinterName,
IN INT nCmdShow,
IN LPARAM lParam
)
/*++
Routine Description:
This function opens the property sheet of specified printer.
We can't guarentee that this propset will perform all lengthy
operations in a worker thread (we synchronously call things like
ConfigurePort). Therefore, we spawn off a separate thread to
handle printer properties.
Arguments:
hWnd - Specifies the parent window for errors on creation.
pszPrinter - Specifies the printer name (e.g., "My HP LaserJet IIISi").
nCmdShow -
lParam - Specified either a sheet number or sheet name to open. If the high
word of this parameter is non zero it is assumed that this parameter
is a pointer the name of the sheet to open. Otherwize the this
parameter is the zero based index of which sheet to open.
Return Value:
--*/
{
if( IsRunningWOW64() )
{
vPrinterPropPagesWOW64( hwnd, pszPrinterName, nCmdShow, lParam );
}
else
{
vPrinterPropPagesNative( hwnd, pszPrinterName, nCmdShow, lParam );
}
}
/*++
Routine Description:
This function opens the property sheet of specified printer.
We can't guarentee that this propset will perform all lengthy
operations in a worker thread (we synchronously call things like
ConfigurePort). Therefore, we spawn off a separate thread to
handle printer properties.
Arguments:
hWnd - Specifies the parent window for errors on creation.
pDataObject - Pointer to an IDataObject passed to my the caller.
Return Value:
ERROR_SUCCESS UI displayed, ERROR_ACCESS_DENIED failure occurred not UI.
--*/
DWORD
dwPrinterPropPages(
IN HWND hwnd,
IN IDataObject *pDataObject,
IN PBOOL pbDisplayed
)
{
FORMATETC fmte = { CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
STGMEDIUM medium = { TYMED_NULL, NULL, NULL };
UINT cfDsObjectNames = 0;
LPDSOBJECTNAMES pObjectNames = NULL;
DWORD dwReturn = ERROR_ACCESS_DENIED;
TString strName;
//
// Get the DS object clipboard format.
//
fmte.cfFormat = static_cast<USHORT>( RegisterClipboardFormat( CFSTR_DSOBJECTNAMES ) );
//
// Get the data from the provided IDataObject
//
if( SUCCEEDED(pDataObject->GetData(&fmte, &medium)) )
{
//
// Fetch the object name
//
pObjectNames = (LPDSOBJECTNAMES)medium.hGlobal;
if( pObjectNames )
{
for( UINT i = 0 ; i < pObjectNames->cItems ; i++ )
{
TStatusB bStatus;
//
// Get the Ds object path.
//
bStatus DBGCHK = strName.bUpdate( (LPTSTR)(((LPBYTE)pObjectNames)+pObjectNames->aObjects[i].offsetName) );
if( bStatus )
{
TStatus Status;
//
// Bring up printer properties.
//
Status DBGCHK = dwPrinterPropPages( hwnd, strName, NULL );
//
// Set the return value.
//
dwReturn = Status;
}
}
}
//
// Release the storage medium.
//
ReleaseStgMedium( &medium );
}
return dwReturn;
}
/*++
Routine Description:
This function opens the property sheet of specified printer.
We can't guarentee that this propset will perform all lengthy
operations in a worker thread (we synchronously call things like
ConfigurePort). Therefore, we spawn off a separate thread to
handle printer properties.
Arguments:
hWnd - Specifies the parent window for errors on creation.
pDataObject - Pointer to an IDataObject passed to my the caller.
Return Value:
ERROR_SUCCESS UI displayed, ERROR_ACCESS_DENIED failure occurred not UI.
--*/
DWORD
dwPrinterPropPages(
IN HWND hwnd,
IN LPCTSTR pszDsPath,
IN PBOOL pbDisplayed
)
{
SPLASSERT( pszDsPath );
VARIANT Variant;
TDirectoryService Di;
IADs *pDsObject = NULL;
HRESULT hr = E_FAIL;
DWORD dwReturn = ERROR_ACCESS_DENIED;
//
// Initialize the displayed flag.
//
if( pbDisplayed )
{
*pbDisplayed = FALSE;
}
if( VALID_OBJ( Di ) )
{
//
// Get the ads object interface pointer.
//
hr = Di.ADsGetObject( const_cast<LPTSTR>( pszDsPath ),
IID_IADs,
reinterpret_cast<LPVOID*>( &pDsObject ) );
if( SUCCEEDED( hr ) )
{
//
// Initialize the variant for getting the object UNC property.
//
VariantInit(&Variant);
//
// Get the objects uNCName
//
hr = pDsObject->Get( SPLDS_UNC_NAME, &Variant );
if( SUCCEEDED( hr ) && Variant.vt == VT_BSTR && Variant.bstrVal && Variant.bstrVal[0] )
{
VARIANT versionVariant;
VariantInit(&versionVariant);
//
// Get the objects uNCName
//
hr = pDsObject->Get( TEXT("versionNumber"), &versionVariant );
DBGMSG( DBG_TRACE, ( "dwPrinterPropPages: printerObject vesrion %d.\n", versionVariant.lVal ) );
if( SUCCEEDED( hr ) && versionVariant.vt == VT_I4 && versionVariant.lVal >= 2 )
{
//
// At this point we know we will display some UI, either the dialog or an error message.
//
if( pbDisplayed )
{
*pbDisplayed = TRUE;
}
//
// Attempt to display the dialog.
//
dwReturn = dwPrinterPropPagesInternal( hwnd, Variant.bstrVal, 0, 0, SW_SHOW, FALSE, pszDsPath );
}
else
{
//
// If the caller has requested information as to wether we can display
// printer properties then indicate we cannot at this point, otherwise
// let the user know with a message box.
//
if( pbDisplayed )
{
dwReturn = ERROR_SUCCESS;
}
else
{
//
// Display an error message indicating that properties cannot be displayed.
//
iMessage( hwnd,
IDS_ERR_PRINTER_PROP_TITLE,
IDS_ERR_PRINTER_PROP_NONE,
MB_OK|MB_ICONSTOP,
kMsgNone,
NULL );
}
}
//
// Release the version variant.
//
VariantClear( &versionVariant );
}
//
// Release the variant.
//
VariantClear( &Variant );
}
}
//
// Note this routine could fail and still display UI.
// For example an an error message generated by printer properties
// because the thread could not start.
//
return dwReturn;
}
/********************************************************************
Private internal interface.
********************************************************************/
DWORD
dwPrinterPropPagesInternal(
IN HWND hwnd,
IN LPCTSTR pszPrinterName,
IN LPCTSTR pszSheetName,
IN DWORD dwSheetIndex,
IN INT nCmdShow,
IN BOOL bModal,
IN LPCTSTR pszDsPath
)
{
LPCTSTR pszServer;
LPCTSTR pszPrinter;
TCHAR szScratch[kPrinterBufMax];
//
// Split the printer name into its components.
//
vPrinterSplitFullName( szScratch,
ARRAYSIZE(szScratch),
pszPrinterName,
&pszServer,
&pszPrinter );
//
// Get the local machine name.
//
TString strMachineName;
TStatusB bStatus;
bStatus DBGCHK = bGetMachineName( strMachineName );
//
// If the server name matches this machine name then strip off the
// server name form the printer name, when creating the singleton window.
//
if( !_tcsicmp( pszServer, strMachineName ) ) {
pszPrinterName = pszPrinter;
}
TPrinterData* pPrinterData = new TPrinterData( pszPrinterName,
nCmdShow,
pszSheetName,
dwSheetIndex,
hwnd,
bModal,
pszDsPath );
if( !VALID_PTR( pPrinterData )){
goto Fail;
}
//
// If lparam is greater than 64k then dialog is modal.
//
if( bModal ) {
TPrinterProp::iPrinterPropPagesProc( pPrinterData );
return ERROR_SUCCESS;
}
//
// Create the thread which handles the UI. vPrinterPropPages adopts
// pPrinterData.
//
DWORD dwIgnore;
HANDLE hThread;
hThread = TSafeThread::Create( NULL,
0,
(LPTHREAD_START_ROUTINE)TPrinterProp::iPrinterPropPagesProc,
pPrinterData,
0,
&dwIgnore );
if( !hThread ){
goto Fail;
}
CloseHandle( hThread );
return ERROR_SUCCESS;
Fail:
if( !pPrinterData ){
vShowResourceError( hwnd );
} else {
iMessage( hwnd,
IDS_ERR_PRINTER_PROP_TITLE,
IDS_ERR_PRINTER_PROP,
MB_OK|MB_ICONSTOP,
kMsgGetLastError,
NULL );
}
delete pPrinterData;
return ERROR_ACCESS_DENIED;
}
/********************************************************************
Worker thread that handles printer properties.
********************************************************************/
INT
TPrinterProp::
iPrinterPropPagesProc(
IN TPrinterData* pPrinterData ADOPT
)
{
BOOL bStatus = FALSE;
INT Status = ERROR_SUCCESS;
//
// Register the link window class
//
if (LinkWindow_RegisterClass())
{
//
// We are going to use ole.
//
CoInitialize( NULL );
//
// Increment our reference count.
//
pPrinterData->vIncRef();
//
// Register this windows with the shell's unique window handler.
//
bStatus = pPrinterData->bRegisterWindow( PRINTER_PIDL_TYPE_PROPERTIES );
if( bStatus ){
//
// If the windows is already present.
//
if( pPrinterData->bIsWindowPresent() ){
DBGMSG( DBG_TRACE, ( "iPrinterPropPagesProc: currently running.\n" ) );
Status = ERROR_SUCCESS;
bStatus = FALSE;
}
}
if( bStatus ){
//
// Create the printer sheets and check if valid.
//
TPrinterPropertySheetManager *pPrinterSheets = new TPrinterPropertySheetManager( pPrinterData );
if( pPrinterSheets ) {
//
// Save the pointer to the property sheet manager.
//
pPrinterData->pPrinterPropertySheetManager() = pPrinterSheets;
//
// Check if we have a valid object.
//
if( VALID_PTR( pPrinterSheets )) {
//
// Note: Display Pages will show any errors message.
//
bStatus = pPrinterSheets->bDisplayPages();
} else {
vShowUnexpectedError( NULL, IDS_ERR_PRINTER_PROP_TITLE );
Status = GetLastError();
}
} else {
vShowUnexpectedError( NULL, IDS_ERR_PRINTER_PROP_TITLE );
Status = GetLastError();
}
}
//
// Ensure we release the printer data.
//
pPrinterData->cDecRef();
//
// Balance the CoInitalize
//
CoUninitialize();
//
// Unregister the link window class
//
LinkWindow_UnregisterClass(ghInst);
}
else
{
//
// unable to register the link window class - this is fatal, so we just bail
//
DBGMSG(DBG_WARN, ("LinkWindow_RegisterClass() failed - unable to register link window class\n"));
vShowResourceError(pPrinterData->hwnd());
}
return Status;
}
/********************************************************************
TPrinterData.
********************************************************************/
TPrinterData::
TPrinterData(
IN LPCTSTR pszPrinterName,
IN INT nCmdShow,
IN LPCTSTR pszSheetName,
IN DWORD dwSheetIndex,
IN HWND hwnd,
IN BOOL bModal,
IN LPCTSTR pszDsPath
) : MSingletonWin( pszPrinterName, hwnd, bModal ),
_pDevMode( NULL ),
_bNoAccess( FALSE ),
_bValid( FALSE ),
_bErrorSaving( FALSE ),
_uStartPage( dwSheetIndex ),
_pszServerName( NULL ),
_pPrinterPropertySheetManager( NULL ),
_hPrinter( NULL ),
_ePrinterPublishState( kUnInitalized ),
_dwAttributes( 0 ),
_dwPriority( 0 ),
_dwStartTime( 0 ),
_dwUntilTime( 0 ),
_dwStatus( 0 ),
_strStartPage( pszSheetName ),
_bIsFaxDriver( FALSE ),
_bHideSharingUI( FALSE ),
_strDsPath( pszDsPath ),
_eDsAvailableState( kDsUnInitalized ),
_uMaxActiveCount( 0 ),
_uActiveCount( 0 ),
_dwAction( 0 ),
_bGlobalDevMode( FALSE ),
_strSheetName( pszSheetName ),
_bDriverPagesNotLoaded( FALSE ),
_bApplyEnableState( TRUE ),
_bPooledPrinting( FALSE ),
_bServerFullAccess( FALSE ),
_hwndLastPageSelected( NULL )
{
DBGMSG( DBG_TRACE, ( "TPrinterData::ctor.\n" ) );
//
// Initialize the handle array.
//
memset( _hPages, 0, sizeof( _hPages ) );
//
// Initialize the page hwnd array.
//
memset ( _hwndPages, 0, sizeof( _hwndPages ) );
//
// Validate the singleton window.
//
_bValid = MSingletonWin::bValid() && _strDsPath.bValid();
//
// Check whether it is the default printer state
//
_bDefaultPrinter = CheckDefaultPrinter( pszPrinterName ) == kDefault;
}
TPrinterData::
~TPrinterData(
VOID
)
{
DBGMSG( DBG_TRACE, ( "TPrinterData::dtor.\n" ) );
//
// Release the printer property sheet manager.
//
delete _pPrinterPropertySheetManager;
//
// This may catch anyone trying to use the PropertySheetManager after destruction.
//
_pPrinterPropertySheetManager = NULL;
//
// Unload the printer data.
//
vUnload();
}
/*++
Routine Name:
bRefZeroed
Routine Description:
Called when the reference count drops to zero.
Arguments:
Nothing.
Return Value:
Nothing.
--*/
VOID
TPrinterData::
vRefZeroed(
VOID
)
{
DBGMSG( DBG_TRACE, ( "TPrinterData::vRefZeroed.\n" ) );
//
// Since we are reference counting the printer data object
// we know that it is safe to delete ourselves now.
//
delete this;
}
BOOL
TPrinterData::
bAdministrator(
VOID
)
{
return _dwAccess == PRINTER_ALL_ACCESS;
}
BOOL
TPrinterData::
bLoad(
VOID
)
/*++
Routine Description:
Load printer information. This call can fail because of access
denied, in which case only the security page should be added
to the propset.
Arguments:
Return Value:
--*/
{
//
// Retrieve icons.
//
LoadPrinterIcons(_strPrinterName, &_shLargeIcon, &_shSmallIcon);
SPLASSERT( _shLargeIcon );
SPLASSERT( _shSmallIcon );
//
// Open the printer.
//
TStatusB bStatus( DBG_WARN, ERROR_ACCESS_DENIED );
bStatus DBGNOCHK = FALSE;
PPRINTER_INFO_2 pInfo2 = NULL;
DWORD cbInfo2 = 0;
PPRINTER_INFO_7 pInfo7 = NULL;
DWORD cbInfo7 = 0;
PPRINTER_INFO_8 pInfo8 = NULL;
DWORD cbInfo8 = 0;
PPRINTER_INFO_9 pInfo9 = NULL;
DWORD cbInfo9 = 0;
TStatus Status( DBG_WARN );
_dwAccess = 0;
//
// Open the printer.
//
Status DBGCHK = TPrinter::sOpenPrinter( _strPrinterName,
&_dwAccess,
&_hPrinter );
if( Status ){
_hPrinter = NULL;
goto Fail;
}
//
// Gather the information.
//
bStatus DBGCHK = VDataRefresh::bGetPrinter( _hPrinter,
2,
(PVOID*)&pInfo2,
&cbInfo2 );
(VOID)_PrinterInfo.bUpdate( pInfo2 );
if( !bStatus ){
goto Fail;
}
//
// If we are loading global document default data.
//
if( _bGlobalDevMode )
{
//
// Get the global dev mode.
//
bStatus DBGCHK = VDataRefresh::bGetPrinter( _hPrinter, 8, (PVOID*)&pInfo8, &cbInfo8 );
if( bStatus )
{
DBGMSG( DBG_TRACE, ("Info level 8\n") );
pInfo2->pDevMode = pInfo8->pDevMode;
}
}
else
{
//
// Get the per user dev mode.
//
bStatus DBGCHK = VDataRefresh::bGetPrinter( _hPrinter, 9, (PVOID*)&pInfo9, &cbInfo9 );
if( bStatus )
{
DBGMSG( DBG_TRACE, ("Info level 9\n") );
pInfo2->pDevMode = pInfo9->pDevMode;
}
//
// Ignore failure here, this allows printer properties
// to work on a downlevel machine.
//
else
{
bStatus DBGNOCHK = TRUE;
}
}
//
// Make a copy of the devmode.
//
if( pInfo2->pDevMode ){
COUNTB cbDevMode = pInfo2->pDevMode->dmSize + pInfo2->pDevMode->dmDriverExtra;
_pDevMode = (PDEVMODE)AllocMem( cbDevMode );
if( !_pDevMode ){
DBGMSG( DBG_WARN, ( "PrinterData.bLoad: failed to alloc dm %d: %d\n", cbDevMode, GetLastError( )));
bStatus DBGNOCHK = FALSE;
goto Fail;
}
CopyMemory( _pDevMode, pInfo2->pDevMode, cbDevMode );
}
_dwAttributes = pInfo2->Attributes;
_dwPriority = pInfo2->Priority;
_dwStartTime = pInfo2->StartTime;
_dwUntilTime = pInfo2->UntilTime;
_dwStatus = pInfo2->Status;
//
// Run through printer_info_2.
// Check strings for allocation.
//
if( !_strPrinterName.bUpdate( pInfo2->pPrinterName ) ||
!_strCurrentPrinterName.bUpdate( _strPrinterName ) ||
!_strServerName.bUpdate( pInfo2->pServerName ) ||
!_strShareName.bUpdate( pInfo2->pShareName ) ||
!_strDriverName.bUpdate( pInfo2->pDriverName ) ||
!_strComment.bUpdate( pInfo2->pComment ) ||
!_strLocation.bUpdate( pInfo2->pLocation ) ||
!_strPortName.bUpdate( pInfo2->pPortName ) ||
!_strSepFile.bUpdate( pInfo2->pSepFile ) ||
!_strPrintProcessor.bUpdate( pInfo2->pPrintProcessor ) ||
!_strDatatype.bUpdate( pInfo2->pDatatype )){
DBGMSG( DBG_WARN, ( "PrinterProp.bLoad: String update failed %x %d\n", this, GetLastError( )));
bStatus DBGNOCHK = FALSE;
}
//
// check whether pool printing is enabled
//
_bPooledPrinting = _PrinterInfo._bPooledPrinting;
//
// Make a pointer to the server name. A Null pointer
// indicates the local machine.
//
if( _strServerName.bEmpty() ){
_pszServerName = NULL;
} else {
_pszServerName = (LPCTSTR)_strServerName;
}
//
// Get the current environment string and version number.
//
if( !bGetCurrentDriver( _strServerName, &_dwDriverVersion ) ||
!bGetDriverEnv( _dwDriverVersion, _strDriverEnv ) ){
DBGMSG( DBG_WARN, ( "Get Driver version and environment failed.\n" ) );
bStatus DBGNOCHK = FALSE;
goto Fail;
}
DBGMSG( DBG_TRACE, ( "Driver Version %d Environment " TSTR "\n", _dwDriverVersion, (LPCTSTR)_strDriverEnv ) );
if( bStatus )
{
//
// Get special information about this print queue.
//
vGetSpecialInformation();
//
// Get the current DS printer state.
//
bStatus DBGNOCHK = VDataRefresh::bGetPrinter( _hPrinter,
7,
(PVOID*)&pInfo7,
&cbInfo7 );
if( bStatus )
{
DBGMSG( DBG_TRACE, ("Info level 7 dwAction %x\n", pInfo7->dwAction ) );
(VOID)_PrinterInfo.bUpdate( pInfo7 );
bStatus DBGCHK = _strObjectGUID.bUpdate( pInfo7->pszObjectGUID );
_dwAction = pInfo7->dwAction;
}
//
// We do not fail the bLoad if we cannont get the info level 7 data.
// This is necessary to support the downlevel case.
//
bStatus DBGNOCHK = TRUE;
}
if( bStatus )
{
//
// Check whether the user has full priviledge to access the server, the return value
// will be used when we are trying to install a printer driver
//
HANDLE hPrinter = NULL;
DWORD dwAccess = SERVER_ALL_ACCESS;
//
// Open the printer.
//
TPrinter::sOpenPrinter( _strServerName,
&dwAccess,
&hPrinter );
_bServerFullAccess = hPrinter ? TRUE : FALSE;
if( hPrinter )
{
ClosePrinter( hPrinter );
}
}
Fail:
FreeMem( pInfo2 );
FreeMem( pInfo7 );
FreeMem( pInfo8 );
FreeMem( pInfo9 );
//
// If we've failed because access was denied, then return
// success but set the bNoAccess flag. This allows the
// user to see the security tab.
//
if( !bStatus && ERROR_ACCESS_DENIED == GetLastError( )){
_bNoAccess = TRUE;
return TRUE;
}
return bStatus;
}
VOID
TPrinterData::
vUnload(
VOID
)
/*++
Routine Description:
Free associated data in this, so that this can be freed or
loaded again.
Arguments:
Return Value:
--*/
{
DBGMSG( DBG_TRACE, ( "TPrinterData::vUnload.\n" ) );
//
// Release the deve mode.
//
FreeMem( _pDevMode );
_pDevMode = NULL;
//
// Close the printer
//
if( _hPrinter ){
ClosePrinter( _hPrinter );
_hPrinter = NULL;
}
}
BOOL
TPrinterData::
bSave(
BOOL bUpdateDevMode
)
/*++
Routine Description:
Save the data store in this.
Arguments:
bUpdateDevmode flag indicates we should update the devmode.
Return Value:
TRUE success, FLASE error occurred.
--*/
{
//
// If bErrorSaving is set, then somewhere we had an error reading
// from the dialogs. This should be very rare.
//
if( bErrorSaving( ))
{
//
// Tell the user that we can't save the dialogs.
// Then just exit?
//
return FALSE;
}
//
// Display the wait cursor setprinter may take awhile
//
TWaitCursor Cursor;
//
// Setup the INFO_2 structure. First read it, modify it, then
// free it.
//
TStatusB bStatus;
bStatus DBGNOCHK = TRUE;
//
// If we are updating the devmode.
//
if( bUpdateDevMode )
{
//
// If we are updating the global devmode.
//
if( _bGlobalDevMode )
{
return bUpdateGlobalDevMode();
}
else
{
return bUpdatePerUserDevMode();
}
}
//
// If a printer info 2 change occurred do a set printer.
//
if( bCheckForChange( 2 ) )
{
TString strNewName, strTemp;
BOOL bDriverHasChanged = FALSE;
PPRINTER_INFO_2 pInfo2 = NULL;
DWORD cbInfo2 = 0;
bStatus DBGCHK = VDataRefresh::bGetPrinter( _hPrinter, 2, (PVOID*)&pInfo2, &cbInfo2 );
if( bStatus )
{
// assume the default printer name
strNewName.bUpdate(_strPrinterName);
//
// Check if the driver has changed. If the driver has chaned then
// the printer name may have to change if the current printer name
// is a generated name i.e. similar to the driver name.
//
if( _tcsicmp( _strDriverName, _PrinterInfo._strDriverName ) )
{
//
// Indicate the driver changed.
//
bDriverHasChanged = TRUE;
//
// Turn on BIDI since the spooler enables this if a
// language monitor is present. If it isn't it will
// be ignored by the spooler.
//
_dwAttributes |= PRINTER_ATTRIBUTE_ENABLE_BIDI;
//
// Update the printer name if neccessary.
//
bStatus DBGCHK = bDriverChangedGenPrinterName(&strNewName);
}
//
// If the attributes indicate to allways spool raw then the
// datatype must also be raw else the printe will not print.
//
if( _dwAttributes & PRINTER_ATTRIBUTE_RAW_ONLY )
{
DBGMSG( DBG_TRACE, ( "Forcing datatype to raw.\n" ) );
_strDatatype.bUpdate( _T("RAW") );
}
//
// Transfer pPrinterData to pInfo2.
//
pInfo2->pPrinterName = (LPTSTR)pGetAdjustedPrinterName(
static_cast<LPCTSTR>(strNewName),
strTemp);
pInfo2->pShareName = (LPTSTR)(LPCTSTR)_strShareName;
pInfo2->pDriverName = (LPTSTR)(LPCTSTR)_strDriverName;
pInfo2->pComment = (LPTSTR)(LPCTSTR)_strComment;
pInfo2->pLocation = (LPTSTR)(LPCTSTR)_strLocation;
pInfo2->pPortName = (LPTSTR)(LPCTSTR)_strPortName;
pInfo2->pSepFile = (LPTSTR)(LPCTSTR)_strSepFile;
pInfo2->pPrintProcessor = (LPTSTR)(LPCTSTR)_strPrintProcessor;
pInfo2->pDatatype = (LPTSTR)(LPCTSTR)_strDatatype;
pInfo2->Attributes = _dwAttributes;
pInfo2->Priority = _dwPriority;
pInfo2->StartTime = _dwStartTime;
pInfo2->UntilTime = _dwUntilTime;
//
// Another piece of trivia: the security descriptor must be set
// to NULL since it might not be the owner.
//
pInfo2->pSecurityDescriptor = NULL;
if( bStatus )
{
//
// Set the printer information.
//
bStatus DBGCHK = SetPrinter( _hPrinter, 2, (PBYTE)pInfo2, 0 );
}
//
// Update the _strCurrentPrinterName here because it is needed
// to updated before calling bRefreshDriverPages() below.
//
if( bStatus )
{
//
// Update the local printer info 2 copy ( needed for the apply button )
//
_PrinterInfo.bUpdate( pInfo2 );
_bPooledPrinting = _PrinterInfo._bPooledPrinting;
_strCurrentPrinterName.bUpdate( pInfo2->pPrinterName );
_strPrinterName.bUpdate( pInfo2->pPrinterName );
}
//
// Reload the driver pages.
//
if( bStatus && bDriverHasChanged )
{
//
// We are about to insert/remove the dynamic pages - these are
// the driver pages + shell extension pages, so we need to check
// if we are currently in one of them. If we are, then we have to
// switch to one of the static pages. It is not mandatory to switch
// to the General page one, but it seems reasonable.
//
HWND hwndCurPage = PropSheet_GetCurrentPageHwnd(
pPrinterPropertySheetManager()->hGetParentHandle() );
if( _hwndLastPageSelected != hwndCurPage )
{
//
// If we are currently in one of the dynamic pages just switch to the
// general page.
//
PropSheet_SetCurSel( pPrinterPropertySheetManager()->hGetParentHandle(), NULL, 0 );
}
//
// Turn on BIDI bit if it's needed. Update all the dwAttributes members
// simultaneousely because otherwise the logic which enable/disable the
// Apply button will be broken.
//
if( bSupportBidi() )
{
_dwAttributes |= PRINTER_ATTRIBUTE_ENABLE_BIDI;
pInfo2->Attributes |= PRINTER_ATTRIBUTE_ENABLE_BIDI;
_PrinterInfo._dwAttributes |= PRINTER_ATTRIBUTE_ENABLE_BIDI;
}
else
{
_dwAttributes &= ~PRINTER_ATTRIBUTE_ENABLE_BIDI;
pInfo2->Attributes &= ~PRINTER_ATTRIBUTE_ENABLE_BIDI;
_PrinterInfo._dwAttributes &= ~PRINTER_ATTRIBUTE_ENABLE_BIDI;
}
//
// Reload the driver pages.
//
bStatus DBGCHK = _pPrinterPropertySheetManager->bRefreshDriverPages();
//
// If the driver pages were loaded then, set the new title.
//
if( bStatus )
{
_pPrinterPropertySheetManager->vRefreshTitle();
}
//
// Recalc the property sheet size in case of
// monolitic drivers insert a pages with
// a non-standard size
//
PropSheet_RecalcPageSizes( pPrinterPropertySheetManager()->hGetParentHandle() );
}
}
FreeMem( pInfo2 );
}
//
// Update the DS properties if needed
//
if( bStatus && bCheckForChange( 7 ) && bIsDsAvailable() )
{
PPRINTER_INFO_7 pInfo7 = NULL;
DWORD cbInfo7 = 0;
bStatus DBGCHK = VDataRefresh::bGetPrinter( _hPrinter, 7, (PVOID*)&pInfo7, &cbInfo7 );
if( bStatus )
{
//
// If we need to publish this printer into the directory.
//
switch ( ePrinterPublishState() )
{
case kPublish:
if( _dwAttributes & PRINTER_ATTRIBUTE_SHARED )
{
DBGMSG( DBG_TRACE, ( "Publish printer - Publish.\n" ) );
pInfo7->dwAction = DSPRINT_PUBLISH;
bStatus DBGCHK = SetPrinter( _hPrinter, 7, (PBYTE)pInfo7, 0 );
}
break;
case kUnPublish:
{
DBGMSG( DBG_TRACE, ( "Publish printer - UnPublish.\n" ) );
pInfo7->dwAction = DSPRINT_UNPUBLISH;
bStatus DBGCHK = SetPrinter( _hPrinter, 7, (PBYTE)pInfo7, 0 );
}
break;
default:
DBGMSG( DBG_TRACE, ( "Publish printer - NoAction.\n" ) );
break;
}
//
// If set printer failed with an any error remap the error
// to a DS friendly message. If the error is io pending the spooler
// will publish in the background therefore we will silently fail.
//
if( !bStatus )
{
DBGMSG( DBG_TRACE, ( "SetPrinter Info 7 returned %d with %d\n", bStatus, GetLastError() ) );
if( GetLastError() == ERROR_IO_PENDING )
{
bStatus DBGNOCHK = TRUE;
pInfo7->dwAction |= DSPRINT_PENDING;
_dwAction |= DSPRINT_PENDING;
}
else
{
SetLastError( ERROR_IO_PENDING );
}
}
else
{
//
// Set printer info 7 succeede with out an error, then clear
// the pending status indicator bit in both our copy and
// the previous copy.
//
pInfo7->dwAction &= ~DSPRINT_PENDING;
_dwAction &= ~DSPRINT_PENDING;
}
if( bStatus )
{
//
// Update the local printer info 7 copy ( needed for the apply button )
//
_PrinterInfo.bUpdate( pInfo7 );
}
FreeMem( pInfo7 );
}
}
return bStatus;
}
LPCTSTR
TPrinterData::
pGetAdjustedPrinterName(
IN LPCTSTR pszPrinterName,
OUT TString &strTempPrinterName
) const
/*++
Routine Description:
This routine adjusts the printer name in the case of a masq printer or a
network printer. If the printer is a msaq printer or a network printer we must
retain the current server name part of the name. Preserving the name is necessary
for the masq printer in order to continue displaying the masq printer
as a network connection. The print folder code looks at the leading \\ to determine
if the printer should be displayed as a network printer, it does this because
reading the printers attributes is slow.
Arguments:
Temp buffer where to store the new printer name, if this is a masq printer.
Return Value:
Pointer to the adjusted printer name. The name is not modified if this printer
is not a masq printer.
--*/
{
TStatusB bStatus;
// if this is a masq printer do not change the name.
if( _dwAttributes & PRINTER_ATTRIBUTE_NETWORK && _dwAttributes & PRINTER_ATTRIBUTE_LOCAL )
{
bStatus DBGCHK = strTempPrinterName.bUpdate(_strCurrentPrinterName);
}
else if( _dwAttributes & PRINTER_ATTRIBUTE_NETWORK )
{
// if this is a network printer then preserve the server name part of the name.
LPCTSTR pszServer1 = NULL, pszPrinter1 = NULL;
TCHAR szScratch1[kPrinterBufMax];
LPCTSTR pszServer2 = NULL, pszPrinter2 = NULL;
TCHAR szScratch2[kPrinterBufMax];
// split the printer names into their components.
vPrinterSplitFullName(szScratch1, ARRAYSIZE(szScratch1), _strCurrentPrinterName, &pszServer1, &pszPrinter1);
vPrinterSplitFullName(szScratch2, ARRAYSIZE(szScratch2), pszPrinterName, &pszServer2, &pszPrinter2);
// if we have wacks in the printer name then it's either an
// invalid printer name or it's a connection to a masq printer
// in which case we must revert to the original printer name.
if( pszServer2 && _tcslen(pszServer2) )
{
bStatus DBGCHK = strTempPrinterName.bUpdate(_strCurrentPrinterName);
}
else
{
bStatus DBGCHK = strTempPrinterName.bUpdate(pszServer1) &&
strTempPrinterName.bCat(gszWack) &&
strTempPrinterName.bCat(pszPrinter2);
}
}
else
{
// normal local printer, i.e. not a masq local printer then just use the name as is.
bStatus DBGCHK = strTempPrinterName.bUpdate(pszPrinterName);
}
return strTempPrinterName;
}
BOOL
TPrinterData::
bDriverChangedGenPrinterName(
TString *pstrNewName
) const
/*++
Routine Description:
bDriverChangedGenPrinterName
Arguments:
pstrNewName - pointer where to put the new name.
Return Value:
TRUE success, FALSE failure.
--*/
{
TStatusB bStatus;
ASSERT(pstrNewName);
//
// Check if the printer name should change. We change the printer name if
// the driver name is a sub string of the current printer name, and it is
// not a remote printer connection. There is not an explicit check if it
// is a remote printer connection since a remote printer connection will have
// the \\machine\printer name and therefore will never match.
//
if( !_tcsnicmp( _strPrinterName, _PrinterInfo._strDriverName, _tcslen( _PrinterInfo._strDriverName ) ) )
{
TCHAR szNewName[kPrinterBufMax];
//
// Create a new unique printer name.
//
if( NewFriendlyName( static_cast<LPCTSTR>( _strServerName ),
const_cast<LPTSTR>( static_cast<LPCTSTR>( _strDriverName ) ),
szNewName, ARRAYSIZE(szNewName) ) )
{
bStatus DBGCHK = pstrNewName->bUpdate( szNewName );
}
else
{
//
// if NewFriendlyName fails that means the passed name is
// unique itself. i.e. in this case just use the passed
// name (the newly selected driver name)
//
bStatus DBGCHK = pstrNewName->bUpdate( _strDriverName );
}
}
//
// we didn't really updated the name - the default would be
// to use user's choice - i.e. _strPrinterName
//
if( 0 == pstrNewName->uLen() )
{
bStatus DBGCHK = pstrNewName->bUpdate( _strPrinterName );
}
else
{
bStatus DBGCHK = TRUE;
}
return bStatus;
}
BOOL
TPrinterData::
bSupportBidi(
VOID
)
/*++
Routine Description:
Check whether the current printer supports bidi. Assumes there
is a valid hPrinter available.
Note: this returns false if it can't make the determination.
Arguments:
Return Value:
TRUE - Bidi supported.
FALSE - Failed or bidi not supported.
--*/
{
BOOL bSupport = FALSE;
PDRIVER_INFO_3 pInfo3 = NULL;
DWORD dwInfo3 = 0;
//
// Get the printer driver information.
//
if( VDataRefresh::bGetPrinterDriver( _hPrinter,
(LPTSTR)(LPCTSTR)_strDriverEnv,
3,
(PVOID*)&pInfo3,
&dwInfo3 )){
bSupport = pInfo3->pMonitorName && pInfo3->pMonitorName[0];
FreeMem( pInfo3 );
}
return bSupport;
}
TPrinterData::EPublishState
TPrinterData::
ePrinterPublishState(
TPrinterData::EPublishState eNewPublishState
)
/*++
Routine Description:
Sets and Gets the publish state.
Arguments:
None
Return Value:
The current publish state.
--*/
{
//
// If the publish state is being set.
//
if( eNewPublishState != kUnInitalized )
{
_ePrinterPublishState = eNewPublishState;
}
else
{
//
// If the printer publish state has not been initialized.
//
if( _ePrinterPublishState == kUnInitalized )
{
//
// If we are talking to a downlevel server the ds is not available.
//
if( ( GetDriverVersion( _dwDriverVersion ) > 2 ) && bIsDsAvailable( ) )
{
if( ( _dwAction & DSPRINT_PUBLISH ) || ( _dwAction & DSPRINT_UPDATE ) )
{
_ePrinterPublishState = kPublished;
}
else
{
_ePrinterPublishState = kNotPublished;
}
}
else
{
_ePrinterPublishState = kNoDsAvailable;
}
}
}
return _ePrinterPublishState;
}
BOOL
TPrinterData::
bIsDsAvailable(
VOID
)
/*++
Routine Description:
Sets and Gets the publish state.
Arguments:
None
Return Value:
The current publish state.
--*/
{
if( _eDsAvailableState == kDsUnInitalized )
{
//
// Display the wait cursor the DS may take a long time to respond.
//
TWaitCursor Cursor;
TDirectoryService ds;
_eDsAvailableState = ds.bIsDsAvailable(_strServerName) ? kDsAvailable : kDsNotAvailable;
}
return _eDsAvailableState == kDsAvailable;
}
BOOL
TPrinterData::
bCheckForChange(
IN UINT uLevel
)
/*++
Routine Description:
Checkes the data set if it has changed.
Arguments:
None
Return Value:
TRUE data has changed, FALSE data is the same.
--*/
{
DBGMSG( DBG_TRACE, ( "TPrinterData::bCheckForChange\n" ) );
//
// If we are not an administrator nothing should change
// This is a performance optimization, when the user
// is just looking at the printer.
//
if( !bAdministrator() )
{
return FALSE;
}
BOOL bStatus = FALSE;
//
// Assume the data is different.
//
if( !bStatus && uLevel == -1 || uLevel == 2 )
{
//
// We check all values with a case sensitive check. The spooler
// can determine if upper and lower case characters warrent
// a printer change event.
//
if( !_tcscmp( _strServerName, _PrinterInfo._strServerName ) &&
!ComparePrinterName( _strPrinterName, _PrinterInfo._strPrinterName ) &&
!_tcscmp( _strDriverName, _PrinterInfo._strDriverName ) &&
!_tcscmp( _strComment, _PrinterInfo._strComment ) &&
!_tcscmp( _strLocation, _PrinterInfo._strLocation ) &&
!_tcscmp( _strPortName, _PrinterInfo._strPortName ) &&
!_tcscmp( _strSepFile, _PrinterInfo._strSepFile ) &&
!_tcscmp( _strPrintProcessor, _PrinterInfo._strPrintProcessor ) &&
!_tcscmp( _strDatatype, _PrinterInfo._strDatatype ) &&
_dwAttributes == _PrinterInfo._dwAttributes &&
_dwPriority == _PrinterInfo._dwPriority &&
_dwStartTime == _PrinterInfo._dwStartTime &&
_dwUntilTime == _PrinterInfo._dwUntilTime &&
_bPooledPrinting == _PrinterInfo._bPooledPrinting )
{
//
// Ignore the printer share name if not shared.
//
if( uLevel == 2 || _dwAttributes & PRINTER_ATTRIBUTE_SHARED )
{
bStatus = _tcscmp( _strShareName, _PrinterInfo._strShareName );
}
}
else
{
bStatus = TRUE;
}
}
//
// If the data is the same and it is our level
// then check if the data is different.
//
if( !bStatus && uLevel == -1 || uLevel == 7 )
{
//
// Ignore the DS action if not shared.
//
if( uLevel == 7 || _dwAttributes & PRINTER_ATTRIBUTE_SHARED )
{
//
// Ignore the ds pending bit.
//
if( ( _dwAction & ~DSPRINT_PENDING ) == ( _PrinterInfo._dwAction & ~DSPRINT_PENDING ) )
{
bStatus = FALSE;
}
else
{
bStatus = TRUE;
}
}
}
#if DBG
if( bStatus )
DBGMSG( DBG_TRACE, ("Item changed:\n" ));
if( _tcscmp( _strServerName, _PrinterInfo._strServerName ) )
DBGMSG( DBG_TRACE, ("ServerName: "TSTR " " TSTR "\n", (LPCTSTR)_strServerName, (LPCTSTR)_PrinterInfo._strServerName ));
if( ComparePrinterName( _strPrinterName, _PrinterInfo._strPrinterName ) )
DBGMSG( DBG_TRACE, ("PrinterName: "TSTR " " TSTR "\n", (LPCTSTR)_strPrinterName, (LPCTSTR)_PrinterInfo._strPrinterName ));
if( _tcscmp( _strShareName, _PrinterInfo._strShareName ) )
DBGMSG( DBG_TRACE, ("ShareName: "TSTR " " TSTR "\n", (LPCTSTR)_strShareName, (LPCTSTR)_PrinterInfo._strShareName ));
if( _tcscmp( _strDriverName, _PrinterInfo._strDriverName ) )
DBGMSG( DBG_TRACE, ("DriverName: "TSTR " " TSTR "\n", (LPCTSTR)_strDriverName, (LPCTSTR)_PrinterInfo._strDriverName ));
if( _tcscmp( _strComment, _PrinterInfo._strComment ) )
DBGMSG( DBG_TRACE, ("CommentName: "TSTR " " TSTR "\n", (LPCTSTR)_strComment, (LPCTSTR)_PrinterInfo._strComment ));
if( _tcscmp( _strLocation, _PrinterInfo._strLocation ) )
DBGMSG( DBG_TRACE, ("LocationName: "TSTR " " TSTR "\n", (LPCTSTR)_strLocation, (LPCTSTR)_PrinterInfo._strLocation ));
if( _tcscmp( _strPortName, _PrinterInfo._strPortName ) )
DBGMSG( DBG_TRACE, ("PortName: "TSTR " " TSTR "\n", (LPCTSTR)_strPortName, (LPCTSTR)_PrinterInfo._strPortName ));
if( _tcscmp( _strSepFile, _PrinterInfo._strSepFile ) )
DBGMSG( DBG_TRACE, ("SepFile: "TSTR " " TSTR "\n", (LPCTSTR)_strSepFile, (LPCTSTR)_PrinterInfo._strSepFile ));
if( _tcscmp( _strDatatype, _PrinterInfo._strDatatype ) )
DBGMSG( DBG_TRACE, ("Datatype: "TSTR " " TSTR "\n", (LPCTSTR)_strDatatype, (LPCTSTR)_PrinterInfo._strDatatype ));
if( _tcscmp( _strPrintProcessor, _PrinterInfo._strPrintProcessor ) )
DBGMSG( DBG_TRACE, ("PrintProcessor: "TSTR " " TSTR "\n", (LPCTSTR)_strPrintProcessor, (LPCTSTR)_PrinterInfo._strPrintProcessor ));
if( _dwAttributes != _PrinterInfo._dwAttributes )
DBGMSG( DBG_TRACE, ("Attributes: %x %x\n", _dwAttributes, _PrinterInfo._dwAttributes ));
if( _dwPriority != _PrinterInfo._dwPriority )
DBGMSG( DBG_TRACE, ("Priority: %d %d\n", _dwPriority, _PrinterInfo._dwPriority ));
if( _dwStartTime != _PrinterInfo._dwStartTime )
DBGMSG( DBG_TRACE, ("StartTime: %d %d\n", _dwStartTime, _PrinterInfo._dwStartTime ));
if( _dwUntilTime != _PrinterInfo._dwUntilTime )
DBGMSG( DBG_TRACE, ("UntilTime: %d %d\n", _dwUntilTime, _PrinterInfo._dwUntilTime ));
if( _dwAction != _PrinterInfo._dwAction )
DBGMSG( DBG_TRACE, ("DsAction: %x %x\n", _dwAction, _PrinterInfo._dwAction ));
#endif
return bStatus;
}
INT
TPrinterData::
ComparePrinterName(
IN LPCTSTR pszPrinterName1,
IN LPCTSTR pszPrinterName2
)
/*++
Routine Description:
Compare printer name 1 to printer name 2. This routine will
strip the server name and any leading wacks when the comparison
is done.
Arguments:
pszPrinterName1 - Pointer to printer name string (can be fully qualified)
pszPrinterName2 - Pointer to printer name string (can be fully qualified)
Return Value:
1 Printer name 1 is greater than printer name 2
0 Printer name 1 and printer name 2 are equal.
-1 Printer name 1 is less than printer name 2
--*/
{
SPLASSERT( pszPrinterName1 );
SPLASSERT( pszPrinterName2 );
LPCTSTR pszServer1;
LPCTSTR pszPrinter1;
TCHAR szScratch1[kPrinterBufMax];
LPCTSTR pszServer2;
LPCTSTR pszPrinter2;
TCHAR szScratch2[kPrinterBufMax];
//
// Split the printer names into their components.
//
vPrinterSplitFullName( szScratch1, ARRAYSIZE(szScratch1), pszPrinterName1, &pszServer1, &pszPrinter1 );
vPrinterSplitFullName( szScratch2, ARRAYSIZE(szScratch2), pszPrinterName2, &pszServer2, &pszPrinter2 );
//
// Assume not equal.
//
INT iRetval = 1;
if( pszPrinter1 && pszPrinter2 )
{
iRetval = _tcscmp( pszPrinter1, pszPrinter2 );
}
return iRetval;
}
BOOL
TPrinterData::
bUpdateGlobalDevMode(
VOID
)
/*++
Routine Description:
Updates the global devmode using printer info 8.
Arguments:
None
Return Value:
TRUE data devmode updated, FALSE error occurred.
--*/
{
DBGMSG( DBG_TRACE, ( "TPrinterData::bUpdateGlobalDevMode\n" ) );
SPLASSERT( _pDevMode );
PRINTER_INFO_8 Info8 = {0};
DWORD cbInfo8 = 0;
TStatusB bStatus;
//
// Set the devmode in the printer info 8 structure.
//
Info8.pDevMode = _pDevMode;
//
// Set the global dev mode.
//
bStatus DBGCHK = SetPrinter( _hPrinter, 8, (PBYTE)&Info8, 0 );
return bStatus;
}
BOOL
TPrinterData::
bUpdatePerUserDevMode(
VOID
)
/*++
Routine Description:
Updates the global devmode using printer info 8.
Arguments:
None
Return Value:
TRUE data devmode updated, FALSE error occurred.
--*/
{
DBGMSG( DBG_TRACE, ( "TPrinterData::bUpdatePerUserDevMode\n" ) );
SPLASSERT( _pDevMode );
PRINTER_INFO_9 Info9 = {0};
DWORD cbInfo9 = 0;
TStatusB bStatus;
//
// Set the devmode in the printer info 8 structure.
//
Info9.pDevMode = _pDevMode;
//
// Set the global dev mode.
//
bStatus DBGCHK = SetPrinter( _hPrinter, 9, (PBYTE)&Info9, 0 );
return bStatus;
}
VOID
TPrinterData::
vGetSpecialInformation(
VOID
)
/*++
Routine Description:
Checked if this device is a fax printer, we read server
registry key to see if we should display the sharing UI
for this device.
Arguments:
None
Return Value:
Nothing.
--*/
{
DBGMSG( DBG_TRACE, ( "TPrinterData::vGetSpecialInformation\n" ) );
if( !_tcscmp( _strDriverName, FAX_DRIVER_NAME ) )
{
TStatusB bStatus;
//
// Save the fact this is a Fax printer.
//
_bIsFaxDriver = TRUE;
//
// Create the printer data access class.
//
TPrinterDataAccess Data( _strServerName, TPrinterDataAccess::kResourceServer, TPrinterDataAccess::kAccessRead );
//
// Relax the return type checking, the spooler just cannot get it right.
//
Data.RelaxReturnTypeCheck( TRUE );
//
// Initialize the data class.
//
bStatus DBGCHK = Data.Init();
if( bStatus )
{
//
// Assume remote fax is disabled.
//
DWORD dwRemoteFax = 1;
HRESULT hr = Data.Get( SPLREG_REMOTE_FAX, dwRemoteFax );
if( SUCCEEDED(hr) )
{
DBGMSG( DBG_TRACE, ( "TPrinterData::vGetSpecialInformation - RemoteFax %x\n" , dwRemoteFax ) );
_bHideSharingUI = dwRemoteFax ? FALSE : TRUE;
}
}
}
//
// If the printer is a masq printer connected to an http port then hide the sharingUI.
//
if( !_bHideSharingUI )
{
if( (dwAttributes() & PRINTER_ATTRIBUTE_LOCAL) && (dwAttributes() & PRINTER_ATTRIBUTE_NETWORK) )
{
_bHideSharingUI = !_tcsnicmp( _strPortName, gszHttpPrefix0, _tcslen(gszHttpPrefix0) ) ||
!_tcsnicmp( _strPortName, gszHttpPrefix1, _tcslen(gszHttpPrefix1) );
}
}
}
/********************************************************************
Printer info data classes.
********************************************************************/
TPrinterData::TPrinterInfo::
TPrinterInfo(
VOID
) : _dwAttributes( 0 ),
_dwPriority( 0 ),
_dwStartTime( 0 ),
_dwUntilTime( 0 ),
_dwAction( 0 ),
_bPooledPrinting( FALSE )
{
DBGMSG( DBG_TRACE, ( "TPrinterData::TPrinterInfo ctor\n" ) );
}
TPrinterData::TPrinterInfo::
~TPrinterInfo(
VOID
)
{
DBGMSG( DBG_TRACE, ( "TPrinterData::TPrinterInfo dtor\n" ) );
}
BOOL
TPrinterData::TPrinterInfo::
bUpdate(
IN PPRINTER_INFO_2 pInfo
)
{
DBGMSG( DBG_TRACE, ( "TPrinterData::TPrinterInfo::bUpdate 2\n" ) );
TStatusB bStatus;
bStatus DBGNOCHK = FALSE;
if( pInfo )
{
bStatus DBGCHK = _strServerName.bUpdate( pInfo->pServerName ) &&
_strPrinterName.bUpdate( pInfo->pPrinterName ) &&
_strShareName.bUpdate( pInfo->pShareName ) &&
_strDriverName.bUpdate( pInfo->pDriverName ) &&
_strComment.bUpdate( pInfo->pComment ) &&
_strLocation.bUpdate( pInfo->pLocation ) &&
_strPortName.bUpdate( pInfo->pPortName ) &&
_strSepFile.bUpdate( pInfo->pSepFile ) &&
_strPrintProcessor.bUpdate( pInfo->pPrintProcessor ) &&
_strDatatype.bUpdate( pInfo->pDatatype );
//
// check whether pool printing is enabled
//
if( _tcschr( pInfo->pPortName, TEXT( ',' ) ) )
{
_bPooledPrinting = TRUE;
}
else
{
_bPooledPrinting = FALSE;
}
_dwAttributes = pInfo->Attributes;
_dwPriority = pInfo->Priority;
_dwStartTime = pInfo->StartTime;
_dwUntilTime = pInfo->UntilTime;
}
return bStatus;
}
BOOL
TPrinterData::TPrinterInfo::
bUpdate(
IN PPRINTER_INFO_7 pInfo
)
{
DBGMSG( DBG_TRACE, ( "TPrinterData::TPrinterInfo::bUpdate 7\n" ) );
TStatusB bStatus;
bStatus DBGNOCHK = FALSE;
if( pInfo )
{
bStatus DBGCHK = _strObjectGUID.bUpdate( pInfo->pszObjectGUID );
_dwAction = pInfo->dwAction;
}
return bStatus;
}
/********************************************************************
Printer property base class for generic services to
all property pages.
********************************************************************/
TPrinterProp::
TPrinterProp(
TPrinterData* pPrinterData
) : _pPrinterData( pPrinterData )
{
}
VOID
TPrinterProp::
vSetIconName(
VOID
)
/*++
Routine Description:
Sets the printer icon to the custom one.
Arguments:
hDlg - Modifies this dialog.
Return Value:
--*/
{
//
// Set the correct icon; destroy the previous one.
//
SendDlgItemMessage(_hDlg, IDC_PRINTER_ICON, STM_SETICON, (WPARAM)(HICON)_pPrinterData->shLargeIcon(), 0);
LPCTSTR pszServer;
LPCTSTR pszPrinter;
TCHAR szScratch[kPrinterBufMax];
//
// Split the printer name into its components.
//
vPrinterSplitFullName( szScratch,
ARRAYSIZE(szScratch),
_pPrinterData->strPrinterName( ),
&pszServer,
&pszPrinter );
//
// Set the printer name.
//
bSetEditText( _hDlg, IDC_NAME, pszPrinter );
}
VOID
TPrinterProp::
vReloadPages(
VOID
)
/*++
Routine Description:
Something changed (driver or security etc.) so we need to completely
refresh all printer pages.
Arguments:
None.
Return Value:
Nothing
Comments:
This is currently not implemented.
--*/
{
}
BOOL
TPrinterProp::
bHandleMessage(
IN UINT uMsg,
IN WPARAM wParam,
IN LPARAM lParam
)
/*++
Routine Description:
Front end for each sheets message handler.
Arguments:
uMsg - Window message
wParam - wParam
lParam - lParam
Return Value:
TRUE message handled, FALSE message not handled.
--*/
{
BOOL bStatus = TRUE;
switch( uMsg )
{
case WM_INITDIALOG:
bStatus = bHandle_InitDialog( wParam, lParam );
break;
case WM_NOTIFY:
bStatus = bHandle_Notify( wParam, lParam );
break;
case WM_SETTINGCHANGE:
bStatus = bHandle_SettingChange( wParam, lParam );
break;
default:
bStatus = FALSE;
break;
}
//
// Allow the derived classes to handle the message.
//
bStatus = _bHandleMessage( uMsg, wParam, lParam );
//
// We must remember the last non-dynamic page here in order
// to know whether we are in our page or one of the dynamic
// pages later - (the dynamic pages are the shell extention pages
// plus the driver pages).
//
if( WM_NOTIFY == uMsg )
{
LPNMHDR pnmh = (LPNMHDR)lParam;
if( PSN_SETACTIVE == pnmh->code && 0 == GetWindowLong( _hDlg, DWLP_MSGRESULT ) )
{
//
// If activation is accepted
//
_pPrinterData->_hwndLastPageSelected = _hDlg;
}
}
//
// If the message was handled check if the
// apply button should be enabled.
//
if( bStatus )
{
if( _pPrinterData->bCheckForChange() )
{
vPropSheetChangedAllPages();
}
else
{
vPropSheetUnChangedAllPages();
}
}
return bStatus;
}
VOID
TPrinterProp::
vPropSheetChangedAllPages(
VOID
)
/*++
Routine Description:
Indicate that something has changed, we change the state
for all of our pages since the property sheet code
stores changed state on a per sheet basis.
Arguments:
None.
Return Value:
Nothing.
--*/
{
if( _pPrinterData->_bApplyEnableState )
{
for ( UINT i = 0; i < COUNTOF( _pPrinterData->_hwndPages ); i++ )
{
if( _pPrinterData->_hwndPages[i] )
{
PropSheet_Changed( GetParent( _hDlg ), _pPrinterData->_hwndPages[i] );
}
}
}
}
VOID
TPrinterProp::
vPropSheetUnChangedAllPages(
VOID
)
/*++
Routine Description:
Indicate we are back in the original state we change the state
for all of our pages since the property sheet code
stores changed or unchanged state on a per sheet basis.
Arguments:
None.
Return Value:
Nothing.
--*/
{
if( _pPrinterData->_bApplyEnableState )
{
for ( UINT i = 0; i < COUNTOF( _pPrinterData->_hwndPages ); i++ )
{
if( _pPrinterData->_hwndPages[i] )
{
PropSheet_UnChanged( GetParent( _hDlg ), _pPrinterData->_hwndPages[i] );
}
}
}
}
VOID
TPrinterProp::
vSetApplyState(
IN BOOL bNewApplyState
)
/*++
Routine Description:
Sets the current apply state. If the apply state is disable
then the apply button is always disabled.
Arguments:
bNewApplyState - TRUE enabled, FALSE disabled.
Return Value:
Nothing.
--*/
{
//
// Save the current apply enable state.
//
_pPrinterData->_bApplyEnableState = bNewApplyState;
//
// Either enable or disable the apply state.
//
SendMessage( GetParent(_hDlg), bNewApplyState ? PSM_ENABLEAPPLY : PSM_DISABLEAPPLY, 0, 0);
}
BOOL
TPrinterProp::
bHandle_InitDialog(
IN WPARAM wParam,
IN LPARAM lParam
)
/*++
Routine Description:
Handles init dialog message.
Arguments:
wParam - wParam
lParam - lParam
Return Value:
TRUE message handled, FALSE message not handled.
--*/
{
//
// Save the handles to all the activated pages.
///
_pPrinterData->_hwndPages[_pPrinterData->_uMaxActiveCount] = _hDlg;
//
// Count the activated pages.
//
++_pPrinterData->_uMaxActiveCount;
++_pPrinterData->_uActiveCount;
//
// Inform the property sheet manager what are parent handle is.
//
_pPrinterData->_pPrinterPropertySheetManager->vSetParentHandle( GetParent( _hDlg ) );
return TRUE;
}
BOOL
TPrinterProp::
bHandle_Notify(
IN WPARAM wParam,
IN LPARAM lParam
)
/*++
Routine Description:
Handles notify messages.
Arguments:
wParam - wParam
lParam - lParam
Return Value:
TRUE message handled, FALSE message not handled.
--*/
{
BOOL bStatus = TRUE;
LPNMHDR pnmh = (LPNMHDR)lParam;
switch( pnmh->code )
{
//
// The last chance apply message is sent in reverse order page n to page 0.
//
// We listen to this message when the apply button state is disabled due
// to the user changing the printer name. Since we are the first page
// in the set of property sheets we can gaurentee that the last PSN_LASTCHANCEAPPLY
// message will be the last message for all the pages, thus at this time it is
// safe to the printer.
//
case PSN_LASTCHANCEAPPLY:
DBGMSG( DBG_TRACE, ( "TPrinterProp::bHandleMessage PSN_LASTCHANCEAPPLY\n" ) );
if(!_pPrinterData->_bApplyEnableState)
{
vApplyChanges();
}
break;
//
// The apply message is sent in forward order page 0 to page n.
//
case PSN_APPLY:
DBGMSG( DBG_TRACE, ( "TPrinterProp::bHandleMessage PSN_APPLY\n" ) );
if(_pPrinterData->_bApplyEnableState)
{
vApplyChanges();
}
break;
default:
bStatus = FALSE;
break;
}
return bStatus;
}
BOOL
TPrinterProp::
bHandle_SettingChange(
IN WPARAM wParam,
IN LPARAM lParam
)
/*++
Routine Description:
Handles setting change message.
Arguments:
wParam - wParam
lParam - lParam
Return Value:
TRUE message handled, FALSE message not handled.
--*/
{
HWND hCtrl;
BOOL bDefaultPrinter;
//
// WM_SETTINGCHANGE is posted to every page but we only execute the function once. This
// is because we change _bDefaultPrinter only once.
//
bDefaultPrinter = CheckDefaultPrinter( _pPrinterData->strCurrentPrinterName() ) == kDefault;
if( _pPrinterData->bDefaultPrinter() ^ bDefaultPrinter )
{
//
// If the default printer setting is changed and it related to
// current printer, change the window icon
//
_pPrinterData->bDefaultPrinter() = bDefaultPrinter;
CAutoHandleIcon shIconLarge, shIconSmall;
LoadPrinterIcons(_pPrinterData->strCurrentPrinterName(), &shIconLarge, &shIconSmall);
if( shIconLarge && shIconSmall )
{
_pPrinterData->shLargeIcon() = shIconLarge.Detach();
_pPrinterData->shSmallIcon() = shIconSmall.Detach();
//
// Change the printer icon to each page which has printer icon control.
//
for ( UINT i = 0; i < COUNTOF( _pPrinterData->_hwndPages ); i++ )
{
if( _pPrinterData->_hwndPages[i] &&
(hCtrl = GetDlgItem( _pPrinterData->_hwndPages[i], IDC_PRINTER_ICON )) )
{
SendMessage(hCtrl, STM_SETICON, (WPARAM)(HICON)_pPrinterData->shLargeIcon(), 0);
InvalidateRect(hCtrl, NULL, FALSE);
}
}
}
}
return FALSE;
}
VOID
TPrinterProp::
vApplyChanges(
VOID
)
/*++
Routine Description:
This routine applies the changes if this is the last active page
or the caller specified a force flag to do the apply changes now.
Arguments:
bForceApplyNow - TRUE apply the changes now, FALSE wait for last active page.
Return Value:
Nothing.
--*/
{
if (!--_pPrinterData->_uActiveCount)
{
//
// Reset the active page count.
//
_pPrinterData->_uActiveCount = _pPrinterData->_uMaxActiveCount;
//
// Only save the options if we have rights to change settings.
//
if (_pPrinterData->bAdministrator())
{
//
// Save the printer data to the spooler.
//
BOOL bStatus = _pPrinterData->bSave();
if (!bStatus)
{
//
// Display error message to the user.
//
iMessage( _hDlg,
IDS_ERR_PRINTER_PROP_TITLE,
IDS_ERR_SAVE_PRINTER,
MB_OK|MB_ICONSTOP,
kMsgGetLastError,
gaMsgErrMapSetPrinter );
}
else
{
//
// Inform the active pages to refresh themselves.
//
vNotifyActivePagesToRefresh();
//
// Re-enable the apply state.
//
_pPrinterData->_bApplyEnableState = TRUE;
}
//
// If settings are saved successfully.
//
vSetDlgMsgResult( !bStatus ? PSNRET_INVALID_NOCHANGEPAGE : PSNRET_NOERROR );
}
}
}
VOID
TPrinterProp::
vNotifyActivePagesToRefresh(
VOID
)
/*++
Routine Description:
Notify the active pages that they should refresh themselves.
Arguments:
None.
Return Value:
Nothing.
--*/
{
for ( UINT i = 0; i < COUNTOF( _pPrinterData->_hwndPages ); i++ )
{
if( _pPrinterData->_hwndPages[i] )
{
PostMessage( _pPrinterData->_hwndPages[i], WM_APP, 0, 0 );
}
}
}
/*++
Routine Name:
vCancelToClose
Routine Description:
Change the cancel button to close, the user has basically
made a change that cannot be undone using the cancel button.
Arguments:
None.
Return Value:
Nothing.
--*/
VOID
TPrinterProp::
vCancelToClose(
VOID
)
{
PropSheet_CancelToClose( GetParent( _hDlg ) );
}
/********************************************************************
General.
********************************************************************/
TPrinterGeneral::
TPrinterGeneral(
TPrinterData* pPrinterData
) : TPrinterProp( pPrinterData ),
_bSetUIDone( FALSE ),
_pLocationDlg (NULL)
{
}
TPrinterGeneral::
~TPrinterGeneral(
VOID
)
{
delete _pLocationDlg;
}
BOOL
TPrinterGeneral::
bValid(
VOID
)
{
return TPrinterProp::bValid();
}
BOOL
TPrinterGeneral::
bSetUI(
VOID
)
{
// subclass the edit control to workaround a bug
if( !m_wndComment.IsAttached() )
{
VERIFY(m_wndComment.Attach(GetDlgItem(hDlg(), IDC_COMMENT)));
}
//
// Update the fields.
//
bSetEditText( _hDlg, IDC_COMMENT, _pPrinterData->strComment());
bSetEditText( _hDlg, IDC_LOCATION, _pPrinterData->strLocation());
bSetEditText( _hDlg, IDC_MODEL_NAME, _pPrinterData->strDriverName());
//
// When we are not an administrator set the edit controls to read only
// rather and disabled. They are easier to read in read only mode.
//
SendDlgItemMessage( _hDlg, IDC_COMMENT, EM_SETREADONLY, !_pPrinterData->bAdministrator(), 0);
SendDlgItemMessage( _hDlg, IDC_LOCATION,EM_SETREADONLY, !_pPrinterData->bAdministrator(), 0);
SendDlgItemMessage( _hDlg, IDC_NAME, EM_SETREADONLY, !_pPrinterData->bAdministrator(), 0);
//
// We do not support renaming of masq printers, this is done because the leading \\ on
// masq printers is neccessary for the folder code to determine if the printer is the
// special masq printer case. The folder code does this check because to get the printer
// attributes for every printer would slow down the code excessivly.
//
if( _pPrinterData->_dwAttributes & PRINTER_ATTRIBUTE_LOCAL && _pPrinterData->_dwAttributes & PRINTER_ATTRIBUTE_NETWORK )
{
SendDlgItemMessage( _hDlg, IDC_NAME, EM_SETREADONLY, TRUE, 0);
}
else
{
vCheckForSharedMasqPrinter();
}
//
// Create the find dialog.
//
_pLocationDlg = new TFindLocDlg;
if (VALID_PTR(_pLocationDlg) && TPhysicalLocation::bLocationEnabled() && TDirectoryService::bIsDsAvailable())
{
EnableWindow (GetDlgItem (_hDlg, IDC_BROWSE_LOCATION), _pPrinterData->bAdministrator());
}
else
{
//
// If no DS is available, hide the Browse button and extend the location
// edit control appropriately
RECT rcComment;
RECT rcLocation;
HWND hLoc;
hLoc = GetDlgItem (_hDlg, IDC_LOCATION);
GetWindowRect (GetDlgItem (_hDlg, IDC_COMMENT), &rcComment);
GetWindowRect (hLoc, &rcLocation);
SetWindowPos (hLoc,
NULL,
0,0,
rcComment.right-rcComment.left,
rcLocation.bottom-rcLocation.top,
SWP_NOMOVE|SWP_NOZORDER);
ShowWindow (GetDlgItem (_hDlg, IDC_BROWSE_LOCATION), SW_HIDE);
}
//
// Set the pinter name limit text.
//
SendDlgItemMessage( _hDlg, IDC_NAME, EM_SETLIMITTEXT, kPrinterLocalNameMax, 0 );
//
// Set the comment limit text to 255. A printer with a comment string
// longer than 255 characters cannot be shared.
//
SendDlgItemMessage( _hDlg, IDC_COMMENT, EM_SETLIMITTEXT, kPrinterCommentBufMax, 0 );
//
// What the heck lets be consistent and make the location string
// have a limit.
//
SendDlgItemMessage( _hDlg, IDC_LOCATION, EM_SETLIMITTEXT, kPrinterLocationBufMax, 0 );
//
// If the driver pages failed to load or the user did not
// want to load them then hide the devmode editor UI
// because you need a driver to show the dev mode editor.
//
if( _pPrinterData->_bDriverPagesNotLoaded )
{
ShowWindow( GetDlgItem( _hDlg, IDC_PER_USER_DOCUMENT_DEFAULTS ), SW_HIDE );
}
//
// The test page button does not apply for the fax printer.
//
if( _pPrinterData->_bIsFaxDriver )
{
WINDOWPLACEMENT wndpl;
wndpl.length = sizeof( wndpl );
GetWindowPlacement( GetDlgItem( _hDlg, IDC_TEST ), &wndpl );
SetWindowPlacement( GetDlgItem( _hDlg, IDC_PER_USER_DOCUMENT_DEFAULTS ), &wndpl );
ShowWindow( GetDlgItem( _hDlg, IDC_TEST ), SW_HIDE );
}
//
// Display the features information.
//
vReloadFeaturesInformation();
//
// There are a few UI elements that need to be set when
// we are activated, because of a driver change. We
// will artifically do it now.
//
vSetActive();
//
// Indicate SetUI is done. This is used to
// prevent ReadUI from reading junk since edit controls
// recieve EN_CHANGE messages while in WM_INITDIALOG
//
_bSetUIDone = TRUE;
return TRUE;
}
VOID
TPrinterGeneral::
vReloadFeaturesInformation(
VOID
)
{
TStatusB bStatus;
UINT uValidFeatureCount = 0;
//
// Create the printer data access class.
//
TPrinterDataAccess Data( _pPrinterData->_hPrinter );
//
// Relax the return type checking, BOOL are not REG_DWORD but REG_BINARY
//
Data.RelaxReturnTypeCheck( TRUE );
//
// Initialize the data class.
//
bStatus DBGCHK = Data.Init();
if( bStatus )
{
TString strYes;
TString strNo;
TString strTemp;
TString strTemp1;
TString strUnknown;
TString strPPM;
TString strDPI;
HRESULT hr;
BOOL bValue;
DWORD dwValue;
LPCTSTR pszString;
bStatus DBGCHK = strUnknown.bLoadString( ghInst, IDS_FEATURE_UNKNOWN );
bStatus DBGCHK = strYes.bLoadString( ghInst, IDS_YES );
bStatus DBGCHK = strNo.bLoadString( ghInst, IDS_NO );
bStatus DBGCHK = strPPM.bLoadString( ghInst, IDS_SPEED_UNITS );
bStatus DBGCHK = strDPI.bLoadString( ghInst, IDS_RESOLUTION_UNITS );
hr = Data.Get( SPLDS_DRIVER_KEY, SPLDS_PRINT_COLOR, bValue );
uValidFeatureCount = SUCCEEDED(hr) ? uValidFeatureCount+1 : uValidFeatureCount;
bStatus DBGCHK = strTemp.bLoadString( ghInst, IDS_COLOR );
bStatus DBGCHK = strTemp.bCat( gszSpace );
bStatus DBGCHK = strTemp.bCat( FAILED(hr) ? strUnknown : bValue ? strYes : strNo );
bStatus DBGCHK = bSetEditText( _hDlg, IDC_COLOR, strTemp );
hr = Data.Get( SPLDS_DRIVER_KEY, SPLDS_PRINT_DUPLEX_SUPPORTED, bValue );
uValidFeatureCount = SUCCEEDED(hr) ? uValidFeatureCount+1 : uValidFeatureCount;
bStatus DBGCHK = strTemp.bLoadString( ghInst, IDS_DUPLEX );
bStatus DBGCHK = strTemp.bCat( gszSpace );
bStatus DBGCHK = strTemp.bCat( FAILED(hr) ? strUnknown : bValue ? strYes : strNo );
bStatus DBGCHK = bSetEditText( _hDlg, IDC_DUPLEX, strTemp );
hr = Data.Get( SPLDS_DRIVER_KEY, SPLDS_PRINT_STAPLING_SUPPORTED, bValue );
uValidFeatureCount = SUCCEEDED(hr) ? uValidFeatureCount+1 : uValidFeatureCount;
bStatus DBGCHK = strTemp.bLoadString( ghInst, IDS_STAPLE );
bStatus DBGCHK = strTemp.bCat( gszSpace );
bStatus DBGCHK = strTemp.bCat( FAILED(hr) ? strUnknown : bValue ? strYes : strNo );
bSetEditText( _hDlg, IDC_STAPLE, strTemp );
hr = Data.Get( SPLDS_DRIVER_KEY, SPLDS_PRINT_PAGES_PER_MINUTE, dwValue );
uValidFeatureCount = SUCCEEDED(hr) ? uValidFeatureCount+1 : uValidFeatureCount;
bStatus DBGCHK = strTemp.bLoadString( ghInst, IDS_SPEED );
bStatus DBGCHK = strTemp.bCat( gszSpace );
bStatus DBGCHK = strTemp.bCat( FAILED(hr) ? strUnknown : strTemp1.bFormat( _T("%d %s"), dwValue, (LPCTSTR)strPPM ) ? strTemp1 : gszNULL );
bStatus DBGCHK = bSetEditText( _hDlg, IDC_SPEED, strTemp );
hr = Data.Get( SPLDS_DRIVER_KEY, SPLDS_PRINT_MAX_RESOLUTION_SUPPORTED, dwValue );
uValidFeatureCount = SUCCEEDED(hr) ? uValidFeatureCount+1 : uValidFeatureCount;
bStatus DBGCHK = strTemp.bLoadString( ghInst, IDS_RESOLUTION );
bStatus DBGCHK = strTemp.bCat( gszSpace );
bStatus DBGCHK = strTemp.bCat( FAILED(hr) ? strUnknown : strTemp1.bFormat( _T("%d %s"), dwValue, (LPCTSTR)strDPI ) ? strTemp1 : gszNULL );
bStatus DBGCHK = bSetEditText( _hDlg, IDC_RESOLUTION, strTemp );
TString *pStrings = NULL;
UINT nCount = 0;
hr = Data.Get( SPLDS_DRIVER_KEY, SPLDS_PRINT_MEDIA_READY, &pStrings, nCount );
uValidFeatureCount = SUCCEEDED(hr) ? uValidFeatureCount+1 : uValidFeatureCount;
TString strMediaReady;
if( SUCCEEDED(hr) )
{
for( UINT i = 0; i < nCount; i++ )
{
DBGMSG( DBG_TRACE, ( "Media ready " TSTR ".\n", (LPCTSTR)pStrings[i] ) );
bStatus DBGCHK = strMediaReady.bCat( pStrings[i] );
if( i != (nCount-1) )
{
//
// If it is not the last media type, add CRLF symbols at the end
//
bStatus DBGCHK = strMediaReady.bCat( _T("\r\n" ));
}
}
}
//
// We are updating the "Paper Available" regardless of whether
// the GetPrinterDataEx( ... ) succeeds or fails.
//
bStatus DBGCHK = bSetEditText( _hDlg, IDC_PAPER_SIZE_LIST, strMediaReady );
delete [] pStrings;
}
if( !uValidFeatureCount )
{
ShowWindow( GetDlgItem( _hDlg, IDC_COLOR ), SW_HIDE );
ShowWindow( GetDlgItem( _hDlg, IDC_DUPLEX ), SW_HIDE );
ShowWindow( GetDlgItem( _hDlg, IDC_STAPLE ), SW_HIDE );
ShowWindow( GetDlgItem( _hDlg, IDC_SPEED ), SW_HIDE );
ShowWindow( GetDlgItem( _hDlg, IDC_RESOLUTION ), SW_HIDE );
ShowWindow( GetDlgItem( _hDlg, IDC_PAPER_SIZE_LIST ), SW_HIDE );
ShowWindow( GetDlgItem( _hDlg, IDC_GBOX_FEATURES ), SW_HIDE );
ShowWindow( GetDlgItem( _hDlg, IDC_PAPER_SIZE ), SW_HIDE );
}
}
VOID
TPrinterGeneral::
vReadUI(
VOID
)
{
if( !bGetEditText( _hDlg, IDC_COMMENT, _pPrinterData->strComment( )) ||
!bGetEditText( _hDlg, IDC_LOCATION, _pPrinterData->strLocation( )) ||
!bGetEditText( _hDlg, IDC_NAME, _pPrinterData->strPrinterName( )))
{
//
// If we cannot read from any of the edit controls then set the
// error flag.
//
_pPrinterData->_bErrorSaving = FALSE;
//
// Unable to read the text.
//
vShowResourceError( _hDlg );
//
// Don't swith the page.
//
vSetDlgMsgResult( TRUE );
}
else
{
//
// Remove any trailing slashes from the location string
//
TPhysicalLocation::vTrimSlash (_pPrinterData->strLocation());
}
}
VOID
TPrinterGeneral::
vSetActive(
VOID
)
{
//
// Set the icon and printer name.
//
vSetIconName();
//
// Reload the features information.
//
vReloadFeaturesInformation();
//
// Set the new printer driver name.
//
bSetEditText( _hDlg, IDC_MODEL_NAME, _pPrinterData->strDriverName( ));
}
VOID
TPrinterGeneral::
vKillActive(
VOID
)
{
//
// Do not validate the printer name if IDC_NAME field is readonly,
// which means either one of the following:
//
// 1. The printer is masq printer
// 2. The printer is shared masq printer
//
if( ES_READONLY & GetWindowLong(GetDlgItem(_hDlg, IDC_NAME), GWL_STYLE) )
return;
//
// Only validate the printer name if we are an administrator
//
if( _pPrinterData->bAdministrator() )
{
//
// Strip any trailing white space.
//
vStripTrailWhiteSpace( (LPTSTR)(LPCTSTR)_pPrinterData->_strPrinterName );
//
// Check if the name is null.
//
if( _pPrinterData->_strPrinterName.bEmpty( ) ){
iMessage( _hDlg,
IDS_ERR_PRINTER_PROP_TITLE,
IDS_ERR_NO_PRINTER_NAME,
MB_OK|MB_ICONEXCLAMATION,
kMsgNone,
NULL );
vSetDlgMsgResult( TRUE );
return;
}
//
// Validate the printer name for any illegal characters.
//
if( !bIsLocalPrinterNameValid( _pPrinterData->strPrinterName( ) ) )
{
//
// Put up error explaining that at least one port must be
// selected.
//
iMessage( _hDlg,
IDS_ERR_PRINTER_PROP_TITLE,
IDS_ERR_BAD_PRINTER_NAME,
MB_OK|MB_ICONSTOP,
kMsgNone,
NULL );
//
// Don't swith the page.
//
vSetDlgMsgResult( TRUE );
}
}
}
VOID
TPrinterGeneral::
vCheckForSharedMasqPrinter(
VOID
)
{
//
// check if it is a shared masq printer - which means that the printer name may
// contains invalid symbols
//
LPCTSTR pszServer;
LPCTSTR pszPrinter;
TCHAR szScratch[kPrinterBufMax];
vPrinterSplitFullName( szScratch,
ARRAYSIZE(szScratch),
_pPrinterData->strPrinterName( ),
&pszServer,
&pszPrinter );
if( !bIsLocalPrinterNameValid( pszPrinter ) )
{
SendDlgItemMessage( _hDlg, IDC_NAME, EM_SETREADONLY, TRUE, 0);
}
}
BOOL
TPrinterGeneral::
_bHandleMessage(
IN UINT uMsg,
IN WPARAM wParam,
IN LPARAM lParam
)
{
TStatusB bStatus;
bStatus DBGNOCHK = TRUE;
switch( uMsg ){
case WM_INITDIALOG:
bStatus DBGCHK = bSetUI();
break;
case WM_HELP:
case WM_CONTEXTMENU:
bStatus DBGCHK = PrintUIHelp( uMsg, _hDlg, wParam, lParam );
break;
case WM_CLOSE:
//
// Multiline edit controls send WM_CLOSE to dismiss the dialog.
// Convert it to a property-page friendly message.
//
PropSheet_PressButton( GetParent( _hDlg ), PSBTN_CANCEL );
break;
case WM_APP:
vSetActive();
break;
case WM_COMMAND:
switch( GET_WM_COMMAND_ID( wParam, lParam )){
case IDC_COMMENT:
case IDC_LOCATION:
bStatus DBGNOCHK = GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE;
break;
case IDC_NAME:
{
bStatus DBGNOCHK = GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE;
//
// When the printer name changes we disable the apply button because
// we have no way to inform the extention tabs the printer name has changed.
//
TString str;
if( bGetEditText( _hDlg, IDC_NAME, str ) )
{
vSetApplyState( !_pPrinterData->ComparePrinterName( str, _pPrinterData->strCurrentPrinterName() ));
}
break;
}
case IDC_TEST:
{
//
// If this is a masq printer we do need to check the name
// for trailing spaces. In this case the original share name
// is actually the port name.
//
LPCTSTR pszOrigShareName = NULL;
if( _pPrinterData->_dwAttributes & PRINTER_ATTRIBUTE_NETWORK &&
_pPrinterData->_dwAttributes & PRINTER_ATTRIBUTE_LOCAL )
{
pszOrigShareName = _pPrinterData->strPortName();
}
bPrintTestPage( _hDlg, _pPrinterData->strCurrentPrinterName(), pszOrigShareName );
}
break;
case IDC_PER_USER_DOCUMENT_DEFAULTS:
vHandleDocumentDefaults( wParam, lParam );
break;
case IDC_BROWSE_LOCATION:
vHandleBrowseLocation();
break;
default:
bStatus DBGNOCHK = FALSE;
break;
}
break;
case WM_NOTIFY:
{
LPNMHDR pnmh = (LPNMHDR)lParam;
switch( pnmh->code ){
case PSN_KILLACTIVE:
vKillActive();
break;
default:
bStatus DBGNOCHK = FALSE;
break;
}
}
break;
default:
bStatus DBGNOCHK = FALSE;
break;
}
if( bStatus && _bSetUIDone )
{
vReadUI();
}
return bStatus;
}
VOID
TPrinterGeneral::
vHandleDocumentDefaults(
IN WPARAM wParam,
IN LPARAM lParam
)
/*++
Routine Description:
Handle launching document defaults dialog.
Arguments:
wParam - Parameter passed to by dialog proc.
lParam - Parameter passed to by dialog proc.
Return Value:
Nothing.
--*/
{
(VOID)dwDocumentDefaultsInternal( _hDlg,
_pPrinterData->strCurrentPrinterName(),
SW_SHOW,
0,
0,
FALSE );
}
VOID
TPrinterGeneral::
vHandleBrowseLocation(
VOID
)
/*++
Routine Description:
Handle displaying the location tree dialog.
Arguments:
wParam - Parameter passed to by dialog proc.
lParam - Parameter passed to by dialog proc.
Return Value:
Nothing.
--*/
{
TStatusB bStatus;
TString strDefault = _pPrinterData->strLocation();
//
// bDoModal returns FALSE on Cancel
//
bStatus DBGNOCHK = _pLocationDlg->bDoModal(_hDlg, &strDefault);
if (bStatus)
{
TString strLocation;
bStatus DBGCHK = _pLocationDlg->bGetLocation (strLocation);
if (bStatus && !strLocation.bEmpty())
{
//
// Check to append a trailing slash
//
UINT uLen = strLocation.uLen();
if( uLen && gchSeparator != static_cast<LPCTSTR>(strLocation)[uLen-1] )
{
static const TCHAR szSepStr[] = { gchSeparator };
bStatus DBGCHK = strLocation.bCat( szSepStr );
}
bStatus DBGCHK = bSetEditText (_hDlg, IDC_LOCATION, strLocation);
}
//
// Set focus to the edit control for location, even if setedittext failed
// Assumption is that user probably still wants to modify locations
//
SetFocus (GetDlgItem (_hDlg, IDC_LOCATION));
//
// Place the caret at the end of the text, for appending
//
SendDlgItemMessage (_hDlg, IDC_LOCATION, EM_SETSEL, strLocation.uLen(), (LPARAM)-1);
}
}
/********************************************************************
Printer Ports.
********************************************************************/
TPrinterPorts::
TPrinterPorts(
TPrinterData* pPrinterData
) : TPrinterProp( pPrinterData ),
_bAdminFlag( FALSE )
{
}
TPrinterPorts::
~TPrinterPorts(
VOID
)
{
}
BOOL
TPrinterPorts::
bValid(
VOID
)
{
return _PortsLV.bValid();
}
BOOL
TPrinterPorts::
bSetUI(
VOID
)
{
//
// Initalize the class admin flag. We only allow administring ports
// on this printer if the user is an admin and the printer is not
// a masq printer. Masq printer cannot have their ports reassigned,
// spooler will fail the call, just to make the UI more user friendly
// we don't let the user do things that we know will fail.
//
_bAdminFlag = _pPrinterData->bAdministrator();
if( (_pPrinterData->dwAttributes() & PRINTER_ATTRIBUTE_LOCAL) && (_pPrinterData->dwAttributes() & PRINTER_ATTRIBUTE_NETWORK) )
{
_bAdminFlag = FALSE;
}
//
// Initialize the ports list view.
//
if( !_PortsLV.bSetUI( GetDlgItem( _hDlg, IDC_PORTS ), FALSE, TRUE, _bAdminFlag, _hDlg, 0, 0, IDC_PORT_DELETE ) )
{
return FALSE;
}
//
// If we do not have access then don't enumerate the ports
//
if( !_pPrinterData->bNoAccess() )
{
//
// Load the machine's ports into the listview.
//
if( !_PortsLV.bReloadPorts( _pPrinterData->pszServerName() ) )
{
return FALSE;
}
}
//
// Select the current printer's ports.
//
_PortsLV.vCheckPorts((LPTSTR)(LPCTSTR)_pPrinterData->strPortName( ));
//
// Set the ports list view to single selection mode,
//
_PortsLV.vSetSingleSelection( !_pPrinterData->bPooledPrinting() );
//
// Set the pooled printing mode on the UI.
//
vSetCheck( _hDlg, IDC_POOLED_PRINTING, _pPrinterData->bPooledPrinting() );
//
// If we do not have admin privilages or we are remotly
// administering a downlevel machine, then disable
// adding / deleting / configuring ports.
//
if( !_bAdminFlag || ( bIsRemote( _pPrinterData->pszServerName() ) &&
GetDriverVersion( _pPrinterData->dwDriverVersion() ) <= 2 ) )
{
//
// Disable things if not administrator.
//
vEnableCtl( _hDlg, IDC_PORT_CREATE, FALSE );
vEnableCtl( _hDlg, IDC_PORT_DELETE, FALSE );
vEnableCtl( _hDlg, IDC_PROPERTIES, FALSE );
}
//
// Disable bidi selection if not an administrator.
// Disable printer pooling if not an administrator.
//
vEnableCtl( _hDlg, IDC_ENABLE_BIDI, _bAdminFlag );
vEnableCtl( _hDlg, IDC_POOLED_PRINTING, _bAdminFlag );
//
// Enable Configure Port for HTTP printer only
//
if( (_pPrinterData->dwAttributes() & PRINTER_ATTRIBUTE_LOCAL) &&
(_pPrinterData->dwAttributes() & PRINTER_ATTRIBUTE_NETWORK) &&
(!_tcsnicmp( _pPrinterData->strPortName (), gszHttpPrefix0, _tcslen(gszHttpPrefix0) ) ||
!_tcsnicmp( _pPrinterData->strPortName (), gszHttpPrefix1, _tcslen(gszHttpPrefix1) )))
{
vEnableCtl( _hDlg, IDC_PROPERTIES, TRUE );
}
//
// There are a few UI elements that need to be set when
// we are activated, because of a driver change. We
// will artifically do it now.
//
vSetActive();
return TRUE;
}
VOID
TPrinterPorts::
vReadUI(
VOID
)
/*++
Routine Description:
Gets the ports from the listview and create the string.
Arguments:
Return Value:
--*/
{
//
// Read bidi options.
//
DWORD dwAttributes = _pPrinterData->dwAttributes();
if( BST_CHECKED == IsDlgButtonChecked( _hDlg, IDC_ENABLE_BIDI )){
dwAttributes |= PRINTER_ATTRIBUTE_ENABLE_BIDI;
} else {
dwAttributes &= ~PRINTER_ATTRIBUTE_ENABLE_BIDI;
}
_pPrinterData->_dwAttributes = dwAttributes;
//
// Build the ports string as long as we are an admin.
//
if( _bAdminFlag && !_PortsLV.bReadUI( _pPrinterData->_strPortName )){
_pPrinterData->_bErrorSaving = TRUE;
vShowResourceError( _hDlg );
}
return;
}
VOID
TPrinterPorts::
vSetActive(
VOID
)
{
//
// Set the icon and printer name.
//
vSetIconName();
BOOL bEnable = FALSE;
BOOL bCheck = FALSE;
//
// If the call fails or the monitor name is NULL/szNULL,
// then disable bidi.
//
if( _pPrinterData->bSupportBidi( )){
bEnable = TRUE;
//
// Only set the checkbox if a language monitor is present.
// (When we change drivers, we always set this attribute
// bit, even if bidi isn't supported. The spooler and UI
// ignore it in this case.)
//
bCheck = _pPrinterData->dwAttributes() & PRINTER_ATTRIBUTE_ENABLE_BIDI;
}
//
// Set bidi options.
//
vSetCheck( _hDlg, IDC_ENABLE_BIDI, bCheck );
//
// If we are an administrator and this is the local
// machine, we can enable the bidi control.
//
if( _pPrinterData->bAdministrator( ) ){
vEnableCtl( _hDlg, IDC_ENABLE_BIDI, bEnable );
}
//
// If the ports list needs to refreshed.
//
_PortsLV.bReloadPorts( _pPrinterData->pszServerName(), FALSE );
}
BOOL
TPrinterPorts::
bKillActive(
VOID
)
/*++
Routine Description:
Validate that the printer page is in a consistent state.
Arguments:
Return Value:
TRUE - Ok to kill active, FALSE = can't kill active, UI displayed.
--*/
{
COUNT cPorts;
//
// If we do not have access or we are not an administrator
// do not validate the port selection.
//
if( _pPrinterData->bNoAccess() || !_bAdminFlag ){
return TRUE;
}
cPorts = _PortsLV.cSelectedPorts();
//
// Validate that at least 1 port is selected.
// Validate more than 1 port is selected if pooled printing is
// enabled.
//
if( cPorts == 0 )
{
//
// Put up error explaining that at least one port must be
// selected.
//
iMessage( _hDlg,
IDS_ERR_PRINTER_PROP_TITLE,
IDS_ERR_NO_PORTS,
MB_OK|MB_ICONSTOP,
kMsgNone,
NULL );
_PortsLV.vSetFocus();
//
// Don't swith the page.
//
vSetDlgMsgResult( TRUE );
}
else if ( (cPorts == 1) && !_PortsLV.bGetSingleSelection() )
{
INT iStatus = iMessage( _hDlg,
IDS_ERR_PRINTER_PROP_TITLE,
IDS_ERR_ONLY_ONE_PORT,
MB_OKCANCEL | MB_ICONWARNING,
kMsgNone,
NULL );
//
// If user wants to cancel pool printing.
//
if( iStatus == IDOK )
{
vSetCheck( _hDlg, IDC_POOLED_PRINTING, FALSE );
_PortsLV.vSetSingleSelection(TRUE);
_pPrinterData->bPooledPrinting() = FALSE;
//
// Read UI data.
//
vReadUI();
}
else
{
_PortsLV.vSetFocus();
//
// Don't swith the page.
//
vSetDlgMsgResult( TRUE );
}
}
else {
//
// Read UI data.
//
vReadUI();
}
//
// Routine must return true to see DlgMsgResult corretly.
//
return TRUE;
}
BOOL
TPrinterPorts::
_bHandleMessage(
IN UINT uMsg,
IN WPARAM wParam,
IN LPARAM lParam
)
/*++
Routine Description:
Handle message.
Arguments:
Return Value:
--*/
{
TStatusB bStatus;
bStatus DBGNOCHK = TRUE;
switch( uMsg ){
case WM_INITDIALOG:
bStatus DBGCHK = bSetUI();
break;
case WM_APP:
vSetActive();
break;
case WM_HELP:
case WM_CONTEXTMENU:
PrintUIHelp( uMsg, _hDlg, wParam, lParam );
break;
case WM_COMMAND:
switch( GET_WM_COMMAND_ID( wParam, lParam )){
case IDC_PORT_DELETE:
{
//
// Delete the selected port.
//
HWND hwnd = GetDlgItem( _hDlg, IDC_PORT_DELETE );
//
// We will only delete the port if the button is enabled, this check is
// necessary if the user uses the delete key on the keyboard to delete
// the port.
//
if( IsWindowEnabled( hwnd ) )
{
bStatus DBGNOCHK = _PortsLV.bDeletePorts( _hDlg, _pPrinterData->pszServerName( ));
if( bStatus )
{
SetFocus( hwnd );
vCancelToClose();
}
}
}
break;
case IDC_PROPERTIES:
//
// Configure the selected port.
//
bStatus DBGNOCHK = _PortsLV.bConfigurePort( _hDlg, _pPrinterData->pszServerName( ));
SetFocus( GetDlgItem( _hDlg, IDC_PROPERTIES ) );
if( bStatus )
{
vCancelToClose();
}
break;
case IDC_PORT_CREATE:
{
//
// Create add ports class.
//
TAddPort AddPort( _hDlg,
_pPrinterData->pszServerName(),
_pPrinterData->bAdministrator() );
//
// Insure the add port was created successfully.
//
bStatus DBGNOCHK = VALID_OBJ( AddPort );
if( !bStatus ){
vShowUnexpectedError( _hDlg, TAddPort::kErrorMessage );
} else {
//
// Display the add port, add monitor UI.
//
bStatus DBGNOCHK = AddPort.bDoModal();
if( bStatus ){
//
// Refresh ports listview.
//
bStatus DBGNOCHK = _PortsLV.bReloadPorts( _pPrinterData->pszServerName(), TRUE );
if( bStatus ){
//
// A port was added and the list view was reloaded, since this
// action cannot be undone we will change the cancel button to
// close.
//
vCancelToClose();
}
}
}
}
break;
case IDC_POOLED_PRINTING:
{
//
// Get the current selection state.
//
BOOL bSingleSelection; // status of the new state
bSingleSelection = ( BST_CHECKED == IsDlgButtonChecked( _hDlg, IDC_POOLED_PRINTING ) ? FALSE : TRUE );
//
// If we are going from pooled printing to non-pooled printing
// and the printer is currently being used by multiple ports, inform
// the user all the port selection will be lost.
//
if( bSingleSelection &&
_PortsLV.cSelectedPorts() > 1 ){
INT iStatus = iMessage( _hDlg,
IDS_ERR_PRINTER_PROP_TITLE,
IDS_ERR_PORT_SEL_CHANGE,
MB_YESNO|MB_ICONEXCLAMATION,
kMsgNone,
NULL );
//
// If user does not want to do this.
//
if( iStatus != IDYES ){
vSetCheck( _hDlg, IDC_POOLED_PRINTING, TRUE );
bSingleSelection = FALSE;
} else {
//
// Remove all the port selections.
//
_PortsLV.vRemoveAllChecks();
}
}
//
// Set the new selection state.
//
_PortsLV.vSetSingleSelection( bSingleSelection );
_pPrinterData->bPooledPrinting() = !bSingleSelection;
}
break;
case IDC_ENABLE_BIDI:
break;
default:
bStatus DBGNOCHK = FALSE;
break;
}
break;
case WM_NOTIFY:
//
// Handle clicking of check boxes in ports listview.
//
switch( wParam ){
case IDC_PORTS:
//
// Handle any ports list view messages.
//
bStatus DBGNOCHK = _PortsLV.bHandleNotifyMessage( lParam );
break;
case 0:
{
LPNMHDR pnmh = (LPNMHDR)lParam;
switch( pnmh->code ){
case PSN_KILLACTIVE:
bStatus DBGNOCHK = bKillActive();
break;
case PSN_APPLY:
bStatus DBGNOCHK = FALSE;
break;
default:
bStatus DBGNOCHK = FALSE;
break;
}
}
break;
default:
bStatus DBGNOCHK = FALSE;
break;
}
break;
default:
bStatus DBGNOCHK = FALSE;
break;
}
//
// If the message was handled then read the UI to detect
// if there were any changes.
//
if( bStatus )
{
vReadUI();
}
return bStatus;
}
/********************************************************************
JobScheduling.
********************************************************************/
TPrinterJobScheduling::
TPrinterJobScheduling(
TPrinterData* pPrinterData
) : TPrinterProp( pPrinterData ),
_bSetUIDone( FALSE )
{
}
TPrinterJobScheduling::
~TPrinterJobScheduling(
VOID
)
{
}
BOOL
TPrinterJobScheduling::
bValid(
VOID
)
{
return TRUE;
}
VOID
TPrinterJobScheduling::
vEnableAvailable(
IN BOOL bEnable
)
{
vEnableCtl( _hDlg, IDC_START_TIME, bEnable );
vEnableCtl( _hDlg, IDC_UNTIL_TIME, bEnable );
vEnableCtl( _hDlg, IDC_TO_TEXT, bEnable );
}
VOID
TPrinterJobScheduling::
vSetActive(
VOID
)
/*++
Routine Description:
Routine called when the pages is set active. This routine
will refresh the time control if were any local changes.
Arguments:
None.
Return Value:
Nothing.
--*/
{
(VOID)bSetStartAndUntilTime();
}
BOOL
TPrinterJobScheduling::
bSetStartAndUntilTime(
VOID
)
{
TString strFormatString;
TStatusB bStatus;
//
// Get the time format string without seconds.
//
bStatus DBGCHK = bGetTimeFormatString( strFormatString );
//
// If we have retrived a valid time format string then use it,
// else use the default format string implemented by common control.
//
if( bStatus )
{
DateTime_SetFormat(GetDlgItem( _hDlg, IDC_START_TIME ), static_cast<LPCTSTR>( strFormatString ) );
DateTime_SetFormat(GetDlgItem( _hDlg, IDC_UNTIL_TIME ), static_cast<LPCTSTR>( strFormatString ) );
}
//
// If the printer is always available.
//
BOOL bAlways = ( _pPrinterData->dwStartTime() == _pPrinterData->dwUntilTime( ));
//
// Set the start time.
//
SYSTEMTIME StartTime = { 0 };
DWORD dwLocalStartTime = 0;
GetLocalTime( &StartTime );
dwLocalStartTime = ( !bAlways ) ? SystemTimeToLocalTime( _pPrinterData->_dwStartTime ) : 0;
StartTime.wHour = static_cast<WORD>( dwLocalStartTime / 60 );
StartTime.wMinute = static_cast<WORD>( dwLocalStartTime % 60 );
DateTime_SetSystemtime(GetDlgItem( _hDlg, IDC_START_TIME ), GDT_VALID, &StartTime );
//
// Set the until time.
//
SYSTEMTIME UntilTime = { 0 };
DWORD dwLocalUntilTime = 0;
GetLocalTime( &UntilTime );
dwLocalUntilTime = ( !bAlways ) ? SystemTimeToLocalTime( _pPrinterData->_dwUntilTime ) : 0;
UntilTime.wHour = static_cast<WORD>( dwLocalUntilTime / 60 );
UntilTime.wMinute = static_cast<WORD>( dwLocalUntilTime % 60 );
DateTime_SetSystemtime(GetDlgItem( _hDlg, IDC_UNTIL_TIME ), GDT_VALID, &UntilTime );
return TRUE;
}
BOOL
TPrinterJobScheduling::
bSetUI(
VOID
)
{
//
// Fill the drivers list.
//
bFillAndSelectDrivers();
//
// Set bAlways flag.
//
BOOL bAlways = ( _pPrinterData->dwStartTime() == _pPrinterData->dwUntilTime( ));
//
// Set the start and until times.
//
(VOID)bSetStartAndUntilTime();
//
// Set Availability radio buttons.
//
CheckRadioButton( _hDlg, IDC_ALWAYS, IDC_START,
bAlways ? IDC_ALWAYS : IDC_START );
if( !_pPrinterData->bAdministrator( )){
vEnableAvailable( FALSE );
} else {
vEnableAvailable( !bAlways );
}
//
// Set the current priority.
//
SendDlgItemMessage( _hDlg, IDC_PRIORITY, EM_SETLIMITTEXT, 2, 0 );
SendDlgItemMessage( _hDlg, IDC_PRIORITY_UPDOWN, UDM_SETRANGE, 0, MAKELPARAM( 99, 1 ));
SendDlgItemMessage( _hDlg, IDC_PRIORITY_UPDOWN, UDM_SETPOS, 0, MAKELPARAM( _pPrinterData->dwPriority(), 0 ) );
//
// Set the attribte bit UI.
//
DWORD dwAttributes = _pPrinterData->dwAttributes();
vSetCheck( _hDlg,
IDC_DEVQUERYPRINT,
dwAttributes & PRINTER_ATTRIBUTE_ENABLE_DEVQ );
vSetCheck( _hDlg,
IDC_PRINT_SPOOLED_FIRST,
dwAttributes & PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST );
vSetCheck( _hDlg,
IDC_KEEP_PRINTED_JOBS,
dwAttributes & PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS );
vSetCheck( _hDlg,
IDC_SPOOL_DATATYPE,
!(dwAttributes & PRINTER_ATTRIBUTE_RAW_ONLY) );
//
// Set spool radio buttons.
// bQueued -> Spool entire document.
// both -> Spool entire document.
// neither -> Spool and print after first page.
// bDirect -> Direct.
//
BOOL bSpool = !( dwAttributes & PRINTER_ATTRIBUTE_DIRECT ) ||
( dwAttributes & PRINTER_ATTRIBUTE_QUEUED );
CheckRadioButton( _hDlg, IDC_SPOOL, IDC_PRINT_DIRECT,
bSpool ? IDC_SPOOL : IDC_PRINT_DIRECT );
CheckRadioButton( _hDlg, IDC_SPOOL_ALL, IDC_SPOOL_PRINT_FASTER,
( dwAttributes & PRINTER_ATTRIBUTE_QUEUED ) ? IDC_SPOOL_ALL : IDC_SPOOL_PRINT_FASTER );
vEnableCtl( _hDlg, IDC_SPOOL_ALL, bSpool );
vEnableCtl( _hDlg, IDC_SPOOL_PRINT_FASTER, bSpool );
vEnableCtl( _hDlg, IDC_PRINT_SPOOLED_FIRST, bSpool );
vEnableCtl( _hDlg, IDC_DEVQUERYPRINT, bSpool );
vEnableCtl( _hDlg, IDC_KEEP_PRINTED_JOBS, bSpool );
vEnableCtl( _hDlg, IDC_SPOOL_DATATYPE, bSpool );
//
// Enable appropriately.
//
static UINT auControl[] = {
IDC_ALWAYS,
IDC_START,
IDC_SPOOL,
IDC_SPOOL_ALL,
IDC_SPOOL_PRINT_FASTER,
IDC_PRINT_DIRECT,
IDC_DEVQUERYPRINT,
IDC_PRINT_SPOOLED_FIRST,
IDC_KEEP_PRINTED_JOBS,
IDC_SPOOL_DATATYPE,
IDC_SEPARATOR,
IDC_PRINT_PROC,
IDC_GLOBAL_DOCUMENT_DEFAULTS,
IDC_TEXT_PRIORITY,
IDC_PRIORITY,
IDC_PRIORITY_UPDOWN,
IDC_TEXT_DRIVER,
IDC_DRIVER_NAME,
IDC_DRIVER_NEW,
0
};
COUNT i;
if( !_pPrinterData->bAdministrator( )){
for( i=0; auControl[i]; ++i ){
vEnableCtl( _hDlg, auControl[i], FALSE );
}
}
//
// Set the "New Drivers..." button depending on the value of _bServerFullAccess
//
vEnableCtl( _hDlg, IDC_DRIVER_NEW, _pPrinterData->bServerFullAccess() );
if( _pPrinterData->_bDriverPagesNotLoaded )
{
ShowWindow( GetDlgItem( _hDlg, IDC_GLOBAL_DOCUMENT_DEFAULTS ), SW_HIDE );
}
//
// Indicate SetUI is done. This is used to
// prevent ReadUI from reading junk since edit controls
// recieve EN_CHANGE messages while in WM_INITDIALOG
//
_bSetUIDone = TRUE;
return TRUE;
}
VOID
TPrinterJobScheduling::
vReadUI(
VOID
)
{
TStatusB bStatus;
//
// Read the priority setting.
//
_pPrinterData->_dwPriority = (DWORD)SendDlgItemMessage( _hDlg, IDC_PRIORITY_UPDOWN, UDM_GETPOS, 0, 0 );
//
// Get the current attribute.
//
DWORD dwAttributes = _pPrinterData->dwAttributes();
//
// Mask out attributes we are going to read back.
//
dwAttributes &= ~( PRINTER_ATTRIBUTE_ENABLE_DEVQ |
PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST |
PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS |
PRINTER_ATTRIBUTE_QUEUED |
PRINTER_ATTRIBUTE_DIRECT );
if( BST_CHECKED == IsDlgButtonChecked( _hDlg, IDC_DEVQUERYPRINT )){
dwAttributes |= PRINTER_ATTRIBUTE_ENABLE_DEVQ;
}
if( BST_CHECKED == IsDlgButtonChecked( _hDlg, IDC_PRINT_SPOOLED_FIRST )){
dwAttributes |= PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST;
}
if( BST_CHECKED == IsDlgButtonChecked( _hDlg, IDC_KEEP_PRINTED_JOBS )){
dwAttributes |= PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS;
}
if( BST_CHECKED == IsDlgButtonChecked( _hDlg, IDC_SPOOL_DATATYPE )){
dwAttributes &= ~PRINTER_ATTRIBUTE_RAW_ONLY;
}else{
dwAttributes |= PRINTER_ATTRIBUTE_RAW_ONLY;
}
//
// Get radio buttons. If direct is selected, then ignore
// all the other spool fields.
//
if( BST_CHECKED == IsDlgButtonChecked( _hDlg, IDC_PRINT_DIRECT )){
//
// Direct, no spooling options selected.
//
dwAttributes |= PRINTER_ATTRIBUTE_DIRECT;
} else {
//
// Spool, print after last page -> QUEUED.
// Spool, print after first page -> neither.
//
if( BST_CHECKED == IsDlgButtonChecked( _hDlg, IDC_SPOOL_ALL )){
dwAttributes |= PRINTER_ATTRIBUTE_QUEUED;
}
}
_pPrinterData->_dwAttributes = dwAttributes;
//
// Get availability time if the printer is always
// available then set the time to no time restriction.
//
if( bGetCheck( _hDlg, IDC_ALWAYS ) ){
_pPrinterData->_dwStartTime = 0;
_pPrinterData->_dwUntilTime = 0;
} else {
//
// Get the Start time.
//
SYSTEMTIME StartTime;
DateTime_GetSystemtime( GetDlgItem( _hDlg, IDC_START_TIME ), &StartTime );
_pPrinterData->_dwStartTime = LocalTimeToSystemTime( StartTime.wHour * 60 + StartTime.wMinute );
//
// Get the Until time.
//
SYSTEMTIME UntilTime;
DateTime_GetSystemtime( GetDlgItem( _hDlg, IDC_UNTIL_TIME ), &UntilTime );
_pPrinterData->_dwUntilTime = LocalTimeToSystemTime( UntilTime.wHour * 60 + UntilTime.wMinute );
//
// If the printer start and until time are the same this is
// exactly the same as always available.
//
if( _pPrinterData->_dwStartTime == _pPrinterData->_dwUntilTime )
{
_pPrinterData->_dwStartTime = 0;
_pPrinterData->_dwUntilTime = 0;
}
}
//
// Read the driver name
//
bStatus DBGCHK = bGetEditText( _hDlg, IDC_DRIVER_NAME, _pPrinterData->strDriverName());
if( !bStatus )
{
_pPrinterData->_bErrorSaving = TRUE;
vShowResourceError( _hDlg );
}
}
BOOL
TPrinterJobScheduling::
_bHandleMessage(
IN UINT uMsg,
IN WPARAM wParam,
IN LPARAM lParam
)
{
TStatusB bStatus;
bStatus DBGNOCHK = TRUE;
switch( uMsg ){
case WM_INITDIALOG:
bStatus DBGCHK = bSetUI();
break;
case WM_APP:
vSetActive();
break;
case WM_HELP:
case WM_CONTEXTMENU:
PrintUIHelp( uMsg, _hDlg, wParam, lParam );
break;
case WM_WININICHANGE:
vSetActive();
break;
case WM_COMMAND:
switch( GET_WM_COMMAND_ID( wParam, lParam )){
case IDC_SPOOL:
vEnableCtl( _hDlg, IDC_SPOOL_ALL, TRUE );
vEnableCtl( _hDlg, IDC_SPOOL_PRINT_FASTER, TRUE );
vEnableCtl( _hDlg, IDC_PRINT_SPOOLED_FIRST, TRUE );
vEnableCtl( _hDlg, IDC_DEVQUERYPRINT, TRUE );
vEnableCtl( _hDlg, IDC_KEEP_PRINTED_JOBS, TRUE );
vEnableCtl( _hDlg, IDC_SPOOL_DATATYPE, TRUE );
break;
case IDC_PRINT_DIRECT:
vEnableCtl( _hDlg, IDC_SPOOL_ALL, FALSE );
vEnableCtl( _hDlg, IDC_SPOOL_PRINT_FASTER, FALSE );
vEnableCtl( _hDlg, IDC_PRINT_SPOOLED_FIRST, FALSE );
vEnableCtl( _hDlg, IDC_DEVQUERYPRINT, FALSE );
vEnableCtl( _hDlg, IDC_KEEP_PRINTED_JOBS, FALSE );
vEnableCtl( _hDlg, IDC_SPOOL_DATATYPE, FALSE );
break;
case IDC_ALWAYS:
vEnableAvailable( FALSE );
break;
case IDC_START:
vEnableAvailable( TRUE );
break;
case IDC_DEVQUERYPRINT:
case IDC_PRINT_SPOOLED_FIRST:
case IDC_KEEP_PRINTED_JOBS:
case IDC_SPOOL_ALL:
case IDC_SPOOL_PRINT_FASTER:
case IDC_SPOOL_DATATYPE:
case IDC_DRIVER_NAME:
break;
case IDC_PRIORITY:
bStatus DBGNOCHK = GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE;
break;
case IDC_SEPARATOR:
vSeparatorPage();
break;
case IDC_PRINT_PROC:
vPrintProcessor();
break;
case IDC_GLOBAL_DOCUMENT_DEFAULTS:
vHandleGlobalDocumentDefaults( wParam, lParam );
break;
case IDC_DRIVER_NEW:
vHandleNewDriver( wParam, lParam );
break;
default:
bStatus DBGNOCHK = FALSE;
break;
}
break;
case WM_NOTIFY:
{
LPNMHDR pnmh = (LPNMHDR)lParam;
switch( wParam )
{
case 0:
{
switch( pnmh->code )
{
case PSN_KILLACTIVE:
vReadUI();
break;
case PSN_SETACTIVE:
vSetActive();
break;
default:
bStatus DBGNOCHK = FALSE;
break;
}
}
break;
case IDC_START_TIME:
case IDC_UNTIL_TIME:
{
switch( pnmh->code )
{
case DTN_DATETIMECHANGE:
break;
default:
bStatus DBGNOCHK = FALSE;
break;
}
}
break;
default:
bStatus DBGNOCHK = FALSE;
break;
}
}
break;
default:
bStatus DBGNOCHK = FALSE;
break;
}
//
// If a message was handled read the ui from the dialog
//
if( bStatus && _bSetUIDone )
{
vReadUI();
}
return bStatus;
}
VOID
TPrinterJobScheduling::
vSeparatorPage(
VOID
)
{
//
// Create separator page dialog.
//
TSeparatorPage SeparatorPage( _hDlg,
_pPrinterData->strSepFile(),
_pPrinterData->bAdministrator(),
_pPrinterData->strServerName().bEmpty() );
//
// Check if separator page dialog created ok.
//
if( !VALID_OBJ( SeparatorPage )){
iMessage( _hDlg,
IDS_ERR_PRINTER_PROP_TITLE,
TSeparatorPage::kErrorMessage,
MB_OK|MB_ICONHAND,
kMsgNone,
NULL );
return;
}
//
// Interact with the separator page.
//
if( SeparatorPage.bDoModal() ){
//
// Assign back the separator page.
//
if( !_pPrinterData->strSepFile().bUpdate( SeparatorPage.strSeparatorPage() ) ){
vShowResourceError( _hDlg );
}
}
}
VOID
TPrinterJobScheduling::
vPrintProcessor(
VOID
)
{
//
// Create print processor dialog.
//
TPrintProcessor PrintProcessor( _hDlg,
_pPrinterData->strServerName(),
_pPrinterData->strPrintProcessor(),
_pPrinterData->strDatatype(),
_pPrinterData->bAdministrator() );
//
// Check if print processor dialog was created ok.
//
if( !VALID_OBJ( PrintProcessor )){
iMessage( _hDlg,
IDS_ERR_PRINTER_PROP_TITLE,
TPrintProcessor::kErrorMessage,
MB_OK|MB_ICONHAND,
kMsgNone,
NULL );
return;
}
//
// Interact with the print processor page.
//
if( PrintProcessor.bDoModal() ){
//
// Assign back the print proccesor and data type.
//
if( !_pPrinterData->strPrintProcessor().bUpdate( PrintProcessor.strPrintProcessor() ) ||
!_pPrinterData->strDatatype().bUpdate( PrintProcessor.strDatatype() ) ){
vShowResourceError( _hDlg );
}
}
}
VOID
TPrinterJobScheduling::
vHandleGlobalDocumentDefaults(
IN WPARAM wParam,
IN LPARAM lParam
)
/*++
Routine Description:
Handle launching global document defaults dialog.
Arguments:
wParam - Parameter passed to by dialog proc.
lParam - Parameter passed to by dialog proc.
Return Value:
Nothing.
--*/
{
(VOID)dwDocumentDefaultsInternal( _hDlg,
_pPrinterData->strCurrentPrinterName(),
SW_SHOW,
0,
0,
TRUE );
}
BOOL
TPrinterJobScheduling::
bFillAndSelectDrivers(
VOID
)
{
TStatusB bStatus;
PDRIVER_INFO_2 pDriverInfo2 = NULL;
DWORD cDrivers = 0;
DWORD cbDriverInfo2 = 0;
HWND hCtlDrivers = NULL;
//
// Enum the printer drivers on this machine.
//
bStatus DBGCHK = VDataRefresh::bEnumDrivers( _pPrinterData->pszServerName(),
_pPrinterData->strDriverEnv(),
2,
(PVOID *)&pDriverInfo2,
&cbDriverInfo2,
&cDrivers );
if( !bStatus ){
DBGMSG( DBG_WARN, ( "bFillAndSelectDrivers bEnumDriver failed with %d\n", GetLastError() ));
return FALSE;
}
//
// Fill in the driver information.
//
hCtlDrivers = GetDlgItem( _hDlg, IDC_DRIVER_NAME );
ComboBox_ResetContent( hCtlDrivers );
for( UINT i = 0; i < cDrivers; ++i ){
//
// Add only compatible driver versions.
//
if( bIsCompatibleDriverVersion( _pPrinterData->dwDriverVersion(), pDriverInfo2[i].cVersion ) )
{
//
// Never add the fax driver, we do not permit user to switch from a printer
// driver to a fax driver.
//
if( _tcscmp( pDriverInfo2[i].pName, FAX_DRIVER_NAME ) )
{
//
// Filter out duplicates. There could be a version 2 and version 3 etc drivers installed.
// The spooler SetPrinter api does not make a distiction between different
// driver versions, since it only accepts a printer driver name.
//
if( SendMessage( hCtlDrivers, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)pDriverInfo2[i].pName ) == CB_ERR )
{
ComboBox_AddString( hCtlDrivers, pDriverInfo2[i].pName );
}
}
}
}
//
// Release the driver information.
//
FreeMem( pDriverInfo2 );
INT iStatus = ComboBox_SelectString( hCtlDrivers,
-1,
_pPrinterData->strDriverName( ));
//
// The problem here is that the server many not have the driver
// for the client enviroment, so we need to jam in the extra driver
// name if iStatus is -1 (failure case).
//
if( iStatus == -1 ){
DBGMSG( DBG_PROPSINFO, ( "bFillAndSelectDrivers: driver "TSTR" not on server\n", (LPCTSTR)_pPrinterData->strDriverName() ));
ComboBox_AddString( hCtlDrivers, _pPrinterData->strDriverName( ));
INT iSelectResult = ComboBox_SelectString( hCtlDrivers,
-1,
_pPrinterData->strDriverName( ));
if( iSelectResult < 0 ){
DBGMSG( DBG_WARN,( "bFillAndSelectDrivers: driver "TSTR" select failed %d\n", (LPCTSTR)_pPrinterData->strDriverName(), iSelectResult ));
}
}
return TRUE;
}
VOID
TPrinterJobScheduling::
vHandleNewDriver(
IN WPARAM wParam,
IN LPARAM lParam
)
{
TStatusB bStatus;
TCHAR szDriverName[MAX_PATH];
UINT cchDriverNameSize = 0;
//
// Setup a new driver.
//
bStatus DBGCHK = bPrinterSetup( _hDlg,
MSP_NEWDRIVER,
COUNTOF( szDriverName ),
szDriverName,
&cchDriverNameSize,
_pPrinterData->pszServerName() );
//
// If new driver installed ok update the combo box.
//
if( bStatus )
{
//
// If a new driver was added, check if it already exists in the
// the list of drivers.
//
if( SendDlgItemMessage( _hDlg,
IDC_DRIVER_NAME,
CB_FINDSTRINGEXACT,
(WPARAM)-1,
(LPARAM)szDriverName ) == CB_ERR )
{
//
// Add the the new driver to the combo box.
//
ComboBox_AddString( GetDlgItem( _hDlg, IDC_DRIVER_NAME ), szDriverName );
}
//
// Select this newly added driver.
//
ComboBox_SelectString( GetDlgItem( _hDlg, IDC_DRIVER_NAME ), -1, szDriverName );
}
}
/********************************************************************
Sharing.
********************************************************************/
TPrinterSharing::
TPrinterSharing(
TPrinterData* pPrinterData
) : TPrinterProp( pPrinterData ),
_pPrtShare( NULL ),
_bHideListed( TRUE ),
_bSetUIDone( FALSE ),
_bAcceptInvalidDosShareName( FALSE ),
_bDefaultPublishState( TRUE ),
_bSharingEnabled( TRUE )
{
}
TPrinterSharing::
~TPrinterSharing(
VOID
)
{
delete _pPrtShare;
}
BOOL
TPrinterSharing::
bValid(
VOID
)
{
return TPrinterProp::bValid();
}
VOID
TPrinterSharing::
vSharePrinter(
VOID
)
/*++
Routine Description:
User clicked share radio button. Change the UI appropriately.
Arguments:
Return Value:
--*/
{
//
// Set radio button and possibly enable window.
//
CheckRadioButton( _hDlg, IDC_SHARED_OFF, IDC_SHARED, IDC_SHARED );
if( _pPrinterData->bAdministrator()){
//
// Set the default share name.
//
vSetDefaultShareName();
vEnableCtl( _hDlg, IDC_DS_OPERATION_PENDING, TRUE );
vEnableCtl( _hDlg, IDC_LABEL_SHARENAME, TRUE );
vEnableCtl( _hDlg, IDC_SHARED_NAME, TRUE );
vEnableCtl( _hDlg, IDC_PUBLISHED, TRUE );
//
// Set the focus to the edit control.
//
SetFocus( GetDlgItem( _hDlg, IDC_SHARED_NAME ) );
//
// Select the share name exit text.
//
Edit_SetSel( GetDlgItem( _hDlg, IDC_SHARED_NAME ), 0, -1 );
//
// Set the published check box.
//
if( !_bHideListed )
{
vSetCheck( _hDlg, IDC_PUBLISHED, _bDefaultPublishState );
}
}
}
VOID
TPrinterSharing::
vUnsharePrinter(
VOID
)
/*++
Routine Description:
User clicked don't share radio button. Change the UI appropriately.
Arguments:
Return Value:
--*/
{
//
// Set radio button and disable window.
//
CheckRadioButton( _hDlg, IDC_SHARED_OFF, IDC_SHARED, IDC_SHARED_OFF );
vEnableCtl( _hDlg, IDC_DS_OPERATION_PENDING, FALSE );
vEnableCtl( _hDlg, IDC_LABEL_SHARENAME, FALSE );
vEnableCtl( _hDlg, IDC_SHARED_NAME, FALSE );
vEnableCtl( _hDlg, IDC_PUBLISHED, FALSE );
//
// Clear the published check box.
//
if( !_bHideListed )
{
vSetCheck( _hDlg, IDC_PUBLISHED, FALSE );
}
}
VOID
TPrinterSharing::
vSetDefaultShareName(
VOID
)
/*++
Routine Description:
Sets the default share name if use has choosen to share
this printer. We will update the share name if
this is the first time setting the share name.
Arguments:
None.
Return Value:
Nothing.
--*/
{
TStatusB bStatus;
TString strShareName;
//
// Read the current contents of the edit control.
//
bStatus DBGCHK = bGetEditText( _hDlg, IDC_SHARED_NAME, strShareName );
DBGMSG( DBG_TRACE, ( "strShareName " TSTR "\n", (LPCTSTR)strShareName ) );
//
// Create a share name if the current edit field is empty.
//
if( strShareName.bEmpty() ){
//
// If the share object has not be constructed, then
// construct it.
//
if( !_pPrtShare ){
_pPrtShare = new TPrtShare( _pPrinterData->pszServerName() );
}
//
// Ensure the share object is still valid.
//
if( VALID_PTR( _pPrtShare ) ){
//
// Get just the printer name.
//
LPCTSTR pszServer;
LPCTSTR pszPrinter;
TCHAR szScratch[kPrinterBufMax];
vPrinterSplitFullName( szScratch,
ARRAYSIZE(szScratch),
_pPrinterData->strPrinterName( ),
&pszServer,
&pszPrinter );
//
// Create valid unique share name.
//
bStatus DBGNOCHK = _pPrtShare->bNewShareName( strShareName, pszPrinter );
//
// Set the default share name.
//
bStatus DBGCHK = bSetEditText( _hDlg, IDC_SHARED_NAME, strShareName );
}
}
}
BOOL
TPrinterSharing::
bSetUI(
VOID
)
{
//
// Set of controls on this page.
//
static UINT auShared[] = { IDC_SHARED_NAME,
IDC_SHARED,
IDC_SHARED_OFF,
IDC_PUBLISHED,
IDC_SERVER_PROPERTIES,
IDC_LABEL_SHARENAME,
IDC_SHARING_ENABLED_GROUPBOX,
IDC_SHARING_INFOTEXT,
0 };
static UINT auSharingNotSupported[] = { IDC_NAME,
IDC_SHARING_DISABLED,
IDC_DIVIDER6,
IDC_ENABLE_SHARING,
0 };
TStatusB bStatus;
TString strText;
TString strDirName;
BOOL bSharingNotSupported = FALSE;
if( FALSE == _bSharingEnabled && FALSE == _pPrinterData->bHideSharingUI() ) {
//
// Change the text of the link control to point the user to the
// home networking wizard (HNW)
//
TString strText;
bStatus DBGCHK = strText.bLoadString(ghInst, IDS_TEXT_SHARING_NOT_ENABLED);
if (bStatus) {
bSetEditText(_hDlg, IDC_SHARING_DISABLED, strText);
}
} else {
//
// If we're here sharing is either enabled or not supported for
// the selected printer. Sharing may not be supported for some
// special type of printers like fax printers and/or masq
// printers (http printers or downlevel printers like win9x,
// Novell, Solaris, Linux, etc...)
//
bSharingNotSupported = TRUE;
}
//
// If the sharing UI is to be hidded then remove all the controls.
//
if( FALSE == _bSharingEnabled || _pPrinterData->bHideSharingUI() ){
//
// Hide the sharing controls.
//
for( UINT i=0; auShared[i]; ++i ){
ShowWindow( GetDlgItem( _hDlg, auShared[i] ), SW_HIDE );
}
//
// Show the sharing not supported/enabled controls.
//
for( UINT i=0; auSharingNotSupported[i]; ++i ){
if( bSharingNotSupported && IDC_ENABLE_SHARING == auSharingNotSupported[i] ) {
//
// Skip enabling this control.
//
continue;
}
ShowWindow( GetDlgItem( _hDlg, auSharingNotSupported[i] ), SW_NORMAL );
}
//
// Hide a few controls that are not in the array.
//
ShowWindow( GetDlgItem( _hDlg, IDC_SHARING_GBOX ), SW_HIDE );
ShowWindow( GetDlgItem( _hDlg, IDC_ADDITIONAL_DRIVERS_TEXT2 ), SW_HIDE );
}
else
{
//
// Show the sharing controls.
//
for( UINT i=0; auShared[i]; ++i ){
ShowWindow( GetDlgItem( _hDlg, auShared[i] ), SW_NORMAL );
}
//
// Hide the sharing not supported/enabled controls.
//
for( UINT i=0; auSharingNotSupported[i]; ++i ){
ShowWindow( GetDlgItem( _hDlg, auSharingNotSupported[i] ), SW_HIDE );
}
//
// Show a few controls that are not in the array.
//
ShowWindow( GetDlgItem( _hDlg, IDC_SHARING_GBOX ), SW_NORMAL );
ShowWindow( GetDlgItem( _hDlg, IDC_ADDITIONAL_DRIVERS_TEXT2 ), SW_NORMAL );
}
//
// Save the origianal share name.
//
bStatus DBGCHK = _strShareName.bUpdate( _pPrinterData->strShareName() );
//
// Set the printer share name limit. The limit in win9x is
// 8.3 == 12+1 chars (including NULL terminator). The Winnt limit
// is defined as NNLEN;
//
SendDlgItemMessage( _hDlg, IDC_SHARED_NAME, EM_SETLIMITTEXT, kPrinterShareNameMax, 0 );
//
// Update the fields.
//
bSetEditText( _hDlg, IDC_SHARED_NAME, _pPrinterData->strShareName( ));
//
// Get the flag that indicates we need to display the listed in the directory
// check box.
//
_bHideListed = _pPrinterData->ePrinterPublishState() == TPrinterData::kNoDsAvailable;
//
// If this is a masq printer do not show the publish UI, we do not allow publishing
// of masq printer. The definition of a masq printer is a printer connection that
// happens to be implemented as a local printer with a re-directed port. So masq
// printer should be treated like printer connections a per user resouce.
//
if( _pPrinterData->_dwAttributes & PRINTER_ATTRIBUTE_NETWORK && _pPrinterData->_dwAttributes & PRINTER_ATTRIBUTE_LOCAL )
{
_bHideListed = TRUE;
}
//
// If we have decided not to hide the listed in the directory then check
// if the spooler policy bit will allow the user to actually publish the
// printer.
//
if( !_bHideListed )
{
//
// Check this policy only if we are administering a
// local printer. Otherwise show the publishing UI would
//
if( !_pPrinterData->_pszServerName )
{
//
// Read the per machine policy bit that the spooler uses for
// controlling printer publishing.
//
TPersist SpoolerPolicy( gszSpoolerPolicy, TPersist::kOpen|TPersist::kRead, HKEY_LOCAL_MACHINE );
if( VALID_OBJ( SpoolerPolicy ) )
{
BOOL bCanPublish;
bStatus DBGNOCHK = SpoolerPolicy.bRead( gszSpoolerPublish, bCanPublish );
if( bStatus )
{
_bHideListed = !bCanPublish;
}
}
}
//
// Read the per user default publish policy bit.
//
TPersist Policy( gszAddPrinterWizardPolicy, TPersist::kOpen|TPersist::kRead, HKEY_LOCAL_MACHINE );
if( VALID_OBJ( Policy ) )
{
bStatus DBGNOCHK = Policy.bRead( gszAPWPublish, _bDefaultPublishState );
}
}
//
// Hide the publish controls if the DS is not loaded or we are viewing
// a downlevel spooler.
//
if( _bHideListed ){
//
// Hide the publish check box.
//
ShowWindow( GetDlgItem( _hDlg, IDC_PUBLISHED ), SW_HIDE );
ShowWindow( GetDlgItem( _hDlg, IDC_DS_OPERATION_PENDING ), SW_HIDE );
} else {
//
// Load the pending string.
//
bStatus DBGCHK = _strPendingText.bLoadString( ghInst, IDS_DS_PENDING_TEXT );
}
//
// Select correct radio button.
//
if( _pPrinterData->dwAttributes() & PRINTER_ATTRIBUTE_SHARED ){
vSharePrinter();
} else {
vUnsharePrinter();
}
//
// Check the published check box if the printer is published.
//
if( _pPrinterData->dwAttributes() & PRINTER_ATTRIBUTE_PUBLISHED ){
vSetCheck( _hDlg, IDC_PUBLISHED, TRUE );
} else {
vSetCheck( _hDlg, IDC_PUBLISHED, FALSE );
}
//
// If not an administrator, or the network is not installed
// disable the edit controls.
//
if( !_pPrinterData->bAdministrator( ) || !TPrtShare::bNetworkInstalled() ){
for( UINT i=0; auShared[i]; ++i ){
vEnableCtl( _hDlg, auShared[i], FALSE );
}
}
//
// Set the "Additional Drivers..." button depending on the value of _bServerFullAccess
//
vEnableCtl( _hDlg, IDC_SHARING_GBOX, _pPrinterData->bServerFullAccess() );
vEnableCtl( _hDlg, IDC_ADDITIONAL_DRIVERS_TEXT2, _pPrinterData->bServerFullAccess() );
vEnableCtl( _hDlg, IDC_SERVER_PROPERTIES, _pPrinterData->bServerFullAccess() );
//
// Special case the share name if we are not an administrator make the share name
// a read only control rather than a grayed out edit control.
//
if( !_pPrinterData->bAdministrator( ) || !TPrtShare::bNetworkInstalled() ){
SendDlgItemMessage( _hDlg, IDC_SHARED_NAME, EM_SETREADONLY, TRUE, 0);
vEnableCtl( _hDlg, IDC_SHARED_NAME, TRUE );
}
//
// There are a few UI elements that need to be set when
// we are activated, because of a driver change. We
// will artifically do it now.
//
vSetActive();
// Indicate SetUI is done. This is used to
// prevent ReadUI from reading junk since edit controls
// can recieve EN_CHANGE messages before WM_INITDIALOG
//
_bSetUIDone = TRUE;
return TRUE;
}
VOID
TPrinterSharing::
vReadUI(
VOID
)
{
TStatusB bStatus;
//
// Check if the printer has been shared.
//
if( BST_CHECKED == IsDlgButtonChecked( _hDlg, IDC_SHARED_OFF )){
//
// Indicate the printer is not share.
//
_pPrinterData->dwAttributes() &= ~PRINTER_ATTRIBUTE_SHARED;
} else {
//
// Indicate printer is shared.
//
_pPrinterData->dwAttributes() |= PRINTER_ATTRIBUTE_SHARED;
}
//
// Do nothing with the publish state if the DS is not available.
//
if( _pPrinterData->ePrinterPublishState() != TPrinterData::kNoDsAvailable ){
//
// Check the current publish state.
//
TPrinterData::EPublishState bSelectedPublisheState = bGetCheck( _hDlg, IDC_PUBLISHED ) ?
TPrinterData::kPublished : TPrinterData::kNotPublished;
//
// If the printer is not shared then indicate the seleceted state is not
// published. This will either result in no action or a unpublish.
//
if( !( _pPrinterData->dwAttributes() & PRINTER_ATTRIBUTE_SHARED ) ){
bSelectedPublisheState = TPrinterData::kNotPublished;
}
//
// If the publish state matched the current state then do nothing.
//
if( bSelectedPublisheState == _pPrinterData->ePrinterPublishState() ){
_pPrinterData->ePrinterPublishState( TPrinterData::kNoAction );
} else {
//
// Update the publish action.
//
if( bSelectedPublisheState == TPrinterData::kPublished ){
_pPrinterData->ePrinterPublishState( TPrinterData::kPublish );
} else {
_pPrinterData->ePrinterPublishState( TPrinterData::kUnPublish );
}
}
//
// Set the new publish action.
//
switch ( _pPrinterData->ePrinterPublishState() )
{
case TPrinterData::kPublish:
_pPrinterData->_dwAction = DSPRINT_PUBLISH | _pPrinterData->_dwAction & DSPRINT_PENDING;
break;
case TPrinterData::kUnPublish:
_pPrinterData->_dwAction = DSPRINT_UNPUBLISH | _pPrinterData->_dwAction & DSPRINT_PENDING;
break;
case TPrinterData::kNoAction:
default:
break;
}
}
//
// Get the share name from the edit control.
//
bStatus DBGCHK = bGetEditText( _hDlg, IDC_SHARED_NAME, _pPrinterData->strShareName() );
if( !bStatus )
{
_pPrinterData->_bErrorSaving = TRUE;
vShowResourceError( _hDlg );
}
}
BOOL
TPrinterSharing::
bKillActive(
VOID
)
/*++
Routine Description:
Validate that the share page is in a consistent state.
Arguments:
None.
Return Value:
TRUE - Ok to kill active, FALSE = can't kill active, UI displayed.
--*/
{
BOOL bStatus = TRUE;
//
// Read the UI in to the printer data.
//
vReadUI();
//
// If not shared then just return success.
//
if( !( _pPrinterData->_dwAttributes & PRINTER_ATTRIBUTE_SHARED ) )
{
return bStatus;
}
//
// If the share name has not changed then do nothing.
//
if( _strShareName == _pPrinterData->_strShareName )
{
return bStatus;
}
//
// If the share object has not been constructed, then create it.
//
if( !_pPrtShare )
{
//
// Construct the share object.
//
_pPrtShare = new TPrtShare( _pPrinterData->pszServerName() );
//
// Ensure we have a valid share object.
//
bStatus = VALID_PTR( _pPrtShare );
}
if( bStatus )
{
//
// If the share name is empty.
//
if( _pPrinterData->_strShareName.bEmpty() )
{
iMessage( _hDlg,
IDS_ERR_PRINTER_PROP_TITLE,
IDS_ERR_NO_SHARE_NAME,
MB_OK|MB_ICONSTOP,
kMsgNone,
NULL );
bStatus = FALSE;
}
}
if( bStatus )
{
//
// If share name is not a valid NT share name, put error message.
//
if( _pPrtShare->iIsValidNtShare( _pPrinterData->_strShareName ) != TPrtShare::kSuccess )
{
iMessage( _hDlg,
IDS_ERR_PRINTER_PROP_TITLE,
IDS_ERR_INVALID_CHAR_SHARENAME,
MB_OK|MB_ICONSTOP,
kMsgNone,
NULL );
bStatus = FALSE;
}
}
if( bStatus )
{
//
// Check if the share name is a valid DOS share.
//
if( !_bAcceptInvalidDosShareName && ( _pPrtShare->iIsValidDosShare( _pPrinterData->_strShareName ) != TPrtShare::kSuccess ) )
{
INT iStatus = iMessage( _hDlg,
IDS_ERR_PRINTER_PROP_TITLE,
IDS_ERR_SHARE_NAME_NOT_DOS,
MB_YESNO|MB_ICONEXCLAMATION,
kMsgNone,
NULL );
if( iStatus != IDYES )
{
bStatus = FALSE;
}
else
{
_bAcceptInvalidDosShareName = TRUE;
}
}
}
if( bStatus )
{
//
// If the share name confilcts with an existing name.
// If the previous name was ours and we were shared,
// do not display the error message.
//
if( !_pPrtShare->bIsValidShareNameForThisPrinter( _pPrinterData->_strShareName,
_pPrinterData->strPrinterName() ))
{
iMessage( _hDlg,
IDS_ERR_PRINTER_PROP_TITLE,
IDS_ERR_DUPLICATE_SHARE,
MB_OK|MB_ICONSTOP,
kMsgNone,
NULL );
bStatus = FALSE;
}
}
//
// Check if it is ok to loose the focus.
//
if( !bStatus )
{
//
// Set the focus to the shared as text.
//
SetFocus( GetDlgItem( _hDlg, IDC_SHARED_NAME ));
//
// Don't switch pages.
//
vSetDlgMsgResult( TRUE );
//
// Must return true to acknowledge the SetDlgMsgResult error.
//
bStatus = TRUE;
}
return bStatus;
}
VOID
TPrinterSharing::
vSetActive(
VOID
)
/*++
Routine Description:
Routine called when the pages is set active. This routine
will refresh the icon if it has changed.
Arguments:
None.
Return Value:
Nothing.
--*/
{
//
// Set the icon and printer name.
//
vSetIconName();
//
// Set the pending status.
//
if( _pPrinterData->_dwAction & DSPRINT_PENDING && !_bHideListed )
{
bSetEditText( _hDlg, IDC_DS_OPERATION_PENDING, _strPendingText );
}
else
{
bSetEditText( _hDlg, IDC_DS_OPERATION_PENDING, gszNULL );
}
}
VOID
TPrinterSharing::
vAdditionalDrivers(
IN WPARAM wParam,
IN LPARAM lParam
)
/*++
Routine Description:
Handle launching server prperties dialog.
Arguments:
wParam - Parameter passed to by dialog proc.
lParam - Parameter passed to by dialog proc.
Return Value:
Nothing.
--*/
{
BOOL bStatus = FALSE;
//
// Create additional drivers dialog.
//
TAdditionalDrivers Drivers( _hDlg,
_pPrinterData->strServerName(),
_pPrinterData->strPrinterName(),
_pPrinterData->strDriverName(),
_pPrinterData->bAdministrator() );
//
// Check if print processor dialog was created ok.
//
if( VALID_OBJ( Drivers ))
{
bStatus = TRUE;
if( Drivers.bDoModal() == IDOK )
{
vCancelToClose();
}
}
//
// If an error occurred then display an error message.
//
if( !bStatus )
{
iMessage( _hDlg,
IDS_ERR_PRINTER_PROP_TITLE,
IDS_ERR_ADD_DRV_ERROR,
MB_OK|MB_ICONHAND,
kMsgGetLastError,
NULL );
}
}
BOOL
TPrinterSharing::
_bHandleMessage(
IN UINT uMsg,
IN WPARAM wParam,
IN LPARAM lParam
)
{
TStatusB bStatus;
bStatus DBGNOCHK = TRUE;
switch (uMsg)
{
case WM_INITDIALOG:
{
//
// First we need to check if sharing is enabled. If sharing isn't
// enabled then we direct the user to the home networking wizard
// (HNW) to enable sharing.
//
BOOL bSharingEnabled;
if (SUCCEEDED(IsSharingEnabled(&bSharingEnabled)))
{
_bSharingEnabled = bSharingEnabled;
}
//
// Load the UI now...
//
bSetUI();
}
break;
case WM_SETTINGCHANGE:
{
//
// The home networking wizard (HNW) will send WM_SETTINGCHANGE when
// sharing options change. We need to check here and reload the UI
// if necessary.
//
BOOL bSharingEnabled;
if (SUCCEEDED(IsSharingEnabled(&bSharingEnabled)))
{
if (_bSharingEnabled != bSharingEnabled)
{
//
// The setting has changed - refresh the state and reload the UI.
//
_bSharingEnabled = bSharingEnabled;
bSetUI();
}
}
}
break;
case WM_APP:
vSetActive();
break;
case WM_HELP:
case WM_CONTEXTMENU:
PrintUIHelp(uMsg, _hDlg, wParam, lParam);
break;
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case IDC_SHARED_NAME:
bStatus DBGNOCHK = GET_WM_COMMAND_CMD(wParam, lParam) == EN_CHANGE;
//
// When we change the content of share name, we need to check dos-validate share name again
//
if (bStatus)
{
_bAcceptInvalidDosShareName = FALSE;
}
break;
case IDC_SHARED_OFF:
vUnsharePrinter();
break;
case IDC_SHARED:
vSharePrinter();
break;
case IDC_SERVER_PROPERTIES:
vAdditionalDrivers(wParam, lParam);
break;
case IDC_PUBLISHED:
break;
default:
bStatus DBGNOCHK = FALSE;
break;
}
break;
case WM_NOTIFY:
{
LPNMHDR pnmh = (LPNMHDR)lParam;
switch (pnmh->code)
{
case PSN_KILLACTIVE:
bStatus DBGNOCHK = bKillActive();
break;
case NM_RETURN:
case NM_CLICK:
if (IDC_SHARING_DISABLED == wParam)
{
//
// Launch the home networking wizard (HNW) to enable sharing.
//
BOOL bRebootRequired = FALSE;
bStatus DBGCHK = SUCCEEDED(LaunchHomeNetworkingWizard(_hDlg, &bRebootRequired));
if (bStatus && bRebootRequired)
{
//
// Reboot was requested. Note that if the user has made changes in the UI
// and hasn't hit the apply button then he'll loose those changes, but
// that should be OK because he still has the option to choose [No],
// apply the changes and then restart.
//
RestartDialogEx(_hDlg, NULL, EWX_REBOOT,
SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_MINOR_RECONFIG);
}
}
else if ( IDC_ENABLE_SHARING == wParam )
{
UINT iRet = DialogBox( ghInst, MAKEINTRESOURCE(IDD_SIMPLE_SHARE_ENABLE_WARNING), _hDlg, WarningDlgProc );
if ( IDC_RB_RUN_THE_WIZARD == iRet )
{
//
// Launch the home networking wizard (HNW) to enable sharing.
//
BOOL bRebootRequired = FALSE;
bStatus DBGCHK = SUCCEEDED(LaunchHomeNetworkingWizard(_hDlg, &bRebootRequired));
if (bStatus && bRebootRequired)
{
//
// Reboot was requested. Note that if the user has made changes in the UI
// and hasn't hit the apply button then he'll loose those changes, but
// that should be OK because he still has the option to choose [No],
// apply the changes and then restart.
//
RestartDialogEx(_hDlg, NULL, EWX_REBOOT,
SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_MINOR_RECONFIG);
}
}
else if ( IDC_RB_ENABLE_FILE_SHARING == iRet )
{
ILocalMachine *pLM;
HRESULT hr = CoCreateInstance(CLSID_ShellLocalMachine, NULL, CLSCTX_INPROC_SERVER, IID_ILocalMachine, (void**)&pLM);
if (SUCCEEDED(hr))
{
hr = pLM->EnableGuest(ILM_GUEST_NETWORK_LOGON);
pLM->Release();
if ( HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) == hr )
{
TString strTitle;
TString strMessage;
bStatus DBGCHK = strTitle.bLoadString( ghInst, IDS_ERR_ACCESS_DENIED );
bStatus DBGCHK = strMessage.bLoadString( ghInst, IDS_INSUFFICENT_PRIVILLEGE );
MessageBox( _hDlg, strMessage, strTitle, MB_OK );
}
//
// Let everybody else know we changed something.
//
SendNotifyMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0);
}
bStatus DBGNOCHK = SUCCEEDED(hr);
}
else
{
bStatus DBGNOCHK = FALSE;
}
}
else
{
bStatus DBGNOCHK = FALSE;
}
break;
default:
bStatus DBGNOCHK = FALSE;
break;
}
}
break;
default:
bStatus DBGNOCHK = FALSE;
break;
}
if (bStatus && _bSetUIDone)
{
vReadUI();
}
return bStatus;
}
/*++
Routine Description:
Dialog proc for the enabling sharing warning dialog.
Arguments:
Standard dialog message parameters.
Return Value:
EndDialog will return IDCANCEL if the user cancelled the dialog. EndDialog
will return IDC_RB_RUN_THE_WIZARD if the user selected to run the Wizard.
EndDialog will return IDC_RB_ENABLE_FILE_SHARING if the user selected to
bypass the wizard.
--*/
INT_PTR
WarningDlgProc(
IN HWND hWnd,
IN UINT msg,
IN WPARAM wParam,
IN LPARAM lParam
)
{
switch (msg)
{
case WM_INITDIALOG:
{
//
// Load warning icon from USER32.
//
HICON hIcon = LoadIcon(NULL, MAKEINTRESOURCE(IDI_WARNING));
if (hIcon)
{
SendDlgItemMessage(hWnd, IDC_ICON_INFO, STM_SETICON, (WPARAM )hIcon, 0L);
}
//
// Set default radio item.
//
SendDlgItemMessage(hWnd, IDC_RB_RUN_THE_WIZARD, BM_SETCHECK, BST_CHECKED, 0);
}
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDOK:
if ( BN_CLICKED == HIWORD(wParam) )
{
UINT iRet = SendDlgItemMessage(hWnd, IDC_RB_RUN_THE_WIZARD, BM_GETCHECK, 0, 0 );
if ( BST_CHECKED == iRet )
{
EndDialog(hWnd, IDC_RB_RUN_THE_WIZARD );
}
else
{
EndDialog(hWnd, IDC_RB_ENABLE_FILE_SHARING );
}
}
break;
case IDCANCEL:
if ( BN_CLICKED == HIWORD(wParam) )
{
EndDialog(hWnd, IDCANCEL);
return TRUE;
}
break;
}
break;
}
return FALSE;
}