Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

404 lines
8.8 KiB

/*++
Copyright (c) 1997 Microsoft Corporation
All rights reserved
Module Name:
devmode.c
Abstract:
Handles per-user devmode implementation.
Author:
Environment:
User Mode -Win32
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
#include "client.h"
/********************************************************************
Forward prototypes
********************************************************************/
LPWSTR
FormatPrinterForRegistryKey(
LPWSTR pSource,
LPWSTR pScratch
);
BOOL
bGetDevModeLocation(
IN PSPOOL pSpool,
OUT PHKEY phKey,
OUT LPCWSTR *ppszValue
);
const WCHAR gszPrinterConnections[] = L"Printers\\Connections\\";
const WCHAR gszDevMode[] = L"DevMode";
const WCHAR gszDevModePerUserLocal[] = L"Printers\\DevModePerUser";
/********************************************************************
Public functions
********************************************************************/
BOOL
bSetDevModePerUser(
PSPOOL pSpool,
PDEVMODE pDevMode
)
/*++
Routine Description:
Sets the per-user DevMode in HKCU.
Arguments:
pSpool - Printer to set.
pDevMode - DevMode to save. If NULL, deletes value.
Return Value:
TRUE - Success
FALSE - Failure
--*/
{
HKEY hKey = NULL;
BOOL bReturn = FALSE;
LPWSTR pszValue = NULL;
DWORD dwStatus = ERROR_SUCCESS;
//
// Retrieve the location of the DevMode.
//
bReturn = bGetDevModeLocation( pSpool,
&hKey,
&pszValue );
if( bReturn ){
if( !pDevMode ){
//
// NULL, so delete the value.
//
dwStatus = RegDeleteValue( hKey, pszValue );
} else {
dwStatus = RegSetValueEx( hKey,
pszValue,
0,
REG_BINARY,
(PBYTE)pDevMode,
pDevMode->dmSize +
pDevMode->dmDriverExtra );
}
RegCloseKey( hKey );
}
if( dwStatus != ERROR_SUCCESS ){
SetLastError( dwStatus );
bReturn = FALSE;
}
return bReturn;
}
BOOL
bGetDevModePerUser(
PSPOOL pSpool,
PDEVMODE *ppDevMode
)
/*++
Routine Description:
Retrieves the per-user DevMode based on the current user.
Arguments:
pSpool - Printer to use.
ppDevMode - Receives pointer to devmode. Must be freed by callee.
Return Value:
TRUE - Success: able to check if per-user DevMode exists. *ppDevMode
is NULL if no per-user DevMode is there. (TRUE does not indicate
that a per-user DevMode was found, only that we successfully checked.)
FALSE - Failure.
--*/
{
HKEY hKey = NULL;
BOOL bReturn = FALSE;
LPWSTR pszValue = NULL;
LONG Status = ERROR_SUCCESS;
*ppDevMode = NULL;
//
// Retrieve the location of the DevMode.
//
if( bGetDevModeLocation( pSpool,
&hKey,
&pszValue )){
DWORD cbDevModePerUser;
//
// Key exists. See if we can read it and get the per-user DevMode.
//
Status = RegQueryInfoKey( hKey,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
&cbDevModePerUser,
NULL,
NULL );
if( Status == ERROR_SUCCESS ){
*ppDevMode = AllocSplMem( cbDevModePerUser );
if( *ppDevMode ){
Status = RegQueryValueEx( hKey,
pszValue,
NULL,
NULL,
(PBYTE)*ppDevMode,
&cbDevModePerUser );
if( Status == ERROR_SUCCESS ){
bReturn = TRUE;
}
}
if( !bReturn ){
FreeSplMem( *ppDevMode );
*ppDevMode = NULL;
}
//
// Allow ERROR_FILE_NOT_FOUND to return success. *ppDevMode
// is still NULL, but we return TRUE to indicate that we
// successfully checked the registry--we just didn't find one.
//
if( Status == ERROR_FILE_NOT_FOUND ){
bReturn = TRUE;
}
}
RegCloseKey( hKey );
}
if( !bReturn ){
SetLastError( Status );
}
return bReturn;
}
BOOL
bCompatibleDevMode(
PSPOOL pSpool,
PDEVMODE pDevModeBase,
PDEVMODE pDevModeNew
)
/*++
Routine Description:
Check if two DevModes are compatible (e.g., they can be used
interchangably).
This is done by checking size and version information. Not
foolproof, but the best we can do since we can't look at private
information.
Arguments:
pSpool - Printer to check.
pDevModeBase - Known good DevMode.
pDevModeNew - DevMode to check.
Return Value:
TRUE - Appears compatible.
FALSE - Not compatible.
--*/
{
if( !pDevModeBase || ! pDevModeNew ){
return FALSE;
}
return pDevModeBase->dmSize == pDevModeNew->dmSize &&
pDevModeBase->dmDriverExtra == pDevModeNew->dmDriverExtra &&
pDevModeBase->dmSpecVersion == pDevModeNew->dmSpecVersion &&
pDevModeBase->dmDriverVersion == pDevModeNew->dmDriverVersion;
}
/********************************************************************
Support Functions
********************************************************************/
LPWSTR
FormatPrinterForRegistryKey(
LPWSTR pSource,
LPWSTR pScratch
)
{
if (pScratch != pSource) {
//
// Copy the string into the scratch buffer:
//
wcscpy(pScratch, pSource);
}
//
// Check each character, and, if it's a backslash,
// convert it to a comma:
//
for (pSource = pScratch; *pSource; pSource++) {
if (*pSource == L'\\')
*pSource = L',';
}
return pScratch;
}
BOOL
bGetDevModeLocation(
IN PSPOOL pSpool,
OUT PHKEY phKey,
OUT LPCWSTR *ppszValue
)
/*++
Routine Description:
Retrieves the location of the per-user DevMode.
On success, caller is responsible for closing phKey. ppszValue's
life is dependent on pSpool.
Arguments:
pSpool - Printer to use.
phKey - Receives R/W key of per-user DevMode. On success, this
must be closed by caller.
ppszValue - Receives value of per-user DevMode (where to read/write).
Return Value:
TRUE - Success
FALSE - Failure, LastError set.
--*/
{
WCHAR szPrinterScratch[MAX_PRINTER_NAME + COUNTOF( gszPrinterConnections )];
BOOL bReturn = FALSE;
DWORD dwError = ERROR_SUCCESS;
//
// If it starts with two backslashes, it may be either a connection
// or a masq printer.
//
if( pSpool->pszPrinter[0] == L'\\' && pSpool->pszPrinter[1] == L'\\' ){
//
// Query the registry for pSpool->pszPrinter and look for DevMode.
// First look at the HKCU:Printer\Connections.
//
wcscpy( szPrinterScratch, gszPrinterConnections );
FormatPrinterForRegistryKey(
pSpool->pszPrinter,
&szPrinterScratch[ COUNTOF( gszPrinterConnections )-1] );
dwError = RegOpenKeyEx( HKEY_CURRENT_USER,
szPrinterScratch,
0,
KEY_READ | KEY_WRITE,
phKey );
if( dwError == ERROR_SUCCESS ){
*ppszValue = gszDevMode;
bReturn = TRUE;
}
}
if( !bReturn ){
DWORD dwIgnore;
//
// Not a connection or didn't exist in the connections key.
// Look in the Printers\DevModePerUser key.
//
dwError = RegCreateKeyEx( HKEY_CURRENT_USER,
gszDevModePerUserLocal,
0,
NULL,
0,
KEY_READ | KEY_WRITE,
NULL,
phKey,
&dwIgnore );
if( dwError == ERROR_SUCCESS ){
*ppszValue = pSpool->pszPrinter;
bReturn = TRUE;
}
}
if( !bReturn ){
SetLastError( dwError );
}
return bReturn;
}