405 lines
8.8 KiB
C
405 lines
8.8 KiB
C
/*++
|
|
|
|
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;
|
|
}
|
|
|