[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
This commit is contained in:
Colin Finck 2015-06-19 15:21:30 +00:00
parent a4d50f82ff
commit 9be537abb7
7 changed files with 689 additions and 238 deletions

View file

@ -1,6 +1,8 @@
spec2def(localspl.dll localspl.spec ADD_IMPORTLIB) spec2def(localspl.dll localspl.spec ADD_IMPORTLIB)
include_directories(${REACTOS_SOURCE_DIR}/lib/skiplist)
list(APPEND SOURCE list(APPEND SOURCE
jobs.c jobs.c
main.c main.c
@ -16,7 +18,7 @@ add_library(localspl SHARED
${CMAKE_CURRENT_BINARY_DIR}/localspl.def) ${CMAKE_CURRENT_BINARY_DIR}/localspl.def)
set_module_type(localspl win32dll UNICODE) set_module_type(localspl win32dll UNICODE)
target_link_libraries(localspl wine) target_link_libraries(localspl skiplist16 wine)
add_importlibs(localspl advapi32 spoolss msvcrt kernel32 ntdll) add_importlibs(localspl advapi32 rpcrt4 spoolss msvcrt kernel32 ntdll)
add_pch(localspl precomp.h SOURCE) add_pch(localspl precomp.h SOURCE)
add_cd_file(TARGET localspl DESTINATION reactos/system32 FOR all) add_cd_file(TARGET localspl DESTINATION reactos/system32 FOR all)

View file

@ -7,10 +7,103 @@
#include "precomp.h" #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 void
InitializeJobQueue() InitializeGlobalJobList()
{ {
const WCHAR wszPath[] = L"\\PRINTERS\\?????.SHD"; const WCHAR wszPath[] = L"\\PRINTERS\\?????.SHD";
const DWORD cchPath = _countof(wszPath) - 1; const DWORD cchPath = _countof(wszPath) - 1;
@ -19,11 +112,18 @@ InitializeJobQueue()
DWORD dwJobID; DWORD dwJobID;
HANDLE hFind; HANDLE hFind;
PLOCAL_JOB pJob; PLOCAL_JOB pJob = NULL;
PWSTR p; PWSTR p;
WCHAR wszFullPath[MAX_PATH]; WCHAR wszFullPath[MAX_PATH];
WIN32_FIND_DATAW FindData; 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. // Construct the full path search pattern.
CopyMemory(wszFullPath, wszSpoolDirectory, cchSpoolDirectory * sizeof(WCHAR)); CopyMemory(wszFullPath, wszSpoolDirectory, cchSpoolDirectory * sizeof(WCHAR));
CopyMemory(&wszFullPath[cchSpoolDirectory], wszPath, (cchPath + 1) * sizeof(WCHAR)); CopyMemory(&wszFullPath[cchSpoolDirectory], wszPath, (cchPath + 1) * sizeof(WCHAR));
@ -33,7 +133,7 @@ InitializeJobQueue()
if (hFind == INVALID_HANDLE_VALUE) if (hFind == INVALID_HANDLE_VALUE)
{ {
// No unfinished jobs found. // No unfinished jobs found.
return; goto Cleanup;
} }
do do
@ -56,12 +156,368 @@ InitializeJobQueue()
if (!pJob) if (!pJob)
continue; continue;
// Add it to the job queue of the respective printer. // Add it to the Global Job List.
InsertTailList(&pJob->Printer->JobQueue, &pJob->Entry); 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)); 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 PLOCAL_JOB
@ -80,7 +536,7 @@ ReadJobShadowFile(PCWSTR pwszFilePath)
hFile = CreateFileW(pwszFilePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); hFile = CreateFileW(pwszFilePath, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) 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; goto Cleanup;
} }
@ -89,30 +545,30 @@ ReadJobShadowFile(PCWSTR pwszFilePath)
pShadowFile = DllAllocSplMem(cbFileSize); pShadowFile = DllAllocSplMem(cbFileSize);
if (!pShadowFile) if (!pShadowFile)
{ {
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError()); ERR("DllAllocSplMem failed with error %lufor file \"%S\"!\n", GetLastError(), pwszFilePath);
goto Cleanup; goto Cleanup;
} }
// Read the entire file. // Read the entire file.
if (!ReadFile(hFile, pShadowFile, cbFileSize, &cbRead, NULL)) 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; goto Cleanup;
} }
// Check signature and header size. // Check signature and header size.
if (pShadowFile->dwSignature != SHD_WIN2003_SIGNATURE || pShadowFile->cbHeader != sizeof(SHD_HEADER)) 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; goto Cleanup;
} }
// Retrieve the associated printer from the table. // Retrieve the associated printer from the list.
pwszPrinterName = (PWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offPrinterName); pwszPrinterName = (PWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offPrinterName);
pPrinter = RtlLookupElementGenericTable(&PrinterTable, pwszPrinterName); pPrinter = LookupElementSkiplist(&PrinterList, &pwszPrinterName, NULL);
if (!pPrinter) 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; goto Cleanup;
} }
@ -120,15 +576,18 @@ ReadJobShadowFile(PCWSTR pwszFilePath)
pJob = DllAllocSplMem(sizeof(LOCAL_JOB)); pJob = DllAllocSplMem(sizeof(LOCAL_JOB));
if (!pJob) if (!pJob)
{ {
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError()); ERR("DllAllocSplMem failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath);
goto Cleanup; goto Cleanup;
} }
pJob->dwJobID = pShadowFile->dwJobID; pJob->dwJobID = pShadowFile->dwJobID;
pJob->dwTotalPages = pShadowFile->dwTotalPages;
pJob->dwPriority = pShadowFile->dwPriority;
pJob->Printer = pPrinter; pJob->Printer = pPrinter;
pJob->pwszDatatype = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offDatatype)); pJob->pwszDatatype = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offDatatype));
pJob->pwszDocumentName = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offDocumentName)); pJob->pwszDocumentName = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile + pShadowFile->offDocumentName));
pJob->pwszOutputFile = NULL; pJob->pwszOutputFile = NULL;
CopyMemory(&pJob->stSubmitted, &pShadowFile->stSubmitted, sizeof(SYSTEMTIME));
CopyMemory(&pJob->DevMode, (PDEVMODEW)((ULONG_PTR)pShadowFile + pShadowFile->offDevMode), sizeof(DEVMODEW)); CopyMemory(&pJob->DevMode, (PDEVMODEW)((ULONG_PTR)pShadowFile + pShadowFile->offDevMode), sizeof(DEVMODEW));
pReturnValue = pJob; pReturnValue = pJob;
@ -160,33 +619,42 @@ WriteJobShadowFile(PCWSTR pwszFilePath, const PLOCAL_JOB pJob)
hFile = CreateFileW(pwszFilePath, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, 0, NULL); hFile = CreateFileW(pwszFilePath, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) 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; goto Cleanup;
} }
// Compute the total size of the shadow file. // Compute the total size of the shadow file.
cbPrinterName = (wcslen(pJob->Printer->pwszPrinterName) + 1) * sizeof(WCHAR);
cbDatatype = (wcslen(pJob->pwszDatatype) + 1) * sizeof(WCHAR); cbDatatype = (wcslen(pJob->pwszDatatype) + 1) * sizeof(WCHAR);
cbDocumentName = (wcslen(pJob->pwszDocumentName) + 1) * sizeof(WCHAR); cbDocumentName = (wcslen(pJob->pwszDocumentName) + 1) * sizeof(WCHAR);
cbPrinterName = (wcslen(pJob->Printer->pwszPrinterName) + 1) * sizeof(WCHAR); cbFileSize = sizeof(SHD_HEADER) + cbPrinterName + cbDatatype + cbDocumentName + sizeof(DEVMODEW);
cbFileSize = sizeof(SHD_HEADER) + cbDatatype + cbDocumentName + cbPrinterName;
// Allocate memory for it. // Allocate memory for it.
pShadowFile = DllAllocSplMem(cbFileSize); pShadowFile = DllAllocSplMem(cbFileSize);
if (!pShadowFile) if (!pShadowFile)
{ {
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError()); ERR("DllAllocSplMem failed with error %lu for file \"%S\"!\n", GetLastError(), pwszFilePath);
goto Cleanup; goto Cleanup;
} }
// Fill out the shadow file header information. // Fill out the shadow file header information.
pShadowFile->dwSignature = SHD_WIN2003_SIGNATURE; pShadowFile->dwSignature = SHD_WIN2003_SIGNATURE;
pShadowFile->cbHeader = sizeof(SHD_HEADER); pShadowFile->cbHeader = sizeof(SHD_HEADER);
// Copy the values.
pShadowFile->dwJobID = pJob->dwJobID; 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. // Add the extra values that are stored as offsets in the shadow file.
// The first value begins right after the shadow file header. // The first value begins right after the shadow file header.
dwCurrentOffset = sizeof(SHD_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); CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->pwszDatatype, cbDatatype);
pShadowFile->offDatatype = dwCurrentOffset; pShadowFile->offDatatype = dwCurrentOffset;
dwCurrentOffset += cbDatatype; dwCurrentOffset += cbDatatype;
@ -195,14 +663,14 @@ WriteJobShadowFile(PCWSTR pwszFilePath, const PLOCAL_JOB pJob)
pShadowFile->offDocumentName = dwCurrentOffset; pShadowFile->offDocumentName = dwCurrentOffset;
dwCurrentOffset += cbDocumentName; dwCurrentOffset += cbDocumentName;
CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, pJob->Printer->pwszPrinterName, cbPrinterName); CopyMemory((PBYTE)pShadowFile + dwCurrentOffset, &pJob->DevMode, sizeof(DEVMODEW));
pShadowFile->offPrinterName = dwCurrentOffset; pShadowFile->offDevMode = dwCurrentOffset;
dwCurrentOffset += cbPrinterName; dwCurrentOffset += sizeof(DEVMODEW);
// Write the file. // Write the file.
if (!WriteFile(hFile, pShadowFile, cbFileSize, &cbWritten, NULL)) 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; goto Cleanup;
} }

View file

@ -11,7 +11,7 @@
WCHAR wszSpoolDirectory[MAX_PATH]; WCHAR wszSpoolDirectory[MAX_PATH];
DWORD cchSpoolDirectory; DWORD cchSpoolDirectory;
// Constants // Global Constants
const WCHAR wszCurrentEnvironment[] = const WCHAR wszCurrentEnvironment[] =
#if defined(_X86_) #if defined(_X86_)
L"Windows NT x86"; L"Windows NT x86";
@ -23,16 +23,19 @@ const WCHAR wszCurrentEnvironment[] =
#error Unsupported architecture #error Unsupported architecture
#endif #endif
const WCHAR wszDefaultDocumentName[] = L"Local Downlevel Document";
const WCHAR* wszPrintProviderInfo[3] = { const WCHAR* wszPrintProviderInfo[3] = {
L"Windows NT Local Print Providor", // Name L"Windows NT Local Print Providor", // Name
L"Windows NT Local Printers", // Description L"Windows NT Local Printers", // Description
L"Locally connected Printers" // Comment L"Locally connected Printers" // Comment
}; };
static const PRINTPROVIDOR PrintProviderFunctions = { // Local Constants
static const PRINTPROVIDOR _PrintProviderFunctions = {
LocalOpenPrinter, // fpOpenPrinter LocalOpenPrinter, // fpOpenPrinter
NULL, // fpSetJob NULL, // fpSetJob
NULL, // fpGetJob LocalGetJob, // fpGetJob
NULL, // fpEnumJobs NULL, // fpEnumJobs
NULL, // fpAddPrinter NULL, // fpAddPrinter
NULL, // fpDeletePrinter NULL, // fpDeletePrinter
@ -56,7 +59,7 @@ static const PRINTPROVIDOR PrintProviderFunctions = {
NULL, // fpAbortPrinter NULL, // fpAbortPrinter
NULL, // fpReadPrinter NULL, // fpReadPrinter
LocalEndDocPrinter, // fpEndDocPrinter LocalEndDocPrinter, // fpEndDocPrinter
NULL, // fpAddJob LocalAddJob, // fpAddJob
NULL, // fpScheduleJob NULL, // fpScheduleJob
NULL, // fpGetPrinterData NULL, // fpGetPrinterData
NULL, // fpSetPrinterData NULL, // fpSetPrinterData
@ -139,8 +142,9 @@ DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
case DLL_PROCESS_ATTACH: case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hinstDLL); DisableThreadLibraryCalls(hinstDLL);
_GetSpoolDirectory(); _GetSpoolDirectory();
InitializePrintProcessorTable(); InitializePrintProcessorList();
InitializePrinterTable(); InitializePrinterList();
InitializeGlobalJobList();
break; break;
} }
@ -150,7 +154,7 @@ DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
BOOL WINAPI BOOL WINAPI
InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor, DWORD cbPrintProvidor, LPWSTR pFullRegistryPath) InitializePrintProvidor(LPPRINTPROVIDOR pPrintProvidor, DWORD cbPrintProvidor, LPWSTR pFullRegistryPath)
{ {
CopyMemory(pPrintProvidor, &PrintProviderFunctions, min(cbPrintProvidor, sizeof(PRINTPROVIDOR))); CopyMemory(pPrintProvidor, &_PrintProviderFunctions, min(cbPrintProvidor, sizeof(PRINTPROVIDOR)));
return TRUE; return TRUE;
} }

