📄 printqueue.cpp
字号:
for(it = PrintJobList.begin(); it != itEnd; ++it) {
(*it)->ShutDown();
}
}
HRESULT
SMBPrintQueue::FindPrintJob(USHORT Fid, PrintJob **pPrintJob)
{
CCritSection csLock(&csJobListLock);
csLock.Lock();
//
// Loop through all active jobs
ce::list<PrintJob *, PRINTJOB_LIST_ALLOC >::iterator it;
ce::list<PrintJob *, PRINTJOB_LIST_ALLOC >::iterator itEnd = PrintJobList.end();
*pPrintJob = NULL;
for(it = PrintJobList.begin(); it != itEnd; ++it) {
if(Fid == (*it)->JobID()) {
*pPrintJob = *it;
}
}
if(NULL != *pPrintJob) {
(*pPrintJob)->AddRef();
return S_OK;
}
else
return E_FAIL;
}
//
// NOTE: THIS IS ONLY TO BE CALLED BY THE PrintJob DESTRUCTOR!!!
//
HRESULT
SMBPrintQueue::RemovePrintJob(PrintJob *pPrintJob)
{
CCritSection csLock(&csJobListLock);
csLock.Lock();
HRESULT hr = E_FAIL;
//
// Loop through all active jobs
ce::list<PrintJob *, PRINTJOB_LIST_ALLOC >::iterator it;
ce::list<PrintJob *, PRINTJOB_LIST_ALLOC >::iterator itEnd = PrintJobList.end();
for(it = PrintJobList.begin(); it != itEnd; ++it) {
if(pPrintJob == (*it)) {
PrintJobList.erase(it++);
hr = S_OK;
break;
}
}
return hr;
}
HRESULT
SMBPrintQueue::JobsFinished(PrintJob *pPrintJob)
{
TRACEMSG(ZONE_PRINTQUEUE, (L"SMBSRV: printqueue -- closing spool for job %d", pPrintJob->JobID()));
//
// Here we set its status to finished...
if(pPrintJob) {
pPrintJob->SetInternalStatus(pPrintJob->GetInternalStatus() | JOB_STATUS_FINISHED);
}
return S_OK;
}
/*
*
* Print Job class information
*
*/
PrintJob::PrintJob(Share *_pMyShare, USHORT usFID) :
m_pMyShare(_pMyShare)
{
m_fShutDown = FALSE;
m_lRefCnt = 1;
m_uiBytesWritten = 0;
m_WakeUpThereIsData = CreateEvent(NULL, FALSE, FALSE, NULL);
InitializeCriticalSection(&m_csRingBuffer);
InitializeCriticalSection(&m_csMainLock);
m_usJobID = usFID;
this->SetInternalStatus(JOB_STATUS_UNKNOWN);
//
// Write down the start time (format per spec in cirsprt.doc)
m_ulStartTime = SecSinceJan1970_0_0_0();
//
// Add ourselves to our print queue
SMBPrintQueue *pMyQueue = NULL;
if(m_pMyShare) {
pMyQueue = m_pMyShare->GetPrintQueue();
}
ASSERT(NULL != pMyQueue);
if(pMyQueue) {
pMyQueue->AddJobToSpool(this);
}
}
PrintJob::~PrintJob()
{
TRACEMSG(ZONE_PRINTQUEUE, (L"SMB-PRINT: Job:%d finished", JobID()));
//
// Remove the print job from our queue
SMBPrintQueue *pMyQueue = NULL;
if(m_pMyShare) {
pMyQueue = m_pMyShare->GetPrintQueue();
}
ASSERT(NULL != pMyQueue);
if(pMyQueue) {
pMyQueue->RemovePrintJob(this);
}
DeleteCriticalSection(&m_csRingBuffer);
DeleteCriticalSection(&m_csMainLock);
CloseHandle(m_WakeUpThereIsData);
}
VOID
PrintJob::SetInternalStatus(USHORT s)
{
CCritSection csLock(&m_csMainLock);
csLock.Lock();
m_usJobInternalStatus = s;
TRACEMSG(ZONE_PRINTQUEUE, (L"SMBSRV: PrintQUEUE -- setting internal status on job %d -- status=(0x%x)!", JobID(), s));
IFDBG(if(s&JOB_STATUS_UNKNOWN)TRACEMSG(ZONE_PRINTQUEUE, (L" Unknown")));
IFDBG(if(s&JOB_STATUS_HAS_DATA)TRACEMSG(JOB_STATUS_HAS_DATA, (L" Has Data")));
IFDBG(if(s&JOB_STATUS_FINISHED)TRACEMSG(JOB_STATUS_FINISHED, (L" Finished")));
IFDBG(if(s&JOB_STATUS_FINISHED)TRACEMSG(JOB_STATUS_FINISHED, (L" In Print Queue")));
IFDBG(if(s&JOB_STATUS_ABORTED)TRACEMSG(JOB_STATUS_ABORTED, (L" Aborted")));
IFDBG(if(s&JOB_STATUS_PAUSED)TRACEMSG(JOB_STATUS_PAUSED, (L" Paused")));
//
// If we have been aborted, purge out the ringbuffer (this will happen on delete etc)
if(0 != (s&JOB_STATUS_ABORTED)) {
CCritSection csRingLock(&m_csRingBuffer);
csRingLock.Lock();
m_QueuedData.Purge();
}
//if they set the finished bit, wake up the writer
if(0 != (s & JOB_STATUS_FINISHED)) {
TRACEMSG(ZONE_PRINTQUEUE, (L"....setting finished bit!"));
SetEvent(m_WakeUpThereIsData);
}
}
HRESULT
PrintJob::SetComment(const WCHAR *_pComment)
{
HRESULT hr;
CCritSection csLock(&m_csMainLock);
csLock.Lock();
if(FAILED(hr = m_Comment.Clear())) {
return hr;
}
return m_Comment.append(_pComment);
}
HRESULT
PrintJob::SetQueueName(const WCHAR *pName)
{
HRESULT hr;
CCritSection csLock(&m_csMainLock);
csLock.Lock();
if(FAILED(hr = m_QueueName.Clear())) {
return hr;
}
return m_QueueName.append(pName);
}
HRESULT
PrintJob::SetOwnerName(const WCHAR * pName)
{
HRESULT hr;
CCritSection csLock(&m_csMainLock);
csLock.Lock();
if(FAILED(hr = m_OwnerName.Clear())) {
return hr;
}
return m_OwnerName.append(pName);
}
HRESULT
PrintJob::Read(BYTE *pDest, UINT uiSize, UINT *pRead)
{
HRESULT hr;
BOOL fNeedToBlock = FALSE;
CCritSection csLock(&m_csRingBuffer);
csLock.Lock();
*pRead = 0;
//
// if there isnt any data to read, we need to block until there is data
if(0 == m_QueuedData.BytesReadyToRead() &&
0 == (this->GetInternalStatus() & JOB_STATUS_FINISHED)) {
csLock.UnLock();
TRACEMSG(ZONE_PRINTQUEUE, (L"SMBSRV-PRINTQUEUE: print spool read() going to block (queue size %d)", m_QueuedData.BytesReadyToRead()));
if(WAIT_FAILED == WaitForSingleObject(m_WakeUpThereIsData, INFINITE)) {
TRACEMSG(ZONE_ERROR, (L"SMBSRV-PRINTQUEUE: error waiting for read event!!"));
ASSERT(FALSE);
hr = E_UNEXPECTED;
goto Done;
}
csLock.Lock();
}
ASSERT(csLock.IsLocked());
TRACEMSG(ZONE_PRINTQUEUE, (L"SMBSRV-PRINTQUEUE: print spool read() has %d bytes in queue", m_QueuedData.BytesReadyToRead()));
if(TRUE == this->m_fShutDown) {
TRACEMSG(ZONE_PRINTQUEUE, (L"SMBSRV-PRINTQUEUE: we have been told to shut down... canceling the request"));
return E_FAIL;
}
//
// Do the actual Read()
hr = m_QueuedData.Read(pDest, uiSize, pRead);
Done:
ASSERT(SUCCEEDED(hr));
ASSERT(uiSize >= *pRead);
return hr;
}
HRESULT
PrintJob::Write(const BYTE *pData, UINT uiSize, ULONG ulOffset, UINT *uiWritten)
{
HRESULT hr = E_FAIL;
BOOL fWakeupThreadOnExit = ((0==m_uiBytesWritten) && uiSize)?TRUE:FALSE;
#ifdef DEBUG
UINT uiBytesBefore = 0;
BOOL fBypassCountCheck = FALSE;
#endif
CCritSection csLock(&m_csRingBuffer);
UINT uiWrittenInPass;
if(NULL == pData || NULL == uiWritten) {
hr = E_INVALIDARG;
goto Done;
}
*uiWritten = 0;
csLock.Lock();
//
// If the job has been ended, this means it was removed
// by someone OTHER than the person writing! this is okay, but we
// have to do something -- tell them its okay
if(GetInternalStatus() & (JOB_STATUS_FINISHED | JOB_STATUS_ABORTED)) {
TRACEMSG(ZONE_PRINTQUEUE, (L"SMBSRV-PRINT: Job:%d has been closed, but TID is still valid (unclosed). -- just pretend that we wrote", JobID()));
*uiWritten = uiSize;
hr = S_OK;
#ifdef DEBUG
fBypassCountCheck = TRUE;
#endif
goto Done;
}
#ifdef DEBUG
uiBytesBefore = this->BytesLeftInQueue();
#endif
//
// Loop writing data into the spool
//
// If this job ISNT in the queue and our buffer is less than a quarter full always return 0 bytes written
//
//
// Here is the buffer layout
// [JOBS NOT ON QUEUE %25][Job In Queue 55%][Job In Queue Delay buffer 20%]
// the delay buffer is to help compensate for slow/jammed printers (and only given to the job thats activly printing)
//
//
// NOTE: this will make 9x clients quit their job, but the problem is if we dont do it
// jobs not on the queue will starve the job trying to print (causing deadlock)
if(FALSE == (GetInternalStatus() & JOB_STATUS_PRINTING) &&
m_QueuedData.BytesRemaining() * 4 <= m_QueuedData.TotalBufferSize()) {
TRACEMSG(ZONE_ERROR, (L"SMB_SRV: Buffer for job *NOT PRINTING* has gotten to %d of %d -- not writing!", m_QueuedData.BytesRemaining(), m_QueuedData.TotalBufferSize()));
uiWrittenInPass = 0;
hr = S_OK;
} else {
do {
if(SUCCEEDED(hr = m_QueuedData.Write(pData, uiSize, &uiWrittenInPass))) {
ASSERT(uiSize >= uiWrittenInPass);
pData += uiWrittenInPass;
uiSize -= uiWrittenInPass;
*uiWritten = (*uiWritten) + uiWrittenInPass;
m_uiBytesWritten += uiWrittenInPass;
} else {
uiWrittenInPass = 0;
hr = S_OK; //its okay if we didnt write, this just means buffers were full
}
} while(uiSize && uiWrittenInPass && SUCCEEDED(hr));
}
Done:
//
// If we wrote data, wake up the reader
if(0 != *uiWritten) {
TRACEMSG(ZONE_PRINTQUEUE, (L"SMBSRV-PRINTQUEUE: PRINTQUEUE -- writer() waking up reader() for JobID: %d", JobID()));
TRACEMSG(ZONE_PRINTQUEUE, (L" ...queue size is %d -- total written %d -- this pass %d\n", m_QueuedData.BytesReadyToRead(), m_uiBytesWritten, *uiWritten));
#ifdef PRINTQUEUE_BLOCK_WRITES
Sleep(PRINTQUEUE_MS_PER_KILOBYTE * (*uiWritten) / 1024);
#endif
SetEvent(m_WakeUpThereIsData);
#ifdef DEBUG
if(FALSE == fBypassCountCheck) {
ASSERT(uiBytesBefore + *uiWritten == this->BytesLeftInQueue());
}
#endif
}
if(m_QueuedData.TotalBufferSize() - m_QueuedData.BytesReadyToRead() <= 1024*1024 ||
(100 * m_QueuedData.BytesReadyToRead() / m_QueuedData.TotalBufferSize()) >= 80) {
TRACEMSG(ZONE_ERROR, (L"SMB_SRV: Buffer size has gotten to %d of %d -- delaying packets", m_QueuedData.BytesReadyToRead(), m_QueuedData.TotalBufferSize()));
// Free up the cracker
Sleep(1000);
}
return hr;
}
USHORT
PrintJob::JobID() {
CCritSection csLock(&m_csMainLock);
csLock.Lock();
return m_usJobID;
}
USHORT
PrintJob::GetInternalStatus() {
CCritSection csLock(&m_csMainLock);
csLock.Lock();
return m_usJobInternalStatus;
}
USHORT
PrintJob::GetStatus() { //this function converts status code to be good for network
USHORT Status = GetInternalStatus();
USHORT usRetStatus = 0;
if( Status & JOB_STATUS_PAUSED)
usRetStatus |= PRJ_QS_PAUSED;
if( Status & JOB_STATUS_PRINTING)
usRetStatus |= PRJ_QS_PRINTING;
else
usRetStatus |= PRJ_QS_SPOOLING;
return usRetStatus;
}
UINT
PrintJob::BytesLeftInQueue() {
CCritSection csLock(&m_csMainLock);
csLock.Lock();
return m_QueuedData.BytesReadyToRead();
}
const WCHAR *
PrintJob::GetQueueName() {
return m_QueueName.GetString();
}
const WCHAR *
PrintJob::GetComment() {
return m_Comment.GetString();
}
const WCHAR *
PrintJob::GetOwnerName() {
return m_OwnerName.GetString();
}
Share *
PrintJob::MyShare() {
return m_pMyShare;
}
VOID
PrintJob::Release() {
if(0 == InterlockedDecrement(&m_lRefCnt)) {
delete this;
}
#ifdef DEBUG
TRACEMSG(ZONE_PRINTQUEUE, (L"SMB_SRV: Release() for job %d to cnt %d", m_usJobID, m_lRefCnt));
#endif
}
VOID
PrintJob::AddRef() {
InterlockedIncrement(&m_lRefCnt);
TRACEMSG(ZONE_PRINTQUEUE, (L"SMB_SRV: AddRef() for job %d to cnt %d", m_usJobID, m_lRefCnt));
}
VOID
PrintJob::ShutDown() {
ASSERT(!m_fShutDown);
m_fShutDown = TRUE;
SetEvent(m_WakeUpThereIsData);
}
UINT
PrintJob::TotalBytesWritten() {
return m_uiBytesWritten;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -