return TRUE;
}
-void
+BOOL
InitializeGlobalJobList()
{
const WCHAR wszPath[] = L"\\PRINTERS\\?????.SHD";
const DWORD cchFolders = sizeof("\\PRINTERS\\") - 1;
const DWORD cchPattern = sizeof("?????") - 1;
+ DWORD dwErrorCode;
DWORD dwJobID;
HANDLE hFind;
PLOCAL_JOB pJob = NULL;
if (hFind == INVALID_HANDLE_VALUE)
{
// No unfinished jobs found.
+ dwErrorCode = ERROR_SUCCESS;
goto Cleanup;
}
// 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;
}
// 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
// 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;
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.
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);
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:
}
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);
FILETIME ftNow;
FILETIME ftSubmitted;
JOB_INFO_2W JobInfo2 = { 0 };
- PBYTE pString;
ULARGE_INTEGER uliNow;
ULARGE_INTEGER uliSubmitted;
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))
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:
}
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;
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;
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;
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)
{
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)
{
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);
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;
}
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;
}
}
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;
}
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);
// 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;
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;
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;
}