📄 printqueue.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
#include <windows.h>
#include <Winbase.h>
#include <CReg.hxx>
#include "SMB_Globals.h"
#include "PrintQueue.h"
#include "ShareInfo.h"
#include "SMBPackets.h"
#include "SMBErrors.h"
#include "ConnectionManager.h"
#include "Cracker.h"
#include "SMBCommands.h"
BOOL PrintQueue::fIsRunning = FALSE;
//blocking writes simulates a stalled printer (to test queue managment)
//#define PRINTQUEUE_BLOCK_WRITES // <-- uses PRINTQUEUE_MS_PER_BYTE (this slows the SMB)
//#define PRINTQUEUE_BLOCK_READS // <-- uses PRINTQUEUE_MS_PER_BYTE (this slows the printing)
//#define PRINTQUEUE_USE_FILE
//#define PRINTQUEUE_MS_SLEEP_TO_START_QUEUE 5000
//#define PRINTQUEUE_MS_PER_KILOBYTE 100
#define DEFAULT_SWAP_FILE L"\\Printer.swap"
#define DEFAULT_SWAP_MAX 2000000
#define DEFAULT_SWAP_INC 10000
ce::fixed_block_allocator<10> SMB_Globals::g_PrintJobAllocator;
//
// Forward declare functions here
VOID FileTimeToDosDateTime(FILETIME * ft,WORD *ddate,WORD *dtime);
DWORD DosToNetTime(WORD time, WORD date);
DWORD
PrintQueue::SMBSRV_SpoolThread(LPVOID lpvPrintQueue)
{
UINT uiToBeWrittenSize = 20000;
BYTE *pToBeWritten = new BYTE[uiToBeWrittenSize]; //BUGBUG: make this a const (and = to the block size)
SMBPrintQueue *pPrintQueue = (SMBPrintQueue *)lpvPrintQueue;
if(NULL == pPrintQueue) {
ASSERT(FALSE);
goto Done;
}
if(NULL == pToBeWritten) {
goto Done;
}
for(;;)
{
PrintJob *pPrintJob = NULL;
HANDLE hPrinter = INVALID_HANDLE_VALUE;
TRACEMSG(ZONE_PRINTQUEUE, (L"SMBSRV-PRINTQUEUE: Waiting for new print job to enter the queue... ZZZzzzz"));
if(pPrintQueue->ShuttingDown()) {
TRACEMSG(ZONE_PRINTQUEUE, (L"SMBSRV-PRINTQUEUE: Shutting down -- stopping spool thread"));
break;
}
//
// Get the next job (remember to Release() it!)
if(NULL == (pPrintJob = pPrintQueue->WaitForJobThatIsReady())) {
TRACEMSG(ZONE_PRINTQUEUE, (L"SMBSRV-PRINTQUEUE: we woke up but there isnt anything to print... maybe we were removing a dead job"));
continue;
}
TRACEMSG(ZONE_PRINTQUEUE, (L"SMBSRV-PRINTQUEUE: I'm up... I'm up... Got a job to start printing!"));
//
// See if the job has been aborted, if so kill it off
if(pPrintJob->GetInternalStatus() & JOB_STATUS_ABORTED) {
TRACEMSG(ZONE_PRINTQUEUE, (L"SMBSRV-PRINTQUEUE: this job was aborted... kill it off"));
//
// Release our job, if there are no more refs to it, it will go away
pPrintJob->Release();
continue;
}
#if defined (PRINTQUEUE_MS_SLEEP_TO_START_QUEUE)
TRACEMSG(ZONE_PRINTQUEUE, (L"SMBSRV-PRINTQUEUE: going to sleep for %d ms to simulate slow printer?",PRINTQUEUE_MS_SLEEP_TO_START_QUEUE));
Sleep(PRINTQUEUE_MS_SLEEP_TO_START_QUEUE);
#endif
#if !defined(PRINTQUEUE_USE_FILE)
//
// Open up the parallel port
if(NULL == pPrintJob->MyShare())
{
TRACEMSG(ZONE_ERROR, (L"SMBSRV-PRINTQUEUE: Error opening opening up share"));
goto Done;
}
if(INVALID_HANDLE_VALUE == (hPrinter = CreateFile(pPrintQueue->GetPortName(), GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL,NULL)))
//if(INVALID_HANDLE_VALUE == (hPrinter = CreateFile(L"myprinter.file", GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL,NULL)))
{
TRACEMSG(ZONE_ERROR, (L"SMBSRV-PRINTQUEUE: Error opening printer on %s (err=%d)", pPrintQueue->GetPortName(), GetLastError()));
Sleep(5000); //BUGBUG: sleep for some reg configurable amount of time here
//
// Thump the queue
pPrintQueue->JobReadyForPrint(NULL);
continue;
}
#else
WCHAR TempFileName[MAX_PATH];
GetTempFileName(L"\\", L"SMBSpool", 0, TempFileName);
if(INVALID_HANDLE_VALUE == (hPrinter = CreateFile(TempFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,NULL)))
{
TRACEMSG(ZONE_ERROR, (L"SMBSRV-PRINTQUEUE: Error opening printer on %s (err=%d)", pPrintQueue->GetPortName(), GetLastError()));
Sleep(5000); //BUGBUG: sleep for some reg configurable amount of time here
//
// Thump the queue
pPrintQueue->JobReadyForPrint(NULL);
continue;
}
#endif
TRACEMSG(ZONE_PRINTQUEUE, (L"SMBSRV-PRINTQUEUE: Job:%d has started printing", pPrintJob->JobID()));
//
// Mark bit saying the job is printing
pPrintJob->SetInternalStatus(pPrintJob->GetInternalStatus() | JOB_STATUS_PRINTING);
//
// Loop while there is data
UINT uiRead;
UINT uiTotalRead = 0;
BOOL fDontWrite = FALSE;
HRESULT hr;
while(SUCCEEDED(hr = pPrintJob->Read(pToBeWritten, uiToBeWrittenSize, &uiRead))) {
if(0 == uiRead &&
0 == pPrintJob->BytesLeftInQueue() &&
(pPrintJob->GetInternalStatus() & JOB_STATUS_FINISHED)) {
TRACEMSG(ZONE_PRINTQUEUE, (L"SMBSRV-PRINTQUEUE: nothing left to read -- we are done, close up"));
break;
}
uiTotalRead += uiRead;
//
// Write back to printer
BYTE *pToWrite = pToBeWritten;
while(uiRead) {
DWORD dwWritten;
if(FALSE == fDontWrite && 0 == WriteFile(hPrinter, pToWrite, uiRead, &dwWritten, NULL))
{
TRACEMSG(ZONE_ERROR, (L"SMBSRV-PRINTQUEUE: Error writing to printer! (err=%d)", GetLastError()));
ASSERT(FALSE);
fDontWrite = TRUE;
} else if(TRUE == fDontWrite) {
TRACEMSG(ZONE_ERROR, (L"SMBSRV-PRINTQUEUE: MAJOR Error writing to printer! (err=%d) - lying to flush buffers!", GetLastError()));
dwWritten = uiRead;
}
#if defined(PRINTQUEUE_BLOCK_READS) && defined(DEBUG)
Sleep(PRINTQUEUE_MS_PER_KILOBYTE * dwWritten / 1024);
#endif
TRACEMSG(ZONE_PRINTQUEUE, (L"SMBSRV-PRINTQUEUE: Just Sent %d bytes to printer", dwWritten));
pToWrite += dwWritten;
uiRead -= dwWritten;
}
}
//
// Mark the job saying we are done with it
TRACEMSG(ZONE_PRINTQUEUE, (L"SMBSRV-PRINTQUEUE: Finished print job... closing handle and going to sleep (%d bytes read/written for job)", uiTotalRead));
pPrintJob->SetInternalStatus(pPrintJob->GetInternalStatus() | JOB_STATUS_PRINTED);
pPrintJob->SetInternalStatus(pPrintJob->GetInternalStatus() & (~JOB_STATUS_PRINTING));
pPrintJob->Release();
//
// Close up shop
CloseHandle(hPrinter);
hPrinter = INVALID_HANDLE_VALUE;
#if defined (PRINTQUEUE_USE_FILE)
//
// If we are spooling to file, delete the file
DeleteFile(TempFileName);
#endif
}
#if !defined(PRINTQUEUE_USE_FILE)
Done:
#endif
//
// We need to go and release all jobs that are ours. do this by marking them
// invalid, and releasing them
{
PrintJob *pPrintJob = NULL;
while(NULL != (pPrintJob = pPrintQueue->GetJobNextJobThatIsReady())) {
pPrintJob->SetInternalStatus(pPrintJob->GetInternalStatus() | JOB_STATUS_PRINTED);
pPrintJob->SetInternalStatus(pPrintJob->GetInternalStatus() & (~JOB_STATUS_PRINTING));
pPrintJob->Release();
}
}
if(NULL != pToBeWritten) {
delete [] pToBeWritten;
}
return 0;
}
HRESULT StartPrintSpool()
{
CReg RegPrinter;
HRESULT hr = E_FAIL;
WCHAR SwapFile[MAX_PATH];
UINT uiMax, uiInc;
//
// Load the CName from the registry
if(FALSE == RegPrinter.Open(HKEY_LOCAL_MACHINE, L"Services\\SMBServer")) {
swprintf(SwapFile, DEFAULT_SWAP_FILE);
uiMax = DEFAULT_SWAP_MAX;
uiInc = DEFAULT_SWAP_INC;
} else {
if(FALSE == RegPrinter.ValueSZ(L"PrintSwapFile", SwapFile, MAX_PATH/sizeof(WCHAR))) {
swprintf(SwapFile, DEFAULT_SWAP_FILE);
}
uiMax = RegPrinter.ValueDW(L"PrintSwapMax", DEFAULT_SWAP_MAX);
uiInc = RegPrinter.ValueDW(L"PrintSwapInc", DEFAULT_SWAP_INC);
}
TRACEMSG(ZONE_PRINTQUEUE, (L"SMB_PRINT: Configuring swap file."));
TRACEMSG(ZONE_PRINTQUEUE, (L" File: %s", SwapFile));
TRACEMSG(ZONE_PRINTQUEUE, (L" Max : %d", uiMax));
TRACEMSG(ZONE_PRINTQUEUE, (L" Inc : %d", uiInc));
//
// Fire up our swap memory
if(FAILED(hr = SMB_Globals::g_PrinterMemMapBuffers.Open(SwapFile, uiMax, uiInc))) {
TRACEMSG(ZONE_ERROR, (L"SMB_PRINT: Error Opening memory map! -- cant continue"));
goto Done;
}
ASSERT(FALSE == PrintQueue::fIsRunning);
PrintQueue::fIsRunning = TRUE;
Done:
return hr;
}
HRESULT StopPrintSpool()
{
HRESULT hr = E_FAIL;
UINT i, uiNumShares;
//
// Verify incoming params
if(FALSE == PrintQueue::fIsRunning) {
TRACEMSG(ZONE_PRINTQUEUE, (L"SMBSRV-PRINTQUEUE: stopping print spool not required since it never started!"));
hr = S_OK;
goto Done;
}
//
// At this point we know that no new shares are going to be ENTERED
// so its okay to enumerate through them killing off jobs
uiNumShares = SMB_Globals::g_pShareManager->NumShares();
for(i=0; i<uiNumShares; i++) {
Share *pShare = SMB_Globals::g_pShareManager->SearchForShare(i);
SMBPrintQueue *pQueue;
if(NULL != pShare && NULL!=(pQueue = pShare->GetPrintQueue())){
//
// Tap the event saying there is a job ready (this is a lie, but
// the thread will check to see if its supposed to shutdown so its
// okay (it saves an event)
pQueue->SetShutDown(TRUE);
pQueue->StopAllJobs();
pQueue->JobReadyForPrint(NULL);
}
}
hr = S_OK;
ASSERT(TRUE == PrintQueue::fIsRunning);
Done:
if(SUCCEEDED(hr)) {
PrintQueue::fIsRunning = FALSE;
}
return hr;
}
HRESULT SetString(CHAR **pOldString, const CHAR *pNewString)
{
HRESULT hr;
UINT uiLen;
CHAR *pTemp;
//verify incoming params
if(NULL == pNewString) {
hr = E_INVALIDARG;
goto Done;
}
//make a new memory buffer for the name
uiLen = strlen(pNewString) + 1;
pTemp = new CHAR[uiLen];
//if we are out of memory return
if(NULL == pTemp) {
hr = E_OUTOFMEMORY;
goto Done;
}
//delete old memory and replace with new
if(*pOldString)
delete [] *pOldString;
*pOldString = pTemp;
//do the copy
memcpy(*pOldString, pNewString, uiLen);
hr = S_OK;
Done:
return hr;
}
SMBPrintQueue::SMBPrintQueue()
{
Priority = 0;
StartTime = 0;
UntilTime = 0;
Pad1 = 0;
pSepFile = 0;
pPrProc = 0;
pParams = 0;
pComment = 0;
Status = 0;
cJobs = 0;
pPrinters = 0;
pDriverName = 0;
pDriverData = 0;
pName = 0;
wPortName = 0;
fShutDown = FALSE;
ReadyToPrintSemaphore = NULL;
InitializeCriticalSection(&csJobListLock);
//
// Fire up the spool semaphore
ReadyToPrintSemaphore = CreateSemaphore(NULL, 0, SMB_Globals::g_uiMaxJobsInPrintQueue ,NULL);
//
// Spin the print spool thread (this thread does the actual printing
// MUST Be last for error handling
if(NULL == (PrintThreadHandle = CreateThread(NULL, 0, PrintQueue::SMBSRV_SpoolThread, (VOID*)this, 0, NULL))) {
TRACEMSG(ZONE_ERROR, (L"SSMBSRV-PRINTQUEUE: cant make spool thread"));
}
}
SMBPrintQueue::~SMBPrintQueue()
{
//
// Tap the event saying there is a job ready (this is a lie, but
// the thread will check to see if its supposed to shutdown so its
// okay (it saves an event)
this->SetShutDown(TRUE);
this->StopAllJobs();
this->JobReadyForPrint(NULL);
//
// Now block for the print thread to stop
if(WAIT_FAILED == WaitForSingleObject(PrintThreadHandle, INFINITE)) {
TRACEMSG(ZONE_INIT, (L"SMBSRV-PRINTQUEUE: Waiting for spool thread FAILED!"));
ASSERT(FALSE);
}
//
// Destroy all members
if(pName)
delete [] pName;
if(pSepFile)
delete [] pSepFile;
if(pPrProc)
delete [] pPrProc;
if(pParams)
delete [] pParams;
if(pComment)
delete [] pComment;
if(pPrinters)
delete [] pPrinters;
if(pDriverName)
delete [] pDriverName;
if(pDriverData)
delete [] pDriverData;
if(wPortName)
delete [] wPortName;
//
// Clean up memory
DeleteCriticalSection(&csJobListLock);
CloseHandle(ReadyToPrintSemaphore);
CloseHandle(PrintThreadHandle);
ReadyToPrintSemaphore = INVALID_HANDLE_VALUE;
PrintThreadHandle = INVALID_HANDLE_VALUE;
ASSERT(INVALID_HANDLE_VALUE == PrintThreadHandle);
ASSERT(0 == PrintJobList.size());
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -