2015-06-22 14:31:47 +00:00
|
|
|
/*
|
|
|
|
* PROJECT: ReactOS Spooler API
|
2017-09-29 17:18:19 +00:00
|
|
|
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
|
2015-06-22 14:31:47 +00:00
|
|
|
* PURPOSE: Functions related to Printers and printing
|
2018-01-17 11:52:12 +00:00
|
|
|
* COPYRIGHT: Copyright 2015-2018 Colin Finck (colin@reactos.org)
|
2015-06-22 14:31:47 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "precomp.h"
|
2018-01-17 11:52:12 +00:00
|
|
|
#include <marshalling/printers.h>
|
2020-08-04 02:07:58 +00:00
|
|
|
//#include <marshalling/printerdrivers.h>
|
2020-01-31 17:42:55 +00:00
|
|
|
#include <strsafe.h>
|
2015-06-22 14:31:47 +00:00
|
|
|
|
2020-08-04 02:07:58 +00:00
|
|
|
extern HINSTANCE hinstWinSpool;
|
|
|
|
//
|
|
|
|
// See winddiui.h, ReactOS version is limited.
|
|
|
|
// Loading from XyzUI.dll part of XyzDRV.dll set. example TTYUI.DLL or UniDrvUI.DLL.
|
|
|
|
//
|
|
|
|
typedef DWORD (WINAPI *DEVICECAPABILITIES) (HANDLE,PWSTR,WORD,PVOID,PDEVMODEW);
|
|
|
|
static DEVICECAPABILITIES fpDeviceCapabilities;
|
|
|
|
|
|
|
|
typedef LONG (WINAPI *DEVICEPROPERTYSHEETS) (PPROPSHEETUI_INFO,LPARAM);
|
|
|
|
static DEVICEPROPERTYSHEETS fpDevicePropertySheets;
|
|
|
|
typedef LONG (WINAPI *DOCUMENTPROPERTYSHEETS) (PPROPSHEETUI_INFO,LPARAM);
|
|
|
|
static DOCUMENTPROPERTYSHEETS fpDocumentPropertySheets;
|
|
|
|
|
|
|
|
typedef LONG (WINAPI *COMMONPROPERTYSHEETUIW) (HWND,PFNPROPSHEETUI,LPARAM,LPDWORD);
|
|
|
|
static COMMONPROPERTYSHEETUIW fpCommonPropertySheetUIW;
|
|
|
|
|
|
|
|
typedef LONG (WINAPI *QUERYCOLORPROFILE) (HANDLE,PDEVMODEW,ULONG,PVOID,ULONG*,FLONG*);
|
|
|
|
static QUERYCOLORPROFILE fpQueryColorProfile;
|
|
|
|
|
|
|
|
typedef BOOL (WINAPI *SPOOLERPRINTEREVENT) (LPWSTR,int,DWORD,LPARAM);
|
|
|
|
static SPOOLERPRINTEREVENT fpPrinterEvent;
|
|
|
|
|
|
|
|
typedef BOOL (WINAPI *DEVQUERYPRINT) (HANDLE,LPDEVMODEW,DWORD*);
|
|
|
|
static DEVQUERYPRINT fpDevQueryPrint;
|
|
|
|
|
|
|
|
typedef BOOL (WINAPI *DEVQUERYPRINTEX) (PDEVQUERYPRINT_INFO);
|
|
|
|
static DEVQUERYPRINTEX fpDevQueryPrintEx;
|
|
|
|
|
|
|
|
//
|
|
|
|
// PrintUI.dll
|
|
|
|
//
|
|
|
|
LONG WINAPI ConstructPrinterFriendlyName( PWSTR, PVOID, LPDWORD Size );
|
|
|
|
typedef LONG (WINAPI *CONSTRUCTPRINTERFRIENDLYNAME) (PWSTR,PVOID,LPDWORD);
|
|
|
|
static CONSTRUCTPRINTERFRIENDLYNAME fpConstructPrinterFriendlyName;
|
|
|
|
|
|
|
|
//
|
|
|
|
// CompstUI User Data
|
|
|
|
//
|
|
|
|
typedef struct _COMPUI_USERDATA
|
|
|
|
{
|
|
|
|
HMODULE hModule;
|
|
|
|
LPWSTR pszPrinterName;
|
|
|
|
} COMPUI_USERDATA, *PCOMPUI_USERDATA;
|
|
|
|
|
2017-05-09 15:44:42 +00:00
|
|
|
// Local Constants
|
|
|
|
|
|
|
|
/** And the award for the most confusingly named setting goes to "Device", for storing the default printer of the current user.
|
|
|
|
Ok, I admit that this has historical reasons. It's still not straightforward in any way though! */
|
|
|
|
static const WCHAR wszWindowsKey[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows";
|
|
|
|
static const WCHAR wszDeviceValue[] = L"Device";
|
|
|
|
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
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.
|
2015-07-17 15:11:34 +00:00
|
|
|
GetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, NULL, 0, &cbNeeded);
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
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;
|
[PRINTING]
- Implement GetPrinterDataA, GetPrinterDataExA, GetPrinterDataExW, GetPrinterDataW, SetPrinterDataA, SetPrinterDataExA, SetPrinterDataExW, SetPrinterDataW.
They support all features for Print Server and Printer Handles (minus security checks!)
I've also added tests for them.
- Store Printer data in SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers instead of SYSTEM\CurrentControlSet\Control\Print\Printers and create a registry symlink from the former path to the new one just like Windows does.
According to https://social.technet.microsoft.com/Forums/windowsserver/en-US/a683ab54-c43c-4ebe-af8f-1f7a65af2a51, this is needed when having >900 printers to work around a size limit of the SYSTEM registry hive. And if Windows has both locations, we need both for compatibility anyway.
- Add several settings which are queried by the new Printer Data APIs when working with Print Server Handles.
- Store the job directory in the Windows-compatible "DefaultSpoolDirectory" setting and make use of it.
- Revert the ASSERTs in LocalEnumPrinters again to let us verify the NULL pointer exceptions in localspl_apitest (thanks Serge! CORE-13433)
- Translate ERROR_INVALID_NAME to ERROR_INVALID_PRINTER_NAME in all cases in OpenPrinterW (thanks Victor! CORE-13412)
- Make EnumMonitorsW and EnumPortsW in spoolss more robust against failing Print Monitors.
- Remove the wrong !phPrinter check in OpenPrinterW to make Print Server Handles work for real.
- Fix error handling when memory allocation fails: HeapAlloc doesn't set last error, so it's just wrong to query or return it.
One more item done from https://reactos.org/wiki/Printing !
This is all still a big Work-in-Progress, with many subtle bugs deep down in ReactOS, for which I need to open additional tickets. But I didn't want to make this commit even bigger..
svn path=/trunk/; revision=75125
2017-06-19 14:18:19 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the job information.
|
2015-07-17 15:11:34 +00:00
|
|
|
if (!GetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1, cbNeeded, &cbNeeded))
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
{
|
|
|
|
dwErrorCode = GetLastError();
|
|
|
|
ERR("GetJobW failed with error %lu!\n", dwErrorCode);
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add our document information.
|
2015-07-20 15:21:03 +00:00
|
|
|
if (pDocInfo1->pDatatype)
|
|
|
|
pJobInfo1->pDatatype = pDocInfo1->pDatatype;
|
|
|
|
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
pJobInfo1->pDocument = pDocInfo1->pDocName;
|
|
|
|
|
|
|
|
// Set the new job information.
|
2015-07-17 15:11:34 +00:00
|
|
|
if (!SetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1, 0))
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-12-09 12:35:42 +00:00
|
|
|
BOOL WINAPI
|
|
|
|
AbortPrinter(HANDLE hPrinter)
|
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
DWORD dwErrorCode;
|
|
|
|
PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
|
|
|
|
|
2017-12-09 12:35:42 +00:00
|
|
|
TRACE("AbortPrinter(%p)\n", hPrinter);
|
2020-08-04 02:07:58 +00:00
|
|
|
|
|
|
|
// Sanity checks.
|
|
|
|
if (!pHandle)
|
|
|
|
{
|
|
|
|
dwErrorCode = ERROR_INVALID_HANDLE;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
pHandle->bTrayIcon = pHandle->bStartedDoc = FALSE;
|
|
|
|
|
|
|
|
if ( pHandle->hSPLFile != INVALID_HANDLE_VALUE && pHandle->bJob )
|
|
|
|
{
|
|
|
|
// Close any open file handle.
|
|
|
|
CloseHandle( pHandle->hSPLFile );
|
|
|
|
pHandle->hSPLFile = INVALID_HANDLE_VALUE;
|
|
|
|
|
|
|
|
SetJobW( hPrinter, pHandle->dwJobID, 0, NULL, JOB_CONTROL_DELETE );
|
|
|
|
|
|
|
|
return ScheduleJob( hPrinter, pHandle->dwJobID );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do the RPC call.
|
|
|
|
RpcTryExcept
|
|
|
|
{
|
|
|
|
dwErrorCode = _RpcAbortPrinter(&pHandle->hPrinter);
|
|
|
|
}
|
|
|
|
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
{
|
|
|
|
dwErrorCode = RpcExceptionCode();
|
|
|
|
ERR("_RpcAbortPrinter failed with exception code %lu!\n", dwErrorCode);
|
|
|
|
}
|
|
|
|
RpcEndExcept;
|
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
SetLastError(dwErrorCode);
|
|
|
|
return (dwErrorCode == ERROR_SUCCESS);
|
2017-12-09 12:35:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
HANDLE WINAPI
|
|
|
|
AddPrinterA(PSTR pName, DWORD Level, PBYTE pPrinter)
|
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
UNICODE_STRING pNameW, usBuffer;
|
|
|
|
PWSTR pwstrNameW;
|
|
|
|
PRINTER_INFO_2W *ppi2w = (PRINTER_INFO_2W*)pPrinter;
|
|
|
|
PRINTER_INFO_2A *ppi2a = (PRINTER_INFO_2A*)pPrinter;
|
|
|
|
HANDLE ret = NULL;
|
|
|
|
PWSTR pwszPrinterName = NULL;
|
|
|
|
PWSTR pwszServerName = NULL;
|
|
|
|
PWSTR pwszShareName = NULL;
|
|
|
|
PWSTR pwszPortName = NULL;
|
|
|
|
PWSTR pwszDriverName = NULL;
|
|
|
|
PWSTR pwszComment = NULL;
|
|
|
|
PWSTR pwszLocation = NULL;
|
|
|
|
PWSTR pwszSepFile = NULL;
|
|
|
|
PWSTR pwszPrintProcessor = NULL;
|
|
|
|
PWSTR pwszDatatype = NULL;
|
|
|
|
PWSTR pwszParameters = NULL;
|
|
|
|
PDEVMODEW pdmw = NULL;
|
|
|
|
|
|
|
|
TRACE("AddPrinterA(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
|
|
|
|
|
|
|
|
if(Level != 2)
|
|
|
|
{
|
|
|
|
ERR("Level = %d, unsupported!\n", Level);
|
|
|
|
SetLastError(ERROR_INVALID_LEVEL);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pwstrNameW = AsciiToUnicode(&pNameW,pName);
|
|
|
|
|
|
|
|
if (ppi2a->pShareName)
|
|
|
|
{
|
|
|
|
pwszShareName = AsciiToUnicode(&usBuffer, ppi2a->pShareName);
|
|
|
|
if (!(ppi2w->pShareName = pwszShareName)) goto Cleanup;
|
|
|
|
}
|
|
|
|
if (ppi2a->pPortName)
|
|
|
|
{
|
|
|
|
pwszPortName = AsciiToUnicode(&usBuffer, ppi2a->pPortName);
|
|
|
|
if (!(ppi2w->pPortName = pwszPortName)) goto Cleanup;
|
|
|
|
}
|
|
|
|
if (ppi2a->pDriverName)
|
|
|
|
{
|
|
|
|
pwszDriverName = AsciiToUnicode(&usBuffer, ppi2a->pDriverName);
|
|
|
|
if (!(ppi2w->pDriverName = pwszDriverName)) goto Cleanup;
|
|
|
|
}
|
|
|
|
if (ppi2a->pComment)
|
|
|
|
{
|
|
|
|
pwszComment = AsciiToUnicode(&usBuffer, ppi2a->pComment);
|
|
|
|
if (!(ppi2w->pComment = pwszComment)) goto Cleanup;
|
|
|
|
}
|
|
|
|
if (ppi2a->pLocation)
|
|
|
|
{
|
|
|
|
pwszLocation = AsciiToUnicode(&usBuffer, ppi2a->pLocation);
|
|
|
|
if (!(ppi2w->pLocation = pwszLocation)) goto Cleanup;
|
|
|
|
}
|
|
|
|
if (ppi2a->pSepFile)
|
|
|
|
{
|
|
|
|
pwszSepFile = AsciiToUnicode(&usBuffer, ppi2a->pSepFile);
|
|
|
|
if (!(ppi2w->pSepFile = pwszSepFile)) goto Cleanup;
|
|
|
|
}
|
|
|
|
if (ppi2a->pServerName)
|
|
|
|
{
|
|
|
|
pwszPrintProcessor = AsciiToUnicode(&usBuffer, ppi2a->pPrintProcessor);
|
|
|
|
if (!(ppi2w->pPrintProcessor = pwszPrintProcessor)) goto Cleanup;
|
|
|
|
}
|
|
|
|
if (ppi2a->pDatatype)
|
|
|
|
{
|
|
|
|
pwszDatatype = AsciiToUnicode(&usBuffer, ppi2a->pDatatype);
|
|
|
|
if (!(ppi2w->pDatatype = pwszDatatype)) goto Cleanup;
|
|
|
|
}
|
|
|
|
if (ppi2a->pParameters)
|
|
|
|
{
|
|
|
|
pwszParameters = AsciiToUnicode(&usBuffer, ppi2a->pParameters);
|
|
|
|
if (!(ppi2w->pParameters = pwszParameters)) goto Cleanup;
|
|
|
|
}
|
|
|
|
if ( ppi2a->pDevMode )
|
|
|
|
{
|
|
|
|
RosConvertAnsiDevModeToUnicodeDevmode( ppi2a->pDevMode, &pdmw );
|
|
|
|
ppi2w->pDevMode = pdmw;
|
|
|
|
}
|
|
|
|
if (ppi2a->pServerName)
|
|
|
|
{
|
|
|
|
pwszServerName = AsciiToUnicode(&usBuffer, ppi2a->pServerName);
|
|
|
|
if (!(ppi2w->pPrinterName = pwszServerName)) goto Cleanup;
|
|
|
|
}
|
|
|
|
if (ppi2a->pPrinterName)
|
|
|
|
{
|
|
|
|
pwszPrinterName = AsciiToUnicode(&usBuffer, ppi2a->pPrinterName);
|
|
|
|
if (!(ppi2w->pPrinterName = pwszPrinterName)) goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)ppi2w);
|
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
if (pdmw) HeapFree(hProcessHeap, 0, pdmw);
|
|
|
|
if (pwszPrinterName) HeapFree(hProcessHeap, 0, pwszPrinterName);
|
|
|
|
if (pwszServerName) HeapFree(hProcessHeap, 0, pwszServerName);
|
|
|
|
if (pwszShareName) HeapFree(hProcessHeap, 0, pwszShareName);
|
|
|
|
if (pwszPortName) HeapFree(hProcessHeap, 0, pwszPortName);
|
|
|
|
if (pwszDriverName) HeapFree(hProcessHeap, 0, pwszDriverName);
|
|
|
|
if (pwszComment) HeapFree(hProcessHeap, 0, pwszComment);
|
|
|
|
if (pwszLocation) HeapFree(hProcessHeap, 0, pwszLocation);
|
|
|
|
if (pwszSepFile) HeapFree(hProcessHeap, 0, pwszSepFile);
|
|
|
|
if (pwszPrintProcessor) HeapFree(hProcessHeap, 0, pwszPrintProcessor);
|
|
|
|
if (pwszDatatype) HeapFree(hProcessHeap, 0, pwszDatatype);
|
|
|
|
if (pwszParameters) HeapFree(hProcessHeap, 0, pwszParameters);
|
|
|
|
|
|
|
|
RtlFreeUnicodeString(&pNameW);
|
|
|
|
return ret;
|
2017-12-09 12:35:42 +00:00
|
|
|
}
|
|
|
|
|
2015-07-22 17:59:46 +00:00
|
|
|
HANDLE WINAPI
|
|
|
|
AddPrinterW(PWSTR pName, DWORD Level, PBYTE pPrinter)
|
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
DWORD dwErrorCode;
|
|
|
|
WINSPOOL_PRINTER_CONTAINER PrinterContainer;
|
|
|
|
WINSPOOL_DEVMODE_CONTAINER DevModeContainer;
|
|
|
|
WINSPOOL_SECURITY_CONTAINER SecurityContainer;
|
|
|
|
SECURITY_DESCRIPTOR *sd = NULL;
|
|
|
|
DWORD size;
|
|
|
|
HANDLE hPrinter = NULL, hHandle = NULL;
|
|
|
|
PSPOOLER_HANDLE pHandle = NULL;
|
|
|
|
|
2017-12-09 11:00:09 +00:00
|
|
|
TRACE("AddPrinterW(%S, %lu, %p)\n", pName, Level, pPrinter);
|
2020-08-04 02:07:58 +00:00
|
|
|
|
|
|
|
DevModeContainer.cbBuf = 0;
|
|
|
|
DevModeContainer.pDevMode = NULL;
|
|
|
|
|
|
|
|
SecurityContainer.cbBuf = 0;
|
|
|
|
SecurityContainer.pSecurity = NULL;
|
|
|
|
|
|
|
|
if ( Level != 2 )
|
|
|
|
{
|
|
|
|
FIXME( "Unsupported level %d\n", Level );
|
|
|
|
SetLastError( ERROR_INVALID_LEVEL );
|
|
|
|
return hHandle;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PPRINTER_INFO_2W pi2w = (PPRINTER_INFO_2W)pPrinter;
|
|
|
|
if ( pi2w )
|
|
|
|
{
|
|
|
|
if ( pi2w->pDevMode )
|
|
|
|
{
|
|
|
|
if ( IsValidDevmodeNoSizeW( pi2w->pDevMode ) )
|
|
|
|
{
|
|
|
|
DevModeContainer.cbBuf = pi2w->pDevMode->dmSize + pi2w->pDevMode->dmDriverExtra;
|
|
|
|
DevModeContainer.pDevMode = (PBYTE)pi2w->pDevMode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( pi2w->pSecurityDescriptor )
|
|
|
|
{
|
|
|
|
sd = get_sd( pi2w->pSecurityDescriptor, &size );
|
|
|
|
if ( sd )
|
|
|
|
{
|
|
|
|
SecurityContainer.cbBuf = size;
|
|
|
|
SecurityContainer.pSecurity = (PBYTE)sd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return hHandle;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PrinterContainer.PrinterInfo.pPrinterInfo1 = (WINSPOOL_PRINTER_INFO_1*)pPrinter;
|
|
|
|
PrinterContainer.Level = Level;
|
|
|
|
|
|
|
|
// Do the RPC call
|
|
|
|
RpcTryExcept
|
|
|
|
{
|
|
|
|
dwErrorCode = _RpcAddPrinter( pName, &PrinterContainer, &DevModeContainer, &SecurityContainer, &hPrinter );
|
|
|
|
}
|
|
|
|
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
{
|
|
|
|
dwErrorCode = RpcExceptionCode();
|
|
|
|
}
|
|
|
|
RpcEndExcept;
|
|
|
|
|
|
|
|
if (hPrinter)
|
|
|
|
{
|
|
|
|
// 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!\n");
|
|
|
|
_RpcDeletePrinter(hPrinter);
|
|
|
|
_RpcClosePrinter(hPrinter);
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
pHandle->Sig = SPOOLER_HANDLE_SIG;
|
|
|
|
pHandle->hPrinter = hPrinter;
|
|
|
|
pHandle->hSPLFile = INVALID_HANDLE_VALUE;
|
|
|
|
pHandle->hSpoolFileHandle = INVALID_HANDLE_VALUE;
|
|
|
|
hHandle = (HANDLE)pHandle;
|
|
|
|
}
|
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
if ( sd ) HeapFree( GetProcessHeap(), 0, sd );
|
|
|
|
|
|
|
|
SetLastError(dwErrorCode);
|
|
|
|
return hHandle;
|
2015-07-22 17:59:46 +00:00
|
|
|
}
|
|
|
|
|
2015-06-22 14:31:47 +00:00
|
|
|
BOOL WINAPI
|
|
|
|
ClosePrinter(HANDLE hPrinter)
|
|
|
|
{
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
DWORD dwErrorCode;
|
|
|
|
PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
|
|
|
|
|
2017-12-09 11:00:09 +00:00
|
|
|
TRACE("ClosePrinter(%p)\n", hPrinter);
|
|
|
|
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
// Sanity checks.
|
2020-08-04 02:07:58 +00:00
|
|
|
if ( IntProtectHandle( hPrinter, TRUE ) )
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
{
|
|
|
|
dwErrorCode = ERROR_INVALID_HANDLE;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do the RPC call.
|
|
|
|
RpcTryExcept
|
|
|
|
{
|
2017-06-26 15:16:46 +00:00
|
|
|
dwErrorCode = _RpcClosePrinter(&pHandle->hPrinter);
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
}
|
|
|
|
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);
|
|
|
|
|
2020-08-04 02:07:58 +00:00
|
|
|
pHandle->Sig = -1;
|
|
|
|
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
// Free the memory for the handle.
|
|
|
|
HeapFree(hProcessHeap, 0, pHandle);
|
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
SetLastError(dwErrorCode);
|
|
|
|
return (dwErrorCode == ERROR_SUCCESS);
|
2015-06-22 14:31:47 +00:00
|
|
|
}
|
|
|
|
|
2017-12-09 12:35:42 +00:00
|
|
|
BOOL WINAPI
|
|
|
|
DeletePrinter(HANDLE hPrinter)
|
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
DWORD dwErrorCode;
|
|
|
|
PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
|
|
|
|
|
2017-12-09 12:35:42 +00:00
|
|
|
TRACE("DeletePrinter(%p)\n", hPrinter);
|
2020-08-04 02:07:58 +00:00
|
|
|
|
|
|
|
// Sanity checks.
|
|
|
|
if (!pHandle)
|
|
|
|
{
|
|
|
|
dwErrorCode = ERROR_INVALID_HANDLE;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do the RPC call.
|
|
|
|
RpcTryExcept
|
|
|
|
{
|
|
|
|
dwErrorCode = _RpcDeletePrinter(&pHandle->hPrinter);
|
|
|
|
}
|
|
|
|
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
{
|
|
|
|
dwErrorCode = RpcExceptionCode();
|
|
|
|
ERR("_RpcDeletePrinter failed with exception code %lu!\n", dwErrorCode);
|
|
|
|
}
|
|
|
|
RpcEndExcept;
|
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
SetLastError(dwErrorCode);
|
|
|
|
return (dwErrorCode == ERROR_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Based on GDI32:printdrv.c:IntGetPrinterDriver.
|
|
|
|
//
|
|
|
|
HMODULE
|
|
|
|
WINAPI
|
|
|
|
LoadPrinterDriver( HANDLE hspool )
|
|
|
|
{
|
|
|
|
INT iTries = 0;
|
|
|
|
DWORD Size = (sizeof(WCHAR) * MAX_PATH) * 2; // DRIVER_INFO_5W + plus strings.
|
|
|
|
PDRIVER_INFO_5W pdi = NULL;
|
|
|
|
HMODULE hLibrary = NULL;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
++iTries;
|
|
|
|
|
|
|
|
pdi = RtlAllocateHeap( GetProcessHeap(), 0, Size);
|
|
|
|
|
|
|
|
if ( !pdi )
|
|
|
|
break;
|
|
|
|
|
|
|
|
if ( GetPrinterDriverW(hspool, NULL, 5, (LPBYTE)pdi, Size, &Size) )
|
|
|
|
{
|
|
|
|
TRACE("Level 5 Size %d\n",Size);
|
|
|
|
|
|
|
|
// Name and load configure library (for example, C:\DRIVERS\Pscrptui.dll). Not printui.dll!
|
|
|
|
|
|
|
|
hLibrary = LoadLibrary(pdi->pConfigFile);
|
|
|
|
|
2020-08-26 22:12:20 +00:00
|
|
|
FIXME("IGPD : Get Printer Driver Config File : %S\n",pdi->pConfigFile);
|
2020-08-04 02:07:58 +00:00
|
|
|
|
|
|
|
RtlFreeHeap( GetProcessHeap(), 0, pdi);
|
|
|
|
return hLibrary;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
|
|
|
|
++iTries;
|
|
|
|
|
|
|
|
RtlFreeHeap( GetProcessHeap(), 0, pdi);
|
|
|
|
}
|
|
|
|
while ( iTries < 2 );
|
|
|
|
ERR("No Printer Driver Error %d\n",GetLastError());
|
|
|
|
return NULL;
|
2017-12-09 12:35:42 +00:00
|
|
|
}
|
|
|
|
|
2015-06-22 14:31:47 +00:00
|
|
|
DWORD WINAPI
|
|
|
|
DeviceCapabilitiesA(LPCSTR pDevice, LPCSTR pPort, WORD fwCapability, LPSTR pOutput, const DEVMODEA* pDevMode)
|
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
PWSTR pwszDeviceName = NULL;
|
|
|
|
PDEVMODEW pdmwInput = NULL;
|
|
|
|
BOOL bReturnValue = GDI_ERROR;
|
|
|
|
DWORD cch;
|
|
|
|
|
|
|
|
FIXME("DeviceCapabilitiesA(%s, %s, %hu, %p, %p)\n", pDevice, pPort, fwCapability, pOutput, pDevMode);
|
|
|
|
|
|
|
|
if (pDevice)
|
|
|
|
{
|
|
|
|
// Convert pName to a Unicode string pwszDeviceName.
|
|
|
|
cch = strlen(pDevice);
|
|
|
|
|
|
|
|
pwszDeviceName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
|
|
|
|
if (!pwszDeviceName)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
MultiByteToWideChar(CP_ACP, 0, pDevice, -1, pwszDeviceName, cch + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pDevMode)
|
|
|
|
{
|
|
|
|
RosConvertAnsiDevModeToUnicodeDevmode((PDEVMODEA)pDevMode, &pdmwInput);
|
|
|
|
}
|
|
|
|
|
|
|
|
// pPort is ignored so no need to pass it.
|
|
|
|
bReturnValue = DeviceCapabilitiesW( pwszDeviceName, NULL, fwCapability, (LPWSTR)pOutput, (const DEVMODEW*) pdmwInput );
|
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
if(pwszDeviceName)
|
|
|
|
HeapFree(hProcessHeap, 0, pwszDeviceName);
|
|
|
|
|
|
|
|
if (pdmwInput)
|
|
|
|
HeapFree(hProcessHeap, 0, pdmwInput);
|
|
|
|
|
|
|
|
return bReturnValue;
|
2015-06-22 14:31:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
DWORD WINAPI
|
|
|
|
DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort, WORD fwCapability, LPWSTR pOutput, const DEVMODEW* pDevMode)
|
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
HANDLE hPrinter;
|
|
|
|
HMODULE hLibrary;
|
|
|
|
DWORD iDevCap = GDI_ERROR;
|
|
|
|
|
|
|
|
FIXME("DeviceCapabilitiesW(%S, %S, %hu, %p, %p)\n", pDevice, pPort, fwCapability, pOutput, pDevMode);
|
|
|
|
|
|
|
|
if ( pDevMode )
|
|
|
|
{
|
|
|
|
if (!IsValidDevmodeNoSizeW( (PDEVMODEW)pDevMode ) )
|
|
|
|
{
|
2020-09-08 18:15:16 +00:00
|
|
|
ERR("DeviceCapabilitiesW : Devode Invalid\n");
|
2020-08-04 02:07:58 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( OpenPrinterW( (LPWSTR)pDevice, &hPrinter, NULL ) )
|
|
|
|
{
|
|
|
|
hLibrary = LoadPrinterDriver( hPrinter );
|
|
|
|
|
|
|
|
if ( hLibrary )
|
|
|
|
{
|
|
|
|
fpDeviceCapabilities = (PVOID)GetProcAddress( hLibrary, "DrvDeviceCapabilities" );
|
|
|
|
|
|
|
|
if ( fpDeviceCapabilities )
|
|
|
|
{
|
|
|
|
iDevCap = fpDeviceCapabilities( hPrinter, (PWSTR)pDevice, fwCapability, pOutput, (PDEVMODE)pDevMode );
|
|
|
|
}
|
|
|
|
|
|
|
|
FreeLibrary(hLibrary);
|
|
|
|
}
|
|
|
|
|
|
|
|
ClosePrinter( hPrinter );
|
|
|
|
}
|
|
|
|
|
|
|
|
return iDevCap;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
|
|
WINAPI
|
|
|
|
DevQueryPrint( HANDLE hPrinter, LPDEVMODEW pDevMode, DWORD *pResID)
|
|
|
|
{
|
|
|
|
HMODULE hLibrary;
|
|
|
|
BOOL Ret = FALSE;
|
|
|
|
|
|
|
|
hLibrary = LoadPrinterDriver( hPrinter );
|
|
|
|
|
|
|
|
if ( hLibrary )
|
|
|
|
{
|
|
|
|
fpDevQueryPrint = (PVOID)GetProcAddress( hLibrary, "DevQueryPrint" );
|
|
|
|
|
|
|
|
if ( fpDevQueryPrint )
|
|
|
|
{
|
|
|
|
Ret = fpDevQueryPrint( hPrinter, pDevMode, pResID );
|
|
|
|
}
|
|
|
|
|
|
|
|
FreeLibrary(hLibrary);
|
|
|
|
}
|
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI
|
|
|
|
DevQueryPrintEx( PDEVQUERYPRINT_INFO pDQPInfo )
|
|
|
|
{
|
|
|
|
HMODULE hLibrary;
|
|
|
|
BOOL Ret = FALSE;
|
|
|
|
|
|
|
|
hLibrary = LoadPrinterDriver( pDQPInfo->hPrinter );
|
|
|
|
|
|
|
|
if ( hLibrary )
|
|
|
|
{
|
|
|
|
fpDevQueryPrintEx = (PVOID)GetProcAddress( hLibrary, "DevQueryPrintEx" );
|
|
|
|
|
|
|
|
if ( fpDevQueryPrintEx )
|
|
|
|
{
|
|
|
|
Ret = fpDevQueryPrintEx( pDQPInfo );
|
|
|
|
}
|
|
|
|
|
|
|
|
FreeLibrary(hLibrary);
|
|
|
|
}
|
|
|
|
return Ret;
|
2015-06-22 14:31:47 +00:00
|
|
|
}
|
|
|
|
|
2020-01-31 23:38:47 +00:00
|
|
|
INT WINAPI
|
|
|
|
DocumentEvent( HANDLE hPrinter, HDC hdc, int iEsc, ULONG cbIn, PVOID pvIn, ULONG cbOut, PVOID pvOut)
|
|
|
|
{
|
2020-08-26 22:12:20 +00:00
|
|
|
FIXME("DocumentEvent(%p, %p, %lu, %lu, %p, %lu, %p)\n", hPrinter, hdc, iEsc, cbIn, pvIn, cbOut, pvOut);
|
2020-01-31 23:38:47 +00:00
|
|
|
UNIMPLEMENTED;
|
|
|
|
return DOCUMENTEVENT_UNSUPPORTED;
|
|
|
|
}
|
|
|
|
|
2015-06-22 14:31:47 +00:00
|
|
|
LONG WINAPI
|
|
|
|
DocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput, DWORD fMode)
|
|
|
|
{
|
2020-02-25 07:02:46 +00:00
|
|
|
PWSTR pwszDeviceName = NULL;
|
|
|
|
PDEVMODEW pdmwInput = NULL;
|
|
|
|
PDEVMODEW pdmwOutput = NULL;
|
2020-08-31 00:06:35 +00:00
|
|
|
LONG lReturnValue = -1;
|
2020-02-25 07:02:46 +00:00
|
|
|
DWORD cch;
|
|
|
|
|
2020-08-04 02:07:58 +00:00
|
|
|
FIXME("DocumentPropertiesA(%p, %p, %s, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode);
|
2020-02-25 07:02:46 +00:00
|
|
|
|
|
|
|
if (pDeviceName)
|
|
|
|
{
|
|
|
|
// Convert pName to a Unicode string pwszDeviceName.
|
|
|
|
cch = strlen(pDeviceName);
|
|
|
|
|
|
|
|
pwszDeviceName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
|
|
|
|
if (!pwszDeviceName)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
MultiByteToWideChar(CP_ACP, 0, pDeviceName, -1, pwszDeviceName, cch + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pDevModeInput)
|
|
|
|
{
|
|
|
|
// Create working buffer for input to DocumentPropertiesW.
|
2020-08-04 02:07:58 +00:00
|
|
|
RosConvertAnsiDevModeToUnicodeDevmode(pDevModeInput, &pdmwInput);
|
2020-02-25 07:02:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pDevModeOutput)
|
|
|
|
{
|
|
|
|
// Create working buffer for output from DocumentPropertiesW.
|
2020-08-04 02:07:58 +00:00
|
|
|
|
|
|
|
// Do it RIGHT! Get the F...ing Size!
|
|
|
|
LONG Size = DocumentPropertiesW( hWnd, hPrinter, pwszDeviceName, NULL, NULL, 0 );
|
|
|
|
|
|
|
|
if ( Size < 0 )
|
2020-02-25 07:02:46 +00:00
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
pdmwOutput = HeapAlloc(hProcessHeap, 0, Size);
|
|
|
|
if (!pdmwOutput)
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
ERR("HeapAlloc failed!\n");
|
2020-02-25 07:02:46 +00:00
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-31 00:06:35 +00:00
|
|
|
lReturnValue = DocumentPropertiesW(hWnd, hPrinter, pwszDeviceName, pdmwOutput, pdmwInput, fMode);
|
|
|
|
FIXME("lReturnValue from DocumentPropertiesW is '%ld'.\n", lReturnValue);
|
2020-02-25 07:02:46 +00:00
|
|
|
|
2020-08-31 00:06:35 +00:00
|
|
|
if (lReturnValue < 0)
|
2020-02-25 07:02:46 +00:00
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
FIXME("DocumentPropertiesW failed!\n");
|
2020-02-25 07:02:46 +00:00
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pdmwOutput)
|
|
|
|
{
|
|
|
|
RosConvertUnicodeDevModeToAnsiDevmode(pdmwOutput, pDevModeOutput);
|
|
|
|
}
|
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
if(pwszDeviceName)
|
|
|
|
HeapFree(hProcessHeap, 0, pwszDeviceName);
|
|
|
|
|
|
|
|
if (pdmwInput)
|
|
|
|
HeapFree(hProcessHeap, 0, pdmwInput);
|
|
|
|
|
|
|
|
if (pdmwOutput)
|
|
|
|
HeapFree(hProcessHeap, 0, pdmwOutput);
|
|
|
|
|
2020-08-31 00:06:35 +00:00
|
|
|
return lReturnValue;
|
2015-06-22 14:31:47 +00:00
|
|
|
}
|
|
|
|
|
2020-08-04 02:07:58 +00:00
|
|
|
PRINTER_INFO_9W * get_devmodeW(HANDLE hprn)
|
2019-01-06 01:24:42 +00:00
|
|
|
{
|
|
|
|
PRINTER_INFO_9W *pi9 = NULL;
|
|
|
|
DWORD needed = 0;
|
|
|
|
BOOL res;
|
|
|
|
|
|
|
|
res = GetPrinterW(hprn, 9, NULL, 0, &needed);
|
|
|
|
if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
|
|
|
|
{
|
|
|
|
pi9 = HeapAlloc(hProcessHeap, 0, needed);
|
|
|
|
res = GetPrinterW(hprn, 9, (LPBYTE)pi9, needed, &needed);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (res)
|
|
|
|
return pi9;
|
|
|
|
|
|
|
|
ERR("GetPrinterW failed with %u\n", GetLastError());
|
|
|
|
HeapFree(hProcessHeap, 0, pi9);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2020-08-04 02:07:58 +00:00
|
|
|
BOOL
|
|
|
|
FASTCALL
|
|
|
|
CreateUIUserData( ULONG_PTR *puserdata, HANDLE hPrinter )
|
2015-06-22 14:31:47 +00:00
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
PCOMPUI_USERDATA pcui_ud = DllAllocSplMem( sizeof(COMPUI_USERDATA) );
|
2019-01-06 01:24:42 +00:00
|
|
|
|
2020-08-04 02:07:58 +00:00
|
|
|
*puserdata = (ULONG_PTR)pcui_ud;
|
|
|
|
FIXME("CreateUIUserData\n");
|
|
|
|
if ( pcui_ud )
|
2019-01-06 01:24:42 +00:00
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
pcui_ud->hModule = LoadPrinterDriver( hPrinter );
|
|
|
|
|
|
|
|
if ( !pcui_ud->hModule )
|
|
|
|
{
|
|
|
|
DllFreeSplMem( pcui_ud );
|
|
|
|
*puserdata = 0;
|
|
|
|
}
|
2019-01-06 01:24:42 +00:00
|
|
|
}
|
2020-08-04 02:07:58 +00:00
|
|
|
return *puserdata != 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
FASTCALL
|
|
|
|
DestroyUIUserData( ULONG_PTR *puserdata )
|
|
|
|
{
|
|
|
|
PCOMPUI_USERDATA pcui_ud = (PCOMPUI_USERDATA)*puserdata;
|
|
|
|
FIXME("DestroyUIUserData\n");
|
|
|
|
if ( pcui_ud )
|
2019-01-06 01:24:42 +00:00
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
if ( pcui_ud->hModule )
|
|
|
|
{
|
|
|
|
FreeLibrary( pcui_ud->hModule );
|
|
|
|
pcui_ud->hModule = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( pcui_ud->pszPrinterName )
|
|
|
|
{
|
|
|
|
DllFreeSplMem( pcui_ud->pszPrinterName );
|
|
|
|
pcui_ud->pszPrinterName = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
DllFreeSplMem( pcui_ud );
|
|
|
|
*puserdata = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
|
|
FASTCALL
|
|
|
|
IntFixUpDevModeNames( PDOCUMENTPROPERTYHEADER pdphdr )
|
|
|
|
{
|
|
|
|
PRINTER_INFO_2W *pi2 = NULL;
|
|
|
|
DWORD needed = 0;
|
|
|
|
BOOL res;
|
|
|
|
|
|
|
|
if (!(pdphdr->fMode & DM_OUT_BUFFER) ||
|
|
|
|
pdphdr->fMode & DM_NOPERMISSION || // Do not allow the user to modify properties on the displayed property sheet pages.
|
|
|
|
!pdphdr->pdmOut )
|
|
|
|
{
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
res = GetPrinterW( pdphdr->hPrinter, 2, NULL, 0, &needed);
|
|
|
|
if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
|
|
|
|
{
|
|
|
|
pi2 = HeapAlloc(hProcessHeap, 0, needed);
|
|
|
|
res = GetPrinterW( pdphdr->hPrinter, 2, (LPBYTE)pi2, needed, &needed);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (res)
|
|
|
|
{
|
|
|
|
FIXME("IFUDMN : Get Printer Name %S\n",pi2->pPrinterName);
|
|
|
|
StringCchCopyW( pdphdr->pdmOut->dmDeviceName, CCHDEVICENAME-1, pi2->pPrinterName );
|
|
|
|
pdphdr->pdmOut->dmDeviceName[CCHDEVICENAME-1] = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ERR("IFUDMN : GetPrinterW failed with %u\n", GetLastError());
|
|
|
|
}
|
|
|
|
HeapFree(hProcessHeap, 0, pi2);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
LONG
|
|
|
|
WINAPI
|
|
|
|
CreatePrinterFriendlyName( PCOMPUI_USERDATA pcui_ud, LPWSTR pszPrinterName )
|
|
|
|
{
|
|
|
|
LONG Result = 0;
|
|
|
|
DWORD Size = 0;
|
|
|
|
HMODULE hLibrary = NULL;
|
|
|
|
|
|
|
|
hLibrary = LoadLibraryA( "printui.dll" );
|
|
|
|
|
|
|
|
if ( hLibrary )
|
|
|
|
{
|
|
|
|
fpConstructPrinterFriendlyName = (PVOID)GetProcAddress( hLibrary, "ConstructPrinterFriendlyName" );
|
|
|
|
|
|
|
|
if ( fpConstructPrinterFriendlyName )
|
|
|
|
{
|
|
|
|
if ( !fpConstructPrinterFriendlyName( pszPrinterName, NULL, &Size ) )
|
|
|
|
{
|
|
|
|
if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
|
|
|
|
{
|
|
|
|
PWSTR pwstr = DllAllocSplMem( (Size + 1) * sizeof(WCHAR) );
|
|
|
|
|
|
|
|
pcui_ud->pszPrinterName = pwstr;
|
|
|
|
|
|
|
|
if ( pwstr )
|
|
|
|
Result = fpConstructPrinterFriendlyName( pszPrinterName, pwstr, &Size );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FreeLibrary( hLibrary );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !Result )
|
|
|
|
{
|
|
|
|
DllFreeSplMem( pcui_ud->pszPrinterName );
|
|
|
|
pcui_ud->pszPrinterName = AllocSplStr( pszPrinterName );
|
2019-01-06 01:24:42 +00:00
|
|
|
}
|
|
|
|
|
2020-08-04 02:07:58 +00:00
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Tested with XP CompstUI as a callback and works. Fails perfectly.
|
|
|
|
//
|
|
|
|
LONG
|
|
|
|
WINAPI
|
|
|
|
DocumentPropertySheets( PPROPSHEETUI_INFO pCPSUIInfo, LPARAM lparam )
|
|
|
|
{
|
|
|
|
LONG Result = -1;
|
|
|
|
PDOCUMENTPROPERTYHEADER pdphdr;
|
|
|
|
|
|
|
|
FIXME("DocumentPropertySheets(%p, 0x%lx)\n", pCPSUIInfo, lparam);
|
2019-01-06 01:24:42 +00:00
|
|
|
|
2020-08-04 02:07:58 +00:00
|
|
|
// If pPSUIInfo is NULL, and if either lParam -> fMode is zero or lParam -> pdmOut is NULL,
|
|
|
|
// this function should return the size, in bytes, of the printer's DEVMODEW structure.
|
|
|
|
if ( !pCPSUIInfo && lparam )
|
2019-01-06 01:24:42 +00:00
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
pdphdr = (PDOCUMENTPROPERTYHEADER)lparam;
|
|
|
|
|
|
|
|
if ( pdphdr->cbSize >= sizeof(PDOCUMENTPROPERTYHEADER) &&
|
|
|
|
!(pdphdr->fMode & DM_PROMPT) )
|
2019-01-06 01:24:42 +00:00
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
HMODULE hLibrary = LoadPrinterDriver( pdphdr->hPrinter );
|
2019-01-06 01:24:42 +00:00
|
|
|
|
2020-08-04 02:07:58 +00:00
|
|
|
if ( hLibrary )
|
2019-01-06 01:24:42 +00:00
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
fpDocumentPropertySheets = (PVOID)GetProcAddress( hLibrary, "DrvDocumentPropertySheets" );
|
|
|
|
|
|
|
|
if ( fpDocumentPropertySheets )
|
|
|
|
{
|
2020-09-08 18:15:16 +00:00
|
|
|
FIXME("DPS : fpDocumentPropertySheets(%p, 0x%lx) pdmOut %p\n", pCPSUIInfo, lparam, pdphdr->pdmOut);
|
2020-08-04 02:07:58 +00:00
|
|
|
Result = fpDocumentPropertySheets( pCPSUIInfo, lparam );
|
2020-09-08 18:15:16 +00:00
|
|
|
FIXME("DPS : fpDocumentPropertySheets result %d cbOut %d\n",Result, pdphdr->cbOut);
|
2020-08-04 02:07:58 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// ReactOS backup!!! Currently no supporting UI driver.
|
|
|
|
//
|
|
|
|
PRINTER_INFO_9W * pi9 = get_devmodeW( pdphdr->hPrinter );
|
|
|
|
if ( pi9 )
|
|
|
|
{
|
|
|
|
Result = pi9->pDevMode->dmSize + pi9->pDevMode->dmDriverExtra;
|
|
|
|
FIXME("IDPS : Using ReactOS backup!!! DevMode Size %d\n",Result);
|
|
|
|
HeapFree(hProcessHeap, 0, pi9);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FreeLibrary(hLibrary);
|
2019-01-06 01:24:42 +00:00
|
|
|
|
2020-08-04 02:07:58 +00:00
|
|
|
if ( Result > 0 )
|
|
|
|
{
|
|
|
|
IntFixUpDevModeNames( pdphdr );
|
|
|
|
}
|
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
else
|
2019-01-06 01:24:42 +00:00
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
2019-01-06 01:24:42 +00:00
|
|
|
}
|
2020-08-04 02:07:58 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
}
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
Result = 0;
|
|
|
|
|
|
|
|
if ( pCPSUIInfo )
|
|
|
|
{
|
|
|
|
PSETRESULT_INFO psri;
|
|
|
|
PPROPSHEETUI_INFO_HEADER ppsuiihdr;
|
|
|
|
PCOMPUI_USERDATA pcui_ud;
|
|
|
|
pdphdr = (PDOCUMENTPROPERTYHEADER)pCPSUIInfo->lParamInit;
|
2019-01-06 01:24:42 +00:00
|
|
|
|
2020-08-04 02:07:58 +00:00
|
|
|
if ( pdphdr->cbSize < sizeof(PDOCUMENTPROPERTYHEADER) )
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch ( pCPSUIInfo->Reason )
|
|
|
|
{
|
|
|
|
case PROPSHEETUI_REASON_INIT:
|
2019-01-06 01:24:42 +00:00
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
FIXME("DocPS : PROPSHEETUI_REASON_INIT\n");
|
|
|
|
if ( CreateUIUserData( &pCPSUIInfo->UserData, pdphdr->hPrinter ) )
|
|
|
|
{
|
|
|
|
pcui_ud = (PCOMPUI_USERDATA)pCPSUIInfo->UserData;
|
|
|
|
|
|
|
|
fpDocumentPropertySheets = (PVOID)GetProcAddress( pcui_ud->hModule, "DrvDocumentPropertySheets" );
|
|
|
|
|
|
|
|
if ( fpDocumentPropertySheets )
|
|
|
|
{
|
|
|
|
pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet,
|
|
|
|
CPSFUNC_SET_FUSION_CONTEXT,
|
|
|
|
-3, // What type of handle is this?
|
|
|
|
0 ); // Not used, must be zero.
|
|
|
|
|
|
|
|
Result = pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet,
|
|
|
|
CPSFUNC_ADD_PFNPROPSHEETUIW,
|
|
|
|
(LPARAM)fpDocumentPropertySheets,
|
|
|
|
pCPSUIInfo->lParamInit );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
FIXME("DocPS : PROPSHEETUI_REASON_INIT Fail\n");
|
|
|
|
DestroyUIUserData( &pCPSUIInfo->UserData );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROPSHEETUI_REASON_GET_INFO_HEADER:
|
|
|
|
FIXME("DocPS : PROPSHEETUI_REASON_GET_INFO_HEADER\n");
|
|
|
|
|
|
|
|
ppsuiihdr = (PPROPSHEETUI_INFO_HEADER)lparam;
|
|
|
|
|
|
|
|
pcui_ud = (PCOMPUI_USERDATA)pCPSUIInfo->UserData;
|
|
|
|
|
|
|
|
CreatePrinterFriendlyName( pcui_ud, pdphdr->pszPrinterName );
|
|
|
|
|
|
|
|
ppsuiihdr->Flags = PSUIHDRF_NOAPPLYNOW|PSUIHDRF_PROPTITLE;
|
|
|
|
ppsuiihdr->pTitle = pcui_ud->pszPrinterName;
|
|
|
|
ppsuiihdr->hInst = hinstWinSpool;
|
|
|
|
ppsuiihdr->IconID = IDI_CPSUI_DOCUMENT;
|
|
|
|
|
|
|
|
Result = CPSUI_OK;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROPSHEETUI_REASON_DESTROY:
|
|
|
|
FIXME("DocPS : PROPSHEETUI_REASON_DESTROY\n");
|
|
|
|
DestroyUIUserData( &pCPSUIInfo->UserData );
|
|
|
|
Result = CPSUI_OK;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROPSHEETUI_REASON_SET_RESULT:
|
|
|
|
FIXME("DocPS : PROPSHEETUI_REASON_SET_RESULT\n");
|
|
|
|
|
|
|
|
psri = (PSETRESULT_INFO)lparam;
|
|
|
|
|
|
|
|
pCPSUIInfo->Result = psri->Result;
|
|
|
|
if ( pCPSUIInfo->Result > 0 )
|
2019-01-06 01:24:42 +00:00
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
IntFixUpDevModeNames( pdphdr );
|
2019-01-06 01:24:42 +00:00
|
|
|
}
|
2020-08-04 02:07:58 +00:00
|
|
|
Result = CPSUI_OK;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
LONG
|
|
|
|
WINAPI
|
|
|
|
DevicePropertySheets( PPROPSHEETUI_INFO pCPSUIInfo, LPARAM lparam )
|
|
|
|
{
|
|
|
|
LONG Result = 0;
|
|
|
|
PDEVICEPROPERTYHEADER pdphdr;
|
|
|
|
|
|
|
|
FIXME("DevicePropertySheets(%p, 0x%lx)\n", pCPSUIInfo, lparam);
|
|
|
|
|
|
|
|
if ( pCPSUIInfo )
|
|
|
|
{
|
|
|
|
PSETRESULT_INFO psri;
|
|
|
|
PPROPSHEETUI_INFO_HEADER ppsuiihdr;
|
|
|
|
PCOMPUI_USERDATA pcui_ud;
|
|
|
|
pdphdr = (PDEVICEPROPERTYHEADER)pCPSUIInfo->lParamInit;
|
|
|
|
|
|
|
|
if ( pdphdr->cbSize < sizeof(DEVICEPROPERTYHEADER) )
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch ( pCPSUIInfo->Reason )
|
|
|
|
{
|
|
|
|
case PROPSHEETUI_REASON_INIT:
|
|
|
|
{
|
|
|
|
FIXME("DevPS : PROPSHEETUI_REASON_INIT\n");
|
|
|
|
if ( CreateUIUserData( &pCPSUIInfo->UserData, pdphdr->hPrinter ) )
|
2019-01-06 01:24:42 +00:00
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
pcui_ud = (PCOMPUI_USERDATA)pCPSUIInfo->UserData;
|
|
|
|
|
|
|
|
fpDevicePropertySheets = (PVOID)GetProcAddress( pcui_ud->hModule, "DrvDevicePropertySheets" );
|
|
|
|
|
|
|
|
if ( fpDevicePropertySheets )
|
|
|
|
{
|
|
|
|
pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet,
|
|
|
|
CPSFUNC_SET_FUSION_CONTEXT,
|
|
|
|
-3, // What type of handle is this?
|
|
|
|
0 ); // Not used, must be zero.
|
|
|
|
|
|
|
|
Result = pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet,
|
|
|
|
CPSFUNC_ADD_PFNPROPSHEETUIW,
|
|
|
|
(LPARAM)fpDevicePropertySheets,
|
|
|
|
pCPSUIInfo->lParamInit );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
FIXME("DevPS : PROPSHEETUI_REASON_INIT Fail\n");
|
|
|
|
DestroyUIUserData( &pCPSUIInfo->UserData );
|
2019-01-06 01:24:42 +00:00
|
|
|
}
|
|
|
|
}
|
2020-08-04 02:07:58 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case PROPSHEETUI_REASON_GET_INFO_HEADER:
|
|
|
|
FIXME("DevPS : PROPSHEETUI_REASON_GET_INFO_HEADER\n");
|
|
|
|
|
|
|
|
ppsuiihdr = (PPROPSHEETUI_INFO_HEADER)lparam;
|
|
|
|
|
|
|
|
pcui_ud = (PCOMPUI_USERDATA)pCPSUIInfo->UserData;
|
|
|
|
|
|
|
|
CreatePrinterFriendlyName( pcui_ud, pdphdr->pszPrinterName );
|
|
|
|
|
|
|
|
ppsuiihdr->Flags = PSUIHDRF_NOAPPLYNOW|PSUIHDRF_PROPTITLE;
|
|
|
|
ppsuiihdr->pTitle = pcui_ud->pszPrinterName;
|
|
|
|
ppsuiihdr->hInst = hinstWinSpool;
|
|
|
|
ppsuiihdr->IconID = IDI_CPSUI_DOCUMENT;
|
|
|
|
|
|
|
|
Result = CPSUI_OK;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROPSHEETUI_REASON_DESTROY:
|
|
|
|
FIXME("DevPS : PROPSHEETUI_REASON_DESTROY\n");
|
|
|
|
DestroyUIUserData( &pCPSUIInfo->UserData );
|
|
|
|
Result = CPSUI_OK;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROPSHEETUI_REASON_SET_RESULT:
|
|
|
|
FIXME("DevPS : PROPSHEETUI_REASON_SET_RESULT\n");
|
|
|
|
psri = (PSETRESULT_INFO)lparam;
|
|
|
|
pCPSUIInfo->Result = psri->Result;
|
|
|
|
Result = CPSUI_OK;
|
|
|
|
break;
|
2019-01-06 01:24:42 +00:00
|
|
|
}
|
2020-08-04 02:07:58 +00:00
|
|
|
}
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
|
|
|
LONG
|
|
|
|
WINAPI
|
|
|
|
CallCommonPropertySheetUI(HWND hWnd, PFNPROPSHEETUI pfnPropSheetUI, LPARAM lparam, LPDWORD pResult)
|
|
|
|
{
|
|
|
|
HMODULE hLibrary = NULL;
|
|
|
|
LONG Ret = ERR_CPSUI_GETLASTERROR;
|
|
|
|
|
|
|
|
FIXME("CallCommonPropertySheetUI(%p, %p, 0x%lx, %p)\n", hWnd, pfnPropSheetUI, lparam, pResult);
|
|
|
|
|
|
|
|
if ( ( hLibrary = LoadLibraryA( "compstui.dll" ) ) )
|
|
|
|
{
|
|
|
|
fpCommonPropertySheetUIW = (PVOID) GetProcAddress(hLibrary, "CommonPropertySheetUIW");
|
|
|
|
|
|
|
|
if ( fpCommonPropertySheetUIW )
|
|
|
|
{
|
|
|
|
Ret = fpCommonPropertySheetUIW( hWnd, pfnPropSheetUI, lparam, pResult );
|
|
|
|
}
|
|
|
|
|
|
|
|
FreeLibrary(hLibrary);
|
|
|
|
}
|
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
LONG WINAPI
|
|
|
|
DocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName, PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput, DWORD fMode)
|
|
|
|
{
|
|
|
|
HANDLE hUseHandle = NULL;
|
|
|
|
DOCUMENTPROPERTYHEADER docprophdr;
|
|
|
|
LONG Result = IDOK;
|
|
|
|
|
|
|
|
FIXME("DocumentPropertiesW(%p, %p, %S, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode);
|
|
|
|
|
|
|
|
if (hPrinter)
|
|
|
|
{
|
|
|
|
hUseHandle = hPrinter;
|
|
|
|
}
|
|
|
|
else if (!OpenPrinterW(pDeviceName, &hUseHandle, NULL))
|
|
|
|
{
|
|
|
|
ERR("No handle, and no usable printer name passed in\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !(fMode & DM_IN_BUFFER ) ||
|
|
|
|
( ( pDevModeInput && !IsValidDevmodeNoSizeW( (PDEVMODEW)pDevModeInput ) ) ) )
|
|
|
|
{
|
|
|
|
pDevModeInput = NULL;
|
|
|
|
fMode &= ~DM_IN_BUFFER;
|
|
|
|
}
|
|
|
|
|
|
|
|
docprophdr.cbSize = sizeof(DOCUMENTPROPERTYHEADER);
|
|
|
|
docprophdr.Reserved = 0;
|
|
|
|
docprophdr.hPrinter = hUseHandle;
|
|
|
|
docprophdr.pszPrinterName = pDeviceName;
|
|
|
|
docprophdr.cbOut = 0;
|
|
|
|
|
|
|
|
if ( pDevModeOutput )
|
|
|
|
{
|
|
|
|
docprophdr.pdmIn = NULL;
|
|
|
|
docprophdr.pdmOut = NULL;
|
|
|
|
docprophdr.fMode = 0;
|
|
|
|
FIXME("DPW : Call DocumentPropertySheets with pDevModeOutput %p\n",pDevModeOutput);
|
|
|
|
docprophdr.cbOut = DocumentPropertySheets( NULL, (LPARAM)&docprophdr );
|
|
|
|
}
|
|
|
|
|
|
|
|
docprophdr.pdmIn = pDevModeInput;
|
|
|
|
docprophdr.pdmOut = pDevModeOutput;
|
|
|
|
docprophdr.fMode = fMode;
|
|
|
|
|
|
|
|
if ( fMode & DM_IN_PROMPT )
|
|
|
|
{
|
|
|
|
Result = CPSUI_CANCEL;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Now call the Property Sheet for Print > Properties.
|
|
|
|
//
|
|
|
|
if ( CallCommonPropertySheetUI( hWnd, (PFNPROPSHEETUI)DocumentPropertySheets, (LPARAM)&docprophdr, (LPDWORD)&Result ) < 0 )
|
2019-01-06 01:24:42 +00:00
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
FIXME("CallCommonPropertySheetUI return error\n");
|
|
|
|
Result = ERR_CPSUI_GETLASTERROR;
|
2019-01-06 01:24:42 +00:00
|
|
|
}
|
2020-08-04 02:07:58 +00:00
|
|
|
else
|
|
|
|
Result = (Result == CPSUI_OK) ? IDOK : IDCANCEL;
|
|
|
|
FIXME("CallCommonPropertySheetUI returned\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FIXME("DPW : CallDocumentPropertySheets\n");
|
|
|
|
Result = DocumentPropertySheets( NULL, (LPARAM)&docprophdr );
|
|
|
|
}
|
2019-01-06 01:24:42 +00:00
|
|
|
|
2020-08-04 02:07:58 +00:00
|
|
|
if ( Result != ERR_CPSUI_GETLASTERROR || Result != ERR_CPSUI_ALLOCMEM_FAILED )
|
|
|
|
{
|
|
|
|
if ( pDevModeOutput )
|
|
|
|
{
|
|
|
|
if ( !IsValidDevmodeNoSizeW( pDevModeOutput ) )
|
|
|
|
{
|
|
|
|
ERR("DPW : Improper pDevModeOutput size.\n");
|
|
|
|
Result = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ERR("No pDevModeOutput\n");
|
|
|
|
}
|
2019-01-06 01:24:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (hUseHandle && !hPrinter)
|
|
|
|
ClosePrinter(hUseHandle);
|
|
|
|
return Result;
|
2015-06-22 14:31:47 +00:00
|
|
|
}
|
|
|
|
|
2020-08-04 02:07:58 +00:00
|
|
|
BOOL
|
|
|
|
WINAPI
|
|
|
|
PrinterProperties( HWND hWnd, HANDLE hPrinter )
|
|
|
|
{
|
|
|
|
PRINTER_INFO_2W *pi2 = NULL;
|
|
|
|
DWORD needed = 0;
|
|
|
|
LONG Ret, Result = 0;
|
|
|
|
BOOL res;
|
|
|
|
DEVICEPROPERTYHEADER devprophdr;
|
|
|
|
|
|
|
|
FIXME("PrinterProperties(%p, %p)\n", hWnd, hPrinter);
|
|
|
|
|
|
|
|
devprophdr.cbSize = sizeof(DEVICEPROPERTYHEADER);
|
|
|
|
devprophdr.Flags = DPS_NOPERMISSION;
|
|
|
|
devprophdr.hPrinter = hPrinter;
|
|
|
|
devprophdr.pszPrinterName = NULL;
|
|
|
|
|
|
|
|
res = GetPrinterW( hPrinter, 2, NULL, 0, &needed);
|
|
|
|
if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
|
|
|
|
{
|
|
|
|
pi2 = HeapAlloc(hProcessHeap, 0, needed);
|
|
|
|
res = GetPrinterW(hPrinter, 2, (LPBYTE)pi2, needed, &needed);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Above can fail, still process w/o printer name.
|
|
|
|
//
|
|
|
|
if ( res ) devprophdr.pszPrinterName = pi2->pPrinterName;
|
|
|
|
|
|
|
|
needed = 1;
|
|
|
|
|
|
|
|
if ( ( SetPrinterDataW( hPrinter, L"PrinterPropertiesPermission", REG_DWORD, (LPBYTE)&needed, sizeof(DWORD) ) == ERROR_SUCCESS ) )
|
|
|
|
{
|
|
|
|
devprophdr.Flags &= ~DPS_NOPERMISSION;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ret = CallCommonPropertySheetUI( hWnd, (PFNPROPSHEETUI)DevicePropertySheets, (LPARAM)&devprophdr, (LPDWORD)&Result );
|
|
|
|
|
|
|
|
res = (Ret >= 0);
|
|
|
|
|
|
|
|
if (!res)
|
|
|
|
{
|
|
|
|
FIXME("PrinterProperties fail ICPSUI\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pi2) HeapFree(hProcessHeap, 0, pi2);
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2015-06-22 14:31:47 +00:00
|
|
|
BOOL WINAPI
|
|
|
|
EndDocPrinter(HANDLE hPrinter)
|
|
|
|
{
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
DWORD dwErrorCode;
|
|
|
|
PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
|
|
|
|
|
2017-12-09 11:00:09 +00:00
|
|
|
TRACE("EndDocPrinter(%p)\n", hPrinter);
|
|
|
|
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
// 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.
|
2020-08-04 02:07:58 +00:00
|
|
|
pHandle->bTrayIcon = pHandle->bJob = pHandle->bStartedDoc = FALSE;
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
SetLastError(dwErrorCode);
|
|
|
|
return (dwErrorCode == ERROR_SUCCESS);
|
2015-06-22 14:31:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI
|
|
|
|
EndPagePrinter(HANDLE hPrinter)
|
|
|
|
{
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
DWORD dwErrorCode;
|
|
|
|
PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
|
|
|
|
|
2017-12-09 11:00:09 +00:00
|
|
|
TRACE("EndPagePrinter(%p)\n", hPrinter);
|
|
|
|
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
// 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);
|
2015-06-22 14:31:47 +00:00
|
|
|
}
|
|
|
|
|
2015-07-17 10:57:10 +00:00
|
|
|
BOOL WINAPI
|
|
|
|
EnumPrintersA(DWORD Flags, PSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
|
|
|
|
{
|
2020-04-27 20:10:22 +00:00
|
|
|
DWORD dwErrorCode;
|
2020-01-31 17:42:55 +00:00
|
|
|
DWORD cch;
|
|
|
|
PWSTR pwszName = NULL;
|
|
|
|
PSTR pszPrinterName = NULL;
|
|
|
|
PSTR pszServerName = NULL;
|
|
|
|
PSTR pszDescription = NULL;
|
|
|
|
PSTR pszName = NULL;
|
|
|
|
PSTR pszComment = NULL;
|
|
|
|
PSTR pszShareName = NULL;
|
|
|
|
PSTR pszPortName = NULL;
|
|
|
|
PSTR pszDriverName = NULL;
|
|
|
|
PSTR pszLocation = NULL;
|
|
|
|
PSTR pszSepFile = NULL;
|
|
|
|
PSTR pszPrintProcessor = NULL;
|
|
|
|
PSTR pszDatatype = NULL;
|
|
|
|
PSTR pszParameters = NULL;
|
|
|
|
DWORD i;
|
|
|
|
PPRINTER_INFO_1W ppi1w = NULL;
|
|
|
|
PPRINTER_INFO_1A ppi1a = NULL;
|
|
|
|
PPRINTER_INFO_2W ppi2w = NULL;
|
|
|
|
PPRINTER_INFO_2A ppi2a = NULL;
|
|
|
|
PPRINTER_INFO_4W ppi4w = NULL;
|
|
|
|
PPRINTER_INFO_4A ppi4a = NULL;
|
|
|
|
PPRINTER_INFO_5W ppi5w = NULL;
|
|
|
|
PPRINTER_INFO_5A ppi5a = NULL;
|
|
|
|
|
2017-12-09 11:00:09 +00:00
|
|
|
TRACE("EnumPrintersA(%lu, %s, %lu, %p, %lu, %p, %p)\n", Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
|
2020-01-31 17:42:55 +00:00
|
|
|
|
|
|
|
// Check for invalid levels here for early error return. MSDN says that only 1, 2, 4, and 5 are allowable.
|
|
|
|
if (Level != 1 && Level != 2 && Level != 4 && Level != 5)
|
|
|
|
{
|
2020-04-27 20:10:22 +00:00
|
|
|
dwErrorCode = ERROR_INVALID_LEVEL;
|
2020-01-31 17:42:55 +00:00
|
|
|
ERR("Invalid Level!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Name)
|
|
|
|
{
|
|
|
|
// Convert pName to a Unicode string pwszName.
|
|
|
|
cch = strlen(Name);
|
|
|
|
|
|
|
|
pwszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
|
|
|
|
if (!pwszName)
|
|
|
|
{
|
2020-04-27 20:10:22 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-01-31 17:42:55 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
MultiByteToWideChar(CP_ACP, 0, Name, -1, pwszName, cch + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Ref: https://stackoverflow.com/questions/41147180/why-enumprintersa-and-enumprintersw-request-the-same-amount-of-memory */
|
2020-05-26 18:21:25 +00:00
|
|
|
if (!EnumPrintersW(Flags, pwszName, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned))
|
2020-04-27 20:10:22 +00:00
|
|
|
{
|
|
|
|
dwErrorCode = GetLastError();
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
2020-01-31 17:42:55 +00:00
|
|
|
|
|
|
|
/* We are mapping multiple different pointers to the same pPrinterEnum pointer here so that */
|
|
|
|
/* we can do in-place conversion. We read the Unicode response from the EnumPrintersW and */
|
|
|
|
/* then we write back the ANSI conversion into the same buffer for our EnumPrintersA output */
|
|
|
|
|
|
|
|
/* mapping to pPrinterEnum for Unicode (w) characters for Levels 1, 2, 4, and 5 */
|
|
|
|
ppi1w = (PPRINTER_INFO_1W)pPrinterEnum;
|
|
|
|
ppi2w = (PPRINTER_INFO_2W)pPrinterEnum;
|
|
|
|
ppi4w = (PPRINTER_INFO_4W)pPrinterEnum;
|
|
|
|
ppi5w = (PPRINTER_INFO_5W)pPrinterEnum;
|
|
|
|
/* mapping to pPrinterEnum for ANSI (a) characters for Levels 1, 2, 4, and 5 */
|
|
|
|
ppi1a = (PPRINTER_INFO_1A)pPrinterEnum;
|
|
|
|
ppi2a = (PPRINTER_INFO_2A)pPrinterEnum;
|
|
|
|
ppi4a = (PPRINTER_INFO_4A)pPrinterEnum;
|
|
|
|
ppi5a = (PPRINTER_INFO_5A)pPrinterEnum;
|
|
|
|
|
|
|
|
for (i = 0; i < *pcReturned; i++)
|
|
|
|
{
|
|
|
|
switch (Level)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
{
|
|
|
|
if (ppi1w[i].pDescription)
|
|
|
|
{
|
|
|
|
// Convert Unicode pDescription to a ANSI string pszDescription.
|
|
|
|
cch = wcslen(ppi1w[i].pDescription);
|
|
|
|
|
|
|
|
pszDescription = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszDescription)
|
|
|
|
{
|
2020-04-27 20:10:22 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-01-31 17:42:55 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
2020-01-31 17:47:53 +00:00
|
|
|
goto Cleanup;
|
2020-01-31 17:42:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pDescription, -1, pszDescription, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi1a[i].pDescription, cch + 1, pszDescription);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszDescription);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi1w[i].pName)
|
|
|
|
{
|
|
|
|
// Convert Unicode pName to a ANSI string pszName.
|
|
|
|
cch = wcslen(ppi1w[i].pName);
|
|
|
|
|
|
|
|
pszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszName)
|
|
|
|
{
|
2020-04-27 20:10:22 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-01-31 17:42:55 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pName, -1, pszName, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi1a[i].pName, cch + 1, pszName);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszName);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi1w[i].pComment)
|
|
|
|
{
|
|
|
|
// Convert Unicode pComment to a ANSI string pszComment.
|
|
|
|
cch = wcslen(ppi1w[i].pComment);
|
|
|
|
|
|
|
|
pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszComment)
|
|
|
|
{
|
2020-04-27 20:10:22 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-01-31 17:42:55 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pComment, -1, pszComment, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi1a[i].pComment, cch + 1, pszComment);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszComment);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
{
|
|
|
|
if (ppi2w[i].pServerName)
|
|
|
|
{
|
|
|
|
// Convert Unicode pServerName to a ANSI string pszServerName.
|
|
|
|
cch = wcslen(ppi2w[i].pServerName);
|
|
|
|
|
|
|
|
pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszServerName)
|
|
|
|
{
|
2020-04-27 20:10:22 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-01-31 17:42:55 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
2020-01-31 17:47:53 +00:00
|
|
|
goto Cleanup;
|
2020-01-31 17:42:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pServerName, -1, pszServerName, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi2a[i].pServerName, cch + 1, pszServerName);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszServerName);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi2w[i].pPrinterName)
|
|
|
|
{
|
|
|
|
// Convert Unicode pPrinterName to a ANSI string pszPrinterName.
|
|
|
|
cch = wcslen(ppi2w[i].pPrinterName);
|
|
|
|
|
|
|
|
pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszPrinterName)
|
|
|
|
{
|
2020-04-27 20:10:22 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-01-31 17:42:55 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi2a[i].pPrinterName, cch + 1, pszPrinterName);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszPrinterName);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi2w[i].pShareName)
|
|
|
|
{
|
|
|
|
// Convert Unicode pShareName to a ANSI string pszShareName.
|
|
|
|
cch = wcslen(ppi2w[i].pShareName);
|
|
|
|
|
|
|
|
pszShareName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszShareName)
|
|
|
|
{
|
2020-04-27 20:10:22 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-01-31 17:42:55 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pShareName, -1, pszShareName, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi2a[i].pShareName, cch + 1, pszShareName);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszShareName);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi2w[i].pPortName)
|
|
|
|
{
|
|
|
|
// Convert Unicode pPortName to a ANSI string pszPortName.
|
|
|
|
cch = wcslen(ppi2w[i].pPortName);
|
|
|
|
|
|
|
|
pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszPortName)
|
|
|
|
{
|
2020-04-27 20:10:22 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-01-31 17:42:55 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPortName, -1, pszPortName, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi2a[i].pPortName, cch + 1, pszPortName);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszPortName);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi2w[i].pDriverName)
|
|
|
|
{
|
|
|
|
// Convert Unicode pDriverName to a ANSI string pszDriverName.
|
|
|
|
cch = wcslen(ppi2w[i].pDriverName);
|
|
|
|
|
|
|
|
pszDriverName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszDriverName)
|
|
|
|
{
|
2020-04-27 20:10:22 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-01-31 17:42:55 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pDriverName, -1, pszDriverName, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi2a[i].pDriverName, cch + 1, pszDriverName);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszDriverName);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi2w[i].pComment)
|
|
|
|
{
|
|
|
|
// Convert Unicode pComment to a ANSI string pszComment.
|
|
|
|
cch = wcslen(ppi2w[i].pComment);
|
|
|
|
|
|
|
|
pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszComment)
|
|
|
|
{
|
2020-04-27 20:10:22 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-01-31 17:42:55 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pComment, -1, pszComment, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi2a[i].pComment, cch + 1, pszComment);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszComment);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi2w[i].pLocation)
|
|
|
|
{
|
|
|
|
// Convert Unicode pLocation to a ANSI string pszLocation.
|
|
|
|
cch = wcslen(ppi2w[i].pLocation);
|
|
|
|
|
|
|
|
pszLocation = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszLocation)
|
|
|
|
{
|
2020-04-27 20:10:22 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-01-31 17:42:55 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pLocation, -1, pszLocation, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi2a[i].pLocation, cch + 1, pszLocation);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszLocation);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (ppi2w[i].pSepFile)
|
|
|
|
{
|
|
|
|
// Convert Unicode pSepFile to a ANSI string pszSepFile.
|
|
|
|
cch = wcslen(ppi2w[i].pSepFile);
|
|
|
|
|
|
|
|
pszSepFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszSepFile)
|
|
|
|
{
|
2020-04-27 20:10:22 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-01-31 17:42:55 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pSepFile, -1, pszSepFile, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi2a[i].pSepFile, cch + 1, pszSepFile);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszSepFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi2w[i].pPrintProcessor)
|
|
|
|
{
|
|
|
|
// Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor.
|
|
|
|
cch = wcslen(ppi2w[i].pPrintProcessor);
|
|
|
|
|
|
|
|
pszPrintProcessor = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszPrintProcessor)
|
|
|
|
{
|
2020-04-27 20:10:22 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-01-31 17:42:55 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPrintProcessor, -1, pszPrintProcessor, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi2a[i].pPrintProcessor, cch + 1, pszPrintProcessor);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszPrintProcessor);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (ppi2w[i].pDatatype)
|
|
|
|
{
|
|
|
|
// Convert Unicode pDatatype to a ANSI string pszDatatype.
|
|
|
|
cch = wcslen(ppi2w[i].pDatatype);
|
|
|
|
|
|
|
|
pszDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszDatatype)
|
|
|
|
{
|
2020-04-27 20:10:22 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-01-31 17:42:55 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pDatatype, -1, pszDatatype, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi2a[i].pDatatype, cch + 1, pszDatatype);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszDatatype);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi2w[i].pParameters)
|
|
|
|
{
|
|
|
|
// Convert Unicode pParameters to a ANSI string pszParameters.
|
|
|
|
cch = wcslen(ppi2w[i].pParameters);
|
|
|
|
|
|
|
|
pszParameters = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszParameters)
|
|
|
|
{
|
2020-04-27 20:10:22 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-01-31 17:42:55 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pParameters, -1, pszParameters, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi2a[i].pParameters, cch + 1, pszParameters);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszParameters);
|
|
|
|
}
|
2020-08-04 02:07:58 +00:00
|
|
|
if ( ppi2w[i].pDevMode )
|
|
|
|
{
|
|
|
|
RosConvertUnicodeDevModeToAnsiDevmode( ppi2w[i].pDevMode, ppi2a[i].pDevMode );
|
|
|
|
}
|
2020-01-31 17:42:55 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 4:
|
|
|
|
{
|
|
|
|
if (ppi4w[i].pPrinterName)
|
|
|
|
{
|
|
|
|
// Convert Unicode pPrinterName to a ANSI string pszPrinterName.
|
|
|
|
cch = wcslen(ppi4w[i].pPrinterName);
|
|
|
|
|
|
|
|
pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszPrinterName)
|
|
|
|
{
|
2020-04-27 20:10:22 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-01-31 17:42:55 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
2020-01-31 17:47:53 +00:00
|
|
|
goto Cleanup;
|
2020-01-31 17:42:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi4w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi4a[i].pPrinterName, cch + 1, pszPrinterName);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszPrinterName);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi4w[i].pServerName)
|
|
|
|
{
|
|
|
|
// Convert Unicode pServerName to a ANSI string pszServerName.
|
|
|
|
cch = wcslen(ppi4w[i].pServerName);
|
|
|
|
|
|
|
|
pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszServerName)
|
|
|
|
{
|
2020-04-27 20:10:22 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-01-31 17:42:55 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi4w[i].pServerName, -1, pszServerName, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi4a[i].pServerName, cch + 1, pszServerName);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszServerName);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 5:
|
|
|
|
{
|
|
|
|
if (ppi5w[i].pPrinterName)
|
|
|
|
{
|
|
|
|
// Convert Unicode pPrinterName to a ANSI string pszPrinterName.
|
|
|
|
cch = wcslen(ppi5w[i].pPrinterName);
|
|
|
|
|
|
|
|
pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszPrinterName)
|
|
|
|
{
|
2020-04-27 20:10:22 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-01-31 17:42:55 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi5w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi5a[i].pPrinterName, cch + 1, pszPrinterName);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszPrinterName);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi5w[i].pPortName)
|
|
|
|
{
|
|
|
|
// Convert Unicode pPortName to a ANSI string pszPortName.
|
|
|
|
cch = wcslen(ppi5w[i].pPortName);
|
|
|
|
|
|
|
|
pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszPortName)
|
|
|
|
{
|
2020-04-27 20:10:22 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-01-31 17:42:55 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi5w[i].pPortName, -1, pszPortName, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi5a[i].pPortName, cch + 1, pszPortName);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszPortName);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // switch
|
|
|
|
} // for
|
|
|
|
|
2020-04-27 20:10:22 +00:00
|
|
|
dwErrorCode = ERROR_SUCCESS;
|
|
|
|
|
2020-01-31 17:42:55 +00:00
|
|
|
Cleanup:
|
2020-04-27 20:10:22 +00:00
|
|
|
if (pwszName)
|
|
|
|
{
|
|
|
|
HeapFree(hProcessHeap, 0, pwszName);
|
|
|
|
}
|
2020-01-31 17:42:55 +00:00
|
|
|
|
2020-04-27 20:10:22 +00:00
|
|
|
SetLastError(dwErrorCode);
|
|
|
|
return (dwErrorCode == ERROR_SUCCESS);
|
2015-07-17 10:57:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI
|
|
|
|
EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
|
|
|
|
{
|
|
|
|
DWORD dwErrorCode;
|
|
|
|
|
2017-12-09 11:00:09 +00:00
|
|
|
TRACE("EnumPrintersW(%lu, %S, %lu, %p, %lu, %p, %p)\n", Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
|
|
|
|
|
2017-04-16 14:12:01 +00:00
|
|
|
// Dismiss invalid levels already at this point.
|
|
|
|
if (Level == 3 || Level > 5)
|
|
|
|
{
|
|
|
|
dwErrorCode = ERROR_INVALID_LEVEL;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cbBuf && pPrinterEnum)
|
|
|
|
ZeroMemory(pPrinterEnum, cbBuf);
|
|
|
|
|
2015-07-17 10:57:10 +00:00
|
|
|
// Do the RPC call
|
|
|
|
RpcTryExcept
|
|
|
|
{
|
|
|
|
dwErrorCode = _RpcEnumPrinters(Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
|
|
|
|
}
|
|
|
|
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
{
|
|
|
|
dwErrorCode = RpcExceptionCode();
|
|
|
|
ERR("_RpcEnumPrinters failed with exception code %lu!\n", dwErrorCode);
|
|
|
|
}
|
|
|
|
RpcEndExcept;
|
|
|
|
|
|
|
|
if (dwErrorCode == ERROR_SUCCESS)
|
|
|
|
{
|
2018-01-17 11:52:12 +00:00
|
|
|
// Replace relative offset addresses in the output by absolute pointers.
|
|
|
|
ASSERT(Level <= 9);
|
|
|
|
MarshallUpStructuresArray(cbBuf, pPrinterEnum, *pcReturned, pPrinterInfoMarshalling[Level]->pInfo, pPrinterInfoMarshalling[Level]->cbStructureSize, TRUE);
|
2015-07-17 10:57:10 +00:00
|
|
|
}
|
|
|
|
|
2017-04-16 14:12:01 +00:00
|
|
|
Cleanup:
|
2015-07-17 10:57:10 +00:00
|
|
|
SetLastError(dwErrorCode);
|
|
|
|
return (dwErrorCode == ERROR_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2017-12-09 12:35:42 +00:00
|
|
|
BOOL WINAPI
|
|
|
|
FlushPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten, DWORD cSleep)
|
|
|
|
{
|
|
|
|
TRACE("FlushPrinter(%p, %p, %lu, %p, %lu)\n", hPrinter, pBuf, cbBuf, pcWritten, cSleep);
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2015-06-22 14:31:47 +00:00
|
|
|
BOOL WINAPI
|
|
|
|
GetDefaultPrinterA(LPSTR pszBuffer, LPDWORD pcchBuffer)
|
|
|
|
{
|
2017-05-09 15:44:42 +00:00
|
|
|
DWORD dwErrorCode;
|
|
|
|
PWSTR pwszBuffer = NULL;
|
|
|
|
|
2017-12-09 11:00:09 +00:00
|
|
|
TRACE("GetDefaultPrinterA(%p, %p)\n", pszBuffer, pcchBuffer);
|
|
|
|
|
2017-05-09 15:44:42 +00:00
|
|
|
// Sanity check.
|
|
|
|
if (!pcchBuffer)
|
|
|
|
{
|
|
|
|
dwErrorCode = ERROR_INVALID_PARAMETER;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if an ANSI buffer was given and if so, allocate a Unicode buffer of the same size.
|
|
|
|
if (pszBuffer && *pcchBuffer)
|
|
|
|
{
|
|
|
|
pwszBuffer = HeapAlloc(hProcessHeap, 0, *pcchBuffer * sizeof(WCHAR));
|
|
|
|
if (!pwszBuffer)
|
|
|
|
{
|
[PRINTING]
- Implement GetPrinterDataA, GetPrinterDataExA, GetPrinterDataExW, GetPrinterDataW, SetPrinterDataA, SetPrinterDataExA, SetPrinterDataExW, SetPrinterDataW.
They support all features for Print Server and Printer Handles (minus security checks!)
I've also added tests for them.
- Store Printer data in SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers instead of SYSTEM\CurrentControlSet\Control\Print\Printers and create a registry symlink from the former path to the new one just like Windows does.
According to https://social.technet.microsoft.com/Forums/windowsserver/en-US/a683ab54-c43c-4ebe-af8f-1f7a65af2a51, this is needed when having >900 printers to work around a size limit of the SYSTEM registry hive. And if Windows has both locations, we need both for compatibility anyway.
- Add several settings which are queried by the new Printer Data APIs when working with Print Server Handles.
- Store the job directory in the Windows-compatible "DefaultSpoolDirectory" setting and make use of it.
- Revert the ASSERTs in LocalEnumPrinters again to let us verify the NULL pointer exceptions in localspl_apitest (thanks Serge! CORE-13433)
- Translate ERROR_INVALID_NAME to ERROR_INVALID_PRINTER_NAME in all cases in OpenPrinterW (thanks Victor! CORE-13412)
- Make EnumMonitorsW and EnumPortsW in spoolss more robust against failing Print Monitors.
- Remove the wrong !phPrinter check in OpenPrinterW to make Print Server Handles work for real.
- Fix error handling when memory allocation fails: HeapAlloc doesn't set last error, so it's just wrong to query or return it.
One more item done from https://reactos.org/wiki/Printing !
This is all still a big Work-in-Progress, with many subtle bugs deep down in ReactOS, for which I need to open additional tickets. But I didn't want to make this commit even bigger..
svn path=/trunk/; revision=75125
2017-06-19 14:18:19 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
ERR("HeapAlloc failed!\n");
|
2017-05-09 15:44:42 +00:00
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!GetDefaultPrinterW(pwszBuffer, pcchBuffer))
|
|
|
|
{
|
|
|
|
dwErrorCode = GetLastError();
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
2017-12-09 09:59:40 +00:00
|
|
|
// We successfully got a string in pwszBuffer, so convert the Unicode string to ANSI.
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, *pcchBuffer, NULL, NULL);
|
|
|
|
|
2017-05-09 15:44:42 +00:00
|
|
|
dwErrorCode = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
if (pwszBuffer)
|
|
|
|
HeapFree(hProcessHeap, 0, pwszBuffer);
|
|
|
|
|
|
|
|
SetLastError(dwErrorCode);
|
|
|
|
return (dwErrorCode == ERROR_SUCCESS);
|
2015-06-22 14:31:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI
|
|
|
|
GetDefaultPrinterW(LPWSTR pszBuffer, LPDWORD pcchBuffer)
|
|
|
|
{
|
2017-05-09 15:44:42 +00:00
|
|
|
DWORD cbNeeded;
|
|
|
|
DWORD cchInputBuffer;
|
|
|
|
DWORD dwErrorCode;
|
|
|
|
HKEY hWindowsKey = NULL;
|
|
|
|
PWSTR pwszDevice = NULL;
|
|
|
|
PWSTR pwszComma;
|
|
|
|
|
2017-12-09 11:00:09 +00:00
|
|
|
TRACE("GetDefaultPrinterW(%p, %p)\n", pszBuffer, pcchBuffer);
|
|
|
|
|
2017-05-09 15:44:42 +00:00
|
|
|
// Sanity check.
|
|
|
|
if (!pcchBuffer)
|
|
|
|
{
|
|
|
|
dwErrorCode = ERROR_INVALID_PARAMETER;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
cchInputBuffer = *pcchBuffer;
|
|
|
|
|
|
|
|
// Open the registry key where the default printer for the current user is stored.
|
|
|
|
dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszWindowsKey, 0, KEY_READ, &hWindowsKey);
|
|
|
|
if (dwErrorCode != ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Determine the size of the required buffer.
|
|
|
|
dwErrorCode = (DWORD)RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, NULL, &cbNeeded);
|
|
|
|
if (dwErrorCode != ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allocate it.
|
|
|
|
pwszDevice = HeapAlloc(hProcessHeap, 0, cbNeeded);
|
|
|
|
if (!pwszDevice)
|
|
|
|
{
|
[PRINTING]
- Implement GetPrinterDataA, GetPrinterDataExA, GetPrinterDataExW, GetPrinterDataW, SetPrinterDataA, SetPrinterDataExA, SetPrinterDataExW, SetPrinterDataW.
They support all features for Print Server and Printer Handles (minus security checks!)
I've also added tests for them.
- Store Printer data in SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers instead of SYSTEM\CurrentControlSet\Control\Print\Printers and create a registry symlink from the former path to the new one just like Windows does.
According to https://social.technet.microsoft.com/Forums/windowsserver/en-US/a683ab54-c43c-4ebe-af8f-1f7a65af2a51, this is needed when having >900 printers to work around a size limit of the SYSTEM registry hive. And if Windows has both locations, we need both for compatibility anyway.
- Add several settings which are queried by the new Printer Data APIs when working with Print Server Handles.
- Store the job directory in the Windows-compatible "DefaultSpoolDirectory" setting and make use of it.
- Revert the ASSERTs in LocalEnumPrinters again to let us verify the NULL pointer exceptions in localspl_apitest (thanks Serge! CORE-13433)
- Translate ERROR_INVALID_NAME to ERROR_INVALID_PRINTER_NAME in all cases in OpenPrinterW (thanks Victor! CORE-13412)
- Make EnumMonitorsW and EnumPortsW in spoolss more robust against failing Print Monitors.
- Remove the wrong !phPrinter check in OpenPrinterW to make Print Server Handles work for real.
- Fix error handling when memory allocation fails: HeapAlloc doesn't set last error, so it's just wrong to query or return it.
One more item done from https://reactos.org/wiki/Printing !
This is all still a big Work-in-Progress, with many subtle bugs deep down in ReactOS, for which I need to open additional tickets. But I didn't want to make this commit even bigger..
svn path=/trunk/; revision=75125
2017-06-19 14:18:19 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
ERR("HeapAlloc failed!\n");
|
2017-05-09 15:44:42 +00:00
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now get the actual value.
|
|
|
|
dwErrorCode = RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, (PBYTE)pwszDevice, &cbNeeded);
|
|
|
|
if (dwErrorCode != ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We get a string "<Printer Name>,winspool,<Port>:".
|
|
|
|
// Extract the printer name from it.
|
|
|
|
pwszComma = wcschr(pwszDevice, L',');
|
|
|
|
if (!pwszComma)
|
|
|
|
{
|
|
|
|
ERR("Found no or invalid default printer: %S!\n", pwszDevice);
|
|
|
|
dwErrorCode = ERROR_INVALID_NAME;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Store the length of the Printer Name (including the terminating NUL character!) in *pcchBuffer.
|
|
|
|
*pcchBuffer = pwszComma - pwszDevice + 1;
|
|
|
|
|
|
|
|
// Check if the supplied buffer is large enough.
|
2020-08-04 02:07:58 +00:00
|
|
|
if ( !pszBuffer || cchInputBuffer < *pcchBuffer)
|
2017-05-09 15:44:42 +00:00
|
|
|
{
|
|
|
|
dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy the default printer.
|
|
|
|
*pwszComma = 0;
|
|
|
|
CopyMemory(pszBuffer, pwszDevice, *pcchBuffer * sizeof(WCHAR));
|
|
|
|
|
|
|
|
dwErrorCode = ERROR_SUCCESS;
|
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
if (hWindowsKey)
|
|
|
|
RegCloseKey(hWindowsKey);
|
|
|
|
|
|
|
|
if (pwszDevice)
|
|
|
|
HeapFree(hProcessHeap, 0, pwszDevice);
|
|
|
|
|
|
|
|
SetLastError(dwErrorCode);
|
|
|
|
return (dwErrorCode == ERROR_SUCCESS);
|
2015-06-22 14:31:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI
|
|
|
|
GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
|
|
|
|
{
|
2020-05-23 07:08:00 +00:00
|
|
|
DWORD dwErrorCode;
|
2020-02-06 18:02:46 +00:00
|
|
|
PPRINTER_INFO_1A ppi1a = (PPRINTER_INFO_1A)pPrinter;
|
|
|
|
PPRINTER_INFO_1W ppi1w = (PPRINTER_INFO_1W)pPrinter;
|
|
|
|
PPRINTER_INFO_2A ppi2a = (PPRINTER_INFO_2A)pPrinter;
|
|
|
|
PPRINTER_INFO_2W ppi2w = (PPRINTER_INFO_2W)pPrinter;
|
|
|
|
PPRINTER_INFO_4A ppi4a = (PPRINTER_INFO_4A)pPrinter;
|
|
|
|
PPRINTER_INFO_4W ppi4w = (PPRINTER_INFO_4W)pPrinter;
|
|
|
|
PPRINTER_INFO_5A ppi5a = (PPRINTER_INFO_5A)pPrinter;
|
|
|
|
PPRINTER_INFO_5W ppi5w = (PPRINTER_INFO_5W)pPrinter;
|
|
|
|
PPRINTER_INFO_7A ppi7a = (PPRINTER_INFO_7A)pPrinter;
|
|
|
|
PPRINTER_INFO_7W ppi7w = (PPRINTER_INFO_7W)pPrinter;
|
2020-08-04 02:07:58 +00:00
|
|
|
PPRINTER_INFO_9A ppi9a = (PPRINTER_INFO_9A)pPrinter;
|
|
|
|
PPRINTER_INFO_9W ppi9w = (PPRINTER_INFO_9W)pPrinter;
|
2020-02-06 18:02:46 +00:00
|
|
|
DWORD cch;
|
|
|
|
|
2017-12-09 11:00:09 +00:00
|
|
|
TRACE("GetPrinterA(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
|
2020-02-06 18:02:46 +00:00
|
|
|
|
|
|
|
// Check for invalid levels here for early error return. Should be 1-9.
|
|
|
|
if (Level < 1 || Level > 9)
|
|
|
|
{
|
2020-05-23 07:08:00 +00:00
|
|
|
dwErrorCode = ERROR_INVALID_LEVEL;
|
2020-02-06 18:02:46 +00:00
|
|
|
ERR("Invalid Level!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
2020-05-26 18:21:25 +00:00
|
|
|
if (!GetPrinterW(hPrinter, Level, pPrinter, cbBuf, pcbNeeded))
|
2020-02-06 18:02:46 +00:00
|
|
|
{
|
2020-05-23 07:08:00 +00:00
|
|
|
dwErrorCode = GetLastError();
|
2020-02-06 18:02:46 +00:00
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (Level)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
{
|
|
|
|
if (ppi1w->pDescription)
|
|
|
|
{
|
|
|
|
PSTR pszDescription;
|
|
|
|
|
|
|
|
// Convert Unicode pDescription to a ANSI string pszDescription.
|
|
|
|
cch = wcslen(ppi1w->pDescription);
|
|
|
|
|
|
|
|
pszDescription = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszDescription)
|
|
|
|
{
|
2020-05-23 07:08:00 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-02-06 18:02:46 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi1w->pDescription, -1, pszDescription, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi1a->pDescription, cch + 1, pszDescription);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszDescription);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi1w->pName)
|
|
|
|
{
|
|
|
|
PSTR pszName;
|
|
|
|
|
|
|
|
// Convert Unicode pName to a ANSI string pszName.
|
|
|
|
cch = wcslen(ppi1w->pName);
|
|
|
|
|
|
|
|
pszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszName)
|
|
|
|
{
|
2020-05-23 07:08:00 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-02-06 18:02:46 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi1w->pName, -1, pszName, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi1a->pName, cch + 1, pszName);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszName);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi1w->pComment)
|
|
|
|
{
|
|
|
|
PSTR pszComment;
|
|
|
|
|
|
|
|
// Convert Unicode pComment to a ANSI string pszComment.
|
|
|
|
cch = wcslen(ppi1w->pComment);
|
|
|
|
|
|
|
|
pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszComment)
|
|
|
|
{
|
2020-05-23 07:08:00 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-02-06 18:02:46 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi1w->pComment, -1, pszComment, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi1a->pComment, cch + 1, pszComment);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszComment);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 2:
|
|
|
|
{
|
|
|
|
if (ppi2w->pServerName)
|
|
|
|
{
|
|
|
|
PSTR pszServerName;
|
|
|
|
|
|
|
|
// Convert Unicode pServerName to a ANSI string pszServerName.
|
|
|
|
cch = wcslen(ppi2w->pServerName);
|
|
|
|
|
|
|
|
pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszServerName)
|
|
|
|
{
|
2020-05-23 07:08:00 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-02-06 18:02:46 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi2w->pServerName, -1, pszServerName, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi2a->pServerName, cch + 1, pszServerName);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszServerName);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi2w->pPrinterName)
|
|
|
|
{
|
|
|
|
PSTR pszPrinterName;
|
|
|
|
|
|
|
|
// Convert Unicode pPrinterName to a ANSI string pszPrinterName.
|
|
|
|
cch = wcslen(ppi2w->pPrinterName);
|
|
|
|
|
|
|
|
pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszPrinterName)
|
|
|
|
{
|
2020-05-23 07:08:00 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-02-06 18:02:46 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi2w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi2a->pPrinterName, cch + 1, pszPrinterName);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszPrinterName);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi2w->pShareName)
|
|
|
|
{
|
|
|
|
PSTR pszShareName;
|
|
|
|
|
|
|
|
// Convert Unicode pShareName to a ANSI string pszShareName.
|
|
|
|
cch = wcslen(ppi2w->pShareName);
|
|
|
|
|
|
|
|
pszShareName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszShareName)
|
|
|
|
{
|
2020-05-23 07:08:00 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-02-06 18:02:46 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi2w->pShareName, -1, pszShareName, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi2a->pShareName, cch + 1, pszShareName);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszShareName);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi2w->pPortName)
|
|
|
|
{
|
|
|
|
PSTR pszPortName;
|
|
|
|
|
|
|
|
// Convert Unicode pPortName to a ANSI string pszPortName.
|
|
|
|
cch = wcslen(ppi2w->pPortName);
|
|
|
|
|
|
|
|
pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszPortName)
|
|
|
|
{
|
2020-05-23 07:08:00 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-02-06 18:02:46 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi2w->pPortName, -1, pszPortName, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi2a->pPortName, cch + 1, pszPortName);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszPortName);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi2w->pDriverName)
|
|
|
|
{
|
|
|
|
PSTR pszDriverName;
|
|
|
|
|
|
|
|
// Convert Unicode pDriverName to a ANSI string pszDriverName.
|
|
|
|
cch = wcslen(ppi2w->pDriverName);
|
|
|
|
|
|
|
|
pszDriverName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszDriverName)
|
|
|
|
{
|
2020-05-23 07:08:00 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-02-06 18:02:46 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi2w->pDriverName, -1, pszDriverName, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi2a->pDriverName, cch + 1, pszDriverName);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszDriverName);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi2w->pComment)
|
|
|
|
{
|
|
|
|
PSTR pszComment;
|
|
|
|
|
|
|
|
// Convert Unicode pComment to a ANSI string pszComment.
|
|
|
|
cch = wcslen(ppi2w->pComment);
|
|
|
|
|
|
|
|
pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszComment)
|
|
|
|
{
|
2020-05-23 07:08:00 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-02-06 18:02:46 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi2w->pComment, -1, pszComment, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi2a->pComment, cch + 1, pszComment);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszComment);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi2w->pLocation)
|
|
|
|
{
|
|
|
|
PSTR pszLocation;
|
|
|
|
|
|
|
|
// Convert Unicode pLocation to a ANSI string pszLocation.
|
|
|
|
cch = wcslen(ppi2w->pLocation);
|
|
|
|
|
|
|
|
pszLocation = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszLocation)
|
|
|
|
{
|
2020-05-23 07:08:00 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-02-06 18:02:46 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi2w->pLocation, -1, pszLocation, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi2a->pLocation, cch + 1, pszLocation);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszLocation);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi2w->pSepFile)
|
|
|
|
{
|
|
|
|
PSTR pszSepFile;
|
|
|
|
|
|
|
|
// Convert Unicode pSepFile to a ANSI string pszSepFile.
|
|
|
|
cch = wcslen(ppi2w->pSepFile);
|
|
|
|
|
|
|
|
pszSepFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszSepFile)
|
|
|
|
{
|
2020-05-23 07:08:00 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-02-06 18:02:46 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi2w->pSepFile, -1, pszSepFile, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi2a->pSepFile, cch + 1, pszSepFile);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszSepFile);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi2w->pPrintProcessor)
|
|
|
|
{
|
|
|
|
PSTR pszPrintProcessor;
|
|
|
|
|
|
|
|
// Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor.
|
|
|
|
cch = wcslen(ppi2w->pPrintProcessor);
|
|
|
|
|
|
|
|
pszPrintProcessor = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszPrintProcessor)
|
|
|
|
{
|
2020-05-23 07:08:00 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-02-06 18:02:46 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi2w->pPrintProcessor, -1, pszPrintProcessor, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi2a->pPrintProcessor, cch + 1, pszPrintProcessor);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszPrintProcessor);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi2w->pDatatype)
|
|
|
|
{
|
|
|
|
PSTR pszDatatype;
|
|
|
|
|
|
|
|
// Convert Unicode pDatatype to a ANSI string pszDatatype.
|
|
|
|
cch = wcslen(ppi2w->pDatatype);
|
|
|
|
|
|
|
|
pszDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszDatatype)
|
|
|
|
{
|
2020-05-23 07:08:00 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-02-06 18:02:46 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi2w->pDatatype, -1, pszDatatype, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi2a->pDatatype, cch + 1, pszDatatype);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszDatatype);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi2w->pParameters)
|
|
|
|
{
|
|
|
|
PSTR pszParameters;
|
|
|
|
|
|
|
|
// Convert Unicode pParameters to a ANSI string pszParameters.
|
|
|
|
cch = wcslen(ppi2w->pParameters);
|
|
|
|
|
|
|
|
pszParameters = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszParameters)
|
|
|
|
{
|
2020-05-23 07:08:00 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-02-06 18:02:46 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi2w->pParameters, -1, pszParameters, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi2a->pParameters, cch + 1, pszParameters);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszParameters);
|
|
|
|
}
|
2020-08-04 02:07:58 +00:00
|
|
|
if ( ppi2w->pDevMode )
|
|
|
|
{
|
|
|
|
RosConvertUnicodeDevModeToAnsiDevmode( ppi2w->pDevMode, ppi2a->pDevMode );
|
|
|
|
}
|
2020-02-06 18:02:46 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 4:
|
|
|
|
{
|
|
|
|
if (ppi4w->pPrinterName)
|
|
|
|
{
|
|
|
|
PSTR pszPrinterName;
|
|
|
|
|
|
|
|
// Convert Unicode pPrinterName to a ANSI string pszPrinterName.
|
|
|
|
cch = wcslen(ppi4w->pPrinterName);
|
|
|
|
|
|
|
|
pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszPrinterName)
|
|
|
|
{
|
2020-05-23 07:08:00 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-02-06 18:02:46 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi4w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi4a->pPrinterName, cch + 1, pszPrinterName);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszPrinterName);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi4w->pServerName)
|
|
|
|
{
|
|
|
|
PSTR pszServerName;
|
|
|
|
|
|
|
|
// Convert Unicode pServerName to a ANSI string pszServerName.
|
|
|
|
cch = wcslen(ppi4w->pServerName);
|
|
|
|
|
|
|
|
pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszServerName)
|
|
|
|
{
|
2020-05-23 07:08:00 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-02-06 18:02:46 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi4w->pServerName, -1, pszServerName, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi4a->pServerName, cch + 1, pszServerName);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszServerName);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 5:
|
|
|
|
{
|
|
|
|
if (ppi5w->pPrinterName)
|
|
|
|
{
|
|
|
|
PSTR pszPrinterName;
|
|
|
|
|
|
|
|
// Convert Unicode pPrinterName to a ANSI string pszPrinterName.
|
|
|
|
cch = wcslen(ppi5w->pPrinterName);
|
|
|
|
|
|
|
|
pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszPrinterName)
|
|
|
|
{
|
2020-05-23 07:08:00 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-02-06 18:02:46 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi5w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi5a->pPrinterName, cch + 1, pszPrinterName);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszPrinterName);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ppi5w->pPortName)
|
|
|
|
{
|
|
|
|
PSTR pszPortName;
|
|
|
|
|
|
|
|
// Convert Unicode pPortName to a ANSI string pszPortName.
|
|
|
|
cch = wcslen(ppi5w->pPortName);
|
|
|
|
|
|
|
|
pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszPortName)
|
|
|
|
{
|
2020-05-23 07:08:00 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-02-06 18:02:46 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi5w->pPortName, -1, pszPortName, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi5a->pPortName, cch + 1, pszPortName);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszPortName);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 7:
|
|
|
|
{
|
|
|
|
if (ppi7w->pszObjectGUID)
|
|
|
|
{
|
|
|
|
PSTR pszaObjectGUID;
|
|
|
|
|
|
|
|
// Convert Unicode pszObjectGUID to a ANSI string pszaObjectGUID.
|
|
|
|
cch = wcslen(ppi7w->pszObjectGUID);
|
|
|
|
|
|
|
|
pszaObjectGUID = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
|
|
|
|
if (!pszaObjectGUID)
|
|
|
|
{
|
2020-05-23 07:08:00 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
2020-02-06 18:02:46 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, ppi7w->pszObjectGUID, -1, pszaObjectGUID, cch + 1, NULL, NULL);
|
|
|
|
StringCchCopyA(ppi7a->pszObjectGUID, cch + 1, pszaObjectGUID);
|
|
|
|
|
|
|
|
HeapFree(hProcessHeap, 0, pszaObjectGUID);
|
|
|
|
}
|
|
|
|
}
|
2020-08-04 02:07:58 +00:00
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
case 9:
|
|
|
|
RosConvertUnicodeDevModeToAnsiDevmode(ppi9w->pDevMode, ppi9a->pDevMode);
|
|
|
|
break;
|
2020-02-06 18:02:46 +00:00
|
|
|
} // switch
|
|
|
|
|
2020-05-23 07:08:00 +00:00
|
|
|
dwErrorCode = ERROR_SUCCESS;
|
|
|
|
|
2020-02-06 18:02:46 +00:00
|
|
|
Cleanup:
|
2020-05-23 07:08:00 +00:00
|
|
|
SetLastError(dwErrorCode);
|
|
|
|
return (dwErrorCode == ERROR_SUCCESS);
|
2015-06-22 14:31:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI
|
2020-08-04 02:07:58 +00:00
|
|
|
GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
|
|
|
|
{
|
2020-05-26 18:21:25 +00:00
|
|
|
DWORD dwErrorCode;
|
2020-08-04 02:07:58 +00:00
|
|
|
PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
|
2020-02-12 18:52:34 +00:00
|
|
|
|
2020-08-04 02:07:58 +00:00
|
|
|
TRACE("GetPrinterW(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
|
2020-02-12 18:52:34 +00:00
|
|
|
|
2020-08-04 02:07:58 +00:00
|
|
|
// Sanity checks.
|
|
|
|
if (!pHandle)
|
2020-02-12 18:52:34 +00:00
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
dwErrorCode = ERROR_INVALID_HANDLE;
|
2020-05-26 18:21:25 +00:00
|
|
|
goto Cleanup;
|
2020-02-12 18:52:34 +00:00
|
|
|
}
|
|
|
|
|
2020-08-04 02:07:58 +00:00
|
|
|
// Dismiss invalid levels already at this point.
|
|
|
|
if (Level > 9)
|
2020-02-12 18:52:34 +00:00
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
dwErrorCode = ERROR_INVALID_LEVEL;
|
2017-04-30 15:12:53 +00:00
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cbBuf && pPrinter)
|
|
|
|
ZeroMemory(pPrinter, cbBuf);
|
|
|
|
|
|
|
|
// Do the RPC call
|
|
|
|
RpcTryExcept
|
|
|
|
{
|
2017-12-10 11:28:08 +00:00
|
|
|
dwErrorCode = _RpcGetPrinter(pHandle->hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
|
2017-04-30 15:12:53 +00:00
|
|
|
}
|
|
|
|
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
{
|
|
|
|
dwErrorCode = RpcExceptionCode();
|
|
|
|
ERR("_RpcGetPrinter failed with exception code %lu!\n", dwErrorCode);
|
|
|
|
}
|
|
|
|
RpcEndExcept;
|
|
|
|
|
|
|
|
if (dwErrorCode == ERROR_SUCCESS)
|
|
|
|
{
|
2018-01-17 11:52:12 +00:00
|
|
|
// Replace relative offset addresses in the output by absolute pointers.
|
|
|
|
ASSERT(Level <= 9);
|
|
|
|
MarshallUpStructure(cbBuf, pPrinter, pPrinterInfoMarshalling[Level]->pInfo, pPrinterInfoMarshalling[Level]->cbStructureSize, TRUE);
|
2017-04-30 15:12:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
SetLastError(dwErrorCode);
|
|
|
|
return (dwErrorCode == ERROR_SUCCESS);
|
2015-06-22 14:31:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI
|
|
|
|
OpenPrinterA(LPSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSA pDefault)
|
|
|
|
{
|
|
|
|
BOOL bReturnValue = FALSE;
|
2016-01-06 05:15:44 +00:00
|
|
|
DWORD cch;
|
2015-06-22 14:31:47 +00:00
|
|
|
PWSTR pwszPrinterName = NULL;
|
|
|
|
PRINTER_DEFAULTSW wDefault = { 0 };
|
|
|
|
|
2017-12-09 11:00:09 +00:00
|
|
|
TRACE("OpenPrinterA(%s, %p, %p)\n", pPrinterName, phPrinter, pDefault);
|
|
|
|
|
2015-06-22 14:31:47 +00:00
|
|
|
if (pPrinterName)
|
|
|
|
{
|
|
|
|
// Convert pPrinterName to a Unicode string pwszPrinterName
|
2016-01-06 05:15:44 +00:00
|
|
|
cch = strlen(pPrinterName);
|
2015-06-22 14:31:47 +00:00
|
|
|
|
2016-01-06 05:15:44 +00:00
|
|
|
pwszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
|
2015-06-22 14:31:47 +00:00
|
|
|
if (!pwszPrinterName)
|
|
|
|
{
|
[PRINTING]
- Implement GetPrinterDataA, GetPrinterDataExA, GetPrinterDataExW, GetPrinterDataW, SetPrinterDataA, SetPrinterDataExA, SetPrinterDataExW, SetPrinterDataW.
They support all features for Print Server and Printer Handles (minus security checks!)
I've also added tests for them.
- Store Printer data in SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers instead of SYSTEM\CurrentControlSet\Control\Print\Printers and create a registry symlink from the former path to the new one just like Windows does.
According to https://social.technet.microsoft.com/Forums/windowsserver/en-US/a683ab54-c43c-4ebe-af8f-1f7a65af2a51, this is needed when having >900 printers to work around a size limit of the SYSTEM registry hive. And if Windows has both locations, we need both for compatibility anyway.
- Add several settings which are queried by the new Printer Data APIs when working with Print Server Handles.
- Store the job directory in the Windows-compatible "DefaultSpoolDirectory" setting and make use of it.
- Revert the ASSERTs in LocalEnumPrinters again to let us verify the NULL pointer exceptions in localspl_apitest (thanks Serge! CORE-13433)
- Translate ERROR_INVALID_NAME to ERROR_INVALID_PRINTER_NAME in all cases in OpenPrinterW (thanks Victor! CORE-13412)
- Make EnumMonitorsW and EnumPortsW in spoolss more robust against failing Print Monitors.
- Remove the wrong !phPrinter check in OpenPrinterW to make Print Server Handles work for real.
- Fix error handling when memory allocation fails: HeapAlloc doesn't set last error, so it's just wrong to query or return it.
One more item done from https://reactos.org/wiki/Printing !
This is all still a big Work-in-Progress, with many subtle bugs deep down in ReactOS, for which I need to open additional tickets. But I didn't want to make this commit even bigger..
svn path=/trunk/; revision=75125
2017-06-19 14:18:19 +00:00
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
ERR("HeapAlloc failed!\n");
|
2015-06-22 14:31:47 +00:00
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
2016-01-06 05:15:44 +00:00
|
|
|
MultiByteToWideChar(CP_ACP, 0, pPrinterName, -1, pwszPrinterName, cch + 1);
|
2015-06-22 14:31:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pDefault)
|
|
|
|
{
|
|
|
|
wDefault.DesiredAccess = pDefault->DesiredAccess;
|
|
|
|
|
|
|
|
if (pDefault->pDatatype)
|
|
|
|
{
|
2016-01-06 05:15:44 +00:00
|
|
|
// Convert pDefault->pDatatype to a Unicode string wDefault.pDatatype
|
|
|
|
cch = strlen(pDefault->pDatatype);
|
2015-06-22 14:31:47 +00:00
|
|
|
|
2016-01-06 05:15:44 +00:00
|
|
|
wDefault.pDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
|
|
|
|
if (!wDefault.pDatatype)
|
2015-06-22 14:31:47 +00:00
|
|
|
{
|
[PRINTING]
- Implement GetPrinterDataA, GetPrinterDataExA, GetPrinterDataExW, GetPrinterDataW, SetPrinterDataA, SetPrinterDataExA, SetPrinterDataExW, SetPrinterDataW.
They support all features for Print Server and Printer Handles (minus security checks!)
I've also added tests for them.
- Store Printer data in SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers instead of SYSTEM\CurrentControlSet\Control\Print\Printers and create a registry symlink from the former path to the new one just like Windows does.
According to https://social.technet.microsoft.com/Forums/windowsserver/en-US/a683ab54-c43c-4ebe-af8f-1f7a65af2a51, this is needed when having >900 printers to work around a size limit of the SYSTEM registry hive. And if Windows has both locations, we need both for compatibility anyway.
- Add several settings which are queried by the new Printer Data APIs when working with Print Server Handles.
- Store the job directory in the Windows-compatible "DefaultSpoolDirectory" setting and make use of it.
- Revert the ASSERTs in LocalEnumPrinters again to let us verify the NULL pointer exceptions in localspl_apitest (thanks Serge! CORE-13433)
- Translate ERROR_INVALID_NAME to ERROR_INVALID_PRINTER_NAME in all cases in OpenPrinterW (thanks Victor! CORE-13412)
- Make EnumMonitorsW and EnumPortsW in spoolss more robust against failing Print Monitors.
- Remove the wrong !phPrinter check in OpenPrinterW to make Print Server Handles work for real.
- Fix error handling when memory allocation fails: HeapAlloc doesn't set last error, so it's just wrong to query or return it.
One more item done from https://reactos.org/wiki/Printing !
This is all still a big Work-in-Progress, with many subtle bugs deep down in ReactOS, for which I need to open additional tickets. But I didn't want to make this commit even bigger..
svn path=/trunk/; revision=75125
2017-06-19 14:18:19 +00:00
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
ERR("HeapAlloc failed!\n");
|
2015-06-22 14:31:47 +00:00
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
2016-01-06 05:15:44 +00:00
|
|
|
MultiByteToWideChar(CP_ACP, 0, pDefault->pDatatype, -1, wDefault.pDatatype, cch + 1);
|
2015-06-22 14:31:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pDefault->pDevMode)
|
|
|
|
wDefault.pDevMode = GdiConvertToDevmodeW(pDefault->pDevMode);
|
|
|
|
}
|
|
|
|
|
|
|
|
bReturnValue = OpenPrinterW(pwszPrinterName, phPrinter, &wDefault);
|
|
|
|
|
2020-08-04 02:07:58 +00:00
|
|
|
if ( bReturnValue )
|
|
|
|
{
|
|
|
|
PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)*phPrinter;
|
|
|
|
pHandle->bAnsi = TRUE;
|
|
|
|
}
|
|
|
|
|
2015-06-22 14:31:47 +00:00
|
|
|
Cleanup:
|
2016-01-06 05:15:44 +00:00
|
|
|
if (wDefault.pDatatype)
|
|
|
|
HeapFree(hProcessHeap, 0, wDefault.pDatatype);
|
|
|
|
|
2015-06-22 14:31:47 +00:00
|
|
|
if (wDefault.pDevMode)
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
HeapFree(hProcessHeap, 0, wDefault.pDevMode);
|
2015-06-22 14:31:47 +00:00
|
|
|
|
|
|
|
if (pwszPrinterName)
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
HeapFree(hProcessHeap, 0, pwszPrinterName);
|
2015-06-22 14:31:47 +00:00
|
|
|
|
|
|
|
return bReturnValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI
|
|
|
|
OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefault)
|
|
|
|
{
|
|
|
|
DWORD dwErrorCode;
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
HANDLE hPrinter;
|
|
|
|
PSPOOLER_HANDLE pHandle;
|
2015-06-22 14:31:47 +00:00
|
|
|
PWSTR pDatatype = NULL;
|
2015-07-17 14:34:23 +00:00
|
|
|
WINSPOOL_DEVMODE_CONTAINER DevModeContainer = { 0 };
|
2015-06-22 14:31:47 +00:00
|
|
|
ACCESS_MASK AccessRequired = 0;
|
|
|
|
|
2017-12-09 11:00:09 +00:00
|
|
|
TRACE("OpenPrinterW(%S, %p, %p)\n", pPrinterName, phPrinter, pDefault);
|
|
|
|
|
[PRINTING]
- Implement GetPrinterDataA, GetPrinterDataExA, GetPrinterDataExW, GetPrinterDataW, SetPrinterDataA, SetPrinterDataExA, SetPrinterDataExW, SetPrinterDataW.
They support all features for Print Server and Printer Handles (minus security checks!)
I've also added tests for them.
- Store Printer data in SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers instead of SYSTEM\CurrentControlSet\Control\Print\Printers and create a registry symlink from the former path to the new one just like Windows does.
According to https://social.technet.microsoft.com/Forums/windowsserver/en-US/a683ab54-c43c-4ebe-af8f-1f7a65af2a51, this is needed when having >900 printers to work around a size limit of the SYSTEM registry hive. And if Windows has both locations, we need both for compatibility anyway.
- Add several settings which are queried by the new Printer Data APIs when working with Print Server Handles.
- Store the job directory in the Windows-compatible "DefaultSpoolDirectory" setting and make use of it.
- Revert the ASSERTs in LocalEnumPrinters again to let us verify the NULL pointer exceptions in localspl_apitest (thanks Serge! CORE-13433)
- Translate ERROR_INVALID_NAME to ERROR_INVALID_PRINTER_NAME in all cases in OpenPrinterW (thanks Victor! CORE-13412)
- Make EnumMonitorsW and EnumPortsW in spoolss more robust against failing Print Monitors.
- Remove the wrong !phPrinter check in OpenPrinterW to make Print Server Handles work for real.
- Fix error handling when memory allocation fails: HeapAlloc doesn't set last error, so it's just wrong to query or return it.
One more item done from https://reactos.org/wiki/Printing !
This is all still a big Work-in-Progress, with many subtle bugs deep down in ReactOS, for which I need to open additional tickets. But I didn't want to make this commit even bigger..
svn path=/trunk/; revision=75125
2017-06-19 14:18:19 +00:00
|
|
|
// Sanity check
|
|
|
|
if (!phPrinter)
|
|
|
|
{
|
|
|
|
dwErrorCode = ERROR_INVALID_PARAMETER;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
2015-06-22 14:31:47 +00:00
|
|
|
// Prepare the additional parameters in the format required by _RpcOpenPrinter
|
|
|
|
if (pDefault)
|
|
|
|
{
|
|
|
|
pDatatype = pDefault->pDatatype;
|
|
|
|
DevModeContainer.cbBuf = sizeof(DEVMODEW);
|
|
|
|
DevModeContainer.pDevMode = (BYTE*)pDefault->pDevMode;
|
|
|
|
AccessRequired = pDefault->DesiredAccess;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do the RPC call
|
|
|
|
RpcTryExcept
|
|
|
|
{
|
2015-07-17 14:34:23 +00:00
|
|
|
dwErrorCode = _RpcOpenPrinter(pPrinterName, &hPrinter, pDatatype, &DevModeContainer, AccessRequired);
|
2015-06-22 14:31:47 +00:00
|
|
|
}
|
|
|
|
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
{
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
dwErrorCode = RpcExceptionCode();
|
|
|
|
ERR("_RpcOpenPrinter failed with exception code %lu!\n", dwErrorCode);
|
2015-06-22 14:31:47 +00:00
|
|
|
}
|
|
|
|
RpcEndExcept;
|
|
|
|
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
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;
|
[PRINTING]
- Implement GetPrinterDataA, GetPrinterDataExA, GetPrinterDataExW, GetPrinterDataW, SetPrinterDataA, SetPrinterDataExA, SetPrinterDataExW, SetPrinterDataW.
They support all features for Print Server and Printer Handles (minus security checks!)
I've also added tests for them.
- Store Printer data in SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers instead of SYSTEM\CurrentControlSet\Control\Print\Printers and create a registry symlink from the former path to the new one just like Windows does.
According to https://social.technet.microsoft.com/Forums/windowsserver/en-US/a683ab54-c43c-4ebe-af8f-1f7a65af2a51, this is needed when having >900 printers to work around a size limit of the SYSTEM registry hive. And if Windows has both locations, we need both for compatibility anyway.
- Add several settings which are queried by the new Printer Data APIs when working with Print Server Handles.
- Store the job directory in the Windows-compatible "DefaultSpoolDirectory" setting and make use of it.
- Revert the ASSERTs in LocalEnumPrinters again to let us verify the NULL pointer exceptions in localspl_apitest (thanks Serge! CORE-13433)
- Translate ERROR_INVALID_NAME to ERROR_INVALID_PRINTER_NAME in all cases in OpenPrinterW (thanks Victor! CORE-13412)
- Make EnumMonitorsW and EnumPortsW in spoolss more robust against failing Print Monitors.
- Remove the wrong !phPrinter check in OpenPrinterW to make Print Server Handles work for real.
- Fix error handling when memory allocation fails: HeapAlloc doesn't set last error, so it's just wrong to query or return it.
One more item done from https://reactos.org/wiki/Printing !
This is all still a big Work-in-Progress, with many subtle bugs deep down in ReactOS, for which I need to open additional tickets. But I didn't want to make this commit even bigger..
svn path=/trunk/; revision=75125
2017-06-19 14:18:19 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
2020-08-04 02:07:58 +00:00
|
|
|
pHandle->Sig = SPOOLER_HANDLE_SIG;
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
pHandle->hPrinter = hPrinter;
|
|
|
|
pHandle->hSPLFile = INVALID_HANDLE_VALUE;
|
2020-08-04 02:07:58 +00:00
|
|
|
pHandle->hSpoolFileHandle = INVALID_HANDLE_VALUE;
|
|
|
|
|
|
|
|
// Return it as phPrinter.
|
|
|
|
*phPrinter = (HANDLE)pHandle;
|
|
|
|
}
|
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
SetLastError(dwErrorCode);
|
|
|
|
return (dwErrorCode == ERROR_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Dead API.
|
|
|
|
//
|
|
|
|
DWORD WINAPI
|
|
|
|
PrinterMessageBoxA(HANDLE hPrinter, DWORD Error, HWND hWnd, LPSTR pText, LPSTR pCaption, DWORD dwType)
|
|
|
|
{
|
|
|
|
return 50;
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD WINAPI
|
|
|
|
PrinterMessageBoxW(HANDLE hPrinter, DWORD Error, HWND hWnd, LPWSTR pText, LPWSTR pCaption, DWORD dwType)
|
|
|
|
{
|
|
|
|
return 50;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI
|
|
|
|
QueryColorProfile(
|
|
|
|
HANDLE hPrinter,
|
|
|
|
PDEVMODEW pdevmode,
|
|
|
|
ULONG ulQueryMode,
|
|
|
|
VOID *pvProfileData,
|
|
|
|
ULONG *pcbProfileData,
|
|
|
|
FLONG *pflProfileData )
|
|
|
|
{
|
|
|
|
PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
|
|
|
|
BOOL Ret = FALSE;
|
|
|
|
HMODULE hLibrary;
|
|
|
|
|
|
|
|
FIXME("QueryColorProfile(%p, %p, %l, %p, %p, %p)\n", hPrinter, pdevmode, ulQueryMode, pvProfileData, pcbProfileData, pflProfileData);
|
|
|
|
|
|
|
|
if ( pHandle->bNoColorProfile )
|
|
|
|
{
|
|
|
|
Ret = (BOOL)SP_ERROR;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
|
|
|
|
if ( pdevmode )
|
|
|
|
{
|
|
|
|
if (!IsValidDevmodeNoSizeW( pdevmode ) )
|
|
|
|
{
|
|
|
|
ERR("DeviceCapabilitiesW : Devode Invalid");
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
hLibrary = LoadPrinterDriver( hPrinter );
|
|
|
|
|
|
|
|
if ( hLibrary )
|
|
|
|
{
|
|
|
|
fpQueryColorProfile = (PVOID)GetProcAddress( hLibrary, "DrvQueryColorProfile" );
|
|
|
|
|
|
|
|
if ( fpQueryColorProfile )
|
|
|
|
{
|
|
|
|
Ret = fpQueryColorProfile( hPrinter, pdevmode, ulQueryMode, pvProfileData, pcbProfileData, pflProfileData );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pHandle->bNoColorProfile = TRUE;
|
|
|
|
Ret = (BOOL)SP_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
FreeLibrary(hLibrary);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Note from GDI32:printdrv.c
|
|
|
|
//
|
|
|
|
// QuerySpoolMode :
|
|
|
|
// BOOL return TRUE if successful.
|
|
|
|
// dlFont 0x0001 for Downloading fonts. 0x0002 unknown XPS_PASS?.
|
|
|
|
// dwVersion is version of EMFSPOOL. Must be 0x00010000. See [MS-EMFSPOOL] page 18.
|
|
|
|
//
|
|
|
|
|
|
|
|
#define QSM_DOWNLOADINGFONTS 0x0001
|
|
|
|
|
|
|
|
/*
|
|
|
|
Note from MSDN : "V4 print drivers using RAW mode to send PCL/Postscript have 0 byte spool file"
|
|
|
|
|
|
|
|
Use XPS_PASS instead of RAW to pass information directly to the print filter pipeline in
|
|
|
|
v4 and v3 XPSDrv drivers. Here's how to proceed with Windows 8:
|
|
|
|
|
|
|
|
Call GetPrinterDriver to retrieve the DRIVER_INFO_8 structure.
|
|
|
|
Check DRIVER_INFO_8::dwPrinterDriverAttributes for the PRINTER_DRIVER_XPS flag.
|
|
|
|
Choose your datatype based on the presence or absence of the flag:
|
|
|
|
If the flag is set, use XPS_PASS.
|
|
|
|
If the flag isn't set, use RAW.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define QSM_XPS_PASS 0x0002 // Guessing. PRINTER_DRIVER_XPS?
|
|
|
|
|
|
|
|
BOOL WINAPI
|
|
|
|
QuerySpoolMode( HANDLE hPrinter, PDWORD downloadFontsFlags, PDWORD dwVersion )
|
|
|
|
{
|
|
|
|
PRINTER_INFO_2W *pi2 = NULL;
|
|
|
|
DWORD needed = 0;
|
|
|
|
BOOL res;
|
|
|
|
|
|
|
|
FIXME("QuerySpoolMode(%p, %p, %p)\n", hPrinter, downloadFontsFlags, dwVersion);
|
|
|
|
|
|
|
|
res = GetPrinterW( hPrinter, 2, NULL, 0, &needed);
|
|
|
|
if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
|
|
|
|
{
|
|
|
|
pi2 = HeapAlloc(hProcessHeap, 0, needed);
|
|
|
|
res = GetPrinterW(hPrinter, 2, (LPBYTE)pi2, needed, &needed);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( res )
|
|
|
|
{
|
|
|
|
*dwVersion = 0x10000;
|
|
|
|
*downloadFontsFlags = 0;
|
|
|
|
|
|
|
|
if ( pi2->pServerName )
|
|
|
|
{
|
|
|
|
*downloadFontsFlags |= QSM_DOWNLOADINGFONTS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// Guessing,,,
|
|
|
|
// To do : Add GetPrinterDriver for DRIVER_INFO_8, test PRINTER_DRIVER_XPS flag,
|
|
|
|
// to set *downloadFontsFlags |= QSM_XPS_PASS;
|
|
|
|
//
|
|
|
|
// Vista+ looks for QSM_XPS_PASS to be set in GDI32.
|
|
|
|
//
|
|
|
|
HeapFree(hProcessHeap, 0, pi2);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// This requires IC support.
|
|
|
|
//
|
|
|
|
DWORD WINAPI
|
|
|
|
QueryRemoteFonts( HANDLE hPrinter, PUNIVERSAL_FONT_ID pufi, ULONG NumberOfUFIs )
|
|
|
|
{
|
|
|
|
HANDLE hIC;
|
|
|
|
DWORD Result = -1, cOut, cIn = 0;
|
|
|
|
PBYTE pOut;
|
|
|
|
|
|
|
|
FIXME("QueryRemoteFonts(%p, %p, %lu)\n", hPrinter, pufi, NumberOfUFIs);
|
|
|
|
|
|
|
|
hIC = CreatePrinterIC( hPrinter, NULL );
|
|
|
|
if ( hIC )
|
|
|
|
{
|
|
|
|
cOut = (NumberOfUFIs * sizeof(UNIVERSAL_FONT_ID)) + sizeof(DWORD); // Include "DWORD" first part to return size.
|
|
|
|
|
|
|
|
pOut = HeapAlloc( hProcessHeap, 0, cOut );
|
|
|
|
if ( pOut )
|
|
|
|
{
|
|
|
|
if ( PlayGdiScriptOnPrinterIC( hIC, (LPBYTE)&cIn, sizeof(DWORD), pOut, cOut, 0 ) )
|
|
|
|
{
|
|
|
|
cIn = *((PDWORD)pOut); // Fisrt part is the size of the UFID object.
|
|
|
|
|
|
|
|
Result = cIn; // Return the required size.
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
|
2020-08-04 02:07:58 +00:00
|
|
|
if( NumberOfUFIs < cIn )
|
|
|
|
{
|
|
|
|
cIn = NumberOfUFIs;
|
|
|
|
}
|
|
|
|
// Copy whole object back to GDI32, exclude first DWORD part.
|
|
|
|
memcpy( pufi, pOut + sizeof(DWORD), cIn * sizeof(UNIVERSAL_FONT_ID) );
|
|
|
|
}
|
|
|
|
HeapFree( hProcessHeap, 0, pOut );
|
|
|
|
}
|
|
|
|
DeletePrinterIC( hIC );
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
}
|
2020-08-04 02:07:58 +00:00
|
|
|
return Result;
|
2015-06-22 14:31:47 +00:00
|
|
|
}
|
|
|
|
|
2015-06-28 15:51:32 +00:00
|
|
|
BOOL WINAPI
|
|
|
|
ReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead)
|
|
|
|
{
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
DWORD dwErrorCode;
|
|
|
|
PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
|
|
|
|
|
2017-12-09 11:00:09 +00:00
|
|
|
TRACE("ReadPrinter(%p, %p, %lu, %p)\n", hPrinter, pBuf, cbBuf, pNoBytesRead);
|
|
|
|
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
// 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);
|
2015-06-28 15:51:32 +00:00
|
|
|
}
|
|
|
|
|
2017-12-09 12:35:42 +00:00
|
|
|
BOOL WINAPI
|
|
|
|
ResetPrinterA(HANDLE hPrinter, PPRINTER_DEFAULTSA pDefault)
|
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
BOOL ret;
|
|
|
|
UNICODE_STRING pNameW;
|
|
|
|
PDEVMODEW pdmw = NULL;
|
|
|
|
PPRINTER_DEFAULTSW pdw = (PPRINTER_DEFAULTSW)pDefault;
|
|
|
|
|
2017-12-09 12:35:42 +00:00
|
|
|
TRACE("ResetPrinterA(%p, %p)\n", hPrinter, pDefault);
|
2020-08-04 02:07:58 +00:00
|
|
|
|
|
|
|
if ( pDefault->pDatatype == (LPSTR)-1 )
|
|
|
|
{
|
|
|
|
pdw->pDatatype = (LPWSTR)-1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pdw->pDatatype = AsciiToUnicode( &pNameW, pDefault->pDatatype );
|
|
|
|
}
|
|
|
|
if ( pDefault->pDevMode == (LPDEVMODEA)-1)
|
|
|
|
{
|
|
|
|
pdw->pDevMode = (LPDEVMODEW)-1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( pDefault->pDevMode )//&& IsValidDevmodeNoSizeW( pDefault->pDevMode ) )
|
|
|
|
{
|
|
|
|
RosConvertAnsiDevModeToUnicodeDevmode( pDefault->pDevMode, &pdmw );
|
|
|
|
pdw->pDevMode = pdmw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = ResetPrinterW( hPrinter, pdw );
|
|
|
|
|
|
|
|
if (pdmw) HeapFree(hProcessHeap, 0, pdmw);
|
|
|
|
|
|
|
|
RtlFreeUnicodeString( &pNameW );
|
|
|
|
|
|
|
|
return ret;
|
2017-12-09 12:35:42 +00:00
|
|
|
}
|
|
|
|
|
2015-07-22 17:59:46 +00:00
|
|
|
BOOL WINAPI
|
|
|
|
ResetPrinterW(HANDLE hPrinter, PPRINTER_DEFAULTSW pDefault)
|
|
|
|
{
|
2017-12-09 11:00:09 +00:00
|
|
|
TRACE("ResetPrinterW(%p, %p)\n", hPrinter, pDefault);
|
2015-07-22 17:59:46 +00:00
|
|
|
UNIMPLEMENTED;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2020-08-26 22:12:20 +00:00
|
|
|
BOOL WINAPI
|
|
|
|
SeekPrinter( HANDLE hPrinter, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER pliNewPointer, DWORD dwMoveMethod, BOOL bWrite )
|
|
|
|
{
|
|
|
|
DWORD dwErrorCode;
|
|
|
|
PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
|
|
|
|
|
|
|
|
FIXME("SeekPrinter(%p, %I64u, %p, %lu, %d)\n", hPrinter, liDistanceToMove.QuadPart, pliNewPointer, dwMoveMethod, bWrite);
|
|
|
|
|
|
|
|
// Sanity checks.
|
|
|
|
if (!pHandle)
|
|
|
|
{
|
|
|
|
dwErrorCode = ERROR_INVALID_HANDLE;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do the RPC call
|
|
|
|
RpcTryExcept
|
|
|
|
{
|
|
|
|
dwErrorCode = _RpcSeekPrinter(pHandle->hPrinter, liDistanceToMove, pliNewPointer, dwMoveMethod, bWrite);
|
|
|
|
}
|
|
|
|
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
{
|
|
|
|
dwErrorCode = RpcExceptionCode();
|
|
|
|
ERR("_RpcSeekPrinter failed with exception code %lu!\n", dwErrorCode);
|
|
|
|
}
|
|
|
|
RpcEndExcept;
|
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
SetLastError(dwErrorCode);
|
|
|
|
return (dwErrorCode == ERROR_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2017-05-09 15:44:42 +00:00
|
|
|
BOOL WINAPI
|
|
|
|
SetDefaultPrinterA(LPCSTR pszPrinter)
|
|
|
|
{
|
|
|
|
BOOL bReturnValue = FALSE;
|
|
|
|
DWORD cch;
|
|
|
|
PWSTR pwszPrinter = NULL;
|
|
|
|
|
2017-12-09 11:00:09 +00:00
|
|
|
TRACE("SetDefaultPrinterA(%s)\n", pszPrinter);
|
|
|
|
|
2017-05-09 15:44:42 +00:00
|
|
|
if (pszPrinter)
|
|
|
|
{
|
|
|
|
// Convert pszPrinter to a Unicode string pwszPrinter
|
|
|
|
cch = strlen(pszPrinter);
|
|
|
|
|
|
|
|
pwszPrinter = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
|
|
|
|
if (!pwszPrinter)
|
|
|
|
{
|
[PRINTING]
- Implement GetPrinterDataA, GetPrinterDataExA, GetPrinterDataExW, GetPrinterDataW, SetPrinterDataA, SetPrinterDataExA, SetPrinterDataExW, SetPrinterDataW.
They support all features for Print Server and Printer Handles (minus security checks!)
I've also added tests for them.
- Store Printer data in SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers instead of SYSTEM\CurrentControlSet\Control\Print\Printers and create a registry symlink from the former path to the new one just like Windows does.
According to https://social.technet.microsoft.com/Forums/windowsserver/en-US/a683ab54-c43c-4ebe-af8f-1f7a65af2a51, this is needed when having >900 printers to work around a size limit of the SYSTEM registry hive. And if Windows has both locations, we need both for compatibility anyway.
- Add several settings which are queried by the new Printer Data APIs when working with Print Server Handles.
- Store the job directory in the Windows-compatible "DefaultSpoolDirectory" setting and make use of it.
- Revert the ASSERTs in LocalEnumPrinters again to let us verify the NULL pointer exceptions in localspl_apitest (thanks Serge! CORE-13433)
- Translate ERROR_INVALID_NAME to ERROR_INVALID_PRINTER_NAME in all cases in OpenPrinterW (thanks Victor! CORE-13412)
- Make EnumMonitorsW and EnumPortsW in spoolss more robust against failing Print Monitors.
- Remove the wrong !phPrinter check in OpenPrinterW to make Print Server Handles work for real.
- Fix error handling when memory allocation fails: HeapAlloc doesn't set last error, so it's just wrong to query or return it.
One more item done from https://reactos.org/wiki/Printing !
This is all still a big Work-in-Progress, with many subtle bugs deep down in ReactOS, for which I need to open additional tickets. But I didn't want to make this commit even bigger..
svn path=/trunk/; revision=75125
2017-06-19 14:18:19 +00:00
|
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
ERR("HeapAlloc failed!\n");
|
2017-05-09 15:44:42 +00:00
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, pwszPrinter, cch + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
bReturnValue = SetDefaultPrinterW(pwszPrinter);
|
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
if (pwszPrinter)
|
|
|
|
HeapFree(hProcessHeap, 0, pwszPrinter);
|
|
|
|
|
|
|
|
return bReturnValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI
|
|
|
|
SetDefaultPrinterW(LPCWSTR pszPrinter)
|
|
|
|
{
|
|
|
|
const WCHAR wszDevicesKey[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Devices";
|
|
|
|
|
|
|
|
DWORD cbDeviceValueData;
|
|
|
|
DWORD cbPrinterValueData = 0;
|
|
|
|
DWORD cchPrinter;
|
|
|
|
DWORD dwErrorCode;
|
|
|
|
HKEY hDevicesKey = NULL;
|
|
|
|
HKEY hWindowsKey = NULL;
|
|
|
|
PWSTR pwszDeviceValueData = NULL;
|
|
|
|
WCHAR wszPrinter[MAX_PRINTER_NAME + 1];
|
|
|
|
|
2017-12-09 11:00:09 +00:00
|
|
|
TRACE("SetDefaultPrinterW(%S)\n", pszPrinter);
|
|
|
|
|
2017-05-09 15:44:42 +00:00
|
|
|
// Open the Devices registry key.
|
|
|
|
dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszDevicesKey, 0, KEY_READ, &hDevicesKey);
|
|
|
|
if (dwErrorCode != ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Did the caller give us a printer to set as default?
|
|
|
|
if (pszPrinter && *pszPrinter)
|
|
|
|
{
|
|
|
|
// Check if the given printer exists and query the value data size.
|
|
|
|
dwErrorCode = (DWORD)RegQueryValueExW(hDevicesKey, pszPrinter, NULL, NULL, NULL, &cbPrinterValueData);
|
|
|
|
if (dwErrorCode == ERROR_FILE_NOT_FOUND)
|
|
|
|
{
|
2017-05-10 13:03:08 +00:00
|
|
|
dwErrorCode = ERROR_INVALID_PRINTER_NAME;
|
2017-05-09 15:44:42 +00:00
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
else if (dwErrorCode != ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
cchPrinter = wcslen(pszPrinter);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// If there is already a default printer, we're done!
|
|
|
|
cchPrinter = _countof(wszPrinter);
|
|
|
|
if (GetDefaultPrinterW(wszPrinter, &cchPrinter))
|
|
|
|
{
|
|
|
|
dwErrorCode = ERROR_SUCCESS;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, get us the first printer from the "Devices" key to later set it as default and query the value data size.
|
|
|
|
cchPrinter = _countof(wszPrinter);
|
|
|
|
dwErrorCode = (DWORD)RegEnumValueW(hDevicesKey, 0, wszPrinter, &cchPrinter, NULL, NULL, NULL, &cbPrinterValueData);
|
|
|
|
if (dwErrorCode != ERROR_MORE_DATA)
|
|
|
|
goto Cleanup;
|
|
|
|
|
|
|
|
pszPrinter = wszPrinter;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We now need to query the value data, which has the format "winspool,<Port>:"
|
|
|
|
// and make "<Printer Name>,winspool,<Port>:" out of it.
|
|
|
|
// Allocate a buffer large enough for the final data.
|
|
|
|
cbDeviceValueData = (cchPrinter + 1) * sizeof(WCHAR) + cbPrinterValueData;
|
|
|
|
pwszDeviceValueData = HeapAlloc(hProcessHeap, 0, cbDeviceValueData);
|
|
|
|
if (!pwszDeviceValueData)
|
|
|
|
{
|
[PRINTING]
- Implement GetPrinterDataA, GetPrinterDataExA, GetPrinterDataExW, GetPrinterDataW, SetPrinterDataA, SetPrinterDataExA, SetPrinterDataExW, SetPrinterDataW.
They support all features for Print Server and Printer Handles (minus security checks!)
I've also added tests for them.
- Store Printer data in SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers instead of SYSTEM\CurrentControlSet\Control\Print\Printers and create a registry symlink from the former path to the new one just like Windows does.
According to https://social.technet.microsoft.com/Forums/windowsserver/en-US/a683ab54-c43c-4ebe-af8f-1f7a65af2a51, this is needed when having >900 printers to work around a size limit of the SYSTEM registry hive. And if Windows has both locations, we need both for compatibility anyway.
- Add several settings which are queried by the new Printer Data APIs when working with Print Server Handles.
- Store the job directory in the Windows-compatible "DefaultSpoolDirectory" setting and make use of it.
- Revert the ASSERTs in LocalEnumPrinters again to let us verify the NULL pointer exceptions in localspl_apitest (thanks Serge! CORE-13433)
- Translate ERROR_INVALID_NAME to ERROR_INVALID_PRINTER_NAME in all cases in OpenPrinterW (thanks Victor! CORE-13412)
- Make EnumMonitorsW and EnumPortsW in spoolss more robust against failing Print Monitors.
- Remove the wrong !phPrinter check in OpenPrinterW to make Print Server Handles work for real.
- Fix error handling when memory allocation fails: HeapAlloc doesn't set last error, so it's just wrong to query or return it.
One more item done from https://reactos.org/wiki/Printing !
This is all still a big Work-in-Progress, with many subtle bugs deep down in ReactOS, for which I need to open additional tickets. But I didn't want to make this commit even bigger..
svn path=/trunk/; revision=75125
2017-06-19 14:18:19 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
ERR("HeapAlloc failed!\n");
|
2017-05-09 15:44:42 +00:00
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy the Printer Name and a comma into it.
|
|
|
|
CopyMemory(pwszDeviceValueData, pszPrinter, cchPrinter * sizeof(WCHAR));
|
|
|
|
pwszDeviceValueData[cchPrinter] = L',';
|
|
|
|
|
|
|
|
// Append the value data, which has the format "winspool,<Port>:"
|
|
|
|
dwErrorCode = (DWORD)RegQueryValueExW(hDevicesKey, pszPrinter, NULL, NULL, (PBYTE)&pwszDeviceValueData[cchPrinter + 1], &cbPrinterValueData);
|
|
|
|
if (dwErrorCode != ERROR_SUCCESS)
|
|
|
|
goto Cleanup;
|
|
|
|
|
|
|
|
// Open the Windows registry key.
|
|
|
|
dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszWindowsKey, 0, KEY_SET_VALUE, &hWindowsKey);
|
|
|
|
if (dwErrorCode != ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Store our new default printer.
|
|
|
|
dwErrorCode = (DWORD)RegSetValueExW(hWindowsKey, wszDeviceValue, 0, REG_SZ, (PBYTE)pwszDeviceValueData, cbDeviceValueData);
|
|
|
|
if (dwErrorCode != ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
ERR("RegSetValueExW failed with status %lu!\n", dwErrorCode);
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
if (hDevicesKey)
|
|
|
|
RegCloseKey(hDevicesKey);
|
|
|
|
|
|
|
|
if (hWindowsKey)
|
|
|
|
RegCloseKey(hWindowsKey);
|
|
|
|
|
|
|
|
if (pwszDeviceValueData)
|
|
|
|
HeapFree(hProcessHeap, 0, pwszDeviceValueData);
|
|
|
|
|
|
|
|
SetLastError(dwErrorCode);
|
|
|
|
return (dwErrorCode == ERROR_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2017-12-09 12:35:42 +00:00
|
|
|
BOOL WINAPI
|
|
|
|
SetPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command)
|
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
BOOL Ret = FALSE;
|
|
|
|
UNICODE_STRING usBuffer;
|
|
|
|
PPRINTER_INFO_STRESS ppisa = (PPRINTER_INFO_STRESS)pPrinter;
|
|
|
|
PPRINTER_INFO_STRESS ppisw = (PPRINTER_INFO_STRESS)pPrinter;
|
|
|
|
PPRINTER_INFO_2A ppi2a = (PPRINTER_INFO_2A)pPrinter;
|
|
|
|
PPRINTER_INFO_2W ppi2w = (PPRINTER_INFO_2W)pPrinter;
|
|
|
|
PPRINTER_INFO_7A ppi7a = (PPRINTER_INFO_7A)pPrinter;
|
|
|
|
PPRINTER_INFO_7W ppi7w = (PPRINTER_INFO_7W)pPrinter;
|
|
|
|
PPRINTER_INFO_9A ppi9a = (PPRINTER_INFO_9A)pPrinter;
|
|
|
|
PPRINTER_INFO_9W ppi9w = (PPRINTER_INFO_9W)pPrinter;
|
|
|
|
PWSTR pwszPrinterName = NULL;
|
|
|
|
PWSTR pwszServerName = NULL;
|
|
|
|
PWSTR pwszShareName = NULL;
|
|
|
|
PWSTR pwszPortName = NULL;
|
|
|
|
PWSTR pwszDriverName = NULL;
|
|
|
|
PWSTR pwszComment = NULL;
|
|
|
|
PWSTR pwszLocation = NULL;
|
|
|
|
PWSTR pwszSepFile = NULL;
|
|
|
|
PWSTR pwszPrintProcessor = NULL;
|
|
|
|
PWSTR pwszDatatype = NULL;
|
|
|
|
PWSTR pwszParameters = NULL;
|
|
|
|
PDEVMODEW pdmw = NULL;
|
|
|
|
|
|
|
|
FIXME("SetPrinterA(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command);
|
|
|
|
|
|
|
|
switch ( Level )
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
if ( Command == 0 )
|
|
|
|
{
|
|
|
|
if (ppisa->pPrinterName)
|
|
|
|
{
|
|
|
|
pwszPrinterName = AsciiToUnicode(&usBuffer, (LPCSTR)ppisa->pPrinterName);
|
|
|
|
if (!(ppisw->pPrinterName = pwszPrinterName)) goto Cleanup;
|
|
|
|
}
|
|
|
|
if (ppisa->pServerName)
|
|
|
|
{
|
|
|
|
pwszServerName = AsciiToUnicode(&usBuffer, (LPCSTR)ppisa->pServerName);
|
|
|
|
if (!(ppisw->pPrinterName = pwszServerName)) goto Cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( Command == PRINTER_CONTROL_SET_STATUS )
|
|
|
|
{
|
|
|
|
// Set the pPrinter parameter to a pointer to a DWORD value that specifies the new printer status.
|
|
|
|
PRINTER_INFO_6 pi6;
|
2020-08-04 03:23:07 +00:00
|
|
|
pi6.dwStatus = (DWORD_PTR)pPrinter;
|
2020-08-04 02:07:58 +00:00
|
|
|
pPrinter = (LPBYTE)&pi6;
|
|
|
|
Level = 6;
|
|
|
|
Command = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
{
|
|
|
|
if (ppi2a->pShareName)
|
|
|
|
{
|
|
|
|
pwszShareName = AsciiToUnicode(&usBuffer, ppi2a->pShareName);
|
|
|
|
if (!(ppi2w->pShareName = pwszShareName)) goto Cleanup;
|
|
|
|
}
|
|
|
|
if (ppi2a->pPortName)
|
|
|
|
{
|
|
|
|
pwszPortName = AsciiToUnicode(&usBuffer, ppi2a->pPortName);
|
|
|
|
if (!(ppi2w->pPortName = pwszPortName)) goto Cleanup;
|
|
|
|
}
|
|
|
|
if (ppi2a->pDriverName)
|
|
|
|
{
|
|
|
|
pwszDriverName = AsciiToUnicode(&usBuffer, ppi2a->pDriverName);
|
|
|
|
if (!(ppi2w->pDriverName = pwszDriverName)) goto Cleanup;
|
|
|
|
}
|
|
|
|
if (ppi2a->pComment)
|
|
|
|
{
|
|
|
|
pwszComment = AsciiToUnicode(&usBuffer, ppi2a->pComment);
|
|
|
|
if (!(ppi2w->pComment = pwszComment)) goto Cleanup;
|
|
|
|
}
|
|
|
|
if (ppi2a->pLocation)
|
|
|
|
{
|
|
|
|
pwszLocation = AsciiToUnicode(&usBuffer, ppi2a->pLocation);
|
|
|
|
if (!(ppi2w->pLocation = pwszLocation)) goto Cleanup;
|
|
|
|
}
|
|
|
|
if (ppi2a->pSepFile)
|
|
|
|
{
|
|
|
|
pwszSepFile = AsciiToUnicode(&usBuffer, ppi2a->pSepFile);
|
|
|
|
if (!(ppi2w->pSepFile = pwszSepFile)) goto Cleanup;
|
|
|
|
}
|
|
|
|
if (ppi2a->pServerName)
|
|
|
|
{
|
|
|
|
pwszPrintProcessor = AsciiToUnicode(&usBuffer, ppi2a->pPrintProcessor);
|
|
|
|
if (!(ppi2w->pPrintProcessor = pwszPrintProcessor)) goto Cleanup;
|
|
|
|
}
|
|
|
|
if (ppi2a->pDatatype)
|
|
|
|
{
|
|
|
|
pwszDatatype = AsciiToUnicode(&usBuffer, ppi2a->pDatatype);
|
|
|
|
if (!(ppi2w->pDatatype = pwszDatatype)) goto Cleanup;
|
|
|
|
}
|
|
|
|
if (ppi2a->pParameters)
|
|
|
|
{
|
|
|
|
pwszParameters = AsciiToUnicode(&usBuffer, ppi2a->pParameters);
|
|
|
|
if (!(ppi2w->pParameters = pwszParameters)) goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ppi2a->pDevMode )
|
|
|
|
{
|
|
|
|
RosConvertAnsiDevModeToUnicodeDevmode( ppi2a->pDevMode, &pdmw );
|
|
|
|
ppi2w->pDevMode = pdmw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
|
|
// These two strings are relitive and common to these three Levels.
|
|
|
|
// Fall through...
|
|
|
|
//
|
|
|
|
case 4:
|
|
|
|
case 5:
|
|
|
|
{
|
|
|
|
if (ppi2a->pServerName) // 4 & 5 : pPrinterName.
|
|
|
|
{
|
|
|
|
pwszServerName = AsciiToUnicode(&usBuffer, ppi2a->pServerName);
|
|
|
|
if (!(ppi2w->pPrinterName = pwszServerName)) goto Cleanup;
|
|
|
|
}
|
|
|
|
if (ppi2a->pPrinterName) // 4 : pServerName, 5 : pPortName.
|
|
|
|
{
|
|
|
|
pwszPrinterName = AsciiToUnicode(&usBuffer, ppi2a->pPrinterName);
|
|
|
|
if (!(ppi2w->pPrinterName = pwszPrinterName)) goto Cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
case 6:
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
{
|
|
|
|
if (ppi7a->pszObjectGUID)
|
|
|
|
{
|
|
|
|
pwszPrinterName = AsciiToUnicode(&usBuffer, ppi7a->pszObjectGUID);
|
|
|
|
if (!(ppi7w->pszObjectGUID = pwszPrinterName)) goto Cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 8:
|
|
|
|
/* 8 is the global default printer info and 9 already sets it instead of the per-user one */
|
|
|
|
/* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
|
|
|
|
/* fall through */
|
|
|
|
case 9:
|
|
|
|
{
|
|
|
|
RosConvertAnsiDevModeToUnicodeDevmode( ppi9a->pDevMode, &pdmw );
|
|
|
|
ppi9w->pDevMode = pdmw;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
FIXME( "Unsupported level %d\n", Level);
|
|
|
|
SetLastError( ERROR_INVALID_LEVEL );
|
|
|
|
}
|
|
|
|
|
|
|
|
Ret = SetPrinterW( hPrinter, Level, pPrinter, Command );
|
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
if (pdmw) HeapFree(hProcessHeap, 0, pdmw);
|
|
|
|
if (pwszPrinterName) HeapFree(hProcessHeap, 0, pwszPrinterName);
|
|
|
|
if (pwszServerName) HeapFree(hProcessHeap, 0, pwszServerName);
|
|
|
|
if (pwszShareName) HeapFree(hProcessHeap, 0, pwszShareName);
|
|
|
|
if (pwszPortName) HeapFree(hProcessHeap, 0, pwszPortName);
|
|
|
|
if (pwszDriverName) HeapFree(hProcessHeap, 0, pwszDriverName);
|
|
|
|
if (pwszComment) HeapFree(hProcessHeap, 0, pwszComment);
|
|
|
|
if (pwszLocation) HeapFree(hProcessHeap, 0, pwszLocation);
|
|
|
|
if (pwszSepFile) HeapFree(hProcessHeap, 0, pwszSepFile);
|
|
|
|
if (pwszPrintProcessor) HeapFree(hProcessHeap, 0, pwszPrintProcessor);
|
|
|
|
if (pwszDatatype) HeapFree(hProcessHeap, 0, pwszDatatype);
|
|
|
|
if (pwszParameters) HeapFree(hProcessHeap, 0, pwszParameters);
|
|
|
|
return Ret;
|
2017-12-09 12:35:42 +00:00
|
|
|
}
|
|
|
|
|
2015-07-22 17:59:46 +00:00
|
|
|
BOOL WINAPI
|
|
|
|
SetPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command)
|
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
DWORD dwErrorCode;
|
|
|
|
WINSPOOL_PRINTER_CONTAINER PrinterContainer;
|
|
|
|
WINSPOOL_DEVMODE_CONTAINER DevModeContainer;
|
|
|
|
WINSPOOL_SECURITY_CONTAINER SecurityContainer;
|
|
|
|
SECURITY_DESCRIPTOR *sd = NULL;
|
|
|
|
DWORD size;
|
|
|
|
PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
|
|
|
|
|
|
|
|
FIXME("SetPrinterW(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command);
|
|
|
|
|
|
|
|
// Sanity checks
|
|
|
|
if (!pHandle)
|
|
|
|
return ERROR_INVALID_HANDLE;
|
|
|
|
|
|
|
|
DevModeContainer.cbBuf = 0;
|
|
|
|
DevModeContainer.pDevMode = NULL;
|
|
|
|
|
|
|
|
SecurityContainer.cbBuf = 0;
|
|
|
|
SecurityContainer.pSecurity = NULL;
|
|
|
|
|
|
|
|
switch ( Level )
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
if ( Command == PRINTER_CONTROL_SET_STATUS )
|
|
|
|
{
|
|
|
|
// Set the pPrinter parameter to a pointer to a DWORD value that specifies the new printer status.
|
|
|
|
PRINTER_INFO_6 pi6;
|
2020-08-04 03:23:07 +00:00
|
|
|
pi6.dwStatus = (DWORD_PTR)pPrinter;
|
2020-08-04 02:07:58 +00:00
|
|
|
pPrinter = (LPBYTE)&pi6;
|
|
|
|
Level = 6;
|
|
|
|
Command = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
{
|
|
|
|
PPRINTER_INFO_2W pi2w = (PPRINTER_INFO_2W)pPrinter;
|
|
|
|
if ( pi2w )
|
|
|
|
{
|
|
|
|
if ( pi2w->pDevMode )
|
|
|
|
{
|
|
|
|
if ( IsValidDevmodeNoSizeW( pi2w->pDevMode ) )
|
|
|
|
{
|
|
|
|
DevModeContainer.cbBuf = pi2w->pDevMode->dmSize + pi2w->pDevMode->dmDriverExtra;
|
|
|
|
DevModeContainer.pDevMode = (PBYTE)pi2w->pDevMode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( pi2w->pSecurityDescriptor )
|
|
|
|
{
|
|
|
|
sd = get_sd( pi2w->pSecurityDescriptor, &size );
|
|
|
|
if ( sd )
|
|
|
|
{
|
|
|
|
SecurityContainer.cbBuf = size;
|
|
|
|
SecurityContainer.pSecurity = (PBYTE)sd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
{
|
|
|
|
PPRINTER_INFO_3 pi3 = (PPRINTER_INFO_3)pPrinter;
|
|
|
|
if ( pi3 )
|
|
|
|
{
|
|
|
|
if ( pi3->pSecurityDescriptor )
|
|
|
|
{
|
|
|
|
sd = get_sd( pi3->pSecurityDescriptor, &size );
|
|
|
|
if ( sd )
|
|
|
|
{
|
|
|
|
SecurityContainer.cbBuf = size;
|
|
|
|
SecurityContainer.pSecurity = (PBYTE)sd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 4:
|
|
|
|
case 5:
|
|
|
|
case 6:
|
|
|
|
case 7:
|
|
|
|
if ( pPrinter == NULL )
|
|
|
|
{
|
|
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 8:
|
|
|
|
/* 8 is the global default printer info and 9 already sets it instead of the per-user one */
|
|
|
|
/* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
|
|
|
|
/* fall through */
|
|
|
|
case 9:
|
|
|
|
{
|
|
|
|
PPRINTER_INFO_9W pi9w = (PPRINTER_INFO_9W)pPrinter;
|
|
|
|
if ( pi9w )
|
|
|
|
{
|
|
|
|
if ( pi9w->pDevMode )
|
|
|
|
{
|
|
|
|
if ( IsValidDevmodeNoSizeW( pi9w->pDevMode ) )
|
|
|
|
{
|
|
|
|
DevModeContainer.cbBuf = pi9w->pDevMode->dmSize + pi9w->pDevMode->dmDriverExtra;
|
|
|
|
DevModeContainer.pDevMode = (LPBYTE)pi9w->pDevMode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
FIXME( "Unsupported level %d\n", Level );
|
|
|
|
SetLastError( ERROR_INVALID_LEVEL );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PrinterContainer.PrinterInfo.pPrinterInfo1 = (WINSPOOL_PRINTER_INFO_1*)pPrinter;
|
|
|
|
PrinterContainer.Level = Level;
|
|
|
|
|
|
|
|
// Do the RPC call
|
|
|
|
RpcTryExcept
|
|
|
|
{
|
|
|
|
dwErrorCode = _RpcSetPrinter(pHandle->hPrinter, &PrinterContainer, &DevModeContainer, &SecurityContainer, Command);
|
|
|
|
}
|
|
|
|
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
{
|
|
|
|
dwErrorCode = RpcExceptionCode();
|
|
|
|
}
|
|
|
|
RpcEndExcept;
|
|
|
|
|
|
|
|
if ( sd ) HeapFree( GetProcessHeap(), 0, sd );
|
|
|
|
|
|
|
|
SetLastError(dwErrorCode);
|
|
|
|
return (dwErrorCode == ERROR_SUCCESS);
|
2015-07-22 17:59:46 +00:00
|
|
|
}
|
|
|
|
|
2020-01-31 23:38:47 +00:00
|
|
|
BOOL WINAPI
|
|
|
|
SplDriverUnloadComplete(LPWSTR pDriverFile)
|
|
|
|
{
|
2020-02-06 18:10:21 +00:00
|
|
|
TRACE("DriverUnloadComplete(%S)\n", pDriverFile);
|
2020-01-31 23:38:47 +00:00
|
|
|
UNIMPLEMENTED;
|
|
|
|
return TRUE; // return true for now.
|
|
|
|
}
|
2020-08-04 02:07:58 +00:00
|
|
|
BOOL WINAPI
|
|
|
|
|
|
|
|
SpoolerPrinterEvent( LPWSTR pPrinterName, INT DriverEvent, DWORD Flags, LPARAM lParam )
|
|
|
|
{
|
|
|
|
HMODULE hLibrary;
|
|
|
|
HANDLE hPrinter;
|
|
|
|
BOOL Ret = FALSE;
|
|
|
|
|
|
|
|
if ( OpenPrinterW( pPrinterName, &hPrinter, NULL ) )
|
|
|
|
{
|
|
|
|
hLibrary = LoadPrinterDriver( hPrinter );
|
|
|
|
|
|
|
|
if ( hLibrary )
|
|
|
|
{
|
|
|
|
fpPrinterEvent = (PVOID)GetProcAddress( hLibrary, "DrvPrinterEvent" );
|
|
|
|
|
|
|
|
if ( fpPrinterEvent )
|
|
|
|
{
|
|
|
|
Ret = fpPrinterEvent( pPrinterName, DriverEvent, Flags, lParam );
|
|
|
|
}
|
|
|
|
|
|
|
|
FreeLibrary(hLibrary);
|
|
|
|
}
|
|
|
|
|
|
|
|
ClosePrinter( hPrinter );
|
|
|
|
}
|
|
|
|
|
|
|
|
return Ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
|
|
|
{
|
|
|
|
LPWSTR filename;
|
|
|
|
|
|
|
|
switch(msg)
|
|
|
|
{
|
|
|
|
case WM_INITDIALOG:
|
|
|
|
SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
case WM_COMMAND:
|
|
|
|
if(HIWORD(wparam) == BN_CLICKED)
|
|
|
|
{
|
|
|
|
if(LOWORD(wparam) == IDOK)
|
|
|
|
{
|
|
|
|
HANDLE hf;
|
|
|
|
DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
|
|
|
|
LPWSTR *output;
|
|
|
|
|
|
|
|
filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
|
|
|
|
GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
|
|
|
|
|
|
|
|
if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
|
|
|
|
{
|
|
|
|
WCHAR caption[200], message[200];
|
|
|
|
int mb_ret;
|
|
|
|
|
|
|
|
LoadStringW(hinstWinSpool, IDS_CAPTION, caption, ARRAYSIZE(caption));
|
|
|
|
LoadStringW(hinstWinSpool, IDS_FILE_EXISTS, message, ARRAYSIZE(message));
|
|
|
|
mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
|
|
|
|
if(mb_ret == IDCANCEL)
|
|
|
|
{
|
|
|
|
HeapFree(GetProcessHeap(), 0, filename);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
if(hf == INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
WCHAR caption[200], message[200];
|
|
|
|
|
|
|
|
LoadStringW(hinstWinSpool, IDS_CAPTION, caption, ARRAYSIZE(caption));
|
|
|
|
LoadStringW(hinstWinSpool, IDS_CANNOT_OPEN, message, ARRAYSIZE(message));
|
|
|
|
MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
|
|
|
|
HeapFree(GetProcessHeap(), 0, filename);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
CloseHandle(hf);
|
|
|
|
DeleteFileW(filename);
|
|
|
|
output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
|
|
|
|
*output = filename;
|
|
|
|
EndDialog(hwnd, IDOK);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
if(LOWORD(wparam) == IDCANCEL)
|
|
|
|
{
|
|
|
|
EndDialog(hwnd, IDCANCEL);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
|
|
|
|
|
|
|
|
LPWSTR WINAPI
|
|
|
|
StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
|
|
|
|
{
|
|
|
|
LPWSTR ret = NULL;
|
|
|
|
DWORD len, attr, retDlg;
|
|
|
|
|
|
|
|
FIXME("StartDocDlgW(%p, %p)\n", hPrinter, doc);
|
|
|
|
|
|
|
|
if (doc->lpszOutput == NULL) /* Check whether default port is FILE: */
|
|
|
|
{
|
|
|
|
PRINTER_INFO_5W *pi5;
|
|
|
|
GetPrinterW(hPrinter, 5, NULL, 0, &len);
|
|
|
|
if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
|
|
|
return NULL;
|
|
|
|
pi5 = HeapAlloc(GetProcessHeap(), 0, len);
|
|
|
|
GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
|
|
|
|
if (!pi5->pPortName || wcsicmp(pi5->pPortName, FILE_Port))
|
|
|
|
{
|
|
|
|
HeapFree(GetProcessHeap(), 0, pi5);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(), 0, pi5);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (doc->lpszOutput == NULL || !wcsicmp(doc->lpszOutput, FILE_Port))
|
|
|
|
{
|
|
|
|
LPWSTR name;
|
|
|
|
|
|
|
|
retDlg = DialogBoxParamW( hinstWinSpool,
|
|
|
|
MAKEINTRESOURCEW(FILENAME_DIALOG),
|
|
|
|
GetForegroundWindow(),
|
|
|
|
file_dlg_proc,
|
|
|
|
(LPARAM)&name );
|
|
|
|
|
|
|
|
if ( retDlg == IDOK )
|
|
|
|
{
|
|
|
|
if (!(len = GetFullPathNameW(name, 0, NULL, NULL)))
|
|
|
|
{
|
|
|
|
HeapFree(GetProcessHeap(), 0, name);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
|
|
|
|
GetFullPathNameW(name, len, ret, NULL);
|
|
|
|
HeapFree(GetProcessHeap(), 0, name);
|
|
|
|
}
|
|
|
|
else if ( retDlg == 0 ) // FALSE, some type of error occurred.
|
|
|
|
{
|
|
|
|
ret = (LPWSTR)SP_ERROR;
|
|
|
|
}
|
|
|
|
else if ( retDlg == IDCANCEL )
|
|
|
|
{
|
|
|
|
SetLastError( ERROR_CANCELLED );
|
|
|
|
ret = (LPWSTR)SP_APPABORT;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
|
|
|
|
GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
|
|
|
|
|
|
|
|
attr = GetFileAttributesW(ret);
|
|
|
|
if (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
|
|
|
|
{
|
|
|
|
HeapFree(GetProcessHeap(), 0, ret);
|
|
|
|
ret = NULL;
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
LPSTR WINAPI
|
|
|
|
StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
|
|
|
|
{
|
|
|
|
UNICODE_STRING usBuffer;
|
|
|
|
DOCINFOW docW = { 0 };
|
|
|
|
LPWSTR retW;
|
|
|
|
LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
|
|
|
|
LPSTR ret = NULL;
|
|
|
|
|
|
|
|
docW.cbSize = sizeof(docW);
|
|
|
|
if (doc->lpszDocName)
|
|
|
|
{
|
|
|
|
docnameW = AsciiToUnicode(&usBuffer, doc->lpszDocName);
|
|
|
|
if (!(docW.lpszDocName = docnameW)) goto failed;
|
|
|
|
}
|
|
|
|
if (doc->lpszOutput)
|
|
|
|
{
|
|
|
|
outputW = AsciiToUnicode(&usBuffer, doc->lpszOutput);
|
|
|
|
if (!(docW.lpszOutput = outputW)) goto failed;
|
|
|
|
}
|
|
|
|
if (doc->lpszDatatype)
|
|
|
|
{
|
|
|
|
datatypeW = AsciiToUnicode(&usBuffer, doc->lpszDatatype);
|
|
|
|
if (!(docW.lpszDatatype = datatypeW)) goto failed;
|
|
|
|
}
|
|
|
|
docW.fwType = doc->fwType;
|
|
|
|
|
|
|
|
retW = StartDocDlgW(hPrinter, &docW);
|
|
|
|
|
|
|
|
if (retW)
|
|
|
|
{
|
|
|
|
DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
|
|
|
|
ret = HeapAlloc(GetProcessHeap(), 0, len);
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
|
|
|
|
HeapFree(GetProcessHeap(), 0, retW);
|
|
|
|
}
|
|
|
|
|
|
|
|
failed:
|
|
|
|
if (datatypeW) HeapFree(GetProcessHeap(), 0, datatypeW);
|
|
|
|
if (outputW) HeapFree(GetProcessHeap(), 0, outputW);
|
|
|
|
if (docnameW) HeapFree(GetProcessHeap(), 0, docnameW);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2020-01-31 23:38:47 +00:00
|
|
|
|
2016-01-06 05:15:44 +00:00
|
|
|
DWORD WINAPI
|
|
|
|
StartDocPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
|
|
|
|
{
|
|
|
|
DOC_INFO_1W wDocInfo1 = { 0 };
|
|
|
|
DWORD cch;
|
|
|
|
DWORD dwErrorCode;
|
|
|
|
DWORD dwReturnValue = 0;
|
|
|
|
PDOC_INFO_1A pDocInfo1 = (PDOC_INFO_1A)pDocInfo;
|
|
|
|
|
2017-12-09 11:00:09 +00:00
|
|
|
TRACE("StartDocPrinterA(%p, %lu, %p)\n", hPrinter, Level, pDocInfo);
|
|
|
|
|
2016-01-06 05:15:44 +00:00
|
|
|
// Only check the minimum required for accessing pDocInfo.
|
|
|
|
// Additional sanity checks are done in StartDocPrinterW.
|
|
|
|
if (!pDocInfo1)
|
|
|
|
{
|
|
|
|
dwErrorCode = ERROR_INVALID_PARAMETER;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Level != 1)
|
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
ERR("Level = %d, unsupported!\n", Level);
|
2016-01-06 05:15:44 +00:00
|
|
|
dwErrorCode = ERROR_INVALID_LEVEL;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pDocInfo1->pDatatype)
|
|
|
|
{
|
|
|
|
// Convert pDocInfo1->pDatatype to a Unicode string wDocInfo1.pDatatype
|
|
|
|
cch = strlen(pDocInfo1->pDatatype);
|
|
|
|
|
|
|
|
wDocInfo1.pDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
|
|
|
|
if (!wDocInfo1.pDatatype)
|
|
|
|
{
|
[PRINTING]
- Implement GetPrinterDataA, GetPrinterDataExA, GetPrinterDataExW, GetPrinterDataW, SetPrinterDataA, SetPrinterDataExA, SetPrinterDataExW, SetPrinterDataW.
They support all features for Print Server and Printer Handles (minus security checks!)
I've also added tests for them.
- Store Printer data in SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers instead of SYSTEM\CurrentControlSet\Control\Print\Printers and create a registry symlink from the former path to the new one just like Windows does.
According to https://social.technet.microsoft.com/Forums/windowsserver/en-US/a683ab54-c43c-4ebe-af8f-1f7a65af2a51, this is needed when having >900 printers to work around a size limit of the SYSTEM registry hive. And if Windows has both locations, we need both for compatibility anyway.
- Add several settings which are queried by the new Printer Data APIs when working with Print Server Handles.
- Store the job directory in the Windows-compatible "DefaultSpoolDirectory" setting and make use of it.
- Revert the ASSERTs in LocalEnumPrinters again to let us verify the NULL pointer exceptions in localspl_apitest (thanks Serge! CORE-13433)
- Translate ERROR_INVALID_NAME to ERROR_INVALID_PRINTER_NAME in all cases in OpenPrinterW (thanks Victor! CORE-13412)
- Make EnumMonitorsW and EnumPortsW in spoolss more robust against failing Print Monitors.
- Remove the wrong !phPrinter check in OpenPrinterW to make Print Server Handles work for real.
- Fix error handling when memory allocation fails: HeapAlloc doesn't set last error, so it's just wrong to query or return it.
One more item done from https://reactos.org/wiki/Printing !
This is all still a big Work-in-Progress, with many subtle bugs deep down in ReactOS, for which I need to open additional tickets. But I didn't want to make this commit even bigger..
svn path=/trunk/; revision=75125
2017-06-19 14:18:19 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
ERR("HeapAlloc failed!\n");
|
2016-01-06 05:15:44 +00:00
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pDatatype, -1, wDocInfo1.pDatatype, cch + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pDocInfo1->pDocName)
|
|
|
|
{
|
|
|
|
// Convert pDocInfo1->pDocName to a Unicode string wDocInfo1.pDocName
|
|
|
|
cch = strlen(pDocInfo1->pDocName);
|
|
|
|
|
|
|
|
wDocInfo1.pDocName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
|
|
|
|
if (!wDocInfo1.pDocName)
|
|
|
|
{
|
[PRINTING]
- Implement GetPrinterDataA, GetPrinterDataExA, GetPrinterDataExW, GetPrinterDataW, SetPrinterDataA, SetPrinterDataExA, SetPrinterDataExW, SetPrinterDataW.
They support all features for Print Server and Printer Handles (minus security checks!)
I've also added tests for them.
- Store Printer data in SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers instead of SYSTEM\CurrentControlSet\Control\Print\Printers and create a registry symlink from the former path to the new one just like Windows does.
According to https://social.technet.microsoft.com/Forums/windowsserver/en-US/a683ab54-c43c-4ebe-af8f-1f7a65af2a51, this is needed when having >900 printers to work around a size limit of the SYSTEM registry hive. And if Windows has both locations, we need both for compatibility anyway.
- Add several settings which are queried by the new Printer Data APIs when working with Print Server Handles.
- Store the job directory in the Windows-compatible "DefaultSpoolDirectory" setting and make use of it.
- Revert the ASSERTs in LocalEnumPrinters again to let us verify the NULL pointer exceptions in localspl_apitest (thanks Serge! CORE-13433)
- Translate ERROR_INVALID_NAME to ERROR_INVALID_PRINTER_NAME in all cases in OpenPrinterW (thanks Victor! CORE-13412)
- Make EnumMonitorsW and EnumPortsW in spoolss more robust against failing Print Monitors.
- Remove the wrong !phPrinter check in OpenPrinterW to make Print Server Handles work for real.
- Fix error handling when memory allocation fails: HeapAlloc doesn't set last error, so it's just wrong to query or return it.
One more item done from https://reactos.org/wiki/Printing !
This is all still a big Work-in-Progress, with many subtle bugs deep down in ReactOS, for which I need to open additional tickets. But I didn't want to make this commit even bigger..
svn path=/trunk/; revision=75125
2017-06-19 14:18:19 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
ERR("HeapAlloc failed!\n");
|
2016-01-06 05:15:44 +00:00
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pDocName, -1, wDocInfo1.pDocName, cch + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pDocInfo1->pOutputFile)
|
|
|
|
{
|
|
|
|
// Convert pDocInfo1->pOutputFile to a Unicode string wDocInfo1.pOutputFile
|
|
|
|
cch = strlen(pDocInfo1->pOutputFile);
|
|
|
|
|
|
|
|
wDocInfo1.pOutputFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
|
|
|
|
if (!wDocInfo1.pOutputFile)
|
|
|
|
{
|
[PRINTING]
- Implement GetPrinterDataA, GetPrinterDataExA, GetPrinterDataExW, GetPrinterDataW, SetPrinterDataA, SetPrinterDataExA, SetPrinterDataExW, SetPrinterDataW.
They support all features for Print Server and Printer Handles (minus security checks!)
I've also added tests for them.
- Store Printer data in SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers instead of SYSTEM\CurrentControlSet\Control\Print\Printers and create a registry symlink from the former path to the new one just like Windows does.
According to https://social.technet.microsoft.com/Forums/windowsserver/en-US/a683ab54-c43c-4ebe-af8f-1f7a65af2a51, this is needed when having >900 printers to work around a size limit of the SYSTEM registry hive. And if Windows has both locations, we need both for compatibility anyway.
- Add several settings which are queried by the new Printer Data APIs when working with Print Server Handles.
- Store the job directory in the Windows-compatible "DefaultSpoolDirectory" setting and make use of it.
- Revert the ASSERTs in LocalEnumPrinters again to let us verify the NULL pointer exceptions in localspl_apitest (thanks Serge! CORE-13433)
- Translate ERROR_INVALID_NAME to ERROR_INVALID_PRINTER_NAME in all cases in OpenPrinterW (thanks Victor! CORE-13412)
- Make EnumMonitorsW and EnumPortsW in spoolss more robust against failing Print Monitors.
- Remove the wrong !phPrinter check in OpenPrinterW to make Print Server Handles work for real.
- Fix error handling when memory allocation fails: HeapAlloc doesn't set last error, so it's just wrong to query or return it.
One more item done from https://reactos.org/wiki/Printing !
This is all still a big Work-in-Progress, with many subtle bugs deep down in ReactOS, for which I need to open additional tickets. But I didn't want to make this commit even bigger..
svn path=/trunk/; revision=75125
2017-06-19 14:18:19 +00:00
|
|
|
dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
ERR("HeapAlloc failed!\n");
|
2016-01-06 05:15:44 +00:00
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pOutputFile, -1, wDocInfo1.pOutputFile, cch + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
dwReturnValue = StartDocPrinterW(hPrinter, Level, (PBYTE)&wDocInfo1);
|
|
|
|
dwErrorCode = GetLastError();
|
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
if (wDocInfo1.pDatatype)
|
|
|
|
HeapFree(hProcessHeap, 0, wDocInfo1.pDatatype);
|
|
|
|
|
|
|
|
if (wDocInfo1.pDocName)
|
|
|
|
HeapFree(hProcessHeap, 0, wDocInfo1.pDocName);
|
|
|
|
|
|
|
|
if (wDocInfo1.pOutputFile)
|
|
|
|
HeapFree(hProcessHeap, 0, wDocInfo1.pOutputFile);
|
|
|
|
|
|
|
|
SetLastError(dwErrorCode);
|
|
|
|
return dwReturnValue;
|
|
|
|
}
|
|
|
|
|
2015-06-22 14:31:47 +00:00
|
|
|
DWORD WINAPI
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
StartDocPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
|
2015-06-22 14:31:47 +00:00
|
|
|
{
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
DWORD cbAddJobInfo1;
|
|
|
|
DWORD cbNeeded;
|
|
|
|
DWORD dwErrorCode;
|
2016-01-06 05:15:44 +00:00
|
|
|
DWORD dwReturnValue = 0;
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
PADDJOB_INFO_1W pAddJobInfo1 = NULL;
|
|
|
|
PDOC_INFO_1W pDocInfo1 = (PDOC_INFO_1W)pDocInfo;
|
|
|
|
PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
|
|
|
|
|
2017-12-09 11:00:09 +00:00
|
|
|
TRACE("StartDocPrinterW(%p, %lu, %p)\n", hPrinter, Level, pDocInfo);
|
|
|
|
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
// Sanity checks.
|
|
|
|
if (!pHandle)
|
|
|
|
{
|
|
|
|
dwErrorCode = ERROR_INVALID_HANDLE;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!pDocInfo1)
|
|
|
|
{
|
|
|
|
dwErrorCode = ERROR_INVALID_PARAMETER;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Level != 1)
|
|
|
|
{
|
2020-08-04 02:07:58 +00:00
|
|
|
ERR("Level = %d, unsupported!\n", Level);
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
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;
|
[PRINTING]
- Implement GetPrinterDataA, GetPrinterDataExA, GetPrinterDataExW, GetPrinterDataW, SetPrinterDataA, SetPrinterDataExA, SetPrinterDataExW, SetPrinterDataW.
They support all features for Print Server and Printer Handles (minus security checks!)
I've also added tests for them.
- Store Printer data in SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers instead of SYSTEM\CurrentControlSet\Control\Print\Printers and create a registry symlink from the former path to the new one just like Windows does.
According to https://social.technet.microsoft.com/Forums/windowsserver/en-US/a683ab54-c43c-4ebe-af8f-1f7a65af2a51, this is needed when having >900 printers to work around a size limit of the SYSTEM registry hive. And if Windows has both locations, we need both for compatibility anyway.
- Add several settings which are queried by the new Printer Data APIs when working with Print Server Handles.
- Store the job directory in the Windows-compatible "DefaultSpoolDirectory" setting and make use of it.
- Revert the ASSERTs in LocalEnumPrinters again to let us verify the NULL pointer exceptions in localspl_apitest (thanks Serge! CORE-13433)
- Translate ERROR_INVALID_NAME to ERROR_INVALID_PRINTER_NAME in all cases in OpenPrinterW (thanks Victor! CORE-13412)
- Make EnumMonitorsW and EnumPortsW in spoolss more robust against failing Print Monitors.
- Remove the wrong !phPrinter check in OpenPrinterW to make Print Server Handles work for real.
- Fix error handling when memory allocation fails: HeapAlloc doesn't set last error, so it's just wrong to query or return it.
One more item done from https://reactos.org/wiki/Printing !
This is all still a big Work-in-Progress, with many subtle bugs deep down in ReactOS, for which I need to open additional tickets. But I didn't want to make this commit even bigger..
svn path=/trunk/; revision=75125
2017-06-19 14:18:19 +00:00
|
|
|
ERR("HeapAlloc failed!\n");
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try to add a new job.
|
|
|
|
// This only succeeds if the printer is set to do spooled printing.
|
2015-07-17 15:11:34 +00:00
|
|
|
if (AddJobW((HANDLE)pHandle, 1, (PBYTE)pAddJobInfo1, cbAddJobInfo1, &cbNeeded))
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
{
|
|
|
|
// 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)
|
2016-01-06 05:15:44 +00:00
|
|
|
{
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
pHandle->bStartedDoc = TRUE;
|
2016-01-06 05:15:44 +00:00
|
|
|
dwReturnValue = pHandle->dwJobID;
|
2020-08-04 02:07:58 +00:00
|
|
|
if ( !pHandle->bTrayIcon )
|
|
|
|
{
|
2020-08-26 22:12:20 +00:00
|
|
|
UpdateTrayIcon( hPrinter, pHandle->dwJobID );
|
2020-08-04 02:07:58 +00:00
|
|
|
}
|
2016-01-06 05:15:44 +00:00
|
|
|
}
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
if (pAddJobInfo1)
|
|
|
|
HeapFree(hProcessHeap, 0, pAddJobInfo1);
|
|
|
|
|
|
|
|
SetLastError(dwErrorCode);
|
2016-01-06 05:15:44 +00:00
|
|
|
return dwReturnValue;
|
2015-06-22 14:31:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI
|
|
|
|
StartPagePrinter(HANDLE hPrinter)
|
|
|
|
{
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
DWORD dwErrorCode;
|
|
|
|
PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
|
|
|
|
|
2017-12-09 11:00:09 +00:00
|
|
|
TRACE("StartPagePrinter(%p)\n", hPrinter);
|
|
|
|
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
// 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);
|
2015-06-22 14:31:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
WritePrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten)
|
2015-06-22 14:31:47 +00:00
|
|
|
{
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
DWORD dwErrorCode;
|
|
|
|
PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
|
|
|
|
|
2017-12-09 11:00:09 +00:00
|
|
|
TRACE("WritePrinter(%p, %p, %lu, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
|
|
|
|
|
[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 :)
svn path=/branches/colins-printing-for-freedom/; revision=68405
2015-07-16 15:03:47 +00:00
|
|
|
// 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);
|
2015-06-22 14:31:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI
|
|
|
|
XcvDataW(HANDLE hXcv, PCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded, PDWORD pdwStatus)
|
|
|
|
{
|
2020-08-26 22:12:20 +00:00
|
|
|
DWORD dwErrorCode, Bogus = 0;
|
|
|
|
PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hXcv;
|
|
|
|
|
2017-12-09 11:00:09 +00:00
|
|
|
TRACE("XcvDataW(%p, %S, %p, %lu, %p, %lu, %p, %p)\n", hXcv, pszDataName, pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
|
2020-08-26 22:12:20 +00:00
|
|
|
|
|
|
|
if ( pcbOutputNeeded == NULL )
|
|
|
|
{
|
|
|
|
dwErrorCode = ERROR_INVALID_PARAMETER;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sanity checks.
|
|
|
|
if (!pHandle) // ( IntProtectHandle( hXcv, FALSE ) )
|
|
|
|
{
|
|
|
|
dwErrorCode = ERROR_INVALID_HANDLE;
|
|
|
|
goto Cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Do fixups.
|
|
|
|
//
|
|
|
|
if ( pInputData == NULL )
|
|
|
|
{
|
|
|
|
if ( !cbInputData )
|
|
|
|
{
|
|
|
|
pInputData = (PBYTE)&Bogus;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( pOutputData == NULL )
|
|
|
|
{
|
|
|
|
if ( !cbOutputData )
|
|
|
|
{
|
|
|
|
pOutputData = (PBYTE)&Bogus;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do the RPC call
|
|
|
|
RpcTryExcept
|
|
|
|
{
|
|
|
|
dwErrorCode = _RpcXcvData( pHandle->hPrinter,
|
|
|
|
pszDataName,
|
|
|
|
pInputData,
|
|
|
|
cbInputData,
|
|
|
|
pOutputData,
|
|
|
|
cbOutputData,
|
|
|
|
pcbOutputNeeded,
|
|
|
|
pdwStatus );
|
|
|
|
}
|
|
|
|
RpcExcept(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
{
|
|
|
|
dwErrorCode = RpcExceptionCode();
|
|
|
|
ERR("_RpcXcvData failed with exception code %lu!\n", dwErrorCode);
|
|
|
|
}
|
|
|
|
RpcEndExcept;
|
|
|
|
|
|
|
|
//IntUnprotectHandle( hXcv );
|
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
SetLastError(dwErrorCode);
|
|
|
|
return (dwErrorCode == ERROR_SUCCESS);
|
2015-06-22 14:31:47 +00:00
|
|
|
}
|