mirror of
https://github.com/reactos/reactos.git
synced 2025-08-04 11:06:42 +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)
|
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)
|
||||||
|
|
|
@ -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,14 +156,370 @@ 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));
|
||||||
|
|
||||||
|
Cleanup:
|
||||||
|
// Outside the loop
|
||||||
|
if (hFind)
|
||||||
FindClose(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
|
||||||
ReadJobShadowFile(PCWSTR pwszFilePath)
|
ReadJobShadowFile(PCWSTR pwszFilePath)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
{
|
|
||||||
// We have reached the end of the list without finding the desired Job ID.
|
|
||||||
SetLastError(ERROR_INVALID_PRINTER_NAME);
|
SetLastError(ERROR_INVALID_PRINTER_NAME);
|
||||||
goto Cleanup;
|
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;
|
pPrinterHandle->StartedJob = pJob;
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
pEntry = pEntry->Flink;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue