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.
 
 
 
 
 
 

2490 lines
70 KiB

/*++
Copyright (C) Microsoft Corporation, 1996 - 1999
All rights reserved.
Module Name:
rundll.cxx
Abstract:
Run dll entry interface for lauching printer related
UI from shell extenstion and other shell related components.
Author:
Steve Kiraly (SteveKi) 29-Sept-1996
Revision History:
--*/
#include "precomp.hxx"
#pragma hdrstop
#include "rundll.hxx"
#include "getopt.hxx"
#include "parser.hxx"
#include "permc.hxx"
#include "asyncdlg.hxx"
#include "tstpage.hxx"
#include "time.hxx"
#include "psetup.hxx"
#include "drvsetup.hxx"
#include "instarch.hxx"
#include "portslv.hxx"
#include "dsinterf.hxx"
#include "prtprop.hxx"
#include "prtshare.hxx"
#include "dsinterf.hxx"
#include "drvsetup.hxx"
#include "driverif.hxx"
#include "driverlv.hxx"
#include "archlv.hxx"
#include "detect.hxx"
#include "setup.hxx"
#include "spllibex.hxx"
#include "spinterf.hxx"
#include "persist.hxx"
/*++
Routine Name:
PrintUIEntryW
Routine Description:
Interface for the Rundll32 process.
Arguments:
hwnd - Window handle of stub window.
hInstance, - Rundll instance handle.
pszCmdLine - Pointer to UNICOE command line.
nCmdShow - Show command value always TRUE.
Return Value:
Nothing.
--*/
DWORD
PrintUIEntryW(
IN HWND hwnd,
IN HINSTANCE hInstance,
IN LPCTSTR pszCmdLine,
IN UINT nCmdShow
)
{
DBGMSG( DBG_TRACE, ( "PrintUIEntryW interface\n" ) );
DBGMSG( DBG_TRACE, ( "hwnd %x\n", hwnd ) );
DBGMSG( DBG_TRACE, ( "hInstance %x\n", hInstance ) );
DBGMSG( DBG_TRACE, ( "pszCmdLine %ws\n", pszCmdLine ) );
DBGMSG( DBG_TRACE, ( "nCmdShow %d\n", nCmdShow ) );
DBGMSG( DBG_TRACE, ( "CommandLine %ws\n", GetCommandLine() ) );
//
// we need to count the error messages to see if necessary to
// show up UI in case of an error or if somebody has been done
// this already
//
CMsgBoxCounter msgCounter(MB_ICONSTOP|MB_ICONINFORMATION);
UINT ac = 0;
TCHAR **av = NULL;
BOOL bRetval = FALSE;
AParams Params = {0};
//
// Strip any trailing white space.
//
vStripTrailWhiteSpace( (LPTSTR)pszCmdLine );
//
// Convert the command line to an argv,
//
bRetval = StringToArgv( pszCmdLine, // Command line arguments
&ac, // Place to return arg count
&av, // Place to return argv
FALSE ); // There is no file name on the command line
if( bRetval )
{
//
// Store pointer to command line.
//
Params.pszCmdLine = pszCmdLine;
//
// Parse the command line argumens and execute the command.
//
bRetval = bDoCommand( hwnd, ac, av, &Params );
}
if( !bRetval )
{
//
// If we are not in quiet mode display error messsage.
//
if( !Params.Flags.IsQuiet && 0 == msgCounter.GetCount() )
{
switch( Params.dwLastError )
{
case ERROR_SUCCESS:
case ERROR_CANCELLED:
break;
case ERROR_ACCESS_DENIED:
{
// show up a friendly message that conform the shell32.dll
// message in this case. this is because this will be invoked
// primarily from shell32.dll from the runas commands
iMessage(NULL, IDS_PRINTERS_TITLE, IDS_FRIENDLY_ACCESSDENIED,
MB_OK|MB_ICONINFORMATION, kMsgNone, NULL);
}
break;
case ERROR_INVALID_PARAMETER:
{
// show up a friendly message to say that the arguments are invalid
iMessage(NULL, IDS_PRINTERS_TITLE, IDS_ERROR_INVALID_ARG,
MB_OK|MB_ICONSTOP, kMsgNone, NULL);
}
break;
default:
{
// we are going to show a generic error message here
iMessage(NULL, IDS_PRINTERS_TITLE, IDS_ERR_GENERIC,
MB_OK|MB_ICONSTOP, Params.dwLastError, NULL);
}
break;
}
}
//
// If the last error code was not set then set it to a generic
// error value. There is no way to trace the original error code
// We just chose one, ERROR_INVALID_FUNCTION
//
if( Params.dwLastError == ERROR_SUCCESS )
{
Params.dwLastError = GetLastError();
if( Params.dwLastError == ERROR_SUCCESS )
{
Params.dwLastError = ERROR_INVALID_FUNCTION;
}
}
}
//
// Ensure we release the command line argv.
//
ReleaseArgv( av );
//
// If something failed and the error code was not set then set
// the error to an unspecified error value.
//
if( !bRetval )
{
//
// Set the last error incase the caller ignores the return value.
//
SetLastError( Params.dwLastError );
}
return Params.dwLastError;
}
/*++
Routine Name:
bDoCommand
Routine Description:
Parses the commmand line passed by rundll32.
Arguments:
hwnd - Parent window handle.
ac - Number of strings.
av - Pointer to an array of pointer to strings.
Return Value:
TRUE function complete ok. FALSE error occurred.
--*/
BOOL
bDoCommand(
IN HWND hwnd,
IN INT ac,
IN LPTSTR *av,
IN AParams *pParams
)
{
INT retval;
LPTSTR options = TEXT("?KYUPHwuzZkyxqeospS:X:t:d:i:n:r:m:c:l:a:f:b:g:h:v:j:M:W:G:"); // Supported options
INT iFunction = kUnknown;
BOOL bStatus = FALSE;
//
// Set to known state
//
SetLastError( ERROR_SUCCESS );
//
// Indicate there is not a file name as the first argument.
//
TGetOptContext context;
context.optind = 0;
//
// Process any command line arguments switches.
//
for (context.opterr = 0, retval = 0; retval != EOF; )
{
retval = getopt (ac, av, options, context);
switch (retval)
{
case 't':
pParams->dwSheet = _ttoi( context.optarg );
break;
case 'n':
pParams->pPrinterName = context.optarg;
break;
case 'r':
pParams->pPortName = context.optarg;
break;
case 'm':
pParams->pModelName = context.optarg;
break;
case 'M':
// get the message type first
pParams->uMsgType = *context.optarg == TEXT('q') ? kMsgConfirmation :
*context.optarg == TEXT('w') ? kMsgWarning : kMsgUnknownType;
// get the real message text here
context.optarg++;
if( kMsgUnknownType != pParams->uMsgType && context.optarg && *context.optarg )
{
pParams->pMsgConfirm = context.optarg;
}
break;
case 'b':
pParams->pBasePrinterName = context.optarg;
break;
case 'f':
pParams->pInfFileName = context.optarg;
break;
case 'a':
pParams->pBinFileName = context.optarg;
break;
case 'G':
{
// global flags
if( *context.optarg == TEXT('w') )
{
// we should suppress the setup driver warnings UI
// -- i.e. we're in super quiet mode
pParams->Flags.IsSupressSetupUI = TRUE;
}
}
break;
case 'g':
iFunction = *context.optarg == TEXT('a') ? kAddPerMachineConnection :
*context.optarg == TEXT('d') ? kDeletePerMachineConnection :
*context.optarg == TEXT('e') ? kEnumPerMachineConnections : kUnknown;
break;
case 'j':
pParams->pProvider = context.optarg;
break;
case 'i':
iFunction = *context.optarg == TEXT('n') ? kInstallNetPrinter :
*context.optarg == TEXT('l') ? kInstallLocalPrinter :
*context.optarg == TEXT('d') ? kInstallPrinterDriver :
*context.optarg == TEXT('a') ? kInstallDriverWithInf :
*context.optarg == TEXT('f') ? kInstallPrinterWithInf :
*context.optarg == TEXT('i') ? kInstallLocalPrinterWithInf : kUnknown;
break;
case 'd':
iFunction = *context.optarg == TEXT('n') ? kDeleteNetPrinter :
*context.optarg == TEXT('l') ? kDeleteLocalPrinter :
*context.optarg == TEXT('d') ? kDeletePrinterDriver : kUnknown;
break;
case 'o':
iFunction = kWin32QueueView;
break;
case 's':
iFunction = kServerProperties;
break;
case 'p':
iFunction = kProperties;
break;
case 'X':
iFunction = *context.optarg == TEXT('g') ? kPrinterGetSettings :
*context.optarg == TEXT('s') ? kPrinterSetSettings : kUnknown;
break;
case 'e':
iFunction = kDocumentDefaults;
break;
case 'c':
pParams->pMachineName = context.optarg;
break;
case 'l':
pParams->pSourcePath = context.optarg;
break;
case 'h':
pParams->pArchitecture = context.optarg;
break;
case 'v':
pParams->pVersion = context.optarg;
break;
case 'q':
pParams->Flags.IsQuiet = TRUE;
break;
case 'k':
iFunction = kPrintTestPage;
break;
case 'y':
iFunction = kSetAsDefault;
break;
case 'x':
pParams->Flags.IsWebPointAndPrint = TRUE;
break;
case 'z':
pParams->Flags.IsNoSharing = TRUE;
break;
case 'Z':
pParams->Flags.IsShared = TRUE;
break;
case 'u':
pParams->Flags.IsUseExistingDriver = TRUE;
break;
case 'w':
pParams->Flags.IsUnknownDriverPrompt = TRUE;
break;
case 'W':
// wizards flags
pParams->Flags.IsWizardRestartable = *context.optarg == TEXT('r') ? TRUE : FALSE;
break;
case 'H':
pParams->Flags.IsHydraSpecific = TRUE;
break;
case 'P':
pParams->Flags.IsPromptForNeededFiles = TRUE;
break;
case 'Y':
pParams->Flags.IsDontAutoGenerateName = TRUE;
break;
case 'K':
pParams->Flags.IsUseNonLocalizedStrings = TRUE;
break;
case 'S':
iFunction = *context.optarg == TEXT('s') ? kPrinterPersist :
*context.optarg == TEXT('r') ? kPrinterRestore : kUnknown;
break;
case 'U':
pParams->Flags.IsWindowsUpdate = TRUE;
break;
case EOF:
bStatus = TRUE;
break;
case '?':
iFunction = kCommandHelp;
bStatus = TRUE;
retval = EOF;
break;
case INVALID_COMAND:
bStatus = FALSE;
retval = EOF;
break;
default:
retval = EOF;
break;
}
}
//
// If success validate the command line arguments.
//
if( bStatus )
{
//
// Do simple validation on the command line arguments.
//
bStatus = bValidateCommand( iFunction, pParams );
if( bStatus )
{
//
// If there are any remaining arguments then get
// the argument count and pointer to it.
//
if( context.optind < ac )
{
pParams->av = &av[context.optind];
pParams->ac = ac - context.optind;
}
//
// Check to see if we need to ask the user to confirm the operation if
// not in quiet mode.
//
BOOL bContinueExecution = TRUE;
if( !pParams->Flags.IsQuiet && kMsgUnknownType != pParams->uMsgType && pParams->pMsgConfirm )
{
//
// there is a confirmation/warning message specified and we are going to
// give opportunity to the user to cancel the whole command here
//
UINT uFlags = kMsgConfirmation == pParams->uMsgType ? MB_ICONQUESTION :
kMsgConfirmation == pParams->uMsgType ? MB_ICONEXCLAMATION : 0;
ASSERT(uFlags); // shouldn't be zero
uFlags |= MB_YESNO; // we are asking YES/NO question
bContinueExecution = (IDYES == iMessage2(NULL, MAKEINTRESOURCE(IDS_PRINTERS_TITLE),
pParams->pMsgConfirm, uFlags, kMsgNone, NULL));
}
if( bContinueExecution )
{
//
// Execute the command.
//
bStatus = bExecuteCommand( hwnd, iFunction, pParams );
}
}
}
return bStatus;
}
/*++
Routine Name:
bValidateCommand
Routine Description:
Validates the command line arguments
Arguments:
iFunction - Function code.
pParams - pointer to paramter structure.
Return Value:
TRUE arguments are valid. FALSE invalid argument found.
--*/
BOOL
bValidateCommand(
IN INT iFunction,
IN AParams *pParams
)
{
DBGMSG( DBG_TRACE, ("iFunction %d\n", iFunction ) );
DBGMSG( DBG_TRACE, ("Params\n" ) );
DBGMSG( DBG_TRACE, ("Flags %x\n", pParams->Flags ) );
DBGMSG( DBG_TRACE, ("dwSheet %d\n", pParams->dwSheet ) );
DBGMSG( DBG_TRACE, ("dwLastError %d\n", pParams->dwLastError ) );
DBGMSG( DBG_TRACE, ("pPrinterName "TSTR"\n", DBGSTR( pParams->pPrinterName ) ) );
DBGMSG( DBG_TRACE, ("pPortName "TSTR"\n", DBGSTR( pParams->pPortName ) ) );
DBGMSG( DBG_TRACE, ("pModelName "TSTR"\n", DBGSTR( pParams->pModelName ) ) );
DBGMSG( DBG_TRACE, ("pInfFileName "TSTR"\n", DBGSTR( pParams->pInfFileName ) ) );
DBGMSG( DBG_TRACE, ("pBasePrinterName "TSTR"\n", DBGSTR( pParams->pBasePrinterName) ) );
DBGMSG( DBG_TRACE, ("pMachineName "TSTR"\n", DBGSTR( pParams->pMachineName ) ) );
DBGMSG( DBG_TRACE, ("pSourcePath "TSTR"\n", DBGSTR( pParams->pSourcePath ) ) );
DBGMSG( DBG_TRACE, ("pszCmdLine "TSTR"\n", DBGSTR( pParams->pszCmdLine ) ) );
DBGMSG( DBG_TRACE, ("pBinFileName "TSTR"\n", DBGSTR( pParams->pBinFileName ) ) );
BOOL bRetval = FALSE;
switch( iFunction )
{
case kInstallLocalPrinter:
case kDeleteLocalPrinter:
case kInstallPrinterDriver:
case kEnumPerMachineConnections:
case kServerProperties:
case kCommandHelp:
bRetval = TRUE;
break;
case kInstallLocalPrinterWithInf:
if( pParams->pInfFileName )
{
bRetval = TRUE;
}
break;
case kSetAsDefault:
case kAddPerMachineConnection:
case kDeletePerMachineConnection:
case kInstallNetPrinter:
case kDeleteNetPrinter:
case kWin32QueueView:
case kProperties:
case kDocumentDefaults:
case kPrintTestPage:
case kPrinterGetSettings:
case kPrinterSetSettings:
if( pParams->pPrinterName )
{
bRetval = TRUE;
}
else
{
pParams->dwLastError = ERROR_INVALID_PRINTER_NAME;
}
break;
case kInstallPrinterWithInf:
if( pParams->pModelName && pParams->pInfFileName && pParams->pPortName )
{
bRetval = TRUE;
if( pParams->Flags.IsWebPointAndPrint )
{
//
// Commenting out pBinFileName - for local cab install for wp&p the bin file
// won't exist. This may be fixed if syncing to the server is added and
// this could be put back then. - pvine
//
bRetval = pParams->pPrinterName /*&& pParams->pBinFileName */? TRUE : FALSE;
}
else if( pParams->Flags.IsDontAutoGenerateName )
{
bRetval = pParams->pBasePrinterName != NULL;
}
}
break;
case kPrinterPersist:
case kPrinterRestore:
bRetval = pParams->pPrinterName && pParams->pBinFileName ? TRUE : FALSE;
break;
case kDeletePrinterDriver:
case kInstallDriverWithInf:
if( pParams->pModelName )
{
bRetval = TRUE;
}
break;
case kUnknown:
pParams->dwLastError = ERROR_INVALID_FUNCTION;
bRetval = FALSE;
break;
}
if( !bRetval && ERROR_SUCCESS == pParams->dwLastError )
{
//
// An invalid parameter has been passed.
//
pParams->dwLastError = ERROR_INVALID_PARAMETER;
}
return bRetval;
}
/*++
Routine Name:
bExecuteCommand
Routine Description:
Executes the command from the rundll32 command line
after it has parsed.
Arguments:
hwnd - parent window handle.
iFunction - Function code.
pParams - pointer to paramter structure.
Return Value:
TRUE function complete ok. FALSE error occurred.
--*/
BOOL
bExecuteCommand(
IN HWND hwnd,
IN INT iFunction,
IN AParams *pParams
)
{
BOOL bRetval = TRUE;
TCHAR szBuffer[kPrinterBufMax];
UINT uSize = COUNTOF( szBuffer );
DBGMSG( DBG_TRACE, ("Function %d\n", iFunction ) );
szBuffer[0] = TEXT('\0');
if( pParams->pPrinterName )
{
StringCchCopy( szBuffer, COUNTOF( szBuffer ) , pParams->pPrinterName);
}
//
// Dispatch the specified function.
//
// !!Policy!! if a command is executed then it is responsible
// for displaying any error UI i.e message boxes.
//
switch( iFunction )
{
case kInstallNetPrinter:
(VOID)bPrinterSetup( hwnd, MSP_NETPRINTER, MAX_PATH, szBuffer, &uSize, pParams->pMachineName );
break;
case kDeleteNetPrinter:
bRetval = bPrinterNetRemove( hwnd, szBuffer, pParams->Flags.IsQuiet );
break;
case kDeleteLocalPrinter:
bRetval = bRemovePrinter( hwnd, szBuffer, pParams->pMachineName, pParams->Flags.IsQuiet );
break;
case kInstallPrinterDriver:
bRetval = bDriverSetupNew( hwnd, TWizard::kDriverInstall, MAX_PATH, szBuffer, &uSize,
pParams->pMachineName, 0, pParams->Flags.IsWizardRestartable );
break;
case kInstallLocalPrinter:
bRetval = bPrinterSetupNew( hwnd, TWizard::kPrinterInstall, MAX_PATH, szBuffer, &uSize,
pParams->pMachineName, NULL, pParams->Flags.IsWizardRestartable );
break;
case kInstallLocalPrinterWithInf:
bRetval = bPrinterSetupNew( hwnd, TWizard::kPrinterInstall, MAX_PATH, szBuffer, &uSize, pParams->pMachineName, pParams->pInfFileName, FALSE );
break;
case kInstallDriverWithInf:
bRetval = bDoInfDriverInstall( pParams );
break;
case kInstallPrinterWithInf:
bRetval = bDoInfPrinterInstall( pParams );
break;
case kAddPerMachineConnection:
vAddPerMachineConnection(pParams->pMachineName,pParams->pPrinterName,pParams->pProvider,pParams->Flags.IsQuiet);
break;
case kDeletePerMachineConnection:
vDeletePerMachineConnection(pParams->pMachineName,pParams->pPrinterName,pParams->Flags.IsQuiet);
break;
case kEnumPerMachineConnections:
vEnumPerMachineConnections(pParams->pMachineName,pParams->pInfFileName,pParams->Flags.IsQuiet);
break;
case kWin32QueueView:
vQueueCreate( hwnd, pParams->pPrinterName, SW_SHOW, TRUE );
break;
case kProperties:
vPrinterPropPages( hwnd, pParams->pPrinterName, SW_SHOW, MAKELPARAM( pParams->dwSheet+256, 0 ));
break;
case kDocumentDefaults:
vDocumentDefaults( hwnd, pParams->pPrinterName, SW_SHOW, MAKELPARAM( pParams->dwSheet, 1 ));
break;
case kServerProperties:
vServerPropPages( hwnd, pParams->pPrinterName, SW_SHOW, MAKELPARAM( pParams->dwSheet, 1 ));
break;
case kDeletePrinterDriver:
bRetval = bDoDriverRemoval( pParams );
break;
case kSetAsDefault:
bRetval = SetDefaultPrinter( pParams->pPrinterName );
break;
case kPrintTestPage:
bRetval = bDoPrintTestPage( hwnd, pParams->pPrinterName );
break;
case kPrinterGetSettings:
bRetval = bDoGetPrintSettings( pParams );
break;
case kPrinterSetSettings:
bRetval = bDoSetPrintSettings( pParams );
break;
case kPrinterPersist:
bRetval = bDoPersistPrinterSettings( kPrinterPersist , pParams );
break;
case kPrinterRestore:
bRetval = bDoPersistPrinterSettings( kPrinterRestore , pParams );
break;
case kCommandHelp:
vUsage( pParams );
break;
case kUnknown:
default:
bRetval = TRUE;
break;
}
//
// Some of the functions do not setup pParams->dwLastError,
// so we must rely on the GetLastError() in this case.
//
if( !bRetval && ERROR_SUCCESS == pParams->dwLastError )
{
pParams->dwLastError = GetLastError();
}
return bRetval;
}
/*++
Routine Name:
vUsage
Routine Description:
Display a usage message for the rundll switches.
Arguments:
Nothing.
Return Value:
None.
--*/
VOID
vUsage(
IN AParams *pParams
)
{
TStatusB bStatus;
TString strTemp;
if (!pParams->Flags.IsQuiet)
{
TRunDllDisplay Usage( NULL );
if (VALID_OBJ( Usage ))
{
#ifdef COMMAND_SPECIFIC_HELP
if( pParams->ac )
{
for( UINT i = 0; i < pParams->ac; i++ )
{
bStatus DBGCHK = Usage.WriteOut( pParams->av[i] );
bStatus DBGCHK = Usage.WriteOut( TEXT("\r\n") );
}
}
else
#endif
{
//
// Note we do not check the return values of the string operations
// because bombing out is just as bad as printing an empty string. The
// string class will prevent us from ever crashing.
//
bStatus DBGCHK = strTemp.bLoadString( ghInst, IDS_RUNDLL_TITLE );
bStatus DBGCHK = Usage.SetTitle( strTemp );
bStatus DBGCHK = strTemp.bLoadString( ghInst, IDS_RUNDLL_USAGE );
bStatus DBGCHK = Usage.WriteOut( strTemp );
for( UINT i = IDS_RUNDLL_OPTION0; i <= IDS_RUNDLL_OPTION_END; i++ )
{
bStatus DBGCHK = Usage.WriteOut( TEXT("\r\n ") );
bStatus DBGCHK = strTemp.bLoadString( ghInst, i );
bStatus DBGCHK = Usage.WriteOut( strTemp );
}
bStatus DBGCHK = Usage.WriteOut( TEXT("\r\n\r\n") );
bStatus DBGCHK = strTemp.bLoadString( ghInst,IDS_RUNDLL_EXAMPLE0 );
bStatus DBGCHK = Usage.WriteOut( strTemp );
for( i = IDS_RUNDLL_EXAMPLE1; i <= IDS_RUNDLL_EXAMPLE_END; i++ )
{
bStatus DBGCHK = Usage.WriteOut( TEXT("\r\n ") );
bStatus DBGCHK = strTemp.bLoadString( ghInst, i );
bStatus DBGCHK = Usage.WriteOut( strTemp );
}
}
Usage.bDoModal();
}
}
}
/*++
Routine Name:
bDoPersistPrinterSettings
Routine Description:
Store printer settings into file
Calls Re/StorePrinterSettings with args :
pParams->pPrinterName, pParams->pBinFileName and flags builded upon pParams->av
if pParams->ac == 0 , all setttings will be stored/restored
For restoring settings PRINTER_ALL_ACCESS required for specified printer
Arguments:
iFunction specify what function should be called ( Store/RestorePrinterSettings )
AParams* ptr to AParam structure
Return Value:
TRUE if Re/StorePrinterSettings SUCCEEDED.
FALSE otherwise
--*/
BOOL
bDoPersistPrinterSettings(
IN INT iFunction,
IN AParams *pParams
)
{
DWORD dwFlags = 0;
UINT idx;
UINT ParamIdx;
UINT OptionIdx;
HRESULT hr;
struct ParamEntry
{
TCHAR Option;
DWORD Flag;
};
static ParamEntry PrintSettings_ParamTable [] = {
{TEXT('2'), PRST_PRINTER_INFO_2},
{TEXT('7'), PRST_PRINTER_INFO_7},
{TEXT('c'), PRST_COLOR_PROF},
{TEXT('d'), PRST_PRINTER_DATA},
{TEXT('s'), PRST_PRINTER_SEC},
{TEXT('g'), PRST_PRINTER_DEVMODE},
{TEXT('u'), PRST_USER_DEVMODE},
{TEXT('r'), PRST_RESOLVE_NAME},
{TEXT('f'), PRST_FORCE_NAME},
{TEXT('p'), PRST_RESOLVE_PORT},
{TEXT('h'), PRST_RESOLVE_SHARE},
{TEXT('H'), PRST_DONT_GENERATE_SHARE},
{TEXT('i'), PRST_DONT_CHANGE_DRIVER},
{TEXT('m'), PRST_MINIMUM_SETTINGS},
{0, 0},
};
// for every entry in table
for (ParamIdx = 0 ; ParamIdx < pParams->ac; ParamIdx++ )
{
//for every option argv
for (idx = 0; PrintSettings_ParamTable[idx].Option; idx++)
{
OptionIdx = 0;
//for every char in option argv
while(pParams->av[ParamIdx][OptionIdx])
{
if(OptionIdx > 0)
{
hr = E_FAIL;
goto End;
}
if(PrintSettings_ParamTable[idx].Option == pParams->av[ParamIdx][OptionIdx])
{
// apply flags if in table
dwFlags |= PrintSettings_ParamTable[idx].Flag;
DBGMSG(DBG_TRACE , ("Char %c\n" , pParams->av[ParamIdx][OptionIdx]));
}
OptionIdx++;
}
}
}
if((dwFlags & PRST_FORCE_NAME) && (dwFlags & PRST_RESOLVE_NAME))
{
hr = E_FAIL;
goto End;
}
//
// if no "printer" flags specified , set flags to PRST_ALL_SETTINGS
//
if(!(dwFlags & PRST_ALL_SETTINGS))
{
dwFlags |= PRST_ALL_SETTINGS;
}
hr = (iFunction == kPrinterRestore) ?
RestorePrinterSettings( pParams->pPrinterName, pParams->pBinFileName, dwFlags)
:
StorePrinterSettings( pParams->pPrinterName, pParams->pBinFileName, dwFlags) ;
End:
return SUCCEEDED(hr);
}
/*++
Routine Name:
bDoWebPnpPreInstall
Routine Description:
Do Web Point and Print Pre installation tasks.
Arguments:
pParams - pointer to paramter structure.
pfConnection - pointer where to return connection status
Return Value:
TRUE Web Point and Print code was successfull, FALSE error occurred.
--*/
BOOL
bDoWebPnpPreInstall(
IN AParams *pParams
)
{
TStatusB bStatus;
//
// Inform the point and print code pre entry.
//
bStatus DBGCHK = SUCCEEDED(Winspool_WebPnpEntry( pParams->pszCmdLine ));
//
// If something failed return the last error.
//
if( !bStatus )
{
pParams->dwLastError = GetLastError();
}
return bStatus;
}
/*++
Routine Name:
bDoInfPrinterInstall
Routine Description:
Do inf based printer installation.
Arguments:
pParams - pointer to paramter structure.
Return Value:
None.
--*/
BOOL
bDoInfPrinterInstall(
IN AParams *pParams
)
{
TStatusB bStatus;
TCHAR szBuffer[kPrinterBufMax];
//
// Assume success.
//
bStatus DBGNOCHK = TRUE;
//
// If we are invoked for a Web Point and Pint install.
//
if( bStatus && pParams->Flags.IsWebPointAndPrint )
{
//
// Inform the point and print code pre entry.
//
bStatus DBGCHK = bDoWebPnpPreInstall( pParams );
}
//
// If web pnp pre installed succeeded.
//
if( bStatus )
{
TInfInstall II;
TParameterBlock PB;
ZeroMemory( &II, sizeof( II ) );
ZeroMemory( &PB, sizeof( PB ) );
ZeroMemory( szBuffer, sizeof( szBuffer ) );
if( pParams->pBasePrinterName )
{
StringCchCopy( szBuffer, COUNTOF( szBuffer ) , pParams->pBasePrinterName);
}
II.cbSize = sizeof( II );
II.pszServerName = pParams->pMachineName;
II.pszInfName = pParams->pInfFileName;
II.pszModelName = pParams->pModelName;
II.pszPortName = pParams->pPortName;
II.pszSourcePath = pParams->pSourcePath;
II.pszPrinterNameBuffer = szBuffer;
II.cchPrinterName = COUNTOF( szBuffer );
//
// If this is a web point and print install then set the flags
// to indicate that we want to create the masq printer.
//
II.dwFlags = 0;
II.dwFlags |= pParams->Flags.IsWebPointAndPrint ? kPnPInterface_WebPointAndPrint : 0;
II.dwFlags |= pParams->Flags.IsQuiet ? kPnPInterface_Quiet : 0;
II.dwFlags |= pParams->Flags.IsNoSharing ? kPnPInterface_NoShare : 0;
II.dwFlags |= pParams->Flags.IsUseExistingDriver ? kPnpInterface_UseExisting : 0;
II.dwFlags |= pParams->Flags.IsUnknownDriverPrompt ? kPnpInterface_PromptIfUnknownDriver : 0;
II.dwFlags |= pParams->Flags.IsHydraSpecific ? kPnpInterface_HydraSpecific : 0;
II.dwFlags |= pParams->Flags.IsPromptForNeededFiles ? kPnPInterface_PromptIfFileNeeded : 0;
II.dwFlags |= pParams->Flags.IsShared ? kPnPInterface_Share : 0;
II.dwFlags |= pParams->Flags.IsDontAutoGenerateName ? kPnPInterface_DontAutoGenerateName : 0;
II.dwFlags |= pParams->Flags.IsSupressSetupUI ? kPnPInterface_SupressSetupUI : 0;
PB.pInfInstall = &II;
pParams->dwLastError = PnPInterface( kInfInstall, &PB );
bStatus DBGNOCHK = (pParams->dwLastError == ERROR_SUCCESS);
}
//
// If we succeeded and this is a web point and print event.
//
if( bStatus && pParams->Flags.IsWebPointAndPrint )
{
//
// Inform the web point and print code that the printer was
// installed, they can do ay post processing here.
//
bStatus DBGCHK = SUCCEEDED(Winspool_WebPnpPostEntry( FALSE, pParams->pBinFileName, pParams->pPortName, szBuffer ));
}
return pParams->dwLastError == ERROR_SUCCESS ? TRUE : FALSE;
}
/*++
Routine Name:
bDoInfDriverInstall
Routine Description:
Do inf based printer driver installation.
Arguments:
pParams - pointer to paramter structure.
Return Value:
None.
--*/
BOOL
bDoInfDriverInstall(
IN AParams *pParams
)
{
TInfDriverInstall II = {0};
TParameterBlock PB = {0};
II.cbSize = sizeof( II );
II.pszServerName = pParams->pMachineName;
II.pszInfName = pParams->pInfFileName;
II.pszModelName = pParams->pModelName;
II.pszSourcePath = pParams->pSourcePath;
II.pszVersion = pParams->pVersion;
II.pszArchitecture = pParams->pArchitecture;
II.dwFlags = 0;
II.dwFlags |= pParams->Flags.IsQuiet ? kPnPInterface_Quiet : 0;
II.dwFlags |= pParams->Flags.IsWindowsUpdate ? kPnPInterface_WindowsUpdate : 0;
II.dwFlags |= pParams->Flags.IsUseNonLocalizedStrings ? kPnPInterface_UseNonLocalizedStrings : 0;
II.dwFlags |= pParams->Flags.IsSupressSetupUI ? kPnPInterface_SupressSetupUI : 0;
PB.pInfDriverInstall = &II;
pParams->dwLastError = PnPInterface( kInfDriverInstall, &PB );
return pParams->dwLastError == ERROR_SUCCESS;
}
/*++
Routine Name:
bDoDriverRemoval
Routine Description:
Do driver delete
Arguments:
pParams - pointer to paramter structure.
Return Value:
None.
--*/
BOOL
bDoDriverRemoval(
IN AParams *pParams
)
{
TDriverRemoval II = {0};
TParameterBlock PB = {0};
II.cbSize = sizeof( II );
II.pszServerName = pParams->pMachineName;
II.pszModelName = pParams->pModelName;
II.pszVersion = pParams->pVersion;
II.pszArchitecture = pParams->pArchitecture;
II.dwFlags = 0;
II.dwFlags |= pParams->Flags.IsUseNonLocalizedStrings ? kPnPInterface_UseNonLocalizedStrings : 0;
II.dwFlags |= pParams->Flags.IsQuiet ? kPnPInterface_Quiet : 0;
II.dwFlags |= pParams->Flags.IsSupressSetupUI ? kPnPInterface_SupressSetupUI : 0;
PB.pDriverRemoval = &II;
pParams->dwLastError = PnPInterface( kDriverRemoval, &PB );
if( ERROR_UNKNOWN_PRINTER_DRIVER == pParams->dwLastError )
{
// this error code is used primarily for blocking bad
// oem drivers so the default message used is pretty
// incorrect. remap the message to better one based on
// the context
CMsgBoxCounter::SetMsg(IDS_ERROR_DRIVER_DOESNT_EXISTS);
}
return pParams->dwLastError == ERROR_SUCCESS;
}
/********************************************************************
Setting and Getting printer information methods.
********************************************************************/
static TSelect::SelectionVal PrintSettings_ValueTable [] = {
{IDS_RUNDLL_SET_PAUSE, PRINTER_CONTROL_PAUSE, OFFSETOF( PRINTER_INFO_2, Status )},
{IDS_RUNDLL_SET_RESUME, PRINTER_CONTROL_RESUME, OFFSETOF( PRINTER_INFO_2, Status )},
{IDS_RUNDLL_SET_PURGE, PRINTER_CONTROL_PURGE, OFFSETOF( PRINTER_INFO_2, Status )},
{NULL, 0, NULL}};
static TSelect::SelectionBit PrintSettings_BitTable [] = {
{IDS_RUNDLL_SET_QUEUED, PRINTER_ATTRIBUTE_QUEUED, TSelect::kNop},
{IDS_RUNDLL_SET_DIRECT, PRINTER_ATTRIBUTE_DIRECT, TSelect::kNop},
{IDS_RUNDLL_SET_DEFAULT, PRINTER_ATTRIBUTE_DEFAULT, TSelect::kNop},
{IDS_RUNDLL_SET_SHARED, PRINTER_ATTRIBUTE_SHARED, TSelect::kNop},
{IDS_RUNDLL_SET_HIDDEN, PRINTER_ATTRIBUTE_HIDDEN, TSelect::kNop},
{IDS_RUNDLL_SET_NETWORK, PRINTER_ATTRIBUTE_NETWORK, TSelect::kNop},
{IDS_RUNDLL_SET_LOCAL, PRINTER_ATTRIBUTE_LOCAL, TSelect::kNop},
{IDS_RUNDLL_SET_ENABLEDEVQ, PRINTER_ATTRIBUTE_ENABLE_DEVQ, TSelect::kNop},
{IDS_RUNDLL_SET_KEEPPRINTEDJOBS,PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS, TSelect::kNop},
{IDS_RUNDLL_SET_DOCOMPLETEFIRST,PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST,TSelect::kNop},
{IDS_RUNDLL_SET_WORKOFFLINE, PRINTER_ATTRIBUTE_WORK_OFFLINE, TSelect::kNop},
{IDS_RUNDLL_SET_ENABLEBIDI, PRINTER_ATTRIBUTE_ENABLE_BIDI, TSelect::kNop},
{IDS_RUNDLL_SET_RAWONLY, PRINTER_ATTRIBUTE_RAW_ONLY, TSelect::kNop},
{IDS_RUNDLL_SET_PUBLISHED, PRINTER_ATTRIBUTE_PUBLISHED, TSelect::kNop},
{0, 0, TSelect::kNop}};
static TSelect::Selection PrintSettings_Table [] = {
{IDS_RUNDLL_SET_PRINTERNAME, TSelect::kString, NULL, OFFSETOF( PRINTER_INFO_2, pPrinterName ) },
{IDS_RUNDLL_SET_SHARENAME, TSelect::kString, NULL, OFFSETOF( PRINTER_INFO_2, pShareName ) },
{IDS_RUNDLL_SET_PORTNAME, TSelect::kString, NULL, OFFSETOF( PRINTER_INFO_2, pPortName ) },
{IDS_RUNDLL_SET_DRIVERNAME, TSelect::kString, NULL, OFFSETOF( PRINTER_INFO_2, pDriverName ) },
{IDS_RUNDLL_SET_COMMENT, TSelect::kString, NULL, OFFSETOF( PRINTER_INFO_2, pComment ) },
{IDS_RUNDLL_SET_LOCATION, TSelect::kString, NULL, OFFSETOF( PRINTER_INFO_2, pLocation ) },
{IDS_RUNDLL_SET_SEPFILE, TSelect::kString, NULL, OFFSETOF( PRINTER_INFO_2, pSepFile ) },
{IDS_RUNDLL_SET_PRINTPROCESSOR, TSelect::kString, NULL, OFFSETOF( PRINTER_INFO_2, pPrintProcessor )},
{IDS_RUNDLL_SET_DATATYPE, TSelect::kString, NULL, OFFSETOF( PRINTER_INFO_2, pDatatype ) },
{IDS_RUNDLL_SET_PARAMETERS, TSelect::kString, NULL, OFFSETOF( PRINTER_INFO_2, pParameters ) },
{IDS_RUNDLL_SET_ATTRIBUTES, TSelect::kBitTable, PrintSettings_BitTable, OFFSETOF( PRINTER_INFO_2, Attributes ) },
{IDS_RUNDLL_SET_PRIORITY, TSelect::kInt, NULL, OFFSETOF( PRINTER_INFO_2, Priority ) },
{IDS_RUNDLL_SET_DEFAULTPRIORITY,TSelect::kInt, NULL, OFFSETOF( PRINTER_INFO_2, DefaultPriority ) },
{IDS_RUNDLL_SET_STARTTIME, TSelect::kInt, NULL, OFFSETOF( PRINTER_INFO_2, StartTime ) },
{IDS_RUNDLL_SET_UNTILTIME, TSelect::kInt, NULL, OFFSETOF( PRINTER_INFO_2, UntilTime ) },
{IDS_RUNDLL_SET_STATUS, TSelect::kValTable, PrintSettings_ValueTable,OFFSETOF( PRINTER_INFO_2, Status ) },
{NULL, TSelect::kNone, NULL, NULL }};
/*++
Routine Name:
bDoGetPrintSettings
Routine Description:
Get the specified printer settings.
Arguments:
pParams - pointer to paramter structure.
Return Value:
TRUE success, FALSE error.
--*/
BOOL
bDoGetPrintSettings(
IN AParams *pParams
)
{
DBGMSG( DBG_TRACE, ( "bDoGetPrintSettings\n" ) );
return PrintSettings_DisplayInformation( pParams, PrintSettings_Table );
}
/*++
Routine Name:
bDoSetPrintSettings
Routine Description:
Set the specified printer settings.
Arguments:
pParams - pointer to paramter structure.
Return Value:
TRUE success, FALSE error.
--*/
BOOL
bDoSetPrintSettings(
IN AParams *pParams
)
{
DBGMSG( DBG_TRACE, ( "bDoSetPrintSettings\n" ) );
DBGMSG( DBG_TRACE, ( "Argument count %d.\n", pParams->ac ) );
TStatusB bStatus;
bStatus DBGNOCHK = FALSE;
TSelect Select;
PRINTER_INFO_2 Info = {0};
Info.Attributes = (DWORD)-1;
Info.Priority = (DWORD)-1;
Info.DefaultPriority = (DWORD)-1;
Info.StartTime = (DWORD)-1;
Info.UntilTime = (DWORD)-1;
Info.Status = (DWORD)-1;
//
// Validate command arguments
//
if( !PrintSettings_ValidateArguments( pParams ) )
{
DBGMSG( DBG_WARN, ( "Argument validation failed.\n" ) );
return pParams->dwLastError == ERROR_SUCCESS;
}
//
// Lookup the printer setting command.
//
for( UINT i = 0; i < pParams->ac; i += 2 )
{
if( (i+0 < pParams->ac) && (i+1 < pParams->ac) )
{
bStatus DBGCHK = Select.bLookup( PrintSettings_Table, &Info, pParams->av[i], pParams->av[i+1] );
if( !bStatus )
{
DBGMSG( DBG_WARN, ( "Invalid key name found.\n" ) );
pParams->dwLastError = ERROR_INVALID_PARAMETER;
break;
}
}
else
{
DBGMSG( DBG_WARN, ( "Unmatched key / value pair arguments\n" ) );
pParams->dwLastError = ERROR_INVALID_PARAMETER;
bStatus DBGNOCHK = FALSE;
break;
}
}
//
// Set the printer data.
//
if( bStatus )
{
//
// Set the printer information.
//
bStatus DBGCHK = PrintSettings_SetInfo( pParams, Info );
if( !bStatus )
{
DBGMSG( DBG_TRACE, ( "PrintSettings_SetInfo failed with %d\n", pParams->dwLastError ) );
}
}
return bStatus;
}
/*++
Routine Name:
PrintSettings_ValidateArguments
Routine Description:
Validate the command line arguments
Arguments:
pParams - pointer to paramter structure.
Return Value:
TRUE success, FALSE error.
--*/
BOOL
PrintSettings_ValidateArguments(
IN AParams *pParams
)
{
TStatusB bStatus;
bStatus DBGNOCHK = FALSE;
TString strHelp1;
TString strHelp2;
//
// There must be at least one additional argumet.
//
if( !(pParams->ac >= 1) )
{
DBGMSG( DBG_WARN, ( "Insufficent number of additional arguments.\n" ) );
pParams->dwLastError = ERROR_INVALID_PARAMETER;
return bStatus;
}
//
// If a help command was specified.
//
bStatus DBGCHK = strHelp1.bLoadString( ghInst, IDS_RUNDLL_HELP1 );
bStatus DBGCHK = strHelp2.bLoadString( ghInst, IDS_RUNDLL_HELP2 );
if( !_tcsicmp( pParams->av[0], strHelp1 ) || !_tcsicmp( pParams->av[0], strHelp2 ) )
{
pParams->dwLastError = ERROR_SUCCESS;
PrintSettings_DisplayHelp( pParams, PrintSettings_Table );
return FALSE;
}
//
// Success we have validated the arguments.
//
bStatus DBGNOCHK = TRUE;
return bStatus;
}
/*++
Routine Name:
PrintSettings_SetInfo
Routine Description:
Set the printer info data.
Arguments:
Info - Reference to printer info data.
pParams - pointer to paramter structure.
Return Value:
TRUE success, FALSE error.
--*/
BOOL
PrintSettings_SetInfo(
IN AParams *pParams,
IN PRINTER_INFO_2 &Info
)
{
DBGMSG( DBG_TRACE, ( "PrintSettings_SetInfo\n" ) );
TStatus Status;
TStatusB bStatus;
bStatus DBGNOCHK = FALSE;
HANDLE hPrinter = NULL;
PPRINTER_INFO_2 pInfo = NULL;
DWORD cbInfo = 0;
DWORD dwAccess = 0;
DWORD dwOldAttributes = 0;
DWORD dwNewAttributes = 0;
//
// Open the printer.
//
Status DBGCHK = TPrinter::sOpenPrinter( pParams->pPrinterName, &dwAccess, &hPrinter );
if( Status == ERROR_SUCCESS )
{
//
// Get the printer data.
//
bStatus DBGNOCHK = VDataRefresh::bGetPrinter( hPrinter, 2, (PVOID *)&pInfo, (PDWORD)&cbInfo );
//
// Merge in any changed fields.
//
if( bStatus )
{
TSelect Select;
//
// Convert the bit table to a value.
//
Select.bApplyBitTableToValue( PrintSettings_BitTable, pInfo->Attributes, &Info.Attributes );
//
// Publishing and UnPublishing needs to be special cased, since this setting is
// not done in the printer info 2 structure. The published bit is a read only
// attribute in the printer info 2, the publish state is changed using set printer
// info 7.
//
dwOldAttributes = pInfo->Attributes;
dwNewAttributes = Info.Attributes != -1 ? Info.Attributes : pInfo->Attributes;
//
// Copy the changed date into the info sturcture.
//
pInfo->pPrinterName = Info.pPrinterName ? Info.pPrinterName : pInfo->pPrinterName;
pInfo->pShareName = Info.pShareName ? Info.pShareName : pInfo->pShareName;
pInfo->pPortName = Info.pPortName ? Info.pPortName : pInfo->pPortName;
pInfo->pDriverName = Info.pDriverName ? Info.pDriverName : pInfo->pDriverName;
pInfo->pComment = Info.pComment ? Info.pComment : pInfo->pComment;
pInfo->pLocation = Info.pLocation ? Info.pLocation : pInfo->pLocation;
pInfo->pSepFile = Info.pSepFile ? Info.pSepFile : pInfo->pSepFile;
pInfo->pDatatype = Info.pDatatype ? Info.pDatatype : pInfo->pDatatype;
pInfo->pParameters = Info.pParameters ? Info.pParameters : pInfo->pParameters;
pInfo->Attributes = Info.Attributes != -1 ? Info.Attributes : pInfo->Attributes;
pInfo->Priority = Info.Priority != -1 ? Info.Priority : pInfo->Priority;
pInfo->DefaultPriority = Info.DefaultPriority != -1 ? Info.DefaultPriority : pInfo->DefaultPriority;
pInfo->StartTime = Info.StartTime != -1 ? Info.StartTime : pInfo->StartTime;
pInfo->UntilTime = Info.UntilTime != -1 ? Info.UntilTime : pInfo->UntilTime;
}
//
// Set the changed printer data.
//
if( bStatus )
{
bStatus DBGCHK = SetPrinter( hPrinter, 2, (PBYTE)pInfo, 0 );
if( bStatus )
{
if( Info.Status != -1 )
{
bStatus DBGCHK = SetPrinter( hPrinter, 0, NULL, Info.Status );
}
}
}
//
// Handle the printer publishing case.
//
if( bStatus )
{
BOOL bPublish;
TDirectoryService ds;
bPublish = ds.bIsDsAvailable(pInfo->pServerName);
if( bPublish )
{
//
// Check this policy only if we are administering a
// local printer. In case it fails or the registry key
// could not be found, we will assume the publishing
// policy is allowed and go ahead to publish it.
//
if( !pInfo->pServerName || !pInfo->pServerName[0] )
{
//
// 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;
if( SpoolerPolicy.bRead( gszSpoolerPublish, bCanPublish ) )
{
bPublish = bCanPublish;
}
}
}
}
if( bPublish )
{
//
// Only do something if the attributes are different.
//
if( dwOldAttributes != dwNewAttributes )
{
//
// If the current printer state is not shared and it
// was previously published then unpublish it now.
//
if(!(pInfo->Attributes & PRINTER_ATTRIBUTE_SHARED) &&
dwOldAttributes & PRINTER_ATTRIBUTE_PUBLISHED)
{
dwNewAttributes &= ~PRINTER_ATTRIBUTE_PUBLISHED;
}
//
// Only unpublish requests or shared printer publish requests.
//
bStatus DBGCHK = !(dwNewAttributes & PRINTER_ATTRIBUTE_PUBLISHED) ||
(dwNewAttributes & PRINTER_ATTRIBUTE_PUBLISHED &&
pInfo->Attributes & PRINTER_ATTRIBUTE_SHARED);
if(bStatus)
{
PRINTER_INFO_7 Info7 = {0};
Info7.dwAction = (dwNewAttributes & PRINTER_ATTRIBUTE_PUBLISHED)
? DSPRINT_PUBLISH : DSPRINT_UNPUBLISH;
bStatus DBGCHK = SetPrinter( hPrinter, 7, (PBYTE)&Info7, 0 );
//
// Printer info 7 fails with ERROR_IO_PENDING when the publishing is occurring
// in the background. For the rundll32 interface just return success.
//
if(!bStatus && (GetLastError() == ERROR_IO_PENDING))
{
SetLastError(ERROR_SUCCESS);
bStatus DBGNOCHK = TRUE;
}
}
else
{
SetLastError(ERROR_INVALID_PARAMETER);
}
}
}
}
//
// Release the printer info data.
//
FreeMem( pInfo );
//
// Close the printer handle if one was opened.
//
if( hPrinter )
{
ClosePrinter( hPrinter );
}
}
//
// If something failed preserve the last error.
//
if( !bStatus )
{
pParams->dwLastError = GetLastError();
}
return bStatus;
}
/*++
Routine Name:
PrintSettings_DisplayHelp
Routine Description:
Displays the printer settings command arguments.
Arguments:
pParams - pointer to paramter structure.
pSelection - pointer argument selection table.
Return Value:
TRUE success, FALSE error.
--*/
BOOL
PrintSettings_DisplayHelp(
IN AParams *pParams,
IN TSelect::Selection *pSelection
)
{
DBGMSG( DBG_TRACE, ( "PrintSettings_DisplayHelp\n" ) );
TStatusB bStatus;
TRunDllDisplay Usage( NULL, pParams->pInfFileName, (pParams->pInfFileName && *pParams->pInfFileName) ?
TRunDllDisplay::kFile : TRunDllDisplay::kEditBox );
bStatus DBGNOCHK = VALID_OBJ( Usage );
if( bStatus )
{
TString strTemp;
TString strString;
TString strInt;
TString strStart;
TString strEnd;
TString strSep;
TString strFormat;
TString strBit;
LPCTSTR pszType;
//
// Set the title.
//
bStatus DBGCHK = strTemp.bLoadString( ghInst, IDS_RUNDLL_SET_ATTRIBUTE_TITLE );
bStatus DBGCHK = Usage.SetTitle( strTemp );
//
// Set the usage example.
//
bStatus DBGCHK = strTemp.bLoadString( ghInst, IDS_RUNDLL_SET_ATTRIBUTE_USAGE );
bStatus DBGCHK = Usage.WriteOut( strTemp );
bStatus DBGCHK = Usage.WriteOut( TEXT("\r\n") );
//
// Load some constant strings.
//
bStatus DBGCHK = strString.bLoadString( ghInst, IDS_RUNDLL_STRING );
bStatus DBGCHK = strInt.bLoadString( ghInst, IDS_RUNDLL_INTEGER );
bStatus DBGCHK = strStart.bLoadString( ghInst, IDS_RUNDLL_START );
bStatus DBGCHK = strEnd.bLoadString( ghInst, IDS_RUNDLL_END );
bStatus DBGCHK = strSep.bLoadString( ghInst, IDS_RUNDLL_SEP );
bStatus DBGCHK = strFormat.bLoadString( ghInst, IDS_RUNDLL_FORMAT );
for( ; pSelection->iKeyWord; pSelection++ )
{
switch( pSelection->eDataType )
{
case TSelect::kInt:
pszType = strInt;
break;
case TSelect::kString:
pszType = strString;
break;
case TSelect::kValTable:
case TSelect::kBitTable:
{
bStatus DBGCHK = strBit.bUpdate( strStart );
TSelect::SelectionBit *pSel = (TSelect::SelectionBit *)pSelection->pTable;
for( ; pSel->iKeyWord; pSel++ )
{
bStatus DBGCHK = strTemp.bLoadString( ghInst, pSel->iKeyWord );
bStatus DBGCHK = strBit.bCat( strTemp );
if( (pSel+1)->iKeyWord )
{
bStatus DBGCHK = strBit.bCat( strSep );
}
}
bStatus DBGCHK = strBit.bCat( strEnd );
pszType = strBit;
}
break;
default:
pszType = gszNULL;
break;
}
bStatus DBGCHK = strTemp.bLoadString( ghInst, pSelection->iKeyWord );
bStatus DBGCHK = strTemp.bFormat( strFormat, (LPCTSTR)strTemp, pszType );
bStatus DBGCHK = Usage.WriteOut( strTemp );
bStatus DBGCHK = Usage.WriteOut( TEXT("\r\n") );
}
bStatus DBGCHK = strTemp.bLoadString( ghInst,IDS_RUNDLL_EXAMPLE0 );
bStatus DBGCHK = Usage.WriteOut( strTemp );
for( UINT i = IDS_RUNDLL_SET_EXAMPLE1; i <= IDS_RUNDLL_SET_EXAMPLE_END; i++ )
{
bStatus DBGCHK = Usage.WriteOut( TEXT("\r\n ") );
bStatus DBGCHK = strTemp.bLoadString( ghInst, i );
bStatus DBGCHK = Usage.WriteOut( strTemp );
}
bStatus DBGCHK = Usage.bDoModal();
}
return bStatus;
}
/*++
Routine Name:
PrintSettings_DisplayInformation
Routine Description:
Displays the printer settings
Arguments:
pParams - pointer to paramter structure.
pSelection - pointer argument selection table.
Return Value:
TRUE success, FALSE error.
--*/
BOOL
PrintSettings_DisplayInformation(
IN AParams *pParams,
IN TSelect::Selection *pSelection
)
{
DBGMSG( DBG_TRACE, ( "PrintSettings_DisplayInformation\n" ) );
TStatus Status( DBG_WARN );
TString strTemp;
TString strKeyword;
TString strFormat1;
TString strFormat2;
TString strTitle;
TStatusB bStatus;
bStatus DBGNOCHK = FALSE;
DWORD dwAccess = 0;
HANDLE hPrinter = NULL;
PPRINTER_INFO_2 pInfo = NULL;
DWORD cbInfo = 0;
//
// Open the printer.
//
Status DBGCHK = TPrinter::sOpenPrinter( pParams->pPrinterName, &dwAccess, &hPrinter );
if( Status == ERROR_SUCCESS )
{
//
// Get the printer data.
//
bStatus DBGNOCHK = VDataRefresh::bGetPrinter( hPrinter, 2, (PVOID *)&pInfo, (PDWORD)&cbInfo );
if( bStatus )
{
//
// Display the printer data.
//
TRunDllDisplay Usage( NULL, pParams->pInfFileName, (pParams->pInfFileName && *pParams->pInfFileName) ?
TRunDllDisplay::kFile : TRunDllDisplay::kEditBox );
bStatus DBGNOCHK = VALID_OBJ( Usage );
if( bStatus )
{
Usage.vSetTabStops(64);
bStatus DBGCHK = strTitle.bLoadString( ghInst, IDS_RUNDLL_DISPLAY_TITLE );
bStatus DBGCHK = strTitle.bCat( pParams->pPrinterName );
Usage.SetTitle( strTitle );
bStatus DBGCHK = strFormat1.bLoadString( ghInst, IDS_RUNDLL_DISPLAY_FORMAT1 );
bStatus DBGCHK = strFormat2.bLoadString( ghInst, IDS_RUNDLL_DISPLAY_FORMAT2 );
for( ; pSelection->iKeyWord; pSelection++ )
{
bStatus DBGCHK = strKeyword.bLoadString( ghInst, pSelection->iKeyWord );
switch( pSelection->eDataType )
{
case TSelect::kString:
bStatus DBGCHK = strTemp.bFormat( strFormat1, (LPCTSTR)strKeyword, *(LPCTSTR *)((PBYTE)pInfo+pSelection->iOffset) );
break;
case TSelect::kInt:
bStatus DBGCHK = strTemp.bFormat( strFormat2, (LPCTSTR)strKeyword, *(UINT *)((PBYTE)pInfo+pSelection->iOffset) );
break;
case TSelect::kBitTable:
bStatus DBGCHK = PrintSettings_DisplayAttributes( strTemp, pSelection, *(UINT *)((PBYTE)pInfo+pSelection->iOffset) );
bStatus DBGCHK = strTemp.bFormat( strFormat1, (LPCTSTR)strKeyword, (LPCTSTR)strTemp );
break;
case TSelect::kValTable:
bStatus DBGCHK = PrintSettings_DisplayStatus( strTemp, pSelection, *(UINT *)((PBYTE)pInfo+pSelection->iOffset) );
bStatus DBGCHK = strTemp.bFormat( strFormat1, (LPCTSTR)strKeyword, (LPCTSTR)strTemp );
break;
default:
bStatus DBGCHK = strTemp.bUpdate( NULL );
break;
}
bStatus DBGCHK = Usage.WriteOut( strTemp );
bStatus DBGCHK = Usage.WriteOut( TEXT("\r\n") );
}
bStatus DBGCHK = Usage.bDoModal();
}
}
//
// Release the printer info data.
//
FreeMem( pInfo );
//
// Close the printer handle if one was opened.
//
if( hPrinter )
{
ClosePrinter( hPrinter );
}
}
return bStatus;
}
/*++
Routine Name:
PrintSettings_DisplayAttributes
Routine Description:
Get the current printer attributes in a displayable form.
Arguments:
Return Value:
TRUE success, FALSE error.
--*/
BOOL
PrintSettings_DisplayAttributes(
IN TString &strBit,
IN TSelect::Selection *pSelection,
IN UINT uAttributes
)
{
DBGMSG( DBG_TRACE, ( "PrintSettings_DisplayAttributes\n" ) );
TStatusB bStatus;
TString strStart;
TString strEnd;
TString strSep;
TString strTemp;
bStatus DBGCHK = strStart.bLoadString( ghInst, IDS_RUNDLL_START );
bStatus DBGCHK = strEnd.bLoadString( ghInst, IDS_RUNDLL_END );
bStatus DBGCHK = strSep.bLoadString( ghInst, IDS_RUNDLL_SEP );
TSelect::SelectionBit *pSel = (TSelect::SelectionBit *)pSelection->pTable;
bStatus DBGCHK = strBit.bUpdate( strStart );
for( ; pSel->iKeyWord; pSel++ )
{
if( uAttributes & pSel->uBit )
{
bStatus DBGCHK = strTemp.bLoadString( ghInst, pSel->iKeyWord );
bStatus DBGCHK = strBit.bCat( strTemp );
bStatus DBGCHK = strBit.bCat( strSep );
}
}
bStatus DBGCHK = strBit.bCat( strEnd );
return TRUE;
}
/*++
Routine Name:
PrintSettings_DisplayStatus
Routine Description:
Get the status in a displayable form.
Arguments:
Return Value:
TRUE success, FALSE error.
--*/
BOOL
PrintSettings_DisplayStatus(
IN TString &strVal,
IN TSelect::Selection *pSelection,
IN UINT uStatus
)
{
DBGMSG( DBG_TRACE, ( "PrintSettings_DisplayStatus\n" ) );
TStatusB bStatus;
TString strStart;
TString strEnd;
TString strTemp;
bStatus DBGCHK = strStart.bLoadString( ghInst, IDS_RUNDLL_START );
bStatus DBGCHK = strEnd.bLoadString( ghInst, IDS_RUNDLL_END );
TSelect::SelectionVal *pSel = (TSelect::SelectionVal *)pSelection->pTable;
bStatus DBGCHK = strVal.bUpdate( strStart );
for( ; pSel->iKeyWord; pSel++ )
{
if( uStatus == pSel->uValue )
{
bStatus DBGCHK = strTemp.bLoadString( ghInst, pSel->iKeyWord );
bStatus DBGCHK = strVal.bCat( strTemp );
break;
}
}
bStatus DBGCHK = strVal.bCat( strEnd );
return TRUE;
}
/********************************************************************
RunDll Usage
********************************************************************/
TRunDllDisplay::
TRunDllDisplay(
IN HWND hWnd,
IN LPCTSTR pszFileName,
IN DisplayType Display
) : _hWnd( hWnd ),
_bValid( FALSE ),
_Display( Display ),
_pFile( NULL ),
_cxGrip( 0 ),
_cyGrip( 0 ),
_hwndGrip( NULL ),
_cTabStop( 0 ),
_dwTabStop( 0 )
{
memset( &_ptLastSize, 0, sizeof(_ptLastSize) );
memset( &_ptMinTrack, 0, sizeof(_ptMinTrack) );
switch( _Display )
{
case kFile:
_pFile = new TFile( pszFileName );
_bValid = VALID_PTR( _pFile );
break;
case kEditBox:
_bValid = TRUE;
break;
default:
SPLASSERT( FALSE );
_bValid = FALSE;
break;
}
}
TRunDllDisplay::
~TRunDllDisplay(
VOID
)
{
if( _hwndGrip )
{
DestroyWindow( _hwndGrip );
}
delete _pFile;
}
BOOL
TRunDllDisplay::
WriteOut(
LPCTSTR pszData
)
{
SPLASSERT( pszData );
return _StringOutput.bCat(pszData);
}
BOOL
TRunDllDisplay::
bValid(
VOID
)
{
return _bValid;
}
VOID
TRunDllDisplay::
vSetTabStops(
IN UINT uTabStop
)
{
_cTabStop = 1;
_dwTabStop = uTabStop;
}
BOOL
TRunDllDisplay::
bDoModal(
VOID
)
{
TStatusB bStatus;
switch( _Display )
{
case kEditBox:
bStatus DBGCHK = (BOOL)DialogBoxParam( ghInst,
MAKEINTRESOURCE( DLG_RUNDLL ),
_hWnd,
MGenericDialog::SetupDlgProc,
(LPARAM)this );
break;
case kFile:
bStatus DBGCHK = _pFile->bWrite( _StringOutput );
break;
default:
bStatus DBGNOCHK = FALSE;
break;
}
return bStatus;
}
BOOL
TRunDllDisplay::
SetTitle(
IN LPCTSTR pszData
)
{
TStatusB bStatus;
bStatus DBGCHK = _StringTitle.bUpdate(pszData);
return bStatus;
}
BOOL
TRunDllDisplay::
bSetUI(
VOID
)
{
TStatusB bStatus;
bStatus DBGCHK = bSetEditText( _hDlg, IDC_RUNDLL_TITLE, _StringTitle );
bStatus DBGCHK = bSetEditText( _hDlg, IDC_RUNDLL_TEXT, _StringOutput );
SendDlgItemMessage( _hDlg, IDC_RUNDLL_TEXT, EM_SETMODIFY, TRUE, 0 );
//
// Set any applicable tab stops.
//
SendDlgItemMessage( _hDlg, IDC_RUNDLL_TEXT, EM_SETTABSTOPS, _cTabStop, (LPARAM)&_dwTabStop );
//
// Set the initial size.
//
RECT rect;
GetWindowRect(_hDlg, &rect);
_ptLastSize.x = rect.right - rect.left;
_ptLastSize.y = rect.bottom - rect.top;
//
// Save the minimum track information.
//
_ptMinTrack.x = rect.right - rect.left;
_ptMinTrack.y = rect.bottom - rect.top;
//
// Create the sizing grip.
//
RECT rc;
GetClientRect(_hDlg, &rc);
_cxGrip = GetSystemMetrics(SM_CXVSCROLL);
_cyGrip = GetSystemMetrics(SM_CYHSCROLL);
_hwndGrip = CreateWindow( TEXT("Scrollbar"),
NULL,
WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS |
WS_CLIPCHILDREN | SBS_BOTTOMALIGN | SBS_SIZEGRIP |
SBS_SIZEBOXBOTTOMRIGHTALIGN,
rc.right - _cxGrip,
rc.bottom - _cyGrip,
_cxGrip,
_cyGrip,
_hDlg,
(HMENU)-1,
ghInst,
NULL );
if( !_hwndGrip )
{
bStatus DBGCHK = FALSE;
}
//
// Set the dialog icon.
//
INT cxIcon = GetSystemMetrics(SM_CXICON);
INT cyIcon = GetSystemMetrics(SM_CYICON);
HANDLE hIcon;
if( hIcon = LoadImage( ghInst, MAKEINTRESOURCE(IDI_PRINTER), IMAGE_ICON, cxIcon, cyIcon, 0 ) )
{
SendMessage( _hDlg, WM_SETICON, ICON_BIG, (LPARAM)hIcon );
}
//
// The small icon size is already cached for the queue view.
//
if( hIcon = LoadImage( ghInst, MAKEINTRESOURCE(IDI_PRINTER), IMAGE_ICON, gcxSmIcon, gcySmIcon, 0 ) )
{
SendMessage( _hDlg, WM_SETICON, ICON_SMALL, (LPARAM)hIcon );
}
return bStatus;
}
BOOL
TRunDllDisplay::
bHandle_WM_SIZE(
IN WPARAM wParam,
IN LPARAM lParam
)
{
INT width = LOWORD( lParam );
INT height = HIWORD( lParam );
//
// Get the current window size.
//
RECT rect;
GetWindowRect(_hDlg, &rect);
//
// Calculate the deltas in the x and y positions that we need to move
// each of the child controls.
//
INT dx = (rect.right - rect.left) - _ptLastSize.x;
INT dy = (rect.bottom - rect.top) - _ptLastSize.y;
//
// Update the new size.
//
_ptLastSize.x = rect.right - rect.left;
_ptLastSize.y = rect.bottom - rect.top;
//
// Set the sizing grip to the correct location.
//
if( _hwndGrip )
{
SetWindowPos( _hwndGrip,
NULL,
width - _cxGrip,
height - _cyGrip,
_cxGrip,
_cyGrip,
SWP_NOZORDER | SWP_NOACTIVATE );
}
//
// Move the ok button.
//
GetWindowRect(GetDlgItem(_hDlg, IDOK), &rect);
MapWindowPoints(NULL, _hDlg, (LPPOINT)&rect, 2);
SetWindowPos(GetDlgItem(_hDlg, IDOK),
NULL,
rect.left+dx,
rect.top+dy,
0,
0,
SWP_NOZORDER|SWP_NOSIZE);
//
// Resize the edit control
//
GetWindowRect(GetDlgItem(_hDlg, IDC_RUNDLL_TEXT), &rect);
MapWindowPoints(NULL, _hDlg, (LPPOINT)&rect, 2);
SetWindowPos(GetDlgItem(_hDlg, IDC_RUNDLL_TEXT),
NULL,
0,
0,
(rect.right-rect.left)+dx,
(rect.bottom-rect.top)+dy,
SWP_NOZORDER|SWP_NOMOVE);
return FALSE;
}
BOOL
TRunDllDisplay::
bHandle_WM_GETMINMAXINFO(
IN WPARAM wParam,
IN LPARAM lParam
)
{
BOOL bRetval = TRUE;
LPMINMAXINFO pmmi = (LPMINMAXINFO)lParam;
if( ( _ptMinTrack.x != 0 ) || ( _ptMinTrack.y != 0 ) )
{
pmmi->ptMinTrackSize = _ptMinTrack;
bRetval = FALSE;
}
return bRetval;
}
BOOL
TRunDllDisplay::
bHandleMessage(
IN UINT uMsg,
IN WPARAM wParam,
IN LPARAM lParam
)
{
BOOL bStatus = TRUE;
switch (uMsg)
{
case WM_INITDIALOG:
bSetUI();
break;
case WM_SIZE:
bStatus = bHandle_WM_SIZE( wParam, lParam );
break;
case WM_GETMINMAXINFO:
bStatus = bHandle_WM_GETMINMAXINFO( wParam, lParam );
break;
case WM_COMMAND:
switch ( LOWORD( wParam ) )
{
case IDOK:
case IDCANCEL:
EndDialog( _hDlg, LOWORD( wParam ) );
break;
default:
bStatus = FALSE;
break;
}
default:
bStatus = FALSE;
break;
}
return bStatus;
}
/********************************************************************
Very simple file output class
********************************************************************/
TFile::
TFile(
IN LPCTSTR pszFileName,
IN BOOL bNoUnicodeByteMark
) : _strFileName( pszFileName ),
_hFile( INVALID_HANDLE_VALUE ),
_bValid( FALSE )
{
if( !_strFileName.bEmpty() )
{
_hFile = CreateFile( _strFileName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL );
if( _hFile != INVALID_HANDLE_VALUE )
{
_bValid = TRUE;
}
//
// If we are built for unicode then write the unicode byte mark.
//
if( _bValid && !bNoUnicodeByteMark )
{
WORD wUnicodeByteMark = kUnicodePrefix;
_bValid = bWrite( sizeof( wUnicodeByteMark ), reinterpret_cast<LPBYTE>( &wUnicodeByteMark ) );
}
}
}
TFile::
~TFile(
VOID
)
{
if( _hFile != INVALID_HANDLE_VALUE )
{
CloseHandle( _hFile );
}
}
BOOL
TFile::
bValid(
VOID
)
{
return _bValid;
}
BOOL
TFile::
bWrite(
IN TString &strString,
OUT UINT *pBytesWritten OPTIONAL
)
{
return bWrite( strString.uLen() * sizeof( TCHAR ),
reinterpret_cast<LPBYTE>( const_cast<LPTSTR>( static_cast<LPCTSTR>( strString ) ) ),
pBytesWritten );
}
BOOL
TFile::
bWrite(
IN UINT uSize,
IN LPBYTE pData,
OUT UINT *pBytesWritten OPTIONAL
)
{
DWORD dwWritten;
TStatusB bStatus;
bStatus DBGCHK = WriteFile(_hFile,
pData,
uSize,
&dwWritten,
NULL );
if( bStatus )
{
if( pBytesWritten )
{
*pBytesWritten = dwWritten;
}
bStatus DBGCHK = dwWritten == uSize ? TRUE : FALSE;
}
return bStatus;
}