View file

@ -13,6 +13,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <wchar.h> #include <wchar.h>
#include <lmcons.h>
#include <rpc.h>
#include <windef.h> #include <windef.h>
#include <winbase.h> #include <winbase.h>
#include <wingdi.h> #include <wingdi.h>
@ -21,6 +23,8 @@
#include <winsplp.h> #include <winsplp.h>
#include <ndk/rtlfuncs.h> #include <ndk/rtlfuncs.h>
#define SKIPLIST_LEVELS 16
#include <skiplist.h>
#include <spoolss.h> #include <spoolss.h>
#include <wine/debug.h> #include <wine/debug.h>
@ -47,8 +51,10 @@ typedef BOOL (WINAPI *PPrintDocumentOnPrintProcessor)(HANDLE, LPWSTR);
*/ */
typedef struct _LOCAL_PRINT_PROCESSOR typedef struct _LOCAL_PRINT_PROCESSOR
{ {
LIST_ENTRY Entry;
PWSTR pwszName; PWSTR pwszName;
RTL_GENERIC_TABLE DatatypeTable; PDATATYPES_INFO_1W pDatatypesInfo1;
DWORD dwDatatypeCount;
PClosePrintProcessor pfnClosePrintProcessor; PClosePrintProcessor pfnClosePrintProcessor;
PControlPrintProcessor pfnControlPrintProcessor; PControlPrintProcessor pfnControlPrintProcessor;
PEnumPrintProcessorDatatypesW pfnEnumPrintProcessorDatatypesW; PEnumPrintProcessorDatatypesW pfnEnumPrintProcessorDatatypesW;
@ -64,13 +70,15 @@ LOCAL_PRINT_PROCESSOR, *PLOCAL_PRINT_PROCESSOR;
*/ */
typedef struct _LOCAL_PRINTER typedef struct _LOCAL_PRINTER
{ {
// This sort key must be the first element for LookupElementSkiplist to work!
PWSTR pwszPrinterName; PWSTR pwszPrinterName;
PWSTR pwszPrinterDriver; PWSTR pwszPrinterDriver;
PWSTR pwszDescription; PWSTR pwszDescription;
PWSTR pwszDefaultDatatype; PWSTR pwszDefaultDatatype;
DEVMODEW DefaultDevMode; DEVMODEW DefaultDevMode;
PLOCAL_PRINT_PROCESSOR pPrintProcessor; PLOCAL_PRINT_PROCESSOR pPrintProcessor;
LIST_ENTRY JobQueue; SKIPLIST JobList;
} }
LOCAL_PRINTER, *PLOCAL_PRINTER; LOCAL_PRINTER, *PLOCAL_PRINTER;
@ -80,13 +88,24 @@ LOCAL_PRINTER, *PLOCAL_PRINTER;
*/ */
typedef struct _LOCAL_JOB typedef struct _LOCAL_JOB
{ {
LIST_ENTRY Entry; // This sort key must be the first element for LookupElementSkiplist to work!
PLOCAL_PRINTER Printer; DWORD dwJobID; // Internal and external ID of this Job
DWORD dwJobID;
PWSTR pwszDocumentName; PLOCAL_PRINTER Printer; // Associated Printer to this Job
PWSTR pwszDatatype; DWORD dwPriority; // Priority of this Job from MIN_PRIORITY to MAX_PRIORITY, default being DEF_PRIORITY
PWSTR pwszOutputFile; SYSTEMTIME stSubmitted; // Time of the submission of this Job
DEVMODEW DevMode; 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; LOCAL_JOB, *PLOCAL_JOB;
@ -140,35 +159,42 @@ typedef struct _SHD_HEADER
DWORD offPrintProcessor; DWORD offPrintProcessor;
DWORD offDatatype; DWORD offDatatype;
DWORD dwUnknown2; DWORD dwUnknown2;
SYSTEMTIME stSubmitTime; SYSTEMTIME stSubmitted;
DWORD dwStartTime; DWORD dwStartTime;
DWORD dwUntilTime; DWORD dwUntilTime;
DWORD dwUnknown6; DWORD dwUnknown6;
DWORD dwPageCount; DWORD dwTotalPages;
DWORD cbSecurityDescriptor; DWORD cbSecurityDescriptor;
DWORD offSecurityDescriptor; DWORD offSecurityDescriptor;
DWORD dwUnknown3; DWORD dwUnknown3;
DWORD dwUnknown4; DWORD dwUnknown4;
DWORD dwUnknown5; DWORD dwUnknown5;
DWORD offComputerName; DWORD offMachineName;
DWORD dwSPLSize; DWORD dwSPLSize;
} }
SHD_HEADER, *PSHD_HEADER; SHD_HEADER, *PSHD_HEADER;
// jobs.c // 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); PLOCAL_JOB ReadJobShadowFile(PCWSTR pwszFilePath);
BOOL WriteJobShadowFile(PCWSTR pwszFilePath, const PLOCAL_JOB pJob); BOOL WriteJobShadowFile(PCWSTR pwszFilePath, const PLOCAL_JOB pJob);
// main.c // main.c
extern const WCHAR wszCurrentEnvironment[]; extern const WCHAR wszCurrentEnvironment[];
extern const WCHAR wszDefaultDocumentName[];
extern const WCHAR* wszPrintProviderInfo[3]; extern const WCHAR* wszPrintProviderInfo[3];
extern WCHAR wszSpoolDirectory[MAX_PATH]; extern WCHAR wszSpoolDirectory[MAX_PATH];
extern DWORD cchSpoolDirectory; extern DWORD cchSpoolDirectory;
// printers.c // printers.c
extern RTL_GENERIC_TABLE PrinterTable; extern SKIPLIST PrinterList;
void InitializePrinterTable(); void InitializePrinterList();
BOOL WINAPI LocalEnumPrinters(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned); 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); BOOL WINAPI LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDefault);
DWORD WINAPI LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo); DWORD WINAPI LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo);
@ -179,15 +205,14 @@ BOOL WINAPI LocalEndDocPrinter(HANDLE hPrinter);
BOOL WINAPI LocalClosePrinter(HANDLE hPrinter); BOOL WINAPI LocalClosePrinter(HANDLE hPrinter);
// printprocessors.c // printprocessors.c
extern RTL_GENERIC_TABLE PrintProcessorTable; BOOL FindDatatype(PLOCAL_PRINT_PROCESSOR pPrintProcessor, PWSTR pwszDatatype);
void InitializePrintProcessorTable(); 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 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 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); BOOL WINAPI LocalGetPrintProcessorDirectory(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE pPrintProcessorInfo, DWORD cbBuf, LPDWORD pcbNeeded);
// tools.c // tools.c
PWSTR AllocAndRegQueryWSZ(HKEY hKey, PCWSTR pwszValueName); 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 #endif

