Author: cfinck
Date: Thu Jul 16 15:03:47 2015
New Revision: 68405
URL:
http://svn.reactos.org/svn/reactos?rev=68405&view=rev
Log:
[LOCALSPL, WINSPOOL]
Partially implement the whole StartDocPrinter, StartPagePrinter, ReadPrinter,
WritePrinter, EndPagePrinter, EndDocPrinter, ClosePrinter group of functions.
They behave very differently based on whether spooled printing is enabled, whether
it's a local or remote call, etc. Most information was gained by observing callchains
under Windows.
So far, only the spooled path is implemented, the others need more investigation first.
Many other TODOs remain as well, see the comments.
Also make some more comments Doxygen-aware :)
Added:
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/printingthread.c
(with props)
Modified:
branches/colins-printing-for-freedom/reactos/win32ss/printing/base/winspool/jobs.c
branches/colins-printing-for-freedom/reactos/win32ss/printing/base/winspool/main.c
branches/colins-printing-for-freedom/reactos/win32ss/printing/base/winspool/precomp.h
branches/colins-printing-for-freedom/reactos/win32ss/printing/base/winspool/printers.c
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/CMakeLists.txt
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/jobs.c
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/main.c
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/ports.c
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/precomp.h
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/printers.c
Modified:
branches/colins-printing-for-freedom/reactos/win32ss/printing/base/winspool/jobs.c
URL:
http://svn.reactos.org/svn/reactos/branches/colins-printing-for-freedom/rea…
==============================================================================
---
branches/colins-printing-for-freedom/reactos/win32ss/printing/base/winspool/jobs.c [iso-8859-1]
(original)
+++
branches/colins-printing-for-freedom/reactos/win32ss/printing/base/winspool/jobs.c [iso-8859-1]
Thu Jul 16 15:03:47 2015
@@ -61,11 +61,18 @@
{
DWORD dwErrorCode;
PADDJOB_INFO_1W pAddJobInfo1;
-
- // Do the RPC call
- RpcTryExcept
- {
- dwErrorCode = _RpcAddJob(hPrinter, Level, pData, cbBuf, pcbNeeded);
+ PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // Do the RPC call
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcAddJob(pHandle->hPrinter, Level, pData, cbBuf, pcbNeeded);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
@@ -81,6 +88,7 @@
pAddJobInfo1->Path = (PWSTR)((ULONG_PTR)pAddJobInfo1->Path +
(ULONG_PTR)pAddJobInfo1);
}
+Cleanup:
SetLastError(dwErrorCode);
return (dwErrorCode == ERROR_SUCCESS);
}
@@ -98,11 +106,18 @@
DWORD dwErrorCode;
DWORD i;
PBYTE p = pJob;
-
- // Do the RPC call
- RpcTryExcept
- {
- dwErrorCode = _RpcEnumJobs(hPrinter, FirstJob, NoJobs, Level, pJob, cbBuf,
pcbNeeded, pcReturned);
+ PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // Do the RPC call
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcEnumJobs(pHandle->hPrinter, FirstJob, NoJobs, Level, pJob,
cbBuf, pcbNeeded, pcReturned);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
@@ -125,6 +140,7 @@
}
}
+Cleanup:
SetLastError(dwErrorCode);
return (dwErrorCode == ERROR_SUCCESS);
}
@@ -140,11 +156,18 @@
GetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJob, DWORD cbBuf, PDWORD
pcbNeeded)
{
DWORD dwErrorCode;
-
- // Do the RPC call
- RpcTryExcept
- {
- dwErrorCode = _RpcGetJob(hPrinter, JobId, Level, pJob, cbBuf, pcbNeeded);
+ PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // Do the RPC call
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcGetJob(pHandle->hPrinter, JobId, Level, pJob, cbBuf,
pcbNeeded);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
@@ -159,6 +182,7 @@
_MarshallUpJobInfo(pJob, Level);
}
+Cleanup:
SetLastError(dwErrorCode);
return (dwErrorCode == ERROR_SUCCESS);
}
@@ -167,19 +191,27 @@
ScheduleJob(HANDLE hPrinter, DWORD dwJobID)
{
DWORD dwErrorCode;
-
- // Do the RPC call
- RpcTryExcept
- {
- dwErrorCode = _RpcScheduleJob(hPrinter, dwJobID);
- }
- RpcExcept(EXCEPTION_EXECUTE_HANDLER)
- {
- dwErrorCode = RpcExceptionCode();
- ERR("_RpcSetJob failed with exception code %lu!\n", dwErrorCode);
- }
- RpcEndExcept;
-
+ PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // Do the RPC call
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcScheduleJob(pHandle->hPrinter, dwJobID);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcScheduleJob failed with exception code %lu!\n", dwErrorCode);
+ }
+ RpcEndExcept;
+
+Cleanup:
SetLastError(dwErrorCode);
return (dwErrorCode == ERROR_SUCCESS);
}
@@ -195,7 +227,14 @@
SetJobW(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJobInfo, DWORD Command)
{
DWORD dwErrorCode;
+ PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
WINSPOOL_JOB_CONTAINER JobContainer;
+
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
// pJobContainer->JobInfo is a union of pointers, so we can just set any element
to our BYTE pointer.
JobContainer.Level = Level;
@@ -204,7 +243,7 @@
// Do the RPC call
RpcTryExcept
{
- dwErrorCode = _RpcSetJob(hPrinter, JobId, &JobContainer, Command);
+ dwErrorCode = _RpcSetJob(pHandle->hPrinter, JobId, &JobContainer,
Command);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
@@ -213,6 +252,7 @@
}
RpcEndExcept;
- SetLastError(dwErrorCode);
- return (dwErrorCode == ERROR_SUCCESS);
-}
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
Modified:
branches/colins-printing-for-freedom/reactos/win32ss/printing/base/winspool/main.c
URL:
http://svn.reactos.org/svn/reactos/branches/colins-printing-for-freedom/rea…
==============================================================================
---
branches/colins-printing-for-freedom/reactos/win32ss/printing/base/winspool/main.c [iso-8859-1]
(original)
+++
branches/colins-printing-for-freedom/reactos/win32ss/printing/base/winspool/main.c [iso-8859-1]
Thu Jul 16 15:03:47 2015
@@ -6,6 +6,10 @@
*/
#include "precomp.h"
+
+// Global Variables
+HANDLE hProcessHeap;
+
handle_t __RPC_USER
WINSPOOL_HANDLE_bind(WINSPOOL_HANDLE wszName)
@@ -56,13 +60,27 @@
void __RPC_FAR* __RPC_USER
midl_user_allocate(SIZE_T len)
{
- return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
+ return HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, len);
}
void __RPC_USER
midl_user_free(void __RPC_FAR* ptr)
{
- HeapFree(GetProcessHeap(), 0, ptr);
+ HeapFree(hProcessHeap, 0, ptr);
+}
+
+BOOL WINAPI
+DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ DisableThreadLibraryCalls(hinstDLL);
+ hProcessHeap = GetProcessHeap();
+ break;
+ }
+
+ return TRUE;
}
BOOL WINAPI
Modified:
branches/colins-printing-for-freedom/reactos/win32ss/printing/base/winspool/precomp.h
URL:
http://svn.reactos.org/svn/reactos/branches/colins-printing-for-freedom/rea…
==============================================================================
---
branches/colins-printing-for-freedom/reactos/win32ss/printing/base/winspool/precomp.h [iso-8859-1]
(original)
+++
branches/colins-printing-for-freedom/reactos/win32ss/printing/base/winspool/precomp.h [iso-8859-1]
Thu Jul 16 15:03:47 2015
@@ -19,4 +19,20 @@
#include <wine/debug.h>
WINE_DEFAULT_DEBUG_CHANNEL(winspool);
+// Structures
+/*
+ * Describes a handle returned by OpenPrinterW.
+ */
+typedef struct _SPOOLER_HANDLE
+{
+ BOOL bStartedDoc : 1;
+ DWORD dwJobID;
+ HANDLE hPrinter;
+ HANDLE hSPLFile;
+}
+SPOOLER_HANDLE, *PSPOOLER_HANDLE;
+
+// main.c
+extern HANDLE hProcessHeap;
+
#endif
Modified:
branches/colins-printing-for-freedom/reactos/win32ss/printing/base/winspool/printers.c
URL:
http://svn.reactos.org/svn/reactos/branches/colins-printing-for-freedom/rea…
==============================================================================
---
branches/colins-printing-for-freedom/reactos/win32ss/printing/base/winspool/printers.c [iso-8859-1]
(original)
+++
branches/colins-printing-for-freedom/reactos/win32ss/printing/base/winspool/printers.c [iso-8859-1]
Thu Jul 16 15:03:47 2015
@@ -7,6 +7,94 @@
#include "precomp.h"
+static DWORD
+_StartDocPrinterSpooled(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1, PADDJOB_INFO_1W
pAddJobInfo1)
+{
+ DWORD cbNeeded;
+ DWORD dwErrorCode;
+ PJOB_INFO_1W pJobInfo1 = NULL;
+
+ // Create the spool file.
+ pHandle->hSPLFile = CreateFileW(pAddJobInfo1->Path, GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
+ if (pHandle->hSPLFile == INVALID_HANDLE_VALUE)
+ {
+ dwErrorCode = GetLastError();
+ ERR("CreateFileW failed for \"%S\" with error %lu!\n",
pAddJobInfo1->Path, dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Get the size of the job information.
+ GetJobW(pHandle->hPrinter, pAddJobInfo1->JobId, 1, NULL, 0, &cbNeeded);
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ {
+ dwErrorCode = GetLastError();
+ ERR("GetJobW failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Allocate enough memory for the returned job information.
+ pJobInfo1 = HeapAlloc(hProcessHeap, 0, cbNeeded);
+ if (!pJobInfo1)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("HeapAlloc failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // Get the job information.
+ if (!GetJobW(pHandle->hPrinter, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1,
cbNeeded, &cbNeeded))
+ {
+ dwErrorCode = GetLastError();
+ ERR("GetJobW failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Add our document information.
+ pJobInfo1->pDatatype = pDocInfo1->pDatatype;
+ pJobInfo1->pDocument = pDocInfo1->pDocName;
+
+ // Set the new job information.
+ if (!SetJobW(pHandle->hPrinter, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1, 0))
+ {
+ dwErrorCode = GetLastError();
+ ERR("SetJobW failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // We were successful!
+ pHandle->dwJobID = pAddJobInfo1->JobId;
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ if (pJobInfo1)
+ HeapFree(hProcessHeap, 0, pJobInfo1);
+
+ return dwErrorCode;
+}
+
+static DWORD
+_StartDocPrinterWithRPC(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1)
+{
+ DWORD dwErrorCode;
+ WINSPOOL_DOC_INFO_CONTAINER DocInfoContainer;
+
+ DocInfoContainer.Level = 1;
+ DocInfoContainer.DocInfo.pDocInfo1 = (WINSPOOL_DOC_INFO_1*)pDocInfo1;
+
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcStartDocPrinter(pHandle->hPrinter, &DocInfoContainer,
&pHandle->dwJobID);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcStartDocPrinter failed with exception code %lu!\n",
dwErrorCode);
+ }
+ RpcEndExcept;
+
+ return dwErrorCode;
+}
+
BOOL WINAPI
EnumPrintersA(DWORD Flags, LPSTR Name, DWORD Level, LPBYTE pPrinterEnum, DWORD cbBuf,
LPDWORD pcbNeeded, LPDWORD pcReturned)
{
@@ -16,29 +104,60 @@
BOOL WINAPI
EnumPrintersW(DWORD Flags, LPWSTR Name, DWORD Level, LPBYTE pPrinterEnum, DWORD cbBuf,
LPDWORD pcbNeeded, LPDWORD pcReturned)
{
- BOOL bReturnValue = FALSE;
DWORD dwErrorCode;
// Do the RPC call
RpcTryExcept
{
dwErrorCode = _RpcEnumPrinters(Flags, Name, Level, pPrinterEnum, cbBuf,
pcbNeeded, pcReturned);
- SetLastError(dwErrorCode);
- bReturnValue = (dwErrorCode == ERROR_SUCCESS);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
- ERR("_RpcEnumPrinters failed with exception code %lu!\n",
RpcExceptionCode());
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcEnumPrinters failed with exception code %lu!\n",
dwErrorCode);
}
RpcEndExcept;
- return bReturnValue;
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
}
BOOL WINAPI
ClosePrinter(HANDLE hPrinter)
{
- return FALSE;
+ DWORD dwErrorCode;
+ PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // Do the RPC call.
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcClosePrinter(pHandle->hPrinter);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcClosePrinter failed with exception code %lu!\n",
dwErrorCode);
+ }
+ RpcEndExcept;
+
+ // Close any open file handle.
+ if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
+ CloseHandle(pHandle->hSPLFile);
+
+ // Free the memory for the handle.
+ HeapFree(hProcessHeap, 0, pHandle);
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+
}
DWORD WINAPI
@@ -68,13 +187,92 @@
BOOL WINAPI
EndDocPrinter(HANDLE hPrinter)
{
- return FALSE;
+ DWORD dwErrorCode;
+ PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
+ {
+ // For spooled jobs, the document is finished by calling _RpcScheduleJob.
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcScheduleJob(pHandle->hPrinter, pHandle->dwJobID);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcScheduleJob failed with exception code %lu!\n",
dwErrorCode);
+ }
+ RpcEndExcept;
+
+ // Close the spool file handle.
+ CloseHandle(pHandle->hSPLFile);
+ }
+ else
+ {
+ // In all other cases, just call _RpcEndDocPrinter.
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcEndDocPrinter(pHandle->hPrinter);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcEndDocPrinter failed with exception code %lu!\n",
dwErrorCode);
+ }
+ RpcEndExcept;
+ }
+
+ // A new document can now be started again.
+ pHandle->bStartedDoc = FALSE;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
}
BOOL WINAPI
EndPagePrinter(HANDLE hPrinter)
{
- return FALSE;
+ DWORD dwErrorCode;
+ PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
+ {
+ // For spooled jobs, we don't need to do anything.
+ dwErrorCode = ERROR_SUCCESS;
+ }
+ else
+ {
+ // In all other cases, just call _RpcEndPagePrinter.
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcEndPagePrinter(pHandle->hPrinter);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcEndPagePrinter failed with exception code %lu!\n",
dwErrorCode);
+ }
+ RpcEndExcept;
+ }
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
}
BOOL WINAPI
@@ -127,7 +325,7 @@
// Convert pPrinterName to a Unicode string pwszPrinterName
StringLength = strlen(pPrinterName) + 1;
- pwszPrinterName = HeapAlloc(GetProcessHeap(), 0, StringLength * sizeof(WCHAR));
+ pwszPrinterName = HeapAlloc(hProcessHeap, 0, StringLength * sizeof(WCHAR));
if (!pwszPrinterName)
{
ERR("HeapAlloc failed for pwszPrinterName with last error %lu!\n",
GetLastError());
@@ -146,7 +344,7 @@
// Convert pDefault->pDatatype to a Unicode string pwszDatatype that later
becomes wDefault.pDatatype
StringLength = strlen(pDefault->pDatatype) + 1;
- pwszDatatype = HeapAlloc(GetProcessHeap(), 0, StringLength * sizeof(WCHAR));
+ pwszDatatype = HeapAlloc(hProcessHeap, 0, StringLength * sizeof(WCHAR));
if (!pwszDatatype)
{
ERR("HeapAlloc failed for pwszDatatype with last error %lu!\n",
GetLastError());
@@ -165,13 +363,13 @@
Cleanup:
if (wDefault.pDevMode)
- HeapFree(GetProcessHeap(), 0, wDefault.pDevMode);
+ HeapFree(hProcessHeap, 0, wDefault.pDevMode);
if (pwszPrinterName)
- HeapFree(GetProcessHeap(), 0, pwszPrinterName);
+ HeapFree(hProcessHeap, 0, pwszPrinterName);
if (pwszDatatype)
- HeapFree(GetProcessHeap(), 0, pwszDatatype);
+ HeapFree(hProcessHeap, 0, pwszDatatype);
return bReturnValue;
}
@@ -179,8 +377,9 @@
BOOL WINAPI
OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefault)
{
- BOOL bReturnValue = FALSE;
- DWORD dwErrorCode;
+ DWORD dwErrorCode;
+ HANDLE hPrinter;
+ PSPOOLER_HANDLE pHandle;
PWSTR pDatatype = NULL;
WINSPOOL_DEVMODE_CONTAINER DevModeContainer;
WINSPOOL_DEVMODE_CONTAINER* pDevModeContainer = NULL;
@@ -199,41 +398,235 @@
// Do the RPC call
RpcTryExcept
{
- dwErrorCode = _RpcOpenPrinter(pPrinterName, phPrinter, pDatatype,
pDevModeContainer, AccessRequired);
- SetLastError(dwErrorCode);
- bReturnValue = (dwErrorCode == ERROR_SUCCESS);
+ dwErrorCode = _RpcOpenPrinter(pPrinterName, &hPrinter, pDatatype,
pDevModeContainer, AccessRequired);
}
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
{
- ERR("_RpcOpenPrinter failed with exception code %lu!\n",
RpcExceptionCode());
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcOpenPrinter failed with exception code %lu!\n", dwErrorCode);
}
RpcEndExcept;
- return bReturnValue;
+ if (dwErrorCode == ERROR_SUCCESS)
+ {
+ // Create a new SPOOLER_HANDLE structure.
+ pHandle = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(SPOOLER_HANDLE));
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("HeapAlloc failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ pHandle->hPrinter = hPrinter;
+ pHandle->hSPLFile = INVALID_HANDLE_VALUE;
+
+ // Return it as phPrinter.
+ *phPrinter = (HANDLE)pHandle;
+ }
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
}
BOOL WINAPI
ReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead)
{
- return FALSE;
+ DWORD dwErrorCode;
+ PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // Do the RPC call
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcReadPrinter(pHandle->hPrinter, pBuf, cbBuf, pNoBytesRead);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcReadPrinter failed with exception code %lu!\n", dwErrorCode);
+ }
+ RpcEndExcept;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
}
DWORD WINAPI
-StartDocPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
-{
- return 0;
+StartDocPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
+{
+ DWORD cbAddJobInfo1;
+ DWORD cbNeeded;
+ DWORD dwErrorCode;
+ PADDJOB_INFO_1W pAddJobInfo1 = NULL;
+ PDOC_INFO_1W pDocInfo1 = (PDOC_INFO_1W)pDocInfo;
+ PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ if (!pDocInfo1)
+ {
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ if (Level != 1)
+ {
+ dwErrorCode = ERROR_INVALID_LEVEL;
+ goto Cleanup;
+ }
+
+ if (pHandle->bStartedDoc)
+ {
+ dwErrorCode = ERROR_INVALID_PRINTER_STATE;
+ goto Cleanup;
+ }
+
+ // Check if we want to redirect output into a file.
+ if (pDocInfo1->pOutputFile)
+ {
+ // Do a StartDocPrinter RPC call in this case.
+ dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1);
+ }
+ else
+ {
+ // Allocate memory for the ADDJOB_INFO_1W structure and a path.
+ cbAddJobInfo1 = sizeof(ADDJOB_INFO_1W) + MAX_PATH * sizeof(WCHAR);
+ pAddJobInfo1 = HeapAlloc(hProcessHeap, 0, cbAddJobInfo1);
+ if (!pAddJobInfo1)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("HeapAlloc failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // Try to add a new job.
+ // This only succeeds if the printer is set to do spooled printing.
+ if (AddJobW(pHandle->hPrinter, 1, (PBYTE)pAddJobInfo1, cbAddJobInfo1,
&cbNeeded))
+ {
+ // Do spooled printing.
+ dwErrorCode = _StartDocPrinterSpooled(pHandle, pDocInfo1, pAddJobInfo1);
+ }
+ else if (GetLastError() == ERROR_INVALID_ACCESS)
+ {
+ // ERROR_INVALID_ACCESS is returned when the printer is set to do direct
printing.
+ // In this case, we do a StartDocPrinter RPC call.
+ dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1);
+ }
+ else
+ {
+ dwErrorCode = GetLastError();
+ ERR("AddJobW failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+ }
+
+ if (dwErrorCode == ERROR_SUCCESS)
+ pHandle->bStartedDoc = TRUE;
+
+Cleanup:
+ if (pAddJobInfo1)
+ HeapFree(hProcessHeap, 0, pAddJobInfo1);
+
+ SetLastError(dwErrorCode);
+ return pHandle->dwJobID;
}
BOOL WINAPI
StartPagePrinter(HANDLE hPrinter)
{
- return FALSE;
-}
-
-BOOL WINAPI
-WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
-{
- return FALSE;
+ DWORD dwErrorCode;
+ PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // Do the RPC call
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcStartPagePrinter(pHandle->hPrinter);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcStartPagePrinter failed with exception code %lu!\n",
dwErrorCode);
+ }
+ RpcEndExcept;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
+BOOL WINAPI
+WritePrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten)
+{
+ DWORD dwErrorCode;
+ PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ if (!pHandle->bStartedDoc)
+ {
+ dwErrorCode = ERROR_SPL_NO_STARTDOC;
+ goto Cleanup;
+ }
+
+ if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
+ {
+ // Write to the spool file. This doesn't need an RPC request.
+ if (!WriteFile(pHandle->hSPLFile, pBuf, cbBuf, pcWritten, NULL))
+ {
+ dwErrorCode = GetLastError();
+ ERR("WriteFile failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ dwErrorCode = ERROR_SUCCESS;
+ }
+ else
+ {
+ // TODO: This case (for direct printing or remote printing) has bad performance
if multiple small-sized WritePrinter calls are performed.
+ // We may increase performance by writing into a buffer and only doing a single
RPC call when the buffer is full.
+
+ // Do the RPC call
+ RpcTryExcept
+ {
+ dwErrorCode = _RpcWritePrinter(pHandle->hPrinter, pBuf, cbBuf,
pcWritten);
+ }
+ RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+ {
+ dwErrorCode = RpcExceptionCode();
+ ERR("_RpcWritePrinter failed with exception code %lu!\n",
dwErrorCode);
+ }
+ RpcEndExcept;
+ }
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
}
BOOL WINAPI
Modified:
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/branches/colins-printing-for-freedom/rea…
==============================================================================
---
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/CMakeLists.txt [iso-8859-1]
(original)
+++
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/CMakeLists.txt [iso-8859-1]
Thu Jul 16 15:03:47 2015
@@ -10,6 +10,7 @@
ports.c
precomp.h
printers.c
+ printingthread.c
printprocessors.c
tools.c)
Modified:
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/jobs.c
URL:
http://svn.reactos.org/svn/reactos/branches/colins-printing-for-freedom/rea…
==============================================================================
---
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/jobs.c [iso-8859-1]
(original)
+++
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/jobs.c [iso-8859-1]
Thu Jul 16 15:03:47 2015
@@ -13,6 +13,27 @@
// Local Variables
static DWORD _dwLastJobID;
+
+static 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;
+}
/**
* @name _GlobalJobListCompareRoutine
@@ -81,25 +102,23 @@
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;
+DWORD
+GetJobFilePath(PCWSTR pwszExtension, DWORD dwJobID, PWSTR pwszOutput)
+{
+ const WCHAR wszPrintersPath[] = L"\\PRINTERS\\";
+ const DWORD cchPrintersPath = _countof(wszPrintersPath) - 1;
+ const DWORD cchSpoolerFile = sizeof("?????.") - 1;
+ const DWORD cchExtension = sizeof("SPL") - 1; //
pwszExtension may be L"SPL" or L"SHD", same length for both!
+
+ if (pwszOutput)
+ {
+ CopyMemory(pwszOutput, wszSpoolDirectory, cchSpoolDirectory);
+ CopyMemory(&pwszOutput[cchSpoolDirectory], wszPrintersPath,
cchPrintersPath);
+ swprintf(&pwszOutput[cchSpoolDirectory + cchPrintersPath],
L"%05lu.", dwJobID);
+ CopyMemory(&pwszOutput[cchSpoolDirectory + cchPrintersPath + cchSpoolerFile],
pwszExtension, (cchExtension + 1) * sizeof(WCHAR));
+ }
+
+ return (cchSpoolDirectory + cchPrintersPath + cchSpoolerFile + cchExtension + 1) *
sizeof(WCHAR);
}
BOOL
@@ -107,8 +126,6 @@
{
const WCHAR wszPath[] = L"\\PRINTERS\\?????.SHD";
const DWORD cchPath = _countof(wszPath) - 1;
- const DWORD cchFolders = sizeof("\\PRINTERS\\") - 1;
- const DWORD cchPattern = sizeof("?????") - 1;
DWORD dwErrorCode;
DWORD dwJobID;
@@ -118,7 +135,7 @@
WCHAR wszFullPath[MAX_PATH];
WIN32_FIND_DATAW FindData;
- // This one is incremented in GetNextJobID.
+ // This one is incremented in _GetNextJobID.
_dwLastJobID = 0;
// Initialize an empty list for all jobs of all local printers.
@@ -145,6 +162,7 @@
continue;
// Extract the Job ID and verify the file name format at the same time.
+ // This includes all valid names (like "00005.SHD") and excludes
invalid ones (like "10ABC.SHD").
dwJobID = wcstoul(FindData.cFileName, &p, 10);
if (!IS_VALID_JOB_ID(dwJobID))
continue;
@@ -153,7 +171,7 @@
continue;
// This shadow file has a valid name. Construct the full path and try to load
it.
- CopyMemory(&wszFullPath[cchSpoolDirectory + cchFolders], FindData.cFileName,
cchPattern);
+ GetJobFilePath(L"SHD", dwJobID, wszFullPath);
pJob = ReadJobShadowFile(wszFullPath);
if (!pJob)
continue;
@@ -195,78 +213,31 @@
InitializeSkiplist(&pPrinter->JobList, DllAllocSplMem,
_PrinterJobListCompareRoutine, (PSKIPLIST_FREE_ROUTINE)DllFreeSplMem);
}
-BOOL WINAPI
-LocalAddJob(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD pcbNeeded)
+DWORD WINAPI
+CreateJob(PLOCAL_PRINTER_HANDLE pPrinterHandle)
{
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;
+
DWORD cchMachineName;
DWORD cchUserName;
DWORD dwErrorCode;
- PBYTE p;
- PLOCAL_HANDLE pHandle;
PLOCAL_JOB pJob;
- PLOCAL_PRINTER_HANDLE pPrinterHandle;
RPC_BINDING_HANDLE hServerBinding = NULL;
RPC_WSTR pwszBinding = NULL;
RPC_WSTR pwszMachineName = NULL;
- // Check if this is a printer handle.
- pHandle = (PLOCAL_HANDLE)hPrinter;
- if (pHandle->HandleType != HandleType_Printer)
- {
- dwErrorCode = ERROR_INVALID_HANDLE;
- goto Cleanup;
- }
-
- pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
-
- // This handle must not have started a job yet!
- if (pPrinterHandle->pStartedJob)
- {
- dwErrorCode = ERROR_INVALID_HANDLE;
- goto Cleanup;
- }
-
- // Check if this is the right structure level.
- if (Level != 1)
- {
- dwErrorCode = ERROR_INVALID_LEVEL;
- goto Cleanup;
- }
-
- // Check if the printer is set to do direct printing.
- // The Job List isn't used in this case.
- if (pPrinterHandle->pPrinter->dwAttributes & PRINTER_ATTRIBUTE_DIRECT)
- {
- dwErrorCode = ERROR_INVALID_ACCESS;
- goto Cleanup;
- }
-
- // Check if the supplied buffer is large enough.
- *pcbNeeded = sizeof(ADDJOB_INFO_1W) + (cchSpoolDirectory + cchPrintersPath + cchSpl +
1) * sizeof(WCHAR);
- if (cbBuf < *pcbNeeded)
- {
- dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
- goto Cleanup;
- }
-
// Create a new job.
pJob = DllAllocSplMem(sizeof(LOCAL_JOB));
if (!pJob)
{
- dwErrorCode = GetLastError();
- ERR("DllAllocSplMem failed with error %lu!\n", dwErrorCode);
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
goto Cleanup;
}
// Reserve an ID for this job.
- if (!GetNextJobID(&pJob->dwJobID))
+ if (!_GetNextJobID(&pJob->dwJobID))
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
@@ -339,21 +310,18 @@
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);
-
+ // We were successful!
+ pPrinterHandle->bStartedDoc = TRUE;
+ pPrinterHandle->pJob = pJob;
dwErrorCode = ERROR_SUCCESS;
+ // Don't let the cleanup routine free this.
+ pJob = NULL;
+
Cleanup:
+ if (pJob)
+ DllFreeSplMem(pJob);
+
if (pwszMachineName)
RpcStringFreeW(&pwszMachineName);
@@ -363,6 +331,72 @@
if (hServerBinding)
RpcBindingFree(&hServerBinding);
+ return dwErrorCode;
+}
+
+BOOL WINAPI
+LocalAddJob(HANDLE hPrinter, DWORD Level, PBYTE pData, DWORD cbBuf, PDWORD pcbNeeded)
+{
+ ADDJOB_INFO_1W AddJobInfo1;
+ DWORD dwErrorCode;
+ PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
+ PLOCAL_PRINTER_HANDLE pPrinterHandle;
+
+ // Check if this is a printer handle.
+ if (pHandle->HandleType != HandleType_Printer)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
+
+ // This handle must not have started a job yet!
+ if (pPrinterHandle->pJob)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // Check if this is the right structure level.
+ if (Level != 1)
+ {
+ dwErrorCode = ERROR_INVALID_LEVEL;
+ goto Cleanup;
+ }
+
+ // Check if the printer is set to do direct printing.
+ // The Job List isn't used in this case.
+ if (pPrinterHandle->pPrinter->dwAttributes & PRINTER_ATTRIBUTE_DIRECT)
+ {
+ dwErrorCode = ERROR_INVALID_ACCESS;
+ goto Cleanup;
+ }
+
+ // Check if the supplied buffer is large enough.
+ *pcbNeeded = sizeof(ADDJOB_INFO_1W) + GetJobFilePath(L"SPL", 0, NULL);
+ if (cbBuf < *pcbNeeded)
+ {
+ dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
+ goto Cleanup;
+ }
+
+ // All requirements are met - create a new job.
+ dwErrorCode = CreateJob(pPrinterHandle);
+ if (dwErrorCode != ERROR_SUCCESS)
+ goto Cleanup;
+
+ // Mark that this job was started with AddJob (so that it can be scheduled for
printing with ScheduleJob).
+ pPrinterHandle->pJob->bAddedJob = TRUE;
+
+ // Return a proper ADDJOB_INFO_1W structure.
+ AddJobInfo1.JobId = pPrinterHandle->pJob->dwJobID;
+ AddJobInfo1.Path = (PWSTR)(pData + sizeof(ADDJOB_INFO_1W));
+
+ CopyMemory(pData, &AddJobInfo1, sizeof(ADDJOB_INFO_1W));
+ GetJobFilePath(L"SPL", AddJobInfo1.JobId, AddJobInfo1.Path);
+
+Cleanup:
SetLastError(dwErrorCode);
return (dwErrorCode == ERROR_SUCCESS);
}
@@ -842,9 +876,6 @@
BOOL WINAPI
LocalSetJob(HANDLE hPrinter, DWORD JobId, DWORD Level, PBYTE pJobInfo, DWORD Command)
{
- const WCHAR wszFolder[] = L"\\PRINTERS\\";
- const DWORD cchFolder = _countof(wszFolder) - 1;
-
DWORD dwErrorCode;
PLOCAL_HANDLE pHandle;
PLOCAL_JOB pJob;
@@ -883,18 +914,34 @@
if (dwErrorCode != ERROR_SUCCESS)
goto Cleanup;
- // Construct the full path to the shadow file.
- CopyMemory(wszFullPath, wszSpoolDirectory, cchSpoolDirectory * sizeof(WCHAR));
- CopyMemory(&wszFullPath[cchSpoolDirectory], wszFolder, cchFolder *
sizeof(WCHAR));
- swprintf(&wszFullPath[cchSpoolDirectory + cchFolder], L"%05lu.SHD",
JobId);
-
- // Write the job data into the shadow file.
- WriteJobShadowFile(wszFullPath, pJob);
+ // If we do spooled printing, the job information is written down into a shadow
file.
+ if (!(pPrinterHandle->pPrinter->dwAttributes & PRINTER_ATTRIBUTE_DIRECT))
+ {
+ // Write the job data into the shadow file.
+ GetJobFilePath(L"SHD", JobId, wszFullPath);
+ WriteJobShadowFile(wszFullPath, pJob);
+ }
// Perform an additional command if desired.
if (Command)
{
- // TODO
+ if (Command == JOB_CONTROL_SENT_TO_PRINTER)
+ {
+ // This indicates the end of the Print Job.
+
+ // Cancel the Job at the Print Processor.
+ if (pJob->hPrintProcessor)
+
pJob->pPrintProcessor->pfnControlPrintProcessor(pJob->hPrintProcessor,
JOB_CONTROL_CANCEL);
+
+ FreeJob(pJob);
+
+ // TODO: All open handles associated with the job need to be invalidated.
+ // This certainly needs handle tracking...
+ }
+ else
+ {
+ ERR("Unimplemented SetJob Command: %lu!\n", Command);
+ }
}
dwErrorCode = ERROR_SUCCESS;
@@ -1003,18 +1050,15 @@
BOOL WINAPI
LocalScheduleJob(HANDLE hPrinter, DWORD dwJobID)
{
- const WCHAR wszFolder[] = L"\\PRINTERS\\";
- const DWORD cchFolder = _countof(wszFolder) - 1;
-
DWORD dwAttributes;
DWORD dwErrorCode;
- PLOCAL_HANDLE pHandle;
+ HANDLE hThread;
PLOCAL_JOB pJob;
+ PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
PLOCAL_PRINTER_HANDLE pPrinterHandle;
WCHAR wszFullPath[MAX_PATH];
// Check if this is a printer handle.
- pHandle = (PLOCAL_HANDLE)hPrinter;
if (pHandle->HandleType != HandleType_Printer)
{
dwErrorCode = ERROR_INVALID_HANDLE;
@@ -1031,10 +1075,15 @@
goto Cleanup;
}
+ // Check if this Job was started with AddJob.
+ if (!pJob->bAddedJob)
+ {
+ dwErrorCode = ERROR_SPL_NO_ADDJOB;
+ goto Cleanup;
+ }
+
// Construct the full path to the spool file.
- CopyMemory(wszFullPath, wszSpoolDirectory, cchSpoolDirectory * sizeof(WCHAR));
- CopyMemory(&wszFullPath[cchSpoolDirectory], wszFolder, cchFolder *
sizeof(WCHAR));
- swprintf(&wszFullPath[cchSpoolDirectory + cchFolder], L"%05lu.SPL",
dwJobID);
+ GetJobFilePath(L"SPL", dwJobID, wszFullPath);
// Check if it exists.
dwAttributes = GetFileAttributesW(wszFullPath);
@@ -1052,6 +1101,19 @@
wcscpy(wcsrchr(wszFullPath, L'.'), L".SHD");
WriteJobShadowFile(wszFullPath, pJob);
+ // Create the thread for performing the printing process.
+ hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PrintingThreadProc, pJob, 0,
NULL);
+ if (!hThread)
+ {
+ dwErrorCode = GetLastError();
+ ERR("CreateThread failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // We don't need the thread handle. Keeping it open blocks the thread from
terminating.
+ CloseHandle(hThread);
+
+ // ScheduleJob has done its job. The rest happens inside the thread.
dwErrorCode = ERROR_SUCCESS;
Cleanup:
@@ -1134,7 +1196,7 @@
pJob->dwPriority = pShadowFile->dwPriority;
pJob->dwStartTime = pShadowFile->dwStartTime;
pJob->dwTotalPages = pShadowFile->dwTotalPages;
- pJob->dwUntilTime = pShadowFile->dwUntilTime;
+ pJob->dwUntilTime = pShadowFile->dwUntilTime;
pJob->pPrinter = pPrinter;
pJob->pPrintProcessor = pPrintProcessor;
pJob->pDevMode = DuplicateDevMode((PDEVMODEW)((ULONG_PTR)pShadowFile +
pShadowFile->offDevMode));
@@ -1148,6 +1210,9 @@
pJob->pwszUserName = AllocSplStr((PCWSTR)((ULONG_PTR)pShadowFile +
pShadowFile->offUserName));
CopyMemory(&pJob->stSubmitted, &pShadowFile->stSubmitted,
sizeof(SYSTEMTIME));
+
+ // Jobs read from shadow files were always added using AddJob.
+ pJob->bAddedJob = TRUE;
pReturnValue = pJob;
@@ -1303,15 +1368,38 @@
return bReturnValue;
}
-BOOL
+void
FreeJob(PLOCAL_JOB pJob)
{
- ////////// TODO /////////
- /// Add some checks
+ PWSTR pwszSHDFile;
+
+ // Remove the Job from both Job Lists.
+ DeleteElementSkiplist(&pJob->pPrinter->JobList, pJob);
+ DeleteElementSkiplist(&GlobalJobList, pJob);
+
+ // Try to delete the corresponding .SHD file.
+ pwszSHDFile = DllAllocSplMem(GetJobFilePath(L"SHD", 0, NULL));
+ if (pwszSHDFile && GetJobFilePath(L"SHD", pJob->dwJobID,
pwszSHDFile))
+ DeleteFileW(pwszSHDFile);
+
+ // Free memory for the mandatory fields.
+ DllFreeSplMem(pJob->pDevMode);
DllFreeSplStr(pJob->pwszDatatype);
DllFreeSplStr(pJob->pwszDocumentName);
- DllFreeSplStr(pJob->pwszOutputFile);
+ DllFreeSplStr(pJob->pwszMachineName);
+ DllFreeSplStr(pJob->pwszNotifyName);
+ DllFreeSplStr(pJob->pwszUserName);
+
+ // Free memory for the optional fields if they are present.
+ if (pJob->pwszOutputFile)
+ DllFreeSplStr(pJob->pwszOutputFile);
+
+ if (pJob->pwszPrintProcessorParameters)
+ DllFreeSplStr(pJob->pwszPrintProcessorParameters);
+
+ if (pJob->pwszStatus)
+ DllFreeSplStr(pJob->pwszStatus);
+
+ // Finally free the job structure itself.
DllFreeSplMem(pJob);
-
- return TRUE;
-}
+}
Modified:
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/main.c
URL:
http://svn.reactos.org/svn/reactos/branches/colins-printing-for-freedom/rea…
==============================================================================
---
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/main.c [iso-8859-1]
(original)
+++
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/main.c [iso-8859-1]
Thu Jul 16 15:03:47 2015
@@ -59,7 +59,7 @@
LocalWritePrinter, // fpWritePrinter
LocalEndPagePrinter, // fpEndPagePrinter
NULL, // fpAbortPrinter
- NULL, // fpReadPrinter
+ LocalReadPrinter, // fpReadPrinter
LocalEndDocPrinter, // fpEndDocPrinter
LocalAddJob, // fpAddJob
LocalScheduleJob, // fpScheduleJob
Modified:
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/ports.c
URL:
http://svn.reactos.org/svn/reactos/branches/colins-printing-for-freedom/rea…
==============================================================================
---
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/ports.c [iso-8859-1]
(original)
+++
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/ports.c [iso-8859-1]
Thu Jul 16 15:03:47 2015
@@ -11,8 +11,8 @@
static LIST_ENTRY _PortList;
-PLOCAL_PRINT_MONITOR
-FindPrintMonitorByPort(PCWSTR pwszName)
+PLOCAL_PORT
+FindPort(PCWSTR pwszName)
{
PLIST_ENTRY pEntry;
PLOCAL_PORT pPort;
@@ -22,7 +22,7 @@
pPort = CONTAINING_RECORD(pEntry, LOCAL_PORT, Entry);
if (_wcsicmp(pPort->pwszName, pwszName) == 0)
- return pPort->pPrintMonitor;
+ return pPort;
}
return NULL;
Modified:
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/precomp.h
URL:
http://svn.reactos.org/svn/reactos/branches/colins-printing-for-freedom/rea…
==============================================================================
---
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/precomp.h [iso-8859-1]
(original)
+++
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/precomp.h [iso-8859-1]
Thu Jul 16 15:03:47 2015
@@ -49,6 +49,32 @@
typedef LPMONITOR2(WINAPI *PInitializePrintMonitor2)(PMONITORINIT, PHANDLE);
// Structures
+/**
+ * Describes a Print Monitor.
+ */
+typedef struct _LOCAL_PRINT_MONITOR
+{
+ LIST_ENTRY Entry;
+ PWSTR pwszName; /** Name of the Print Monitor as read from the
registry. */
+ PWSTR pwszFileName; /** DLL File Name of the Print Monitor. */
+ BOOL bIsLevel2; /** Whether this Print Monitor supplies an
InitializePrintMonitor2 API (preferred) instead of InitializePrintMonitor. */
+ PVOID pMonitor; /** For bIsLevel2 == TRUE: LPMONITOR2 pointer
returned by InitializePrintMonitor2.
+ For bIsLevel2 == FALSE: LPMONITOREX pointer
returned by InitializePrintMonitor. */
+ HANDLE hMonitor; /** Only used when bIsLevel2 == TRUE: Handle
returned by InitializePrintMonitor2. */
+}
+LOCAL_PRINT_MONITOR, *PLOCAL_PRINT_MONITOR;
+
+/**
+ * Describes a Port handled by a Print Monitor.
+ */
+typedef struct _LOCAL_PORT
+{
+ LIST_ENTRY Entry;
+ PWSTR pwszName; /** The name of the port (including the
trailing colon). */
+ PLOCAL_PRINT_MONITOR pPrintMonitor; /** The Print Monitor handling this port. */
+}
+LOCAL_PORT, *PLOCAL_PORT;
+
/**
* Describes a Print Processor.
*/
@@ -83,6 +109,7 @@
PWSTR pwszDefaultDatatype;
PDEVMODEW pDefaultDevMode;
PLOCAL_PRINT_PROCESSOR pPrintProcessor;
+ PLOCAL_PORT pPort;
SKIPLIST JobList;
}
LOCAL_PRINTER, *PLOCAL_PRINTER;
@@ -94,26 +121,28 @@
typedef struct _LOCAL_JOB
{
// This sort key must be the first element for LookupElementSkiplist to work!
- DWORD dwJobID; // Internal and external ID of this Job
-
- PLOCAL_PRINTER pPrinter; // Associated Printer to this Job
- PLOCAL_PRINT_PROCESSOR pPrintProcessor; // Associated Print Processor 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
- PWSTR pwszPrintProcessorParameters; // Optional; Parameters for the chosen
Print Processor
- PWSTR pwszStatus; // Optional; a Status Message for the
Job
- 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)
- PDEVMODEW pDevMode; // Associated Device Mode to this Job
+ DWORD dwJobID; /** Internal and external ID of this Job
*/
+
+ BOOL bAddedJob : 1; /** Whether AddJob has already been
called on this Job. */
+ HANDLE hPrintProcessor; /** Handle returned by OpenPrintProcessor
while the Job is printing. */
+ PLOCAL_PRINTER pPrinter; /** Associated Printer to this Job */
+ PLOCAL_PRINT_PROCESSOR pPrintProcessor; /** Associated Print Processor 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 */
+ PWSTR pwszPrintProcessorParameters; /** Optional; Parameters for the chosen
Print Processor */
+ PWSTR pwszStatus; /** Optional; a Status Message for the
Job */
+ 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) */
+ PDEVMODEW pDevMode; /** Associated Device Mode to this Job
*/
}
LOCAL_JOB, *PLOCAL_JOB;
@@ -126,8 +155,10 @@
*/
typedef struct _LOCAL_PRINTER_HANDLE
{
+ BOOL bStartedDoc : 1; /** Whether StartDocPrinter has already
been called. */
+ HANDLE hSPLFile; /** Handle to an opened SPL file for
Printer Job handles. */
PLOCAL_PRINTER pPrinter;
- PLOCAL_JOB pStartedJob;
+ PLOCAL_JOB pJob;
PWSTR pwszDatatype;
PDEVMODEW pDevMode;
}
@@ -148,32 +179,6 @@
PVOID pSpecificHandle;
}
LOCAL_HANDLE, *PLOCAL_HANDLE;
-
-/**
- * Describes a Print Monitor.
- */
-typedef struct _LOCAL_PRINT_MONITOR
-{
- LIST_ENTRY Entry;
- PWSTR pwszName; /** Name of the Print Monitor as read from the
registry. */
- PWSTR pwszFileName; /** DLL File Name of the Print Monitor. */
- BOOL bIsLevel2; /** Whether this Print Monitor supplies an
InitializePrintMonitor2 API (preferred) instead of InitializePrintMonitor. */
- PVOID pMonitor; /** For bIsLevel2 == TRUE: LPMONITOR2 pointer
returned by InitializePrintMonitor2.
- For bIsLevel2 == FALSE: LPMONITOREX pointer
returned by InitializePrintMonitor. */
- HANDLE hMonitor; /** Only used when bIsLevel2 == TRUE: Handle
returned by InitializePrintMonitor2. */
-}
-LOCAL_PRINT_MONITOR, *PLOCAL_PRINT_MONITOR;
-
-/**
- * Describes a Port handled by a Print Monitor.
- */
-typedef struct _LOCAL_PORT
-{
- LIST_ENTRY Entry;
- PWSTR pwszName; /** The name of the port (including the
trailing colon). */
- PLOCAL_PRINT_MONITOR pPrintMonitor; /** The Print Monitor handling this port. */
-}
-LOCAL_PORT, *PLOCAL_PORT;
/**
* Describes the header of a print job serialized into a shadow file (.SHD)
@@ -213,10 +218,11 @@
}
SHD_HEADER, *PSHD_HEADER;
-
// jobs.c
extern SKIPLIST GlobalJobList;
-BOOL GetNextJobID(PDWORD dwJobID);
+DWORD WINAPI CreateJob(PLOCAL_PRINTER_HANDLE pPrinterHandle);
+void FreeJob(PLOCAL_JOB pJob);
+DWORD GetJobFilePath(PCWSTR pwszExtension, DWORD dwJobID, PWSTR pwszOutput);
BOOL InitializeGlobalJobList();
void InitializePrinterJobList(PLOCAL_PRINTER pPrinter);
BOOL WINAPI LocalAddJob(HANDLE hPrinter, DWORD Level, LPBYTE pData, DWORD cbBuf, LPDWORD
pcbNeeded);
@@ -242,7 +248,7 @@
BOOL WINAPI LocalEnumMonitors(PWSTR pName, DWORD Level, PBYTE pMonitors, DWORD cbBuf,
PDWORD pcbNeeded, PDWORD pcReturned);
// ports.c
-PLOCAL_PRINT_MONITOR FindPrintMonitorByPort(PCWSTR pwszName);
+PLOCAL_PORT FindPort(PCWSTR pwszName);
BOOL InitializePortList();
BOOL WINAPI LocalEnumPorts(PWSTR pName, DWORD Level, PBYTE pPorts, DWORD cbBuf, PDWORD
pcbNeeded, PDWORD pcReturned);
@@ -251,12 +257,16 @@
BOOL 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);
+BOOL WINAPI LocalReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD
pNoBytesRead);
DWORD WINAPI LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo);
BOOL WINAPI LocalStartPagePrinter(HANDLE hPrinter);
BOOL WINAPI LocalWritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD
pcWritten);
BOOL WINAPI LocalEndPagePrinter(HANDLE hPrinter);
BOOL WINAPI LocalEndDocPrinter(HANDLE hPrinter);
BOOL WINAPI LocalClosePrinter(HANDLE hPrinter);
+
+// printingthread.c
+DWORD WINAPI PrintingThreadProc(PLOCAL_JOB pJob);
// printprocessors.c
BOOL FindDatatype(const PLOCAL_PRINT_PROCESSOR pPrintProcessor, PCWSTR pwszDatatype);
Modified:
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/printers.c
URL:
http://svn.reactos.org/svn/reactos/branches/colins-printing-for-freedom/rea…
==============================================================================
---
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/printers.c [iso-8859-1]
(original)
+++
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/printers.c [iso-8859-1]
Thu Jul 16 15:03:47 2015
@@ -45,8 +45,10 @@
DWORD i;
HKEY hKey = NULL;
HKEY hSubKey = NULL;
+ PLOCAL_PORT pPort;
PLOCAL_PRINTER pPrinter = NULL;
PLOCAL_PRINT_PROCESSOR pPrintProcessor;
+ PWSTR pwszPort = NULL;
PWSTR pwszPrintProcessor = NULL;
WCHAR wszPrinterName[MAX_PRINTER_NAME + 1];
@@ -138,6 +140,19 @@
if (!pPrintProcessor)
{
ERR("Invalid Print Processor \"%S\" for Printer
\"%S\"!\n", pwszPrintProcessor, wszPrinterName);
+ continue;
+ }
+
+ // Get the Port.
+ pwszPort = AllocAndRegQueryWSZ(hSubKey, L"Port");
+ if (!pwszPort)
+ continue;
+
+ // Try to find it in the Port List.
+ pPort = FindPort(pwszPort);
+ if (!pPort)
+ {
+ ERR("Invalid Port \"%S\" for Printer
\"%S\"!\n", pwszPort, wszPrinterName);
continue;
}
@@ -488,10 +503,12 @@
PWSTR pwszSecondParameter = NULL;
PLOCAL_JOB pJob;
PLOCAL_HANDLE pHandle = NULL;
+ PLOCAL_PORT pPort;
PLOCAL_PRINT_MONITOR pPrintMonitor;
PLOCAL_PRINTER pPrinter;
PLOCAL_PRINTER_HANDLE pPrinterHandle = NULL;
WCHAR wszComputerName[MAX_COMPUTERNAME_LENGTH + 1];
+ WCHAR wszFullPath[MAX_PATH];
// TODO: lpPrinterName == NULL is supported and means access to the local printer
server.
// Not sure yet if that is passed down to localspl.dll or processed in advance.
@@ -502,6 +519,8 @@
dwErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
+
+ *phPrinter = NULL;
// Skip any server name in the first parameter.
// Does lpPrinterName begin with two backslashes to indicate a server name?
@@ -592,13 +611,15 @@
// "\\COMPUTERNAME\LPT1:, Port"
// Look for this port in our Print Monitor Port list.
- pPrintMonitor = FindPrintMonitorByPort(pwszFirstParameter);
- if (!pPrintMonitor)
+ pPort = FindPort(pwszFirstParameter);
+ if (!pPort)
{
// The supplied port is unknown to all our Print Monitors.
dwErrorCode = ERROR_INVALID_PRINTER_NAME;
goto Cleanup;
}
+
+ pPrintMonitor = pPort->pPrintMonitor;
// Call the monitor's OpenPort function.
if (pPrintMonitor->bIsLevel2)
@@ -649,13 +670,15 @@
pwszSecondParameter += 5;
// Look for this port in our Print Monitor Port list.
- pPrintMonitor = FindPrintMonitorByPort(pwszSecondParameter);
- if (!pPrintMonitor)
+ pPort = FindPort(pwszFirstParameter);
+ if (!pPort)
{
// The supplied port is unknown to all our Print Monitors.
dwErrorCode = ERROR_INVALID_PRINTER_NAME;
goto Cleanup;
}
+
+ pPrintMonitor = pPort->pPrintMonitor;
}
else
{
@@ -706,6 +729,7 @@
goto Cleanup;
}
+ pPrinterHandle->hSPLFile = INVALID_HANDLE_VALUE;
pPrinterHandle->pPrinter = pPrinter;
// Check if a datatype was given.
@@ -732,7 +756,7 @@
else
pPrinterHandle->pDevMode =
DuplicateDevMode(pPrinter->pDefaultDevMode);
- // Check if the caller wants a handle to an existing job.
+ // Check if the caller wants a handle to an existing Print Job.
if (pwszSecondParameter)
{
// The "Job " string has to follow now.
@@ -767,7 +791,19 @@
goto Cleanup;
}
- pPrinterHandle->pStartedJob = pJob;
+ // Try to open its SPL file.
+ GetJobFilePath(L"SPL", dwJobID, wszFullPath);
+ pPrinterHandle->hSPLFile = CreateFileW(wszFullPath, GENERIC_READ |
GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+ if (pPrinterHandle->hSPLFile == INVALID_HANDLE_VALUE)
+ {
+ dwErrorCode = GetLastError();
+ ERR("CreateFileW failed with error %lu for \"%S\"!",
dwErrorCode, wszFullPath);
+ goto Cleanup;
+ }
+
+ // Associate the job to our Printer Handle, but don't set bStartedDoc.
+ // This prevents the caller from doing further StartDocPrinter, WritePrinter,
etc. calls on it.
+ pPrinterHandle->pJob = pJob;
}
// Return the Printer handle through our general handle.
@@ -805,38 +841,82 @@
return (dwErrorCode == ERROR_SUCCESS);
}
+BOOL WINAPI
+LocalReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead)
+{
+ DWORD dwErrorCode;
+ PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
+ PLOCAL_PRINTER_HANDLE pPrinterHandle;
+
+ // Sanity checks.
+ if (!pHandle || pHandle->HandleType != HandleType_Printer)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
+
+ // ReadPrinter needs an opened SPL file to work.
+ // This only works if a Printer Job Handle was requested in OpenPrinter.
+ if (pPrinterHandle->hSPLFile == INVALID_HANDLE_VALUE)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // Pass the parameters to ReadFile.
+ if (!ReadFile(pPrinterHandle->hSPLFile, pBuf, cbBuf, pNoBytesRead, NULL))
+ {
+ dwErrorCode = GetLastError();
+ ERR("ReadFile failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
+}
+
DWORD WINAPI
-LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pDocInfo)
+LocalStartDocPrinter(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
{
DWORD dwErrorCode;
DWORD dwReturnValue = 0;
- PDOC_INFO_1W pDocumentInfo1;
- PLOCAL_HANDLE pHandle;
- PLOCAL_JOB pJob;
+ PDOC_INFO_1W pDocInfo1 = (PDOC_INFO_1W)pDocInfo;
+ PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
PLOCAL_PRINTER_HANDLE pPrinterHandle;
- // Sanity checks
- if (!pDocInfo)
+ // Sanity checks.
+ if (!pDocInfo1)
{
dwErrorCode = ERROR_INVALID_PARAMETER;
goto Cleanup;
}
- if (!hPrinter)
+ if (!pHandle || pHandle->HandleType != HandleType_Printer)
{
dwErrorCode = ERROR_INVALID_HANDLE;
goto Cleanup;
}
- // Check if this is a printer handle.
- pHandle = (PLOCAL_HANDLE)hPrinter;
- if (pHandle->HandleType != HandleType_Printer)
- {
- dwErrorCode = ERROR_INVALID_HANDLE;
- goto Cleanup;
- }
-
pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
+
+ // pJob may already be occupied if this is a Print Job handle. In this case,
StartDocPrinter has to fail.
+ if (pPrinterHandle->pJob)
+ {
+ dwErrorCode = ERROR_INVALID_PARAMETER;
+ goto Cleanup;
+ }
+
+ // Check the validity of the datatype if we got one.
+ if (pDocInfo1->pDatatype &&
!FindDatatype(pPrinterHandle->pJob->pPrintProcessor, pDocInfo1->pDatatype))
+ {
+ dwErrorCode = ERROR_INVALID_DATATYPE;
+ goto Cleanup;
+ }
// Check if this is the right document information level.
if (Level != 1)
@@ -845,68 +925,30 @@
goto Cleanup;
}
- pDocumentInfo1 = (PDOC_INFO_1W)pDocInfo;
-
- // Create a new job.
- pJob = DllAllocSplMem(sizeof(LOCAL_JOB));
- pJob->pPrinter = pPrinterHandle->pPrinter;
- pJob->dwPriority = DEF_PRIORITY;
-
- // Check if a datatype was given.
- if (pDocumentInfo1->pDatatype)
- {
- // Use the datatype if it's valid.
- if (!FindDatatype(pJob->pPrintProcessor, pDocumentInfo1->pDatatype))
- {
- dwErrorCode = ERROR_INVALID_DATATYPE;
- goto Cleanup;
- }
-
- pJob->pwszDatatype = AllocSplStr(pDocumentInfo1->pDatatype);
- }
- else
- {
- // Use the printer handle datatype.
- pJob->pwszDatatype = AllocSplStr(pPrinterHandle->pwszDatatype);
- }
-
- // Copy over printer defaults.
- pJob->pDevMode = DuplicateDevMode(pPrinterHandle->pDevMode);
-
- // Copy over supplied information.
- if (pDocumentInfo1->pDocName)
- pJob->pwszDocumentName = AllocSplStr(pDocumentInfo1->pDocName);
-
- if (pDocumentInfo1->pOutputFile)
- pJob->pwszOutputFile = AllocSplStr(pDocumentInfo1->pOutputFile);
-
- // Get an ID for the new job.
- if (!GetNextJobID(&pJob->dwJobID))
+ // All requirements are met - create a new job.
+ dwErrorCode = CreateJob(pPrinterHandle);
+ if (dwErrorCode != ERROR_SUCCESS)
+ goto Cleanup;
+
+ // Use any given datatype.
+ if (pDocInfo1->pDatatype &&
!ReallocSplStr(&pPrinterHandle->pJob->pwszDatatype, pDocInfo1->pDatatype))
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
- goto Cleanup;
- }
-
- // Add the job to the Global Job List.
- if (!InsertElementSkiplist(&GlobalJobList, pJob))
+ ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // Use any given document name.
+ if (pDocInfo1->pDocName &&
!ReallocSplStr(&pPrinterHandle->pJob->pwszDocumentName,
pDocInfo1->pDocName))
{
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
- 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->pPrinter->JobList, pJob))
- {
- dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
- ERR("InsertTailElementSkiplist failed for job %lu for the Printer's Job
List!\n", pJob->dwJobID);
- goto Cleanup;
- }
-
- pPrinterHandle->pStartedJob = pJob;
+ ERR("ReallocSplStr failed, last error is %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ // We were successful!
dwErrorCode = ERROR_SUCCESS;
- dwReturnValue = pJob->dwJobID;
+ dwReturnValue = pPrinterHandle->pJob->dwJobID;
Cleanup:
SetLastError(dwErrorCode);
@@ -916,48 +958,170 @@
BOOL WINAPI
LocalStartPagePrinter(HANDLE hPrinter)
{
- ///////////// TODO /////////////////////
- return FALSE;
+ DWORD dwErrorCode;
+ PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
+ PLOCAL_PRINTER_HANDLE pPrinterHandle;
+
+ // Sanity checks.
+ if (!pHandle || pHandle->HandleType != HandleType_Printer)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
+
+ // We require StartDocPrinter or AddJob to be called first.
+ if (!pPrinterHandle->bStartedDoc)
+ {
+ dwErrorCode = ERROR_SPL_NO_STARTDOC;
+ goto Cleanup;
+ }
+
+ // Increase the page count.
+ ++pPrinterHandle->pJob->dwTotalPages;
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
}
BOOL WINAPI
LocalWritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
{
- ///////////// TODO /////////////////////
- return FALSE;
+ DWORD dwErrorCode;
+ PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
+ PLOCAL_PRINTER_HANDLE pPrinterHandle;
+
+ // Sanity checks.
+ if (!pHandle || pHandle->HandleType != HandleType_Printer)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
+
+ // We require StartDocPrinter or AddJob to be called first.
+ if (!pPrinterHandle->bStartedDoc)
+ {
+ dwErrorCode = ERROR_SPL_NO_STARTDOC;
+ goto Cleanup;
+ }
+
+ // TODO: This function is only called when doing non-spooled printing.
+ // This needs to be investigated further. We can't just use
pPrinterHandle->hSPLFile here, because that's currently reserved for Printer Job
handles (see LocalReadPrinter).
+#if 0
+ // Pass the parameters to WriteFile.
+ if (!WriteFile(SOME_SPOOL_FILE_HANDLE, pBuf, cbBuf, pcWritten, NULL))
+ {
+ dwErrorCode = GetLastError();
+ ERR("WriteFile failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+#endif
+
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
}
BOOL WINAPI
LocalEndPagePrinter(HANDLE hPrinter)
{
- ///////////// TODO /////////////////////
- return FALSE;
+ DWORD dwErrorCode;
+ PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
+
+ // Sanity checks.
+ if (!pHandle || pHandle->HandleType != HandleType_Printer)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ // This function doesn't do anything else for now.
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
}
BOOL WINAPI
LocalEndDocPrinter(HANDLE hPrinter)
{
- ///////////// TODO /////////////////////
- return FALSE;
+ DWORD dwErrorCode;
+ PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
+ PLOCAL_PRINTER_HANDLE pPrinterHandle;
+
+ // Sanity checks.
+ if (!pHandle || pHandle->HandleType != HandleType_Printer)
+ {
+ dwErrorCode = ERROR_INVALID_HANDLE;
+ goto Cleanup;
+ }
+
+ pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
+
+ // We require StartDocPrinter or AddJob to be called first.
+ if (!pPrinterHandle->bStartedDoc)
+ {
+ dwErrorCode = ERROR_SPL_NO_STARTDOC;
+ goto Cleanup;
+ }
+
+ // TODO: Something like ScheduleJob
+
+ // Finish the job.
+ pPrinterHandle->bStartedDoc = FALSE;
+ pPrinterHandle->pJob = NULL;
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ SetLastError(dwErrorCode);
+ return (dwErrorCode == ERROR_SUCCESS);
}
BOOL WINAPI
LocalClosePrinter(HANDLE hPrinter)
{
- PLOCAL_HANDLE pHandle;
-
- if (!hPrinter)
+ PLOCAL_HANDLE pHandle = (PLOCAL_HANDLE)hPrinter;
+ PLOCAL_PRINTER_HANDLE pPrinterHandle;
+
+ if (!pHandle)
{
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
- pHandle = (PLOCAL_HANDLE)hPrinter;
-
- ///////////// TODO /////////////////////
- /// Check the handle type, do thoroughful checks on all data fields and clean them.
- ////////////////////////////////////////
-
+ if (pHandle->HandleType == HandleType_Port)
+ {
+ // TODO
+ }
+ else if (pHandle->HandleType == HandleType_Printer)
+ {
+ pPrinterHandle = (PLOCAL_PRINTER_HANDLE)pHandle->pSpecificHandle;
+
+ // Terminate any started job.
+ if (pPrinterHandle->pJob)
+ FreeJob(pPrinterHandle->pJob);
+
+ // Free memory for the fields.
+ DllFreeSplMem(pPrinterHandle->pDevMode);
+ DllFreeSplStr(pPrinterHandle->pwszDatatype);
+
+ // Free memory for the printer handle itself.
+ DllFreeSplMem(pPrinterHandle);
+ }
+ else if (pHandle->HandleType == HandleType_Xcv)
+ {
+ // TODO
+ }
+
+ // Free memory for the handle itself.
DllFreeSplMem(pHandle);
return TRUE;
Added:
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/printingthread.c
URL:
http://svn.reactos.org/svn/reactos/branches/colins-printing-for-freedom/rea…
==============================================================================
---
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/printingthread.c (added)
+++
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/printingthread.c [iso-8859-1]
Thu Jul 16 15:03:47 2015
@@ -0,0 +1,119 @@
+/*
+ * PROJECT: ReactOS Local Spooler
+ * LICENSE: GNU LGPL v2.1 or any later version as published by the Free Software
Foundation
+ * PURPOSE: Implementation of the Thread that actually performs the printing process
+ * COPYRIGHT: Copyright 2015 Colin Finck <colin(a)reactos.org>
+ */
+
+#include "precomp.h"
+
+DWORD WINAPI
+PrintingThreadProc(PLOCAL_JOB pJob)
+{
+ const DWORD cchMaxJobIdDigits = 5; // Job ID is limited to 5 decimal
digits, see IS_VALID_JOB_ID
+ const WCHAR wszJobAppendix[] = L", Job ";
+ const DWORD cchJobAppendix = _countof(wszJobAppendix) - 1;
+ const WCHAR wszPortAppendix[] = L", Port";
+
+ DWORD cchPortName;
+ DWORD cchPrinterName;
+ DWORD dwErrorCode;
+ HANDLE hPrintProcessor = NULL;
+ PLOCAL_PRINT_PROCESSOR pPrintProcessor = pJob->pPrintProcessor;
+ PRINTPROCESSOROPENDATA OpenData;
+ PWSTR pwszPrinterAndJob = NULL;
+ PWSTR pwszPrinterPort = NULL;
+ PWSTR pwszSPLFile = NULL;
+
+ // Prepare the pPrinterName parameter.
+ // This is the string for LocalOpenPrinter to open a port (e.g. "LPT1:,
Port").
+ cchPortName = wcslen(pJob->pPrinter->pPort->pwszName);
+ pwszPrinterPort = DllAllocSplMem(cchPortName * sizeof(WCHAR) +
sizeof(wszPortAppendix));
+ if (!pwszPrinterPort)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ CopyMemory(pwszPrinterPort, pJob->pPrinter->pPort->pwszName, cchPortName *
sizeof(WCHAR));
+ CopyMemory(&pwszPrinterPort[cchPortName], wszPortAppendix,
sizeof(wszPortAppendix));
+
+ // Prepare the pPrintProcessorOpenData parameter.
+ OpenData.JobId = pJob->dwJobID;
+ OpenData.pDatatype = pJob->pwszDatatype;
+ OpenData.pDevMode = pJob->pDevMode;
+ OpenData.pDocumentName = pJob->pwszDocumentName;
+ OpenData.pOutputFile = NULL;
+ OpenData.pParameters = pJob->pwszPrintProcessorParameters;
+ OpenData.pPrinterName = pJob->pPrinter->pwszPrinterName;
+
+ // Open a handle to the Print Processor.
+ hPrintProcessor = pPrintProcessor->pfnOpenPrintProcessor(pwszPrinterPort,
&OpenData);
+ if (!hPrintProcessor)
+ {
+ dwErrorCode = GetLastError();
+ ERR("OpenPrintProcessor failed with error %lu!\n", dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Let other functions use the Print Processor as well while it's opened.
+ pJob->hPrintProcessor = hPrintProcessor;
+
+ // Prepare the pDocumentName parameter.
+ cchPrinterName = wcslen(OpenData.pPrinterName);
+ pwszPrinterAndJob = DllAllocSplMem((cchPrinterName + cchJobAppendix +
cchMaxJobIdDigits + 1) * sizeof(WCHAR));
+ if (!pwszPrinterAndJob)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ CopyMemory(pwszPrinterAndJob, OpenData.pPrinterName, cchPrinterName *
sizeof(WCHAR));
+ CopyMemory(&pwszPrinterAndJob[cchPrinterName], wszJobAppendix, cchJobAppendix *
sizeof(WCHAR));
+ _ultow(OpenData.JobId, &pwszPrinterAndJob[cchPrinterName + cchJobAppendix], 10);
+
+ // Print the document.
+ // Note that pJob is freed after this function, so we may not access it anymore.
+ if (!pPrintProcessor->pfnPrintDocumentOnPrintProcessor(hPrintProcessor,
pwszPrinterAndJob))
+ {
+ dwErrorCode = GetLastError();
+ ERR("PrintDocumentOnPrintProcessor failed with error %lu!\n",
dwErrorCode);
+ goto Cleanup;
+ }
+
+ // Close the Print Processor.
+ pPrintProcessor->pfnClosePrintProcessor(hPrintProcessor);
+ hPrintProcessor = NULL;
+
+ // Delete the spool file.
+ pwszSPLFile = DllAllocSplMem(GetJobFilePath(L"SPL", 0, NULL));
+ if (!pwszSPLFile)
+ {
+ dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ ERR("DllAllocSplMem failed with error %lu!\n", GetLastError());
+ goto Cleanup;
+ }
+
+ GetJobFilePath(L"SPL", OpenData.JobId, pwszSPLFile);
+ DeleteFileW(pwszSPLFile);
+
+ // We were successful!
+ dwErrorCode = ERROR_SUCCESS;
+
+Cleanup:
+ if (hPrintProcessor)
+ pPrintProcessor->pfnClosePrintProcessor(hPrintProcessor);
+
+ if (pwszPrinterPort)
+ DllFreeSplMem(pwszPrinterPort);
+
+ if (pwszPrinterAndJob)
+ DllFreeSplMem(pwszPrinterAndJob);
+
+ if (pwszSPLFile)
+ DllFreeSplMem(pwszSPLFile);
+
+ return dwErrorCode;
+}
Propchange:
branches/colins-printing-for-freedom/reactos/win32ss/printing/providers/localspl/printingthread.c
------------------------------------------------------------------------------
svn:eol-style = native