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.
1720 lines
45 KiB
1720 lines
45 KiB
/*++
|
|
|
|
Copyright (c) 1998-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
w32draut
|
|
|
|
Abstract:
|
|
|
|
This module defines a special subclass of the Win32 client-side RDP
|
|
printer redirection "device" class. The subclass, W32DrAutoPrn manages
|
|
a queue that is automatically discovered by the client via enumerating
|
|
client-side printer queues.
|
|
|
|
Author:
|
|
|
|
Tad Brockway 3/23/99
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <precom.h>
|
|
|
|
#define TRC_FILE "W32DrAut"
|
|
|
|
#include "regapi.h"
|
|
#include "w32draut.h"
|
|
#include "proc.h"
|
|
#include "drdbg.h"
|
|
#include "w32utl.h"
|
|
#include "utl.h"
|
|
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
//
|
|
// Defines
|
|
//
|
|
|
|
#define COM_PORT_NAME _T("COM")
|
|
#define COM_PORT_NAMELEN 3
|
|
#define LPT_PORT_NAME _T("LPT")
|
|
#define LPT_PORT_NAMELEN 3
|
|
#define USB_PORT_NAME _T("USB")
|
|
#define USB_PORT_NAMELEN 3
|
|
#define RDP_PORT_NAME _T("TS")
|
|
#define RDP_PORT_NAMELEN 2
|
|
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
//
|
|
// W32DrAutoPrn Members
|
|
//
|
|
|
|
W32DrAutoPrn::W32DrAutoPrn(
|
|
IN ProcObj *processObject,
|
|
IN const DRSTRING printerName,
|
|
IN const DRSTRING driverName,
|
|
IN const DRSTRING portName,
|
|
IN BOOL isDefault,
|
|
IN ULONG deviceID,
|
|
IN const TCHAR *devicePath
|
|
) : W32DrPRN(processObject, printerName, driverName,
|
|
portName, NULL, isDefault, deviceID, devicePath)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Constructor
|
|
|
|
Arguments:
|
|
|
|
processObject - Associated Process Object.
|
|
printerName - Name of automatic printer queue.
|
|
driverName - Print Driver Name
|
|
portName - Client Port Name
|
|
isDefault - Is this the default printer?
|
|
deviceID - Unique Device Identifier
|
|
devicePath - Path to pass to OpenPrinter when opening the
|
|
device.
|
|
|
|
Return Value:
|
|
|
|
NA
|
|
|
|
--*/
|
|
{
|
|
DC_BEGIN_FN("W32DrAutoPrn");
|
|
_jobID = 0;
|
|
_printerHandle = INVALID_HANDLE_VALUE;
|
|
memset(_szLocalPrintingDocName, 0, sizeof(_szLocalPrintingDocName));
|
|
|
|
ASSERT(processObject);
|
|
PRDPDR_DATA prdpdrData = processObject->GetVCMgr().GetInitData();
|
|
ASSERT(prdpdrData);
|
|
|
|
LPTSTR szDocName = prdpdrData->szLocalPrintingDocName;
|
|
ASSERT(szDocName);
|
|
ASSERT(szDocName[0] != 0);
|
|
_tcsncpy(_szLocalPrintingDocName, szDocName,
|
|
sizeof(_szLocalPrintingDocName)/sizeof(TCHAR));
|
|
|
|
OSVERSIONINFO osVersion;
|
|
osVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
_bRunningOn9x = TRUE;
|
|
if (GetVersionEx(&osVersion)) {
|
|
if (osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT) {
|
|
_bRunningOn9x = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TRC_ERR((TB, _T("GetVersionEx: %08X"), GetLastError()));
|
|
}
|
|
DC_END_FN();
|
|
}
|
|
|
|
W32DrAutoPrn::~W32DrAutoPrn()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destructor
|
|
|
|
Arguments:
|
|
|
|
NA
|
|
|
|
Return Value:
|
|
|
|
NA
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Make sure all docs are finished and the printer handle closed.
|
|
//
|
|
ClosePrinter();
|
|
}
|
|
|
|
BOOL
|
|
W32DrAutoPrn::ShouldAddThisPrinter(
|
|
DWORD queueFilter,
|
|
DWORD userSessionID,
|
|
PPRINTERINFO pPrinterInfo,
|
|
DWORD printerSessionID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Detemine if we should redirect this printer.
|
|
|
|
Arguments:
|
|
|
|
queueFilter - redirect printer filter type.
|
|
userSessionID - current user session ID.
|
|
pPrinterInfo - printer info
|
|
printerSessionID - Printer session ID or INVALID_SESSIONID if printers
|
|
is not a TS printer.
|
|
|
|
Return Value:
|
|
|
|
TRUE to add printer, FALSE otherwise
|
|
|
|
--*/
|
|
{
|
|
BOOL fAddThisPrinter = FALSE;
|
|
DWORD sessionID;
|
|
|
|
DC_BEGIN_FN("W32DrAutoPrn::AddThisPrinter");
|
|
|
|
//
|
|
// Check filters.
|
|
//
|
|
if (queueFilter == FILTER_ALL_QUEUES ) {
|
|
fAddThisPrinter = TRUE;
|
|
}
|
|
else if ((queueFilter & FILTER_NET_QUEUES) &&
|
|
(pPrinterInfo->Attributes & PRINTER_ATTRIBUTE_NETWORK)) {
|
|
fAddThisPrinter = TRUE;
|
|
}
|
|
|
|
//
|
|
// If it's a non-network printer then get the port name.
|
|
//
|
|
|
|
else if((queueFilter & FILTER_LPT_QUEUES) &&
|
|
(_tcsnicmp(
|
|
pPrinterInfo->pPortName,
|
|
LPT_PORT_NAME,
|
|
LPT_PORT_NAMELEN) == 0) ) {
|
|
fAddThisPrinter = TRUE;
|
|
}
|
|
else if ((queueFilter & FILTER_COM_QUEUES) &&
|
|
(_tcsnicmp(
|
|
pPrinterInfo->pPortName,
|
|
COM_PORT_NAME,
|
|
COM_PORT_NAMELEN) == 0) ) {
|
|
fAddThisPrinter = TRUE;
|
|
}
|
|
else if ((queueFilter & FILTER_USB_QUEUES) &&
|
|
(_tcsnicmp(
|
|
pPrinterInfo->pPortName,
|
|
USB_PORT_NAME,
|
|
USB_PORT_NAMELEN) == 0) ) {
|
|
fAddThisPrinter = TRUE;
|
|
}
|
|
else if ((queueFilter & FILTER_RDP_QUEUES) &&
|
|
(_tcsnicmp(
|
|
pPrinterInfo->pPortName,
|
|
RDP_PORT_NAME,
|
|
RDP_PORT_NAMELEN) == 0) ) {
|
|
fAddThisPrinter = TRUE;
|
|
}
|
|
|
|
if ((TRUE == fAddThisPrinter) &&
|
|
(userSessionID != INVALID_SESSIONID) &&
|
|
(printerSessionID != INVALID_SESSIONID)) {
|
|
|
|
//
|
|
// Compare this with our session ID
|
|
//
|
|
if( printerSessionID != userSessionID ) {
|
|
|
|
// this printer is from different session,
|
|
// don't redirect it.
|
|
fAddThisPrinter = FALSE;
|
|
}
|
|
}
|
|
|
|
DC_END_FN();
|
|
return fAddThisPrinter;
|
|
}
|
|
|
|
LPTSTR
|
|
W32DrAutoPrn::GetRDPDefaultPrinter()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the printer name of the default printer.
|
|
|
|
This function allocates memory and returns a pointer
|
|
to the allocated string, if successful. Otherwise, it returns NULL.
|
|
|
|
Arguments:
|
|
|
|
NA
|
|
|
|
Return Value:
|
|
|
|
The default printer name. The caller has to free the memory.
|
|
|
|
--*/
|
|
{
|
|
TCHAR* szIniEntry = NULL;
|
|
LPTSTR pPrinterName = NULL;
|
|
|
|
DC_BEGIN_FN("DrPRN::GetRDPDefaultPrinter");
|
|
|
|
szIniEntry = new TCHAR[ MAX_DEF_PRINTER_ENTRY ];
|
|
|
|
if( NULL == szIniEntry )
|
|
{
|
|
TRC_ERR((TB, _T("Memory allocation failed:%ld."),
|
|
GetLastError()));
|
|
goto Cleanup;
|
|
}
|
|
|
|
szIniEntry[0] = _T('\0');
|
|
|
|
//
|
|
// Get the default printer key from the win.ini file.
|
|
//
|
|
DWORD dwResult = GetProfileString(_T("windows"),
|
|
_T("device"),
|
|
_T(""),
|
|
szIniEntry,
|
|
MAX_DEF_PRINTER_ENTRY);
|
|
if (dwResult && szIniEntry[0]) {
|
|
//
|
|
// Get the printer name. The device value is of the form
|
|
// <printer name>,<driver name>,<port>
|
|
//
|
|
TCHAR *pComma = _tcschr( szIniEntry, _T(','));
|
|
if( pComma ) {
|
|
|
|
*pComma = _T('\0');
|
|
UINT cchLen = _tcslen( szIniEntry ) + 1;
|
|
|
|
pPrinterName = new TCHAR [cchLen];
|
|
if (pPrinterName) {
|
|
StringCchCopy(pPrinterName, cchLen, szIniEntry);
|
|
TRC_NRM((TB, _T("Def. is: %s"), pPrinterName));
|
|
}
|
|
else {
|
|
TRC_ERR((TB, _T("Memory allocation failed:%ld."),
|
|
GetLastError()));
|
|
}
|
|
}
|
|
else {
|
|
TRC_ERR((TB, _T("Invalid device entry in win.ini.")));
|
|
}
|
|
}
|
|
else {
|
|
TRC_NRM((TB, _T("Device entry not found in win.ini.")));
|
|
}
|
|
Cleanup:
|
|
DC_END_FN();
|
|
delete[] szIniEntry;
|
|
return pPrinterName;
|
|
}
|
|
|
|
DWORD
|
|
W32DrAutoPrn::GetPrinterInfoAndSessionID(
|
|
IN ProcObj *procObj,
|
|
IN LPTSTR printerName,
|
|
IN DWORD printerAttribs,
|
|
IN OUT BYTE **pPrinterInfoBuf,
|
|
IN OUT DWORD *pPrinterInfoBufSize,
|
|
OUT DWORD *sessionID,
|
|
OUT PPRINTERINFO printerInfo
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get printer info for a printer and its corresponding TS session ID,
|
|
if it exists.
|
|
|
|
Arguments:
|
|
|
|
procObj - Active Proc Obj
|
|
printerName - Name of printer.
|
|
printerAttribs - Printer Attribs
|
|
pPrinterInfoBuf - This function may resize this buffer.
|
|
pPrinterInfoBufsSize - Current size of the pPrinterInfo2 buf.
|
|
sessionID - TS session ID, if applicable. Otherwise INVALID_SESSIONID.
|
|
printerInfo - Printer information is returned here. We avoid
|
|
pulling in level 2 info if possible. Fields in this data
|
|
structure should not be free'd.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS on success. Otherwise, an error status is returned.
|
|
|
|
--*/
|
|
{
|
|
HANDLE hPrinter = NULL;
|
|
DWORD status = ERROR_SUCCESS;
|
|
DWORD bytesRequired;
|
|
DWORD type;
|
|
DWORD cbNeeded;
|
|
DWORD ret;
|
|
|
|
DC_BEGIN_FN("W32DrAutoPrn::GetPrinterInfoAndSessionID");
|
|
|
|
//
|
|
// No unicode wrappers for GetPrinter on 9x.
|
|
//
|
|
ASSERT(!procObj->Is9x());
|
|
|
|
//
|
|
// Get a printer handle
|
|
//
|
|
if (!OpenPrinter(printerName, &hPrinter, NULL)) {
|
|
status = GetLastError();
|
|
TRC_ALT((TB, L"OpenPrinter: %ld", status));
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
//
|
|
// Check the proc obj shutdown state since we just left an RPC call.
|
|
//
|
|
if (procObj->IsShuttingDown()) {
|
|
status = ERROR_SHUTDOWN_IN_PROGRESS;
|
|
TRC_ALT((TB, _T("Bailing out of printer enumeration because of shutdown.")));
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
//
|
|
// If the printer is a network printer then we try to avoid hitting the
|
|
// network for additional info. For a non-network printer, we need info level 2
|
|
// for info about the port.
|
|
//
|
|
if (printerAttribs & PRINTER_ATTRIBUTE_NETWORK) {
|
|
|
|
//
|
|
// Just need the driver name.
|
|
//
|
|
if (!GetPrinterDriver(hPrinter, NULL, 1, *pPrinterInfoBuf,
|
|
*pPrinterInfoBufSize, &bytesRequired)) {
|
|
|
|
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
|
|
|
*pPrinterInfoBuf = (PBYTE)new BYTE[bytesRequired];
|
|
if (*pPrinterInfoBuf == NULL) {
|
|
TRC_ERR((TB, L"Failed to allocate printer driver info"));
|
|
*pPrinterInfoBufSize = 0;
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
else {
|
|
*pPrinterInfoBufSize = bytesRequired;
|
|
}
|
|
}
|
|
|
|
if (!GetPrinterDriver(hPrinter, NULL, 1, *pPrinterInfoBuf,
|
|
*pPrinterInfoBufSize, &bytesRequired)) {
|
|
status = GetLastError();
|
|
TRC_ERR((TB, _T("GetPrinter: %08X"), status));
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
}
|
|
PDRIVER_INFO_1 p1 = (PDRIVER_INFO_1)*pPrinterInfoBuf;
|
|
printerInfo->pPrinterName = printerName;
|
|
printerInfo->pPortName = NULL;
|
|
printerInfo->pDriverName = p1->pName;
|
|
printerInfo->Attributes = printerAttribs;
|
|
}
|
|
else {
|
|
|
|
if (!GetPrinter(hPrinter, 2, *pPrinterInfoBuf,
|
|
*pPrinterInfoBufSize, &bytesRequired)) {
|
|
|
|
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
|
|
|
*pPrinterInfoBuf = (PBYTE)new BYTE[bytesRequired];
|
|
if (*pPrinterInfoBuf == NULL) {
|
|
TRC_ERR((TB, L"Failed to allocate printer info 2"));
|
|
*pPrinterInfoBufSize = 0;
|
|
status = ERROR_INSUFFICIENT_BUFFER;
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
else {
|
|
*pPrinterInfoBufSize = bytesRequired;
|
|
}
|
|
|
|
if (!GetPrinter(hPrinter, 2, *pPrinterInfoBuf,
|
|
*pPrinterInfoBufSize, &bytesRequired)) {
|
|
status = GetLastError();
|
|
TRC_ERR((TB, _T("GetPrinter: %08X"), status));
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
}
|
|
else {
|
|
status = GetLastError();
|
|
TRC_ERR((TB, _T("GetPrinter: %08X"), status));
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
}
|
|
PPRINTER_INFO_2 p2 = (PPRINTER_INFO_2)*pPrinterInfoBuf;
|
|
printerInfo->pPrinterName = p2->pPrinterName;
|
|
printerInfo->pPortName = p2->pPortName;
|
|
printerInfo->pDriverName = p2->pDriverName;
|
|
printerInfo->Attributes = p2->Attributes;
|
|
}
|
|
|
|
//
|
|
// Check the proc obj shutdown state since we just left an RPC call.
|
|
//
|
|
if (procObj->IsShuttingDown()) {
|
|
status = ERROR_SHUTDOWN_IN_PROGRESS;
|
|
TRC_ALT((TB, _T("Bailing out of printer enumeration because of shutdown.")));
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
//
|
|
// Get the session ID, if it exists.
|
|
//
|
|
ret = GetPrinterData(
|
|
hPrinter,
|
|
DEVICERDR_SESSIONID,
|
|
&type,
|
|
(PBYTE)sessionID,
|
|
sizeof(DWORD),
|
|
&cbNeeded
|
|
);
|
|
if (ret != ERROR_SUCCESS || type != REG_DWORD) {
|
|
*sessionID = INVALID_SESSIONID;
|
|
}
|
|
|
|
CLEANUPANDEXIT:
|
|
|
|
if (hPrinter != NULL) {
|
|
::ClosePrinter(hPrinter);
|
|
}
|
|
|
|
DC_END_FN();
|
|
return status;
|
|
}
|
|
|
|
|
|
DWORD
|
|
W32DrAutoPrn::Enumerate(
|
|
IN ProcObj *procObj,
|
|
IN DrDeviceMgr *deviceMgr
|
|
)
|
|
{
|
|
ULONG ulBufSizeNeeded;
|
|
ULONG ulNumStructs;
|
|
ULONG i;
|
|
LPTSTR szDefaultPrinter = NULL;
|
|
PRINTER_INFO_4 *pPrinterInfo4Buf = NULL;
|
|
DWORD pPrinterInfo4BufSize = 0;
|
|
PBYTE pPrinterInfoBuf = NULL;
|
|
DWORD pPrinterInfoBufSize = 0;
|
|
W32DrPRN *prnDevice = NULL;
|
|
DWORD result = ERROR_SUCCESS;
|
|
DWORD queueFilter;
|
|
LPTSTR friendlyName = NULL;
|
|
LPTSTR pName;
|
|
DWORD userSessionID;
|
|
DWORD printerSessionID;
|
|
BOOL ret;
|
|
PRINTERINFO currentPrinter;
|
|
HRESULT hr;
|
|
|
|
DC_BEGIN_FN("W32DrAutoPrn::Enumerate");
|
|
|
|
if(!procObj->GetVCMgr().GetInitData()->fEnableRedirectPrinters)
|
|
{
|
|
TRC_DBG((TB,_T("Printer redirection disabled, bailing out")));
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
queueFilter = GetPrinterFilterMask(procObj);
|
|
|
|
//
|
|
// Get the size of the printer buffer required to enumerate.
|
|
//
|
|
if (!procObj->Is9x()) {
|
|
//
|
|
// Level 2 can hang on NT if a network print server is down.
|
|
//
|
|
ret = EnumPrinters(
|
|
PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
|
|
NULL, 4, NULL, 0,
|
|
&ulBufSizeNeeded, &ulNumStructs
|
|
);
|
|
}
|
|
else {
|
|
//
|
|
// Level 4 is not supported on 9x and level 2 doesn't hang anyway.
|
|
//
|
|
// !!!!Note!!!!
|
|
// For 9x the Unicode wrapper function, EnumPrintersWrapW takes over.
|
|
// Also, note that level 2 is partially supported.
|
|
//
|
|
ret = EnumPrinters(
|
|
PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
|
|
NULL, 2, NULL, 0,
|
|
&ulBufSizeNeeded, &ulNumStructs
|
|
);
|
|
}
|
|
if (!ret && (result = GetLastError()) != ERROR_INSUFFICIENT_BUFFER) {
|
|
|
|
TRC_ERR((TB, _T("EnumPrinter failed: %ld."),
|
|
result));
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// Check the proc obj shutdown state since we just left an RPC call.
|
|
//
|
|
if (procObj->IsShuttingDown()) {
|
|
TRC_ALT((TB, _T("Bailing out of printer enumeration because of shutdown.")));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Allocate the printer enumeration buffer.
|
|
//
|
|
if (!procObj->Is9x()) {
|
|
pPrinterInfo4Buf = (PRINTER_INFO_4 *)(new BYTE[ulBufSizeNeeded]);
|
|
if (pPrinterInfo4Buf == NULL) {
|
|
TRC_ERR((TB, _T("Alloc failed.")));
|
|
result = ERROR_INSUFFICIENT_BUFFER;
|
|
goto Cleanup;
|
|
}
|
|
else {
|
|
pPrinterInfo4BufSize = ulBufSizeNeeded;
|
|
}
|
|
}
|
|
else {
|
|
pPrinterInfoBuf = (PBYTE)(new BYTE[ulBufSizeNeeded]);
|
|
if (pPrinterInfoBuf == NULL) {
|
|
TRC_ERR((TB, _T("Alloc failed.")));
|
|
result = ERROR_INSUFFICIENT_BUFFER;
|
|
goto Cleanup;
|
|
}
|
|
else {
|
|
pPrinterInfoBufSize = ulBufSizeNeeded;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get the printers.
|
|
//
|
|
if (!procObj->Is9x()) {
|
|
ret = EnumPrinters(
|
|
PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
|
|
NULL,
|
|
4,
|
|
(PBYTE)pPrinterInfo4Buf,
|
|
pPrinterInfo4BufSize,
|
|
&ulBufSizeNeeded,
|
|
&ulNumStructs);
|
|
}
|
|
else {
|
|
//
|
|
// !!!!Note!!!!
|
|
// For 9x the Unicode wrapper function, EnumPrintersWrapW takes over.
|
|
// Also, note that level 2 is only partially supported.
|
|
//
|
|
ret = EnumPrinters(
|
|
PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS,
|
|
NULL,
|
|
2,
|
|
(PBYTE)pPrinterInfoBuf,
|
|
pPrinterInfoBufSize,
|
|
&ulBufSizeNeeded,
|
|
&ulNumStructs);
|
|
}
|
|
if (!ret) {
|
|
result = GetLastError();
|
|
TRC_ALT((TB, _T("EnumPrinter failed, %ld."),
|
|
result));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Check the proc obj shutdown state since we just left an RPC call.
|
|
//
|
|
if (procObj->IsShuttingDown()) {
|
|
TRC_ALT((TB, _T("Bailing out of printer enumeration because of shutdown.")));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Trace the results of EnumPrinters.
|
|
//
|
|
TRC_NRM((TB, _T("Number of Printers found, %ld."),
|
|
ulNumStructs));
|
|
|
|
//
|
|
// Get the name of the current default printer.
|
|
//
|
|
szDefaultPrinter = GetRDPDefaultPrinter();
|
|
|
|
//
|
|
// Get User Session ID
|
|
//
|
|
userSessionID = GetUserSessionID();
|
|
|
|
//
|
|
// Iterate through the results of EnumPrinters and add each printer to the
|
|
// device manager that passes the printer adding filter.
|
|
//
|
|
for (i = 0; i < ulNumStructs; i++) {
|
|
|
|
if (friendlyName != NULL) {
|
|
delete friendlyName;
|
|
friendlyName = NULL;
|
|
}
|
|
|
|
//
|
|
// Get info for the printer and its corresponding TS session ID,
|
|
// if it exists.
|
|
//
|
|
if (!procObj->Is9x()) {
|
|
|
|
if (GetPrinterInfoAndSessionID(
|
|
procObj,
|
|
pPrinterInfo4Buf[i].pPrinterName,
|
|
pPrinterInfo4Buf[i].Attributes,
|
|
&pPrinterInfoBuf,
|
|
&pPrinterInfoBufSize,
|
|
&printerSessionID,
|
|
¤tPrinter
|
|
) != ERROR_SUCCESS) {
|
|
continue;
|
|
}
|
|
}
|
|
else {
|
|
PPRINTER_INFO_2 p2;
|
|
p2 = (PPRINTER_INFO_2)pPrinterInfoBuf;
|
|
|
|
if (p2 != NULL) {
|
|
currentPrinter.pPrinterName = p2[i].pPrinterName;
|
|
currentPrinter.pPortName = p2[i].pPortName;
|
|
currentPrinter.pDriverName = p2[i].pDriverName;
|
|
currentPrinter.Attributes = p2[i].Attributes;
|
|
}
|
|
|
|
printerSessionID = INVALID_SESSIONID;
|
|
}
|
|
|
|
|
|
//
|
|
// Check the proc obj shutdown state since we just left an RPC call.
|
|
//
|
|
if (procObj->IsShuttingDown()) {
|
|
TRC_ALT((TB, _T("Bailing out of printer enumeration because of shutdown.")));
|
|
goto Cleanup;
|
|
}
|
|
|
|
if( FALSE == ShouldAddThisPrinter( queueFilter, userSessionID, ¤tPrinter,
|
|
printerSessionID) ) {
|
|
continue;
|
|
}
|
|
|
|
TCHAR UniquePortName[MAX_PATH];
|
|
ULONG DeviceId;
|
|
|
|
//
|
|
// Is this one the default queue.
|
|
//
|
|
BOOL fDefault = ((szDefaultPrinter) && (currentPrinter.pPrinterName) &&
|
|
(_tcsicmp(szDefaultPrinter, currentPrinter.pPrinterName) == 0));
|
|
|
|
//
|
|
// Generate a "friendly" name if this is a network
|
|
// queue.
|
|
//
|
|
BOOL fNetwork = FALSE, fTSqueue = FALSE;
|
|
RDPDR_VERSION serverVer;
|
|
|
|
serverVer = procObj->serverVersion();
|
|
|
|
// 4 is minor version of post win2000
|
|
if (COMPARE_VERSION(serverVer.Minor, serverVer.Major, 4, 1) < 0) {
|
|
// the server is Win2000 or lower
|
|
if (currentPrinter.Attributes & PRINTER_ATTRIBUTE_NETWORK) {
|
|
friendlyName = CreateFriendlyNameFromNetworkName(
|
|
currentPrinter.pPrinterName,
|
|
TRUE
|
|
);
|
|
// We don't set the fNetwork flag for Win2K because it can't
|
|
// do anything with it anyway.
|
|
}
|
|
} else {
|
|
// the server is higher than Win2000
|
|
|
|
// is it a network printer?
|
|
if (currentPrinter.Attributes & PRINTER_ATTRIBUTE_NETWORK) {
|
|
fNetwork = TRUE;
|
|
}
|
|
|
|
// is it a TS queue?
|
|
if ((currentPrinter.pPortName != NULL) &&
|
|
_tcsnicmp(currentPrinter.pPortName,
|
|
RDP_PORT_NAME,
|
|
RDP_PORT_NAMELEN) == 0) {
|
|
fTSqueue = TRUE;
|
|
friendlyName = CreateNestedName(currentPrinter.pPrinterName, &fNetwork);
|
|
// should we set fNetwork and fTSqueue only in case of success?
|
|
} else if (fNetwork) {
|
|
|
|
friendlyName = CreateFriendlyNameFromNetworkName(
|
|
currentPrinter.pPrinterName, FALSE
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create a new printer device object.
|
|
//
|
|
pName = (friendlyName != NULL) ? friendlyName : currentPrinter.pPrinterName;
|
|
|
|
DeviceId = deviceMgr->GetUniqueObjectID();
|
|
|
|
//
|
|
// 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. e.g.
|
|
// For network printer, they share same port name if it's
|
|
// same printer with different network printer names.
|
|
// We use the format of PRN# as our unique port name
|
|
|
|
hr = StringCchPrintf(UniquePortName,
|
|
SIZE_TCHARS(UniquePortName),
|
|
TEXT("PRN%ld"), DeviceId);
|
|
if (FAILED(hr)) {
|
|
TRC_ERR((TB,_T("Error copying portname :0x%x"),hr));
|
|
result = ERROR_INSUFFICIENT_BUFFER;
|
|
goto Cleanup;
|
|
}
|
|
UniquePortName[7] = TEXT('\0');
|
|
|
|
prnDevice = new W32DrAutoPrn(
|
|
procObj,
|
|
pName,
|
|
currentPrinter.pDriverName,
|
|
UniquePortName,
|
|
fDefault,
|
|
DeviceId,
|
|
currentPrinter.pPrinterName
|
|
);
|
|
|
|
//
|
|
// Add to the device manager if we got a valid object.
|
|
//
|
|
if (prnDevice != NULL) {
|
|
|
|
prnDevice->SetNetwork(fNetwork);
|
|
prnDevice->SetTSqueue(fTSqueue);
|
|
prnDevice->Initialize();
|
|
|
|
if (!(prnDevice->IsValid() &&
|
|
(deviceMgr->AddObject(prnDevice) == STATUS_SUCCESS))) {
|
|
delete prnDevice;
|
|
}
|
|
}
|
|
else {
|
|
TRC_ERR((TB, _T("Failed to allocate W32DrPRN.")));
|
|
result = ERROR_INSUFFICIENT_BUFFER;
|
|
goto Cleanup;
|
|
}
|
|
}
|
|
|
|
Cleanup:
|
|
|
|
//
|
|
// Release the "friendly" printer name.
|
|
//
|
|
if (friendlyName != NULL) {
|
|
delete friendlyName;
|
|
}
|
|
|
|
//
|
|
// Release the default printer buffer.
|
|
//
|
|
if (szDefaultPrinter) {
|
|
delete[] szDefaultPrinter;
|
|
}
|
|
|
|
//
|
|
// Release the level 4 printer enumeration buffer.
|
|
//
|
|
if (pPrinterInfo4Buf != NULL) {
|
|
delete pPrinterInfo4Buf;
|
|
}
|
|
|
|
//
|
|
// Release the printer enumeration buffer.
|
|
//
|
|
if (pPrinterInfoBuf != NULL) {
|
|
delete pPrinterInfoBuf;
|
|
}
|
|
|
|
DC_END_FN();
|
|
|
|
return result;
|
|
}
|
|
|
|
LPTSTR
|
|
W32DrAutoPrn::CreateNestedName(LPTSTR printerName, BOOL* pfNetwork)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create a printer name from the names stored in the registry.
|
|
|
|
Arguments:
|
|
|
|
printerName - Name returned by EnumPrinters
|
|
|
|
Return Value:
|
|
|
|
Nested name on success, that should be released by a call to
|
|
delete. NULL is returned on error.
|
|
|
|
--*/
|
|
{
|
|
DWORD printerNameLen;
|
|
LPTSTR name = NULL;
|
|
HANDLE hPrinter = NULL;
|
|
DWORD i, cbNeeded, dwError;
|
|
BOOL fFail = TRUE;
|
|
|
|
DC_BEGIN_FN("W32DrAutoPrn::CreateNestedName");
|
|
|
|
|
|
if (OpenPrinter(printerName, &hPrinter, NULL)) {
|
|
|
|
// In all cases the name will begin with "__"
|
|
printerNameLen = 2;
|
|
|
|
// try the Server name
|
|
// WARNING: it returns ERROR_SUCCESS under Win9X if nSize = 0
|
|
dwError = GetPrinterData(hPrinter, DEVICERDR_PRINT_SERVER_NAME, NULL, NULL, 0, &cbNeeded);
|
|
if( (dwError == ERROR_MORE_DATA) || (dwError == ERROR_SUCCESS)) {
|
|
printerNameLen += cbNeeded / sizeof(TCHAR);
|
|
*pfNetwork = TRUE;
|
|
} else {
|
|
*pfNetwork = FALSE;
|
|
}
|
|
|
|
// try the Client name
|
|
dwError = GetPrinterData(hPrinter, DEVICERDR_CLIENT_NAME, NULL, NULL, 0, &cbNeeded);
|
|
if( (dwError == ERROR_MORE_DATA) || (dwError == ERROR_SUCCESS)) {
|
|
printerNameLen += cbNeeded / sizeof(TCHAR);
|
|
|
|
if (*pfNetwork) {
|
|
// if there's already a print server name, add a '\'
|
|
printerNameLen += 1;
|
|
}
|
|
} else if(!*pfNetwork) {
|
|
// no print server, no client name, things are going bad...
|
|
DC_QUIT;
|
|
}
|
|
|
|
// try the Printer name
|
|
dwError = GetPrinterData(hPrinter, DEVICERDR_PRINTER_NAME, NULL, NULL, 0, &cbNeeded);
|
|
if( (dwError == ERROR_MORE_DATA) || (dwError == ERROR_SUCCESS)) {
|
|
// add also a '\'
|
|
printerNameLen += 1 + cbNeeded / sizeof(TCHAR);
|
|
} else {
|
|
// no printer name
|
|
DC_QUIT;
|
|
}
|
|
|
|
//
|
|
// Allocate space for the nested name.
|
|
//
|
|
name = new TCHAR[printerNameLen + 1];
|
|
if (name == NULL) {
|
|
|
|
TRC_ERR((TB, _T("Can't allocate %ld bytes for printer name."), printerNameLen));
|
|
|
|
} else {
|
|
|
|
name[0] = _T('!');
|
|
name[1] = _T('!');
|
|
i = 2;
|
|
|
|
// try the Server name
|
|
if (*pfNetwork) {
|
|
if (ERROR_SUCCESS == GetPrinterData(hPrinter,
|
|
DEVICERDR_PRINT_SERVER_NAME,
|
|
NULL,
|
|
(LPBYTE)(name + i),
|
|
(printerNameLen - i) * sizeof(TCHAR),
|
|
&cbNeeded)) {
|
|
i = _tcslen(name);
|
|
name[i++] = _T('!');
|
|
|
|
} else {
|
|
// weird...
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
|
|
// try the Client name
|
|
if (ERROR_SUCCESS == GetPrinterData(hPrinter,
|
|
DEVICERDR_CLIENT_NAME,
|
|
NULL,
|
|
(LPBYTE)(name + i),
|
|
(printerNameLen - i) * sizeof(TCHAR),
|
|
&cbNeeded)) {
|
|
i = _tcslen(name);
|
|
name[i++] = _T('!');
|
|
|
|
} else {
|
|
|
|
if(!*pfNetwork) {
|
|
// no print server, no client name, things are going bad...
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
|
|
// try the Printer name
|
|
if (ERROR_SUCCESS == GetPrinterData(hPrinter,
|
|
DEVICERDR_PRINTER_NAME,
|
|
NULL,
|
|
(LPBYTE)(name + i),
|
|
(printerNameLen - i) * sizeof(TCHAR),
|
|
&cbNeeded)) {
|
|
fFail = FALSE;
|
|
} else {
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
|
|
if (hPrinter) {
|
|
::ClosePrinter(hPrinter);
|
|
}
|
|
|
|
if (fFail && name) {
|
|
delete[] name;
|
|
name = NULL;
|
|
}
|
|
|
|
DC_END_FN();
|
|
|
|
return name;
|
|
}
|
|
|
|
|
|
LPTSTR
|
|
W32DrAutoPrn::CreateFriendlyNameFromNetworkName(LPTSTR printerName,
|
|
BOOL serverIsWin2K)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create a "friendly" printer name from the printer name of a
|
|
network printer.
|
|
|
|
Arguments:
|
|
|
|
printerName - Name returned by EnumPrinters
|
|
serverIsWin2K - For Win2K servers, we format the name as it will appear
|
|
on the server. Whistler servers and beyond do the
|
|
formatting for us.
|
|
|
|
Return Value:
|
|
|
|
Friendly name on success, that should be released by a call to
|
|
delete. NULL is returned on error.
|
|
|
|
--*/
|
|
{
|
|
DWORD printerNameLen;
|
|
LPTSTR name;
|
|
DWORD i;
|
|
WCHAR replaceChar;
|
|
|
|
DC_BEGIN_FN("W32DrAutoPrn::CreateFriendlyNameFromNetworkName");
|
|
|
|
//
|
|
// The \ placeholder is '_' for Win2K because Win2K doesn't reformat
|
|
// printer names. The '_' will actually be visible.
|
|
//
|
|
replaceChar = serverIsWin2K ? TEXT('_') : TEXT('!');
|
|
|
|
//
|
|
// Get the length of the printer name.
|
|
//
|
|
printerNameLen = _tcslen(printerName);
|
|
|
|
//
|
|
// Allocate space for ther "friendly" name.
|
|
//
|
|
name = new TCHAR[printerNameLen + 1];
|
|
if (name == NULL) {
|
|
TRC_ERR((TB, _T("Can't allocate %ld bytes for printer name."),
|
|
printerNameLen));
|
|
}
|
|
|
|
//
|
|
// Copy and convert the name.
|
|
//
|
|
if (name != NULL) {
|
|
for (i=0; i<printerNameLen; i++) {
|
|
if (printerName[i] != TEXT('\\')) {
|
|
name[i] = printerName[i];
|
|
}
|
|
else {
|
|
name[i] = replaceChar;
|
|
}
|
|
}
|
|
name[i] = TEXT('\0');
|
|
}
|
|
|
|
DC_END_FN();
|
|
|
|
return name;
|
|
}
|
|
|
|
LPTSTR
|
|
W32DrAutoPrn::GetLocalPrintingDocName()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Read Local printer Doc Name from the passed in struct
|
|
|
|
Arguments:
|
|
|
|
NA
|
|
|
|
Return Value:
|
|
|
|
Local Printer Document Name
|
|
|
|
--*/
|
|
{
|
|
DC_BEGIN_FN("W32DrAutoPrn::GetLocalPrintingDocName");
|
|
|
|
DC_END_FN();
|
|
return _szLocalPrintingDocName;
|
|
}
|
|
|
|
VOID W32DrAutoPrn::MsgIrpCreate(
|
|
IN PRDPDR_IOREQUEST_PACKET pIoRequestPacket,
|
|
IN UINT32 packetLen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle a Create IRP from the server.
|
|
|
|
Arguments:
|
|
|
|
params - Context for the IO request.
|
|
|
|
Return Value:
|
|
|
|
NA
|
|
|
|
--*/
|
|
{
|
|
W32DRDEV_ASYNCIO_PARAMS *params = NULL;
|
|
|
|
DWORD result = ERROR_SUCCESS;
|
|
|
|
DC_BEGIN_FN("W32DrAutoPrn::MsgIrpCreate");
|
|
|
|
params = new W32DRDEV_ASYNCIO_PARAMS(this, pIoRequestPacket);
|
|
if (params != NULL) {
|
|
params->thrPoolReq = _threadPool->SubmitRequest(
|
|
_AsyncMsgIrpCreateFunc,
|
|
params, NULL
|
|
);
|
|
if (params->thrPoolReq == NULL) {
|
|
result = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
}
|
|
else {
|
|
TRC_ERR((TB, L"Can't allocate parms."));
|
|
result = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
CLEANUPANDEXIT:
|
|
|
|
if (result != ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Return the failed result back to the server and clean up.
|
|
//
|
|
DefaultIORequestMsgHandle(pIoRequestPacket, result);
|
|
if (params != NULL) {
|
|
params->pIoRequestPacket = NULL;
|
|
delete params;
|
|
}
|
|
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
DWORD
|
|
W32DrAutoPrn::AsyncMsgIrpCreateFunc(
|
|
IN W32DRDEV_ASYNCIO_PARAMS *params
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle a "Close" IO request from the server, in a background thread.
|
|
|
|
Arguments:
|
|
|
|
params - Context for the IO request.
|
|
|
|
Return Value:
|
|
|
|
NA
|
|
|
|
--*/
|
|
{
|
|
PRDPDR_DEVICE_IOREQUEST pIoRequest;
|
|
ULONG ulRetCode;
|
|
DWORD result;
|
|
DOC_INFO_1 sDocInfo1;
|
|
|
|
DC_BEGIN_FN("W32DrAutoPrn::AsyncMsgIrpCreateFunc");
|
|
|
|
//
|
|
// This version does not work without a printer name.
|
|
//
|
|
ASSERT(_tcslen(GetPrinterName()));
|
|
|
|
//
|
|
// Get IO request pointer.
|
|
//
|
|
pIoRequest = ¶ms->pIoRequestPacket->IoRequest;
|
|
|
|
//
|
|
// Finish/Cancel any Current Jobs and Close, if Open.
|
|
//
|
|
ClosePrinter();
|
|
|
|
//
|
|
// Open the printer.
|
|
//
|
|
if (!W32DrOpenPrinter(_devicePath, &_printerHandle)) {
|
|
ulRetCode = GetLastError();
|
|
TRC_ERR((TB, _T("OpenPrinter %ld."), ulRetCode));
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Start Doc.
|
|
//
|
|
sDocInfo1.pDocName = GetLocalPrintingDocName();
|
|
sDocInfo1.pOutputFile = NULL;
|
|
sDocInfo1.pDatatype = _T("RAW");
|
|
_jobID = StartDocPrinter(_printerHandle, 1, (PBYTE)&sDocInfo1);
|
|
if (_jobID == 0) {
|
|
ulRetCode = GetLastError();
|
|
TRC_ERR((TB, _T("StartDocPrinter %ld."), ulRetCode));
|
|
ClosePrinter();
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Attempt to disable annoying printer pop up if we have sufficient
|
|
// privilege. Not a big deal, if we fail.
|
|
//
|
|
DisablePrinterPopup(_printerHandle, _jobID);
|
|
|
|
//
|
|
// Start the first page.
|
|
//
|
|
if (!StartPagePrinter(_printerHandle)) {
|
|
ulRetCode = GetLastError();
|
|
TRC_ERR((TB, _T("StartPagePrinter %ld."), ulRetCode));
|
|
ClosePrinter();
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// We are done successfully, say so.
|
|
//
|
|
ulRetCode = ERROR_SUCCESS;
|
|
|
|
Cleanup:
|
|
|
|
//
|
|
// Send the result to the server.
|
|
//
|
|
result = (ulRetCode == ERROR_SUCCESS) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
|
|
DefaultIORequestMsgHandle(params->pIoRequestPacket, result);
|
|
|
|
//
|
|
// Clean up the IO request parameters. DefaultIORequestMsgHandle cleans up
|
|
// the request packet.
|
|
//
|
|
if (params->thrPoolReq != INVALID_THREADPOOLREQUEST) {
|
|
_threadPool->CloseRequest(params->thrPoolReq);
|
|
params->thrPoolReq = INVALID_THREADPOOLREQUEST;
|
|
}
|
|
params->pIoRequestPacket = NULL;
|
|
delete params;
|
|
|
|
DC_END_FN();
|
|
return result;
|
|
}
|
|
|
|
VOID
|
|
W32DrAutoPrn::ClosePrinter()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
End any jobs in progress and close the printer.
|
|
|
|
Arguments:
|
|
|
|
NA
|
|
|
|
Return Value:
|
|
|
|
NA
|
|
|
|
--*/
|
|
{
|
|
DC_BEGIN_FN("W32DrAutoPrn::ClosePrinter");
|
|
|
|
if (_printerHandle != INVALID_HANDLE_VALUE) {
|
|
|
|
//
|
|
// Finish the current page for the current print job.
|
|
//
|
|
if (!EndPagePrinter(_printerHandle)) {
|
|
TRC_ERR((TB, _T("EndPagePrinter %ld."), GetLastError()));
|
|
}
|
|
|
|
//
|
|
// End the current print job.
|
|
//
|
|
if (!EndDocPrinter(_printerHandle)) {
|
|
TRC_ERR((TB, _T("EndDocPrinter %ld."), GetLastError()));
|
|
}
|
|
|
|
//
|
|
// Close the printer.
|
|
//
|
|
if (!::ClosePrinter(_printerHandle)) {
|
|
TRC_ERR((TB, _T("ClosePrinter %ld."), GetLastError()));
|
|
}
|
|
|
|
//
|
|
// Negate the handle and the pending job ID.
|
|
//
|
|
_printerHandle = INVALID_HANDLE_VALUE;
|
|
_jobID = 0;
|
|
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
VOID
|
|
W32DrAutoPrn::MsgIrpClose(
|
|
IN PRDPDR_IOREQUEST_PACKET pIoRequestPacket,
|
|
IN UINT32 packetLen
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle a "Close" IO request from the server by dispatching
|
|
the request to the thread pool. TODO: move this async
|
|
dispatch to the parent class in a future release. All closes
|
|
should be handled outside the main thread.-TadB
|
|
|
|
Arguments:
|
|
|
|
pIoRequestPacket - Server IO request packet.
|
|
|
|
Return Value:
|
|
|
|
NA
|
|
|
|
--*/
|
|
{
|
|
W32DRDEV_ASYNCIO_PARAMS *params = NULL;
|
|
|
|
DWORD result = ERROR_SUCCESS;
|
|
|
|
DC_BEGIN_FN("W32DrAutoPrn::MsgIrpClose");
|
|
|
|
params = new W32DRDEV_ASYNCIO_PARAMS(this, pIoRequestPacket);
|
|
if (params != NULL) {
|
|
params->thrPoolReq = _threadPool->SubmitRequest(
|
|
_AsyncMsgIrpCloseFunc,
|
|
params, NULL
|
|
);
|
|
if (params->thrPoolReq == NULL) {
|
|
result = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
}
|
|
else {
|
|
TRC_ERR((TB, L"Can't allocate parms."));
|
|
result = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto CLEANUPANDEXIT;
|
|
}
|
|
|
|
CLEANUPANDEXIT:
|
|
|
|
if (result != ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Return the failed result back to the server and clean up.
|
|
//
|
|
DefaultIORequestMsgHandle(pIoRequestPacket, result);
|
|
if (params != NULL) {
|
|
params->pIoRequestPacket = NULL;
|
|
delete params;
|
|
}
|
|
|
|
}
|
|
|
|
DC_END_FN();
|
|
}
|
|
|
|
DWORD
|
|
W32DrAutoPrn::AsyncMsgIrpCloseFunc(
|
|
IN W32DRDEV_ASYNCIO_PARAMS *params
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Handle a "Close" IO request from the server, in a background thread.
|
|
|
|
Arguments:
|
|
|
|
params - Context for the IO request.
|
|
|
|
Return Value:
|
|
|
|
NA
|
|
|
|
--*/
|
|
{
|
|
PRDPDR_DEVICE_IOREQUEST pIoRequest;
|
|
DWORD returnValue = STATUS_SUCCESS;
|
|
|
|
DC_BEGIN_FN("W32DrAutoPrn::MsgIrpClose");
|
|
|
|
//
|
|
// Close the printer.
|
|
//
|
|
ClosePrinter();
|
|
|
|
//
|
|
// Send the result to the server.
|
|
//
|
|
DefaultIORequestMsgHandle(params->pIoRequestPacket, returnValue);
|
|
|
|
//
|
|
// Clean up the IO request parameters. DefaultIORequestMsgHandle cleans up
|
|
// the request packet.
|
|
//
|
|
if (params->thrPoolReq != INVALID_THREADPOOLREQUEST) {
|
|
_threadPool->CloseRequest(params->thrPoolReq);
|
|
params->thrPoolReq = INVALID_THREADPOOLREQUEST;
|
|
}
|
|
params->pIoRequestPacket = NULL;
|
|
delete params;
|
|
|
|
DC_END_FN();
|
|
|
|
return returnValue;
|
|
}
|
|
|
|
DWORD
|
|
W32DrAutoPrn::GetPrinterFilterMask(
|
|
IN ProcObj *procObj
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the configurable print redirection filter mask.
|
|
|
|
Arguments:
|
|
|
|
procObj - The relevant process object.
|
|
|
|
Return Value:
|
|
|
|
Configurable Filter Mask
|
|
|
|
--*/
|
|
{
|
|
DWORD filter;
|
|
|
|
//
|
|
// Read FilterQueueType parameters so we know which devices
|
|
// to redirect.
|
|
//
|
|
if (procObj->GetDWordParameter(
|
|
REG_RDPDR_FILTER_QUEUE_TYPE,
|
|
&filter) != ERROR_SUCCESS) {
|
|
//
|
|
// Default.
|
|
//
|
|
filter = FILTER_ALL_QUEUES;
|
|
}
|
|
return filter;
|
|
}
|
|
|
|
BOOL
|
|
W32DrAutoPrn::W32DrOpenPrinter(
|
|
IN LPTSTR pPrinterName,
|
|
IN LPHANDLE phPrinter
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Open a printer with highest access possible.
|
|
|
|
Arguments:
|
|
|
|
pPrinterName - Pointer to printer or server name.
|
|
phPrinter - Pointer to printer or server handle.
|
|
|
|
Return Value:
|
|
|
|
TRUE on success. FALSE, otherwise.
|
|
|
|
--*/
|
|
{
|
|
PRINTER_DEFAULTS sPrinter;
|
|
BOOL result;
|
|
|
|
DC_BEGIN_FN("W32DrAutoPrn::W32DrOpenPrinter");
|
|
|
|
//
|
|
// Open printer.
|
|
//
|
|
sPrinter.pDatatype = NULL;
|
|
sPrinter.pDevMode = NULL;
|
|
sPrinter.DesiredAccess = PRINTER_ACCESS_USE;
|
|
result = OpenPrinter(pPrinterName, phPrinter, &sPrinter);
|
|
if (!result) {
|
|
TRC_ALT((TB, _T("Full-Access OpenPrinter %ld."), GetLastError()));
|
|
|
|
//
|
|
// Try with default access.
|
|
//
|
|
result = OpenPrinter(pPrinterName, phPrinter, NULL);
|
|
if (!result) {
|
|
TRC_ERR((TB, _T("OpenPrinter %ld."), GetLastError()));
|
|
}
|
|
}
|
|
|
|
DC_END_FN();
|
|
|
|
return result;
|
|
}
|
|
|
|
VOID
|
|
W32DrAutoPrn::DisablePrinterPopup(
|
|
HANDLE hPrinterHandle,
|
|
ULONG ulJobID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Disable annoying printer pop up for the specified printer
|
|
and print job.
|
|
|
|
Arguments:
|
|
|
|
hPrinterHandle - handle to a printer device.
|
|
|
|
ulJobID - ID of the job.
|
|
|
|
Return Value:
|
|
|
|
NA
|
|
|
|
--*/
|
|
{
|
|
JOB_INFO_2* pJobInfo2 = NULL;
|
|
ULONG ulJobBufSize;
|
|
|
|
DC_BEGIN_FN("W32DrAutoPrn::DisablePrinterPopup");
|
|
|
|
ulJobBufSize = 2 * 1024;
|
|
pJobInfo2 = (JOB_INFO_2 *)new BYTE[ulJobBufSize];
|
|
|
|
//
|
|
// Note we call the ANSI version of the API
|
|
// because we don't have a UNICODE wrapper for Get/SetJob.
|
|
// Main reason is we don't actually use any returned string
|
|
// data directly.
|
|
//
|
|
|
|
if(!_bRunningOn9x)
|
|
{
|
|
//Call unicode API's
|
|
|
|
if( pJobInfo2 != NULL ) {
|
|
//
|
|
// Get job info.
|
|
//
|
|
if( GetJob(
|
|
hPrinterHandle,
|
|
ulJobID,
|
|
2,
|
|
(PBYTE)pJobInfo2,
|
|
ulJobBufSize,
|
|
&ulJobBufSize )) {
|
|
|
|
//
|
|
// Disable popup notification by setting pNotifyName
|
|
// NULL.
|
|
//
|
|
pJobInfo2->pNotifyName = NULL;
|
|
pJobInfo2->Position = JOB_POSITION_UNSPECIFIED;
|
|
if( !SetJob(
|
|
hPrinterHandle,
|
|
ulJobID,
|
|
2,
|
|
(PBYTE)pJobInfo2,
|
|
0 )) {
|
|
|
|
TRC_ERR((TB, _T("SetJob %ld."), GetLastError()));
|
|
}
|
|
}
|
|
else {
|
|
TRC_ERR((TB, _T("GetJob %ld."), GetLastError()));
|
|
}
|
|
delete (PBYTE)pJobInfo2;
|
|
}
|
|
else {
|
|
TRC_ERR((TB, _T("Memory Allocation failed.")));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Call ANSI API's
|
|
if( pJobInfo2 != NULL ) {
|
|
//
|
|
// Get job info.
|
|
//
|
|
if( GetJobA(
|
|
hPrinterHandle,
|
|
ulJobID,
|
|
2,
|
|
(PBYTE)pJobInfo2,
|
|
ulJobBufSize,
|
|
&ulJobBufSize )) {
|
|
|
|
//
|
|
// Disable popup notification by setting pNotifyName
|
|
// NULL.
|
|
//
|
|
pJobInfo2->pNotifyName = NULL;
|
|
if( !SetJobA(
|
|
hPrinterHandle,
|
|
ulJobID,
|
|
2,
|
|
(PBYTE)pJobInfo2,
|
|
0 )) {
|
|
|
|
TRC_ERR((TB, _T("SetJob %ld."), GetLastError()));
|
|
}
|
|
}
|
|
else {
|
|
TRC_ERR((TB, _T("GetJob %ld."), GetLastError()));
|
|
}
|
|
delete (PBYTE)pJobInfo2;
|
|
}
|
|
else {
|
|
TRC_ERR((TB, _T("Memory Allocation failed.")));
|
|
}
|
|
}
|
|
DC_END_FN();
|
|
}
|
|
|
|
DWORD
|
|
W32DrAutoPrn::AsyncWriteIOFunc(
|
|
IN W32DRDEV_ASYNCIO_PARAMS *params
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Asynchronous Write Operation
|
|
|
|
Arguments:
|
|
|
|
params - Context for the IO request.
|
|
|
|
Return Value:
|
|
|
|
Returns 0 on success. Otherwise, a Windows error code is returned.
|
|
|
|
--*/
|
|
{
|
|
PBYTE pDataBuffer;
|
|
PRDPDR_IOCOMPLETION_PACKET pReplyPacket;
|
|
PRDPDR_DEVICE_IOREQUEST pIoRequest;
|
|
ULONG ulReplyPacketSize = 0;
|
|
DWORD status;
|
|
|
|
DC_BEGIN_FN("W32DrAutoPrn::AsyncWriteIOFunc");
|
|
|
|
// Assert the integrity of the IO context
|
|
ASSERT(params->magicNo == GOODMEMMAGICNUMBER);
|
|
|
|
//
|
|
// Get the IO request and reply..
|
|
//
|
|
pIoRequest = ¶ms->pIoRequestPacket->IoRequest;
|
|
pReplyPacket = params->pIoReplyPacket;
|
|
|
|
//
|
|
// Get the data buffer pointer.
|
|
//
|
|
pDataBuffer = (PBYTE)(pIoRequest + 1);
|
|
|
|
//
|
|
// Write the data to the print queue with the help of the spooler.
|
|
//
|
|
if (!WritePrinter(
|
|
_printerHandle,
|
|
pDataBuffer,
|
|
pIoRequest->Parameters.Write.Length,
|
|
&(pReplyPacket->IoCompletion.Parameters.Write.Length)) ) {
|
|
|
|
status = GetLastError();
|
|
TRC_ERR((TB, _T("WritePrinter %ld."), status));
|
|
}
|
|
else {
|
|
TRC_NRM((TB, _T("WritePrinter completed.")));
|
|
status = ERROR_SUCCESS;
|
|
}
|
|
|
|
DC_END_FN();
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|