mirror of
https://github.com/reactos/reactos.git
synced 2025-08-02 05:15:41 +00:00
[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:
parent
a4d50f82ff
commit
9be537abb7
7 changed files with 689 additions and 238 deletions
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include <lmcons.h>
|
||||
#include <rpc.h>
|
||||
#include <windef.h>
|
||||
#include <winbase.h>
|
||||
#include <wingdi.h>
|
||||
|
@ -21,6 +23,8 @@
|
|||
#include <winsplp.h>
|
||||
#include <ndk/rtlfuncs.h>
|
||||
|
||||
#define SKIPLIST_LEVELS 16
|
||||
#include <skiplist.h>
|
||||
#include <spoolss.h>
|
||||
|
||||
#include <wine/debug.h>
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue