|
|
/*++
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
|