/*++ Copyright (c) 1998 Microsoft Corporation Module Name : rdppnutl.c Abstract: User-Mode RDP Module Containing Redirected Printer-Related Utilities Author: TadB Revision History: --*/ #include #include #include "rdppnutl.h" #include "regapi.h" #include ////////////////////////////////////////////////////////////// // // Defines and Macros // // // Spooler Service Name // #define SPOOLER L"Spooler" // // Is a character numeric? // #define ISNUM(c) ((c>='0')&&(c<='9')) ////////////////////////////////////////////////////////////// // // Globals to this Module // // Number of seconds to wait for the spooler to finish initializing. DWORD SpoolerServiceTimeout = 45; ////////////////////////////////////////////////////////////// // // Internal Prototypes // // Actually performs the printer deletion. void DeleteTSPrinters( IN PRINTER_INFO_5 *pPrinterInfo, IN DWORD count ); // Load registry settings for this module. void LoadRDPPNUTLRegistrySettings(); // Waits until the spooler finishes initializing or until a timeout period // elapses. DWORD WaitForSpoolerToStart(); DWORD RDPPNUTL_RemoveAllTSPrinters() /*++ Routine Description: Removes all TS-Redirected Printer Queues Arguments: Return Value: Returns ERROR_SUCCESS on success. Error status, otherwise. --*/ { PRINTER_INFO_5 *pPrinterInfo = NULL; DWORD cbBuf = 0; DWORD cReturnedStructs = 0; DWORD tsPrintQueueFlags; NTSTATUS status; PBYTE buf = NULL; OSVERSIONINFOEX versionInfo; unsigned char stackBuf[4 * 1024]; // Initial EnumPrinter buffer size to // avoid two round-trip RPC's, if possible. // // This code should only run on server. For Pro/Personal, we can't run because it // affects boot performance. For Pro, we clean up queues in winlogon anyway. // versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); if (!GetVersionEx((LPOSVERSIONINFO)&versionInfo)) { status = GetLastError(); TRACE((DEBUG_TSHRSRV_ERROR,"RDPPNUTL: GetVersionEx failed. Error: %08X.\n", status)); TS_ASSERT(FALSE); return status; } if (versionInfo.wProductType == VER_NT_WORKSTATION) { TRACE((DEBUG_TSHRSRV_DEBUG,"RDPPNUTL: Skipping cleanup because not server\n")); return ERROR_SUCCESS; } TRACE((DEBUG_TSHRSRV_DEBUG,"RDPPNUTL: RDPPNUTL_RemoveAllTSPrinters entry\n")); // // Load registry settings for this module. // LoadRDPPNUTLRegistrySettings(); // // Wait until the spooler has finished initializing. // status = WaitForSpoolerToStart(); if (status != ERROR_SUCCESS) { TRACE(( DEBUG_TSHRSRV_DEBUG, "RDPPNUTL: RDPPNUTL_RemoveAllTSPrinters exiting because spooler failed to start.\n" )); return status; } // // Try to enumerate printers using the stack buffer, first, to avoid two // round-trip RPC's to the spooler, if possible. // if (!EnumPrinters( PRINTER_ENUM_LOCAL, // Flags NULL, // Name 5, // Print Info Type stackBuf, // buffer sizeof(stackBuf), // Size of buffer &cbBuf, // Required &cReturnedStructs)) { status = GetLastError(); // // See if we need to allocate more room for the printer information. // if (status == ERROR_INSUFFICIENT_BUFFER) { buf = TSHeapAlloc(HEAP_ZERO_MEMORY, cbBuf, TS_HTAG_TSS_PRINTERINFO2); if (buf == NULL) { TRACE((DEBUG_TSHRSRV_ERROR,"RDPPNUTL: ALLOCMEM failed. Error: %08X.\n", GetLastError())); status = ERROR_OUTOFMEMORY; } else { pPrinterInfo = (PRINTER_INFO_5 *)buf; status = ERROR_SUCCESS; } // // Enumerate printers. // if (status == ERROR_SUCCESS) { if (!EnumPrinters( PRINTER_ENUM_LOCAL, NULL, 5, (PBYTE)pPrinterInfo, cbBuf, &cbBuf, &cReturnedStructs)) { TRACE((DEBUG_TSHRSRV_ERROR,"RDPPNUTL: EnumPrinters failed. Error: %08X.\n", GetLastError())); status = GetLastError(); } else { TRACE((DEBUG_TSHRSRV_DEBUG,"RDPPNUTL: Second EnumPrinters succeeded.\n")); } } } else { TRACE((DEBUG_TSHRSRV_ERROR,"RDPPNUTL: EnumPrinters failed. Error: %08X.\n", GetLastError())); } } else { TRACE((DEBUG_TSHRSRV_DEBUG,"RDPPNUTL: First EnumPrinters succeeded.\n")); status = ERROR_SUCCESS; pPrinterInfo = (PRINTER_INFO_5 *)stackBuf; } // // Delete all the TS printers. We allow ERROR_INSUFFICIENT_BUFFER here because // a second invokation of EnumPrinters may have missed a few last-minute // printer additions. // if ((status == ERROR_SUCCESS) || (status == ERROR_INSUFFICIENT_BUFFER)) { DeleteTSPrinters(pPrinterInfo, cReturnedStructs); status = ERROR_SUCCESS; } // // Release the printer info buffer. // if (buf != NULL) { TSHeapFree(buf); } TRACE((DEBUG_TSHRSRV_DEBUG,"TShrSRV: RDPPNUTL_RemoveAllTSPrinters exit\n")); return status; } void DeleteTSPrinters( IN PRINTER_INFO_5 *pPrinterInfo, IN DWORD count ) /*++ Routine Description: Actually performs the printer deletion. Arguments: pPrinterInfo - All printer queues on the system. count - Number of printers in pPrinterInfo Return Value: NA --*/ { DWORD i; DWORD regValueDataType; DWORD sessionID; HANDLE hPrinter = NULL; DWORD bufSize; PRINTER_DEFAULTS defaults = {NULL, NULL, PRINTER_ALL_ACCESS}; TRACE((DEBUG_TSHRSRV_DEBUG,"RDPPNUTL: DeleteTSPrinters entry\n")); for (i=0; idwStartType != SERVICE_AUTO_START) { TRACE((DEBUG_TSHRSRV_WARN,"RDPPNUTL: Spooler not configured to start.\n")); result = E_FAIL; goto CleanUpAndExit; } // // Poll the service status until we timeout or until the spooler // starts. // for (i=0; (i