From 9be537abb7877b6b2c69be352f69f1a0269533ce Mon Sep 17 00:00:00 2001 From: Colin Finck Date: Fri, 19 Jun 2015 15:21:30 +0000 Subject: [PATCH] [LOCALSPL] - Get rid of the Generic Tables entirely and make use of the new Skiplist for the Global Job List, the Printer's Job List and the Printer List. Use a doubly linked-list for the Print Processors (there won't be many) and just save the information returned from the Print Processor's EnumPrintProcessorDatatypesW instead of putting it in another structure. - Implement LocalAddJob and LocalGetJob (with full JOB_INFO_1W and JOB_INFO_2W support) This makes use of the element index in the new Skiplist implementation to retrieve the position of the job in the list. - Do some changes to LocalStartDocPrinter, though this will make use of LocalAddJob in the future. - Make some global variables static again. svn path=/branches/colins-printing-for-freedom/; revision=68195 --- .../providers/localspl/CMakeLists.txt | 6 +- .../printing/providers/localspl/jobs.c | 514 +++++++++++++++++- .../printing/providers/localspl/main.c | 18 +- .../printing/providers/localspl/precomp.h | 61 ++- .../printing/providers/localspl/printers.c | 158 +++--- .../providers/localspl/printprocessors.c | 148 ++--- .../printing/providers/localspl/tools.c | 22 - 7 files changed, 689 insertions(+), 238 deletions(-) diff --git a/reactos/win32ss/printing/providers/localspl/CMakeLists.txt b/reactos/win32ss/printing/providers/localspl/CMakeLists.txt index 11a52a8cf86..bf2a5420405 100644 --- a/reactos/win32ss/printing/providers/localspl/CMakeLists.txt +++ b/reactos/win32ss/printing/providers/localspl/CMakeLists.txt @@ -1,6 +1,8 @@ spec2def(localspl.dll localspl.spec ADD_IMPORTLIB) +include_directories(${REACTOS_SOURCE_DIR}/lib/skiplist) + list(APPEND SOURCE jobs.c main.c @@ -16,7 +18,7 @@ add_library(localspl SHARED ${CMAKE_CURRENT_BINARY_DIR}/localspl.def) set_module_type(localspl win32dll UNICODE) -target_link_libraries(localspl wine) -add_importlibs(localspl advapi32 spoolss msvcrt kernel32 ntdll) +target_link_libraries(localspl skiplist16 wine) +add_importlibs(localspl advapi32 rpcrt4 spoolss msvcrt kernel32 ntdll) add_pch(localspl precomp.h SOURCE) add_cd_file(TARGET localspl DESTINATION reactos/system32 FOR all) diff --git a/reactos/win32ss/printing/providers/localspl/jobs.c b/reactos/win32ss/printing/providers/localspl/jobs.c index 7cce869c28f..7fa57536a25 100644 --- a/reactos/win32ss/printing/providers/localspl/jobs.c +++ b/reactos/win32ss/printing/providers/localspl/jobs.c @@ -7,10 +7,103 @@ #include "precomp.h" -LIST_ENTRY LocalJobQueue; +// Global Variables +SKIPLIST GlobalJobList; + +// Local Variables +static DWORD _dwLastJobID; + + +/** + * @name _GlobalJobListCompareRoutine + * + * SKIPLIST_COMPARE_ROUTINE for the Global Job List. + * We need the Global Job List to check whether a Job ID is already in use. Consequently, this list is sorted by ID. + */ +static int WINAPI +_GlobalJobListCompareRoutine(PVOID FirstStruct, PVOID SecondStruct) +{ + PLOCAL_JOB A = (PLOCAL_JOB)FirstStruct; + PLOCAL_JOB B = (PLOCAL_JOB)SecondStruct; + + return A->dwJobID - B->dwJobID; +} + +/** + * @name _PrinterJobListCompareRoutine + * + * SKIPLIST_COMPARE_ROUTINE for the each Printer's Job List. + * Jobs in this list are sorted in the desired order of processing. + */ +static int WINAPI +_PrinterJobListCompareRoutine(PVOID FirstStruct, PVOID SecondStruct) +{ + PLOCAL_JOB A = (PLOCAL_JOB)FirstStruct; + PLOCAL_JOB B = (PLOCAL_JOB)SecondStruct; + int iComparison; + FILETIME ftSubmittedA; + FILETIME ftSubmittedB; + ULARGE_INTEGER uliSubmittedA; + ULARGE_INTEGER uliSubmittedB; + ULONGLONG ullResult; + + // First compare the priorities to determine the order. + // The job with a higher priority shall come first. + iComparison = A->dwPriority - B->dwPriority; + if (iComparison != 0) + return iComparison; + + // Both have the same priority, so go by creation time. + // Comparison is done using the MSDN-recommended way for comparing SYSTEMTIMEs. + if (!SystemTimeToFileTime(&A->stSubmitted, &ftSubmittedA)) + { + ERR("SystemTimeToFileTime failed for A with error %lu!\n", GetLastError()); + return 0; + } + + if (!SystemTimeToFileTime(&B->stSubmitted, &ftSubmittedB)) + { + ERR("SystemTimeToFileTime failed for B with error %lu!\n", GetLastError()); + return 0; + } + + uliSubmittedA.LowPart = ftSubmittedA.dwLowDateTime; + uliSubmittedA.HighPart = ftSubmittedA.dwHighDateTime; + uliSubmittedB.LowPart = ftSubmittedB.dwLowDateTime; + uliSubmittedB.HighPart = ftSubmittedB.dwHighDateTime; + ullResult = uliSubmittedA.QuadPart - uliSubmittedB.QuadPart; + + if (ullResult < 0) + return -1; + else if (ullResult > 0) + return 1; + + return 0; +} + +BOOL +GetNextJobID(PDWORD dwJobID) +{ + ++_dwLastJobID; + + while (LookupElementSkiplist(&GlobalJobList, &_dwLastJobID, NULL)) + { + // This ID is already taken. Try the next one. + ++_dwLastJobID; + } + + if (!IS_VALID_JOB_ID(_dwLastJobID)) + { + ERR("Job ID %lu isn't valid!\n", _dwLastJobID); + return FALSE; + } + + *dwJobID = _dwLastJobID; + return TRUE; +} void -InitializeJobQueue() +InitializeGlobalJobList() { const WCHAR wszPath[] = L"\\PRINTERS\\?????.SHD"; const DWORD cchPath = _countof(wszPath) - 1; @@ -19,11 +112,18 @@ InitializeJobQueue() DWORD dwJobID; HANDLE hFind; - PLOCAL_JOB pJob; + PLOCAL_JOB pJob = NULL; PWSTR p; WCHAR wszFullPath[MAX_PATH]; WIN32_FIND_DATAW FindData; + // This one is incremented in GetNextJobID. + _dwLastJobID = 0; + + // Initialize an empty list for all jobs of all local printers. + // We will search it by Job ID (supply a pointer to a DWORD in LookupElementSkiplist). + InitializeSkiplist(&GlobalJobList, DllAllocSplMem, _GlobalJobListCompareRoutine, (PSKIPLIST_FREE_ROUTINE)DllFreeSplMem); + // Construct the full path search pattern. CopyMemory(wszFullPath, wszSpoolDirectory, cchSpoolDirectory * sizeof(WCHAR)); CopyMemory(&wszFullPath[cchSpoolDirectory], wszPath, (cchPath + 1) * sizeof(WCHAR)); @@ -33,7 +133,7 @@ InitializeJobQueue() if (hFind == INVALID_HANDLE_VALUE) { // No unfinished jobs found. - return; + goto Cleanup; } do @@ -56,12 +156,368 @@ InitializeJobQueue() if (!pJob) continue; - // Add it to the job queue of the respective printer. - InsertTailList(&pJob->Printer->JobQueue, &pJob->Entry); + // Add it to the Global Job List. + if (!InsertElementSkiplist(&GlobalJobList, pJob)) + { + 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->Printer->JobList, pJob)) + { + ERR("InsertElementSkiplist failed for job %lu for the Printer's Job List!\n", pJob->dwJobID); + goto Cleanup; + } } while (FindNextFileW(hFind, &FindData)); - FindClose(hFind); +Cleanup: + // Outside the loop + if (hFind) + FindClose(hFind); +} + +void +InitializePrinterJobList(PLOCAL_PRINTER pPrinter) +{ + // Initialize an empty list for this printer's jobs. + // This one is only for sorting the jobs. If you need to lookup a job, search the GlobalJobList by Job ID. + InitializeSkiplist(&pPrinter->JobList, DllAllocSplMem, _PrinterJobListCompareRoutine, (PSKIPLIST_FREE_ROUTINE)DllFreeSplMem); +} + +BOOL WINAPI +LocalAddJob(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded) +{ + const WCHAR wszDoubleBackslash[] = L"\\"; + const DWORD cchDoubleBackslash = _countof(wszDoubleBackslash) - 1; + const WCHAR wszPrintersPath[] = L"\\PRINTERS\\"; + const DWORD cchPrintersPath = _countof(wszPrintersPath) - 1; + const DWORD cchSpl = _countof("?????.SPL") - 1; + + ADDJOB_INFO_1W AddJobInfo1; + BOOL bReturnValue = FALSE; + DWORD cchMachineName; + DWORD cchUserName; + PBYTE p; + PLOCAL_HANDLE pHandle; + PLOCAL_JOB pJob; + PLOCAL_PRINTER_HANDLE pPrinterHandle; + RPC_BINDING_HANDLE hServerBinding = NULL; + RPC_STATUS Status; + RPC_WSTR pwszBinding = NULL; + RPC_WSTR pwszMachineName = NULL; + + // Check if this is a printer handle. + pHandle = (PLOCAL_HANDLE)hPrinter; + if (pHandle->HandleType != Printer) + goto Cleanup; + + pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->SpecificHandle; + + // Check if this is the right structure level. + if (Level != 1) + goto Cleanup; + + // FIXME: This needs to fail if the printer is set to do direct printing. + + // Check if the supplied buffer is large enough. + *pcbNeeded = sizeof(ADDJOB_INFO_1W) + (cchSpoolDirectory + cchPrintersPath + cchSpl + 1) * sizeof(WCHAR); + if (cbBuf < *pcbNeeded) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + goto Cleanup; + } + + // Create a new job. + pJob = DllAllocSplMem(sizeof(LOCAL_JOB)); + if (!pJob) + { + ERR("DllAllocSplMem failed with error %lu!\n", GetLastError()); + goto Cleanup; + } + + // Reserve an ID for this job. + if (!GetNextJobID(&pJob->dwJobID)) + goto Cleanup; + + // Copy over defaults to the LOCAL_JOB structure. + pJob->Printer = pPrinterHandle->Printer; + pJob->dwPriority = DEF_PRIORITY; + pJob->pwszDatatype = AllocSplStr(pPrinterHandle->pwszDatatype); + pJob->pwszDocumentName = AllocSplStr(wszDefaultDocumentName); + CopyMemory(&pJob->DevMode, &pPrinterHandle->DevMode, sizeof(DEVMODEW)); + GetSystemTime(&pJob->stSubmitted); + + // Get the user name for the Job. + cchUserName = UNLEN + 1; + pJob->pwszUserName = DllAllocSplMem(cchUserName * sizeof(WCHAR)); + if (!GetUserNameW(pJob->pwszUserName, &cchUserName)) + { + ERR("GetUserNameW failed with error %lu!\n", GetLastError()); + goto Cleanup; + } + + // FIXME: For now, pwszNotifyName equals pwszUserName. + pJob->pwszNotifyName = AllocSplStr(pJob->pwszUserName); + + // Get the name of the machine that submitted the Job over RPC. + Status = RpcBindingServerFromClient(NULL, &hServerBinding); + if (Status != RPC_S_OK) + { + ERR("RpcBindingServerFromClient failed with status %lu!\n", Status); + goto Cleanup; + } + + Status = RpcBindingToStringBindingW(hServerBinding, &pwszBinding); + if (Status != RPC_S_OK) + { + ERR("RpcBindingToStringBindingW failed with status %lu!\n", Status); + goto Cleanup; + } + + Status = RpcStringBindingParseW(pwszBinding, NULL, NULL, &pwszMachineName, NULL, NULL); + if (Status != RPC_S_OK) + { + ERR("RpcStringBindingParseW failed with status %lu!\n", Status); + goto Cleanup; + } + + cchMachineName = wcslen(pwszMachineName); + pJob->pwszMachineName = DllAllocSplMem((cchMachineName + cchDoubleBackslash + 1) * sizeof(WCHAR)); + CopyMemory(pJob->pwszMachineName, wszDoubleBackslash, cchDoubleBackslash * sizeof(WCHAR)); + CopyMemory(pJob->pwszMachineName + cchDoubleBackslash, pwszMachineName, (cchMachineName + 1) * sizeof(WCHAR)); + + // Add the job to the Global Job List. + if (!InsertElementSkiplist(&GlobalJobList, pJob)) + { + ERR("InsertElementSkiplist failed for job %lu for the GlobalJobList!\n", pJob->dwJobID); + goto Cleanup; + } + + // Add the job at the end of the Printer's Job List. + // As all new jobs are created with default priority, we can be sure that it would always be inserted at the end. + if (!InsertTailElementSkiplist(&pJob->Printer->JobList, pJob)) + { + ERR("InsertTailElementSkiplist failed for job %lu for the Printer's Job List!\n", pJob->dwJobID); + goto Cleanup; + } + + // Return a proper ADDJOB_INFO_1W structure. + AddJobInfo1.JobId = pJob->dwJobID; + AddJobInfo1.Path = (PWSTR)(pData + sizeof(ADDJOB_INFO_1W)); + p = pData; + CopyMemory(p, &AddJobInfo1, sizeof(ADDJOB_INFO_1W)); + p += sizeof(ADDJOB_INFO_1W); + CopyMemory(p, wszSpoolDirectory, cchSpoolDirectory); + p += cchSpoolDirectory; + CopyMemory(p, wszPrintersPath, cchPrintersPath); + p += cchPrintersPath; + swprintf((PWSTR)p, L"%05lu.SPL", pJob->dwJobID); + + bReturnValue = TRUE; + +Cleanup: + if (pwszMachineName) + RpcStringFreeW(&pwszMachineName); + + if (pwszBinding) + RpcStringFreeW(&pwszBinding); + + if (hServerBinding) + RpcBindingFree(&hServerBinding); + + return bReturnValue; +} + + +static BOOL +_LocalGetJobLevel1(PLOCAL_PRINTER_HANDLE pPrinterHandle, PLOCAL_JOB pJob, PBYTE pOutput, DWORD cbBuf, PDWORD pcbNeeded) +{ + DWORD cbDatatype = (wcslen(pJob->pwszDatatype) + 1) * sizeof(WCHAR); + DWORD cbDocumentName = (wcslen(pJob->pwszDocumentName) + 1) * sizeof(WCHAR); + DWORD cbMachineName = (wcslen(pJob->pwszMachineName) + 1) * sizeof(WCHAR); + DWORD cbPrinterName = (wcslen(pJob->Printer->pwszPrinterName) + 1) * sizeof(WCHAR); + DWORD cbUserName = (wcslen(pJob->pwszUserName) + 1) * sizeof(WCHAR); + JOB_INFO_1W JobInfo1 = { 0 }; + PBYTE pString; + + // Check if the supplied buffer is large enough. + *pcbNeeded = sizeof(JOB_INFO_1W) + cbDatatype + cbDocumentName + cbMachineName + cbPrinterName + cbUserName; + if (cbBuf < *pcbNeeded) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + // Put the strings right after the JOB_INFO_1W structure. + pString = pOutput + sizeof(JOB_INFO_1W); + + JobInfo1.pDatatype = (PWSTR)pString; + CopyMemory(pString, pJob->pwszDatatype, cbDatatype); + pString += cbDatatype; + + JobInfo1.pDocument = (PWSTR)pString; + CopyMemory(pString, pJob->pwszDocumentName, cbDocumentName); + pString += cbDocumentName; + + JobInfo1.pMachineName = (PWSTR)pString; + CopyMemory(pString, pJob->pwszMachineName, cbMachineName); + pString += cbMachineName; + + JobInfo1.pPrinterName = (PWSTR)pString; + CopyMemory(pString, pJob->Printer->pwszPrinterName, cbPrinterName); + pString += cbPrinterName; + + JobInfo1.pUserName = (PWSTR)pString; + CopyMemory(pString, pJob->pwszUserName, cbUserName); + pString += cbUserName; + + // Fill the structure and copy it as well. + 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)); + + return TRUE; +} + +static BOOL +_LocalGetJobLevel2(PLOCAL_PRINTER_HANDLE pPrinterHandle, PLOCAL_JOB pJob, PBYTE pOutput, DWORD cbBuf, PDWORD pcbNeeded) +{ + DWORD cbDatatype = (wcslen(pJob->pwszDatatype) + 1) * sizeof(WCHAR); + DWORD cbDocumentName = (wcslen(pJob->pwszDocumentName) + 1) * sizeof(WCHAR); + DWORD cbDriverName = (wcslen(pJob->Printer->pwszPrinterDriver) + 1) * sizeof(WCHAR); + DWORD cbMachineName = (wcslen(pJob->pwszMachineName) + 1) * sizeof(WCHAR); + DWORD cbNotifyName = (wcslen(pJob->pwszNotifyName) + 1) * sizeof(WCHAR); + DWORD cbPrinterName = (wcslen(pJob->Printer->pwszPrinterName) + 1) * sizeof(WCHAR); + DWORD cbPrintProcessor = (wcslen(pJob->Printer->pPrintProcessor->pwszName) + 1) * sizeof(WCHAR); + DWORD cbUserName = (wcslen(pJob->pwszUserName) + 1) * sizeof(WCHAR); + FILETIME ftNow; + FILETIME ftSubmitted; + JOB_INFO_2W JobInfo2 = { 0 }; + PBYTE pString; + ULARGE_INTEGER uliNow; + ULARGE_INTEGER uliSubmitted; + + // Check if the supplied buffer is large enough. + *pcbNeeded = sizeof(JOB_INFO_2W) + cbDatatype + sizeof(DEVMODEW) + cbDocumentName + cbDriverName + cbMachineName + cbNotifyName + cbPrinterName + cbPrintProcessor + cbUserName; + if (cbBuf < *pcbNeeded) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + return FALSE; + } + + // Put the strings right after the JOB_INFO_2W structure. + pString = pOutput + sizeof(JOB_INFO_2W); + + JobInfo2.pDatatype = (PWSTR)pString; + CopyMemory(pString, pJob->pwszDatatype, cbDatatype); + pString += cbDatatype; + + JobInfo2.pDevMode = (PDEVMODEW)pString; + CopyMemory(pString, &pJob->DevMode, sizeof(DEVMODEW)); + pString += sizeof(DEVMODEW); + + JobInfo2.pDocument = (PWSTR)pString; + CopyMemory(pString, pJob->pwszDocumentName, cbDocumentName); + pString += cbDocumentName; + + JobInfo2.pDriverName = (PWSTR)pString; + CopyMemory(pString, pJob->Printer->pwszPrinterDriver, cbDriverName); + pString += cbDriverName; + + JobInfo2.pMachineName = (PWSTR)pString; + CopyMemory(pString, pJob->pwszMachineName, cbMachineName); + pString += cbMachineName; + + JobInfo2.pNotifyName = (PWSTR)pString; + CopyMemory(pString, pJob->pwszNotifyName, cbNotifyName); + pString += cbNotifyName; + + JobInfo2.pPrinterName = (PWSTR)pString; + CopyMemory(pString, pJob->Printer->pwszPrinterName, cbPrinterName); + pString += cbPrinterName; + + JobInfo2.pPrintProcessor = (PWSTR)pString; + CopyMemory(pString, pJob->Printer->pPrintProcessor->pwszName, cbPrintProcessor); + pString += cbPrintProcessor; + + JobInfo2.pUserName = (PWSTR)pString; + CopyMemory(pString, pJob->pwszUserName, cbUserName); + pString += 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)) + { + ERR("SystemTimeToFileTime failed with error %lu!\n", GetLastError()); + return FALSE; + } + + GetSystemTimeAsFileTime(&ftNow); + uliSubmitted.LowPart = ftSubmitted.dwLowDateTime; + uliSubmitted.HighPart = ftSubmitted.dwHighDateTime; + uliNow.LowPart = ftNow.dwLowDateTime; + uliNow.HighPart = ftNow.dwHighDateTime; + JobInfo2.Time = (DWORD)((uliNow.QuadPart - uliSubmitted.QuadPart) / 10000); + + // Position in JOB_INFO_2W is the 1-based index of the job in the processing queue. + // Retrieve this through the element index of the job in the Printer's Job List. + if (!LookupElementSkiplist(&pJob->Printer->JobList, pJob, &JobInfo2.Position)) + { + ERR("pJob could not be located in the Printer's Job List!\n"); + return FALSE; + } + + // Make the index 1-based. + ++JobInfo2.Position; + + // Fill the rest of the structure. + JobInfo2.JobId = pJob->dwJobID; + JobInfo2.PagesPrinted = pJob->dwPagesPrinted; + JobInfo2.Priority = pJob->dwPriority; + JobInfo2.StartTime = pJob->dwStartTime; + JobInfo2.Status = pJob->dwStatus; + JobInfo2.TotalPages = pJob->dwTotalPages; + JobInfo2.UntilTime = pJob->dwUntilTime; + CopyMemory(&JobInfo2.Submitted, &pJob->stSubmitted, sizeof(SYSTEMTIME)); + + // Finally copy the structure to the output pointer. + CopyMemory(pOutput, &JobInfo2, sizeof(JOB_INFO_2W)); + return TRUE; +} + +BOOL WINAPI +LocalGetJob(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pOutput, DWORD cbBuf, LPDWORD pcbNeeded) +{ + 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) + return FALSE; + + pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->SpecificHandle; + + // Get the desired job. + pJob = LookupElementSkiplist(&GlobalJobList, &JobId, NULL); + if (!pJob || pJob->Printer != pPrinterHandle->Printer) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + // The function behaves differently for each level. + if (Level == 1) + return _LocalGetJobLevel1(pPrinterHandle, pJob, pOutput, cbBuf, pcbNeeded); + else if (Level == 2) + return _LocalGetJobLevel2(pPrinterHandle, pJob, pOutput, cbBuf, pcbNeeded); + + return FALSE; } PLOCAL_JOB @@ -80,7 +536,7 @@ ReadJobShadowFile(PCWSTR pwszFilePath) hFile = CreateFileW(pwszFilePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); if (hFile == INVALID_HANDLE_VALUE) { - ERR("CreateFileW failed with error %lu!\n", GetLastError()); + ERR("CreateFileW failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath); goto Cleanup; } @@ -89,30 +545,30 @@ ReadJobShadowFile(PCWSTR pwszFilePath) pShadowFile = DllAllocSplMem(cbFileSize); if (!pShadowFile) { - ERR("DllAllocSplMem failed with error %lu!\n", GetLastError()); + ERR("DllAllocSplMem failed with error %lufor file \"%S\"!\n", GetLastError(), pwszFilePath); goto Cleanup; } // Read the entire file. if (!ReadFile(hFile, pShadowFile, cbFileSize, &cbRead, NULL)) { - ERR("ReadFile failed with error %lu!\n", GetLastError()); + ERR("ReadFile failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath); goto Cleanup; } // Check signature and header size. if (pShadowFile->dwSignature != SHD_WIN2003_SIGNATURE || pShadowFile->cbHeader != sizeof(SHD_HEADER)) { - ERR("Signature or Header Size mismatch!\n"); + ERR("Signature or Header Size mismatch for file \"%S\"!\n", pwszFilePath); goto Cleanup; } - // Retrieve the associated printer from the table. + // Retrieve the associated printer from the list. pwszPrinterName = (PWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offPrinterName); - pPrinter = RtlLookupElementGenericTable(&PrinterTable, pwszPrinterName); + pPrinter = LookupElementSkiplist(&PrinterList, &pwszPrinterName, NULL); if (!pPrinter) { - ERR("This shadow file references a non-existing printer!\n"); + ERR("Shadow file \"%S\" references a non-existing printer!\n", pwszFilePath); goto Cleanup; } @@ -120,15 +576,18 @@ ReadJobShadowFile(PCWSTR pwszFilePath) pJob = DllAllocSplMem(sizeof(LOCAL_JOB)); if (!pJob) { - ERR("DllAllocSplMem failed with error %lu!\n", GetLastError()); + ERR("DllAllocSplMem failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath); goto Cleanup; } pJob->dwJobID = pShadowFile->dwJobID; + pJob->dwTotalPages = pShadowFile->dwTotalPages; + pJob->dwPriority = pShadowFile->dwPriority; pJob->Printer = pPrinter; pJob->pwszDatatype = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offDatatype)); pJob->pwszDocumentName = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offDocumentName)); pJob->pwszOutputFile = NULL; + CopyMemory(&pJob->stSubmitted, &pShadowFile->stSubmitted, sizeof(SYSTEMTIME)); CopyMemory(&pJob->DevMode, (PDEVMODEW)((ULONG_PTR)pShadowFile + pShadowFile->offDevMode), sizeof(DEVMODEW)); pReturnValue = pJob; @@ -160,33 +619,42 @@ WriteJobShadowFile(PCWSTR pwszFilePath, const PLOCAL_JOB pJob) hFile = CreateFileW(pwszFilePath, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, 0, NULL); if (hFile == INVALID_HANDLE_VALUE) { - ERR("CreateFileW failed with error %lu!\n", GetLastError()); + 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->Printer->pwszPrinterName) + 1) * sizeof(WCHAR); cbDatatype = (wcslen(pJob->pwszDatatype) + 1) * sizeof(WCHAR); cbDocumentName = (wcslen(pJob->pwszDocumentName) + 1) * sizeof(WCHAR); - cbPrinterName = (wcslen(pJob->Printer->pwszPrinterName) + 1) * sizeof(WCHAR); - cbFileSize = sizeof(SHD_HEADER) + cbDatatype + cbDocumentName + cbPrinterName; + cbFileSize = sizeof(SHD_HEADER) + cbPrinterName + cbDatatype + cbDocumentName + sizeof(DEVMODEW); // Allocate memory for it. pShadowFile = DllAllocSplMem(cbFileSize); if (!pShadowFile) { - ERR("DllAllocSplMem failed with error %lu!\n", GetLastError()); + ERR("DllAllocSplMem failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath); goto Cleanup; } // Fill out the shadow file header information. pShadowFile->dwSignature = SHD_WIN2003_SIGNATURE; pShadowFile->cbHeader = sizeof(SHD_HEADER); + + // Copy the values. pShadowFile->dwJobID = pJob->dwJobID; + pShadowFile->dwTotalPages = pJob->dwTotalPages; + pShadowFile->dwPriority = pJob->dwPriority; + CopyMemory(&pShadowFile->stSubmitted, &pJob->stSubmitted, sizeof(SYSTEMTIME)); // 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->Printer->pwszPrinterName, cbPrinterName); + pShadowFile->offPrinterName = dwCurrentOffset; + dwCurrentOffset += cbPrinterName; + CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pwszDatatype, cbDatatype); pShadowFile->offDatatype = dwCurrentOffset; dwCurrentOffset += cbDatatype; @@ -195,14 +663,14 @@ WriteJobShadowFile(PCWSTR pwszFilePath, const PLOCAL_JOB pJob) pShadowFile->offDocumentName = dwCurrentOffset; dwCurrentOffset += cbDocumentName; - CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->Printer->pwszPrinterName, cbPrinterName); - pShadowFile->offPrinterName = dwCurrentOffset; - dwCurrentOffset += cbPrinterName; + CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, &pJob->DevMode, sizeof(DEVMODEW)); + pShadowFile->offDevMode = dwCurrentOffset; + dwCurrentOffset += sizeof(DEVMODEW); // Write the file. if (!WriteFile(hFile, pShadowFile, cbFileSize, &cbWritten, NULL)) { - ERR("WriteFile failed with error %lu!\n", GetLastError()); + ERR("WriteFile failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath); goto Cleanup; } diff --git a/reactos/win32ss/printing/providers/localspl/main.c b/reactos/win32ss/printing/providers/localspl/main.c index 2565b1c27d4..4ede442d30d 100644 --- a/reactos/win32ss/printing/providers/localspl/main.c +++ b/reactos/win32ss/printing/providers/localspl/main.c @@ -11,7 +11,7 @@ WCHAR wszSpoolDirectory[MAX_PATH]; DWORD cchSpoolDirectory; -// Constants +// Global Constants const WCHAR wszCurrentEnvironment[] = #if defined(_X86_) L"Windows NT x86"; @@ -23,16 +23,19 @@ const WCHAR wszCurrentEnvironment[] = #error Unsupported architecture #endif +const WCHAR wszDefaultDocumentName[] = L"Local Downlevel Document"; + const WCHAR* wszPrintProviderInfo[3] = { L"Windows NT Local Print Providor", // Name L"Windows NT Local Printers", // Description L"Locally connected Printers" // Comment }; -static const PRINTPROVIDOR PrintProviderFunctions = { +// Local Constants +static const PRINTPROVIDOR _PrintProviderFunctions = { LocalOpenPrinter, // fpOpenPrinter NULL, // fpSetJob - NULL, // fpGetJob + LocalGetJob, // fpGetJob NULL, // fpEnumJobs NULL, // fpAddPrinter NULL, // fpDeletePrinter @@ -56,7 +59,7 @@ static const PRINTPROVIDOR PrintProviderFunctions = { NULL, // fpAbortPrinter NULL, // fpReadPrinter LocalEndDocPrinter, // fpEndDocPrinter - NULL, // fpAddJob + LocalAddJob, // fpAddJob NULL, // fpScheduleJob NULL, // fpGetPrinterData NULL, // fpSetPrinterData @@ -139,8 +142,9 @@ DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hinstDLL); _GetSpoolDirectory(); - InitializePrintProcessorTable(); - InitializePrinterTable(); + InitializePrintProcessorList(); + InitializePrinterList(); + InitializeGlobalJobList(); break; } @@ -150,7 +154,7 @@ DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) BOOL WINAPI InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor, DWORD cbPrintProvidor, LPWSTR pFullRegistryPath) { - CopyMemory(pPrintProvidor, &PrintProviderFunctions, min(cbPrintProvidor, sizeof(PRINTPROVIDOR))); + CopyMemory(pPrintProvidor, &_PrintProviderFunctions, min(cbPrintProvidor, sizeof(PRINTPROVIDOR))); return TRUE; } diff --git a/reactos/win32ss/printing/providers/localspl/precomp.h b/reactos/win32ss/printing/providers/localspl/precomp.h index cb08315bbb3..d45edfb6684 100644 --- a/reactos/win32ss/printing/providers/localspl/precomp.h +++ b/reactos/win32ss/printing/providers/localspl/precomp.h @@ -13,6 +13,8 @@ #include #include +#include +#include #include #include #include @@ -21,6 +23,8 @@ #include #include +#define SKIPLIST_LEVELS 16 +#include #include #include @@ -47,8 +51,10 @@ typedef BOOL (WINAPI *PPrintDocumentOnPrintProcessor)(HANDLE, LPWSTR); */ typedef struct _LOCAL_PRINT_PROCESSOR { + LIST_ENTRY Entry; PWSTR pwszName; - RTL_GENERIC_TABLE DatatypeTable; + PDATATYPES_INFO_1W pDatatypesInfo1; + DWORD dwDatatypeCount; PClosePrintProcessor pfnClosePrintProcessor; PControlPrintProcessor pfnControlPrintProcessor; PEnumPrintProcessorDatatypesW pfnEnumPrintProcessorDatatypesW; @@ -64,13 +70,15 @@ LOCAL_PRINT_PROCESSOR, *PLOCAL_PRINT_PROCESSOR; */ typedef struct _LOCAL_PRINTER { + // This sort key must be the first element for LookupElementSkiplist to work! PWSTR pwszPrinterName; + PWSTR pwszPrinterDriver; PWSTR pwszDescription; PWSTR pwszDefaultDatatype; DEVMODEW DefaultDevMode; PLOCAL_PRINT_PROCESSOR pPrintProcessor; - LIST_ENTRY JobQueue; + SKIPLIST JobList; } LOCAL_PRINTER, *PLOCAL_PRINTER; @@ -80,13 +88,24 @@ LOCAL_PRINTER, *PLOCAL_PRINTER; */ typedef struct _LOCAL_JOB { - LIST_ENTRY Entry; - PLOCAL_PRINTER Printer; - DWORD dwJobID; - PWSTR pwszDocumentName; - PWSTR pwszDatatype; - PWSTR pwszOutputFile; - DEVMODEW DevMode; + // This sort key must be the first element for LookupElementSkiplist to work! + DWORD dwJobID; // Internal and external ID of this Job + + PLOCAL_PRINTER Printer; // Associated Printer to this Job + DWORD dwPriority; // Priority of this Job from MIN_PRIORITY to MAX_PRIORITY, default being DEF_PRIORITY + SYSTEMTIME stSubmitted; // Time of the submission of this Job + PWSTR pwszUserName; // User that submitted the Job + PWSTR pwszNotifyName; // User that shall be notified about the status of the Job + PWSTR pwszDocumentName; // Name of the Document that is printed + PWSTR pwszDatatype; // Datatype of the Document + PWSTR pwszOutputFile; // Output File to spool the Job to + DWORD dwTotalPages; // Total pages of the Document + DWORD dwPagesPrinted; // Number of pages that have already been printed + DWORD dwStartTime; // Earliest time in minutes since 12:00 AM UTC when this document can be printed + DWORD dwUntilTime; // Latest time in minutes since 12:00 AM UTC when this document can be printed + DWORD dwStatus; // JOB_STATUS_* flags of the Job + PWSTR pwszMachineName; // Name of the machine that submitted the Job (prepended with two backslashes) + DEVMODEW DevMode; // Associated Device Mode to this Job } LOCAL_JOB, *PLOCAL_JOB; @@ -140,35 +159,42 @@ typedef struct _SHD_HEADER DWORD offPrintProcessor; DWORD offDatatype; DWORD dwUnknown2; - SYSTEMTIME stSubmitTime; + SYSTEMTIME stSubmitted; DWORD dwStartTime; DWORD dwUntilTime; DWORD dwUnknown6; - DWORD dwPageCount; + DWORD dwTotalPages; DWORD cbSecurityDescriptor; DWORD offSecurityDescriptor; DWORD dwUnknown3; DWORD dwUnknown4; DWORD dwUnknown5; - DWORD offComputerName; + DWORD offMachineName; DWORD dwSPLSize; } SHD_HEADER, *PSHD_HEADER; // jobs.c +extern SKIPLIST GlobalJobList; +BOOL GetNextJobID(PDWORD dwJobID); +void InitializeGlobalJobList(); +void InitializePrinterJobList(PLOCAL_PRINTER pPrinter); +BOOL WINAPI LocalAddJob(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded); +BOOL WINAPI LocalGetJob(HANDLE hPrinter, DWORD JobId, DWORD Level, LPBYTE pOutput, DWORD cbBuf, LPDWORD pcbNeeded); PLOCAL_JOB ReadJobShadowFile(PCWSTR pwszFilePath); BOOL WriteJobShadowFile(PCWSTR pwszFilePath, const PLOCAL_JOB pJob); // main.c extern const WCHAR wszCurrentEnvironment[]; +extern const WCHAR wszDefaultDocumentName[]; extern const WCHAR* wszPrintProviderInfo[3]; extern WCHAR wszSpoolDirectory[MAX_PATH]; extern DWORD cchSpoolDirectory; // printers.c -extern RTL_GENERIC_TABLE PrinterTable; -void InitializePrinterTable(); +extern SKIPLIST PrinterList; +void InitializePrinterList(); BOOL WINAPI LocalEnumPrinters(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned); BOOL WINAPI LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDefault); DWORD WINAPI LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo); @@ -179,15 +205,14 @@ BOOL WINAPI LocalEndDocPrinter(HANDLE hPrinter); BOOL WINAPI LocalClosePrinter(HANDLE hPrinter); // printprocessors.c -extern RTL_GENERIC_TABLE PrintProcessorTable; -void InitializePrintProcessorTable(); +BOOL FindDatatype(PLOCAL_PRINT_PROCESSOR pPrintProcessor, PWSTR pwszDatatype); +PLOCAL_PRINT_PROCESSOR FindPrintProcessor(PWSTR pwszName); +void InitializePrintProcessorList(); BOOL WINAPI LocalEnumPrintProcessorDatatypes(LPWSTR pName, LPWSTR pPrintProcessorName, DWORD Level, LPBYTE pDatatypes, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned); BOOL WINAPI LocalEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned); BOOL WINAPI LocalGetPrintProcessorDirectory(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded); // tools.c PWSTR AllocAndRegQueryWSZ(HKEY hKey, PCWSTR pwszValueName); -PVOID NTAPI GenericTableAllocateRoutine(PRTL_GENERIC_TABLE Table, CLONG ByteSize); -VOID NTAPI GenericTableFreeRoutine(PRTL_GENERIC_TABLE Table, PVOID Buffer); #endif diff --git a/reactos/win32ss/printing/providers/localspl/printers.c b/reactos/win32ss/printing/providers/localspl/printers.c index 4d8891c3ff3..8a8d6162f96 100644 --- a/reactos/win32ss/printing/providers/localspl/printers.c +++ b/reactos/win32ss/printing/providers/localspl/printers.c @@ -8,40 +8,33 @@ #include "precomp.h" // Global Variables -RTL_GENERIC_TABLE PrinterTable; +SKIPLIST PrinterList; /** - * @name _PrinterTableCompareRoutine + * @name _PrinterListCompareRoutine * - * RTL_GENERIC_COMPARE_ROUTINE for the Printer Table. + * SKIPLIST_COMPARE_ROUTINE for the Printer List. * Does a case-insensitive comparison, because e.g. LocalOpenPrinter doesn't match the case when looking for Printers. */ -static RTL_GENERIC_COMPARE_RESULTS NTAPI -_PrinterTableCompareRoutine(PRTL_GENERIC_TABLE Table, PVOID FirstStruct, PVOID SecondStruct) +static int WINAPI +_PrinterListCompareRoutine(PVOID FirstStruct, PVOID SecondStruct) { PLOCAL_PRINTER A = (PLOCAL_PRINTER)FirstStruct; PLOCAL_PRINTER B = (PLOCAL_PRINTER)SecondStruct; - int iResult = wcsicmp(A->pwszPrinterName, B->pwszPrinterName); - - if (iResult < 0) - return GenericLessThan; - else if (iResult > 0) - return GenericGreaterThan; - else - return GenericEqual; + return wcsicmp(A->pwszPrinterName, B->pwszPrinterName); } /** - * @name InitializePrinterTable + * @name InitializePrinterList * - * Initializes a RTL_GENERIC_TABLE of locally available Printers. - * The table is searchable by name and returns information about the printers, including their job queues. + * Initializes a list of locally available Printers. + * The list is searchable by name and returns information about the printers, including their job queues. * During this process, the job queues are also initialized. */ void -InitializePrinterTable() +InitializePrinterList() { const WCHAR wszPrintersKey[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Printers"; @@ -52,14 +45,13 @@ InitializePrinterTable() HKEY hKey = NULL; HKEY hSubKey = NULL; LONG lStatus; - PLOCAL_PRINT_PROCESSOR pPrintProcessor; PLOCAL_PRINTER pPrinter = NULL; + PLOCAL_PRINT_PROCESSOR pPrintProcessor; PWSTR pwszPrintProcessor = NULL; WCHAR wszPrinterName[MAX_PRINTER_NAME + 1]; - // Initialize an empty table for our printers. - // We will search it by printer name. - RtlInitializeGenericTable(&PrinterTable, _PrinterTableCompareRoutine, GenericTableAllocateRoutine, GenericTableFreeRoutine, NULL); + // Initialize an empty list for our printers. + InitializeSkiplist(&PrinterList, DllAllocSplMem, _PrinterListCompareRoutine, (PSKIPLIST_FREE_ROUTINE)DllFreeSplMem); // Open our printers registry key. Each subkey is a local printer there. lStatus = RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszPrintersKey, 0, KEY_READ, &hKey); @@ -92,6 +84,15 @@ InitializePrinterTable() if (pPrinter->pwszDefaultDatatype) DllFreeSplStr(pPrinter->pwszDefaultDatatype); + if (pPrinter->pwszDescription) + DllFreeSplStr(pPrinter->pwszDescription); + + if (pPrinter->pwszPrinterDriver) + DllFreeSplStr(pPrinter->pwszPrinterDriver); + + if (pPrinter->pwszPrinterName) + DllFreeSplStr(pPrinter->pwszPrinterName); + DllFreeSplMem(pPrinter); pPrinter = NULL; } @@ -129,8 +130,8 @@ InitializePrinterTable() if (!pwszPrintProcessor) continue; - // Try to find it in the Print Processor Table. - pPrintProcessor = RtlLookupElementGenericTable(&PrintProcessorTable, pwszPrintProcessor); + // Try to find it in the Print Processor List. + pPrintProcessor = FindPrintProcessor(pwszPrintProcessor); if (!pPrintProcessor) { ERR("Invalid Print Processor \"%S\" for Printer \"%S\"!\n", pwszPrintProcessor, wszPrinterName); @@ -147,7 +148,7 @@ InitializePrinterTable() pPrinter->pwszPrinterName = AllocSplStr(wszPrinterName); pPrinter->pPrintProcessor = pPrintProcessor; - InitializeListHead(&pPrinter->JobQueue); + InitializePrinterJobList(pPrinter); // Get the printer driver. pPrinter->pwszPrinterDriver = AllocAndRegQueryWSZ(hSubKey, L"Printer Driver"); @@ -165,7 +166,7 @@ InitializePrinterTable() continue; // Verify that it's valid. - if (!RtlLookupElementGenericTable(&pPrintProcessor->DatatypeTable, pPrinter->pwszDefaultDatatype)) + if (!FindDatatype(pPrintProcessor, pPrinter->pwszDefaultDatatype)) { ERR("Invalid default datatype \"%S\" for Printer \"%S\"!\n", pPrinter->pwszDefaultDatatype, wszPrinterName); continue; @@ -176,14 +177,14 @@ InitializePrinterTable() lStatus = RegQueryValueExW(hSubKey, L"Default DevMode", NULL, NULL, (PBYTE)&pPrinter->DefaultDevMode, &cbDevMode); if (lStatus != ERROR_SUCCESS || cbDevMode != sizeof(DEVMODEW)) { - ERR("Couldn't query DevMode for Printer \"%S\", status is %ld, cbDevMode is %lu!\n", wszPrinterName, lStatus, cbDevMode); + ERR("Couldn't query a valid DevMode for Printer \"%S\", status is %ld, cbDevMode is %lu!\n", wszPrinterName, lStatus, cbDevMode); continue; } - // Add this printer to the printer table. - if (!RtlInsertElementGenericTable(&PrinterTable, pPrinter, sizeof(LOCAL_PRINTER), NULL)) + // Add this printer to the printer list. + if (!InsertElementSkiplist(&PrinterList, pPrinter)) { - ERR("RtlInsertElementGenericTable failed with error %lu!\n", GetLastError()); + ERR("InsertElementSkiplist failed for Printer \"%S\"!\n", pPrinter->pwszPrinterName); goto Cleanup; } @@ -192,20 +193,31 @@ InitializePrinterTable() } Cleanup: - if (pwszPrintProcessor) - DllFreeSplStr(pwszPrintProcessor); + // Inside the loop + if (hSubKey) + RegCloseKey(hSubKey); if (pPrinter) { if (pPrinter->pwszDefaultDatatype) DllFreeSplStr(pPrinter->pwszDefaultDatatype); + if (pPrinter->pwszDescription) + DllFreeSplStr(pPrinter->pwszDescription); + + if (pPrinter->pwszPrinterDriver) + DllFreeSplStr(pPrinter->pwszPrinterDriver); + + if (pPrinter->pwszPrinterName) + DllFreeSplStr(pPrinter->pwszPrinterName); + DllFreeSplMem(pPrinter); } - if (hSubKey) - RegCloseKey(hSubKey); + if (pwszPrintProcessor) + DllFreeSplStr(pwszPrintProcessor); + // Outside the loop if (hKey) RegCloseKey(hKey); } @@ -223,9 +235,9 @@ _LocalEnumPrintersLevel1(DWORD Flags, LPWSTR Name, LPBYTE pPrinterEnum, DWORD cb DWORD i; PBYTE pPrinterInfo; PBYTE pPrinterString; + PSKIPLIST_NODE pNode; PLOCAL_PRINTER pPrinter; PRINTER_INFO_1W PrinterInfo1; - PVOID pRestartKey = NULL; WCHAR wszComputerName[2 + MAX_COMPUTERNAME_LENGTH + 1 + 1]; DWORD dwOffsets[] = { @@ -302,8 +314,10 @@ _LocalEnumPrintersLevel1(DWORD Flags, LPWSTR Name, LPBYTE pPrinterEnum, DWORD cb } // Count the required buffer size and the number of printers. - for (pPrinter = RtlEnumerateGenericTableWithoutSplaying(&PrinterTable, &pRestartKey); pPrinter; pPrinter = RtlEnumerateGenericTableWithoutSplaying(&PrinterTable, &pRestartKey)) + for (pNode = PrinterList.Head.Next[0]; pNode; pNode = pNode->Next[0]) { + pPrinter = (PLOCAL_PRINTER)pNode->Element; + // This looks wrong, but is totally right. PRINTER_INFO_1W has three members pName, pComment and pDescription. // But pComment equals the "Description" registry value while pDescription is concatenated out of pName and pComment. // On top of this, the computer name is prepended to the printer name if the user supplied the local computer name during the query. @@ -328,8 +342,10 @@ _LocalEnumPrintersLevel1(DWORD Flags, LPWSTR Name, LPBYTE pPrinterEnum, DWORD cb pPrinterString = pPrinterEnum + *pcReturned * sizeof(PRINTER_INFO_1W); // Copy over the printer information. - for (pPrinter = RtlEnumerateGenericTableWithoutSplaying(&PrinterTable, &pRestartKey); pPrinter; pPrinter = RtlEnumerateGenericTableWithoutSplaying(&PrinterTable, &pRestartKey)) + for (pNode = PrinterList.Head.Next[0]; pNode; pNode = pNode->Next[0]) { + pPrinter = (PLOCAL_PRINTER)pNode->Element; + // FIXME: As for now, the Flags member returns no information. PrinterInfo1.Flags = 0; @@ -409,7 +425,6 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef PLOCAL_HANDLE pHandle; PLOCAL_PRINTER pPrinter; PLOCAL_PRINTER_HANDLE pPrinterHandle = NULL; - PLIST_ENTRY pEntry; WCHAR wszComputerName[MAX_COMPUTERNAME_LENGTH + 1]; // Sanity checks @@ -478,8 +493,8 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef CopyMemory(pwszPrinterName, lpPrinterName, cchPrinterName * sizeof(WCHAR)); pwszPrinterName[cchPrinterName] = 0; - // Retrieve the associated printer from the table. - pPrinter = RtlLookupElementGenericTable(&PrinterTable, pwszPrinterName); + // Retrieve the associated printer from the list. + pPrinter = LookupElementSkiplist(&PrinterList, &pwszPrinterName, NULL); if (!pPrinter) { // The printer does not exist. @@ -495,7 +510,7 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef if (pDefault && pDefault->pDatatype) { // Use the datatype if it's valid. - if (!RtlLookupElementGenericTable(&pPrinter->pPrintProcessor->DatatypeTable, pDefault->pDatatype)) + if (!FindDatatype(pPrinter->pPrintProcessor, pDefault->pDatatype)) { SetLastError(ERROR_INVALID_DATATYPE); goto Cleanup; @@ -550,30 +565,16 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef goto Cleanup; } - // Look for this job in the job queue of the printer. - pEntry = pPrinter->JobQueue.Flink; - - for (;;) + // Look for this job in the Global Job List. + pJob = LookupElementSkiplist(&GlobalJobList, &dwJobID, NULL); + if (!pJob || pJob->Printer != pPrinter) { - if (pEntry == &pPrinter->JobQueue) - { - // We have reached the end of the list without finding the desired Job ID. - SetLastError(ERROR_INVALID_PRINTER_NAME); - goto Cleanup; - } - - // Get our job structure. - pJob = CONTAINING_RECORD(pEntry, LOCAL_JOB, Entry); - - if (pJob->dwJobID == dwJobID) - { - // We have found the desired job. Give the caller a printer handle referencing it. - pPrinterHandle->StartedJob = pJob; - break; - } - - pEntry = pEntry->Flink; + // The user supplied a non-existing Job ID or the Job ID does not belong to the supplied printer name. + SetLastError(ERROR_INVALID_PRINTER_NAME); + goto Cleanup; } + + pPrinterHandle->StartedJob = pJob; } // Create a new handle that references a printer. @@ -647,11 +648,10 @@ Cleanup: DWORD WINAPI LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo) { - DWORD dwReturnValue = 0; PDOC_INFO_1W pDocumentInfo1; PLOCAL_HANDLE pHandle; - PLOCAL_PRINTER_HANDLE pPrinterHandle; PLOCAL_JOB pJob; + PLOCAL_PRINTER_HANDLE pPrinterHandle; // Sanity checks if (!pDocInfo) @@ -688,15 +688,16 @@ LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo) // Create a new job. pJob = DllAllocSplMem(sizeof(LOCAL_JOB)); pJob->Printer = pPrinterHandle->Printer; + pJob->dwPriority = DEF_PRIORITY; // Check if a datatype was given. if (pDocumentInfo1->pDatatype) { // Use the datatype if it's valid. - if (!RtlLookupElementGenericTable(&pJob->Printer->pPrintProcessor->DatatypeTable, pDocumentInfo1->pDatatype)) + if (!FindDatatype(pJob->Printer->pPrintProcessor, pDocumentInfo1->pDatatype)) { SetLastError(ERROR_INVALID_DATATYPE); - goto Cleanup; + return 0; } pJob->pwszDatatype = AllocSplStr(pDocumentInfo1->pDatatype); @@ -717,14 +718,27 @@ LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo) if (pDocumentInfo1->pOutputFile) pJob->pwszOutputFile = AllocSplStr(pDocumentInfo1->pOutputFile); - // Enqueue the job. - ///////////// TODO ///////////////////// + // Get an ID for the new job. + if (!GetNextJobID(&pJob->dwJobID)) + return 0; -Cleanup: - if (pJob) - DllFreeSplMem(pJob); + // Add the job to the Global Job List. + if (!InsertElementSkiplist(&GlobalJobList, pJob)) + { + ERR("InsertElementSkiplist failed for job %lu for the GlobalJobList!\n", pJob->dwJobID); + return 0; + } - return dwReturnValue; + // Add the job at the end of the Printer's Job List. + // As all new jobs are created with default priority, we can be sure that it would always be inserted at the end. + if (!InsertTailElementSkiplist(&pJob->Printer->JobList, pJob)) + { + ERR("InsertTailElementSkiplist failed for job %lu for the Printer's Job List!\n", pJob->dwJobID); + return 0; + } + + pPrinterHandle->StartedJob = pJob; + return pJob->dwJobID; } BOOL WINAPI diff --git a/reactos/win32ss/printing/providers/localspl/printprocessors.c b/reactos/win32ss/printing/providers/localspl/printprocessors.c index 602dd830d4a..a8b9a8951ed 100644 --- a/reactos/win32ss/printing/providers/localspl/printprocessors.c +++ b/reactos/win32ss/printing/providers/localspl/printprocessors.c @@ -8,8 +8,8 @@ #include "precomp.h" -// Global Variables -RTL_GENERIC_TABLE PrintProcessorTable; +// Local Variables +static LIST_ENTRY _PrintProcessorList; /** * @name _OpenEnvironment @@ -76,83 +76,67 @@ Cleanup: return bReturnValue; } -/** - * @name _PrinterTableCompareRoutine - * - * RTL_GENERIC_COMPARE_ROUTINE for the Print Processor Table. - * Does a case-insensitive comparison, because e.g. LocalEnumPrintProcessorDatatypes doesn't match the case when looking for Print Processors. - */ -static RTL_GENERIC_COMPARE_RESULTS NTAPI -_PrintProcessorTableCompareRoutine(PRTL_GENERIC_TABLE Table, PVOID FirstStruct, PVOID SecondStruct) +BOOL +FindDatatype(PLOCAL_PRINT_PROCESSOR pPrintProcessor, PWSTR pwszDatatype) { - PLOCAL_PRINT_PROCESSOR A = (PLOCAL_PRINT_PROCESSOR)FirstStruct; - PLOCAL_PRINT_PROCESSOR B = (PLOCAL_PRINT_PROCESSOR)SecondStruct; + DWORD i; + PDATATYPES_INFO_1W pCurrentDatatype = pPrintProcessor->pDatatypesInfo1; - int iResult = wcsicmp(A->pwszName, B->pwszName); + for (i = 0; i < pPrintProcessor->dwDatatypeCount; i++) + { + if (wcsicmp(pCurrentDatatype->pName, pwszDatatype) == 0) + return TRUE; - if (iResult < 0) - return GenericLessThan; - else if (iResult > 0) - return GenericGreaterThan; - else - return GenericEqual; + ++pCurrentDatatype; + } + + return FALSE; +} + +PLOCAL_PRINT_PROCESSOR +FindPrintProcessor(PWSTR pwszName) +{ + PLIST_ENTRY pEntry; + PLOCAL_PRINT_PROCESSOR pPrintProcessor; + + for (pEntry = _PrintProcessorList.Flink; pEntry; pEntry = pEntry->Flink) + { + pPrintProcessor = CONTAINING_RECORD(pEntry, LOCAL_PRINT_PROCESSOR, Entry); + + if (wcsicmp(pPrintProcessor->pwszName, pwszName) == 0) + return pPrintProcessor; + } + + return NULL; } /** - * @name _DatatypeTableCompareRoutine + * @name InitializePrintProcessorList * - * RTL_GENERIC_COMPARE_ROUTINE for the Datatype Table. - * Does a case-insensitive comparison, because e.g. LocalOpenPrinter doesn't match the case when looking for Datatypes. - */ -static RTL_GENERIC_COMPARE_RESULTS NTAPI -_DatatypeTableCompareRoutine(PRTL_GENERIC_TABLE Table, PVOID FirstStruct, PVOID SecondStruct) -{ - PWSTR A = (PWSTR)FirstStruct; - PWSTR B = (PWSTR)SecondStruct; - - int iResult = wcsicmp(A, B); - - if (iResult < 0) - return GenericLessThan; - else if (iResult > 0) - return GenericGreaterThan; - else - return GenericEqual; -} - -/** - * @name InitializePrintProcessorTable - * - * Initializes a RTL_GENERIC_TABLE of locally available Print Processors. - * The table is searchable by name and returns pointers to the functions of the loaded Print Processor DLL. + * Initializes a singly linked list of locally available Print Processors. */ void -InitializePrintProcessorTable() +InitializePrintProcessorList() { DWORD cbDatatypes; DWORD cbFileName; DWORD cchPrintProcessorPath; DWORD cchMaxSubKey; DWORD cchPrintProcessorName; - DWORD dwDatatypes; DWORD dwSubKeys; DWORD i; - DWORD j; HINSTANCE hinstPrintProcessor; HKEY hKey = NULL; HKEY hSubKey = NULL; HKEY hSubSubKey = NULL; LONG lStatus; - PDATATYPES_INFO_1W pDatatypesInfo1 = NULL; PLOCAL_PRINT_PROCESSOR pPrintProcessor = NULL; - PWSTR pwszDatatype = NULL; PWSTR pwszPrintProcessorName = NULL; WCHAR wszFileName[MAX_PATH]; WCHAR wszPrintProcessorPath[MAX_PATH]; - // Initialize an empty table for our Print Processors. - // We will search it by Print Processor name. - RtlInitializeGenericTable(&PrintProcessorTable, _PrintProcessorTableCompareRoutine, GenericTableAllocateRoutine, GenericTableFreeRoutine, NULL); + // Initialize an empty list for our Print Processors. + InitializeListHead(&_PrintProcessorList); // Prepare the path to the Print Processor directory. if (!LocalGetPrintProcessorDirectory(NULL, NULL, 1, (PBYTE)wszPrintProcessorPath, sizeof(wszPrintProcessorPath), &cchPrintProcessorPath)) @@ -204,16 +188,13 @@ InitializePrintProcessorTable() if (pPrintProcessor->pwszName) DllFreeSplStr(pPrintProcessor->pwszName); + if (pPrintProcessor->pDatatypesInfo1) + DllFreeSplMem(pPrintProcessor->pDatatypesInfo1); + DllFreeSplMem(pPrintProcessor); pPrintProcessor = NULL; } - if (pDatatypesInfo1) - { - DllFreeSplMem(pDatatypesInfo1); - pDatatypesInfo1 = NULL; - } - // Get the name of this Print Processor. cchPrintProcessorName = cchMaxSubKey; lStatus = RegEnumKeyExW(hSubKey, i, pwszPrintProcessorName, &cchPrintProcessorName, NULL, NULL, NULL, NULL); @@ -306,69 +287,47 @@ InitializePrintProcessorTable() } // Get all supported datatypes. - pPrintProcessor->pfnEnumPrintProcessorDatatypesW(NULL, NULL, 1, NULL, 0, &cbDatatypes, &dwDatatypes); - pDatatypesInfo1 = DllAllocSplMem(cbDatatypes); - if (!pDatatypesInfo1) + pPrintProcessor->pfnEnumPrintProcessorDatatypesW(NULL, NULL, 1, NULL, 0, &cbDatatypes, &pPrintProcessor->dwDatatypeCount); + pPrintProcessor->pDatatypesInfo1 = DllAllocSplMem(cbDatatypes); + if (!pPrintProcessor->pDatatypesInfo1) { ERR("DllAllocSplMem failed with error %lu!\n", GetLastError()); goto Cleanup; } - if (!pPrintProcessor->pfnEnumPrintProcessorDatatypesW(NULL, NULL, 1, (PBYTE)pDatatypesInfo1, cbDatatypes, &cbDatatypes, &dwDatatypes)) + if (!pPrintProcessor->pfnEnumPrintProcessorDatatypesW(NULL, NULL, 1, (PBYTE)pPrintProcessor->pDatatypesInfo1, cbDatatypes, &cbDatatypes, &pPrintProcessor->dwDatatypeCount)) { ERR("EnumPrintProcessorDatatypesW failed for Print Processor \"%S\" with error %lu!\n", wszPrintProcessorPath, GetLastError()); continue; } - // Add the supported datatypes to the datatype table. - RtlInitializeGenericTable(&pPrintProcessor->DatatypeTable, _DatatypeTableCompareRoutine, GenericTableAllocateRoutine, GenericTableFreeRoutine, NULL); - - for (j = 0; j < dwDatatypes; j++) - { - pwszDatatype = AllocSplStr(pDatatypesInfo1->pName); - - if (!RtlInsertElementGenericTable(&pPrintProcessor->DatatypeTable, pDatatypesInfo1->pName, sizeof(PWSTR), NULL)) - { - ERR("RtlInsertElementGenericTable failed for iteration %lu with error %lu!\n", j, GetLastError()); - goto Cleanup; - } - - ++pDatatypesInfo1; - } - - // Add the Print Processor to the table. - if (!RtlInsertElementGenericTable(&PrintProcessorTable, pPrintProcessor, sizeof(LOCAL_PRINT_PROCESSOR), NULL)) - { - ERR("RtlInsertElementGenericTable failed for iteration %lu with error %lu!\n", i, GetLastError()); - goto Cleanup; - } + // Add the Print Processor to the list. + InsertTailList(&_PrintProcessorList, &pPrintProcessor->Entry); // Don't let the cleanup routines free this. - pwszDatatype = NULL; pPrintProcessor = NULL; } Cleanup: - if (pwszDatatype) - DllFreeSplStr(pwszDatatype); - - if (pDatatypesInfo1) - DllFreeSplMem(pDatatypesInfo1); + // Inside the loop + if (hSubSubKey) + RegCloseKey(hSubSubKey); if (pPrintProcessor) { if (pPrintProcessor->pwszName) DllFreeSplStr(pPrintProcessor->pwszName); + if (pPrintProcessor->pDatatypesInfo1) + DllFreeSplMem(pPrintProcessor->pDatatypesInfo1); + DllFreeSplMem(pPrintProcessor); } + // Outside the loop if (pwszPrintProcessorName) DllFreeSplStr(pwszPrintProcessorName); - if (hSubSubKey) - RegCloseKey(hSubSubKey); - if (hSubKey) RegCloseKey(hSubKey); @@ -423,7 +382,7 @@ LocalEnumPrintProcessorDatatypes(LPWSTR pName, LPWSTR pPrintProcessorName, DWORD } // Try to find the Print Processor. - pPrintProcessor = RtlLookupElementGenericTable(&PrintProcessorTable, pPrintProcessorName); + pPrintProcessor = FindPrintProcessor(pPrintProcessorName); if (!pPrintProcessor) { SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR); @@ -499,6 +458,7 @@ LocalEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE } // Verify pEnvironment and open its registry key. + // We use the registry and not the PrintProcessorList here, because the caller may request information about a different environment. if (!_OpenEnvironment(pEnvironment, &hKey)) goto Cleanup; diff --git a/reactos/win32ss/printing/providers/localspl/tools.c b/reactos/win32ss/printing/providers/localspl/tools.c index 10515dbfd34..ef6ef5006b5 100644 --- a/reactos/win32ss/printing/providers/localspl/tools.c +++ b/reactos/win32ss/printing/providers/localspl/tools.c @@ -56,25 +56,3 @@ AllocAndRegQueryWSZ(HKEY hKey, PCWSTR pwszValueName) return pwszValue; } - -/** - * @name GenericTableAllocateRoutine - * - * RTL_GENERIC_ALLOCATE_ROUTINE for all our RTL_GENERIC_TABLEs, using DllAllocSplMem. - */ -PVOID NTAPI -GenericTableAllocateRoutine(PRTL_GENERIC_TABLE Table, CLONG ByteSize) -{ - return DllAllocSplMem(ByteSize); -} - -/** - * @name GenericTableFreeRoutine - * - * RTL_GENERIC_FREE_ROUTINE for all our RTL_GENERIC_TABLEs, using DllFreeSplMem. - */ -VOID NTAPI -GenericTableFreeRoutine(PRTL_GENERIC_TABLE Table, PVOID Buffer) -{ - DllFreeSplMem(Buffer); -}