|
|
/*++
Copyright (c) 1998-2000 Microsoft Corporation
Module Name:
w32drman
Abstract:
This module defines a special subclass of the Win32 client-side RDP printer redirection "device" class. The subclass, W32DrManualPrn manages a queue that is manually installed by a user by attaching a server-side queue to a client-side redirected printing port.
Author:
Tad Brockway 3/23/99
Revision History:
--*/
#include <precom.h>
#define TRC_FILE "W32DrMan"
#include "w32drman.h"
#include "w32proc.h"
#include "w32utl.h"
#include "w32drprt.h"
#include "drdbg.h"
#ifdef OS_WINCE
#include "ceconfig.h"
#endif
///////////////////////////////////////////////////////////////
//
// W32DrManualPrn Methods
//
//
//
// W32DrManualPrn
//
W32DrManualPrn::W32DrManualPrn( ProcObj *processObject, const DRSTRING printerName, const DRSTRING driverName, const DRSTRING portName, BOOL defaultPrinter, ULONG deviceID) : W32DrPRN(processObject, printerName, driverName, portName, NULL, defaultPrinter, deviceID, portName)
{ }
//
// ~W32DrManualPrn
//
W32DrManualPrn::~W32DrManualPrn() { }
/*++
Routine Description:
For serial printers, we need to initialize the COM port. Arguments:
fileHandle - Open file object for the COM port.
Return Value:
ERROR_SUCCESS on success. Otherwise, an error code is returned.
--*/ DWORD W32DrManualPrn::InitializeDevice( DrFile* fileObj ) { HANDLE FileHandle; LPTSTR portName;
DC_BEGIN_FN("W32DrManualPrn::InitializeDevice");
if (_isSerialPort) { //
// Our devicePath is formulated as
// sprintf(_devicePath, TEXT("\\\\.\\%s"), portName);
//
portName = _tcsrchr( _devicePath, _T('\\') );
if( portName == NULL ) { // invalid device path
goto CLEANUPANDEXIT; }
portName++;
if( !*portName ) { //
// Invalid port name
//
goto CLEANUPANDEXIT; }
//
// Get the file handle.
//
FileHandle = fileObj->GetFileHandle(); if (!FileHandle || FileHandle == INVALID_HANDLE_VALUE) { ASSERT(FALSE); TRC_ERR((TB, _T("File Object was not created successfully"))); goto CLEANUPANDEXIT; }
W32DrPRT::InitializeSerialPort(portName, FileHandle); }
CLEANUPANDEXIT: DC_END_FN();
//
// This function always returns success. If the port cannot
// be initialized, then subsequent port commands will fail
// anyway.
//
return ERROR_SUCCESS; }
DWORD W32DrManualPrn::Enumerate( IN ProcObj *procObj, IN DrDeviceMgr *deviceMgr ) /*++
Routine Description:
Enumerate devices of this type by adding appropriate device instances to the device manager.
Arguments:
procObj - Corresponding process object. deviceMgr - Device manager to add devices to.
Return Value:
ERROR_SUCCESS on success. Otherwise, an error code is returned.
--*/ { HKEY hKey = NULL; W32DrPRN *prnDevice; ULONG ulIndex; TCHAR achRegSubKey[REGISTRY_KEY_NAME_SIZE]; ULONG ulRegSubKeySize; DWORD result; HKEY hTsClientKey = NULL; DWORD ulType;
DC_BEGIN_FN("W32DrManualPrn::Enumerate");
if(!procObj->GetVCMgr().GetInitData()->fEnableRedirectPrinters) { TRC_DBG((TB,_T("Printer redirection disabled, bailing out"))); return ERROR_SUCCESS; }
//
// Open cached printers key.
//
#ifdef OS_WINCE
//Before opening, make sure the printer list is current.
//This is to ensure that local printers deleted from within a TS session, show up
//when you log on the next time
CEUpdateCachedPrinters(); #endif
result = RegCreateKeyEx(HKEY_CURRENT_USER, REG_RDPDR_CACHED_PRINTERS, 0L, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL); if (result != ERROR_SUCCESS) { TRC_ERR((TB, _T("RegCreateKeyEx failed, %ld."), result)); hKey = NULL; } //
// Check for maximum config length specified in the registry
// by an admin, if any
//
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_TERMINALSERVERCLIENT, 0L, KEY_READ, &hTsClientKey) == ERROR_SUCCESS) {
DWORD maxRegCacheData, sz; if (RegQueryValueEx(hTsClientKey, REG_RDPDR_PRINTER_MAXCACHELEN, NULL, &ulType, (LPBYTE)&maxRegCacheData, &sz) == ERROR_SUCCESS) {
W32DrPRN::_maxCacheDataSize = maxRegCacheData; }
RegCloseKey(hTsClientKey); } //
// Enumerate cached printers.
//
for (ulIndex = 0; result == ERROR_SUCCESS; ulIndex++) {
//
// Try enumerating the ulIndex'th sub key.
//
ulRegSubKeySize = sizeof(achRegSubKey) / sizeof(TCHAR); result = RegEnumKeyEx( hKey, ulIndex, (LPTSTR)achRegSubKey, &ulRegSubKeySize, //size in TCHARS
NULL,NULL,NULL,NULL ); if (result == ERROR_SUCCESS) {
//
// Resolve the registry key into a printer object.
//
//
// Don't like the fact that we are scanning for automatic
// printer settings here. I don't know how much value there is
// in cleaning this up, however.
//
prnDevice = ResolveCachedPrinter(procObj, deviceMgr, hKey, achRegSubKey);
//
// If we didn't get a printer device object then remove the registry key.
//
if (prnDevice == NULL) { TRC_ERR((TB, _T("Didn't get a printer for %s."), achRegSubKey) ); RegDeleteKey(hKey, achRegSubKey); } } else { TRC_NRM((TB, _T("RegEnumKeyEx %ld."), result)); } }
//
// Close the parent registry key.
//
if (hKey != NULL) { RegCloseKey(hKey); }
DC_END_FN();
return result; }
VOID W32DrManualPrn::CachedDataRestored() /*++
Routine Description:
Called once the cached printer data has reached a "steady state."
Arguments:
NA
Return Value:
NA
--*/ { WCHAR *portName;
DC_BEGIN_FN("W32DrManualPrn::CachedDataRestored");
//
// Parse the cached printer information for specific information
// about this printer that is generic to all printers.
//
if (!ParsePrinterCacheInfo()) { if (_cachedData != NULL) { delete _cachedData; _cachedData = NULL; _cachedDataSize = 0; }
//
// If we fail here, then we are no longer valid.
//
W32DrDeviceAsync::SetValid(FALSE); } else {
//
// Our devicePath is formulated as
// sprintf(_devicePath, TEXT("\\\\.\\%s"), portName);
//
#ifndef OS_WINCE
portName = _tcsrchr(_devicePath, _T('\\')); if( portName == NULL ) { ASSERT(FALSE); _isSerialPort = FALSE; goto CLEANUPANDEXIT; } portName++; if( !*portName ) { ASSERT(FALSE); _isSerialPort = FALSE; goto CLEANUPANDEXIT; } #else
portName = _devicePath; #endif
//
// Find out of the port is a serial port.
//
_isSerialPort = !_wcsnicmp(portName, L"COM", 3); }
CLEANUPANDEXIT:
DC_END_FN(); }
BOOL W32DrManualPrn::ParsePrinterCacheInfo() /*++
Routine Description:
Parse the cached printer information for specific information about this printer. Arguments:
NA
Return Value:
TRUE - if valid cache data. FALSE - if not.
--*/ { PRDPDR_PRINTER_ADD_CACHEDATA pAddCacheData; ULONG ulSize; PBYTE pStringData; BOOL valid; ULONG len; LPSTR ansiPortName; LPTSTR portName;
DC_BEGIN_FN("W32DrManualPrn::ParsePrinterCacheInfo");
ASSERT(IsValid());
//
// Check to see the cache size is at least the structure size.
//
valid =_cachedDataSize >= sizeof(RDPDR_PRINTER_ADD_CACHEDATA);
//
// Make sure the internal sizes match the size of the catched data.
//
if (valid) { pAddCacheData = (PRDPDR_PRINTER_ADD_CACHEDATA)_cachedData; ulSize = sizeof(RDPDR_PRINTER_ADD_CACHEDATA) + pAddCacheData->PnPNameLen + pAddCacheData->DriverLen + pAddCacheData->PrinterNameLen + pAddCacheData->CachedFieldsLen; valid = _cachedDataSize >= ulSize; }
//
// Grab the port name out of the cached data. We don't yet know our
// device path because it's embedded in the cached data.
//
if (valid) { pAddCacheData = (PRDPDR_PRINTER_ADD_CACHEDATA)_cachedData; ansiPortName = (LPSTR)pAddCacheData->PortDosName; len = strlen(ansiPortName); }
if (valid) { #if UNICODE
WCHAR unicodePortName[PREFERRED_DOS_NAME_SIZE]; RDPConvertToUnicode( ansiPortName, (LPWSTR)unicodePortName, sizeof(unicodePortName)/sizeof(WCHAR) );
portName = (LPWSTR)unicodePortName;
#else
portName = ansiPortName; #endif
//
// Our device path is the port name.
//
#ifndef OS_WINCE
StringCchPrintf(_devicePath, SIZE_TCHARS(_devicePath), TEXT("\\\\.\\%s"), portName); #else
_stprintf(_devicePath, TEXT("\\\\.\\%s"), portName); #endif
}
//
// Get the PnP name.
//
if (valid) { pStringData = (PBYTE)(pAddCacheData + 1); valid = (!pAddCacheData->PnPNameLen) || (pAddCacheData->PnPNameLen == ((wcslen((LPWSTR)pStringData) + 1) * sizeof(WCHAR))); }
//
// If we got a valid PnP name, get the driver name.
//
if (valid && (pAddCacheData->PnPNameLen > 0)) { //
// Need to convert the name to ANSI if we are non-unicode.
//
#ifdef UNICODE
SetPnPName((DRSTRING)pStringData); #else
SetPnPName(NULL); _pnpName = new char[pAddCacheData->PnPNameLen/sizeof(WCHAR)]; if (_pnpName != NULL) { valid = (RDPConvertToAnsi( (WCHAR *)pStringData, _pnpName, pAddCacheData->PnPNameLen/sizeof(WCHAR) ) == ERROR_SUCCESS); } else { TRC_ERR((TB, _T("Alloc failed."))); valid = FALSE; } #endif
pStringData += pAddCacheData->PnPNameLen; valid = (!pAddCacheData->DriverLen) || (pAddCacheData->DriverLen == ((wcslen((LPWSTR)pStringData) + 1) * sizeof(WCHAR))); }
//
// If we got a valid driver name
//
if (valid && (pAddCacheData->DriverLen > 0)) { #ifdef UNICODE
SetDriverName((DRSTRING)pStringData); #else
SetDriverName(NULL); _driverName = new char[pAddCacheData->DriverLen/sizeof(WCHAR)]; if (_driverName != NULL) { valid = (RDPConvertToAnsi( (WCHAR *)pStringData, _driverName, pAddCacheData->DriverLen/sizeof(WCHAR) ) == ERROR_SUCCESS); } else { TRC_ERR((TB, _T("Alloc failed."))); valid = FALSE; } #endif
pStringData += pAddCacheData->DriverLen; }
//
// Our cache contains printer after driver name
//
if (valid) { pStringData += pAddCacheData->PrinterNameLen; }
//
// Need to adjust the cached pointer to point to the actual cached
// configuration data.
//
if (valid) { PVOID oldCachedData; oldCachedData = _cachedData;
#ifdef OS_WINCE
if (pAddCacheData->CachedFieldsLen > 0) { #endif
_cachedData = new BYTE[pAddCacheData->CachedFieldsLen]; if (_cachedData != NULL) { memcpy((PBYTE)_cachedData, pStringData, pAddCacheData->CachedFieldsLen); _cachedDataSize = pAddCacheData->CachedFieldsLen; } else { TRC_NRM((TB, _T("Can't allocate %ld bytes."), pAddCacheData->CachedFieldsLen)); _cachedDataSize = 0; valid = FALSE; } #ifdef OS_WINCE
} else { _cachedData = NULL; _cachedDataSize = 0; } if (oldCachedData) #endif
delete oldCachedData; }
DC_END_FN();
return valid; }
|