View file

@ -8,40 +8,33 @@
#include "precomp.h" #include "precomp.h"
// Global Variables // 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. * Does a case-insensitive comparison, because e.g. LocalOpenPrinter doesn't match the case when looking for Printers.
*/ */
static RTL_GENERIC_COMPARE_RESULTS NTAPI static int WINAPI
_PrinterTableCompareRoutine(PRTL_GENERIC_TABLE Table, PVOID FirstStruct, PVOID SecondStruct) _PrinterListCompareRoutine(PVOID FirstStruct, PVOID SecondStruct)
{ {
PLOCAL_PRINTER A = (PLOCAL_PRINTER)FirstStruct; PLOCAL_PRINTER A = (PLOCAL_PRINTER)FirstStruct;
PLOCAL_PRINTER B = (PLOCAL_PRINTER)SecondStruct; PLOCAL_PRINTER B = (PLOCAL_PRINTER)SecondStruct;
int iResult = wcsicmp(A->pwszPrinterName, B->pwszPrinterName); return wcsicmp(A->pwszPrinterName, B->pwszPrinterName);
if (iResult < 0)
return GenericLessThan;
else if (iResult > 0)
return GenericGreaterThan;
else
return GenericEqual;
} }
/** /**
* @name InitializePrinterTable * @name InitializePrinterList
* *
* Initializes a RTL_GENERIC_TABLE of locally available Printers. * Initializes a list of locally available Printers.
* The table is searchable by name and returns information about the printers, including their job queues. * 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. * During this process, the job queues are also initialized.
*/ */
void void
InitializePrinterTable() InitializePrinterList()
{ {
const WCHAR wszPrintersKey[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Printers"; const WCHAR wszPrintersKey[] = L"SYSTEM\\CurrentControlSet\\Control\\Print\\Printers";
@ -52,14 +45,13 @@ InitializePrinterTable()
HKEY hKey = NULL; HKEY hKey = NULL;
HKEY hSubKey = NULL; HKEY hSubKey = NULL;
LONG lStatus; LONG lStatus;
PLOCAL_PRINT_PROCESSOR pPrintProcessor;
PLOCAL_PRINTER pPrinter = NULL; PLOCAL_PRINTER pPrinter = NULL;
PLOCAL_PRINT_PROCESSOR pPrintProcessor;
PWSTR pwszPrintProcessor = NULL; PWSTR pwszPrintProcessor = NULL;
WCHAR wszPrinterName[MAX_PRINTER_NAME + 1]; WCHAR wszPrinterName[MAX_PRINTER_NAME + 1];
// Initialize an empty table for our printers. // Initialize an empty list for our printers.
// We will search it by printer name. InitializeSkiplist(&PrinterList, DllAllocSplMem, _PrinterListCompareRoutine, (PSKIPLIST_FREE_ROUTINE)DllFreeSplMem);
RtlInitializeGenericTable(&PrinterTable, _PrinterTableCompareRoutine, GenericTableAllocateRoutine, GenericTableFreeRoutine, NULL);
// Open our printers registry key. Each subkey is a local printer there. // Open our printers registry key. Each subkey is a local printer there.
lStatus = RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszPrintersKey, 0, KEY_READ, &hKey); lStatus = RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszPrintersKey, 0, KEY_READ, &hKey);
@ -92,6 +84,15 @@ InitializePrinterTable()
if (pPrinter->pwszDefaultDatatype) if (pPrinter->pwszDefaultDatatype)
DllFreeSplStr(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); DllFreeSplMem(pPrinter);
pPrinter = NULL; pPrinter = NULL;
} }
@ -129,8 +130,8 @@ InitializePrinterTable()
if (!pwszPrintProcessor) if (!pwszPrintProcessor)
continue; continue;
// Try to find it in the Print Processor Table. // Try to find it in the Print Processor List.
pPrintProcessor = RtlLookupElementGenericTable(&PrintProcessorTable, pwszPrintProcessor); pPrintProcessor = FindPrintProcessor(pwszPrintProcessor);
if (!pPrintProcessor) if (!pPrintProcessor)
{ {
ERR("Invalid Print Processor \"%S\" for Printer \"%S\"!\n", pwszPrintProcessor, wszPrinterName); ERR("Invalid Print Processor \"%S\" for Printer \"%S\"!\n", pwszPrintProcessor, wszPrinterName);
@ -147,7 +148,7 @@ InitializePrinterTable()
pPrinter->pwszPrinterName = AllocSplStr(wszPrinterName); pPrinter->pwszPrinterName = AllocSplStr(wszPrinterName);
pPrinter->pPrintProcessor = pPrintProcessor; pPrinter->pPrintProcessor = pPrintProcessor;
InitializeListHead(&pPrinter->JobQueue); InitializePrinterJobList(pPrinter);
// Get the printer driver. // Get the printer driver.
pPrinter->pwszPrinterDriver = AllocAndRegQueryWSZ(hSubKey, L"Printer Driver"); pPrinter->pwszPrinterDriver = AllocAndRegQueryWSZ(hSubKey, L"Printer Driver");
@ -165,7 +166,7 @@ InitializePrinterTable()
continue; continue;
// Verify that it's valid. // 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); ERR("Invalid default datatype \"%S\" for Printer \"%S\"!\n", pPrinter->pwszDefaultDatatype, wszPrinterName);
continue; continue;
@ -176,14 +177,14 @@ InitializePrinterTable()
lStatus = RegQueryValueExW(hSubKey, L"Default DevMode", NULL, NULL, (PBYTE)&pPrinter->DefaultDevMode, &cbDevMode); lStatus = RegQueryValueExW(hSubKey, L"Default DevMode", NULL, NULL, (PBYTE)&pPrinter->DefaultDevMode, &cbDevMode);
if (lStatus != ERROR_SUCCESS || cbDevMode != sizeof(DEVMODEW)) 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; continue;
} }
// Add this printer to the printer table. // Add this printer to the printer list.
if (!RtlInsertElementGenericTable(&PrinterTable, pPrinter, sizeof(LOCAL_PRINTER), NULL)) if (!InsertElementSkiplist(&PrinterList, pPrinter))
{ {
ERR("RtlInsertElementGenericTable failed with error %lu!\n", GetLastError()); ERR("InsertElementSkiplist failed for Printer \"%S\"!\n", pPrinter->pwszPrinterName);
goto Cleanup; goto Cleanup;
} }
@ -192,20 +193,31 @@ InitializePrinterTable()
} }
Cleanup: Cleanup:
if (pwszPrintProcessor) // Inside the loop
DllFreeSplStr(pwszPrintProcessor); if (hSubKey)
RegCloseKey(hSubKey);
if (pPrinter) if (pPrinter)
{ {
if (pPrinter->pwszDefaultDatatype) if (pPrinter->pwszDefaultDatatype)
DllFreeSplStr(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); DllFreeSplMem(pPrinter);
} }
if (hSubKey) if (pwszPrintProcessor)
RegCloseKey(hSubKey); DllFreeSplStr(pwszPrintProcessor);
// Outside the loop
if (hKey) if (hKey)
RegCloseKey(hKey); RegCloseKey(hKey);
} }
@ -223,9 +235,9 @@ _LocalEnumPrintersLevel1(DWORD Flags, LPWSTR Name, LPBYTE pPrinterEnum, DWORD cb
DWORD i; DWORD i;
PBYTE pPrinterInfo; PBYTE pPrinterInfo;
PBYTE pPrinterString; PBYTE pPrinterString;
PSKIPLIST_NODE pNode;
PLOCAL_PRINTER pPrinter; PLOCAL_PRINTER pPrinter;
PRINTER_INFO_1W PrinterInfo1; PRINTER_INFO_1W PrinterInfo1;
PVOID pRestartKey = NULL;
WCHAR wszComputerName[2 + MAX_COMPUTERNAME_LENGTH + 1 + 1]; WCHAR wszComputerName[2 + MAX_COMPUTERNAME_LENGTH + 1 + 1];
DWORD dwOffsets[] = { 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. // 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. // 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. // 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. // 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); pPrinterString = pPrinterEnum + *pcReturned * sizeof(PRINTER_INFO_1W);
// Copy over the printer information. // 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. // FIXME: As for now, the Flags member returns no information.
PrinterInfo1.Flags = 0; PrinterInfo1.Flags = 0;
@ -409,7 +425,6 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef
PLOCAL_HANDLE pHandle; PLOCAL_HANDLE pHandle;
PLOCAL_PRINTER pPrinter; PLOCAL_PRINTER pPrinter;
PLOCAL_PRINTER_HANDLE pPrinterHandle = NULL; PLOCAL_PRINTER_HANDLE pPrinterHandle = NULL;
PLIST_ENTRY pEntry;
WCHAR wszComputerName[MAX_COMPUTERNAME_LENGTH + 1]; WCHAR wszComputerName[MAX_COMPUTERNAME_LENGTH + 1];
// Sanity checks // Sanity checks
@ -478,8 +493,8 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef
CopyMemory(pwszPrinterName, lpPrinterName, cchPrinterName * sizeof(WCHAR)); CopyMemory(pwszPrinterName, lpPrinterName, cchPrinterName * sizeof(WCHAR));
pwszPrinterName[cchPrinterName] = 0; pwszPrinterName[cchPrinterName] = 0;
// Retrieve the associated printer from the table. // Retrieve the associated printer from the list.
pPrinter = RtlLookupElementGenericTable(&PrinterTable, pwszPrinterName); pPrinter = LookupElementSkiplist(&PrinterList, &pwszPrinterName, NULL);
if (!pPrinter) if (!pPrinter)
{ {
// The printer does not exist. // The printer does not exist.
@ -495,7 +510,7 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef
if (pDefault && pDefault->pDatatype) if (pDefault && pDefault->pDatatype)
{ {
// Use the datatype if it's valid. // Use the datatype if it's valid.
if (!RtlLookupElementGenericTable(&pPrinter->pPrintProcessor->DatatypeTable, pDefault->pDatatype)) if (!FindDatatype(pPrinter->pPrintProcessor, pDefault->pDatatype))
{ {
SetLastError(ERROR_INVALID_DATATYPE); SetLastError(ERROR_INVALID_DATATYPE);
goto Cleanup; goto Cleanup;
@ -550,30 +565,16 @@ LocalOpenPrinter(PWSTR lpPrinterName, HANDLE* phPrinter, PPRINTER_DEFAULTSW pDef
goto Cleanup; goto Cleanup;
} }
// Look for this job in the job queue of the printer. // Look for this job in the Global Job List.
pEntry = pPrinter->JobQueue.Flink; pJob = LookupElementSkiplist(&GlobalJobList, &dwJobID, NULL);
if (!pJob || pJob->Printer != pPrinter)
for (;;)
{ {
if (pEntry == &pPrinter->JobQueue) // 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);
// We have reached the end of the list without finding the desired Job ID. goto Cleanup;
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;
} }
pPrinterHandle->StartedJob = pJob;
} }
// Create a new handle that references a printer. // Create a new handle that references a printer.
@ -647,11 +648,10 @@ Cleanup:
DWORD WINAPI DWORD WINAPI
LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo) LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
{ {
DWORD dwReturnValue = 0;
PDOC_INFO_1W pDocumentInfo1; PDOC_INFO_1W pDocumentInfo1;
PLOCAL_HANDLE pHandle; PLOCAL_HANDLE pHandle;
PLOCAL_PRINTER_HANDLE pPrinterHandle;
PLOCAL_JOB pJob; PLOCAL_JOB pJob;
PLOCAL_PRINTER_HANDLE pPrinterHandle;
// Sanity checks // Sanity checks
if (!pDocInfo) if (!pDocInfo)
@ -688,15 +688,16 @@ LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
// Create a new job. // Create a new job.
pJob = DllAllocSplMem(sizeof(LOCAL_JOB)); pJob = DllAllocSplMem(sizeof(LOCAL_JOB));
pJob->Printer = pPrinterHandle->Printer; pJob->Printer = pPrinterHandle->Printer;
pJob->dwPriority = DEF_PRIORITY;
// Check if a datatype was given. // Check if a datatype was given.
if (pDocumentInfo1->pDatatype) if (pDocumentInfo1->pDatatype)
{ {
// Use the datatype if it's valid. // 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); SetLastError(ERROR_INVALID_DATATYPE);
goto Cleanup; return 0;
} }
pJob->pwszDatatype = AllocSplStr(pDocumentInfo1->pDatatype); pJob->pwszDatatype = AllocSplStr(pDocumentInfo1->pDatatype);
@ -717,14 +718,27 @@ LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
if (pDocumentInfo1->pOutputFile) if (pDocumentInfo1->pOutputFile)
pJob->pwszOutputFile = AllocSplStr(pDocumentInfo1->pOutputFile); pJob->pwszOutputFile = AllocSplStr(pDocumentInfo1->pOutputFile);
// Enqueue the job. // Get an ID for the new job.
///////////// TODO ///////////////////// if (!GetNextJobID(&pJob->dwJobID))
return 0;
Cleanup: // Add the job to the Global Job List.
if (pJob) if (!InsertElementSkiplist(&GlobalJobList, pJob))
DllFreeSplMem(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 BOOL WINAPI

View file

@ -8,8 +8,8 @@
#include "precomp.h" #include "precomp.h"
// Global Variables // Local Variables
RTL_GENERIC_TABLE PrintProcessorTable; static LIST_ENTRY _PrintProcessorList;
/** /**
* @name _OpenEnvironment * @name _OpenEnvironment
@ -76,83 +76,67 @@ Cleanup:
return bReturnValue; return bReturnValue;
} }
/** BOOL
* @name _PrinterTableCompareRoutine FindDatatype(PLOCAL_PRINT_PROCESSOR pPrintProcessor, PWSTR pwszDatatype)
*
* 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)
{ {
PLOCAL_PRINT_PROCESSOR A = (PLOCAL_PRINT_PROCESSOR)FirstStruct; DWORD i;
PLOCAL_PRINT_PROCESSOR B = (PLOCAL_PRINT_PROCESSOR)SecondStruct; 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) ++pCurrentDatatype;
return GenericLessThan; }
else if (iResult > 0)
return GenericGreaterThan; return FALSE;
else }
return GenericEqual;
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. * Initializes a singly linked list of locally available Print Processors.
* 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.
*/ */
void void
InitializePrintProcessorTable() InitializePrintProcessorList()
{ {
DWORD cbDatatypes; DWORD cbDatatypes;
DWORD cbFileName; DWORD cbFileName;
DWORD cchPrintProcessorPath; DWORD cchPrintProcessorPath;
DWORD cchMaxSubKey; DWORD cchMaxSubKey;
DWORD cchPrintProcessorName; DWORD cchPrintProcessorName;
DWORD dwDatatypes;
DWORD dwSubKeys; DWORD dwSubKeys;
DWORD i; DWORD i;
DWORD j;
HINSTANCE hinstPrintProcessor; HINSTANCE hinstPrintProcessor;
HKEY hKey = NULL; HKEY hKey = NULL;
HKEY hSubKey = NULL; HKEY hSubKey = NULL;
HKEY hSubSubKey = NULL; HKEY hSubSubKey = NULL;
LONG lStatus; LONG lStatus;
PDATATYPES_INFO_1W pDatatypesInfo1 = NULL;
PLOCAL_PRINT_PROCESSOR pPrintProcessor = NULL; PLOCAL_PRINT_PROCESSOR pPrintProcessor = NULL;
PWSTR pwszDatatype = NULL;
PWSTR pwszPrintProcessorName = NULL; PWSTR pwszPrintProcessorName = NULL;
WCHAR wszFileName[MAX_PATH]; WCHAR wszFileName[MAX_PATH];
WCHAR wszPrintProcessorPath[MAX_PATH]; WCHAR wszPrintProcessorPath[MAX_PATH];
// Initialize an empty table for our Print Processors. // Initialize an empty list for our Print Processors.
// We will search it by Print Processor name. InitializeListHead(&_PrintProcessorList);
RtlInitializeGenericTable(&PrintProcessorTable, _PrintProcessorTableCompareRoutine, GenericTableAllocateRoutine, GenericTableFreeRoutine, NULL);
// Prepare the path to the Print Processor directory. // Prepare the path to the Print Processor directory.
if (!LocalGetPrintProcessorDirectory(NULL, NULL, 1, (PBYTE)wszPrintProcessorPath, sizeof(wszPrintProcessorPath), &cchPrintProcessorPath)) if (!LocalGetPrintProcessorDirectory(NULL, NULL, 1, (PBYTE)wszPrintProcessorPath, sizeof(wszPrintProcessorPath), &cchPrintProcessorPath))
@ -204,16 +188,13 @@ InitializePrintProcessorTable()
if (pPrintProcessor->pwszName) if (pPrintProcessor->pwszName)
DllFreeSplStr(pPrintProcessor->pwszName); DllFreeSplStr(pPrintProcessor->pwszName);
if (pPrintProcessor->pDatatypesInfo1)
DllFreeSplMem(pPrintProcessor->pDatatypesInfo1);
DllFreeSplMem(pPrintProcessor); DllFreeSplMem(pPrintProcessor);
pPrintProcessor = NULL; pPrintProcessor = NULL;
} }
if (pDatatypesInfo1)
{
DllFreeSplMem(pDatatypesInfo1);
pDatatypesInfo1 = NULL;
}
// Get the name of this Print Processor. // Get the name of this Print Processor.
cchPrintProcessorName = cchMaxSubKey; cchPrintProcessorName = cchMaxSubKey;
lStatus = RegEnumKeyExW(hSubKey, i, pwszPrintProcessorName, &cchPrintProcessorName, NULL, NULL, NULL, NULL); lStatus = RegEnumKeyExW(hSubKey, i, pwszPrintProcessorName, &cchPrintProcessorName, NULL, NULL, NULL, NULL);
@ -306,69 +287,47 @@ InitializePrintProcessorTable()
} }
// Get all supported datatypes. // Get all supported datatypes.
pPrintProcessor->pfnEnumPrintProcessorDatatypesW(NULL, NULL, 1, NULL, 0, &cbDatatypes, &dwDatatypes); pPrintProcessor->pfnEnumPrintProcessorDatatypesW(NULL, NULL, 1, NULL, 0, &cbDatatypes, &pPrintProcessor->dwDatatypeCount);
pDatatypesInfo1 = DllAllocSplMem(cbDatatypes); pPrintProcessor->pDatatypesInfo1 = DllAllocSplMem(cbDatatypes);
if (!pDatatypesInfo1) if (!pPrintProcessor->pDatatypesInfo1)
{ {
ERR("DllAllocSplMem failed with error %lu!\n", GetLastError()); ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
goto Cleanup; 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()); ERR("EnumPrintProcessorDatatypesW failed for Print Processor \"%S\" with error %lu!\n", wszPrintProcessorPath, GetLastError());
continue; continue;
} }
// Add the supported datatypes to the datatype table. // Add the Print Processor to the list.
RtlInitializeGenericTable(&pPrintProcessor->DatatypeTable, _DatatypeTableCompareRoutine, GenericTableAllocateRoutine, GenericTableFreeRoutine, NULL); InsertTailList(&_PrintProcessorList, &pPrintProcessor->Entry);
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;
}
// Don't let the cleanup routines free this. // Don't let the cleanup routines free this.
pwszDatatype = NULL;
pPrintProcessor = NULL; pPrintProcessor = NULL;
} }
Cleanup: Cleanup:
if (pwszDatatype) // Inside the loop
DllFreeSplStr(pwszDatatype); if (hSubSubKey)
RegCloseKey(hSubSubKey);
if (pDatatypesInfo1)
DllFreeSplMem(pDatatypesInfo1);
if (pPrintProcessor) if (pPrintProcessor)
{ {
if (pPrintProcessor->pwszName) if (pPrintProcessor->pwszName)
DllFreeSplStr(pPrintProcessor->pwszName); DllFreeSplStr(pPrintProcessor->pwszName);
if (pPrintProcessor->pDatatypesInfo1)
DllFreeSplMem(pPrintProcessor->pDatatypesInfo1);
DllFreeSplMem(pPrintProcessor); DllFreeSplMem(pPrintProcessor);
} }
// Outside the loop
if (pwszPrintProcessorName) if (pwszPrintProcessorName)
DllFreeSplStr(pwszPrintProcessorName); DllFreeSplStr(pwszPrintProcessorName);
if (hSubSubKey)
RegCloseKey(hSubSubKey);
if (hSubKey) if (hSubKey)
RegCloseKey(hSubKey); RegCloseKey(hSubKey);
@ -423,7 +382,7 @@ LocalEnumPrintProcessorDatatypes(LPWSTR pName, LPWSTR pPrintProcessorName, DWORD
} }
// Try to find the Print Processor. // Try to find the Print Processor.
pPrintProcessor = RtlLookupElementGenericTable(&PrintProcessorTable, pPrintProcessorName); pPrintProcessor = FindPrintProcessor(pPrintProcessorName);
if (!pPrintProcessor) if (!pPrintProcessor)
{ {
SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR); SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
@ -499,6 +458,7 @@ LocalEnumPrintProcessors(LPWSTR pName, LPWSTR pEnvironment, DWORD Level, LPBYTE
} }
// Verify pEnvironment and open its registry key. // 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)) if (!_OpenEnvironment(pEnvironment, &hKey))
goto Cleanup; goto Cleanup;

View file

@ -56,25 +56,3 @@ AllocAndRegQueryWSZ(HKEY hKey, PCWSTR pwszValueName)
return pwszValue; 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);
}