X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=reactos%2Fwin32ss%2Fprinting%2Fproviders%2Flocalspl%2Fjobs.c;h=b080bf944f84ec40560753d0a86e2a5bd3827542;hp=81806b44035cca4a7ade6d3b698c2c5f73805702;hb=2e94fb273dcfe0ef2e94ed6e7514d7f5ccedffbd;hpb=7aef841dea48385604bfbccb101d9c87bcf3ec7c diff --git a/reactos/win32ss/printing/providers/localspl/jobs.c b/reactos/win32ss/printing/providers/localspl/jobs.c index 81806b44035..b080bf944f8 100644 --- a/reactos/win32ss/printing/providers/localspl/jobs.c +++ b/reactos/win32ss/printing/providers/localspl/jobs.c @@ -102,7 +102,7 @@ GetNextJobID(PDWORD dwJobID) return TRUE; } -void +BOOL InitializeGlobalJobList() { const WCHAR wszPath[] = L"\\PRINTERS\\?????.SHD"; @@ -110,6 +110,7 @@ InitializeGlobalJobList() const DWORD cchFolders = sizeof("\\PRINTERS\\") - 1; const DWORD cchPattern = sizeof("?????") - 1; + DWORD dwErrorCode; DWORD dwJobID; HANDLE hFind; PLOCAL_JOB pJob = NULL; @@ -133,6 +134,7 @@ InitializeGlobalJobList() if (hFind == INVALID_HANDLE_VALUE) { // No unfinished jobs found. + dwErrorCode = ERROR_SUCCESS; goto Cleanup; } @@ -159,6 +161,7 @@ InitializeGlobalJobList() // Add it to the Global Job List. if (!InsertElementSkiplist(&GlobalJobList, pJob)) { + dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; ERR("InsertElementSkiplist failed for job %lu for the GlobalJobList!\n", pJob->dwJobID); goto Cleanup; } @@ -166,16 +169,22 @@ InitializeGlobalJobList() // Add it to the Printer's Job List. if (!InsertElementSkiplist(&pJob->pPrinter->JobList, pJob)) { + dwErrorCode = ERROR_NOT_ENOUGH_MEMORY; ERR("InsertElementSkiplist failed for job %lu for the Printer's Job List!\n", pJob->dwJobID); goto Cleanup; } } while (FindNextFileW(hFind, &FindData)); + dwErrorCode = ERROR_SUCCESS; + Cleanup: // Outside the loop if (hFind) FindClose(hFind); + + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); } void @@ -209,7 +218,7 @@ LocalAddJob(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcb // Check if this is a printer handle. pHandle = (PLOCAL_HANDLE)hPrinter; - if (pHandle->HandleType != Printer) + if (pHandle->HandleType != HandleType_Printer) { dwErrorCode = ERROR_INVALID_HANDLE; goto Cleanup; @@ -267,9 +276,10 @@ LocalAddJob(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcb pJob->pPrinter = pPrinterHandle->pPrinter; pJob->pPrintProcessor = pPrinterHandle->pPrinter->pPrintProcessor; pJob->dwPriority = DEF_PRIORITY; + pJob->dwStatus = JOB_STATUS_SPOOLING; pJob->pwszDatatype = AllocSplStr(pPrinterHandle->pwszDatatype); pJob->pwszDocumentName = AllocSplStr(wszDefaultDocumentName); - CopyMemory(&pJob->DevMode, &pPrinterHandle->DevMode, sizeof(DEVMODEW)); + pJob->pDevMode = DuplicateDevMode(pPrinterHandle->pDevMode); GetSystemTime(&pJob->stSubmitted); // Get the user name for the Job. @@ -359,7 +369,7 @@ Cleanup: static DWORD -_LocalGetJobLevel1(PLOCAL_PRINTER_HANDLE pPrinterHandle, PLOCAL_JOB pJob, PBYTE pOutput, DWORD cbBuf, PDWORD pcbNeeded) +_LocalGetJobLevel1(PLOCAL_PRINTER_HANDLE pPrinterHandle, PLOCAL_JOB pJob, PBYTE* ppStart, PBYTE* ppEnd, DWORD cbBuf, PDWORD pcbNeeded) { DWORD cbDatatype = (wcslen(pJob->pwszDatatype) + 1) * sizeof(WCHAR); DWORD cbDocumentName = (wcslen(pJob->pwszDocumentName) + 1) * sizeof(WCHAR); @@ -369,58 +379,57 @@ _LocalGetJobLevel1(PLOCAL_PRINTER_HANDLE pPrinterHandle, PLOCAL_JOB pJob, PBYTE DWORD cbUserName = (wcslen(pJob->pwszUserName) + 1) * sizeof(WCHAR); DWORD dwErrorCode; JOB_INFO_1W JobInfo1 = { 0 }; - PBYTE pString; // A Status Message is optional. if (pJob->pwszStatus) cbStatus = (wcslen(pJob->pwszStatus) + 1) * sizeof(WCHAR); // Check if the supplied buffer is large enough. - *pcbNeeded = sizeof(JOB_INFO_1W) + cbDatatype + cbDocumentName + cbMachineName + cbPrinterName + cbStatus + cbUserName; + *pcbNeeded += sizeof(JOB_INFO_1W) + cbDatatype + cbDocumentName + cbMachineName + cbPrinterName + cbStatus + cbUserName; if (cbBuf < *pcbNeeded) { dwErrorCode = ERROR_INSUFFICIENT_BUFFER; goto Cleanup; } - // Put the strings right after the JOB_INFO_1W structure. - pString = pOutput + sizeof(JOB_INFO_1W); + // Put the strings at the end of the buffer. + *ppEnd -= cbDatatype; + JobInfo1.pDatatype = (PWSTR)*ppEnd; + CopyMemory(*ppEnd, pJob->pwszDatatype, cbDatatype); - JobInfo1.pDatatype = (PWSTR)pString; - CopyMemory(pString, pJob->pwszDatatype, cbDatatype); - pString += cbDatatype; + *ppEnd -= cbDocumentName; + JobInfo1.pDocument = (PWSTR)*ppEnd; + CopyMemory(*ppEnd, pJob->pwszDocumentName, cbDocumentName); - JobInfo1.pDocument = (PWSTR)pString; - CopyMemory(pString, pJob->pwszDocumentName, cbDocumentName); - pString += cbDocumentName; + *ppEnd -= cbMachineName; + JobInfo1.pMachineName = (PWSTR)*ppEnd; + CopyMemory(*ppEnd, pJob->pwszMachineName, cbMachineName); - JobInfo1.pMachineName = (PWSTR)pString; - CopyMemory(pString, pJob->pwszMachineName, cbMachineName); - pString += cbMachineName; - - JobInfo1.pPrinterName = (PWSTR)pString; - CopyMemory(pString, pJob->pPrinter->pwszPrinterName, cbPrinterName); - pString += cbPrinterName; + *ppEnd -= cbPrinterName; + JobInfo1.pPrinterName = (PWSTR)*ppEnd; + CopyMemory(*ppEnd, pJob->pPrinter->pwszPrinterName, cbPrinterName); if (cbStatus) { - JobInfo1.pStatus = (PWSTR)pString; - CopyMemory(pString, pJob->pwszStatus, cbStatus); - pString += cbStatus; + *ppEnd -= cbStatus; + JobInfo1.pStatus = (PWSTR)*ppEnd; + CopyMemory(*ppEnd, pJob->pwszStatus, cbStatus); } - JobInfo1.pUserName = (PWSTR)pString; - CopyMemory(pString, pJob->pwszUserName, cbUserName); - pString += cbUserName; + *ppEnd -= cbUserName; + JobInfo1.pUserName = (PWSTR)*ppEnd; + CopyMemory(*ppEnd, pJob->pwszUserName, cbUserName); - // Fill the structure and copy it as well. + // Fill the rest of the structure. JobInfo1.JobId = pJob->dwJobID; JobInfo1.Priority = pJob->dwPriority; JobInfo1.Status = pJob->dwStatus; JobInfo1.TotalPages = pJob->dwTotalPages; CopyMemory(&JobInfo1.Submitted, &pJob->stSubmitted, sizeof(SYSTEMTIME)); - CopyMemory(pOutput, &JobInfo1, sizeof(JOB_INFO_1W)); + // Finally copy the structure to the output pointer. + CopyMemory(*ppStart, &JobInfo1, sizeof(JOB_INFO_1W)); + *ppStart += sizeof(JOB_INFO_1W); dwErrorCode = ERROR_SUCCESS; Cleanup: @@ -428,9 +437,10 @@ Cleanup: } static DWORD -_LocalGetJobLevel2(PLOCAL_PRINTER_HANDLE pPrinterHandle, PLOCAL_JOB pJob, PBYTE pOutput, DWORD cbBuf, PDWORD pcbNeeded) +_LocalGetJobLevel2(PLOCAL_PRINTER_HANDLE pPrinterHandle, PLOCAL_JOB pJob, PBYTE* ppStart, PBYTE* ppEnd, DWORD cbBuf, PDWORD pcbNeeded) { DWORD cbDatatype = (wcslen(pJob->pwszDatatype) + 1) * sizeof(WCHAR); + DWORD cbDevMode = pJob->pDevMode->dmSize + pJob->pDevMode->dmDriverExtra; DWORD cbDocumentName = (wcslen(pJob->pwszDocumentName) + 1) * sizeof(WCHAR); DWORD cbDriverName = (wcslen(pJob->pPrinter->pwszPrinterDriver) + 1) * sizeof(WCHAR); DWORD cbMachineName = (wcslen(pJob->pwszMachineName) + 1) * sizeof(WCHAR); @@ -444,7 +454,6 @@ _LocalGetJobLevel2(PLOCAL_PRINTER_HANDLE pPrinterHandle, PLOCAL_JOB pJob, PBYTE FILETIME ftNow; FILETIME ftSubmitted; JOB_INFO_2W JobInfo2 = { 0 }; - PBYTE pString; ULARGE_INTEGER uliNow; ULARGE_INTEGER uliSubmitted; @@ -456,65 +465,63 @@ _LocalGetJobLevel2(PLOCAL_PRINTER_HANDLE pPrinterHandle, PLOCAL_JOB pJob, PBYTE cbStatus = (wcslen(pJob->pwszStatus) + 1) * sizeof(WCHAR); // Check if the supplied buffer is large enough. - *pcbNeeded = sizeof(JOB_INFO_2W) + cbDatatype + sizeof(DEVMODEW) + cbDocumentName + cbDriverName + cbMachineName + cbNotifyName + cbPrinterName + cbPrintProcessor + cbPrintProcessorParameters + cbStatus + cbUserName; + *pcbNeeded += sizeof(JOB_INFO_2W) + cbDatatype + cbDevMode + cbDocumentName + cbDriverName + cbMachineName + cbNotifyName + cbPrinterName + cbPrintProcessor + cbPrintProcessorParameters + cbStatus + cbUserName; if (cbBuf < *pcbNeeded) { dwErrorCode = ERROR_INSUFFICIENT_BUFFER; goto Cleanup; } - // Put the strings right after the JOB_INFO_2W structure. - pString = pOutput + sizeof(JOB_INFO_2W); + // Put the strings at the end of the buffer. + *ppEnd -= cbDatatype; + JobInfo2.pDatatype = (PWSTR)*ppEnd; + CopyMemory(*ppEnd, pJob->pwszDatatype, cbDatatype); - JobInfo2.pDatatype = (PWSTR)pString; - CopyMemory(pString, pJob->pwszDatatype, cbDatatype); - pString += cbDatatype; + *ppEnd -= cbDevMode; + JobInfo2.pDevMode = (PDEVMODEW)*ppEnd; + CopyMemory(*ppEnd, pJob->pDevMode, cbDevMode); - JobInfo2.pDevMode = (PDEVMODEW)pString; - CopyMemory(pString, &pJob->DevMode, sizeof(DEVMODEW)); - pString += sizeof(DEVMODEW); + *ppEnd -= cbDocumentName; + JobInfo2.pDocument = (PWSTR)*ppEnd; + CopyMemory(*ppEnd, pJob->pwszDocumentName, cbDocumentName); - JobInfo2.pDocument = (PWSTR)pString; - CopyMemory(pString, pJob->pwszDocumentName, cbDocumentName); - pString += cbDocumentName; + *ppEnd -= cbDriverName; + JobInfo2.pDriverName = (PWSTR)*ppEnd; + CopyMemory(*ppEnd, pJob->pPrinter->pwszPrinterDriver, cbDriverName); - JobInfo2.pDriverName = (PWSTR)pString; - CopyMemory(pString, pJob->pPrinter->pwszPrinterDriver, cbDriverName); - pString += cbDriverName; + *ppEnd -= cbMachineName; + JobInfo2.pMachineName = (PWSTR)*ppEnd; + CopyMemory(*ppEnd, pJob->pwszMachineName, cbMachineName); - JobInfo2.pMachineName = (PWSTR)pString; - CopyMemory(pString, pJob->pwszMachineName, cbMachineName); - pString += cbMachineName; + *ppEnd -= cbNotifyName; + JobInfo2.pNotifyName = (PWSTR)*ppEnd; + CopyMemory(*ppEnd, pJob->pwszNotifyName, cbNotifyName); - JobInfo2.pNotifyName = (PWSTR)pString; - CopyMemory(pString, pJob->pwszNotifyName, cbNotifyName); - pString += cbNotifyName; + *ppEnd -= cbPrinterName; + JobInfo2.pPrinterName = (PWSTR)*ppEnd; + CopyMemory(*ppEnd, pJob->pPrinter->pwszPrinterName, cbPrinterName); - JobInfo2.pPrinterName = (PWSTR)pString; - CopyMemory(pString, pJob->pPrinter->pwszPrinterName, cbPrinterName); - pString += cbPrinterName; - - JobInfo2.pPrintProcessor = (PWSTR)pString; - CopyMemory(pString, pJob->pPrintProcessor->pwszName, cbPrintProcessor); - pString += cbPrintProcessor; + *ppEnd -= cbPrintProcessor; + JobInfo2.pPrintProcessor = (PWSTR)*ppEnd; + CopyMemory(*ppEnd, pJob->pPrintProcessor->pwszName, cbPrintProcessor); if (cbPrintProcessorParameters) { - JobInfo2.pParameters = (PWSTR)pString; - CopyMemory(pString, pJob->pwszPrintProcessorParameters, cbPrintProcessorParameters); - pString += cbPrintProcessorParameters; + *ppEnd -= cbPrintProcessorParameters; + JobInfo2.pParameters = (PWSTR)*ppEnd; + CopyMemory(*ppEnd, pJob->pwszPrintProcessorParameters, cbPrintProcessorParameters); } if (cbStatus) { - JobInfo2.pStatus = (PWSTR)pString; - CopyMemory(pString, pJob->pwszStatus, cbStatus); - pString += cbStatus; + *ppEnd -= cbStatus; + JobInfo2.pStatus = (PWSTR)*ppEnd; + CopyMemory(*ppEnd, pJob->pwszStatus, cbStatus); } - JobInfo2.pUserName = (PWSTR)pString; - CopyMemory(pString, pJob->pwszUserName, cbUserName); - pString += cbUserName; + *ppEnd -= cbUserName; + JobInfo2.pUserName = (PWSTR)*ppEnd; + CopyMemory(*ppEnd, pJob->pwszUserName, cbUserName); // Time in JOB_INFO_2W is the number of milliseconds elapsed since the job was submitted. Calculate this time. if (!SystemTimeToFileTime(&pJob->stSubmitted, &ftSubmitted)) @@ -553,7 +560,8 @@ _LocalGetJobLevel2(PLOCAL_PRINTER_HANDLE pPrinterHandle, PLOCAL_JOB pJob, PBYTE CopyMemory(&JobInfo2.Submitted, &pJob->stSubmitted, sizeof(SYSTEMTIME)); // Finally copy the structure to the output pointer. - CopyMemory(pOutput, &JobInfo2, sizeof(JOB_INFO_2W)); + CopyMemory(*ppStart, &JobInfo2, sizeof(JOB_INFO_2W)); + *ppStart += sizeof(JOB_INFO_2W); dwErrorCode = ERROR_SUCCESS; Cleanup: @@ -561,16 +569,17 @@ Cleanup: } BOOL WINAPI -LocalGetJob(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pOutput, DWORD cbBuf, LPDWORD pcbNeeded) +LocalGetJob(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pStart, DWORD cbBuf, LPDWORD pcbNeeded) { DWORD dwErrorCode; + PBYTE pEnd = &pStart[cbBuf]; PLOCAL_HANDLE pHandle; PLOCAL_JOB pJob; PLOCAL_PRINTER_HANDLE pPrinterHandle; // Check if this is a printer handle. pHandle = (PLOCAL_HANDLE)hPrinter; - if (pHandle->HandleType != Printer) + if (pHandle->HandleType != HandleType_Printer) { dwErrorCode = ERROR_INVALID_HANDLE; goto Cleanup; @@ -586,11 +595,14 @@ LocalGetJob(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pOutput, DWORD cbBu goto Cleanup; } + // Begin counting. + *pcbNeeded = 0; + // The function behaves differently for each level. if (Level == 1) - dwErrorCode = _LocalGetJobLevel1(pPrinterHandle, pJob, pOutput, cbBuf, pcbNeeded); + dwErrorCode = _LocalGetJobLevel1(pPrinterHandle, pJob, &pStart, &pEnd, cbBuf, pcbNeeded); else if (Level == 2) - dwErrorCode = _LocalGetJobLevel2(pPrinterHandle, pJob, pOutput, cbBuf, pcbNeeded); + dwErrorCode = _LocalGetJobLevel2(pPrinterHandle, pJob, &pStart, &pEnd, cbBuf, pcbNeeded); else dwErrorCode = ERROR_INVALID_LEVEL; @@ -830,14 +842,18 @@ Cleanup: BOOL WINAPI LocalSetJob(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJobInfo, DWORD Command) { + const WCHAR wszFolder[] = L"\\PRINTERS\\"; + const DWORD cchFolder = _countof(wszFolder) - 1; + DWORD dwErrorCode; PLOCAL_HANDLE pHandle; PLOCAL_JOB pJob; PLOCAL_PRINTER_HANDLE pPrinterHandle; + WCHAR wszFullPath[MAX_PATH]; // Check if this is a printer handle. pHandle = (PLOCAL_HANDLE)hPrinter; - if (pHandle->HandleType != Printer) + if (pHandle->HandleType != HandleType_Printer) { dwErrorCode = ERROR_INVALID_HANDLE; goto Cleanup; @@ -867,6 +883,14 @@ LocalSetJob(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJobInfo, DWORD Com if (dwErrorCode != ERROR_SUCCESS) goto Cleanup; + // Construct the full path to the shadow file. + CopyMemory(wszFullPath, wszSpoolDirectory, cchSpoolDirectory * sizeof(WCHAR)); + CopyMemory(&wszFullPath[cchSpoolDirectory], wszFolder, cchFolder * sizeof(WCHAR)); + swprintf(&wszFullPath[cchSpoolDirectory + cchFolder], L"%05lu.SHD", JobId); + + // Write the job data into the shadow file. + WriteJobShadowFile(wszFullPath, pJob); + // Perform an additional command if desired. if (Command) { @@ -880,6 +904,161 @@ Cleanup: return (dwErrorCode == ERROR_SUCCESS); } +BOOL WINAPI +LocalEnumJobs(HANDLE hPrinter, DWORD FirstJob, DWORD NoJobs, DWORD Level, PBYTE pStart, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned) +{ + DWORD dwErrorCode; + DWORD i; + PBYTE pEnd = &pStart[cbBuf]; + PLOCAL_HANDLE pHandle; + PLOCAL_JOB pJob; + PSKIPLIST_NODE pFirstJobNode; + PSKIPLIST_NODE pNode; + PLOCAL_PRINTER_HANDLE pPrinterHandle; + + // Check if this is a printer handle. + pHandle = (PLOCAL_HANDLE)hPrinter; + if (pHandle->HandleType != HandleType_Printer) + { + dwErrorCode = ERROR_INVALID_HANDLE; + goto Cleanup; + } + + pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle; + + // Check the level. + if (Level > 2) + { + dwErrorCode = ERROR_INVALID_LEVEL; + goto Cleanup; + } + + // Begin counting. + *pcbNeeded = 0; + *pcReturned = 0; + + // Lookup the node of the first job requested by the caller in the Printer's Job List. + pFirstJobNode = LookupNodeByIndexSkiplist(&pPrinterHandle->pPrinter->JobList, FirstJob); + + // Count the required buffer size and the number of jobs. + i = 0; + pNode = pFirstJobNode; + + while (i < NoJobs && pNode) + { + pJob = (PLOCAL_JOB)pNode->Element; + + // The function behaves differently for each level. + if (Level == 1) + _LocalGetJobLevel1(pPrinterHandle, pJob, NULL, NULL, 0, pcbNeeded); + else if (Level == 2) + _LocalGetJobLevel2(pPrinterHandle, pJob, NULL, NULL, 0, pcbNeeded); + + // We stop either when there are no more jobs in the list or when the caller didn't request more, whatever comes first. + i++; + pNode = pNode->Next[0]; + } + + // Check if the supplied buffer is large enough. + if (cbBuf < *pcbNeeded) + { + dwErrorCode = ERROR_INSUFFICIENT_BUFFER; + goto Cleanup; + } + + // Begin counting again and also empty the given buffer. + *pcbNeeded = 0; + ZeroMemory(pStart, cbBuf); + + // Now call the same functions again to copy the actual data for each job into the buffer. + i = 0; + pNode = pFirstJobNode; + + while (i < NoJobs && pNode) + { + pJob = (PLOCAL_JOB)pNode->Element; + + // The function behaves differently for each level. + if (Level == 1) + dwErrorCode = _LocalGetJobLevel1(pPrinterHandle, pJob, &pStart, &pEnd, cbBuf, pcbNeeded); + else if (Level == 2) + dwErrorCode = _LocalGetJobLevel2(pPrinterHandle, pJob, &pStart, &pEnd, cbBuf, pcbNeeded); + + if (dwErrorCode != ERROR_SUCCESS) + goto Cleanup; + + // We stop either when there are no more jobs in the list or when the caller didn't request more, whatever comes first. + i++; + pNode = pNode->Next[0]; + } + + *pcReturned = i; + dwErrorCode = ERROR_SUCCESS; + +Cleanup: + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); +} + +BOOL WINAPI +LocalScheduleJob(HANDLE hPrinter, DWORD dwJobID) +{ + const WCHAR wszFolder[] = L"\\PRINTERS\\"; + const DWORD cchFolder = _countof(wszFolder) - 1; + + DWORD dwAttributes; + DWORD dwErrorCode; + PLOCAL_HANDLE pHandle; + PLOCAL_JOB pJob; + PLOCAL_PRINTER_HANDLE pPrinterHandle; + WCHAR wszFullPath[MAX_PATH]; + + // Check if this is a printer handle. + pHandle = (PLOCAL_HANDLE)hPrinter; + if (pHandle->HandleType != HandleType_Printer) + { + dwErrorCode = ERROR_INVALID_HANDLE; + goto Cleanup; + } + + pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle; + + // Check if the Job ID is valid. + pJob = LookupElementSkiplist(&GlobalJobList, &dwJobID, NULL); + if (!pJob || pJob->pPrinter != pPrinterHandle->pPrinter) + { + dwErrorCode = ERROR_INVALID_PARAMETER; + goto Cleanup; + } + + // Construct the full path to the spool file. + CopyMemory(wszFullPath, wszSpoolDirectory, cchSpoolDirectory * sizeof(WCHAR)); + CopyMemory(&wszFullPath[cchSpoolDirectory], wszFolder, cchFolder * sizeof(WCHAR)); + swprintf(&wszFullPath[cchSpoolDirectory + cchFolder], L"%05lu.SPL", dwJobID); + + // Check if it exists. + dwAttributes = GetFileAttributesW(wszFullPath); + if (dwAttributes == INVALID_FILE_ATTRIBUTES || dwAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + dwErrorCode = ERROR_SPOOL_FILE_NOT_FOUND; + goto Cleanup; + } + + // Switch from spooling to printing. + pJob->dwStatus &= ~JOB_STATUS_SPOOLING; + pJob->dwStatus |= JOB_STATUS_PRINTING; + + // Write the job data into the shadow file. + wcscpy(wcsrchr(wszFullPath, L'.'), L".SHD"); + WriteJobShadowFile(wszFullPath, pJob); + + dwErrorCode = ERROR_SUCCESS; + +Cleanup: + SetLastError(dwErrorCode); + return (dwErrorCode == ERROR_SUCCESS); +} + PLOCAL_JOB ReadJobShadowFile(PCWSTR pwszFilePath) { @@ -889,11 +1068,13 @@ ReadJobShadowFile(PCWSTR pwszFilePath) PLOCAL_JOB pJob; PLOCAL_JOB pReturnValue = NULL; PLOCAL_PRINTER pPrinter; + PLOCAL_PRINT_PROCESSOR pPrintProcessor; PSHD_HEADER pShadowFile = NULL; PWSTR pwszPrinterName; + PWSTR pwszPrintProcessor; // Try to open the file. - hFile = CreateFileW(pwszFilePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + hFile = CreateFileW(pwszFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (hFile == INVALID_HANDLE_VALUE) { ERR("CreateFileW failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath); @@ -905,7 +1086,7 @@ ReadJobShadowFile(PCWSTR pwszFilePath) pShadowFile = DllAllocSplMem(cbFileSize); if (!pShadowFile) { - ERR("DllAllocSplMem failed with error %lufor file \"%S\"!\n", GetLastError(), pwszFilePath); + ERR("DllAllocSplMem failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath); goto Cleanup; } @@ -928,7 +1109,16 @@ ReadJobShadowFile(PCWSTR pwszFilePath) pPrinter = LookupElementSkiplist(&PrinterList, &pwszPrinterName, NULL); if (!pPrinter) { - ERR("Shadow file \"%S\" references a non-existing printer!\n", pwszFilePath); + ERR("Shadow file \"%S\" references a non-existing printer \"%S\"!\n", pwszFilePath, pwszPrinterName); + goto Cleanup; + } + + // Retrieve the associated Print Processor from the list. + pwszPrintProcessor = (PWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offPrintProcessor); + pPrintProcessor = FindPrintProcessor(pwszPrintProcessor); + if (!pPrintProcessor) + { + ERR("Shadow file \"%S\" references a non-existing Print Processor \"%S\"!\n", pwszFilePath, pwszPrintProcessor); goto Cleanup; } @@ -941,14 +1131,23 @@ ReadJobShadowFile(PCWSTR pwszFilePath) } pJob->dwJobID = pShadowFile->dwJobID; - pJob->dwTotalPages = pShadowFile->dwTotalPages; pJob->dwPriority = pShadowFile->dwPriority; + pJob->dwStartTime = pShadowFile->dwStartTime; + pJob->dwTotalPages = pShadowFile->dwTotalPages; + pJob->dwUntilTime = pShadowFile->dwUntilTime; pJob->pPrinter = pPrinter; + pJob->pPrintProcessor = pPrintProcessor; + pJob->pDevMode = DuplicateDevMode((PDEVMODEW)((ULONG_PTR)pShadowFile + pShadowFile->offDevMode)); pJob->pwszDatatype = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offDatatype)); pJob->pwszDocumentName = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offDocumentName)); - pJob->pwszOutputFile = NULL; + pJob->pwszMachineName = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offMachineName)); + pJob->pwszNotifyName = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offNotifyName)); + + if (pShadowFile->offPrintProcessorParameters) + pJob->pwszPrintProcessorParameters = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offPrintProcessorParameters)); + + pJob->pwszUserName = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offUserName)); CopyMemory(&pJob->stSubmitted, &pShadowFile->stSubmitted, sizeof(SYSTEMTIME)); - CopyMemory(&pJob->DevMode, (PDEVMODEW)((ULONG_PTR)pShadowFile + pShadowFile->offDevMode), sizeof(DEVMODEW)); pReturnValue = pJob; @@ -963,31 +1162,50 @@ Cleanup: } BOOL -WriteJobShadowFile(PCWSTR pwszFilePath, const PLOCAL_JOB pJob) +WriteJobShadowFile(PWSTR pwszFilePath, const PLOCAL_JOB pJob) { BOOL bReturnValue = FALSE; DWORD cbDatatype; + DWORD cbDevMode; DWORD cbDocumentName; DWORD cbFileSize; + DWORD cbMachineName; + DWORD cbNotifyName; + DWORD cbPrinterDriver; DWORD cbPrinterName; + DWORD cbPrintProcessor; + DWORD cbPrintProcessorParameters = 0; + DWORD cbUserName; DWORD cbWritten; DWORD dwCurrentOffset; - HANDLE hFile = INVALID_HANDLE_VALUE; + HANDLE hSHDFile = INVALID_HANDLE_VALUE; + HANDLE hSPLFile = INVALID_HANDLE_VALUE; PSHD_HEADER pShadowFile = NULL; - // Try to open the file. - hFile = CreateFileW(pwszFilePath, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, 0, NULL); - if (hFile == INVALID_HANDLE_VALUE) + // Try to open the SHD file. + hSHDFile = CreateFileW(pwszFilePath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL); + if (hSHDFile == INVALID_HANDLE_VALUE) { ERR("CreateFileW failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath); goto Cleanup; } // Compute the total size of the shadow file. - cbPrinterName = (wcslen(pJob->pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR); cbDatatype = (wcslen(pJob->pwszDatatype) + 1) * sizeof(WCHAR); + cbDevMode = pJob->pDevMode->dmSize + pJob->pDevMode->dmDriverExtra; cbDocumentName = (wcslen(pJob->pwszDocumentName) + 1) * sizeof(WCHAR); - cbFileSize = sizeof(SHD_HEADER) + cbPrinterName + cbDatatype + cbDocumentName + sizeof(DEVMODEW); + cbMachineName = (wcslen(pJob->pwszMachineName) + 1) * sizeof(WCHAR); + cbNotifyName = (wcslen(pJob->pwszNotifyName) + 1) * sizeof(WCHAR); + cbPrinterDriver = (wcslen(pJob->pPrinter->pwszPrinterDriver) + 1) * sizeof(WCHAR); + cbPrinterName = (wcslen(pJob->pPrinter->pwszPrinterName) + 1) * sizeof(WCHAR); + cbPrintProcessor = (wcslen(pJob->pPrintProcessor->pwszName) + 1) * sizeof(WCHAR); + cbUserName = (wcslen(pJob->pwszUserName) + 1) * sizeof(WCHAR); + + // Print Processor Parameters are optional. + if (pJob->pwszPrintProcessorParameters) + cbPrintProcessorParameters = (wcslen(pJob->pwszPrintProcessorParameters) + 1) * sizeof(WCHAR); + + cbFileSize = sizeof(SHD_HEADER) + cbDatatype + cbDocumentName + cbDevMode + cbMachineName + cbNotifyName + cbPrinterDriver + cbPrinterName + cbPrintProcessor + cbPrintProcessorParameters + cbUserName; // Allocate memory for it. pShadowFile = DllAllocSplMem(cbFileSize); @@ -1003,18 +1221,22 @@ WriteJobShadowFile(PCWSTR pwszFilePath, const PLOCAL_JOB pJob) // Copy the values. pShadowFile->dwJobID = pJob->dwJobID; - pShadowFile->dwTotalPages = pJob->dwTotalPages; pShadowFile->dwPriority = pJob->dwPriority; + pShadowFile->dwStartTime = pJob->dwStartTime; + pShadowFile->dwTotalPages = pJob->dwTotalPages; + pShadowFile->dwUntilTime = pJob->dwUntilTime; CopyMemory(&pShadowFile->stSubmitted, &pJob->stSubmitted, sizeof(SYSTEMTIME)); + // Determine the file size of the .SPL file + wcscpy(wcsrchr(pwszFilePath, L'.'), L".SPL"); + hSPLFile = CreateFileW(pwszFilePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + if (hSPLFile != INVALID_HANDLE_VALUE) + pShadowFile->dwSPLSize = GetFileSize(hSPLFile, NULL); + // Add the extra values that are stored as offsets in the shadow file. // The first value begins right after the shadow file header. dwCurrentOffset = sizeof(SHD_HEADER); - CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pPrinter->pwszPrinterName, cbPrinterName); - pShadowFile->offPrinterName = dwCurrentOffset; - dwCurrentOffset += cbPrinterName; - CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pwszDatatype, cbDatatype); pShadowFile->offDatatype = dwCurrentOffset; dwCurrentOffset += cbDatatype; @@ -1023,12 +1245,44 @@ WriteJobShadowFile(PCWSTR pwszFilePath, const PLOCAL_JOB pJob) pShadowFile->offDocumentName = dwCurrentOffset; dwCurrentOffset += cbDocumentName; - CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, &pJob->DevMode, sizeof(DEVMODEW)); + CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pDevMode, cbDevMode); pShadowFile->offDevMode = dwCurrentOffset; - dwCurrentOffset += sizeof(DEVMODEW); + dwCurrentOffset += cbDevMode; + + // offDriverName is only written, but automatically determined through offPrinterName when reading. + CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pPrinter->pwszPrinterDriver, cbPrinterDriver); + pShadowFile->offDriverName = dwCurrentOffset; + dwCurrentOffset += cbPrinterDriver; + + CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pwszMachineName, cbMachineName); + pShadowFile->offMachineName = dwCurrentOffset; + dwCurrentOffset += cbMachineName; + + CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pwszNotifyName, cbNotifyName); + pShadowFile->offNotifyName = dwCurrentOffset; + dwCurrentOffset += cbNotifyName; + + CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pPrinter->pwszPrinterName, cbPrinterName); + pShadowFile->offPrinterName = dwCurrentOffset; + dwCurrentOffset += cbPrinterName; + + CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pPrintProcessor->pwszName, cbPrintProcessor); + pShadowFile->offPrintProcessor = dwCurrentOffset; + dwCurrentOffset += cbPrintProcessor; + + if (cbPrintProcessorParameters) + { + CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pwszPrintProcessorParameters, cbPrintProcessorParameters); + pShadowFile->offPrintProcessorParameters = dwCurrentOffset; + dwCurrentOffset += cbPrintProcessorParameters; + } + + CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pwszUserName, cbUserName); + pShadowFile->offUserName = dwCurrentOffset; + dwCurrentOffset += cbUserName; // Write the file. - if (!WriteFile(hFile, pShadowFile, cbFileSize, &cbWritten, NULL)) + if (!WriteFile(hSHDFile, pShadowFile, cbFileSize, &cbWritten, NULL)) { ERR("WriteFile failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath); goto Cleanup; @@ -1040,8 +1294,11 @@ Cleanup: if (pShadowFile) DllFreeSplMem(pShadowFile); - if (hFile != INVALID_HANDLE_VALUE) - CloseHandle(hFile); + if (hSHDFile != INVALID_HANDLE_VALUE) + CloseHandle(hSHDFile); + + if (hSPLFile != INVALID_HANDLE_VALUE) + CloseHandle(hSPLFile); return bReturnValue; }