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.
1876 lines
47 KiB
1876 lines
47 KiB
/*++
|
|
|
|
Copyright (c) 1998-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
w32drprn
|
|
|
|
Abstract:
|
|
|
|
This module defines the parent for the Win32 client-side RDP
|
|
printer redirection "device" class hierarchy, W32DrPRN.
|
|
|
|
Author:
|
|
|
|
Tad Brockway 3/23/99
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <precom.h>
|
|
|
|
#define TRC_FILE "W32DrPRN"
|
|
|
|
#include <string.h>
|
|
#include "w32drprn.h"
|
|
#include "w32utl.h"
|
|
#include "drobjmgr.h"
|
|
#include "w32drman.h"
|
|
#include "w32proc.h"
|
|
#include "drdbg.h"
|
|
#ifdef OS_WINCE
|
|
#include "ceconfig.h"
|
|
#endif
|
|
|
|
DWORD W32DrPRN::_maxCacheDataSize = DEFAULT_MAXCACHELEN;
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
//
|
|
// W32DrPRN Members
|
|
//
|
|
|
|
W32DrPRN::W32DrPRN(ProcObj *processObject, const DRSTRING printerName,
|
|
const DRSTRING driverName, const DRSTRING portName,
|
|
const DRSTRING pnpName,
|
|
BOOL isDefaultPrinter, ULONG deviceID,
|
|
const TCHAR *devicePath) :
|
|
W32DrDeviceAsync(processObject, deviceID, devicePath),
|
|
DrPRN(printerName, driverName, pnpName, isDefaultPrinter)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Constructor
|
|
|
|
Arguments:
|
|
|
|
printerName - Name of printing device.
|
|
driverName - Name of print driver name.
|
|
portName - Name of client-side printing port.
|
|
pnpName - PnP ID String
|
|
default - Is this the default printer?
|
|
id - Unique device identifier for printing device.
|
|
devicePath - Path to the device.
|
|
|
|
Return Value:
|
|
|
|
NA
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Record the port name.
|
|
//
|
|
SetPortName(portName);
|
|
}
|
|
|
|
W32DrPRN *
|
|
W32DrPRN::ResolveCachedPrinter(
|
|
IN ProcObj *procObj,
|
|
IN DrDeviceMgr *deviceMgr,
|
|
IN HKEY hParentKey,
|
|
IN LPTSTR printerName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Open the subkey of hParentKey associated with the specified
|
|
printer name and instantiate a manual printer or find an existing
|
|
automatic printer object in the device manager, depending on the
|
|
type of cached data found.
|
|
|
|
Arguments:
|
|
|
|
procObj - Associated Processing Object.
|
|
hParentKey - Parent key of printer key.
|
|
printerName - Name of printer ... and name of printer subkey.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
W32DrPRN *prnDevice = NULL;
|
|
DWORD cachedDataSize;
|
|
LPTSTR regValueName;
|
|
LONG result;
|
|
HKEY hPrinterKey;
|
|
DWORD ulType;
|
|
BOOL isManual = FALSE;
|
|
|
|
|
|
DC_BEGIN_FN("W32DrPRN::ResolveCachedPrinter");
|
|
|
|
//
|
|
// Open the key for the cached printer.
|
|
//
|
|
result = RegCreateKeyEx(
|
|
hParentKey, printerName, 0L,
|
|
NULL, REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS, NULL,
|
|
&hPrinterKey, NULL
|
|
);
|
|
if (result != ERROR_SUCCESS) {
|
|
TRC_ERR((TB, _T("RegCreateKeyEx failed: %ld."),result));
|
|
hPrinterKey = NULL;
|
|
goto CleanUpAndExit;
|
|
}
|
|
|
|
//
|
|
// See if the value name for the cached printer data is for
|
|
// a manual printer.
|
|
//
|
|
regValueName = (LPTSTR)REG_RDPDR_PRINTER_CACHE_DATA;
|
|
cachedDataSize = 0;
|
|
#ifndef OS_WINCE
|
|
result = RegQueryValueEx(hPrinterKey, regValueName,
|
|
NULL, &ulType, NULL, &cachedDataSize
|
|
);
|
|
//
|
|
// Check for hacks
|
|
//
|
|
if (cachedDataSize >= GetMaxCacheDataSize() * 1000) {
|
|
ASSERT(FALSE);
|
|
goto CleanUpAndExit;
|
|
}
|
|
|
|
#else
|
|
cachedDataSize = GetCachedDataSize(hPrinterKey);
|
|
#endif
|
|
//
|
|
// If no manual printer then check for an automatic printer.
|
|
//
|
|
if (result == ERROR_FILE_NOT_FOUND) {
|
|
|
|
regValueName = (LPTSTR)REG_RDPDR_AUTO_PRN_CACHE_DATA;
|
|
cachedDataSize = 0;
|
|
result = RegQueryValueEx(hPrinterKey, regValueName,
|
|
NULL, &ulType, NULL, &cachedDataSize
|
|
);
|
|
|
|
//
|
|
// If the entry exists and has some data associated with it
|
|
// then see if we have a corresponding automatic printer to
|
|
// add the data to.
|
|
//
|
|
if ((result == ERROR_SUCCESS) && (cachedDataSize > 0)) {
|
|
prnDevice = (W32DrPRN *)deviceMgr->GetObject(
|
|
(LPTSTR)printerName,
|
|
RDPDR_DTYP_PRINT
|
|
);
|
|
if (prnDevice != NULL) {
|
|
ASSERT(!STRICMP(prnDevice->ClassName(), TEXT("W32DrAutoPrn")));
|
|
}
|
|
}
|
|
else {
|
|
prnDevice = NULL;
|
|
}
|
|
}
|
|
//
|
|
// Otherwise, if there is some actual cached data then instantiate
|
|
// a manual printer object and add it to the device manager.
|
|
//
|
|
else if ((result == ERROR_SUCCESS) && (cachedDataSize > 0)) {
|
|
TCHAR UniquePortName[MAX_PATH];
|
|
ULONG DeviceId;
|
|
|
|
isManual = TRUE;
|
|
|
|
//
|
|
// The unique port name is going to be passed to the server
|
|
// as preferred dos name (max 7 characters long). As we want to
|
|
// keep a unique dos name for each printer device, we need
|
|
// to fake our own port name.
|
|
//
|
|
DeviceId = deviceMgr->GetUniqueObjectID();
|
|
|
|
StringCchPrintf(UniquePortName,
|
|
SIZE_TCHARS(UniquePortName),
|
|
TEXT("PRN%ld"), DeviceId);
|
|
UniquePortName[7] = TEXT('\0');
|
|
|
|
#ifndef OS_WINCE
|
|
prnDevice = new W32DrManualPrn(procObj, printerName, TEXT(""),
|
|
UniquePortName, FALSE,
|
|
DeviceId);
|
|
#else
|
|
//check of it is the default printer
|
|
BOOL fDefault = FALSE;
|
|
HKEY hk = NULL;
|
|
WCHAR szWDefault[PREFERRED_DOS_NAME_SIZE];
|
|
UCHAR szADefault[PREFERRED_DOS_NAME_SIZE];
|
|
DWORD dwSize = sizeof(szWDefault);
|
|
if ( (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_RDPDR_WINCE_DEFAULT_PRN, 0, 0, &hk)) &&
|
|
(ERROR_SUCCESS == RegQueryValueEx(hk, NULL, NULL, &ulType, (LPBYTE )szWDefault, &dwSize)) &&
|
|
(ulType == REG_SZ) && (dwSize < sizeof(szWDefault)) &&
|
|
(WideCharToMultiByte(GetACP(), 0, szWDefault, -1, (char *)szADefault, sizeof(szADefault), NULL, NULL) > 0) )
|
|
{
|
|
UCHAR szPort[PREFERRED_DOS_NAME_SIZE] = {0};
|
|
dwSize = sizeof(szPort);
|
|
RegQueryValueEx(hPrinterKey, regValueName, NULL, &ulType, szPort, &dwSize);
|
|
fDefault = (0 == _stricmp((char *)szADefault, (char *)szPort));
|
|
}
|
|
if (hk)
|
|
RegCloseKey(hk);
|
|
|
|
prnDevice = new W32DrManualPrn(procObj, printerName, TEXT(""),
|
|
UniquePortName, fDefault,
|
|
DeviceId);
|
|
#endif
|
|
|
|
if (prnDevice != NULL) {
|
|
prnDevice->Initialize();
|
|
if (!prnDevice->IsValid() ||
|
|
(deviceMgr->AddObject(prnDevice) != ERROR_SUCCESS)) {
|
|
delete prnDevice;
|
|
prnDevice = NULL;
|
|
}
|
|
}
|
|
else {
|
|
TRC_ERR((TB, _T("Out of memory when crating manual printer.")));
|
|
}
|
|
}
|
|
else {
|
|
TRC_NRM((TB, _T("Can't resolve printer %s."),printerName));
|
|
prnDevice = NULL;
|
|
}
|
|
|
|
//
|
|
// If ended up with a printer device object then add the cached data.
|
|
//
|
|
if ((prnDevice != NULL) &&
|
|
(prnDevice->SetCachedDataSize(cachedDataSize) == ERROR_SUCCESS)) {
|
|
|
|
//
|
|
// Read the cached data.
|
|
//
|
|
#ifndef OS_WINCE
|
|
result = RegQueryValueEx(hPrinterKey, regValueName,
|
|
NULL, &ulType, prnDevice->GetCachedDataPtr(),
|
|
&cachedDataSize
|
|
);
|
|
#else
|
|
ulType = REG_BINARY;
|
|
result = ReadCachedData(hPrinterKey,
|
|
prnDevice->GetCachedDataPtr(),
|
|
&cachedDataSize
|
|
);
|
|
#endif
|
|
|
|
//
|
|
// Let the printer device object know that we are done recovering
|
|
// cached data.
|
|
//
|
|
if (result == ERROR_SUCCESS) {
|
|
//
|
|
// Make sure the found data is binary data.
|
|
//
|
|
ASSERT(ulType == REG_BINARY);
|
|
if (ulType == REG_BINARY) {
|
|
prnDevice->CachedDataRestored();
|
|
}
|
|
else {
|
|
result = ERROR_INVALID_DATA;
|
|
}
|
|
}
|
|
else {
|
|
TRC_NRM((TB, _T("RegQueryValueEx failed: %ld."),result));
|
|
}
|
|
|
|
//
|
|
// On error processing the cached data.
|
|
//
|
|
if ((result != ERROR_SUCCESS) || (!prnDevice->IsValid())) {
|
|
//
|
|
// For a manual printer, we should close and delete its reg key.
|
|
//
|
|
if (isManual) {
|
|
TRC_ALT((TB, _T("Deleting manual printer %s on cache data error."),
|
|
printerName));
|
|
ASSERT(hPrinterKey != NULL);
|
|
RegCloseKey(hPrinterKey);
|
|
hPrinterKey = NULL;
|
|
RegDeleteKey(hParentKey, printerName);
|
|
}
|
|
//
|
|
// If the printer is an auto printer, zero the cached data for this device
|
|
// on error and delete the reg value, but we should still redirect the
|
|
// printer.
|
|
//
|
|
else {
|
|
prnDevice->SetCachedDataSize(0);
|
|
RegDeleteValue(hPrinterKey, regValueName);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// See if our resulting printer is valid after all this processing. If not,
|
|
// it should be whacked and removed from the device object list.
|
|
//
|
|
if ((prnDevice != NULL) && !prnDevice->IsValid()) {
|
|
TRC_ERR((TB, _T("Whacking invalid printer device %s."), printerName));
|
|
deviceMgr->RemoveObject(prnDevice->GetID());
|
|
delete prnDevice;
|
|
prnDevice = NULL;
|
|
}
|
|
|
|
CleanUpAndExit:
|
|
|
|
//
|
|
// Close the printer registry key.
|
|
//
|
|
if (hPrinterKey != NULL) {
|
|
RegCloseKey(hPrinterKey);
|
|
}
|
|
|
|
DC_END_FN();
|
|
return prnDevice;
|
|
}
|
|
|
|
VOID
|
|
W32DrPRN::ProcessPrinterCacheInfo(
|
|
IN PRDPDR_PRINTER_CACHEDATA_PACKET pCachePacket,
|
|
IN UINT32 maxDataLen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Process device cache info packet from the server.
|
|
|
|
Arguments:
|
|
|
|
pCachePacket - Pointer to the cache info packet from server.
|
|
maxDataLen - Maximum data length for this packet
|
|
|
|
Return Value:
|
|
|
|
NA
|
|
|
|
--*/
|
|
{
|
|
DC_BEGIN_FN("DrPRN::ProcessPrinterCacheInfo");
|
|
//
|
|
// Compute the valid maximum length that any of the events have
|
|
//
|
|
maxDataLen -= sizeof(RDPDR_PRINTER_CACHEDATA_PACKET);
|
|
switch ( pCachePacket->EventId )
|
|
{
|
|
case RDPDR_ADD_PRINTER_EVENT :
|
|
AddPrinterCacheInfo(
|
|
(PRDPDR_PRINTER_ADD_CACHEDATA)(pCachePacket + 1), maxDataLen);
|
|
break;
|
|
|
|
case RDPDR_DELETE_PRINTER_EVENT :
|
|
DeletePrinterCacheInfo(
|
|
(PRDPDR_PRINTER_DELETE_CACHEDATA)(pCachePacket + 1), maxDataLen);
|
|
break;
|
|
|
|
case RDPDR_UPDATE_PRINTER_EVENT :
|
|
UpdatePrinterCacheInfo(
|
|
(PRDPDR_PRINTER_UPDATE_CACHEDATA)(pCachePacket + 1), maxDataLen);
|
|
break;
|
|
|
|
case RDPDR_RENAME_PRINTER_EVENT :
|
|
RenamePrinterCacheInfo(
|
|
(PRDPDR_PRINTER_RENAME_CACHEDATA)(pCachePacket + 1), maxDataLen);
|
|
break;
|
|
default:
|
|
TRC_ALT((TB, _T("Unhandled %ld."), pCachePacket->EventId));
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Clean up the server message because the transaction is complete.
|
|
//
|
|
delete pCachePacket;
|
|
DC_END_FN();
|
|
}
|
|
|
|
ULONG
|
|
W32DrPRN::AddPrinterCacheInfo(
|
|
PRDPDR_PRINTER_ADD_CACHEDATA pAddPrinterData,
|
|
UINT32 maxDataLen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Writes device cache info to the registry.
|
|
|
|
Arguments:
|
|
|
|
pAddPrinterData - pointer to the RDPDR_PRINTER_ADD_CACHEDATA structure.
|
|
maxDataLen - Maximum data length for this data
|
|
|
|
Return Value:
|
|
|
|
Windows Error Code.
|
|
|
|
--*/
|
|
{
|
|
ULONG ulError;
|
|
LPTSTR pszKeyName;
|
|
LPWSTR pszUnicodeKeyString;
|
|
PBYTE lpStringData;
|
|
|
|
HKEY hKey = NULL;
|
|
HKEY hPrinterKey = NULL;
|
|
ULONG ulDisposition;
|
|
ULONG ulPrinterData;
|
|
|
|
DC_BEGIN_FN("W32DrPRN::AddPrinterCacheInfo");
|
|
|
|
ASSERT(pAddPrinterData->PrinterNameLen != 0);
|
|
|
|
if( pAddPrinterData->PrinterNameLen == 0 ) {
|
|
ulError = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
ulPrinterData =
|
|
sizeof(RDPDR_PRINTER_ADD_CACHEDATA) +
|
|
pAddPrinterData->PnPNameLen +
|
|
pAddPrinterData->DriverLen +
|
|
pAddPrinterData->PrinterNameLen +
|
|
pAddPrinterData->CachedFieldsLen;
|
|
|
|
//
|
|
// Make sure that the data length is valid.
|
|
// Make sure that the cache info doesn't exceed
|
|
// the max configured length
|
|
//
|
|
//
|
|
if(ulPrinterData > maxDataLen ||
|
|
ulPrinterData > GetMaxCacheDataSize() * 1000) {
|
|
ulError = ERROR_INVALID_DATA;
|
|
TRC_ERR((TB, _T("Cache Data Length is invalid - %ld"), ulError));
|
|
ASSERT(FALSE);
|
|
goto Cleanup;
|
|
}
|
|
//
|
|
// Prepare registry key name.
|
|
//
|
|
lpStringData = (PBYTE)(pAddPrinterData + 1);
|
|
pszUnicodeKeyString = (LPWSTR)
|
|
(lpStringData +
|
|
pAddPrinterData->PnPNameLen +
|
|
pAddPrinterData->DriverLen);
|
|
|
|
#ifdef UNICODE
|
|
pszKeyName = pszUnicodeKeyString;
|
|
#else
|
|
//
|
|
// Convert the unicode string to ansi.
|
|
//
|
|
CHAR achAnsiKeyName[MAX_PATH];
|
|
|
|
RDPConvertToAnsi(
|
|
pszUnicodeKeyString,
|
|
(LPSTR)achAnsiKeyName,
|
|
sizeof(achAnsiKeyName) );
|
|
|
|
pszKeyName = (LPSTR)achAnsiKeyName;
|
|
#endif
|
|
|
|
//
|
|
// Open rdpdr cached printers key.
|
|
//
|
|
ulError =
|
|
RegCreateKeyEx(
|
|
HKEY_CURRENT_USER,
|
|
REG_RDPDR_CACHED_PRINTERS,
|
|
0L,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKey,
|
|
&ulDisposition);
|
|
if (ulError != ERROR_SUCCESS) {
|
|
TRC_ERR((TB, _T("RegCreateKeyEx %ld."), ulError));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Create/Open registry key.
|
|
//
|
|
ulError =
|
|
RegCreateKeyEx(
|
|
hKey,
|
|
pszKeyName,
|
|
0L,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hPrinterKey,
|
|
&ulDisposition);
|
|
if (ulError != ERROR_SUCCESS) {
|
|
|
|
TRC_ERR((TB, _T("RegCreateKeyEx %ld."), ulError));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Write cache data.
|
|
//
|
|
ulError =
|
|
RegSetValueEx(
|
|
hPrinterKey,
|
|
REG_RDPDR_PRINTER_CACHE_DATA,
|
|
NULL,
|
|
REG_BINARY,
|
|
(PBYTE)pAddPrinterData,
|
|
ulPrinterData
|
|
);
|
|
if (ulError != ERROR_SUCCESS) {
|
|
TRC_ERR((TB, _T("RegSetValueEx() failed, %ld."), ulError));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// We are done.
|
|
//
|
|
Cleanup:
|
|
if( hPrinterKey != NULL ) {
|
|
RegCloseKey( hPrinterKey );
|
|
}
|
|
if( hKey != NULL ) {
|
|
RegCloseKey( hKey );
|
|
}
|
|
|
|
DC_END_FN();
|
|
|
|
return ulError;
|
|
}
|
|
|
|
ULONG
|
|
W32DrPRN::DeletePrinterCacheInfo(
|
|
PRDPDR_PRINTER_DELETE_CACHEDATA pDeletePrinterData,
|
|
UINT32 maxDataLen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Delete device cache info from the registry.
|
|
|
|
Arguments:
|
|
|
|
pDeletePrinterData - pointer to the RDPDR_PRINTER_DELETE_CACHEDATA structure.
|
|
maxDataLen - Maximum data length for this data
|
|
|
|
Return Value:
|
|
|
|
Windows Error Code.
|
|
|
|
--*/
|
|
{
|
|
ULONG ulError;
|
|
LPTSTR pszKeyName;
|
|
LPWSTR pszUnicodeKeyString;
|
|
|
|
HKEY hKey = NULL;
|
|
ULONG ulDisposition;
|
|
|
|
DC_BEGIN_FN("W32DrPRN::DeletePrinterCacheInfo");
|
|
|
|
ASSERT(pDeletePrinterData->PrinterNameLen != 0);
|
|
|
|
if( pDeletePrinterData->PrinterNameLen == 0 ) {
|
|
ulError = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
ULONG ulPrinterData =
|
|
sizeof(RDPDR_PRINTER_DELETE_CACHEDATA) +
|
|
pDeletePrinterData->PrinterNameLen;
|
|
//
|
|
// Make sure that the data length is valid
|
|
//
|
|
if(ulPrinterData > maxDataLen ||
|
|
ulPrinterData > GetMaxCacheDataSize() * 1000) {
|
|
ulError = ERROR_INVALID_DATA;
|
|
TRC_ERR((TB, _T("Cache Data Length is invalid - %ld"), ulError));
|
|
ASSERT(FALSE);
|
|
goto Cleanup;
|
|
}
|
|
//
|
|
// prepare registry key name.
|
|
//
|
|
pszUnicodeKeyString = (LPWSTR)(pDeletePrinterData + 1);
|
|
|
|
#ifdef UNICODE
|
|
|
|
pszKeyName = pszUnicodeKeyString;
|
|
|
|
#else // UNICODE
|
|
|
|
//
|
|
// convert the unicode string to ansi.
|
|
//
|
|
|
|
CHAR achAnsiKeyName[MAX_PATH];
|
|
|
|
RDPConvertToAnsi(
|
|
pszUnicodeKeyString,
|
|
(LPSTR)achAnsiKeyName,
|
|
sizeof(achAnsiKeyName) );
|
|
|
|
pszKeyName = (LPSTR)achAnsiKeyName;
|
|
|
|
#endif // UNICODE
|
|
|
|
//
|
|
// open rdpdr cached printers key.
|
|
//
|
|
|
|
ulError =
|
|
RegCreateKeyEx(
|
|
HKEY_CURRENT_USER,
|
|
REG_RDPDR_CACHED_PRINTERS,
|
|
0L,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKey,
|
|
&ulDisposition);
|
|
|
|
if (ulError != ERROR_SUCCESS) {
|
|
|
|
TRC_ERR((TB, _T("RegCreateKeyEx() failed, %ld."), ulError));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// delete registry key.
|
|
//
|
|
// Note : assumed, no sub-key presends.
|
|
//
|
|
|
|
ulError = RegDeleteKey( hKey, pszKeyName );
|
|
|
|
if (ulError != ERROR_SUCCESS) {
|
|
|
|
TRC_ERR((TB, _T("RegDeleteKey() failed, %ld."), ulError));
|
|
goto Cleanup;
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if( hKey != NULL ) {
|
|
RegCloseKey( hKey );
|
|
}
|
|
|
|
DC_END_FN();
|
|
return ulError;
|
|
}
|
|
|
|
ULONG
|
|
W32DrPRN::RenamePrinterCacheInfo(
|
|
PRDPDR_PRINTER_RENAME_CACHEDATA pRenamePrinterData,
|
|
UINT32 maxDataLen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Rename device cache info in the registry.
|
|
|
|
Arguments:
|
|
|
|
pRenamePrinterData - pointer to the RDPDR_PRINTER_RENAME_CACHEDATA
|
|
structure.
|
|
maxDataLen - Maximum data length for this data
|
|
|
|
Return Value:
|
|
|
|
Windows Error Code.
|
|
|
|
--*/
|
|
{
|
|
DC_BEGIN_FN("W32DrPRN::RenamePrinterCacheInfo");
|
|
|
|
ULONG ulError;
|
|
|
|
LPTSTR pszOldKeyName;
|
|
LPTSTR pszNewKeyName;
|
|
LPWSTR pszOldUnicodeKeyString;
|
|
LPWSTR pszNewUnicodeKeyString;
|
|
|
|
HKEY hKey = NULL;
|
|
HKEY hOldKey = NULL;
|
|
HKEY hNewKey = NULL;
|
|
ULONG ulDisposition;
|
|
ULONG ulType;
|
|
|
|
ULONG ulPrinterDataLen;
|
|
ULONG ulAllocPrinterDataLen = REGISTRY_ALLOC_DATA_SIZE;
|
|
PBYTE pbPrinterData = NULL;
|
|
BOOL bBufferExpanded = FALSE;
|
|
|
|
BOOL bAutoPrinter = FALSE;
|
|
LPTSTR pszValueStr;
|
|
|
|
pszValueStr = (LPTSTR)REG_RDPDR_PRINTER_CACHE_DATA;
|
|
|
|
ASSERT(pRenamePrinterData->OldPrinterNameLen != 0);
|
|
|
|
ASSERT(pRenamePrinterData->NewPrinterNameLen != 0);
|
|
|
|
if( pRenamePrinterData->OldPrinterNameLen == 0 ) {
|
|
ulError = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if( pRenamePrinterData->NewPrinterNameLen == 0 ) {
|
|
ulError = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
ULONG ulPrinterData =
|
|
sizeof(RDPDR_PRINTER_RENAME_CACHEDATA) +
|
|
pRenamePrinterData->OldPrinterNameLen +
|
|
pRenamePrinterData->NewPrinterNameLen;
|
|
|
|
//
|
|
// Make sure that the data length is valid
|
|
//
|
|
if(ulPrinterData > maxDataLen ||
|
|
ulPrinterData > GetMaxCacheDataSize() * 1000) {
|
|
ulError = ERROR_INVALID_DATA;
|
|
TRC_ERR((TB, _T("Cache Data Length is invalid - %ld"), ulError));
|
|
ASSERT(FALSE);
|
|
goto Cleanup;
|
|
}
|
|
//
|
|
// prepare registry key name.
|
|
//
|
|
|
|
pszOldUnicodeKeyString = (LPWSTR)(pRenamePrinterData + 1);
|
|
pszNewUnicodeKeyString = (LPWSTR)
|
|
((PBYTE)pszOldUnicodeKeyString +
|
|
pRenamePrinterData->OldPrinterNameLen);
|
|
|
|
TRC_ERR((TB, _T("pszOldUnicodeKeyString is %ws."), pszOldUnicodeKeyString));
|
|
TRC_ERR((TB, _T("pszNewUnicodeKeyString is %ws."), pszNewUnicodeKeyString));
|
|
|
|
//
|
|
// No change in queue name.
|
|
//
|
|
if( _wcsicmp(pszOldUnicodeKeyString, pszNewUnicodeKeyString) == 0 ) {
|
|
ulError = ERROR_SUCCESS;
|
|
goto Cleanup;
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
|
|
pszOldKeyName = pszOldUnicodeKeyString;
|
|
pszNewKeyName = pszNewUnicodeKeyString;
|
|
|
|
#else // UNICODE
|
|
|
|
//
|
|
// convert the unicode string to ansi.
|
|
//
|
|
|
|
CHAR achOldAnsiKeyName[MAX_PATH];
|
|
CHAR achNewAnsiKeyName[MAX_PATH];
|
|
|
|
RDPConvertToAnsi(
|
|
pszOldUnicodeKeyString,
|
|
(LPSTR)achOldAnsiKeyName,
|
|
sizeof(achOldAnsiKeyName) );
|
|
|
|
pszOldKeyName = (LPSTR)achOldAnsiKeyName;
|
|
|
|
RDPConvertToAnsi(
|
|
pszNewUnicodeKeyString,
|
|
(LPSTR)achNewAnsiKeyName,
|
|
sizeof(achNewAnsiKeyName) );
|
|
|
|
pszNewKeyName = (LPSTR)achNewAnsiKeyName;
|
|
|
|
|
|
|
|
#endif // UNICODE
|
|
|
|
//
|
|
// open rdpdr cached printers key.
|
|
//
|
|
|
|
ulError =
|
|
RegCreateKeyEx(
|
|
HKEY_CURRENT_USER,
|
|
REG_RDPDR_CACHED_PRINTERS,
|
|
0L,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKey,
|
|
&ulDisposition);
|
|
|
|
if (ulError != ERROR_SUCCESS) {
|
|
|
|
TRC_ERR((TB, _T("RegCreateKeyEx() failed, %ld."), ulError));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Open old Key.
|
|
//
|
|
|
|
ulError =
|
|
RegOpenKeyEx(
|
|
hKey,
|
|
pszOldKeyName,
|
|
0L,
|
|
KEY_ALL_ACCESS,
|
|
&hOldKey);
|
|
|
|
if (ulError != ERROR_SUCCESS) {
|
|
|
|
TRC_ERR((TB, _T("RegOpenKeyEx() failed, %ld."), ulError));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// read cache data.
|
|
//
|
|
|
|
ReadAgain:
|
|
|
|
pbPrinterData = new BYTE[ulAllocPrinterDataLen];
|
|
if( pbPrinterData == NULL ) {
|
|
ulError = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
ulPrinterDataLen = ulAllocPrinterDataLen;
|
|
ulError =
|
|
RegQueryValueEx(
|
|
hOldKey,
|
|
pszValueStr,
|
|
NULL,
|
|
&ulType,
|
|
pbPrinterData,
|
|
&ulPrinterDataLen);
|
|
|
|
TRC_ERR((TB, _T("RegQueryValueEx returned: %ld."), ulError));
|
|
|
|
if (ulError != ERROR_SUCCESS) {
|
|
if( ulError == ERROR_MORE_DATA ) {
|
|
|
|
//
|
|
// do the buffer expansion only once to aviod infinite look
|
|
// in case of registry corruption or so.
|
|
//
|
|
|
|
if( !bBufferExpanded ) {
|
|
|
|
ASSERT(ulPrinterDataLen > ulAllocPrinterDataLen);
|
|
|
|
//
|
|
// need bigger buffer.
|
|
// Compute new buffer size.
|
|
//
|
|
|
|
ulAllocPrinterDataLen =
|
|
((ulPrinterDataLen / REGISTRY_ALLOC_DATA_SIZE) + 1) *
|
|
REGISTRY_ALLOC_DATA_SIZE;
|
|
|
|
//
|
|
// free old buffer.
|
|
//
|
|
|
|
delete pbPrinterData;
|
|
pbPrinterData = NULL;
|
|
|
|
ASSERT(ulAllocPrinterDataLen >= ulPrinterDataLen);
|
|
|
|
bBufferExpanded = TRUE;
|
|
goto ReadAgain;
|
|
}
|
|
}
|
|
else {
|
|
//
|
|
// It could be auto printer. Try again.
|
|
//
|
|
if (!bAutoPrinter) {
|
|
bAutoPrinter = TRUE;
|
|
pszValueStr = (LPTSTR)REG_RDPDR_AUTO_PRN_CACHE_DATA;
|
|
|
|
//
|
|
// free old buffer
|
|
//
|
|
|
|
delete pbPrinterData;
|
|
pbPrinterData = NULL;
|
|
|
|
goto ReadAgain;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ulError != ERROR_SUCCESS) {
|
|
|
|
TRC_ERR((TB, _T("RegQueryValueEx() failed, %ld."), ulError));
|
|
goto Cleanup;
|
|
}
|
|
|
|
ASSERT(ulType == REG_BINARY);
|
|
|
|
if( ulType != REG_BINARY ) {
|
|
|
|
TRC_ERR((TB, _T("RegQueryValueEx returns wrong type, %ld."), ulType));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Update the printer name in the cache info
|
|
//
|
|
ulError = DrPRN::UpdatePrinterNameInCacheData(
|
|
&pbPrinterData,
|
|
&ulPrinterDataLen,
|
|
(PBYTE)pszNewUnicodeKeyString,
|
|
pRenamePrinterData->NewPrinterNameLen);
|
|
|
|
//
|
|
// Let's not worry about the success/failure of the above function.
|
|
// We will anyway right the cache information to the new key
|
|
//
|
|
|
|
//
|
|
// write the data to the new key.
|
|
//
|
|
|
|
//
|
|
// open new key.
|
|
//
|
|
|
|
ulError =
|
|
RegCreateKeyEx(
|
|
hKey,
|
|
pszNewKeyName,
|
|
0L,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hNewKey,
|
|
&ulDisposition);
|
|
|
|
if (ulError != ERROR_SUCCESS) {
|
|
|
|
TRC_ERR((TB, _T("RegCreateKeyEx() failed, %ld."), ulError));
|
|
goto Cleanup;
|
|
}
|
|
|
|
ASSERT(ulDisposition != REG_OPENED_EXISTING_KEY);
|
|
|
|
ulError =
|
|
RegSetValueEx(
|
|
hNewKey,
|
|
pszValueStr,
|
|
NULL,
|
|
ulType,
|
|
pbPrinterData,
|
|
ulPrinterDataLen);
|
|
|
|
if (ulError != ERROR_SUCCESS) {
|
|
|
|
TRC_ERR((TB, _T("RegSetValueEx() failed, %ld."), ulError));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Try to rename the local printer
|
|
//
|
|
if (bAutoPrinter) {
|
|
RenamePrinter(pszOldKeyName, pszNewKeyName);
|
|
}
|
|
//
|
|
// now delete old registry key.
|
|
//
|
|
// Note : assumed, no sub-key presends.
|
|
//
|
|
|
|
ulError = RegCloseKey( hOldKey );
|
|
if (ulError != ERROR_SUCCESS) {
|
|
|
|
TRC_ERR((TB, _T("RegCloseKey() failed, %ld."), ulError));
|
|
goto Cleanup;
|
|
}
|
|
|
|
hOldKey = NULL;
|
|
|
|
ulError = RegDeleteKey( hKey, pszOldKeyName );
|
|
|
|
if (ulError != ERROR_SUCCESS) {
|
|
|
|
TRC_ERR((TB, _T("RegDeleteKey() failed, %ld."), ulError));
|
|
goto Cleanup;
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
if( hKey != NULL ) {
|
|
RegCloseKey( hKey );
|
|
}
|
|
|
|
if( hOldKey != NULL ) {
|
|
RegCloseKey( hOldKey );
|
|
}
|
|
|
|
if( hNewKey != NULL ) {
|
|
RegCloseKey( hNewKey );
|
|
}
|
|
|
|
if (pbPrinterData) {
|
|
delete pbPrinterData;
|
|
}
|
|
|
|
DC_END_FN();
|
|
return ulError;
|
|
}
|
|
|
|
ULONG
|
|
W32DrPRN::UpdatePrinterCacheInfo(
|
|
PRDPDR_PRINTER_UPDATE_CACHEDATA pUpdatePrinterData,
|
|
UINT32 maxDataLen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update device cache info in the registry.
|
|
|
|
Arguments:
|
|
|
|
pUpdatePrinterData - pointer to the RDPDR_PRINTER_UPDATE_CACHEDATA
|
|
structure.
|
|
maxDataLen - Maximum data length for this data
|
|
|
|
Return Value:
|
|
|
|
Windows Error Code.
|
|
|
|
--*/
|
|
{
|
|
DC_BEGIN_FN("W32DrPRN::UpdatePrinterCacheInfo");
|
|
ULONG ulError;
|
|
LPTSTR pszKeyName;
|
|
LPWSTR pszUnicodeKeyString;
|
|
|
|
HKEY hKey = NULL;
|
|
HKEY hPrinterKey = NULL;
|
|
ULONG ulDisposition;
|
|
ULONG ulConfigDataLen;
|
|
PBYTE pbConfigData;
|
|
|
|
ULONG ulPrinterDataLen;
|
|
ULONG ulAllocPrinterDataLen = REGISTRY_ALLOC_DATA_SIZE;
|
|
PBYTE pbPrinterData = NULL;
|
|
|
|
BOOL bAutoPrinter = FALSE;
|
|
|
|
ASSERT(pUpdatePrinterData->PrinterNameLen != 0);
|
|
|
|
if( pUpdatePrinterData->PrinterNameLen == 0 ) {
|
|
ulError = ERROR_INVALID_PARAMETER;
|
|
goto Cleanup;
|
|
}
|
|
|
|
ulPrinterDataLen =
|
|
sizeof(RDPDR_PRINTER_UPDATE_CACHEDATA) +
|
|
pUpdatePrinterData->PrinterNameLen +
|
|
pUpdatePrinterData->ConfigDataLen;
|
|
|
|
//
|
|
// Make sure that the data length is valid
|
|
//
|
|
if(ulPrinterDataLen > maxDataLen ||
|
|
ulPrinterDataLen > GetMaxCacheDataSize() * 1000) {
|
|
ulError = ERROR_INVALID_DATA;
|
|
TRC_ERR((TB, _T("Cache Data Length is invalid - %ld"), ulError));
|
|
ASSERT(FALSE);
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// prepare registry key name.
|
|
//
|
|
|
|
|
|
pszUnicodeKeyString = (LPWSTR)(pUpdatePrinterData + 1);
|
|
|
|
#ifdef UNICODE
|
|
|
|
pszKeyName = pszUnicodeKeyString;
|
|
|
|
#else // UNICODE
|
|
|
|
//
|
|
// convert the unicode string to ansi.
|
|
//
|
|
|
|
CHAR achAnsiKeyName[MAX_PATH];
|
|
|
|
RDPConvertToAnsi(
|
|
pszUnicodeKeyString,
|
|
(LPSTR)achAnsiKeyName,
|
|
sizeof(achAnsiKeyName) );
|
|
|
|
pszKeyName = (LPSTR)achAnsiKeyName;
|
|
|
|
#endif // UNICODE
|
|
|
|
//
|
|
// open rdpdr cached printers key.
|
|
//
|
|
|
|
ulError =
|
|
RegCreateKeyEx(
|
|
HKEY_CURRENT_USER,
|
|
REG_RDPDR_CACHED_PRINTERS,
|
|
0L,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hKey,
|
|
&ulDisposition);
|
|
|
|
if (ulError != ERROR_SUCCESS) {
|
|
|
|
TRC_ERR((TB, _T("RegCreateKeyEx() failed, %ld."), ulError));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// update registry data.
|
|
//
|
|
|
|
//
|
|
// Open registry key.
|
|
//
|
|
|
|
ulError =
|
|
RegCreateKeyEx(
|
|
hKey,
|
|
pszKeyName,
|
|
0L,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_ALL_ACCESS,
|
|
NULL,
|
|
&hPrinterKey,
|
|
&ulDisposition);
|
|
|
|
if (ulError != ERROR_SUCCESS) {
|
|
TRC_ERR((TB, _T("RegCreateKeyEx() failed, %ld."), ulError));
|
|
goto Cleanup;
|
|
}
|
|
|
|
if( ulDisposition != REG_OPENED_EXISTING_KEY ) {
|
|
|
|
//
|
|
// we do not find a cache entry, so it must be automatic printer
|
|
// cache data.
|
|
//
|
|
|
|
bAutoPrinter = TRUE;
|
|
TRC_NRM((TB, _T("Created new Key, Auto cache printer detected.")));
|
|
}
|
|
|
|
if( !bAutoPrinter ) {
|
|
|
|
//
|
|
// read old cache data.
|
|
//
|
|
|
|
ULONG ulType;
|
|
|
|
#ifndef OS_WINCE
|
|
do {
|
|
|
|
pbPrinterData = new BYTE[ulAllocPrinterDataLen];
|
|
if( pbPrinterData == NULL ) {
|
|
ulError = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
ulPrinterDataLen = ulAllocPrinterDataLen;
|
|
ulError =
|
|
RegQueryValueEx(
|
|
hPrinterKey,
|
|
(PTCHAR)REG_RDPDR_PRINTER_CACHE_DATA,
|
|
NULL,
|
|
&ulType,
|
|
pbPrinterData,
|
|
&ulPrinterDataLen);
|
|
|
|
if( ulError == ERROR_MORE_DATA ) {
|
|
|
|
ASSERT(ulPrinterDataLen > ulAllocPrinterDataLen);
|
|
|
|
//
|
|
// need bigger buffer.
|
|
// Compute new buffer size.
|
|
//
|
|
|
|
ulAllocPrinterDataLen =
|
|
((ulPrinterDataLen / REGISTRY_ALLOC_DATA_SIZE) + 1) *
|
|
REGISTRY_ALLOC_DATA_SIZE;
|
|
|
|
//
|
|
// free old buffer.
|
|
//
|
|
|
|
delete pbPrinterData;
|
|
pbPrinterData = NULL;
|
|
|
|
ASSERT(ulAllocPrinterDataLen >= ulPrinterDataLen);
|
|
}
|
|
else if( ulError == ERROR_FILE_NOT_FOUND ) {
|
|
|
|
//
|
|
// we do not find a cache entry, so it must be automatic
|
|
// printer cache data.
|
|
//
|
|
|
|
TRC_NRM((TB, _T("No Old Cache data, Auto cache printer detected.")));
|
|
bAutoPrinter = TRUE;
|
|
ulError = ERROR_SUCCESS;
|
|
ulType = REG_BINARY;
|
|
}
|
|
|
|
} while ( ulError == ERROR_MORE_DATA );
|
|
#else
|
|
ulPrinterDataLen = GetCachedDataSize(hPrinterKey);
|
|
pbPrinterData = new BYTE[ulPrinterDataLen];
|
|
if( pbPrinterData == NULL ) {
|
|
ulError = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
ulType = REG_BINARY;
|
|
ulError = ReadCachedData(hPrinterKey, pbPrinterData, &ulPrinterDataLen);
|
|
#endif
|
|
|
|
|
|
if (ulError != ERROR_SUCCESS) {
|
|
TRC_ERR((TB, _T("RegQueryValueEx() failed, %ld."), ulError));
|
|
goto Cleanup;
|
|
}
|
|
|
|
ASSERT(ulType == REG_BINARY);
|
|
}
|
|
|
|
if( !bAutoPrinter ) {
|
|
|
|
//
|
|
// update the printer data.
|
|
//
|
|
|
|
ulConfigDataLen = pUpdatePrinterData->ConfigDataLen;
|
|
pbConfigData =
|
|
(PBYTE)(pUpdatePrinterData + 1) +
|
|
pUpdatePrinterData->PrinterNameLen;
|
|
|
|
ulError =
|
|
DrPRN::UpdatePrinterCacheData(
|
|
&pbPrinterData,
|
|
&ulPrinterDataLen,
|
|
pbConfigData,
|
|
ulConfigDataLen );
|
|
|
|
if (ulError != ERROR_SUCCESS) {
|
|
TRC_ERR((TB, _T("UpdatePrinterCacheData() failed, %ld."), ulError));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// write cache data.
|
|
//
|
|
|
|
#ifndef OS_WINCE
|
|
ulError =
|
|
RegSetValueEx(
|
|
hPrinterKey,
|
|
REG_RDPDR_PRINTER_CACHE_DATA,
|
|
NULL,
|
|
REG_BINARY,
|
|
pbPrinterData,
|
|
ulPrinterDataLen );
|
|
#else
|
|
ulError = WriteCachedData(hPrinterKey, pbPrinterData, ulPrinterDataLen);
|
|
#endif
|
|
}
|
|
else {
|
|
|
|
pbConfigData = (PBYTE)(pUpdatePrinterData+1);
|
|
pbConfigData += pUpdatePrinterData->PrinterNameLen;
|
|
|
|
//
|
|
// write cache data.
|
|
//
|
|
|
|
ulError =
|
|
RegSetValueEx(
|
|
hPrinterKey,
|
|
REG_RDPDR_AUTO_PRN_CACHE_DATA,
|
|
NULL,
|
|
REG_BINARY,
|
|
pbConfigData,
|
|
pUpdatePrinterData->ConfigDataLen );
|
|
}
|
|
|
|
if (ulError != ERROR_SUCCESS) {
|
|
|
|
TRC_ERR((TB, _T("RegSetValueEx() failed, %ld."), ulError));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// we are done.
|
|
//
|
|
|
|
Cleanup:
|
|
|
|
if( hPrinterKey != NULL ) {
|
|
RegCloseKey( hPrinterKey );
|
|
}
|
|
|
|
if( hKey != NULL ) {
|
|
RegCloseKey( hKey );
|
|
}
|
|
|
|
//
|
|
// delete data buffers.
|
|
//
|
|
|
|
delete pbPrinterData;
|
|
|
|
DC_END_FN();
|
|
return ulError;
|
|
}
|
|
|
|
VOID
|
|
W32DrPRN::RenamePrinter(
|
|
LPTSTR pwszOldname,
|
|
LPTSTR pwszNewname
|
|
)
|
|
{
|
|
DC_BEGIN_FN("W32DrPRN::RenamePrinter");
|
|
|
|
ASSERT(pwszOldname != NULL);
|
|
|
|
ASSERT(pwszNewname != NULL);
|
|
|
|
if (!(pwszOldname && pwszNewname)) {
|
|
DC_END_FN();
|
|
return;
|
|
}
|
|
|
|
#ifndef OS_WINCE
|
|
|
|
HANDLE hPrinter = NULL;
|
|
BOOL bRunningOn9x = TRUE;
|
|
OSVERSIONINFO osVersion;
|
|
|
|
PRINTER_INFO_2 * ppi2 = NULL;
|
|
PRINTER_INFO_2A * ppi2a = NULL; //ansi version
|
|
DWORD size = 0;
|
|
|
|
if (!OpenPrinter(pwszOldname, &hPrinter, NULL)) {
|
|
TRC_ERR((TB, _T("OpenPrinter() failed, %ld."), GetLastError()));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// We don't have GetPrinter/SetPrinter wrappers
|
|
// so just call either the A or W api's depending on the platform
|
|
// this works because we treat the returned data as an opaque
|
|
// blob and pass it from one API to the next.
|
|
//
|
|
// Doing it this way is more efficient than calling wrappers
|
|
// that would do a _lot_ of uncessary conversions. Although
|
|
// it does make the code a little bit bigger.
|
|
//
|
|
//
|
|
osVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
if (GetVersionEx(&osVersion)) {
|
|
if (osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT) {
|
|
bRunningOn9x = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB, _T("GetVersionEx: %08X"), GetLastError()));
|
|
}
|
|
|
|
//
|
|
// Code is duplicated to into two large separate
|
|
// branches to reduce number of overall branches
|
|
//
|
|
if(!bRunningOn9x)
|
|
{
|
|
//Not win9x, use UNICODE API's
|
|
if (!GetPrinter(
|
|
hPrinter,
|
|
2,
|
|
(LPBYTE)ppi2,
|
|
0,
|
|
&size)) {
|
|
|
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
|
TRC_ERR((TB, _T("GetPrinter() failed, %ld."), GetLastError()));
|
|
goto Cleanup;
|
|
}
|
|
|
|
ppi2 = (PRINTER_INFO_2 *) new BYTE [size];
|
|
|
|
if (ppi2 != NULL) {
|
|
if (!GetPrinter(
|
|
hPrinter,
|
|
2,
|
|
(LPBYTE)ppi2,
|
|
size,
|
|
&size)) {
|
|
|
|
TRC_ERR((TB, _T("GetPrinter() failed, %ld."), GetLastError()));
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
else {
|
|
TRC_ERR((TB, _T("GetPrinter() failed, %ld."), GetLastError()));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// replace the name
|
|
//
|
|
ppi2->pPrinterName = pwszNewname;
|
|
ppi2->pSecurityDescriptor = NULL; //we don't want to modify the security descriptors.
|
|
|
|
if (!SetPrinter(hPrinter, 2, (LPBYTE)ppi2, 0)) {
|
|
TRC_ERR((TB, _T("SetPrinter() failed, %ld."), GetLastError()));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Do this in ANSI mode
|
|
if (!GetPrinterA(
|
|
hPrinter,
|
|
2,
|
|
(LPBYTE)ppi2a,
|
|
0,
|
|
&size)) {
|
|
|
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
|
TRC_ERR((TB, _T("GetPrinter() failed, %ld."), GetLastError()));
|
|
goto Cleanup;
|
|
}
|
|
|
|
ppi2a = (PRINTER_INFO_2A *) new BYTE [size];
|
|
|
|
if (ppi2 != NULL) {
|
|
if (!GetPrinterA(
|
|
hPrinter,
|
|
2,
|
|
(LPBYTE)ppi2a,
|
|
size,
|
|
&size)) {
|
|
|
|
TRC_ERR((TB, _T("GetPrinter() failed, %ld."), GetLastError()));
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
else {
|
|
TRC_ERR((TB, _T("GetPrinter() failed, %ld."), GetLastError()));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// replace the name
|
|
//
|
|
CHAR ansiPrinterName[2048];
|
|
RDPConvertToAnsi( pwszNewname, ansiPrinterName,
|
|
sizeof(ansiPrinterName) );
|
|
ppi2a->pPrinterName = ansiPrinterName;
|
|
ppi2a->pSecurityDescriptor = NULL; //we don't want to modify the security descriptors.
|
|
|
|
if (!SetPrinterA(hPrinter, 2, (LPBYTE)ppi2a, 0)) {
|
|
TRC_ERR((TB, _T("SetPrinter() failed, %ld."), GetLastError()));
|
|
}
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
if (hPrinter != NULL) {
|
|
ClosePrinter(hPrinter);
|
|
}
|
|
|
|
if (ppi2) {
|
|
delete[] ppi2;
|
|
}
|
|
else if (ppi2a)
|
|
{
|
|
//can't have gone through both UNICODE and ANSI branches
|
|
delete[] ppi2a;
|
|
}
|
|
|
|
#endif //!OS_WINCE
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
ULONG
|
|
W32DrPRN::GetDevAnnounceDataSize()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Return the size (in bytes) of a device announce packet for
|
|
this device.
|
|
|
|
Arguments:
|
|
|
|
NA
|
|
|
|
Return Value:
|
|
|
|
The size (in bytes) of a device announce packet for this device.
|
|
|
|
--*/
|
|
{
|
|
ULONG size = 0;
|
|
|
|
DC_BEGIN_FN("W32DrPRN::GetDevAnnounceDataSize");
|
|
|
|
ASSERT(IsValid());
|
|
if (!IsValid()) { return 0; }
|
|
|
|
size = 0;
|
|
|
|
//
|
|
// Add the base announce size.
|
|
//
|
|
size += sizeof(RDPDR_DEVICE_ANNOUNCE);
|
|
|
|
//
|
|
// Add the printer announce header.
|
|
//
|
|
size += sizeof(RDPDR_PRINTERDEVICE_ANNOUNCE);
|
|
|
|
//
|
|
// Include printer name.
|
|
//
|
|
size += ((STRLEN(_printerName) + 1) * sizeof(WCHAR));
|
|
|
|
//
|
|
// Include printer driver name.
|
|
//
|
|
size += ((STRLEN(_driverName) + 1) * sizeof(WCHAR));
|
|
|
|
//
|
|
// Include cached data.
|
|
//
|
|
size += _cachedDataSize;
|
|
|
|
DC_END_FN();
|
|
|
|
return size;
|
|
}
|
|
|
|
VOID
|
|
W32DrPRN::GetDevAnnounceData(
|
|
IN PRDPDR_DEVICE_ANNOUNCE pDeviceAnnounce
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a device announce packet for this device to the input buffer.
|
|
|
|
Arguments:
|
|
|
|
pDeviceAnnounce - Device Packet to Append Device Data To
|
|
deviceType - Device Type Identifier
|
|
deviceID - Identifier for Device
|
|
|
|
Return Value:
|
|
|
|
NA
|
|
|
|
--*/
|
|
{
|
|
PRDPDR_PRINTERDEVICE_ANNOUNCE pPrinterAnnounce;
|
|
PBYTE pbStringData;
|
|
|
|
DC_BEGIN_FN("W32DrPRN::GetDevAnnounceData");
|
|
|
|
ASSERT(IsValid());
|
|
if (!IsValid()) { return; }
|
|
|
|
//
|
|
// Record the device ID.
|
|
//
|
|
pDeviceAnnounce->DeviceType = GetDeviceType();
|
|
pDeviceAnnounce->DeviceId = GetID();
|
|
|
|
//
|
|
// Record the port name in ANSI.
|
|
//
|
|
#ifdef UNICODE
|
|
RDPConvertToAnsi(GetPortName(), (LPSTR)pDeviceAnnounce->PreferredDosName,
|
|
sizeof(pDeviceAnnounce->PreferredDosName)
|
|
);
|
|
#else
|
|
STRCPY((char *)pDeviceAnnounce->PreferredDosName, GetPortName());
|
|
#endif
|
|
|
|
//
|
|
// Get pointers to printer-specific data.
|
|
//
|
|
pPrinterAnnounce =
|
|
(PRDPDR_PRINTERDEVICE_ANNOUNCE)(pDeviceAnnounce + 1);
|
|
|
|
//
|
|
// Embedded data pointer.
|
|
//
|
|
pbStringData = (PBYTE)(pPrinterAnnounce + 1);
|
|
|
|
//
|
|
// Flags
|
|
//
|
|
pPrinterAnnounce->Flags = 0;
|
|
if (_isDefault) {
|
|
pPrinterAnnounce->Flags |= RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER;
|
|
}
|
|
|
|
if (_isNetwork) {
|
|
pPrinterAnnounce->Flags |= RDPDR_PRINTER_ANNOUNCE_FLAG_NETWORKPRINTER;
|
|
}
|
|
|
|
if (_isTSqueue) {
|
|
pPrinterAnnounce->Flags |= RDPDR_PRINTER_ANNOUNCE_FLAG_TSPRINTER;
|
|
}
|
|
|
|
//
|
|
// ANSI Code Page
|
|
//
|
|
pPrinterAnnounce->CodePage = 0;
|
|
|
|
//
|
|
// Misc. Field Lengths
|
|
//
|
|
pPrinterAnnounce->PnPNameLen = 0;
|
|
pPrinterAnnounce->CachedFieldsLen = 0;
|
|
|
|
//
|
|
// Copy the driver name.
|
|
//
|
|
if (GetDriverName() != NULL) {
|
|
#if defined(UNICODE)
|
|
//
|
|
// Unicode to Unicode just requires a memcpy.
|
|
//
|
|
pPrinterAnnounce->DriverLen = ((STRLEN(GetDriverName()) + 1) *
|
|
sizeof(WCHAR));
|
|
memcpy(pbStringData, _driverName, pPrinterAnnounce->DriverLen);
|
|
#else
|
|
//
|
|
// On Win32 ANSI, we will convert to Unicode.
|
|
//
|
|
pPrinterAnnounce->DriverLen = ((STRLEN(GetDriverName()) + 1) *
|
|
sizeof(WCHAR));
|
|
RDPConvertToUnicode(_driverName, (LPWSTR)pbStringData,
|
|
pPrinterAnnounce->DriverLen );
|
|
#endif
|
|
pbStringData += pPrinterAnnounce->DriverLen;
|
|
}
|
|
else {
|
|
pPrinterAnnounce->DriverLen = 0;
|
|
}
|
|
|
|
//
|
|
// Copy the printer name.
|
|
//
|
|
if (GetPrinterName() != NULL) {
|
|
#if defined(UNICODE)
|
|
//
|
|
// Unicode to Unicode just requires a memcpy.
|
|
//
|
|
pPrinterAnnounce->PrinterNameLen = (STRLEN(_printerName) + 1) *
|
|
sizeof(WCHAR);
|
|
memcpy(pbStringData, _printerName, pPrinterAnnounce->PrinterNameLen );
|
|
#else
|
|
//
|
|
// On Win32 ANSI, we will convert to Unicode.
|
|
//
|
|
pPrinterAnnounce->PrinterNameLen = (STRLEN(_printerName) + 1) *
|
|
sizeof(WCHAR);
|
|
RDPConvertToUnicode(_printerName, (LPWSTR)pbStringData,
|
|
pPrinterAnnounce->PrinterNameLen );
|
|
#endif
|
|
pbStringData += pPrinterAnnounce->PrinterNameLen;
|
|
}
|
|
else {
|
|
pPrinterAnnounce->PrinterNameLen = 0;
|
|
}
|
|
|
|
//
|
|
// Copy the cached data.
|
|
//
|
|
if (_cachedData != NULL) {
|
|
|
|
pPrinterAnnounce->CachedFieldsLen = _cachedDataSize;
|
|
|
|
memcpy(pbStringData, _cachedData, (size_t)_cachedDataSize);
|
|
|
|
pbStringData += _cachedDataSize;
|
|
}
|
|
|
|
//
|
|
// Computer the length of the data area that follows the device announce
|
|
// header.
|
|
//
|
|
pDeviceAnnounce->DeviceDataLength =
|
|
(ULONG)(pbStringData - (PBYTE)pPrinterAnnounce);
|
|
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
|
|
#ifdef OS_WINCE
|
|
ULONG
|
|
W32DrPRN::GetCachedDataSize(
|
|
HKEY hPrinterKey
|
|
)
|
|
{
|
|
DC_BEGIN_FN("W32DrPRN::GetCachedDataSize");
|
|
|
|
TRC_ASSERT((hPrinterKey != NULL), (TB,_T("hPrinterKey is NULL")));
|
|
|
|
DWORD dwRet = ERROR_SUCCESS;
|
|
DWORD dwTotSize = 0;
|
|
WCHAR szValueName[MAX_PATH];
|
|
for (DWORD dwIndex = 0; dwRet == ERROR_SUCCESS; dwIndex++)
|
|
{
|
|
DWORD dwType;
|
|
DWORD dwSize = 0;
|
|
wsprintf(szValueName, L"%s%d", REG_RDPDR_PRINTER_CACHE_DATA, dwIndex);
|
|
dwRet = RegQueryValueEx(hPrinterKey, szValueName, NULL, &dwType, NULL, &dwSize);
|
|
if ((dwRet == ERROR_SUCCESS) && (dwType == REG_BINARY) )
|
|
{
|
|
dwTotSize += dwSize;
|
|
}
|
|
}
|
|
|
|
DC_END_FN();
|
|
|
|
return dwTotSize;
|
|
}
|
|
|
|
ULONG
|
|
W32DrPRN::ReadCachedData(
|
|
HKEY hPrinterKey,
|
|
UCHAR *pBuf,
|
|
ULONG *pulSize
|
|
)
|
|
{
|
|
DC_BEGIN_FN("W32DrPRN::ReadCachedData");
|
|
|
|
TRC_ASSERT((hPrinterKey != NULL), (TB,_T("hPrinterKey is NULL")));
|
|
TRC_ASSERT(((pBuf != NULL) && (pulSize != NULL)), (TB,_T("Invalid parameters pBuf = 0x%08x, pulSize=0x%08x"), pBuf, pulSize));
|
|
|
|
DWORD dwRet = ERROR_SUCCESS;
|
|
DWORD dwRemaining = *pulSize;
|
|
WCHAR szValueName[MAX_PATH];
|
|
|
|
for (DWORD dwIndex = 0; dwRet == ERROR_SUCCESS; dwIndex++)
|
|
{
|
|
DWORD dwType;
|
|
DWORD dwSize = dwRemaining;
|
|
|
|
wsprintf(szValueName, L"%s%d", REG_RDPDR_PRINTER_CACHE_DATA, dwIndex);
|
|
dwRet = RegQueryValueEx(hPrinterKey, szValueName, NULL, &dwType, pBuf, &dwSize);
|
|
if ((dwRet == ERROR_SUCCESS) && (dwType == REG_BINARY) )
|
|
{
|
|
dwRemaining -= dwSize;
|
|
pBuf += dwSize;
|
|
}
|
|
}
|
|
*pulSize -= dwRemaining;
|
|
return (*pulSize > 0) ? ERROR_SUCCESS : dwRet;
|
|
}
|
|
|
|
ULONG
|
|
W32DrPRN::WriteCachedData(
|
|
HKEY hPrinterKey,
|
|
UCHAR *pBuf,
|
|
ULONG ulSize
|
|
)
|
|
{
|
|
DC_BEGIN_FN("W32DrPRN::WriteCachedData");
|
|
|
|
TRC_ASSERT((hPrinterKey != NULL), (TB,_T("hPrinterKey is NULL")));
|
|
TRC_ASSERT((pBuf != NULL), (TB,_T("pBuf is NULL!")));
|
|
|
|
DWORD dwRet = ERROR_SUCCESS;
|
|
DWORD dwRemaining = ulSize;
|
|
WCHAR szValueName[MAX_PATH];
|
|
|
|
for (DWORD dwIndex = 0; dwRemaining > 0; dwIndex++)
|
|
{
|
|
DWORD dwSize = (dwRemaining >= 4096) ? 4096 : dwRemaining;
|
|
|
|
wsprintf(szValueName, L"%s%d", REG_RDPDR_PRINTER_CACHE_DATA, dwIndex);
|
|
dwRet = RegSetValueEx(hPrinterKey, szValueName, NULL, REG_BINARY, pBuf, dwSize);
|
|
if (dwRet == ERROR_SUCCESS)
|
|
{
|
|
dwRemaining -= dwSize;
|
|
pBuf += dwSize;
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB, _T("Error - RegQueryValueEx on %s failed"), szValueName));
|
|
for (DWORD dw=0; dw<dwIndex; dw++)
|
|
{
|
|
wsprintf(szValueName, L"%s%d", REG_RDPDR_PRINTER_CACHE_DATA, dw);
|
|
RegDeleteValue(hPrinterKey, szValueName);
|
|
}
|
|
return dwRet;
|
|
}
|
|
|
|
}
|
|
DC_END_FN();
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|