1c2c66affSColin Finck /*
2c2c66affSColin Finck  * PROJECT:     ReactOS Spooler API
3c2c66affSColin Finck  * LICENSE:     GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4c2c66affSColin Finck  * PURPOSE:     Functions related to Printers and printing
522ffe530SColin Finck  * COPYRIGHT:   Copyright 2015-2018 Colin Finck (colin@reactos.org)
6c2c66affSColin Finck  */
7c2c66affSColin Finck 
8c2c66affSColin Finck #include "precomp.h"
922ffe530SColin Finck #include <marshalling/printers.h>
107bffb703SJames Tabor //#include <marshalling/printerdrivers.h>
11e8b17782SDoug Lyons #include <strsafe.h>
12c2c66affSColin Finck 
137bffb703SJames Tabor extern HINSTANCE hinstWinSpool;
147bffb703SJames Tabor //
157bffb703SJames Tabor // See winddiui.h, ReactOS version is limited.
167bffb703SJames Tabor // Loading from XyzUI.dll part of XyzDRV.dll set. example TTYUI.DLL or UniDrvUI.DLL.
177bffb703SJames Tabor //
187bffb703SJames Tabor typedef DWORD (WINAPI *DEVICECAPABILITIES) (HANDLE,PWSTR,WORD,PVOID,PDEVMODEW);
197bffb703SJames Tabor static DEVICECAPABILITIES fpDeviceCapabilities;
207bffb703SJames Tabor 
217bffb703SJames Tabor typedef LONG (WINAPI *DEVICEPROPERTYSHEETS) (PPROPSHEETUI_INFO,LPARAM);
227bffb703SJames Tabor static DEVICEPROPERTYSHEETS fpDevicePropertySheets;
237bffb703SJames Tabor typedef LONG (WINAPI *DOCUMENTPROPERTYSHEETS) (PPROPSHEETUI_INFO,LPARAM);
247bffb703SJames Tabor static DOCUMENTPROPERTYSHEETS fpDocumentPropertySheets;
257bffb703SJames Tabor 
267bffb703SJames Tabor typedef LONG (WINAPI *COMMONPROPERTYSHEETUIW) (HWND,PFNPROPSHEETUI,LPARAM,LPDWORD);
277bffb703SJames Tabor static COMMONPROPERTYSHEETUIW fpCommonPropertySheetUIW;
287bffb703SJames Tabor 
297bffb703SJames Tabor typedef LONG (WINAPI *QUERYCOLORPROFILE) (HANDLE,PDEVMODEW,ULONG,PVOID,ULONG*,FLONG*);
307bffb703SJames Tabor static  QUERYCOLORPROFILE fpQueryColorProfile;
317bffb703SJames Tabor 
327bffb703SJames Tabor typedef BOOL (WINAPI *SPOOLERPRINTEREVENT) (LPWSTR,int,DWORD,LPARAM);
337bffb703SJames Tabor static SPOOLERPRINTEREVENT fpPrinterEvent;
347bffb703SJames Tabor 
357bffb703SJames Tabor typedef BOOL (WINAPI *DEVQUERYPRINT) (HANDLE,LPDEVMODEW,DWORD*);
367bffb703SJames Tabor static DEVQUERYPRINT fpDevQueryPrint;
377bffb703SJames Tabor 
387bffb703SJames Tabor typedef BOOL (WINAPI *DEVQUERYPRINTEX) (PDEVQUERYPRINT_INFO);
397bffb703SJames Tabor static DEVQUERYPRINTEX fpDevQueryPrintEx;
407bffb703SJames Tabor 
417bffb703SJames Tabor //
427bffb703SJames Tabor //  PrintUI.dll
437bffb703SJames Tabor //
447bffb703SJames Tabor LONG WINAPI ConstructPrinterFriendlyName( PWSTR, PVOID, LPDWORD Size );
457bffb703SJames Tabor typedef LONG (WINAPI *CONSTRUCTPRINTERFRIENDLYNAME) (PWSTR,PVOID,LPDWORD);
467bffb703SJames Tabor static CONSTRUCTPRINTERFRIENDLYNAME fpConstructPrinterFriendlyName;
477bffb703SJames Tabor 
487bffb703SJames Tabor //
497bffb703SJames Tabor //  CompstUI User Data
507bffb703SJames Tabor //
517bffb703SJames Tabor typedef struct _COMPUI_USERDATA
527bffb703SJames Tabor {
537bffb703SJames Tabor   HMODULE hModule;
547bffb703SJames Tabor   LPWSTR pszPrinterName;
557bffb703SJames Tabor } COMPUI_USERDATA, *PCOMPUI_USERDATA;
567bffb703SJames Tabor 
57c2c66affSColin Finck // Local Constants
58c2c66affSColin Finck 
59c2c66affSColin Finck /** And the award for the most confusingly named setting goes to "Device", for storing the default printer of the current user.
60c2c66affSColin Finck     Ok, I admit that this has historical reasons. It's still not straightforward in any way though! */
61c2c66affSColin Finck static const WCHAR wszWindowsKey[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows";
62c2c66affSColin Finck static const WCHAR wszDeviceValue[] = L"Device";
63c2c66affSColin Finck 
64c2c66affSColin Finck static DWORD
_StartDocPrinterSpooled(PSPOOLER_HANDLE pHandle,PDOC_INFO_1W pDocInfo1,PADDJOB_INFO_1W pAddJobInfo1)65c2c66affSColin Finck _StartDocPrinterSpooled(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1, PADDJOB_INFO_1W pAddJobInfo1)
66c2c66affSColin Finck {
67c2c66affSColin Finck     DWORD cbNeeded;
68c2c66affSColin Finck     DWORD dwErrorCode;
69c2c66affSColin Finck     PJOB_INFO_1W pJobInfo1 = NULL;
70c2c66affSColin Finck 
71c2c66affSColin Finck     // Create the spool file.
72c2c66affSColin Finck     pHandle->hSPLFile = CreateFileW(pAddJobInfo1->Path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
73c2c66affSColin Finck     if (pHandle->hSPLFile == INVALID_HANDLE_VALUE)
74c2c66affSColin Finck     {
75c2c66affSColin Finck         dwErrorCode = GetLastError();
76c2c66affSColin Finck         ERR("CreateFileW failed for \"%S\" with error %lu!\n", pAddJobInfo1->Path, dwErrorCode);
77c2c66affSColin Finck         goto Cleanup;
78c2c66affSColin Finck     }
79c2c66affSColin Finck 
80c2c66affSColin Finck     // Get the size of the job information.
81c2c66affSColin Finck     GetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, NULL, 0, &cbNeeded);
82c2c66affSColin Finck     if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
83c2c66affSColin Finck     {
84c2c66affSColin Finck         dwErrorCode = GetLastError();
85c2c66affSColin Finck         ERR("GetJobW failed with error %lu!\n", dwErrorCode);
86c2c66affSColin Finck         goto Cleanup;
87c2c66affSColin Finck     }
88c2c66affSColin Finck 
89c2c66affSColin Finck     // Allocate enough memory for the returned job information.
90c2c66affSColin Finck     pJobInfo1 = HeapAlloc(hProcessHeap, 0, cbNeeded);
91c2c66affSColin Finck     if (!pJobInfo1)
92c2c66affSColin Finck     {
93c2c66affSColin Finck         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
94c2c66affSColin Finck         ERR("HeapAlloc failed!\n");
95c2c66affSColin Finck         goto Cleanup;
96c2c66affSColin Finck     }
97c2c66affSColin Finck 
98c2c66affSColin Finck     // Get the job information.
99c2c66affSColin Finck     if (!GetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1, cbNeeded, &cbNeeded))
100c2c66affSColin Finck     {
101c2c66affSColin Finck         dwErrorCode = GetLastError();
102c2c66affSColin Finck         ERR("GetJobW failed with error %lu!\n", dwErrorCode);
103c2c66affSColin Finck         goto Cleanup;
104c2c66affSColin Finck     }
105c2c66affSColin Finck 
106c2c66affSColin Finck     // Add our document information.
107c2c66affSColin Finck     if (pDocInfo1->pDatatype)
108c2c66affSColin Finck         pJobInfo1->pDatatype = pDocInfo1->pDatatype;
109c2c66affSColin Finck 
110c2c66affSColin Finck     pJobInfo1->pDocument = pDocInfo1->pDocName;
111c2c66affSColin Finck 
112c2c66affSColin Finck     // Set the new job information.
113c2c66affSColin Finck     if (!SetJobW((HANDLE)pHandle, pAddJobInfo1->JobId, 1, (PBYTE)pJobInfo1, 0))
114c2c66affSColin Finck     {
115c2c66affSColin Finck         dwErrorCode = GetLastError();
116c2c66affSColin Finck         ERR("SetJobW failed with error %lu!\n", dwErrorCode);
117c2c66affSColin Finck         goto Cleanup;
118c2c66affSColin Finck     }
119c2c66affSColin Finck 
120c2c66affSColin Finck     // We were successful!
121c2c66affSColin Finck     pHandle->dwJobID = pAddJobInfo1->JobId;
122c2c66affSColin Finck     dwErrorCode = ERROR_SUCCESS;
123c2c66affSColin Finck 
124c2c66affSColin Finck Cleanup:
125c2c66affSColin Finck     if (pJobInfo1)
126c2c66affSColin Finck         HeapFree(hProcessHeap, 0, pJobInfo1);
127c2c66affSColin Finck 
128c2c66affSColin Finck     return dwErrorCode;
129c2c66affSColin Finck }
130c2c66affSColin Finck 
131c2c66affSColin Finck static DWORD
_StartDocPrinterWithRPC(PSPOOLER_HANDLE pHandle,PDOC_INFO_1W pDocInfo1)132c2c66affSColin Finck _StartDocPrinterWithRPC(PSPOOLER_HANDLE pHandle, PDOC_INFO_1W pDocInfo1)
133c2c66affSColin Finck {
134c2c66affSColin Finck     DWORD dwErrorCode;
135c2c66affSColin Finck     WINSPOOL_DOC_INFO_CONTAINER DocInfoContainer;
136c2c66affSColin Finck 
137c2c66affSColin Finck     DocInfoContainer.Level = 1;
138c2c66affSColin Finck     DocInfoContainer.DocInfo.pDocInfo1 = (WINSPOOL_DOC_INFO_1*)pDocInfo1;
139c2c66affSColin Finck 
140c2c66affSColin Finck     RpcTryExcept
141c2c66affSColin Finck     {
142c2c66affSColin Finck         dwErrorCode = _RpcStartDocPrinter(pHandle->hPrinter, &DocInfoContainer, &pHandle->dwJobID);
143c2c66affSColin Finck     }
144c2c66affSColin Finck     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
145c2c66affSColin Finck     {
146c2c66affSColin Finck         dwErrorCode = RpcExceptionCode();
147c2c66affSColin Finck         ERR("_RpcStartDocPrinter failed with exception code %lu!\n", dwErrorCode);
148c2c66affSColin Finck     }
149c2c66affSColin Finck     RpcEndExcept;
150c2c66affSColin Finck 
151c2c66affSColin Finck     return dwErrorCode;
152c2c66affSColin Finck }
153c2c66affSColin Finck 
15446b91659SColin Finck BOOL WINAPI
AbortPrinter(HANDLE hPrinter)15546b91659SColin Finck AbortPrinter(HANDLE hPrinter)
15646b91659SColin Finck {
1577bffb703SJames Tabor     DWORD dwErrorCode;
1587bffb703SJames Tabor     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
1597bffb703SJames Tabor 
16046b91659SColin Finck     TRACE("AbortPrinter(%p)\n", hPrinter);
1617bffb703SJames Tabor 
1627bffb703SJames Tabor     // Sanity checks.
1637bffb703SJames Tabor     if (!pHandle)
1647bffb703SJames Tabor     {
1657bffb703SJames Tabor         dwErrorCode = ERROR_INVALID_HANDLE;
1667bffb703SJames Tabor         goto Cleanup;
1677bffb703SJames Tabor     }
1687bffb703SJames Tabor 
1697bffb703SJames Tabor     pHandle->bTrayIcon = pHandle->bStartedDoc = FALSE;
1707bffb703SJames Tabor 
1717bffb703SJames Tabor     if ( pHandle->hSPLFile != INVALID_HANDLE_VALUE && pHandle->bJob )
1727bffb703SJames Tabor     {
1737bffb703SJames Tabor         // Close any open file handle.
1747bffb703SJames Tabor         CloseHandle( pHandle->hSPLFile );
1757bffb703SJames Tabor         pHandle->hSPLFile = INVALID_HANDLE_VALUE;
1767bffb703SJames Tabor 
1777bffb703SJames Tabor         SetJobW( hPrinter, pHandle->dwJobID, 0, NULL, JOB_CONTROL_DELETE );
1787bffb703SJames Tabor 
1797bffb703SJames Tabor         return ScheduleJob( hPrinter, pHandle->dwJobID );
1807bffb703SJames Tabor     }
1817bffb703SJames Tabor 
1827bffb703SJames Tabor     // Do the RPC call.
1837bffb703SJames Tabor     RpcTryExcept
1847bffb703SJames Tabor     {
1857bffb703SJames Tabor         dwErrorCode = _RpcAbortPrinter(&pHandle->hPrinter);
1867bffb703SJames Tabor     }
1877bffb703SJames Tabor     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1887bffb703SJames Tabor     {
1897bffb703SJames Tabor         dwErrorCode = RpcExceptionCode();
1907bffb703SJames Tabor         ERR("_RpcAbortPrinter failed with exception code %lu!\n", dwErrorCode);
1917bffb703SJames Tabor     }
1927bffb703SJames Tabor     RpcEndExcept;
1937bffb703SJames Tabor 
1947bffb703SJames Tabor Cleanup:
1957bffb703SJames Tabor     SetLastError(dwErrorCode);
1967bffb703SJames Tabor     return (dwErrorCode == ERROR_SUCCESS);
19746b91659SColin Finck }
19846b91659SColin Finck 
19946b91659SColin Finck HANDLE WINAPI
AddPrinterA(PSTR pName,DWORD Level,PBYTE pPrinter)20046b91659SColin Finck AddPrinterA(PSTR pName, DWORD Level, PBYTE pPrinter)
20146b91659SColin Finck {
2027bffb703SJames Tabor     UNICODE_STRING pNameW, usBuffer;
2037bffb703SJames Tabor     PWSTR pwstrNameW;
2047bffb703SJames Tabor     PRINTER_INFO_2W *ppi2w = (PRINTER_INFO_2W*)pPrinter;
2057bffb703SJames Tabor     PRINTER_INFO_2A *ppi2a = (PRINTER_INFO_2A*)pPrinter;
2067bffb703SJames Tabor     HANDLE ret = NULL;
2077bffb703SJames Tabor     PWSTR pwszPrinterName = NULL;
2087bffb703SJames Tabor     PWSTR pwszServerName = NULL;
2097bffb703SJames Tabor     PWSTR pwszShareName = NULL;
2107bffb703SJames Tabor     PWSTR pwszPortName = NULL;
2117bffb703SJames Tabor     PWSTR pwszDriverName = NULL;
2127bffb703SJames Tabor     PWSTR pwszComment = NULL;
2137bffb703SJames Tabor     PWSTR pwszLocation = NULL;
2147bffb703SJames Tabor     PWSTR pwszSepFile = NULL;
2157bffb703SJames Tabor     PWSTR pwszPrintProcessor = NULL;
2167bffb703SJames Tabor     PWSTR pwszDatatype = NULL;
2177bffb703SJames Tabor     PWSTR pwszParameters = NULL;
2187bffb703SJames Tabor     PDEVMODEW pdmw = NULL;
2197bffb703SJames Tabor 
2207bffb703SJames Tabor     TRACE("AddPrinterA(%s, %d, %p)\n", debugstr_a(pName), Level, pPrinter);
2217bffb703SJames Tabor 
2227bffb703SJames Tabor     if(Level != 2)
2237bffb703SJames Tabor     {
2247bffb703SJames Tabor         ERR("Level = %d, unsupported!\n", Level);
2257bffb703SJames Tabor         SetLastError(ERROR_INVALID_LEVEL);
22646b91659SColin Finck         return NULL;
22746b91659SColin Finck     }
22846b91659SColin Finck 
2297bffb703SJames Tabor     pwstrNameW = AsciiToUnicode(&pNameW,pName);
2307bffb703SJames Tabor 
2317bffb703SJames Tabor     if (ppi2a->pShareName)
2327bffb703SJames Tabor     {
2337bffb703SJames Tabor         pwszShareName = AsciiToUnicode(&usBuffer, ppi2a->pShareName);
2347bffb703SJames Tabor         if (!(ppi2w->pShareName = pwszShareName)) goto Cleanup;
2357bffb703SJames Tabor     }
2367bffb703SJames Tabor     if (ppi2a->pPortName)
2377bffb703SJames Tabor     {
2387bffb703SJames Tabor         pwszPortName = AsciiToUnicode(&usBuffer, ppi2a->pPortName);
2397bffb703SJames Tabor         if (!(ppi2w->pPortName = pwszPortName)) goto Cleanup;
2407bffb703SJames Tabor     }
2417bffb703SJames Tabor     if (ppi2a->pDriverName)
2427bffb703SJames Tabor     {
2437bffb703SJames Tabor         pwszDriverName = AsciiToUnicode(&usBuffer, ppi2a->pDriverName);
2447bffb703SJames Tabor         if (!(ppi2w->pDriverName = pwszDriverName)) goto Cleanup;
2457bffb703SJames Tabor     }
2467bffb703SJames Tabor     if (ppi2a->pComment)
2477bffb703SJames Tabor     {
2487bffb703SJames Tabor         pwszComment = AsciiToUnicode(&usBuffer, ppi2a->pComment);
2497bffb703SJames Tabor         if (!(ppi2w->pComment = pwszComment)) goto Cleanup;
2507bffb703SJames Tabor     }
2517bffb703SJames Tabor     if (ppi2a->pLocation)
2527bffb703SJames Tabor     {
2537bffb703SJames Tabor         pwszLocation = AsciiToUnicode(&usBuffer, ppi2a->pLocation);
2547bffb703SJames Tabor         if (!(ppi2w->pLocation = pwszLocation)) goto Cleanup;
2557bffb703SJames Tabor     }
2567bffb703SJames Tabor     if (ppi2a->pSepFile)
2577bffb703SJames Tabor     {
2587bffb703SJames Tabor         pwszSepFile = AsciiToUnicode(&usBuffer, ppi2a->pSepFile);
2597bffb703SJames Tabor         if (!(ppi2w->pSepFile = pwszSepFile)) goto Cleanup;
2607bffb703SJames Tabor     }
2617bffb703SJames Tabor     if (ppi2a->pServerName)
2627bffb703SJames Tabor     {
2637bffb703SJames Tabor         pwszPrintProcessor = AsciiToUnicode(&usBuffer, ppi2a->pPrintProcessor);
2647bffb703SJames Tabor         if (!(ppi2w->pPrintProcessor = pwszPrintProcessor)) goto Cleanup;
2657bffb703SJames Tabor     }
2667bffb703SJames Tabor     if (ppi2a->pDatatype)
2677bffb703SJames Tabor     {
2687bffb703SJames Tabor         pwszDatatype = AsciiToUnicode(&usBuffer, ppi2a->pDatatype);
2697bffb703SJames Tabor         if (!(ppi2w->pDatatype = pwszDatatype)) goto Cleanup;
2707bffb703SJames Tabor     }
2717bffb703SJames Tabor     if (ppi2a->pParameters)
2727bffb703SJames Tabor     {
2737bffb703SJames Tabor         pwszParameters = AsciiToUnicode(&usBuffer, ppi2a->pParameters);
2747bffb703SJames Tabor         if (!(ppi2w->pParameters = pwszParameters)) goto Cleanup;
2757bffb703SJames Tabor     }
2767bffb703SJames Tabor     if ( ppi2a->pDevMode )
2777bffb703SJames Tabor     {
2787bffb703SJames Tabor         RosConvertAnsiDevModeToUnicodeDevmode( ppi2a->pDevMode, &pdmw );
2797bffb703SJames Tabor         ppi2w->pDevMode = pdmw;
2807bffb703SJames Tabor     }
2817bffb703SJames Tabor     if (ppi2a->pServerName)
2827bffb703SJames Tabor     {
2837bffb703SJames Tabor         pwszServerName = AsciiToUnicode(&usBuffer, ppi2a->pServerName);
2847bffb703SJames Tabor         if (!(ppi2w->pPrinterName = pwszServerName)) goto Cleanup;
2857bffb703SJames Tabor     }
2867bffb703SJames Tabor     if (ppi2a->pPrinterName)
2877bffb703SJames Tabor     {
2887bffb703SJames Tabor         pwszPrinterName = AsciiToUnicode(&usBuffer, ppi2a->pPrinterName);
2897bffb703SJames Tabor         if (!(ppi2w->pPrinterName = pwszPrinterName)) goto Cleanup;
2907bffb703SJames Tabor     }
2917bffb703SJames Tabor 
2927bffb703SJames Tabor     ret = AddPrinterW(pwstrNameW, Level, (LPBYTE)ppi2w);
2937bffb703SJames Tabor 
2947bffb703SJames Tabor Cleanup:
2957bffb703SJames Tabor     if (pdmw) HeapFree(hProcessHeap, 0, pdmw);
2967bffb703SJames Tabor     if (pwszPrinterName) HeapFree(hProcessHeap, 0, pwszPrinterName);
2977bffb703SJames Tabor     if (pwszServerName) HeapFree(hProcessHeap, 0, pwszServerName);
2987bffb703SJames Tabor     if (pwszShareName) HeapFree(hProcessHeap, 0, pwszShareName);
2997bffb703SJames Tabor     if (pwszPortName) HeapFree(hProcessHeap, 0, pwszPortName);
3007bffb703SJames Tabor     if (pwszDriverName) HeapFree(hProcessHeap, 0, pwszDriverName);
3017bffb703SJames Tabor     if (pwszComment) HeapFree(hProcessHeap, 0, pwszComment);
3027bffb703SJames Tabor     if (pwszLocation) HeapFree(hProcessHeap, 0, pwszLocation);
3037bffb703SJames Tabor     if (pwszSepFile) HeapFree(hProcessHeap, 0, pwszSepFile);
3047bffb703SJames Tabor     if (pwszPrintProcessor) HeapFree(hProcessHeap, 0, pwszPrintProcessor);
3057bffb703SJames Tabor     if (pwszDatatype) HeapFree(hProcessHeap, 0, pwszDatatype);
3067bffb703SJames Tabor     if (pwszParameters) HeapFree(hProcessHeap, 0, pwszParameters);
3077bffb703SJames Tabor 
3087bffb703SJames Tabor     RtlFreeUnicodeString(&pNameW);
3097bffb703SJames Tabor     return ret;
3107bffb703SJames Tabor }
3117bffb703SJames Tabor 
312c2c66affSColin Finck HANDLE WINAPI
AddPrinterW(PWSTR pName,DWORD Level,PBYTE pPrinter)313c2c66affSColin Finck AddPrinterW(PWSTR pName, DWORD Level, PBYTE pPrinter)
314c2c66affSColin Finck {
3157bffb703SJames Tabor     DWORD dwErrorCode;
3167bffb703SJames Tabor     WINSPOOL_PRINTER_CONTAINER PrinterContainer;
3177bffb703SJames Tabor     WINSPOOL_DEVMODE_CONTAINER DevModeContainer;
3187bffb703SJames Tabor     WINSPOOL_SECURITY_CONTAINER SecurityContainer;
3197bffb703SJames Tabor     SECURITY_DESCRIPTOR *sd = NULL;
3207bffb703SJames Tabor     DWORD size;
3217bffb703SJames Tabor     HANDLE hPrinter = NULL, hHandle = NULL;
3227bffb703SJames Tabor     PSPOOLER_HANDLE pHandle = NULL;
3237bffb703SJames Tabor 
3241f6f08ecSColin Finck     TRACE("AddPrinterW(%S, %lu, %p)\n", pName, Level, pPrinter);
3257bffb703SJames Tabor 
3267bffb703SJames Tabor     DevModeContainer.cbBuf = 0;
3277bffb703SJames Tabor     DevModeContainer.pDevMode = NULL;
3287bffb703SJames Tabor 
3297bffb703SJames Tabor     SecurityContainer.cbBuf = 0;
3307bffb703SJames Tabor     SecurityContainer.pSecurity = NULL;
3317bffb703SJames Tabor 
3327bffb703SJames Tabor     if ( Level != 2 )
3337bffb703SJames Tabor     {
3347bffb703SJames Tabor         FIXME( "Unsupported level %d\n", Level );
3357bffb703SJames Tabor         SetLastError( ERROR_INVALID_LEVEL );
3367bffb703SJames Tabor         return hHandle;
3377bffb703SJames Tabor     }
3387bffb703SJames Tabor     else
3397bffb703SJames Tabor     {
3407bffb703SJames Tabor         PPRINTER_INFO_2W pi2w = (PPRINTER_INFO_2W)pPrinter;
3417bffb703SJames Tabor         if ( pi2w )
3427bffb703SJames Tabor         {
3437bffb703SJames Tabor             if ( pi2w->pDevMode )
3447bffb703SJames Tabor             {
3457bffb703SJames Tabor                 if ( IsValidDevmodeNoSizeW( pi2w->pDevMode ) )
3467bffb703SJames Tabor                 {
3477bffb703SJames Tabor                     DevModeContainer.cbBuf = pi2w->pDevMode->dmSize + pi2w->pDevMode->dmDriverExtra;
3487bffb703SJames Tabor                     DevModeContainer.pDevMode = (PBYTE)pi2w->pDevMode;
3497bffb703SJames Tabor                 }
3507bffb703SJames Tabor             }
3517bffb703SJames Tabor 
3527bffb703SJames Tabor             if ( pi2w->pSecurityDescriptor )
3537bffb703SJames Tabor             {
3547bffb703SJames Tabor                 sd = get_sd( pi2w->pSecurityDescriptor, &size );
3557bffb703SJames Tabor                 if ( sd )
3567bffb703SJames Tabor                 {
3577bffb703SJames Tabor                     SecurityContainer.cbBuf = size;
3587bffb703SJames Tabor                     SecurityContainer.pSecurity = (PBYTE)sd;
3597bffb703SJames Tabor                 }
3607bffb703SJames Tabor             }
3617bffb703SJames Tabor         }
3627bffb703SJames Tabor         else
3637bffb703SJames Tabor         {
3647bffb703SJames Tabor             SetLastError(ERROR_INVALID_PARAMETER);
3657bffb703SJames Tabor             return hHandle;
3667bffb703SJames Tabor         }
3677bffb703SJames Tabor     }
3687bffb703SJames Tabor 
3697bffb703SJames Tabor     PrinterContainer.PrinterInfo.pPrinterInfo1 = (WINSPOOL_PRINTER_INFO_1*)pPrinter;
3707bffb703SJames Tabor     PrinterContainer.Level = Level;
3717bffb703SJames Tabor 
3727bffb703SJames Tabor     // Do the RPC call
3737bffb703SJames Tabor     RpcTryExcept
3747bffb703SJames Tabor     {
3757bffb703SJames Tabor         dwErrorCode = _RpcAddPrinter( pName, &PrinterContainer, &DevModeContainer, &SecurityContainer, &hPrinter );
3767bffb703SJames Tabor     }
3777bffb703SJames Tabor     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
3787bffb703SJames Tabor     {
3797bffb703SJames Tabor         dwErrorCode = RpcExceptionCode();
3807bffb703SJames Tabor     }
3817bffb703SJames Tabor     RpcEndExcept;
3827bffb703SJames Tabor 
3837bffb703SJames Tabor     if (hPrinter)
3847bffb703SJames Tabor     {
3857bffb703SJames Tabor         // Create a new SPOOLER_HANDLE structure.
3867bffb703SJames Tabor         pHandle = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(SPOOLER_HANDLE));
3877bffb703SJames Tabor         if (!pHandle)
3887bffb703SJames Tabor         {
3897bffb703SJames Tabor             dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
3907bffb703SJames Tabor             ERR("HeapAlloc failed!\n");
3917bffb703SJames Tabor             _RpcDeletePrinter(hPrinter);
3927bffb703SJames Tabor             _RpcClosePrinter(hPrinter);
3937bffb703SJames Tabor             goto Cleanup;
3947bffb703SJames Tabor         }
3957bffb703SJames Tabor 
3967bffb703SJames Tabor         pHandle->Sig = SPOOLER_HANDLE_SIG;
3977bffb703SJames Tabor         pHandle->hPrinter = hPrinter;
3987bffb703SJames Tabor         pHandle->hSPLFile = INVALID_HANDLE_VALUE;
3997bffb703SJames Tabor         pHandle->hSpoolFileHandle = INVALID_HANDLE_VALUE;
4007bffb703SJames Tabor         hHandle = (HANDLE)pHandle;
4017bffb703SJames Tabor     }
4027bffb703SJames Tabor 
4037bffb703SJames Tabor Cleanup:
4047bffb703SJames Tabor     if ( sd ) HeapFree( GetProcessHeap(), 0, sd );
4057bffb703SJames Tabor 
4067bffb703SJames Tabor     SetLastError(dwErrorCode);
4077bffb703SJames Tabor     return hHandle;
408c2c66affSColin Finck }
409c2c66affSColin Finck 
410c2c66affSColin Finck BOOL WINAPI
ClosePrinter(HANDLE hPrinter)411c2c66affSColin Finck ClosePrinter(HANDLE hPrinter)
412c2c66affSColin Finck {
413c2c66affSColin Finck     DWORD dwErrorCode;
414c2c66affSColin Finck     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
415c2c66affSColin Finck 
4161f6f08ecSColin Finck     TRACE("ClosePrinter(%p)\n", hPrinter);
4171f6f08ecSColin Finck 
418c2c66affSColin Finck     // Sanity checks.
4197bffb703SJames Tabor     if ( IntProtectHandle( hPrinter, TRUE ) )
420c2c66affSColin Finck     {
421c2c66affSColin Finck         dwErrorCode = ERROR_INVALID_HANDLE;
422c2c66affSColin Finck         goto Cleanup;
423c2c66affSColin Finck     }
424c2c66affSColin Finck 
425c2c66affSColin Finck     // Do the RPC call.
426c2c66affSColin Finck     RpcTryExcept
427c2c66affSColin Finck     {
428c2c66affSColin Finck         dwErrorCode = _RpcClosePrinter(&pHandle->hPrinter);
429c2c66affSColin Finck     }
430c2c66affSColin Finck     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
431c2c66affSColin Finck     {
432c2c66affSColin Finck         dwErrorCode = RpcExceptionCode();
433c2c66affSColin Finck         ERR("_RpcClosePrinter failed with exception code %lu!\n", dwErrorCode);
434c2c66affSColin Finck     }
435c2c66affSColin Finck     RpcEndExcept;
436c2c66affSColin Finck 
437c2c66affSColin Finck     // Close any open file handle.
438c2c66affSColin Finck     if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
439c2c66affSColin Finck         CloseHandle(pHandle->hSPLFile);
440c2c66affSColin Finck 
4417bffb703SJames Tabor     pHandle->Sig = -1;
4427bffb703SJames Tabor 
443c2c66affSColin Finck     // Free the memory for the handle.
444c2c66affSColin Finck     HeapFree(hProcessHeap, 0, pHandle);
445c2c66affSColin Finck 
446c2c66affSColin Finck Cleanup:
447c2c66affSColin Finck     SetLastError(dwErrorCode);
448c2c66affSColin Finck     return (dwErrorCode == ERROR_SUCCESS);
449c2c66affSColin Finck }
450c2c66affSColin Finck 
45146b91659SColin Finck BOOL WINAPI
DeletePrinter(HANDLE hPrinter)45246b91659SColin Finck DeletePrinter(HANDLE hPrinter)
45346b91659SColin Finck {
4547bffb703SJames Tabor     DWORD dwErrorCode;
4557bffb703SJames Tabor     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
4567bffb703SJames Tabor 
45746b91659SColin Finck     TRACE("DeletePrinter(%p)\n", hPrinter);
4587bffb703SJames Tabor 
4597bffb703SJames Tabor     // Sanity checks.
4607bffb703SJames Tabor     if (!pHandle)
4617bffb703SJames Tabor     {
4627bffb703SJames Tabor         dwErrorCode = ERROR_INVALID_HANDLE;
4637bffb703SJames Tabor         goto Cleanup;
4647bffb703SJames Tabor     }
4657bffb703SJames Tabor 
4667bffb703SJames Tabor     // Do the RPC call.
4677bffb703SJames Tabor     RpcTryExcept
4687bffb703SJames Tabor     {
4697bffb703SJames Tabor         dwErrorCode = _RpcDeletePrinter(&pHandle->hPrinter);
4707bffb703SJames Tabor     }
4717bffb703SJames Tabor     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
4727bffb703SJames Tabor     {
4737bffb703SJames Tabor         dwErrorCode = RpcExceptionCode();
4747bffb703SJames Tabor         ERR("_RpcDeletePrinter failed with exception code %lu!\n", dwErrorCode);
4757bffb703SJames Tabor     }
4767bffb703SJames Tabor     RpcEndExcept;
4777bffb703SJames Tabor 
4787bffb703SJames Tabor Cleanup:
4797bffb703SJames Tabor     SetLastError(dwErrorCode);
4807bffb703SJames Tabor     return (dwErrorCode == ERROR_SUCCESS);
4817bffb703SJames Tabor }
4827bffb703SJames Tabor 
4837bffb703SJames Tabor //
4847bffb703SJames Tabor // Based on GDI32:printdrv.c:IntGetPrinterDriver.
4857bffb703SJames Tabor //
4867bffb703SJames Tabor HMODULE
4877bffb703SJames Tabor WINAPI
LoadPrinterDriver(HANDLE hspool)4887bffb703SJames Tabor LoadPrinterDriver( HANDLE hspool )
4897bffb703SJames Tabor {
4907bffb703SJames Tabor     INT iTries = 0;
4917bffb703SJames Tabor     DWORD Size = (sizeof(WCHAR) * MAX_PATH) * 2; // DRIVER_INFO_5W + plus strings.
4927bffb703SJames Tabor     PDRIVER_INFO_5W pdi = NULL;
4937bffb703SJames Tabor     HMODULE hLibrary = NULL;
4947bffb703SJames Tabor 
4957bffb703SJames Tabor     do
4967bffb703SJames Tabor     {
4977bffb703SJames Tabor         ++iTries;
4987bffb703SJames Tabor 
4997bffb703SJames Tabor         pdi = RtlAllocateHeap( GetProcessHeap(), 0, Size);
5007bffb703SJames Tabor 
5017bffb703SJames Tabor         if ( !pdi )
5027bffb703SJames Tabor             break;
5037bffb703SJames Tabor 
5047bffb703SJames Tabor         if ( GetPrinterDriverW(hspool, NULL, 5, (LPBYTE)pdi, Size, &Size) )
5057bffb703SJames Tabor         {
5067bffb703SJames Tabor             TRACE("Level 5 Size %d\n",Size);
5077bffb703SJames Tabor 
5087bffb703SJames Tabor             // Name and load configure library (for example, C:\DRIVERS\Pscrptui.dll). Not printui.dll!
5097bffb703SJames Tabor 
5107bffb703SJames Tabor             hLibrary = LoadLibrary(pdi->pConfigFile);
5117bffb703SJames Tabor 
51262c4b828SJames Tabor             FIXME("IGPD : Get Printer Driver Config File : %S\n",pdi->pConfigFile);
5137bffb703SJames Tabor 
5147bffb703SJames Tabor             RtlFreeHeap( GetProcessHeap(), 0, pdi);
5157bffb703SJames Tabor             return hLibrary;
5167bffb703SJames Tabor         }
5177bffb703SJames Tabor 
5187bffb703SJames Tabor         if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
5197bffb703SJames Tabor             ++iTries;
5207bffb703SJames Tabor 
5217bffb703SJames Tabor         RtlFreeHeap( GetProcessHeap(), 0, pdi);
5227bffb703SJames Tabor      }
5237bffb703SJames Tabor      while ( iTries < 2 );
5247bffb703SJames Tabor      ERR("No Printer Driver Error %d\n",GetLastError());
5257bffb703SJames Tabor      return NULL;
52646b91659SColin Finck }
52746b91659SColin Finck 
528c2c66affSColin Finck DWORD WINAPI
DeviceCapabilitiesA(LPCSTR pDevice,LPCSTR pPort,WORD fwCapability,LPSTR pOutput,const DEVMODEA * pDevMode)529c2c66affSColin Finck DeviceCapabilitiesA(LPCSTR pDevice, LPCSTR pPort, WORD fwCapability, LPSTR pOutput, const DEVMODEA* pDevMode)
530c2c66affSColin Finck {
5317bffb703SJames Tabor     PWSTR pwszDeviceName = NULL;
5327bffb703SJames Tabor     PDEVMODEW pdmwInput = NULL;
5337bffb703SJames Tabor     BOOL bReturnValue = GDI_ERROR;
5347bffb703SJames Tabor     DWORD cch;
5357bffb703SJames Tabor 
5367bffb703SJames Tabor     FIXME("DeviceCapabilitiesA(%s, %s, %hu, %p, %p)\n", pDevice, pPort, fwCapability, pOutput, pDevMode);
5377bffb703SJames Tabor 
5387bffb703SJames Tabor     if (pDevice)
5397bffb703SJames Tabor     {
5407bffb703SJames Tabor         // Convert pName to a Unicode string pwszDeviceName.
5417bffb703SJames Tabor         cch = strlen(pDevice);
5427bffb703SJames Tabor 
5437bffb703SJames Tabor         pwszDeviceName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
5447bffb703SJames Tabor         if (!pwszDeviceName)
5457bffb703SJames Tabor         {
5467bffb703SJames Tabor             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
5477bffb703SJames Tabor             ERR("HeapAlloc failed!\n");
5487bffb703SJames Tabor             goto Cleanup;
5497bffb703SJames Tabor         }
5507bffb703SJames Tabor 
5517bffb703SJames Tabor         MultiByteToWideChar(CP_ACP, 0, pDevice, -1, pwszDeviceName, cch + 1);
5527bffb703SJames Tabor     }
5537bffb703SJames Tabor 
5547bffb703SJames Tabor     if (pDevMode)
5557bffb703SJames Tabor     {
5567bffb703SJames Tabor         RosConvertAnsiDevModeToUnicodeDevmode((PDEVMODEA)pDevMode, &pdmwInput);
5577bffb703SJames Tabor     }
5587bffb703SJames Tabor 
5597bffb703SJames Tabor     // pPort is ignored so no need to pass it.
5607bffb703SJames Tabor     bReturnValue = DeviceCapabilitiesW( pwszDeviceName, NULL, fwCapability, (LPWSTR)pOutput, (const DEVMODEW*) pdmwInput );
5617bffb703SJames Tabor 
5627bffb703SJames Tabor Cleanup:
5637bffb703SJames Tabor     if(pwszDeviceName)
5647bffb703SJames Tabor         HeapFree(hProcessHeap, 0, pwszDeviceName);
5657bffb703SJames Tabor 
5667bffb703SJames Tabor     if (pdmwInput)
5677bffb703SJames Tabor         HeapFree(hProcessHeap, 0, pdmwInput);
5687bffb703SJames Tabor 
5697bffb703SJames Tabor     return bReturnValue;
570c2c66affSColin Finck }
571c2c66affSColin Finck 
572c2c66affSColin Finck DWORD WINAPI
DeviceCapabilitiesW(LPCWSTR pDevice,LPCWSTR pPort,WORD fwCapability,LPWSTR pOutput,const DEVMODEW * pDevMode)573c2c66affSColin Finck DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort, WORD fwCapability, LPWSTR pOutput, const DEVMODEW* pDevMode)
574c2c66affSColin Finck {
5757bffb703SJames Tabor     HANDLE hPrinter;
5767bffb703SJames Tabor     HMODULE hLibrary;
5777bffb703SJames Tabor     DWORD iDevCap = GDI_ERROR;
5787bffb703SJames Tabor 
5797bffb703SJames Tabor     FIXME("DeviceCapabilitiesW(%S, %S, %hu, %p, %p)\n", pDevice, pPort, fwCapability, pOutput, pDevMode);
5807bffb703SJames Tabor 
5817bffb703SJames Tabor     if ( pDevMode )
5827bffb703SJames Tabor     {
5837bffb703SJames Tabor         if (!IsValidDevmodeNoSizeW( (PDEVMODEW)pDevMode ) )
5847bffb703SJames Tabor         {
5853ca21762SJames Tabor             ERR("DeviceCapabilitiesW : Devode Invalid\n");
5867bffb703SJames Tabor             return -1;
5877bffb703SJames Tabor         }
5887bffb703SJames Tabor     }
5897bffb703SJames Tabor 
5907bffb703SJames Tabor     if ( OpenPrinterW( (LPWSTR)pDevice, &hPrinter, NULL ) )
5917bffb703SJames Tabor     {
5927bffb703SJames Tabor         hLibrary = LoadPrinterDriver( hPrinter );
5937bffb703SJames Tabor 
5947bffb703SJames Tabor         if ( hLibrary )
5957bffb703SJames Tabor         {
5967bffb703SJames Tabor             fpDeviceCapabilities = (PVOID)GetProcAddress( hLibrary, "DrvDeviceCapabilities" );
5977bffb703SJames Tabor 
5987bffb703SJames Tabor             if ( fpDeviceCapabilities )
5997bffb703SJames Tabor             {
6007bffb703SJames Tabor                 iDevCap = fpDeviceCapabilities( hPrinter, (PWSTR)pDevice, fwCapability, pOutput, (PDEVMODE)pDevMode );
6017bffb703SJames Tabor             }
6027bffb703SJames Tabor 
6037bffb703SJames Tabor             FreeLibrary(hLibrary);
6047bffb703SJames Tabor         }
6057bffb703SJames Tabor 
6067bffb703SJames Tabor         ClosePrinter( hPrinter );
6077bffb703SJames Tabor     }
6087bffb703SJames Tabor 
6097bffb703SJames Tabor     return iDevCap;
6107bffb703SJames Tabor }
6117bffb703SJames Tabor 
6127bffb703SJames Tabor BOOL
6137bffb703SJames Tabor WINAPI
DevQueryPrint(HANDLE hPrinter,LPDEVMODEW pDevMode,DWORD * pResID)6147bffb703SJames Tabor DevQueryPrint( HANDLE hPrinter, LPDEVMODEW pDevMode, DWORD *pResID)
6157bffb703SJames Tabor {
6167bffb703SJames Tabor     HMODULE hLibrary;
6177bffb703SJames Tabor     BOOL Ret = FALSE;
6187bffb703SJames Tabor 
6197bffb703SJames Tabor     hLibrary = LoadPrinterDriver( hPrinter );
6207bffb703SJames Tabor 
6217bffb703SJames Tabor     if ( hLibrary )
6227bffb703SJames Tabor     {
6237bffb703SJames Tabor         fpDevQueryPrint = (PVOID)GetProcAddress( hLibrary, "DevQueryPrint" );
6247bffb703SJames Tabor 
6257bffb703SJames Tabor         if ( fpDevQueryPrint )
6267bffb703SJames Tabor         {
6277bffb703SJames Tabor             Ret = fpDevQueryPrint( hPrinter, pDevMode, pResID );
6287bffb703SJames Tabor         }
6297bffb703SJames Tabor 
6307bffb703SJames Tabor         FreeLibrary(hLibrary);
6317bffb703SJames Tabor     }
6327bffb703SJames Tabor     return Ret;
6337bffb703SJames Tabor }
6347bffb703SJames Tabor 
6357bffb703SJames Tabor BOOL WINAPI
DevQueryPrintEx(PDEVQUERYPRINT_INFO pDQPInfo)6367bffb703SJames Tabor DevQueryPrintEx( PDEVQUERYPRINT_INFO pDQPInfo )
6377bffb703SJames Tabor {
6387bffb703SJames Tabor     HMODULE hLibrary;
6397bffb703SJames Tabor     BOOL Ret = FALSE;
6407bffb703SJames Tabor 
6417bffb703SJames Tabor     hLibrary = LoadPrinterDriver( pDQPInfo->hPrinter );
6427bffb703SJames Tabor 
6437bffb703SJames Tabor     if ( hLibrary )
6447bffb703SJames Tabor     {
6457bffb703SJames Tabor         fpDevQueryPrintEx = (PVOID)GetProcAddress( hLibrary, "DevQueryPrintEx" );
6467bffb703SJames Tabor 
6477bffb703SJames Tabor         if ( fpDevQueryPrintEx )
6487bffb703SJames Tabor         {
6497bffb703SJames Tabor             Ret = fpDevQueryPrintEx( pDQPInfo );
6507bffb703SJames Tabor         }
6517bffb703SJames Tabor 
6527bffb703SJames Tabor         FreeLibrary(hLibrary);
6537bffb703SJames Tabor     }
6547bffb703SJames Tabor     return Ret;
655c2c66affSColin Finck }
656c2c66affSColin Finck 
657adffa8eaSJames Tabor INT WINAPI
DocumentEvent(HANDLE hPrinter,HDC hdc,int iEsc,ULONG cbIn,PVOID pvIn,ULONG cbOut,PVOID pvOut)658adffa8eaSJames Tabor DocumentEvent( HANDLE hPrinter, HDC hdc, int iEsc, ULONG cbIn, PVOID pvIn, ULONG cbOut, PVOID pvOut)
659adffa8eaSJames Tabor {
66062c4b828SJames Tabor     FIXME("DocumentEvent(%p, %p, %lu, %lu, %p, %lu, %p)\n", hPrinter, hdc, iEsc, cbIn, pvIn, cbOut, pvOut);
661adffa8eaSJames Tabor     UNIMPLEMENTED;
662adffa8eaSJames Tabor     return DOCUMENTEVENT_UNSUPPORTED;
663adffa8eaSJames Tabor }
664adffa8eaSJames Tabor 
665c2c66affSColin Finck LONG WINAPI
DocumentPropertiesA(HWND hWnd,HANDLE hPrinter,LPSTR pDeviceName,PDEVMODEA pDevModeOutput,PDEVMODEA pDevModeInput,DWORD fMode)666c2c66affSColin Finck DocumentPropertiesA(HWND hWnd, HANDLE hPrinter, LPSTR pDeviceName, PDEVMODEA pDevModeOutput, PDEVMODEA pDevModeInput, DWORD fMode)
667c2c66affSColin Finck {
6683077c0e4SDoug Lyons     PWSTR pwszDeviceName = NULL;
6693077c0e4SDoug Lyons     PDEVMODEW pdmwInput = NULL;
6703077c0e4SDoug Lyons     PDEVMODEW pdmwOutput = NULL;
671dde92f8fSJoachim Henze     LONG lReturnValue = -1;
6723077c0e4SDoug Lyons     DWORD cch;
6733077c0e4SDoug Lyons 
6747bffb703SJames Tabor     FIXME("DocumentPropertiesA(%p, %p, %s, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode);
6753077c0e4SDoug Lyons 
6763077c0e4SDoug Lyons     if (pDeviceName)
6773077c0e4SDoug Lyons     {
6783077c0e4SDoug Lyons         // Convert pName to a Unicode string pwszDeviceName.
6793077c0e4SDoug Lyons         cch = strlen(pDeviceName);
6803077c0e4SDoug Lyons 
6813077c0e4SDoug Lyons         pwszDeviceName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
6823077c0e4SDoug Lyons         if (!pwszDeviceName)
6833077c0e4SDoug Lyons         {
6843077c0e4SDoug Lyons             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
6853077c0e4SDoug Lyons             ERR("HeapAlloc failed!\n");
6863077c0e4SDoug Lyons             goto Cleanup;
6873077c0e4SDoug Lyons         }
6883077c0e4SDoug Lyons 
6893077c0e4SDoug Lyons         MultiByteToWideChar(CP_ACP, 0, pDeviceName, -1, pwszDeviceName, cch + 1);
6903077c0e4SDoug Lyons     }
6913077c0e4SDoug Lyons 
6923077c0e4SDoug Lyons     if (pDevModeInput)
6933077c0e4SDoug Lyons     {
6943077c0e4SDoug Lyons         // Create working buffer for input to DocumentPropertiesW.
6957bffb703SJames Tabor         RosConvertAnsiDevModeToUnicodeDevmode(pDevModeInput, &pdmwInput);
6963077c0e4SDoug Lyons     }
6973077c0e4SDoug Lyons 
6983077c0e4SDoug Lyons     if (pDevModeOutput)
6993077c0e4SDoug Lyons     {
7003077c0e4SDoug Lyons         // Create working buffer for output from DocumentPropertiesW.
7017bffb703SJames Tabor 
7027bffb703SJames Tabor         // Do it RIGHT! Get the F...ing Size!
7037bffb703SJames Tabor         LONG Size = DocumentPropertiesW( hWnd, hPrinter, pwszDeviceName, NULL, NULL, 0 );
7047bffb703SJames Tabor 
7057bffb703SJames Tabor         if ( Size < 0 )
7067bffb703SJames Tabor         {
7077bffb703SJames Tabor             goto Cleanup;
7087bffb703SJames Tabor         }
7097bffb703SJames Tabor 
7107bffb703SJames Tabor         pdmwOutput = HeapAlloc(hProcessHeap, 0, Size);
7113077c0e4SDoug Lyons         if (!pdmwOutput)
7123077c0e4SDoug Lyons         {
7133077c0e4SDoug Lyons             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
7143077c0e4SDoug Lyons             ERR("HeapAlloc failed!\n");
7153077c0e4SDoug Lyons             goto Cleanup;
7163077c0e4SDoug Lyons         }
7173077c0e4SDoug Lyons     }
7183077c0e4SDoug Lyons 
719dde92f8fSJoachim Henze     lReturnValue = DocumentPropertiesW(hWnd, hPrinter, pwszDeviceName, pdmwOutput, pdmwInput, fMode);
720dde92f8fSJoachim Henze     FIXME("lReturnValue from DocumentPropertiesW is '%ld'.\n", lReturnValue);
7213077c0e4SDoug Lyons 
722dde92f8fSJoachim Henze     if (lReturnValue < 0)
7233077c0e4SDoug Lyons     {
7247bffb703SJames Tabor         FIXME("DocumentPropertiesW failed!\n");
7253077c0e4SDoug Lyons         goto Cleanup;
7263077c0e4SDoug Lyons     }
7273077c0e4SDoug Lyons 
7283077c0e4SDoug Lyons     if (pdmwOutput)
7293077c0e4SDoug Lyons     {
7303077c0e4SDoug Lyons         RosConvertUnicodeDevModeToAnsiDevmode(pdmwOutput, pDevModeOutput);
7313077c0e4SDoug Lyons     }
7323077c0e4SDoug Lyons 
7333077c0e4SDoug Lyons Cleanup:
7343077c0e4SDoug Lyons     if(pwszDeviceName)
7353077c0e4SDoug Lyons         HeapFree(hProcessHeap, 0, pwszDeviceName);
7363077c0e4SDoug Lyons 
7373077c0e4SDoug Lyons     if (pdmwInput)
7383077c0e4SDoug Lyons         HeapFree(hProcessHeap, 0, pdmwInput);
7393077c0e4SDoug Lyons 
7403077c0e4SDoug Lyons     if (pdmwOutput)
7413077c0e4SDoug Lyons         HeapFree(hProcessHeap, 0, pdmwOutput);
7423077c0e4SDoug Lyons 
743dde92f8fSJoachim Henze     return lReturnValue;
744c2c66affSColin Finck }
745c2c66affSColin Finck 
get_devmodeW(HANDLE hprn)7467bffb703SJames Tabor PRINTER_INFO_9W * get_devmodeW(HANDLE hprn)
7478ad75174SMark Jansen {
7488ad75174SMark Jansen     PRINTER_INFO_9W *pi9 = NULL;
7498ad75174SMark Jansen     DWORD needed = 0;
7508ad75174SMark Jansen     BOOL res;
7518ad75174SMark Jansen 
7528ad75174SMark Jansen     res = GetPrinterW(hprn, 9, NULL, 0, &needed);
7538ad75174SMark Jansen     if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
7548ad75174SMark Jansen     {
7558ad75174SMark Jansen         pi9 = HeapAlloc(hProcessHeap, 0, needed);
7560e68e27fSTimo Kreuzer         if (!pi9)
7570e68e27fSTimo Kreuzer         {
7580e68e27fSTimo Kreuzer             ERR("Failed to allocate PRINTER_INFO_9W of %u bytes\n", needed);
7590e68e27fSTimo Kreuzer             return NULL;
7600e68e27fSTimo Kreuzer         }
7618ad75174SMark Jansen         res = GetPrinterW(hprn, 9, (LPBYTE)pi9, needed, &needed);
7628ad75174SMark Jansen     }
7638ad75174SMark Jansen 
7648ad75174SMark Jansen     if (res)
7658ad75174SMark Jansen         return pi9;
7668ad75174SMark Jansen 
7678ad75174SMark Jansen     ERR("GetPrinterW failed with %u\n", GetLastError());
7688ad75174SMark Jansen     HeapFree(hProcessHeap, 0, pi9);
7698ad75174SMark Jansen     return NULL;
7708ad75174SMark Jansen }
7718ad75174SMark Jansen 
7727bffb703SJames Tabor BOOL
7737bffb703SJames Tabor FASTCALL
CreateUIUserData(ULONG_PTR * puserdata,HANDLE hPrinter)7747bffb703SJames Tabor CreateUIUserData( ULONG_PTR *puserdata, HANDLE hPrinter )
7757bffb703SJames Tabor {
7767bffb703SJames Tabor     PCOMPUI_USERDATA pcui_ud = DllAllocSplMem( sizeof(COMPUI_USERDATA) );
7777bffb703SJames Tabor 
7787bffb703SJames Tabor     *puserdata = (ULONG_PTR)pcui_ud;
7797bffb703SJames Tabor     FIXME("CreateUIUserData\n");
7807bffb703SJames Tabor     if ( pcui_ud )
7817bffb703SJames Tabor     {
7827bffb703SJames Tabor         pcui_ud->hModule = LoadPrinterDriver( hPrinter );
7837bffb703SJames Tabor 
7847bffb703SJames Tabor         if ( !pcui_ud->hModule )
7857bffb703SJames Tabor         {
7867bffb703SJames Tabor             DllFreeSplMem( pcui_ud );
7877bffb703SJames Tabor             *puserdata = 0;
7887bffb703SJames Tabor         }
7897bffb703SJames Tabor     }
7907bffb703SJames Tabor     return *puserdata != 0;
7917bffb703SJames Tabor }
7927bffb703SJames Tabor 
7937bffb703SJames Tabor VOID
7947bffb703SJames Tabor FASTCALL
DestroyUIUserData(ULONG_PTR * puserdata)7957bffb703SJames Tabor DestroyUIUserData( ULONG_PTR *puserdata )
7967bffb703SJames Tabor {
7977bffb703SJames Tabor     PCOMPUI_USERDATA pcui_ud = (PCOMPUI_USERDATA)*puserdata;
7987bffb703SJames Tabor     FIXME("DestroyUIUserData\n");
7997bffb703SJames Tabor     if ( pcui_ud )
8007bffb703SJames Tabor     {
8017bffb703SJames Tabor         if ( pcui_ud->hModule )
8027bffb703SJames Tabor         {
8037bffb703SJames Tabor             FreeLibrary( pcui_ud->hModule );
8047bffb703SJames Tabor             pcui_ud->hModule = NULL;
8057bffb703SJames Tabor         }
8067bffb703SJames Tabor 
8077bffb703SJames Tabor         if ( pcui_ud->pszPrinterName )
8087bffb703SJames Tabor         {
8097bffb703SJames Tabor             DllFreeSplMem( pcui_ud->pszPrinterName );
8107bffb703SJames Tabor             pcui_ud->pszPrinterName = NULL;
8117bffb703SJames Tabor         }
8127bffb703SJames Tabor 
8137bffb703SJames Tabor         DllFreeSplMem( pcui_ud );
8147bffb703SJames Tabor         *puserdata = 0;
8157bffb703SJames Tabor     }
8167bffb703SJames Tabor }
8177bffb703SJames Tabor 
8187bffb703SJames Tabor BOOL
8197bffb703SJames Tabor FASTCALL
IntFixUpDevModeNames(PDOCUMENTPROPERTYHEADER pdphdr)8207bffb703SJames Tabor IntFixUpDevModeNames( PDOCUMENTPROPERTYHEADER pdphdr )
8217bffb703SJames Tabor {
8227bffb703SJames Tabor     PRINTER_INFO_2W *pi2 = NULL;
8237bffb703SJames Tabor     DWORD needed = 0;
8247bffb703SJames Tabor     BOOL res;
8257bffb703SJames Tabor 
8267bffb703SJames Tabor     if (!(pdphdr->fMode & DM_OUT_BUFFER) ||
8277bffb703SJames Tabor          pdphdr->fMode & DM_NOPERMISSION || // Do not allow the user to modify properties on the displayed property sheet pages.
8287bffb703SJames Tabor         !pdphdr->pdmOut )
8297bffb703SJames Tabor     {
8307bffb703SJames Tabor         return FALSE;
8317bffb703SJames Tabor     }
8327bffb703SJames Tabor 
8337bffb703SJames Tabor     res = GetPrinterW( pdphdr->hPrinter, 2, NULL, 0, &needed);
8347bffb703SJames Tabor     if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
8357bffb703SJames Tabor     {
8367bffb703SJames Tabor         pi2 = HeapAlloc(hProcessHeap, 0, needed);
8370e68e27fSTimo Kreuzer         if (!pi2)
8380e68e27fSTimo Kreuzer         {
8390e68e27fSTimo Kreuzer             ERR("Failed to allocate PRINTER_INFO_2W of %u bytes\n", needed);
8400e68e27fSTimo Kreuzer             return FALSE;
8410e68e27fSTimo Kreuzer         }
8427bffb703SJames Tabor         res = GetPrinterW( pdphdr->hPrinter, 2, (LPBYTE)pi2, needed, &needed);
8437bffb703SJames Tabor     }
8447bffb703SJames Tabor 
8457bffb703SJames Tabor     if (res)
8467bffb703SJames Tabor     {
84702df49ebSTimo Kreuzer         /* Check if the provided buffer is large enough */
84802df49ebSTimo Kreuzer         DWORD cbDevMode = pi2->pDevMode->dmSize + pi2->pDevMode->dmDriverExtra;
84902df49ebSTimo Kreuzer         if (pdphdr->cbOut < cbDevMode)
85002df49ebSTimo Kreuzer         {
85102df49ebSTimo Kreuzer             ERR("cbOut (%lu) < cbDevMode(%u)\n", pdphdr->cbOut, cbDevMode);
85202df49ebSTimo Kreuzer             res = FALSE;
85302df49ebSTimo Kreuzer             goto Exit;
85402df49ebSTimo Kreuzer         }
85502df49ebSTimo Kreuzer 
85602df49ebSTimo Kreuzer         /* Copy the devmode */
85702df49ebSTimo Kreuzer         RtlCopyMemory(pdphdr->pdmOut, pi2->pDevMode, cbDevMode);
85802df49ebSTimo Kreuzer 
85902df49ebSTimo Kreuzer         TRACE("IFUDMN : Get Printer Name %S\n", pi2->pPrinterName);
8607bffb703SJames Tabor         StringCchCopyW( pdphdr->pdmOut->dmDeviceName, CCHDEVICENAME-1, pi2->pPrinterName );
8617bffb703SJames Tabor         pdphdr->pdmOut->dmDeviceName[CCHDEVICENAME-1] = 0;
8627bffb703SJames Tabor     }
8637bffb703SJames Tabor     else
8647bffb703SJames Tabor     {
8657bffb703SJames Tabor         ERR("IFUDMN : GetPrinterW failed with %u\n", GetLastError());
8667bffb703SJames Tabor     }
86702df49ebSTimo Kreuzer 
86802df49ebSTimo Kreuzer Exit:
8697bffb703SJames Tabor     HeapFree(hProcessHeap, 0, pi2);
8707bffb703SJames Tabor     return res;
8717bffb703SJames Tabor }
8727bffb703SJames Tabor 
8737bffb703SJames Tabor LONG
8747bffb703SJames Tabor WINAPI
CreatePrinterFriendlyName(PCOMPUI_USERDATA pcui_ud,LPWSTR pszPrinterName)8757bffb703SJames Tabor CreatePrinterFriendlyName( PCOMPUI_USERDATA pcui_ud, LPWSTR pszPrinterName )
8767bffb703SJames Tabor {
8777bffb703SJames Tabor     LONG Result = 0;
8787bffb703SJames Tabor     DWORD Size = 0;
8797bffb703SJames Tabor     HMODULE hLibrary = NULL;
8807bffb703SJames Tabor 
8817bffb703SJames Tabor     hLibrary = LoadLibraryA( "printui.dll" );
8827bffb703SJames Tabor 
8837bffb703SJames Tabor     if ( hLibrary )
8847bffb703SJames Tabor     {
8857bffb703SJames Tabor         fpConstructPrinterFriendlyName = (PVOID)GetProcAddress( hLibrary, "ConstructPrinterFriendlyName" );
8867bffb703SJames Tabor 
8877bffb703SJames Tabor         if ( fpConstructPrinterFriendlyName )
8887bffb703SJames Tabor         {
8897bffb703SJames Tabor              if ( !fpConstructPrinterFriendlyName( pszPrinterName, NULL, &Size ) )
8907bffb703SJames Tabor              {
8917bffb703SJames Tabor                  if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
8927bffb703SJames Tabor                  {
8937bffb703SJames Tabor                      PWSTR pwstr = DllAllocSplMem( (Size + 1) * sizeof(WCHAR) );
8947bffb703SJames Tabor 
8957bffb703SJames Tabor                      pcui_ud->pszPrinterName = pwstr;
8967bffb703SJames Tabor 
8977bffb703SJames Tabor                      if ( pwstr )
8987bffb703SJames Tabor                          Result = fpConstructPrinterFriendlyName( pszPrinterName, pwstr, &Size );
8997bffb703SJames Tabor                  }
9007bffb703SJames Tabor              }
9017bffb703SJames Tabor         }
9027bffb703SJames Tabor         FreeLibrary( hLibrary );
9037bffb703SJames Tabor     }
9047bffb703SJames Tabor 
9057bffb703SJames Tabor     if ( !Result )
9067bffb703SJames Tabor     {
9077bffb703SJames Tabor         DllFreeSplMem( pcui_ud->pszPrinterName );
9087bffb703SJames Tabor         pcui_ud->pszPrinterName = AllocSplStr( pszPrinterName );
9097bffb703SJames Tabor     }
9107bffb703SJames Tabor 
9117bffb703SJames Tabor     return Result;
9127bffb703SJames Tabor }
9137bffb703SJames Tabor 
9147bffb703SJames Tabor //
9157bffb703SJames Tabor // Tested with XP CompstUI as a callback and works. Fails perfectly.
9167bffb703SJames Tabor //
9177bffb703SJames Tabor LONG
9187bffb703SJames Tabor WINAPI
DocumentPropertySheets(PPROPSHEETUI_INFO pCPSUIInfo,LPARAM lparam)9197bffb703SJames Tabor DocumentPropertySheets( PPROPSHEETUI_INFO pCPSUIInfo, LPARAM lparam )
9207bffb703SJames Tabor {
9217bffb703SJames Tabor     LONG Result = -1;
9227bffb703SJames Tabor     PDOCUMENTPROPERTYHEADER pdphdr;
9237bffb703SJames Tabor 
9247bffb703SJames Tabor     FIXME("DocumentPropertySheets(%p, 0x%lx)\n", pCPSUIInfo, lparam);
9257bffb703SJames Tabor 
9267bffb703SJames Tabor     // If pPSUIInfo is NULL, and if either lParam -> fMode is zero or lParam -> pdmOut is NULL,
9277bffb703SJames Tabor     // this function should return the size, in bytes, of the printer's DEVMODEW structure.
9287bffb703SJames Tabor     if ( !pCPSUIInfo && lparam )
9297bffb703SJames Tabor     {
9307bffb703SJames Tabor         pdphdr = (PDOCUMENTPROPERTYHEADER)lparam;
9317bffb703SJames Tabor 
9327bffb703SJames Tabor         if ( pdphdr->cbSize >= sizeof(PDOCUMENTPROPERTYHEADER) &&
9337bffb703SJames Tabor             !(pdphdr->fMode & DM_PROMPT) )
9347bffb703SJames Tabor         {
9357bffb703SJames Tabor             HMODULE hLibrary = LoadPrinterDriver( pdphdr->hPrinter );
9367bffb703SJames Tabor 
9377bffb703SJames Tabor             if ( hLibrary )
9387bffb703SJames Tabor             {
9397bffb703SJames Tabor                 fpDocumentPropertySheets = (PVOID)GetProcAddress( hLibrary, "DrvDocumentPropertySheets" );
9407bffb703SJames Tabor 
9417bffb703SJames Tabor                 if ( fpDocumentPropertySheets )
9427bffb703SJames Tabor                 {
9433ca21762SJames Tabor                     FIXME("DPS : fpDocumentPropertySheets(%p, 0x%lx) pdmOut %p\n", pCPSUIInfo, lparam, pdphdr->pdmOut);
9447bffb703SJames Tabor                     Result = fpDocumentPropertySheets( pCPSUIInfo, lparam );
9453ca21762SJames Tabor                     FIXME("DPS : fpDocumentPropertySheets result %d cbOut %d\n",Result, pdphdr->cbOut);
9467bffb703SJames Tabor                 }
9477bffb703SJames Tabor                 else
9487bffb703SJames Tabor                 {
9497bffb703SJames Tabor                     //
9507bffb703SJames Tabor                     // ReactOS backup!!! Currently no supporting UI driver.
9517bffb703SJames Tabor                     //
9527bffb703SJames Tabor                     PRINTER_INFO_9W * pi9 = get_devmodeW( pdphdr->hPrinter );
9537bffb703SJames Tabor                     if ( pi9 )
9547bffb703SJames Tabor                     {
9557bffb703SJames Tabor                         Result = pi9->pDevMode->dmSize + pi9->pDevMode->dmDriverExtra;
9567bffb703SJames Tabor                         FIXME("IDPS : Using ReactOS backup!!! DevMode Size %d\n",Result);
9577bffb703SJames Tabor                         HeapFree(hProcessHeap, 0, pi9);
9587bffb703SJames Tabor                     }
9597bffb703SJames Tabor                 }
9607bffb703SJames Tabor 
9617bffb703SJames Tabor                 FreeLibrary(hLibrary);
9627bffb703SJames Tabor 
9637bffb703SJames Tabor                 if ( Result > 0 )
9647bffb703SJames Tabor                 {
9657bffb703SJames Tabor                     IntFixUpDevModeNames( pdphdr );
9667bffb703SJames Tabor                 }
9677bffb703SJames Tabor 
9687bffb703SJames Tabor                 return Result;
9697bffb703SJames Tabor             }
9707bffb703SJames Tabor             else
9717bffb703SJames Tabor             {
9727bffb703SJames Tabor                 SetLastError(ERROR_INVALID_HANDLE);
9737bffb703SJames Tabor             }
9747bffb703SJames Tabor         }
9757bffb703SJames Tabor         else
9767bffb703SJames Tabor         {
9777bffb703SJames Tabor             SetLastError(ERROR_INVALID_PARAMETER);
9787bffb703SJames Tabor         }
9797bffb703SJames Tabor         return Result;
9807bffb703SJames Tabor     }
9817bffb703SJames Tabor 
9827bffb703SJames Tabor     Result = 0;
9837bffb703SJames Tabor 
9847bffb703SJames Tabor     if ( pCPSUIInfo )
9857bffb703SJames Tabor     {
9867bffb703SJames Tabor         PSETRESULT_INFO psri;
9877bffb703SJames Tabor         PPROPSHEETUI_INFO_HEADER ppsuiihdr;
9887bffb703SJames Tabor         PCOMPUI_USERDATA pcui_ud;
9897bffb703SJames Tabor         pdphdr = (PDOCUMENTPROPERTYHEADER)pCPSUIInfo->lParamInit;
9907bffb703SJames Tabor 
9917bffb703SJames Tabor         if ( pdphdr->cbSize < sizeof(PDOCUMENTPROPERTYHEADER) )
9927bffb703SJames Tabor         {
9937bffb703SJames Tabor             SetLastError(ERROR_INVALID_PARAMETER);
9947bffb703SJames Tabor             return Result;
9957bffb703SJames Tabor         }
9967bffb703SJames Tabor 
9977bffb703SJames Tabor         switch ( pCPSUIInfo->Reason )
9987bffb703SJames Tabor         {
9997bffb703SJames Tabor             case PROPSHEETUI_REASON_INIT:
10007bffb703SJames Tabor             {
10017bffb703SJames Tabor                 FIXME("DocPS : PROPSHEETUI_REASON_INIT\n");
10027bffb703SJames Tabor                 if ( CreateUIUserData( &pCPSUIInfo->UserData, pdphdr->hPrinter ) )
10037bffb703SJames Tabor                 {
10047bffb703SJames Tabor                     pcui_ud = (PCOMPUI_USERDATA)pCPSUIInfo->UserData;
10057bffb703SJames Tabor 
10067bffb703SJames Tabor                     fpDocumentPropertySheets = (PVOID)GetProcAddress( pcui_ud->hModule, "DrvDocumentPropertySheets" );
10077bffb703SJames Tabor 
10087bffb703SJames Tabor                     if ( fpDocumentPropertySheets )
10097bffb703SJames Tabor                     {
10107bffb703SJames Tabor                         pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet,
10117bffb703SJames Tabor                                                      CPSFUNC_SET_FUSION_CONTEXT,
10127bffb703SJames Tabor                                                      -3,  // What type of handle is this?
10137bffb703SJames Tabor                                                      0 ); // Not used, must be zero.
10147bffb703SJames Tabor 
10157bffb703SJames Tabor                         Result = pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet,
10167bffb703SJames Tabor                                                               CPSFUNC_ADD_PFNPROPSHEETUIW,
10177bffb703SJames Tabor                                                              (LPARAM)fpDocumentPropertySheets,
10187bffb703SJames Tabor                                                               pCPSUIInfo->lParamInit );
10197bffb703SJames Tabor                         break;
10207bffb703SJames Tabor                     }
10217bffb703SJames Tabor                     FIXME("DocPS : PROPSHEETUI_REASON_INIT Fail\n");
10227bffb703SJames Tabor                     DestroyUIUserData( &pCPSUIInfo->UserData );
10237bffb703SJames Tabor                 }
10247bffb703SJames Tabor             }
10257bffb703SJames Tabor                 break;
10267bffb703SJames Tabor 
10277bffb703SJames Tabor             case PROPSHEETUI_REASON_GET_INFO_HEADER:
10287bffb703SJames Tabor                 FIXME("DocPS : PROPSHEETUI_REASON_GET_INFO_HEADER\n");
10297bffb703SJames Tabor 
10307bffb703SJames Tabor                 ppsuiihdr = (PPROPSHEETUI_INFO_HEADER)lparam;
10317bffb703SJames Tabor 
10327bffb703SJames Tabor                 pcui_ud = (PCOMPUI_USERDATA)pCPSUIInfo->UserData;
10337bffb703SJames Tabor 
10347bffb703SJames Tabor                 CreatePrinterFriendlyName( pcui_ud, pdphdr->pszPrinterName );
10357bffb703SJames Tabor 
10367bffb703SJames Tabor                 ppsuiihdr->Flags  = PSUIHDRF_NOAPPLYNOW|PSUIHDRF_PROPTITLE;
10377bffb703SJames Tabor                 ppsuiihdr->pTitle = pcui_ud->pszPrinterName;
10387bffb703SJames Tabor                 ppsuiihdr->hInst  = hinstWinSpool;
10397bffb703SJames Tabor                 ppsuiihdr->IconID = IDI_CPSUI_DOCUMENT;
10407bffb703SJames Tabor 
10417bffb703SJames Tabor                 Result = CPSUI_OK;
10427bffb703SJames Tabor                 break;
10437bffb703SJames Tabor 
10447bffb703SJames Tabor             case PROPSHEETUI_REASON_DESTROY:
10457bffb703SJames Tabor                 FIXME("DocPS : PROPSHEETUI_REASON_DESTROY\n");
10467bffb703SJames Tabor                 DestroyUIUserData( &pCPSUIInfo->UserData );
10477bffb703SJames Tabor                 Result = CPSUI_OK;
10487bffb703SJames Tabor                 break;
10497bffb703SJames Tabor 
10507bffb703SJames Tabor             case PROPSHEETUI_REASON_SET_RESULT:
10517bffb703SJames Tabor                 FIXME("DocPS : PROPSHEETUI_REASON_SET_RESULT\n");
10527bffb703SJames Tabor 
10537bffb703SJames Tabor                 psri = (PSETRESULT_INFO)lparam;
10547bffb703SJames Tabor 
10557bffb703SJames Tabor                 pCPSUIInfo->Result = psri->Result;
10567bffb703SJames Tabor                 if ( pCPSUIInfo->Result > 0 )
10577bffb703SJames Tabor                 {
10587bffb703SJames Tabor                     IntFixUpDevModeNames( pdphdr );
10597bffb703SJames Tabor                 }
10607bffb703SJames Tabor                 Result = CPSUI_OK;
10617bffb703SJames Tabor                 break;
10627bffb703SJames Tabor         }
10637bffb703SJames Tabor     }
10647bffb703SJames Tabor     return Result;
10657bffb703SJames Tabor }
10667bffb703SJames Tabor 
10677bffb703SJames Tabor LONG
10687bffb703SJames Tabor WINAPI
DevicePropertySheets(PPROPSHEETUI_INFO pCPSUIInfo,LPARAM lparam)10697bffb703SJames Tabor DevicePropertySheets( PPROPSHEETUI_INFO pCPSUIInfo, LPARAM lparam )
10707bffb703SJames Tabor {
10717bffb703SJames Tabor     LONG Result = 0;
10727bffb703SJames Tabor     PDEVICEPROPERTYHEADER pdphdr;
10737bffb703SJames Tabor 
10747bffb703SJames Tabor     FIXME("DevicePropertySheets(%p, 0x%lx)\n", pCPSUIInfo, lparam);
10757bffb703SJames Tabor 
10767bffb703SJames Tabor     if ( pCPSUIInfo )
10777bffb703SJames Tabor     {
10787bffb703SJames Tabor         PSETRESULT_INFO psri;
10797bffb703SJames Tabor         PPROPSHEETUI_INFO_HEADER ppsuiihdr;
10807bffb703SJames Tabor         PCOMPUI_USERDATA pcui_ud;
10817bffb703SJames Tabor         pdphdr = (PDEVICEPROPERTYHEADER)pCPSUIInfo->lParamInit;
10827bffb703SJames Tabor 
10837bffb703SJames Tabor         if ( pdphdr->cbSize < sizeof(DEVICEPROPERTYHEADER) )
10847bffb703SJames Tabor         {
10857bffb703SJames Tabor             SetLastError(ERROR_INVALID_PARAMETER);
10867bffb703SJames Tabor             return Result;
10877bffb703SJames Tabor         }
10887bffb703SJames Tabor 
10897bffb703SJames Tabor         switch ( pCPSUIInfo->Reason )
10907bffb703SJames Tabor         {
10917bffb703SJames Tabor             case PROPSHEETUI_REASON_INIT:
10927bffb703SJames Tabor             {
10937bffb703SJames Tabor                 FIXME("DevPS : PROPSHEETUI_REASON_INIT\n");
10947bffb703SJames Tabor                 if ( CreateUIUserData( &pCPSUIInfo->UserData, pdphdr->hPrinter ) )
10957bffb703SJames Tabor                 {
10967bffb703SJames Tabor                     pcui_ud = (PCOMPUI_USERDATA)pCPSUIInfo->UserData;
10977bffb703SJames Tabor 
10987bffb703SJames Tabor                     fpDevicePropertySheets = (PVOID)GetProcAddress( pcui_ud->hModule, "DrvDevicePropertySheets" );
10997bffb703SJames Tabor 
11007bffb703SJames Tabor                     if ( fpDevicePropertySheets )
11017bffb703SJames Tabor                     {
11027bffb703SJames Tabor                         pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet,
11037bffb703SJames Tabor                                                      CPSFUNC_SET_FUSION_CONTEXT,
11047bffb703SJames Tabor                                                      -3,  // What type of handle is this?
11057bffb703SJames Tabor                                                      0 ); // Not used, must be zero.
11067bffb703SJames Tabor 
11077bffb703SJames Tabor                         Result = pCPSUIInfo->pfnComPropSheet( pCPSUIInfo->hComPropSheet,
11087bffb703SJames Tabor                                                               CPSFUNC_ADD_PFNPROPSHEETUIW,
11097bffb703SJames Tabor                                                              (LPARAM)fpDevicePropertySheets,
11107bffb703SJames Tabor                                                               pCPSUIInfo->lParamInit );
11117bffb703SJames Tabor                         break;
11127bffb703SJames Tabor                     }
11137bffb703SJames Tabor                     FIXME("DevPS : PROPSHEETUI_REASON_INIT Fail\n");
11147bffb703SJames Tabor                     DestroyUIUserData( &pCPSUIInfo->UserData );
11157bffb703SJames Tabor                 }
11167bffb703SJames Tabor             }
11177bffb703SJames Tabor                 break;
11187bffb703SJames Tabor 
11197bffb703SJames Tabor             case PROPSHEETUI_REASON_GET_INFO_HEADER:
11207bffb703SJames Tabor                 FIXME("DevPS : PROPSHEETUI_REASON_GET_INFO_HEADER\n");
11217bffb703SJames Tabor 
11227bffb703SJames Tabor                 ppsuiihdr = (PPROPSHEETUI_INFO_HEADER)lparam;
11237bffb703SJames Tabor 
11247bffb703SJames Tabor                 pcui_ud = (PCOMPUI_USERDATA)pCPSUIInfo->UserData;
11257bffb703SJames Tabor 
11267bffb703SJames Tabor                 CreatePrinterFriendlyName( pcui_ud, pdphdr->pszPrinterName );
11277bffb703SJames Tabor 
11287bffb703SJames Tabor                 ppsuiihdr->Flags  = PSUIHDRF_NOAPPLYNOW|PSUIHDRF_PROPTITLE;
11297bffb703SJames Tabor                 ppsuiihdr->pTitle = pcui_ud->pszPrinterName;
11307bffb703SJames Tabor                 ppsuiihdr->hInst  = hinstWinSpool;
11317bffb703SJames Tabor                 ppsuiihdr->IconID = IDI_CPSUI_DOCUMENT;
11327bffb703SJames Tabor 
11337bffb703SJames Tabor                 Result = CPSUI_OK;
11347bffb703SJames Tabor                 break;
11357bffb703SJames Tabor 
11367bffb703SJames Tabor             case PROPSHEETUI_REASON_DESTROY:
11377bffb703SJames Tabor                 FIXME("DevPS : PROPSHEETUI_REASON_DESTROY\n");
11387bffb703SJames Tabor                 DestroyUIUserData( &pCPSUIInfo->UserData );
11397bffb703SJames Tabor                 Result = CPSUI_OK;
11407bffb703SJames Tabor                 break;
11417bffb703SJames Tabor 
11427bffb703SJames Tabor             case PROPSHEETUI_REASON_SET_RESULT:
11437bffb703SJames Tabor                 FIXME("DevPS : PROPSHEETUI_REASON_SET_RESULT\n");
11447bffb703SJames Tabor                 psri = (PSETRESULT_INFO)lparam;
11457bffb703SJames Tabor                 pCPSUIInfo->Result = psri->Result;
11467bffb703SJames Tabor                 Result = CPSUI_OK;
11477bffb703SJames Tabor                 break;
11487bffb703SJames Tabor         }
11497bffb703SJames Tabor     }
11507bffb703SJames Tabor     return Result;
11517bffb703SJames Tabor }
11527bffb703SJames Tabor 
11537bffb703SJames Tabor LONG
11547bffb703SJames Tabor WINAPI
CallCommonPropertySheetUI(HWND hWnd,PFNPROPSHEETUI pfnPropSheetUI,LPARAM lparam,LPDWORD pResult)11557bffb703SJames Tabor CallCommonPropertySheetUI(HWND hWnd, PFNPROPSHEETUI pfnPropSheetUI, LPARAM lparam, LPDWORD pResult)
11567bffb703SJames Tabor {
11577bffb703SJames Tabor     HMODULE hLibrary = NULL;
11587bffb703SJames Tabor     LONG Ret = ERR_CPSUI_GETLASTERROR;
11597bffb703SJames Tabor 
11607bffb703SJames Tabor     FIXME("CallCommonPropertySheetUI(%p, %p, 0x%lx, %p)\n", hWnd, pfnPropSheetUI, lparam, pResult);
11617bffb703SJames Tabor 
11627bffb703SJames Tabor     if ( ( hLibrary = LoadLibraryA( "compstui.dll" ) ) )
11637bffb703SJames Tabor     {
11647bffb703SJames Tabor         fpCommonPropertySheetUIW = (PVOID) GetProcAddress(hLibrary, "CommonPropertySheetUIW");
11657bffb703SJames Tabor 
11667bffb703SJames Tabor         if ( fpCommonPropertySheetUIW )
11677bffb703SJames Tabor         {
11687bffb703SJames Tabor             Ret = fpCommonPropertySheetUIW( hWnd, pfnPropSheetUI, lparam, pResult );
11697bffb703SJames Tabor         }
11707bffb703SJames Tabor 
11717bffb703SJames Tabor         FreeLibrary(hLibrary);
11727bffb703SJames Tabor     }
11737bffb703SJames Tabor     return Ret;
11747bffb703SJames Tabor }
11757bffb703SJames Tabor 
1176c2c66affSColin Finck LONG WINAPI
DocumentPropertiesW(HWND hWnd,HANDLE hPrinter,LPWSTR pDeviceName,PDEVMODEW pDevModeOutput,PDEVMODEW pDevModeInput,DWORD fMode)1177c2c66affSColin Finck DocumentPropertiesW(HWND hWnd, HANDLE hPrinter, LPWSTR pDeviceName, PDEVMODEW pDevModeOutput, PDEVMODEW pDevModeInput, DWORD fMode)
1178c2c66affSColin Finck {
11798ad75174SMark Jansen     HANDLE hUseHandle = NULL;
11807bffb703SJames Tabor     DOCUMENTPROPERTYHEADER docprophdr;
11817bffb703SJames Tabor     LONG Result = IDOK;
11828ad75174SMark Jansen 
11837bffb703SJames Tabor     FIXME("DocumentPropertiesW(%p, %p, %S, %p, %p, %lu)\n", hWnd, hPrinter, pDeviceName, pDevModeOutput, pDevModeInput, fMode);
11847bffb703SJames Tabor 
11858ad75174SMark Jansen     if (hPrinter)
11868ad75174SMark Jansen     {
11878ad75174SMark Jansen         hUseHandle = hPrinter;
11888ad75174SMark Jansen     }
11898ad75174SMark Jansen     else if (!OpenPrinterW(pDeviceName, &hUseHandle, NULL))
11908ad75174SMark Jansen     {
11918ad75174SMark Jansen         ERR("No handle, and no usable printer name passed in\n");
119246b91659SColin Finck         return -1;
1193c2c66affSColin Finck     }
1194c2c66affSColin Finck 
11957bffb703SJames Tabor     if ( !(fMode & DM_IN_BUFFER ) ||
11967bffb703SJames Tabor          ( ( pDevModeInput && !IsValidDevmodeNoSizeW( (PDEVMODEW)pDevModeInput ) ) ) )
11978ad75174SMark Jansen     {
11987bffb703SJames Tabor         pDevModeInput = NULL;
11997bffb703SJames Tabor         fMode &= ~DM_IN_BUFFER;
12008ad75174SMark Jansen     }
12018ad75174SMark Jansen 
12027bffb703SJames Tabor     docprophdr.cbSize         = sizeof(DOCUMENTPROPERTYHEADER);
12037bffb703SJames Tabor     docprophdr.Reserved       = 0;
12047bffb703SJames Tabor     docprophdr.hPrinter       = hUseHandle;
12057bffb703SJames Tabor     docprophdr.pszPrinterName = pDeviceName;
12067bffb703SJames Tabor     docprophdr.cbOut          = 0;
12077bffb703SJames Tabor 
12087bffb703SJames Tabor     if ( pDevModeOutput )
12097bffb703SJames Tabor     {
12107bffb703SJames Tabor         docprophdr.pdmIn  = NULL;
12117bffb703SJames Tabor         docprophdr.pdmOut = NULL;
12127bffb703SJames Tabor         docprophdr.fMode  = 0;
12137bffb703SJames Tabor         FIXME("DPW : Call DocumentPropertySheets with pDevModeOutput %p\n",pDevModeOutput);
12147bffb703SJames Tabor         docprophdr.cbOut  = DocumentPropertySheets( NULL, (LPARAM)&docprophdr );
12157bffb703SJames Tabor     }
12167bffb703SJames Tabor 
12177bffb703SJames Tabor     docprophdr.pdmIn  = pDevModeInput;
12187bffb703SJames Tabor     docprophdr.pdmOut = pDevModeOutput;
12197bffb703SJames Tabor     docprophdr.fMode  = fMode;
12207bffb703SJames Tabor 
12218ad75174SMark Jansen     if ( fMode & DM_IN_PROMPT )
12228ad75174SMark Jansen     {
12237bffb703SJames Tabor         Result = CPSUI_CANCEL;
12247bffb703SJames Tabor 
12257bffb703SJames Tabor         //
12267bffb703SJames Tabor         // Now call the Property Sheet for Print > Properties.
12277bffb703SJames Tabor         //
12287bffb703SJames Tabor         if ( CallCommonPropertySheetUI( hWnd, (PFNPROPSHEETUI)DocumentPropertySheets, (LPARAM)&docprophdr, (LPDWORD)&Result ) < 0 )
12297bffb703SJames Tabor         {
12307bffb703SJames Tabor             FIXME("CallCommonPropertySheetUI return error\n");
12317bffb703SJames Tabor             Result = ERR_CPSUI_GETLASTERROR;
12327bffb703SJames Tabor         }
12337bffb703SJames Tabor         else
12347bffb703SJames Tabor             Result = (Result == CPSUI_OK) ? IDOK : IDCANCEL;
12357bffb703SJames Tabor         FIXME("CallCommonPropertySheetUI returned\n");
12367bffb703SJames Tabor     }
12377bffb703SJames Tabor     else
12387bffb703SJames Tabor     {
12397bffb703SJames Tabor         FIXME("DPW : CallDocumentPropertySheets\n");
12407bffb703SJames Tabor         Result = DocumentPropertySheets( NULL, (LPARAM)&docprophdr );
12418ad75174SMark Jansen     }
12428ad75174SMark Jansen 
12437bffb703SJames Tabor     if ( Result != ERR_CPSUI_GETLASTERROR || Result != ERR_CPSUI_ALLOCMEM_FAILED )
12448ad75174SMark Jansen     {
12458ad75174SMark Jansen         if ( pDevModeOutput )
12468ad75174SMark Jansen         {
12477bffb703SJames Tabor             if ( !IsValidDevmodeNoSizeW( pDevModeOutput ) )
12487bffb703SJames Tabor             {
12497bffb703SJames Tabor                 ERR("DPW : Improper pDevModeOutput size.\n");
12507bffb703SJames Tabor                 Result = -1;
12517bffb703SJames Tabor             }
12528ad75174SMark Jansen         }
12538ad75174SMark Jansen         else
12548ad75174SMark Jansen         {
12558ad75174SMark Jansen             ERR("No pDevModeOutput\n");
12568ad75174SMark Jansen         }
12578ad75174SMark Jansen     }
12588ad75174SMark Jansen 
12598ad75174SMark Jansen     if (hUseHandle && !hPrinter)
12608ad75174SMark Jansen         ClosePrinter(hUseHandle);
12618ad75174SMark Jansen     return Result;
12628ad75174SMark Jansen }
12638ad75174SMark Jansen 
12647bffb703SJames Tabor BOOL
12657bffb703SJames Tabor WINAPI
PrinterProperties(HWND hWnd,HANDLE hPrinter)12667bffb703SJames Tabor PrinterProperties( HWND hWnd, HANDLE hPrinter )
12677bffb703SJames Tabor {
12687bffb703SJames Tabor     PRINTER_INFO_2W *pi2 = NULL;
12697bffb703SJames Tabor     DWORD needed = 0;
12707bffb703SJames Tabor     LONG Ret, Result = 0;
12717bffb703SJames Tabor     BOOL res;
12727bffb703SJames Tabor     DEVICEPROPERTYHEADER devprophdr;
12737bffb703SJames Tabor 
12747bffb703SJames Tabor     FIXME("PrinterProperties(%p, %p)\n", hWnd, hPrinter);
12757bffb703SJames Tabor 
12767bffb703SJames Tabor     devprophdr.cbSize         = sizeof(DEVICEPROPERTYHEADER);
12777bffb703SJames Tabor     devprophdr.Flags          = DPS_NOPERMISSION;
12787bffb703SJames Tabor     devprophdr.hPrinter       = hPrinter;
12797bffb703SJames Tabor     devprophdr.pszPrinterName = NULL;
12807bffb703SJames Tabor 
12817bffb703SJames Tabor     res = GetPrinterW( hPrinter, 2, NULL, 0, &needed);
12827bffb703SJames Tabor     if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
12837bffb703SJames Tabor     {
12847bffb703SJames Tabor         pi2 = HeapAlloc(hProcessHeap, 0, needed);
12850e68e27fSTimo Kreuzer         if (!pi2)
12860e68e27fSTimo Kreuzer         {
12870e68e27fSTimo Kreuzer             ERR("Failed to allocate PRINTER_INFO_2W of %u bytes\n", needed);
12880e68e27fSTimo Kreuzer             return FALSE;
12890e68e27fSTimo Kreuzer         }
12907bffb703SJames Tabor         res = GetPrinterW(hPrinter, 2, (LPBYTE)pi2, needed, &needed);
12917bffb703SJames Tabor     }
12927bffb703SJames Tabor 
12937bffb703SJames Tabor     //
12947bffb703SJames Tabor     // Above can fail, still process w/o printer name.
12957bffb703SJames Tabor     //
12967bffb703SJames Tabor     if ( res ) devprophdr.pszPrinterName = pi2->pPrinterName;
12977bffb703SJames Tabor 
12987bffb703SJames Tabor     needed = 1;
12997bffb703SJames Tabor 
13007bffb703SJames Tabor     if ( ( SetPrinterDataW( hPrinter, L"PrinterPropertiesPermission", REG_DWORD, (LPBYTE)&needed, sizeof(DWORD) ) == ERROR_SUCCESS ) )
13017bffb703SJames Tabor     {
13027bffb703SJames Tabor         devprophdr.Flags &= ~DPS_NOPERMISSION;
13037bffb703SJames Tabor     }
13047bffb703SJames Tabor 
13057bffb703SJames Tabor     Ret = CallCommonPropertySheetUI( hWnd, (PFNPROPSHEETUI)DevicePropertySheets, (LPARAM)&devprophdr, (LPDWORD)&Result );
13067bffb703SJames Tabor 
13077bffb703SJames Tabor     res = (Ret >= 0);
13087bffb703SJames Tabor 
13097bffb703SJames Tabor     if (!res)
13107bffb703SJames Tabor     {
13117bffb703SJames Tabor         FIXME("PrinterProperties fail ICPSUI\n");
13127bffb703SJames Tabor     }
13137bffb703SJames Tabor 
13147bffb703SJames Tabor     if (pi2) HeapFree(hProcessHeap, 0, pi2);
13157bffb703SJames Tabor 
13167bffb703SJames Tabor     return res;
13177bffb703SJames Tabor }
13187bffb703SJames Tabor 
1319c2c66affSColin Finck BOOL WINAPI
EndDocPrinter(HANDLE hPrinter)1320c2c66affSColin Finck EndDocPrinter(HANDLE hPrinter)
1321c2c66affSColin Finck {
1322c2c66affSColin Finck     DWORD dwErrorCode;
1323c2c66affSColin Finck     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
1324c2c66affSColin Finck 
13251f6f08ecSColin Finck     TRACE("EndDocPrinter(%p)\n", hPrinter);
13261f6f08ecSColin Finck 
1327c2c66affSColin Finck     // Sanity checks.
1328c2c66affSColin Finck     if (!pHandle)
1329c2c66affSColin Finck     {
1330c2c66affSColin Finck         dwErrorCode = ERROR_INVALID_HANDLE;
1331c2c66affSColin Finck         goto Cleanup;
1332c2c66affSColin Finck     }
1333c2c66affSColin Finck 
1334c2c66affSColin Finck     if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
1335c2c66affSColin Finck     {
1336c2c66affSColin Finck         // For spooled jobs, the document is finished by calling _RpcScheduleJob.
1337c2c66affSColin Finck         RpcTryExcept
1338c2c66affSColin Finck         {
1339c2c66affSColin Finck             dwErrorCode = _RpcScheduleJob(pHandle->hPrinter, pHandle->dwJobID);
1340c2c66affSColin Finck         }
1341c2c66affSColin Finck         RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1342c2c66affSColin Finck         {
1343c2c66affSColin Finck             dwErrorCode = RpcExceptionCode();
1344c2c66affSColin Finck             ERR("_RpcScheduleJob failed with exception code %lu!\n", dwErrorCode);
1345c2c66affSColin Finck         }
1346c2c66affSColin Finck         RpcEndExcept;
1347c2c66affSColin Finck 
1348c2c66affSColin Finck         // Close the spool file handle.
1349c2c66affSColin Finck         CloseHandle(pHandle->hSPLFile);
1350c2c66affSColin Finck     }
1351c2c66affSColin Finck     else
1352c2c66affSColin Finck     {
1353c2c66affSColin Finck         // In all other cases, just call _RpcEndDocPrinter.
1354c2c66affSColin Finck         RpcTryExcept
1355c2c66affSColin Finck         {
1356c2c66affSColin Finck             dwErrorCode = _RpcEndDocPrinter(pHandle->hPrinter);
1357c2c66affSColin Finck         }
1358c2c66affSColin Finck         RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1359c2c66affSColin Finck         {
1360c2c66affSColin Finck             dwErrorCode = RpcExceptionCode();
1361c2c66affSColin Finck             ERR("_RpcEndDocPrinter failed with exception code %lu!\n", dwErrorCode);
1362c2c66affSColin Finck         }
1363c2c66affSColin Finck         RpcEndExcept;
1364c2c66affSColin Finck     }
1365c2c66affSColin Finck 
1366c2c66affSColin Finck     // A new document can now be started again.
13677bffb703SJames Tabor     pHandle->bTrayIcon = pHandle->bJob = pHandle->bStartedDoc = FALSE;
1368c2c66affSColin Finck 
1369c2c66affSColin Finck Cleanup:
1370c2c66affSColin Finck     SetLastError(dwErrorCode);
1371c2c66affSColin Finck     return (dwErrorCode == ERROR_SUCCESS);
1372c2c66affSColin Finck }
1373c2c66affSColin Finck 
1374c2c66affSColin Finck BOOL WINAPI
EndPagePrinter(HANDLE hPrinter)1375c2c66affSColin Finck EndPagePrinter(HANDLE hPrinter)
1376c2c66affSColin Finck {
1377c2c66affSColin Finck     DWORD dwErrorCode;
1378c2c66affSColin Finck     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
1379c2c66affSColin Finck 
13801f6f08ecSColin Finck     TRACE("EndPagePrinter(%p)\n", hPrinter);
13811f6f08ecSColin Finck 
1382c2c66affSColin Finck     // Sanity checks.
1383c2c66affSColin Finck     if (!pHandle)
1384c2c66affSColin Finck     {
1385c2c66affSColin Finck         dwErrorCode = ERROR_INVALID_HANDLE;
1386c2c66affSColin Finck         goto Cleanup;
1387c2c66affSColin Finck     }
1388c2c66affSColin Finck 
1389c2c66affSColin Finck     if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
1390c2c66affSColin Finck     {
1391c2c66affSColin Finck         // For spooled jobs, we don't need to do anything.
1392c2c66affSColin Finck         dwErrorCode = ERROR_SUCCESS;
1393c2c66affSColin Finck     }
1394c2c66affSColin Finck     else
1395c2c66affSColin Finck     {
1396c2c66affSColin Finck         // In all other cases, just call _RpcEndPagePrinter.
1397c2c66affSColin Finck         RpcTryExcept
1398c2c66affSColin Finck         {
1399c2c66affSColin Finck             dwErrorCode = _RpcEndPagePrinter(pHandle->hPrinter);
1400c2c66affSColin Finck         }
1401c2c66affSColin Finck         RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1402c2c66affSColin Finck         {
1403c2c66affSColin Finck             dwErrorCode = RpcExceptionCode();
1404c2c66affSColin Finck             ERR("_RpcEndPagePrinter failed with exception code %lu!\n", dwErrorCode);
1405c2c66affSColin Finck         }
1406c2c66affSColin Finck         RpcEndExcept;
1407c2c66affSColin Finck     }
1408c2c66affSColin Finck 
1409c2c66affSColin Finck Cleanup:
1410c2c66affSColin Finck     SetLastError(dwErrorCode);
1411c2c66affSColin Finck     return (dwErrorCode == ERROR_SUCCESS);
1412c2c66affSColin Finck }
1413c2c66affSColin Finck 
1414c2c66affSColin Finck BOOL WINAPI
EnumPrintersA(DWORD Flags,PSTR Name,DWORD Level,PBYTE pPrinterEnum,DWORD cbBuf,PDWORD pcbNeeded,PDWORD pcReturned)1415c2c66affSColin Finck EnumPrintersA(DWORD Flags, PSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
1416c2c66affSColin Finck {
1417b139bae5SSerge Gautherie     DWORD dwErrorCode;
1418e8b17782SDoug Lyons     DWORD cch;
1419e8b17782SDoug Lyons     PWSTR pwszName = NULL;
1420e8b17782SDoug Lyons     PSTR pszPrinterName = NULL;
1421e8b17782SDoug Lyons     PSTR pszServerName = NULL;
1422e8b17782SDoug Lyons     PSTR pszDescription = NULL;
1423e8b17782SDoug Lyons     PSTR pszName = NULL;
1424e8b17782SDoug Lyons     PSTR pszComment = NULL;
1425e8b17782SDoug Lyons     PSTR pszShareName = NULL;
1426e8b17782SDoug Lyons     PSTR pszPortName = NULL;
1427e8b17782SDoug Lyons     PSTR pszDriverName = NULL;
1428e8b17782SDoug Lyons     PSTR pszLocation = NULL;
1429e8b17782SDoug Lyons     PSTR pszSepFile = NULL;
1430e8b17782SDoug Lyons     PSTR pszPrintProcessor = NULL;
1431e8b17782SDoug Lyons     PSTR pszDatatype = NULL;
1432e8b17782SDoug Lyons     PSTR pszParameters = NULL;
1433e8b17782SDoug Lyons     DWORD i;
1434e8b17782SDoug Lyons     PPRINTER_INFO_1W ppi1w = NULL;
1435e8b17782SDoug Lyons     PPRINTER_INFO_1A ppi1a = NULL;
1436e8b17782SDoug Lyons     PPRINTER_INFO_2W ppi2w = NULL;
1437e8b17782SDoug Lyons     PPRINTER_INFO_2A ppi2a = NULL;
1438e8b17782SDoug Lyons     PPRINTER_INFO_4W ppi4w = NULL;
1439e8b17782SDoug Lyons     PPRINTER_INFO_4A ppi4a = NULL;
1440e8b17782SDoug Lyons     PPRINTER_INFO_5W ppi5w = NULL;
1441e8b17782SDoug Lyons     PPRINTER_INFO_5A ppi5a = NULL;
1442e8b17782SDoug Lyons 
14431f6f08ecSColin Finck     TRACE("EnumPrintersA(%lu, %s, %lu, %p, %lu, %p, %p)\n", Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
1444e8b17782SDoug Lyons 
1445e8b17782SDoug Lyons     // Check for invalid levels here for early error return. MSDN says that only 1, 2, 4, and 5 are allowable.
1446e8b17782SDoug Lyons     if (Level !=  1 && Level != 2 && Level != 4 && Level != 5)
1447e8b17782SDoug Lyons     {
1448b139bae5SSerge Gautherie         dwErrorCode = ERROR_INVALID_LEVEL;
1449e8b17782SDoug Lyons         ERR("Invalid Level!\n");
1450e8b17782SDoug Lyons         goto Cleanup;
1451e8b17782SDoug Lyons     }
1452e8b17782SDoug Lyons 
1453e8b17782SDoug Lyons     if (Name)
1454e8b17782SDoug Lyons     {
1455e8b17782SDoug Lyons         // Convert pName to a Unicode string pwszName.
1456e8b17782SDoug Lyons         cch = strlen(Name);
1457e8b17782SDoug Lyons 
1458e8b17782SDoug Lyons         pwszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
1459e8b17782SDoug Lyons         if (!pwszName)
1460e8b17782SDoug Lyons         {
1461b139bae5SSerge Gautherie             dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1462e8b17782SDoug Lyons             ERR("HeapAlloc failed!\n");
1463e8b17782SDoug Lyons             goto Cleanup;
1464e8b17782SDoug Lyons         }
1465e8b17782SDoug Lyons 
1466e8b17782SDoug Lyons         MultiByteToWideChar(CP_ACP, 0, Name, -1, pwszName, cch + 1);
1467e8b17782SDoug Lyons     }
1468e8b17782SDoug Lyons 
1469e8b17782SDoug Lyons     /* Ref: https://stackoverflow.com/questions/41147180/why-enumprintersa-and-enumprintersw-request-the-same-amount-of-memory */
14704b1ae540SSerge Gautherie     if (!EnumPrintersW(Flags, pwszName, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned))
1471b139bae5SSerge Gautherie     {
1472b139bae5SSerge Gautherie         dwErrorCode = GetLastError();
1473b139bae5SSerge Gautherie         goto Cleanup;
1474b139bae5SSerge Gautherie     }
1475e8b17782SDoug Lyons 
1476e8b17782SDoug Lyons     /* We are mapping multiple different pointers to the same pPrinterEnum pointer here so that */
1477e8b17782SDoug Lyons     /* we can do in-place conversion. We read the Unicode response from the EnumPrintersW and */
1478e8b17782SDoug Lyons     /* then we write back the ANSI conversion into the same buffer for our EnumPrintersA output */
1479e8b17782SDoug Lyons 
1480e8b17782SDoug Lyons     /* mapping to pPrinterEnum for Unicode (w) characters for Levels 1, 2, 4, and 5 */
1481e8b17782SDoug Lyons     ppi1w = (PPRINTER_INFO_1W)pPrinterEnum;
1482e8b17782SDoug Lyons     ppi2w = (PPRINTER_INFO_2W)pPrinterEnum;
1483e8b17782SDoug Lyons     ppi4w = (PPRINTER_INFO_4W)pPrinterEnum;
1484e8b17782SDoug Lyons     ppi5w = (PPRINTER_INFO_5W)pPrinterEnum;
1485e8b17782SDoug Lyons     /* mapping to pPrinterEnum for ANSI (a) characters for Levels 1, 2, 4, and 5 */
1486e8b17782SDoug Lyons     ppi1a = (PPRINTER_INFO_1A)pPrinterEnum;
1487e8b17782SDoug Lyons     ppi2a = (PPRINTER_INFO_2A)pPrinterEnum;
1488e8b17782SDoug Lyons     ppi4a = (PPRINTER_INFO_4A)pPrinterEnum;
1489e8b17782SDoug Lyons     ppi5a = (PPRINTER_INFO_5A)pPrinterEnum;
1490e8b17782SDoug Lyons 
1491e8b17782SDoug Lyons     for (i = 0; i < *pcReturned; i++)
1492e8b17782SDoug Lyons     {
1493e8b17782SDoug Lyons         switch (Level)
1494e8b17782SDoug Lyons         {
1495e8b17782SDoug Lyons             case 1:
1496e8b17782SDoug Lyons             {
1497e8b17782SDoug Lyons                 if (ppi1w[i].pDescription)
1498e8b17782SDoug Lyons                 {
1499e8b17782SDoug Lyons                     // Convert Unicode pDescription to a ANSI string pszDescription.
1500e8b17782SDoug Lyons                     cch = wcslen(ppi1w[i].pDescription);
1501e8b17782SDoug Lyons 
1502e8b17782SDoug Lyons                     pszDescription = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1503e8b17782SDoug Lyons                     if (!pszDescription)
1504e8b17782SDoug Lyons                     {
1505b139bae5SSerge Gautherie                         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1506e8b17782SDoug Lyons                         ERR("HeapAlloc failed!\n");
1507e8b17782SDoug Lyons                         goto Cleanup;
1508e8b17782SDoug Lyons                     }
1509e8b17782SDoug Lyons 
1510e8b17782SDoug Lyons                     WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pDescription, -1, pszDescription, cch + 1, NULL, NULL);
1511e8b17782SDoug Lyons                     StringCchCopyA(ppi1a[i].pDescription, cch + 1, pszDescription);
1512e8b17782SDoug Lyons 
1513e8b17782SDoug Lyons                     HeapFree(hProcessHeap, 0, pszDescription);
1514e8b17782SDoug Lyons                 }
1515e8b17782SDoug Lyons 
1516e8b17782SDoug Lyons                 if (ppi1w[i].pName)
1517e8b17782SDoug Lyons                 {
1518e8b17782SDoug Lyons                     // Convert Unicode pName to a ANSI string pszName.
1519e8b17782SDoug Lyons                     cch = wcslen(ppi1w[i].pName);
1520e8b17782SDoug Lyons 
1521e8b17782SDoug Lyons                     pszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1522e8b17782SDoug Lyons                     if (!pszName)
1523e8b17782SDoug Lyons                     {
1524b139bae5SSerge Gautherie                         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1525e8b17782SDoug Lyons                         ERR("HeapAlloc failed!\n");
1526e8b17782SDoug Lyons                         goto Cleanup;
1527e8b17782SDoug Lyons                     }
1528e8b17782SDoug Lyons 
1529e8b17782SDoug Lyons                     WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pName, -1, pszName, cch + 1, NULL, NULL);
1530e8b17782SDoug Lyons                     StringCchCopyA(ppi1a[i].pName, cch + 1, pszName);
1531e8b17782SDoug Lyons 
1532e8b17782SDoug Lyons                     HeapFree(hProcessHeap, 0, pszName);
1533e8b17782SDoug Lyons                 }
1534e8b17782SDoug Lyons 
1535e8b17782SDoug Lyons                 if (ppi1w[i].pComment)
1536e8b17782SDoug Lyons                 {
1537e8b17782SDoug Lyons                     // Convert Unicode pComment to a ANSI string pszComment.
1538e8b17782SDoug Lyons                     cch = wcslen(ppi1w[i].pComment);
1539e8b17782SDoug Lyons 
1540e8b17782SDoug Lyons                     pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1541e8b17782SDoug Lyons                     if (!pszComment)
1542e8b17782SDoug Lyons                     {
1543b139bae5SSerge Gautherie                         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1544e8b17782SDoug Lyons                         ERR("HeapAlloc failed!\n");
1545e8b17782SDoug Lyons                         goto Cleanup;
1546e8b17782SDoug Lyons                     }
1547e8b17782SDoug Lyons 
1548e8b17782SDoug Lyons                     WideCharToMultiByte(CP_ACP, 0, ppi1w[i].pComment, -1, pszComment, cch + 1, NULL, NULL);
1549e8b17782SDoug Lyons                     StringCchCopyA(ppi1a[i].pComment, cch + 1, pszComment);
1550e8b17782SDoug Lyons 
1551e8b17782SDoug Lyons                     HeapFree(hProcessHeap, 0, pszComment);
1552e8b17782SDoug Lyons                 }
1553e8b17782SDoug Lyons                 break;
1554e8b17782SDoug Lyons             }
1555e8b17782SDoug Lyons 
1556e8b17782SDoug Lyons 
1557e8b17782SDoug Lyons             case 2:
1558e8b17782SDoug Lyons             {
1559e8b17782SDoug Lyons                 if (ppi2w[i].pServerName)
1560e8b17782SDoug Lyons                 {
1561e8b17782SDoug Lyons                     // Convert Unicode pServerName to a ANSI string pszServerName.
1562e8b17782SDoug Lyons                     cch = wcslen(ppi2w[i].pServerName);
1563e8b17782SDoug Lyons 
1564e8b17782SDoug Lyons                     pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1565e8b17782SDoug Lyons                     if (!pszServerName)
1566e8b17782SDoug Lyons                     {
1567b139bae5SSerge Gautherie                         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1568e8b17782SDoug Lyons                         ERR("HeapAlloc failed!\n");
1569e8b17782SDoug Lyons                         goto Cleanup;
1570e8b17782SDoug Lyons                     }
1571e8b17782SDoug Lyons 
1572e8b17782SDoug Lyons                     WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pServerName, -1, pszServerName, cch + 1, NULL, NULL);
1573e8b17782SDoug Lyons                     StringCchCopyA(ppi2a[i].pServerName, cch + 1, pszServerName);
1574e8b17782SDoug Lyons 
1575e8b17782SDoug Lyons                     HeapFree(hProcessHeap, 0, pszServerName);
1576e8b17782SDoug Lyons                 }
1577e8b17782SDoug Lyons 
1578e8b17782SDoug Lyons                 if (ppi2w[i].pPrinterName)
1579e8b17782SDoug Lyons                 {
1580e8b17782SDoug Lyons                     // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
1581e8b17782SDoug Lyons                     cch = wcslen(ppi2w[i].pPrinterName);
1582e8b17782SDoug Lyons 
1583e8b17782SDoug Lyons                     pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1584e8b17782SDoug Lyons                     if (!pszPrinterName)
1585e8b17782SDoug Lyons                     {
1586b139bae5SSerge Gautherie                         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1587e8b17782SDoug Lyons                         ERR("HeapAlloc failed!\n");
1588e8b17782SDoug Lyons                         goto Cleanup;
1589e8b17782SDoug Lyons                     }
1590e8b17782SDoug Lyons 
1591e8b17782SDoug Lyons                     WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
1592e8b17782SDoug Lyons                     StringCchCopyA(ppi2a[i].pPrinterName, cch + 1, pszPrinterName);
1593e8b17782SDoug Lyons 
1594e8b17782SDoug Lyons                     HeapFree(hProcessHeap, 0, pszPrinterName);
1595e8b17782SDoug Lyons                 }
1596e8b17782SDoug Lyons 
1597e8b17782SDoug Lyons                 if (ppi2w[i].pShareName)
1598e8b17782SDoug Lyons                 {
1599e8b17782SDoug Lyons                     // Convert Unicode pShareName to a ANSI string pszShareName.
1600e8b17782SDoug Lyons                     cch = wcslen(ppi2w[i].pShareName);
1601e8b17782SDoug Lyons 
1602e8b17782SDoug Lyons                     pszShareName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1603e8b17782SDoug Lyons                     if (!pszShareName)
1604e8b17782SDoug Lyons                     {
1605b139bae5SSerge Gautherie                         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1606e8b17782SDoug Lyons                         ERR("HeapAlloc failed!\n");
1607e8b17782SDoug Lyons                         goto Cleanup;
1608e8b17782SDoug Lyons                     }
1609e8b17782SDoug Lyons 
1610e8b17782SDoug Lyons                     WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pShareName, -1, pszShareName, cch + 1, NULL, NULL);
1611e8b17782SDoug Lyons                     StringCchCopyA(ppi2a[i].pShareName, cch + 1, pszShareName);
1612e8b17782SDoug Lyons 
1613e8b17782SDoug Lyons                     HeapFree(hProcessHeap, 0, pszShareName);
1614e8b17782SDoug Lyons                 }
1615e8b17782SDoug Lyons 
1616e8b17782SDoug Lyons                 if (ppi2w[i].pPortName)
1617e8b17782SDoug Lyons                 {
1618e8b17782SDoug Lyons                     // Convert Unicode pPortName to a ANSI string pszPortName.
1619e8b17782SDoug Lyons                     cch = wcslen(ppi2w[i].pPortName);
1620e8b17782SDoug Lyons 
1621e8b17782SDoug Lyons                     pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1622e8b17782SDoug Lyons                     if (!pszPortName)
1623e8b17782SDoug Lyons                     {
1624b139bae5SSerge Gautherie                         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1625e8b17782SDoug Lyons                         ERR("HeapAlloc failed!\n");
1626e8b17782SDoug Lyons                         goto Cleanup;
1627e8b17782SDoug Lyons                     }
1628e8b17782SDoug Lyons 
1629e8b17782SDoug Lyons                     WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPortName, -1, pszPortName, cch + 1, NULL, NULL);
1630e8b17782SDoug Lyons                     StringCchCopyA(ppi2a[i].pPortName, cch + 1, pszPortName);
1631e8b17782SDoug Lyons 
1632e8b17782SDoug Lyons                     HeapFree(hProcessHeap, 0, pszPortName);
1633e8b17782SDoug Lyons                 }
1634e8b17782SDoug Lyons 
1635e8b17782SDoug Lyons                 if (ppi2w[i].pDriverName)
1636e8b17782SDoug Lyons                 {
1637e8b17782SDoug Lyons                     // Convert Unicode pDriverName to a ANSI string pszDriverName.
1638e8b17782SDoug Lyons                     cch = wcslen(ppi2w[i].pDriverName);
1639e8b17782SDoug Lyons 
1640e8b17782SDoug Lyons                     pszDriverName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1641e8b17782SDoug Lyons                     if (!pszDriverName)
1642e8b17782SDoug Lyons                     {
1643b139bae5SSerge Gautherie                         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1644e8b17782SDoug Lyons                         ERR("HeapAlloc failed!\n");
1645e8b17782SDoug Lyons                         goto Cleanup;
1646e8b17782SDoug Lyons                     }
1647e8b17782SDoug Lyons 
1648e8b17782SDoug Lyons                     WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pDriverName, -1, pszDriverName, cch + 1, NULL, NULL);
1649e8b17782SDoug Lyons                     StringCchCopyA(ppi2a[i].pDriverName, cch + 1, pszDriverName);
1650e8b17782SDoug Lyons 
1651e8b17782SDoug Lyons                     HeapFree(hProcessHeap, 0, pszDriverName);
1652e8b17782SDoug Lyons                 }
1653e8b17782SDoug Lyons 
1654e8b17782SDoug Lyons                 if (ppi2w[i].pComment)
1655e8b17782SDoug Lyons                 {
1656e8b17782SDoug Lyons                     // Convert Unicode pComment to a ANSI string pszComment.
1657e8b17782SDoug Lyons                     cch = wcslen(ppi2w[i].pComment);
1658e8b17782SDoug Lyons 
1659e8b17782SDoug Lyons                     pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1660e8b17782SDoug Lyons                     if (!pszComment)
1661e8b17782SDoug Lyons                     {
1662b139bae5SSerge Gautherie                         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1663e8b17782SDoug Lyons                         ERR("HeapAlloc failed!\n");
1664e8b17782SDoug Lyons                         goto Cleanup;
1665e8b17782SDoug Lyons                     }
1666e8b17782SDoug Lyons 
1667e8b17782SDoug Lyons                     WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pComment, -1, pszComment, cch + 1, NULL, NULL);
1668e8b17782SDoug Lyons                     StringCchCopyA(ppi2a[i].pComment, cch + 1, pszComment);
1669e8b17782SDoug Lyons 
1670e8b17782SDoug Lyons                     HeapFree(hProcessHeap, 0, pszComment);
1671e8b17782SDoug Lyons                 }
1672e8b17782SDoug Lyons 
1673e8b17782SDoug Lyons                 if (ppi2w[i].pLocation)
1674e8b17782SDoug Lyons                 {
1675e8b17782SDoug Lyons                     // Convert Unicode pLocation to a ANSI string pszLocation.
1676e8b17782SDoug Lyons                     cch = wcslen(ppi2w[i].pLocation);
1677e8b17782SDoug Lyons 
1678e8b17782SDoug Lyons                     pszLocation = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1679e8b17782SDoug Lyons                     if (!pszLocation)
1680e8b17782SDoug Lyons                     {
1681b139bae5SSerge Gautherie                         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1682e8b17782SDoug Lyons                         ERR("HeapAlloc failed!\n");
1683e8b17782SDoug Lyons                         goto Cleanup;
1684e8b17782SDoug Lyons                     }
1685e8b17782SDoug Lyons 
1686e8b17782SDoug Lyons                     WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pLocation, -1, pszLocation, cch + 1, NULL, NULL);
1687e8b17782SDoug Lyons                     StringCchCopyA(ppi2a[i].pLocation, cch + 1, pszLocation);
1688e8b17782SDoug Lyons 
1689e8b17782SDoug Lyons                     HeapFree(hProcessHeap, 0, pszLocation);
1690e8b17782SDoug Lyons                 }
1691e8b17782SDoug Lyons 
1692e8b17782SDoug Lyons 
1693e8b17782SDoug Lyons                 if (ppi2w[i].pSepFile)
1694e8b17782SDoug Lyons                 {
1695e8b17782SDoug Lyons                     // Convert Unicode pSepFile to a ANSI string pszSepFile.
1696e8b17782SDoug Lyons                     cch = wcslen(ppi2w[i].pSepFile);
1697e8b17782SDoug Lyons 
1698e8b17782SDoug Lyons                     pszSepFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1699e8b17782SDoug Lyons                     if (!pszSepFile)
1700e8b17782SDoug Lyons                     {
1701b139bae5SSerge Gautherie                         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1702e8b17782SDoug Lyons                         ERR("HeapAlloc failed!\n");
1703e8b17782SDoug Lyons                         goto Cleanup;
1704e8b17782SDoug Lyons                     }
1705e8b17782SDoug Lyons 
1706e8b17782SDoug Lyons                     WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pSepFile, -1, pszSepFile, cch + 1, NULL, NULL);
1707e8b17782SDoug Lyons                     StringCchCopyA(ppi2a[i].pSepFile, cch + 1, pszSepFile);
1708e8b17782SDoug Lyons 
1709e8b17782SDoug Lyons                     HeapFree(hProcessHeap, 0, pszSepFile);
1710e8b17782SDoug Lyons                 }
1711e8b17782SDoug Lyons 
1712e8b17782SDoug Lyons                 if (ppi2w[i].pPrintProcessor)
1713e8b17782SDoug Lyons                 {
1714e8b17782SDoug Lyons                     // Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor.
1715e8b17782SDoug Lyons                     cch = wcslen(ppi2w[i].pPrintProcessor);
1716e8b17782SDoug Lyons 
1717e8b17782SDoug Lyons                     pszPrintProcessor = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1718e8b17782SDoug Lyons                     if (!pszPrintProcessor)
1719e8b17782SDoug Lyons                     {
1720b139bae5SSerge Gautherie                         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1721e8b17782SDoug Lyons                         ERR("HeapAlloc failed!\n");
1722e8b17782SDoug Lyons                         goto Cleanup;
1723e8b17782SDoug Lyons                     }
1724e8b17782SDoug Lyons 
1725e8b17782SDoug Lyons                     WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pPrintProcessor, -1, pszPrintProcessor, cch + 1, NULL, NULL);
1726e8b17782SDoug Lyons                     StringCchCopyA(ppi2a[i].pPrintProcessor, cch + 1, pszPrintProcessor);
1727e8b17782SDoug Lyons 
1728e8b17782SDoug Lyons                     HeapFree(hProcessHeap, 0, pszPrintProcessor);
1729e8b17782SDoug Lyons                 }
1730e8b17782SDoug Lyons 
1731e8b17782SDoug Lyons 
1732e8b17782SDoug Lyons                 if (ppi2w[i].pDatatype)
1733e8b17782SDoug Lyons                 {
1734e8b17782SDoug Lyons                     // Convert Unicode pDatatype to a ANSI string pszDatatype.
1735e8b17782SDoug Lyons                     cch = wcslen(ppi2w[i].pDatatype);
1736e8b17782SDoug Lyons 
1737e8b17782SDoug Lyons                     pszDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1738e8b17782SDoug Lyons                     if (!pszDatatype)
1739e8b17782SDoug Lyons                     {
1740b139bae5SSerge Gautherie                         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1741e8b17782SDoug Lyons                         ERR("HeapAlloc failed!\n");
1742e8b17782SDoug Lyons                         goto Cleanup;
1743e8b17782SDoug Lyons                     }
1744e8b17782SDoug Lyons 
1745e8b17782SDoug Lyons                     WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pDatatype, -1, pszDatatype, cch + 1, NULL, NULL);
1746e8b17782SDoug Lyons                     StringCchCopyA(ppi2a[i].pDatatype, cch + 1, pszDatatype);
1747e8b17782SDoug Lyons 
1748e8b17782SDoug Lyons                     HeapFree(hProcessHeap, 0, pszDatatype);
1749e8b17782SDoug Lyons                 }
1750e8b17782SDoug Lyons 
1751e8b17782SDoug Lyons                 if (ppi2w[i].pParameters)
1752e8b17782SDoug Lyons                 {
1753e8b17782SDoug Lyons                     // Convert Unicode pParameters to a ANSI string pszParameters.
1754e8b17782SDoug Lyons                     cch = wcslen(ppi2w[i].pParameters);
1755e8b17782SDoug Lyons 
1756e8b17782SDoug Lyons                     pszParameters = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1757e8b17782SDoug Lyons                     if (!pszParameters)
1758e8b17782SDoug Lyons                     {
1759b139bae5SSerge Gautherie                         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1760e8b17782SDoug Lyons                         ERR("HeapAlloc failed!\n");
1761e8b17782SDoug Lyons                         goto Cleanup;
1762e8b17782SDoug Lyons                     }
1763e8b17782SDoug Lyons 
1764e8b17782SDoug Lyons                     WideCharToMultiByte(CP_ACP, 0, ppi2w[i].pParameters, -1, pszParameters, cch + 1, NULL, NULL);
1765e8b17782SDoug Lyons                     StringCchCopyA(ppi2a[i].pParameters, cch + 1, pszParameters);
1766e8b17782SDoug Lyons 
1767e8b17782SDoug Lyons                     HeapFree(hProcessHeap, 0, pszParameters);
1768e8b17782SDoug Lyons                 }
17697bffb703SJames Tabor                 if ( ppi2w[i].pDevMode )
17707bffb703SJames Tabor                 {
17717bffb703SJames Tabor                     RosConvertUnicodeDevModeToAnsiDevmode( ppi2w[i].pDevMode, ppi2a[i].pDevMode );
17727bffb703SJames Tabor                 }
1773e8b17782SDoug Lyons                 break;
1774e8b17782SDoug Lyons             }
1775e8b17782SDoug Lyons 
1776e8b17782SDoug Lyons             case 4:
1777e8b17782SDoug Lyons             {
1778e8b17782SDoug Lyons                 if (ppi4w[i].pPrinterName)
1779e8b17782SDoug Lyons                 {
1780e8b17782SDoug Lyons                     // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
1781e8b17782SDoug Lyons                     cch = wcslen(ppi4w[i].pPrinterName);
1782e8b17782SDoug Lyons 
1783e8b17782SDoug Lyons                     pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1784e8b17782SDoug Lyons                     if (!pszPrinterName)
1785e8b17782SDoug Lyons                     {
1786b139bae5SSerge Gautherie                         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1787e8b17782SDoug Lyons                         ERR("HeapAlloc failed!\n");
1788e8b17782SDoug Lyons                         goto Cleanup;
1789e8b17782SDoug Lyons                     }
1790e8b17782SDoug Lyons 
1791e8b17782SDoug Lyons                     WideCharToMultiByte(CP_ACP, 0, ppi4w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
1792e8b17782SDoug Lyons                     StringCchCopyA(ppi4a[i].pPrinterName, cch + 1, pszPrinterName);
1793e8b17782SDoug Lyons 
1794e8b17782SDoug Lyons                     HeapFree(hProcessHeap, 0, pszPrinterName);
1795e8b17782SDoug Lyons                 }
1796e8b17782SDoug Lyons 
1797e8b17782SDoug Lyons                 if (ppi4w[i].pServerName)
1798e8b17782SDoug Lyons                 {
1799e8b17782SDoug Lyons                     // Convert Unicode pServerName to a ANSI string pszServerName.
1800e8b17782SDoug Lyons                     cch = wcslen(ppi4w[i].pServerName);
1801e8b17782SDoug Lyons 
1802e8b17782SDoug Lyons                     pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1803e8b17782SDoug Lyons                     if (!pszServerName)
1804e8b17782SDoug Lyons                     {
1805b139bae5SSerge Gautherie                         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1806e8b17782SDoug Lyons                         ERR("HeapAlloc failed!\n");
1807e8b17782SDoug Lyons                         goto Cleanup;
1808e8b17782SDoug Lyons                     }
1809e8b17782SDoug Lyons 
1810e8b17782SDoug Lyons                     WideCharToMultiByte(CP_ACP, 0, ppi4w[i].pServerName, -1, pszServerName, cch + 1, NULL, NULL);
1811e8b17782SDoug Lyons                     StringCchCopyA(ppi4a[i].pServerName, cch + 1, pszServerName);
1812e8b17782SDoug Lyons 
1813e8b17782SDoug Lyons                     HeapFree(hProcessHeap, 0, pszServerName);
1814e8b17782SDoug Lyons                 }
1815e8b17782SDoug Lyons                 break;
1816e8b17782SDoug Lyons             }
1817e8b17782SDoug Lyons 
1818e8b17782SDoug Lyons             case 5:
1819e8b17782SDoug Lyons             {
1820e8b17782SDoug Lyons                 if (ppi5w[i].pPrinterName)
1821e8b17782SDoug Lyons                 {
1822e8b17782SDoug Lyons                     // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
1823e8b17782SDoug Lyons                     cch = wcslen(ppi5w[i].pPrinterName);
1824e8b17782SDoug Lyons 
1825e8b17782SDoug Lyons                     pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1826e8b17782SDoug Lyons                     if (!pszPrinterName)
1827e8b17782SDoug Lyons                     {
1828b139bae5SSerge Gautherie                         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1829e8b17782SDoug Lyons                         ERR("HeapAlloc failed!\n");
1830e8b17782SDoug Lyons                         goto Cleanup;
1831e8b17782SDoug Lyons                     }
1832e8b17782SDoug Lyons 
1833e8b17782SDoug Lyons                     WideCharToMultiByte(CP_ACP, 0, ppi5w[i].pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
1834e8b17782SDoug Lyons                     StringCchCopyA(ppi5a[i].pPrinterName, cch + 1, pszPrinterName);
1835e8b17782SDoug Lyons 
1836e8b17782SDoug Lyons                     HeapFree(hProcessHeap, 0, pszPrinterName);
1837e8b17782SDoug Lyons                 }
1838e8b17782SDoug Lyons 
1839e8b17782SDoug Lyons                 if (ppi5w[i].pPortName)
1840e8b17782SDoug Lyons                 {
1841e8b17782SDoug Lyons                     // Convert Unicode pPortName to a ANSI string pszPortName.
1842e8b17782SDoug Lyons                     cch = wcslen(ppi5w[i].pPortName);
1843e8b17782SDoug Lyons 
1844e8b17782SDoug Lyons                     pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
1845e8b17782SDoug Lyons                     if (!pszPortName)
1846e8b17782SDoug Lyons                     {
1847b139bae5SSerge Gautherie                         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1848e8b17782SDoug Lyons                         ERR("HeapAlloc failed!\n");
1849e8b17782SDoug Lyons                         goto Cleanup;
1850e8b17782SDoug Lyons                     }
1851e8b17782SDoug Lyons 
1852e8b17782SDoug Lyons                     WideCharToMultiByte(CP_ACP, 0, ppi5w[i].pPortName, -1, pszPortName, cch + 1, NULL, NULL);
1853e8b17782SDoug Lyons                     StringCchCopyA(ppi5a[i].pPortName, cch + 1, pszPortName);
1854e8b17782SDoug Lyons 
1855e8b17782SDoug Lyons                     HeapFree(hProcessHeap, 0, pszPortName);
1856e8b17782SDoug Lyons                 }
1857e8b17782SDoug Lyons                 break;
1858e8b17782SDoug Lyons             }
1859e8b17782SDoug Lyons 
1860e8b17782SDoug Lyons         }   // switch
1861e8b17782SDoug Lyons     }       // for
1862e8b17782SDoug Lyons 
1863b139bae5SSerge Gautherie     dwErrorCode = ERROR_SUCCESS;
1864e8b17782SDoug Lyons 
1865b139bae5SSerge Gautherie Cleanup:
1866b139bae5SSerge Gautherie     if (pwszName)
1867b139bae5SSerge Gautherie     {
1868b139bae5SSerge Gautherie         HeapFree(hProcessHeap, 0, pwszName);
1869b139bae5SSerge Gautherie     }
1870b139bae5SSerge Gautherie 
1871b139bae5SSerge Gautherie     SetLastError(dwErrorCode);
1872b139bae5SSerge Gautherie     return (dwErrorCode == ERROR_SUCCESS);
1873c2c66affSColin Finck }
1874c2c66affSColin Finck 
1875c2c66affSColin Finck BOOL WINAPI
EnumPrintersW(DWORD Flags,PWSTR Name,DWORD Level,PBYTE pPrinterEnum,DWORD cbBuf,PDWORD pcbNeeded,PDWORD pcReturned)1876c2c66affSColin Finck EnumPrintersW(DWORD Flags, PWSTR Name, DWORD Level, PBYTE pPrinterEnum, DWORD cbBuf, PDWORD pcbNeeded, PDWORD pcReturned)
1877c2c66affSColin Finck {
1878c2c66affSColin Finck     DWORD dwErrorCode;
1879c2c66affSColin Finck 
18801f6f08ecSColin Finck     TRACE("EnumPrintersW(%lu, %S, %lu, %p, %lu, %p, %p)\n", Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
18811f6f08ecSColin Finck 
1882c2c66affSColin Finck     // Dismiss invalid levels already at this point.
1883c2c66affSColin Finck     if (Level == 3 || Level > 5)
1884c2c66affSColin Finck     {
1885c2c66affSColin Finck         dwErrorCode = ERROR_INVALID_LEVEL;
1886c2c66affSColin Finck         goto Cleanup;
1887c2c66affSColin Finck     }
1888c2c66affSColin Finck 
1889c2c66affSColin Finck     if (cbBuf && pPrinterEnum)
1890c2c66affSColin Finck         ZeroMemory(pPrinterEnum, cbBuf);
1891c2c66affSColin Finck 
1892c2c66affSColin Finck     // Do the RPC call
1893c2c66affSColin Finck     RpcTryExcept
1894c2c66affSColin Finck     {
1895c2c66affSColin Finck         dwErrorCode = _RpcEnumPrinters(Flags, Name, Level, pPrinterEnum, cbBuf, pcbNeeded, pcReturned);
1896c2c66affSColin Finck     }
1897c2c66affSColin Finck     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
1898c2c66affSColin Finck     {
1899c2c66affSColin Finck         dwErrorCode = RpcExceptionCode();
1900c2c66affSColin Finck         ERR("_RpcEnumPrinters failed with exception code %lu!\n", dwErrorCode);
1901c2c66affSColin Finck     }
1902c2c66affSColin Finck     RpcEndExcept;
1903c2c66affSColin Finck 
1904c2c66affSColin Finck     if (dwErrorCode == ERROR_SUCCESS)
1905c2c66affSColin Finck     {
190622ffe530SColin Finck         // Replace relative offset addresses in the output by absolute pointers.
190722ffe530SColin Finck         ASSERT(Level <= 9);
190822ffe530SColin Finck         MarshallUpStructuresArray(cbBuf, pPrinterEnum, *pcReturned, pPrinterInfoMarshalling[Level]->pInfo, pPrinterInfoMarshalling[Level]->cbStructureSize, TRUE);
1909c2c66affSColin Finck     }
1910c2c66affSColin Finck 
1911c2c66affSColin Finck Cleanup:
1912c2c66affSColin Finck     SetLastError(dwErrorCode);
1913c2c66affSColin Finck     return (dwErrorCode == ERROR_SUCCESS);
1914c2c66affSColin Finck }
1915c2c66affSColin Finck 
1916c2c66affSColin Finck BOOL WINAPI
FlushPrinter(HANDLE hPrinter,PVOID pBuf,DWORD cbBuf,PDWORD pcWritten,DWORD cSleep)191746b91659SColin Finck FlushPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten, DWORD cSleep)
191846b91659SColin Finck {
191946b91659SColin Finck     TRACE("FlushPrinter(%p, %p, %lu, %p, %lu)\n", hPrinter, pBuf, cbBuf, pcWritten, cSleep);
192046b91659SColin Finck     UNIMPLEMENTED;
192146b91659SColin Finck     return FALSE;
192246b91659SColin Finck }
192346b91659SColin Finck 
192446b91659SColin Finck BOOL WINAPI
GetDefaultPrinterA(LPSTR pszBuffer,LPDWORD pcchBuffer)1925c2c66affSColin Finck GetDefaultPrinterA(LPSTR pszBuffer, LPDWORD pcchBuffer)
1926c2c66affSColin Finck {
1927c2c66affSColin Finck     DWORD dwErrorCode;
1928c2c66affSColin Finck     PWSTR pwszBuffer = NULL;
1929c2c66affSColin Finck 
19301f6f08ecSColin Finck     TRACE("GetDefaultPrinterA(%p, %p)\n", pszBuffer, pcchBuffer);
19311f6f08ecSColin Finck 
1932c2c66affSColin Finck     // Sanity check.
1933c2c66affSColin Finck     if (!pcchBuffer)
1934c2c66affSColin Finck     {
1935c2c66affSColin Finck         dwErrorCode = ERROR_INVALID_PARAMETER;
1936c2c66affSColin Finck         goto Cleanup;
1937c2c66affSColin Finck     }
1938c2c66affSColin Finck 
1939c2c66affSColin Finck     // Check if an ANSI buffer was given and if so, allocate a Unicode buffer of the same size.
1940c2c66affSColin Finck     if (pszBuffer && *pcchBuffer)
1941c2c66affSColin Finck     {
1942c2c66affSColin Finck         pwszBuffer = HeapAlloc(hProcessHeap, 0, *pcchBuffer * sizeof(WCHAR));
1943c2c66affSColin Finck         if (!pwszBuffer)
1944c2c66affSColin Finck         {
1945c2c66affSColin Finck             dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
1946c2c66affSColin Finck             ERR("HeapAlloc failed!\n");
1947c2c66affSColin Finck             goto Cleanup;
1948c2c66affSColin Finck         }
1949c2c66affSColin Finck     }
1950c2c66affSColin Finck 
1951c2c66affSColin Finck     if (!GetDefaultPrinterW(pwszBuffer, pcchBuffer))
1952c2c66affSColin Finck     {
1953c2c66affSColin Finck         dwErrorCode = GetLastError();
1954c2c66affSColin Finck         goto Cleanup;
1955c2c66affSColin Finck     }
1956c2c66affSColin Finck 
195745b9b5c1SColin Finck     // We successfully got a string in pwszBuffer, so convert the Unicode string to ANSI.
195845b9b5c1SColin Finck     WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, pszBuffer, *pcchBuffer, NULL, NULL);
195945b9b5c1SColin Finck 
1960c2c66affSColin Finck     dwErrorCode = ERROR_SUCCESS;
1961c2c66affSColin Finck 
1962c2c66affSColin Finck Cleanup:
1963c2c66affSColin Finck     if (pwszBuffer)
1964c2c66affSColin Finck         HeapFree(hProcessHeap, 0, pwszBuffer);
1965c2c66affSColin Finck 
1966c2c66affSColin Finck     SetLastError(dwErrorCode);
1967c2c66affSColin Finck     return (dwErrorCode == ERROR_SUCCESS);
1968c2c66affSColin Finck }
1969c2c66affSColin Finck 
1970c2c66affSColin Finck BOOL WINAPI
GetDefaultPrinterW(LPWSTR pszBuffer,LPDWORD pcchBuffer)1971c2c66affSColin Finck GetDefaultPrinterW(LPWSTR pszBuffer, LPDWORD pcchBuffer)
1972c2c66affSColin Finck {
1973c2c66affSColin Finck     DWORD cbNeeded;
1974c2c66affSColin Finck     DWORD cchInputBuffer;
1975c2c66affSColin Finck     DWORD dwErrorCode;
1976c2c66affSColin Finck     HKEY hWindowsKey = NULL;
1977c2c66affSColin Finck     PWSTR pwszDevice = NULL;
1978c2c66affSColin Finck     PWSTR pwszComma;
1979c2c66affSColin Finck 
19801f6f08ecSColin Finck     TRACE("GetDefaultPrinterW(%p, %p)\n", pszBuffer, pcchBuffer);
19811f6f08ecSColin Finck 
1982c2c66affSColin Finck     // Sanity check.
1983c2c66affSColin Finck     if (!pcchBuffer)
1984c2c66affSColin Finck     {
1985c2c66affSColin Finck         dwErrorCode = ERROR_INVALID_PARAMETER;
1986c2c66affSColin Finck         goto Cleanup;
1987c2c66affSColin Finck     }
1988c2c66affSColin Finck 
1989c2c66affSColin Finck     cchInputBuffer = *pcchBuffer;
1990c2c66affSColin Finck 
1991c2c66affSColin Finck     // Open the registry key where the default printer for the current user is stored.
1992c2c66affSColin Finck     dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszWindowsKey, 0, KEY_READ, &hWindowsKey);
1993c2c66affSColin Finck     if (dwErrorCode != ERROR_SUCCESS)
1994c2c66affSColin Finck     {
1995c2c66affSColin Finck         ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
1996c2c66affSColin Finck         goto Cleanup;
1997c2c66affSColin Finck     }
1998c2c66affSColin Finck 
1999c2c66affSColin Finck     // Determine the size of the required buffer.
2000c2c66affSColin Finck     dwErrorCode = (DWORD)RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, NULL, &cbNeeded);
2001c2c66affSColin Finck     if (dwErrorCode != ERROR_SUCCESS)
2002c2c66affSColin Finck     {
2003c2c66affSColin Finck         ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
2004c2c66affSColin Finck         goto Cleanup;
2005c2c66affSColin Finck     }
2006c2c66affSColin Finck 
2007c2c66affSColin Finck     // Allocate it.
2008c2c66affSColin Finck     pwszDevice = HeapAlloc(hProcessHeap, 0, cbNeeded);
2009c2c66affSColin Finck     if (!pwszDevice)
2010c2c66affSColin Finck     {
2011c2c66affSColin Finck         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2012c2c66affSColin Finck         ERR("HeapAlloc failed!\n");
2013c2c66affSColin Finck         goto Cleanup;
2014c2c66affSColin Finck     }
2015c2c66affSColin Finck 
2016c2c66affSColin Finck     // Now get the actual value.
2017c2c66affSColin Finck     dwErrorCode = RegQueryValueExW(hWindowsKey, wszDeviceValue, NULL, NULL, (PBYTE)pwszDevice, &cbNeeded);
2018c2c66affSColin Finck     if (dwErrorCode != ERROR_SUCCESS)
2019c2c66affSColin Finck     {
2020c2c66affSColin Finck         ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
2021c2c66affSColin Finck         goto Cleanup;
2022c2c66affSColin Finck     }
2023c2c66affSColin Finck 
2024c2c66affSColin Finck     // We get a string "<Printer Name>,winspool,<Port>:".
2025c2c66affSColin Finck     // Extract the printer name from it.
2026c2c66affSColin Finck     pwszComma = wcschr(pwszDevice, L',');
2027c2c66affSColin Finck     if (!pwszComma)
2028c2c66affSColin Finck     {
2029c2c66affSColin Finck         ERR("Found no or invalid default printer: %S!\n", pwszDevice);
2030c2c66affSColin Finck         dwErrorCode = ERROR_INVALID_NAME;
2031c2c66affSColin Finck         goto Cleanup;
2032c2c66affSColin Finck     }
2033c2c66affSColin Finck 
2034c2c66affSColin Finck     // Store the length of the Printer Name (including the terminating NUL character!) in *pcchBuffer.
2035c2c66affSColin Finck     *pcchBuffer = pwszComma - pwszDevice + 1;
2036c2c66affSColin Finck 
2037c2c66affSColin Finck     // Check if the supplied buffer is large enough.
20387bffb703SJames Tabor     if ( !pszBuffer || cchInputBuffer < *pcchBuffer)
2039c2c66affSColin Finck     {
2040c2c66affSColin Finck         dwErrorCode = ERROR_INSUFFICIENT_BUFFER;
2041c2c66affSColin Finck         goto Cleanup;
2042c2c66affSColin Finck     }
2043c2c66affSColin Finck 
2044c2c66affSColin Finck     // Copy the default printer.
2045c2c66affSColin Finck     *pwszComma = 0;
2046c2c66affSColin Finck     CopyMemory(pszBuffer, pwszDevice, *pcchBuffer * sizeof(WCHAR));
2047c2c66affSColin Finck 
2048c2c66affSColin Finck     dwErrorCode = ERROR_SUCCESS;
2049c2c66affSColin Finck 
2050c2c66affSColin Finck Cleanup:
2051c2c66affSColin Finck     if (hWindowsKey)
2052c2c66affSColin Finck         RegCloseKey(hWindowsKey);
2053c2c66affSColin Finck 
2054c2c66affSColin Finck     if (pwszDevice)
2055c2c66affSColin Finck         HeapFree(hProcessHeap, 0, pwszDevice);
2056c2c66affSColin Finck 
2057c2c66affSColin Finck     SetLastError(dwErrorCode);
2058c2c66affSColin Finck     return (dwErrorCode == ERROR_SUCCESS);
2059c2c66affSColin Finck }
2060c2c66affSColin Finck 
2061c2c66affSColin Finck BOOL WINAPI
GetPrinterA(HANDLE hPrinter,DWORD Level,LPBYTE pPrinter,DWORD cbBuf,LPDWORD pcbNeeded)2062c2c66affSColin Finck GetPrinterA(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
2063c2c66affSColin Finck {
2064373a8dbbSSerge Gautherie     DWORD dwErrorCode;
2065ecde3768SDoug Lyons     PPRINTER_INFO_1A ppi1a = (PPRINTER_INFO_1A)pPrinter;
2066ecde3768SDoug Lyons     PPRINTER_INFO_1W ppi1w = (PPRINTER_INFO_1W)pPrinter;
2067ecde3768SDoug Lyons     PPRINTER_INFO_2A ppi2a = (PPRINTER_INFO_2A)pPrinter;
2068ecde3768SDoug Lyons     PPRINTER_INFO_2W ppi2w = (PPRINTER_INFO_2W)pPrinter;
2069ecde3768SDoug Lyons     PPRINTER_INFO_4A ppi4a = (PPRINTER_INFO_4A)pPrinter;
2070ecde3768SDoug Lyons     PPRINTER_INFO_4W ppi4w = (PPRINTER_INFO_4W)pPrinter;
2071ecde3768SDoug Lyons     PPRINTER_INFO_5A ppi5a = (PPRINTER_INFO_5A)pPrinter;
2072ecde3768SDoug Lyons     PPRINTER_INFO_5W ppi5w = (PPRINTER_INFO_5W)pPrinter;
2073ecde3768SDoug Lyons     PPRINTER_INFO_7A ppi7a = (PPRINTER_INFO_7A)pPrinter;
2074ecde3768SDoug Lyons     PPRINTER_INFO_7W ppi7w = (PPRINTER_INFO_7W)pPrinter;
20757bffb703SJames Tabor     PPRINTER_INFO_9A ppi9a = (PPRINTER_INFO_9A)pPrinter;
20767bffb703SJames Tabor     PPRINTER_INFO_9W ppi9w = (PPRINTER_INFO_9W)pPrinter;
2077ecde3768SDoug Lyons     DWORD cch;
2078ecde3768SDoug Lyons 
20791f6f08ecSColin Finck     TRACE("GetPrinterA(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
2080ecde3768SDoug Lyons 
2081ecde3768SDoug Lyons     // Check for invalid levels here for early error return. Should be 1-9.
2082ecde3768SDoug Lyons     if (Level <  1 || Level > 9)
2083ecde3768SDoug Lyons     {
2084373a8dbbSSerge Gautherie         dwErrorCode = ERROR_INVALID_LEVEL;
2085ecde3768SDoug Lyons         ERR("Invalid Level!\n");
2086ecde3768SDoug Lyons         goto Cleanup;
2087ecde3768SDoug Lyons     }
2088ecde3768SDoug Lyons 
20894b1ae540SSerge Gautherie     if (!GetPrinterW(hPrinter, Level, pPrinter, cbBuf, pcbNeeded))
2090ecde3768SDoug Lyons     {
2091373a8dbbSSerge Gautherie         dwErrorCode = GetLastError();
2092ecde3768SDoug Lyons         goto Cleanup;
2093ecde3768SDoug Lyons     }
2094ecde3768SDoug Lyons 
2095ecde3768SDoug Lyons     switch (Level)
2096ecde3768SDoug Lyons     {
2097ecde3768SDoug Lyons         case 1:
2098ecde3768SDoug Lyons         {
2099ecde3768SDoug Lyons             if (ppi1w->pDescription)
2100ecde3768SDoug Lyons             {
2101ecde3768SDoug Lyons                 PSTR pszDescription;
2102ecde3768SDoug Lyons 
2103ecde3768SDoug Lyons                 // Convert Unicode pDescription to a ANSI string pszDescription.
2104ecde3768SDoug Lyons                 cch = wcslen(ppi1w->pDescription);
2105ecde3768SDoug Lyons 
2106ecde3768SDoug Lyons                 pszDescription = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2107ecde3768SDoug Lyons                 if (!pszDescription)
2108ecde3768SDoug Lyons                 {
2109373a8dbbSSerge Gautherie                     dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2110ecde3768SDoug Lyons                     ERR("HeapAlloc failed!\n");
2111ecde3768SDoug Lyons                     goto Cleanup;
2112ecde3768SDoug Lyons                 }
2113ecde3768SDoug Lyons 
2114ecde3768SDoug Lyons                 WideCharToMultiByte(CP_ACP, 0, ppi1w->pDescription, -1, pszDescription, cch + 1, NULL, NULL);
2115ecde3768SDoug Lyons                 StringCchCopyA(ppi1a->pDescription, cch + 1, pszDescription);
2116ecde3768SDoug Lyons 
2117ecde3768SDoug Lyons                 HeapFree(hProcessHeap, 0, pszDescription);
2118ecde3768SDoug Lyons             }
2119ecde3768SDoug Lyons 
2120ecde3768SDoug Lyons             if (ppi1w->pName)
2121ecde3768SDoug Lyons             {
2122ecde3768SDoug Lyons                 PSTR pszName;
2123ecde3768SDoug Lyons 
2124ecde3768SDoug Lyons                 // Convert Unicode pName to a ANSI string pszName.
2125ecde3768SDoug Lyons                 cch = wcslen(ppi1w->pName);
2126ecde3768SDoug Lyons 
2127ecde3768SDoug Lyons                 pszName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2128ecde3768SDoug Lyons                 if (!pszName)
2129ecde3768SDoug Lyons                 {
2130373a8dbbSSerge Gautherie                     dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2131ecde3768SDoug Lyons                     ERR("HeapAlloc failed!\n");
2132ecde3768SDoug Lyons                     goto Cleanup;
2133ecde3768SDoug Lyons                 }
2134ecde3768SDoug Lyons 
2135ecde3768SDoug Lyons                 WideCharToMultiByte(CP_ACP, 0, ppi1w->pName, -1, pszName, cch + 1, NULL, NULL);
2136ecde3768SDoug Lyons                 StringCchCopyA(ppi1a->pName, cch + 1, pszName);
2137ecde3768SDoug Lyons 
2138ecde3768SDoug Lyons                 HeapFree(hProcessHeap, 0, pszName);
2139ecde3768SDoug Lyons             }
2140ecde3768SDoug Lyons 
2141ecde3768SDoug Lyons             if (ppi1w->pComment)
2142ecde3768SDoug Lyons             {
2143ecde3768SDoug Lyons                 PSTR pszComment;
2144ecde3768SDoug Lyons 
2145ecde3768SDoug Lyons                 // Convert Unicode pComment to a ANSI string pszComment.
2146ecde3768SDoug Lyons                 cch = wcslen(ppi1w->pComment);
2147ecde3768SDoug Lyons 
2148ecde3768SDoug Lyons                 pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2149ecde3768SDoug Lyons                 if (!pszComment)
2150ecde3768SDoug Lyons                 {
2151373a8dbbSSerge Gautherie                     dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2152ecde3768SDoug Lyons                     ERR("HeapAlloc failed!\n");
2153ecde3768SDoug Lyons                     goto Cleanup;
2154ecde3768SDoug Lyons                 }
2155ecde3768SDoug Lyons 
2156ecde3768SDoug Lyons                 WideCharToMultiByte(CP_ACP, 0, ppi1w->pComment, -1, pszComment, cch + 1, NULL, NULL);
2157ecde3768SDoug Lyons                 StringCchCopyA(ppi1a->pComment, cch + 1, pszComment);
2158ecde3768SDoug Lyons 
2159ecde3768SDoug Lyons                 HeapFree(hProcessHeap, 0, pszComment);
2160ecde3768SDoug Lyons             }
2161ecde3768SDoug Lyons             break;
2162ecde3768SDoug Lyons         }
2163ecde3768SDoug Lyons 
2164ecde3768SDoug Lyons         case 2:
2165ecde3768SDoug Lyons         {
2166ecde3768SDoug Lyons             if (ppi2w->pServerName)
2167ecde3768SDoug Lyons             {
2168ecde3768SDoug Lyons                 PSTR pszServerName;
2169ecde3768SDoug Lyons 
2170ecde3768SDoug Lyons                 // Convert Unicode pServerName to a ANSI string pszServerName.
2171ecde3768SDoug Lyons                 cch = wcslen(ppi2w->pServerName);
2172ecde3768SDoug Lyons 
2173ecde3768SDoug Lyons                 pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2174ecde3768SDoug Lyons                 if (!pszServerName)
2175ecde3768SDoug Lyons                 {
2176373a8dbbSSerge Gautherie                     dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2177ecde3768SDoug Lyons                     ERR("HeapAlloc failed!\n");
2178ecde3768SDoug Lyons                     goto Cleanup;
2179ecde3768SDoug Lyons                 }
2180ecde3768SDoug Lyons 
2181ecde3768SDoug Lyons                 WideCharToMultiByte(CP_ACP, 0, ppi2w->pServerName, -1, pszServerName, cch + 1, NULL, NULL);
2182ecde3768SDoug Lyons                 StringCchCopyA(ppi2a->pServerName, cch + 1, pszServerName);
2183ecde3768SDoug Lyons 
2184ecde3768SDoug Lyons                 HeapFree(hProcessHeap, 0, pszServerName);
2185ecde3768SDoug Lyons             }
2186ecde3768SDoug Lyons 
2187ecde3768SDoug Lyons             if (ppi2w->pPrinterName)
2188ecde3768SDoug Lyons             {
2189ecde3768SDoug Lyons                 PSTR pszPrinterName;
2190ecde3768SDoug Lyons 
2191ecde3768SDoug Lyons                 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
2192ecde3768SDoug Lyons                 cch = wcslen(ppi2w->pPrinterName);
2193ecde3768SDoug Lyons 
2194ecde3768SDoug Lyons                 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2195ecde3768SDoug Lyons                 if (!pszPrinterName)
2196ecde3768SDoug Lyons                 {
2197373a8dbbSSerge Gautherie                     dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2198ecde3768SDoug Lyons                     ERR("HeapAlloc failed!\n");
2199ecde3768SDoug Lyons                     goto Cleanup;
2200ecde3768SDoug Lyons                 }
2201ecde3768SDoug Lyons 
2202ecde3768SDoug Lyons                 WideCharToMultiByte(CP_ACP, 0, ppi2w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
2203ecde3768SDoug Lyons                 StringCchCopyA(ppi2a->pPrinterName, cch + 1, pszPrinterName);
2204ecde3768SDoug Lyons 
2205ecde3768SDoug Lyons                 HeapFree(hProcessHeap, 0, pszPrinterName);
2206ecde3768SDoug Lyons             }
2207ecde3768SDoug Lyons 
2208ecde3768SDoug Lyons             if (ppi2w->pShareName)
2209ecde3768SDoug Lyons             {
2210ecde3768SDoug Lyons                 PSTR pszShareName;
2211ecde3768SDoug Lyons 
2212ecde3768SDoug Lyons                 // Convert Unicode pShareName to a ANSI string pszShareName.
2213ecde3768SDoug Lyons                 cch = wcslen(ppi2w->pShareName);
2214ecde3768SDoug Lyons 
2215ecde3768SDoug Lyons                 pszShareName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2216ecde3768SDoug Lyons                 if (!pszShareName)
2217ecde3768SDoug Lyons                 {
2218373a8dbbSSerge Gautherie                     dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2219ecde3768SDoug Lyons                     ERR("HeapAlloc failed!\n");
2220ecde3768SDoug Lyons                     goto Cleanup;
2221ecde3768SDoug Lyons                 }
2222ecde3768SDoug Lyons 
2223ecde3768SDoug Lyons                 WideCharToMultiByte(CP_ACP, 0, ppi2w->pShareName, -1, pszShareName, cch + 1, NULL, NULL);
2224ecde3768SDoug Lyons                 StringCchCopyA(ppi2a->pShareName, cch + 1, pszShareName);
2225ecde3768SDoug Lyons 
2226ecde3768SDoug Lyons                 HeapFree(hProcessHeap, 0, pszShareName);
2227ecde3768SDoug Lyons             }
2228ecde3768SDoug Lyons 
2229ecde3768SDoug Lyons             if (ppi2w->pPortName)
2230ecde3768SDoug Lyons             {
2231ecde3768SDoug Lyons                 PSTR pszPortName;
2232ecde3768SDoug Lyons 
2233ecde3768SDoug Lyons                 // Convert Unicode pPortName to a ANSI string pszPortName.
2234ecde3768SDoug Lyons                 cch = wcslen(ppi2w->pPortName);
2235ecde3768SDoug Lyons 
2236ecde3768SDoug Lyons                 pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2237ecde3768SDoug Lyons                 if (!pszPortName)
2238ecde3768SDoug Lyons                 {
2239373a8dbbSSerge Gautherie                     dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2240ecde3768SDoug Lyons                     ERR("HeapAlloc failed!\n");
2241ecde3768SDoug Lyons                     goto Cleanup;
2242ecde3768SDoug Lyons                 }
2243ecde3768SDoug Lyons 
2244ecde3768SDoug Lyons                 WideCharToMultiByte(CP_ACP, 0, ppi2w->pPortName, -1, pszPortName, cch + 1, NULL, NULL);
2245ecde3768SDoug Lyons                 StringCchCopyA(ppi2a->pPortName, cch + 1, pszPortName);
2246ecde3768SDoug Lyons 
2247ecde3768SDoug Lyons                 HeapFree(hProcessHeap, 0, pszPortName);
2248ecde3768SDoug Lyons             }
2249ecde3768SDoug Lyons 
2250ecde3768SDoug Lyons             if (ppi2w->pDriverName)
2251ecde3768SDoug Lyons             {
2252ecde3768SDoug Lyons                 PSTR pszDriverName;
2253ecde3768SDoug Lyons 
2254ecde3768SDoug Lyons                 // Convert Unicode pDriverName to a ANSI string pszDriverName.
2255ecde3768SDoug Lyons                 cch = wcslen(ppi2w->pDriverName);
2256ecde3768SDoug Lyons 
2257ecde3768SDoug Lyons                 pszDriverName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2258ecde3768SDoug Lyons                 if (!pszDriverName)
2259ecde3768SDoug Lyons                 {
2260373a8dbbSSerge Gautherie                     dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2261ecde3768SDoug Lyons                     ERR("HeapAlloc failed!\n");
2262ecde3768SDoug Lyons                     goto Cleanup;
2263ecde3768SDoug Lyons                 }
2264ecde3768SDoug Lyons 
2265ecde3768SDoug Lyons                 WideCharToMultiByte(CP_ACP, 0, ppi2w->pDriverName, -1, pszDriverName, cch + 1, NULL, NULL);
2266ecde3768SDoug Lyons                 StringCchCopyA(ppi2a->pDriverName, cch + 1, pszDriverName);
2267ecde3768SDoug Lyons 
2268ecde3768SDoug Lyons                 HeapFree(hProcessHeap, 0, pszDriverName);
2269ecde3768SDoug Lyons             }
2270ecde3768SDoug Lyons 
2271ecde3768SDoug Lyons             if (ppi2w->pComment)
2272ecde3768SDoug Lyons             {
2273ecde3768SDoug Lyons                 PSTR pszComment;
2274ecde3768SDoug Lyons 
2275ecde3768SDoug Lyons                 // Convert Unicode pComment to a ANSI string pszComment.
2276ecde3768SDoug Lyons                 cch = wcslen(ppi2w->pComment);
2277ecde3768SDoug Lyons 
2278ecde3768SDoug Lyons                 pszComment = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2279ecde3768SDoug Lyons                 if (!pszComment)
2280ecde3768SDoug Lyons                 {
2281373a8dbbSSerge Gautherie                     dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2282ecde3768SDoug Lyons                     ERR("HeapAlloc failed!\n");
2283ecde3768SDoug Lyons                     goto Cleanup;
2284ecde3768SDoug Lyons                 }
2285ecde3768SDoug Lyons 
2286ecde3768SDoug Lyons                 WideCharToMultiByte(CP_ACP, 0, ppi2w->pComment, -1, pszComment, cch + 1, NULL, NULL);
2287ecde3768SDoug Lyons                 StringCchCopyA(ppi2a->pComment, cch + 1, pszComment);
2288ecde3768SDoug Lyons 
2289ecde3768SDoug Lyons                 HeapFree(hProcessHeap, 0, pszComment);
2290ecde3768SDoug Lyons             }
2291ecde3768SDoug Lyons 
2292ecde3768SDoug Lyons             if (ppi2w->pLocation)
2293ecde3768SDoug Lyons             {
2294ecde3768SDoug Lyons                 PSTR pszLocation;
2295ecde3768SDoug Lyons 
2296ecde3768SDoug Lyons                 // Convert Unicode pLocation to a ANSI string pszLocation.
2297ecde3768SDoug Lyons                 cch = wcslen(ppi2w->pLocation);
2298ecde3768SDoug Lyons 
2299ecde3768SDoug Lyons                 pszLocation = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2300ecde3768SDoug Lyons                 if (!pszLocation)
2301ecde3768SDoug Lyons                 {
2302373a8dbbSSerge Gautherie                     dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2303ecde3768SDoug Lyons                     ERR("HeapAlloc failed!\n");
2304ecde3768SDoug Lyons                     goto Cleanup;
2305ecde3768SDoug Lyons                 }
2306ecde3768SDoug Lyons 
2307ecde3768SDoug Lyons                 WideCharToMultiByte(CP_ACP, 0, ppi2w->pLocation, -1, pszLocation, cch + 1, NULL, NULL);
2308ecde3768SDoug Lyons                 StringCchCopyA(ppi2a->pLocation, cch + 1, pszLocation);
2309ecde3768SDoug Lyons 
2310ecde3768SDoug Lyons                 HeapFree(hProcessHeap, 0, pszLocation);
2311ecde3768SDoug Lyons             }
2312ecde3768SDoug Lyons 
2313ecde3768SDoug Lyons             if (ppi2w->pSepFile)
2314ecde3768SDoug Lyons             {
2315ecde3768SDoug Lyons                 PSTR pszSepFile;
2316ecde3768SDoug Lyons 
2317ecde3768SDoug Lyons                 // Convert Unicode pSepFile to a ANSI string pszSepFile.
2318ecde3768SDoug Lyons                 cch = wcslen(ppi2w->pSepFile);
2319ecde3768SDoug Lyons 
2320ecde3768SDoug Lyons                 pszSepFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2321ecde3768SDoug Lyons                 if (!pszSepFile)
2322ecde3768SDoug Lyons                 {
2323373a8dbbSSerge Gautherie                     dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2324ecde3768SDoug Lyons                     ERR("HeapAlloc failed!\n");
2325ecde3768SDoug Lyons                     goto Cleanup;
2326ecde3768SDoug Lyons                 }
2327ecde3768SDoug Lyons 
2328ecde3768SDoug Lyons                 WideCharToMultiByte(CP_ACP, 0, ppi2w->pSepFile, -1, pszSepFile, cch + 1, NULL, NULL);
2329ecde3768SDoug Lyons                 StringCchCopyA(ppi2a->pSepFile, cch + 1, pszSepFile);
2330ecde3768SDoug Lyons 
2331ecde3768SDoug Lyons                 HeapFree(hProcessHeap, 0, pszSepFile);
2332ecde3768SDoug Lyons             }
2333ecde3768SDoug Lyons 
2334ecde3768SDoug Lyons             if (ppi2w->pPrintProcessor)
2335ecde3768SDoug Lyons             {
2336ecde3768SDoug Lyons                 PSTR pszPrintProcessor;
2337ecde3768SDoug Lyons 
2338ecde3768SDoug Lyons                 // Convert Unicode pPrintProcessor to a ANSI string pszPrintProcessor.
2339ecde3768SDoug Lyons                 cch = wcslen(ppi2w->pPrintProcessor);
2340ecde3768SDoug Lyons 
2341ecde3768SDoug Lyons                 pszPrintProcessor = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2342ecde3768SDoug Lyons                 if (!pszPrintProcessor)
2343ecde3768SDoug Lyons                 {
2344373a8dbbSSerge Gautherie                     dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2345ecde3768SDoug Lyons                     ERR("HeapAlloc failed!\n");
2346ecde3768SDoug Lyons                     goto Cleanup;
2347ecde3768SDoug Lyons                 }
2348ecde3768SDoug Lyons 
2349ecde3768SDoug Lyons                 WideCharToMultiByte(CP_ACP, 0, ppi2w->pPrintProcessor, -1, pszPrintProcessor, cch + 1, NULL, NULL);
2350ecde3768SDoug Lyons                 StringCchCopyA(ppi2a->pPrintProcessor, cch + 1, pszPrintProcessor);
2351ecde3768SDoug Lyons 
2352ecde3768SDoug Lyons                 HeapFree(hProcessHeap, 0, pszPrintProcessor);
2353ecde3768SDoug Lyons             }
2354ecde3768SDoug Lyons 
2355ecde3768SDoug Lyons             if (ppi2w->pDatatype)
2356ecde3768SDoug Lyons             {
2357ecde3768SDoug Lyons                 PSTR pszDatatype;
2358ecde3768SDoug Lyons 
2359ecde3768SDoug Lyons                 // Convert Unicode pDatatype to a ANSI string pszDatatype.
2360ecde3768SDoug Lyons                 cch = wcslen(ppi2w->pDatatype);
2361ecde3768SDoug Lyons 
2362ecde3768SDoug Lyons                 pszDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2363ecde3768SDoug Lyons                 if (!pszDatatype)
2364ecde3768SDoug Lyons                 {
2365373a8dbbSSerge Gautherie                     dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2366ecde3768SDoug Lyons                     ERR("HeapAlloc failed!\n");
2367ecde3768SDoug Lyons                     goto Cleanup;
2368ecde3768SDoug Lyons                 }
2369ecde3768SDoug Lyons 
2370ecde3768SDoug Lyons                 WideCharToMultiByte(CP_ACP, 0, ppi2w->pDatatype, -1, pszDatatype, cch + 1, NULL, NULL);
2371ecde3768SDoug Lyons                 StringCchCopyA(ppi2a->pDatatype, cch + 1, pszDatatype);
2372ecde3768SDoug Lyons 
2373ecde3768SDoug Lyons                 HeapFree(hProcessHeap, 0, pszDatatype);
2374ecde3768SDoug Lyons             }
2375ecde3768SDoug Lyons 
2376ecde3768SDoug Lyons             if (ppi2w->pParameters)
2377ecde3768SDoug Lyons             {
2378ecde3768SDoug Lyons                 PSTR pszParameters;
2379ecde3768SDoug Lyons 
2380ecde3768SDoug Lyons                 // Convert Unicode pParameters to a ANSI string pszParameters.
2381ecde3768SDoug Lyons                 cch = wcslen(ppi2w->pParameters);
2382ecde3768SDoug Lyons 
2383ecde3768SDoug Lyons                 pszParameters = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2384ecde3768SDoug Lyons                 if (!pszParameters)
2385ecde3768SDoug Lyons                 {
2386373a8dbbSSerge Gautherie                     dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2387ecde3768SDoug Lyons                     ERR("HeapAlloc failed!\n");
2388ecde3768SDoug Lyons                     goto Cleanup;
2389ecde3768SDoug Lyons                 }
2390ecde3768SDoug Lyons 
2391ecde3768SDoug Lyons                 WideCharToMultiByte(CP_ACP, 0, ppi2w->pParameters, -1, pszParameters, cch + 1, NULL, NULL);
2392ecde3768SDoug Lyons                 StringCchCopyA(ppi2a->pParameters, cch + 1, pszParameters);
2393ecde3768SDoug Lyons 
2394ecde3768SDoug Lyons                 HeapFree(hProcessHeap, 0, pszParameters);
2395ecde3768SDoug Lyons             }
23967bffb703SJames Tabor             if ( ppi2w->pDevMode )
23977bffb703SJames Tabor             {
23987bffb703SJames Tabor                 RosConvertUnicodeDevModeToAnsiDevmode( ppi2w->pDevMode, ppi2a->pDevMode );
23997bffb703SJames Tabor             }
2400ecde3768SDoug Lyons             break;
2401ecde3768SDoug Lyons         }
2402ecde3768SDoug Lyons 
2403ecde3768SDoug Lyons         case 4:
2404ecde3768SDoug Lyons         {
2405ecde3768SDoug Lyons             if (ppi4w->pPrinterName)
2406ecde3768SDoug Lyons             {
2407ecde3768SDoug Lyons                 PSTR pszPrinterName;
2408ecde3768SDoug Lyons 
2409ecde3768SDoug Lyons                 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
2410ecde3768SDoug Lyons                 cch = wcslen(ppi4w->pPrinterName);
2411ecde3768SDoug Lyons 
2412ecde3768SDoug Lyons                 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2413ecde3768SDoug Lyons                 if (!pszPrinterName)
2414ecde3768SDoug Lyons                 {
2415373a8dbbSSerge Gautherie                     dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2416ecde3768SDoug Lyons                     ERR("HeapAlloc failed!\n");
2417ecde3768SDoug Lyons                     goto Cleanup;
2418ecde3768SDoug Lyons                 }
2419ecde3768SDoug Lyons 
2420ecde3768SDoug Lyons                 WideCharToMultiByte(CP_ACP, 0, ppi4w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
2421ecde3768SDoug Lyons                 StringCchCopyA(ppi4a->pPrinterName, cch + 1, pszPrinterName);
2422ecde3768SDoug Lyons 
2423ecde3768SDoug Lyons                 HeapFree(hProcessHeap, 0, pszPrinterName);
2424ecde3768SDoug Lyons             }
2425ecde3768SDoug Lyons 
2426ecde3768SDoug Lyons             if (ppi4w->pServerName)
2427ecde3768SDoug Lyons             {
2428ecde3768SDoug Lyons                 PSTR pszServerName;
2429ecde3768SDoug Lyons 
2430ecde3768SDoug Lyons                 // Convert Unicode pServerName to a ANSI string pszServerName.
2431ecde3768SDoug Lyons                 cch = wcslen(ppi4w->pServerName);
2432ecde3768SDoug Lyons 
2433ecde3768SDoug Lyons                 pszServerName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2434ecde3768SDoug Lyons                 if (!pszServerName)
2435ecde3768SDoug Lyons                 {
2436373a8dbbSSerge Gautherie                     dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2437ecde3768SDoug Lyons                     ERR("HeapAlloc failed!\n");
2438ecde3768SDoug Lyons                     goto Cleanup;
2439ecde3768SDoug Lyons                 }
2440ecde3768SDoug Lyons 
2441ecde3768SDoug Lyons                 WideCharToMultiByte(CP_ACP, 0, ppi4w->pServerName, -1, pszServerName, cch + 1, NULL, NULL);
2442ecde3768SDoug Lyons                 StringCchCopyA(ppi4a->pServerName, cch + 1, pszServerName);
2443ecde3768SDoug Lyons 
2444ecde3768SDoug Lyons                 HeapFree(hProcessHeap, 0, pszServerName);
2445ecde3768SDoug Lyons             }
2446ecde3768SDoug Lyons             break;
2447ecde3768SDoug Lyons         }
2448ecde3768SDoug Lyons 
2449ecde3768SDoug Lyons         case 5:
2450ecde3768SDoug Lyons         {
2451ecde3768SDoug Lyons             if (ppi5w->pPrinterName)
2452ecde3768SDoug Lyons             {
2453ecde3768SDoug Lyons                 PSTR pszPrinterName;
2454ecde3768SDoug Lyons 
2455ecde3768SDoug Lyons                 // Convert Unicode pPrinterName to a ANSI string pszPrinterName.
2456ecde3768SDoug Lyons                 cch = wcslen(ppi5w->pPrinterName);
2457ecde3768SDoug Lyons 
2458ecde3768SDoug Lyons                 pszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2459ecde3768SDoug Lyons                 if (!pszPrinterName)
2460ecde3768SDoug Lyons                 {
2461373a8dbbSSerge Gautherie                     dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2462ecde3768SDoug Lyons                     ERR("HeapAlloc failed!\n");
2463ecde3768SDoug Lyons                     goto Cleanup;
2464ecde3768SDoug Lyons                 }
2465ecde3768SDoug Lyons 
2466ecde3768SDoug Lyons                 WideCharToMultiByte(CP_ACP, 0, ppi5w->pPrinterName, -1, pszPrinterName, cch + 1, NULL, NULL);
2467ecde3768SDoug Lyons                 StringCchCopyA(ppi5a->pPrinterName, cch + 1, pszPrinterName);
2468ecde3768SDoug Lyons 
2469ecde3768SDoug Lyons                 HeapFree(hProcessHeap, 0, pszPrinterName);
2470ecde3768SDoug Lyons             }
2471ecde3768SDoug Lyons 
2472ecde3768SDoug Lyons             if (ppi5w->pPortName)
2473ecde3768SDoug Lyons             {
2474ecde3768SDoug Lyons                 PSTR pszPortName;
2475ecde3768SDoug Lyons 
2476ecde3768SDoug Lyons                 // Convert Unicode pPortName to a ANSI string pszPortName.
2477ecde3768SDoug Lyons                 cch = wcslen(ppi5w->pPortName);
2478ecde3768SDoug Lyons 
2479ecde3768SDoug Lyons                 pszPortName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2480ecde3768SDoug Lyons                 if (!pszPortName)
2481ecde3768SDoug Lyons                 {
2482373a8dbbSSerge Gautherie                     dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2483ecde3768SDoug Lyons                     ERR("HeapAlloc failed!\n");
2484ecde3768SDoug Lyons                     goto Cleanup;
2485ecde3768SDoug Lyons                 }
2486ecde3768SDoug Lyons 
2487ecde3768SDoug Lyons                 WideCharToMultiByte(CP_ACP, 0, ppi5w->pPortName, -1, pszPortName, cch + 1, NULL, NULL);
2488ecde3768SDoug Lyons                 StringCchCopyA(ppi5a->pPortName, cch + 1, pszPortName);
2489ecde3768SDoug Lyons 
2490ecde3768SDoug Lyons                 HeapFree(hProcessHeap, 0, pszPortName);
2491ecde3768SDoug Lyons             }
2492ecde3768SDoug Lyons             break;
2493ecde3768SDoug Lyons         }
2494ecde3768SDoug Lyons 
2495ecde3768SDoug Lyons         case 7:
2496ecde3768SDoug Lyons         {
2497ecde3768SDoug Lyons             if (ppi7w->pszObjectGUID)
2498ecde3768SDoug Lyons             {
2499ecde3768SDoug Lyons                 PSTR pszaObjectGUID;
2500ecde3768SDoug Lyons 
2501ecde3768SDoug Lyons                 // Convert Unicode pszObjectGUID to a ANSI string pszaObjectGUID.
2502ecde3768SDoug Lyons                 cch = wcslen(ppi7w->pszObjectGUID);
2503ecde3768SDoug Lyons 
2504ecde3768SDoug Lyons                 pszaObjectGUID = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(CHAR));
2505ecde3768SDoug Lyons                 if (!pszaObjectGUID)
2506ecde3768SDoug Lyons                 {
2507373a8dbbSSerge Gautherie                     dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2508ecde3768SDoug Lyons                     ERR("HeapAlloc failed!\n");
2509ecde3768SDoug Lyons                     goto Cleanup;
2510ecde3768SDoug Lyons                 }
2511ecde3768SDoug Lyons 
2512ecde3768SDoug Lyons                 WideCharToMultiByte(CP_ACP, 0, ppi7w->pszObjectGUID, -1, pszaObjectGUID, cch + 1, NULL, NULL);
2513ecde3768SDoug Lyons                 StringCchCopyA(ppi7a->pszObjectGUID, cch + 1, pszaObjectGUID);
2514ecde3768SDoug Lyons 
2515ecde3768SDoug Lyons                 HeapFree(hProcessHeap, 0, pszaObjectGUID);
2516ecde3768SDoug Lyons             }
2517ecde3768SDoug Lyons         }
25187bffb703SJames Tabor             break;
25197bffb703SJames Tabor         case 8:
25207bffb703SJames Tabor         case 9:
25217bffb703SJames Tabor             RosConvertUnicodeDevModeToAnsiDevmode(ppi9w->pDevMode, ppi9a->pDevMode);
25227bffb703SJames Tabor             break;
2523ecde3768SDoug Lyons     }       // switch
2524ecde3768SDoug Lyons 
2525373a8dbbSSerge Gautherie     dwErrorCode = ERROR_SUCCESS;
2526373a8dbbSSerge Gautherie 
2527ecde3768SDoug Lyons Cleanup:
2528373a8dbbSSerge Gautherie     SetLastError(dwErrorCode);
2529373a8dbbSSerge Gautherie     return (dwErrorCode == ERROR_SUCCESS);
2530c2c66affSColin Finck }
2531c2c66affSColin Finck 
2532c2c66affSColin Finck BOOL WINAPI
GetPrinterW(HANDLE hPrinter,DWORD Level,LPBYTE pPrinter,DWORD cbBuf,LPDWORD pcbNeeded)2533c2c66affSColin Finck GetPrinterW(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter, DWORD cbBuf, LPDWORD pcbNeeded)
2534c2c66affSColin Finck {
2535c2c66affSColin Finck     DWORD dwErrorCode;
25363a69fd4eSColin Finck     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
2537c2c66affSColin Finck 
25381f6f08ecSColin Finck     TRACE("GetPrinterW(%p, %lu, %p, %lu, %p)\n", hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
25391f6f08ecSColin Finck 
25403a69fd4eSColin Finck     // Sanity checks.
25413a69fd4eSColin Finck     if (!pHandle)
25423a69fd4eSColin Finck     {
25433a69fd4eSColin Finck         dwErrorCode = ERROR_INVALID_HANDLE;
25443a69fd4eSColin Finck         goto Cleanup;
25453a69fd4eSColin Finck     }
25463a69fd4eSColin Finck 
2547c2c66affSColin Finck     // Dismiss invalid levels already at this point.
2548c2c66affSColin Finck     if (Level > 9)
2549c2c66affSColin Finck     {
2550c2c66affSColin Finck         dwErrorCode = ERROR_INVALID_LEVEL;
2551c2c66affSColin Finck         goto Cleanup;
2552c2c66affSColin Finck     }
2553c2c66affSColin Finck 
2554c2c66affSColin Finck     if (cbBuf && pPrinter)
2555c2c66affSColin Finck         ZeroMemory(pPrinter, cbBuf);
2556c2c66affSColin Finck 
2557c2c66affSColin Finck     // Do the RPC call
2558c2c66affSColin Finck     RpcTryExcept
2559c2c66affSColin Finck     {
25603a69fd4eSColin Finck         dwErrorCode = _RpcGetPrinter(pHandle->hPrinter, Level, pPrinter, cbBuf, pcbNeeded);
2561c2c66affSColin Finck     }
2562c2c66affSColin Finck     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2563c2c66affSColin Finck     {
2564c2c66affSColin Finck         dwErrorCode = RpcExceptionCode();
2565c2c66affSColin Finck         ERR("_RpcGetPrinter failed with exception code %lu!\n", dwErrorCode);
2566c2c66affSColin Finck     }
2567c2c66affSColin Finck     RpcEndExcept;
2568c2c66affSColin Finck 
2569c2c66affSColin Finck     if (dwErrorCode == ERROR_SUCCESS)
2570c2c66affSColin Finck     {
257122ffe530SColin Finck         // Replace relative offset addresses in the output by absolute pointers.
257222ffe530SColin Finck         ASSERT(Level <= 9);
257322ffe530SColin Finck         MarshallUpStructure(cbBuf, pPrinter, pPrinterInfoMarshalling[Level]->pInfo, pPrinterInfoMarshalling[Level]->cbStructureSize, TRUE);
2574c2c66affSColin Finck     }
2575c2c66affSColin Finck 
2576c2c66affSColin Finck Cleanup:
2577c2c66affSColin Finck     SetLastError(dwErrorCode);
2578c2c66affSColin Finck     return (dwErrorCode == ERROR_SUCCESS);
2579c2c66affSColin Finck }
2580c2c66affSColin Finck 
2581c2c66affSColin Finck BOOL WINAPI
OpenPrinterA(LPSTR pPrinterName,LPHANDLE phPrinter,LPPRINTER_DEFAULTSA pDefault)2582c2c66affSColin Finck OpenPrinterA(LPSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSA pDefault)
2583c2c66affSColin Finck {
2584c2c66affSColin Finck     BOOL bReturnValue = FALSE;
2585c2c66affSColin Finck     DWORD cch;
2586c2c66affSColin Finck     PWSTR pwszPrinterName = NULL;
2587c2c66affSColin Finck     PRINTER_DEFAULTSW wDefault = { 0 };
2588c2c66affSColin Finck 
25891f6f08ecSColin Finck     TRACE("OpenPrinterA(%s, %p, %p)\n", pPrinterName, phPrinter, pDefault);
25901f6f08ecSColin Finck 
2591c2c66affSColin Finck     if (pPrinterName)
2592c2c66affSColin Finck     {
2593c2c66affSColin Finck         // Convert pPrinterName to a Unicode string pwszPrinterName
2594c2c66affSColin Finck         cch = strlen(pPrinterName);
2595c2c66affSColin Finck 
2596c2c66affSColin Finck         pwszPrinterName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
2597c2c66affSColin Finck         if (!pwszPrinterName)
2598c2c66affSColin Finck         {
2599c2c66affSColin Finck             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2600c2c66affSColin Finck             ERR("HeapAlloc failed!\n");
2601c2c66affSColin Finck             goto Cleanup;
2602c2c66affSColin Finck         }
2603c2c66affSColin Finck 
2604c2c66affSColin Finck         MultiByteToWideChar(CP_ACP, 0, pPrinterName, -1, pwszPrinterName, cch + 1);
2605c2c66affSColin Finck     }
2606c2c66affSColin Finck 
2607c2c66affSColin Finck     if (pDefault)
2608c2c66affSColin Finck     {
2609c2c66affSColin Finck         wDefault.DesiredAccess = pDefault->DesiredAccess;
2610c2c66affSColin Finck 
2611c2c66affSColin Finck         if (pDefault->pDatatype)
2612c2c66affSColin Finck         {
2613c2c66affSColin Finck             // Convert pDefault->pDatatype to a Unicode string wDefault.pDatatype
2614c2c66affSColin Finck             cch = strlen(pDefault->pDatatype);
2615c2c66affSColin Finck 
2616c2c66affSColin Finck             wDefault.pDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
2617c2c66affSColin Finck             if (!wDefault.pDatatype)
2618c2c66affSColin Finck             {
2619c2c66affSColin Finck                 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2620c2c66affSColin Finck                 ERR("HeapAlloc failed!\n");
2621c2c66affSColin Finck                 goto Cleanup;
2622c2c66affSColin Finck             }
2623c2c66affSColin Finck 
2624c2c66affSColin Finck             MultiByteToWideChar(CP_ACP, 0, pDefault->pDatatype, -1, wDefault.pDatatype, cch + 1);
2625c2c66affSColin Finck         }
2626c2c66affSColin Finck 
2627c2c66affSColin Finck         if (pDefault->pDevMode)
2628c2c66affSColin Finck             wDefault.pDevMode = GdiConvertToDevmodeW(pDefault->pDevMode);
2629c2c66affSColin Finck     }
2630c2c66affSColin Finck 
2631c2c66affSColin Finck     bReturnValue = OpenPrinterW(pwszPrinterName, phPrinter, &wDefault);
2632c2c66affSColin Finck 
26337bffb703SJames Tabor     if ( bReturnValue )
26347bffb703SJames Tabor     {
26357bffb703SJames Tabor         PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)*phPrinter;
26367bffb703SJames Tabor         pHandle->bAnsi = TRUE;
26377bffb703SJames Tabor     }
26387bffb703SJames Tabor 
2639c2c66affSColin Finck Cleanup:
2640c2c66affSColin Finck     if (wDefault.pDatatype)
2641c2c66affSColin Finck         HeapFree(hProcessHeap, 0, wDefault.pDatatype);
2642c2c66affSColin Finck 
2643c2c66affSColin Finck     if (wDefault.pDevMode)
2644c2c66affSColin Finck         HeapFree(hProcessHeap, 0, wDefault.pDevMode);
2645c2c66affSColin Finck 
2646c2c66affSColin Finck     if (pwszPrinterName)
2647c2c66affSColin Finck         HeapFree(hProcessHeap, 0, pwszPrinterName);
2648c2c66affSColin Finck 
2649c2c66affSColin Finck     return bReturnValue;
2650c2c66affSColin Finck }
2651c2c66affSColin Finck 
2652c2c66affSColin Finck BOOL WINAPI
OpenPrinterW(LPWSTR pPrinterName,LPHANDLE phPrinter,LPPRINTER_DEFAULTSW pDefault)2653c2c66affSColin Finck OpenPrinterW(LPWSTR pPrinterName, LPHANDLE phPrinter, LPPRINTER_DEFAULTSW pDefault)
2654c2c66affSColin Finck {
2655c2c66affSColin Finck     DWORD dwErrorCode;
2656c2c66affSColin Finck     HANDLE hPrinter;
2657c2c66affSColin Finck     PSPOOLER_HANDLE pHandle;
2658c2c66affSColin Finck     PWSTR pDatatype = NULL;
2659c2c66affSColin Finck     WINSPOOL_DEVMODE_CONTAINER DevModeContainer = { 0 };
2660c2c66affSColin Finck     ACCESS_MASK AccessRequired = 0;
2661c2c66affSColin Finck 
26621f6f08ecSColin Finck     TRACE("OpenPrinterW(%S, %p, %p)\n", pPrinterName, phPrinter, pDefault);
26631f6f08ecSColin Finck 
2664c2c66affSColin Finck     // Sanity check
2665c2c66affSColin Finck     if (!phPrinter)
2666c2c66affSColin Finck     {
2667c2c66affSColin Finck         dwErrorCode = ERROR_INVALID_PARAMETER;
2668c2c66affSColin Finck         goto Cleanup;
2669c2c66affSColin Finck     }
2670c2c66affSColin Finck 
2671c2c66affSColin Finck     // Prepare the additional parameters in the format required by _RpcOpenPrinter
2672c2c66affSColin Finck     if (pDefault)
2673c2c66affSColin Finck     {
2674c2c66affSColin Finck         pDatatype = pDefault->pDatatype;
2675c2c66affSColin Finck         DevModeContainer.cbBuf = sizeof(DEVMODEW);
2676c2c66affSColin Finck         DevModeContainer.pDevMode = (BYTE*)pDefault->pDevMode;
2677c2c66affSColin Finck         AccessRequired = pDefault->DesiredAccess;
2678c2c66affSColin Finck     }
2679c2c66affSColin Finck 
2680c2c66affSColin Finck     // Do the RPC call
2681c2c66affSColin Finck     RpcTryExcept
2682c2c66affSColin Finck     {
2683c2c66affSColin Finck         dwErrorCode = _RpcOpenPrinter(pPrinterName, &hPrinter, pDatatype, &DevModeContainer, AccessRequired);
2684c2c66affSColin Finck     }
2685c2c66affSColin Finck     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2686c2c66affSColin Finck     {
2687c2c66affSColin Finck         dwErrorCode = RpcExceptionCode();
2688c2c66affSColin Finck         ERR("_RpcOpenPrinter failed with exception code %lu!\n", dwErrorCode);
2689c2c66affSColin Finck     }
2690c2c66affSColin Finck     RpcEndExcept;
2691c2c66affSColin Finck 
2692c2c66affSColin Finck     if (dwErrorCode == ERROR_SUCCESS)
2693c2c66affSColin Finck     {
2694c2c66affSColin Finck         // Create a new SPOOLER_HANDLE structure.
2695c2c66affSColin Finck         pHandle = HeapAlloc(hProcessHeap, HEAP_ZERO_MEMORY, sizeof(SPOOLER_HANDLE));
2696c2c66affSColin Finck         if (!pHandle)
2697c2c66affSColin Finck         {
2698c2c66affSColin Finck             dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
2699c2c66affSColin Finck             ERR("HeapAlloc failed!\n");
2700c2c66affSColin Finck             goto Cleanup;
2701c2c66affSColin Finck         }
2702c2c66affSColin Finck 
27037bffb703SJames Tabor         pHandle->Sig = SPOOLER_HANDLE_SIG;
2704c2c66affSColin Finck         pHandle->hPrinter = hPrinter;
2705c2c66affSColin Finck         pHandle->hSPLFile = INVALID_HANDLE_VALUE;
27067bffb703SJames Tabor         pHandle->hSpoolFileHandle = INVALID_HANDLE_VALUE;
2707c2c66affSColin Finck 
2708c2c66affSColin Finck         // Return it as phPrinter.
2709c2c66affSColin Finck         *phPrinter = (HANDLE)pHandle;
2710c2c66affSColin Finck     }
2711c2c66affSColin Finck 
2712c2c66affSColin Finck Cleanup:
2713c2c66affSColin Finck     SetLastError(dwErrorCode);
2714c2c66affSColin Finck     return (dwErrorCode == ERROR_SUCCESS);
2715c2c66affSColin Finck }
2716c2c66affSColin Finck 
27177bffb703SJames Tabor //
27187bffb703SJames Tabor // Dead API.
27197bffb703SJames Tabor //
27207bffb703SJames Tabor DWORD WINAPI
PrinterMessageBoxA(HANDLE hPrinter,DWORD Error,HWND hWnd,LPSTR pText,LPSTR pCaption,DWORD dwType)27217bffb703SJames Tabor PrinterMessageBoxA(HANDLE hPrinter, DWORD Error, HWND hWnd, LPSTR pText, LPSTR pCaption, DWORD dwType)
27227bffb703SJames Tabor {
27237bffb703SJames Tabor     return 50;
27247bffb703SJames Tabor }
27257bffb703SJames Tabor 
27267bffb703SJames Tabor DWORD WINAPI
PrinterMessageBoxW(HANDLE hPrinter,DWORD Error,HWND hWnd,LPWSTR pText,LPWSTR pCaption,DWORD dwType)27277bffb703SJames Tabor PrinterMessageBoxW(HANDLE hPrinter, DWORD Error, HWND hWnd, LPWSTR pText, LPWSTR pCaption, DWORD dwType)
27287bffb703SJames Tabor {
27297bffb703SJames Tabor     return 50;
27307bffb703SJames Tabor }
27317bffb703SJames Tabor 
27327bffb703SJames Tabor BOOL WINAPI
QueryColorProfile(HANDLE hPrinter,PDEVMODEW pdevmode,ULONG ulQueryMode,VOID * pvProfileData,ULONG * pcbProfileData,FLONG * pflProfileData)27337bffb703SJames Tabor QueryColorProfile(
27347bffb703SJames Tabor   HANDLE    hPrinter,
27357bffb703SJames Tabor   PDEVMODEW pdevmode,
27367bffb703SJames Tabor   ULONG     ulQueryMode,
27377bffb703SJames Tabor   VOID      *pvProfileData,
27387bffb703SJames Tabor   ULONG     *pcbProfileData,
27397bffb703SJames Tabor   FLONG     *pflProfileData )
27407bffb703SJames Tabor {
27417bffb703SJames Tabor     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
27427bffb703SJames Tabor     BOOL Ret = FALSE;
27437bffb703SJames Tabor     HMODULE hLibrary;
27447bffb703SJames Tabor 
27457bffb703SJames Tabor     FIXME("QueryColorProfile(%p, %p, %l, %p, %p, %p)\n", hPrinter, pdevmode, ulQueryMode, pvProfileData, pcbProfileData, pflProfileData);
27467bffb703SJames Tabor 
27477bffb703SJames Tabor     if ( pHandle->bNoColorProfile )
27487bffb703SJames Tabor     {
27497bffb703SJames Tabor         Ret = (BOOL)SP_ERROR;
27507bffb703SJames Tabor     }
27517bffb703SJames Tabor     else
27527bffb703SJames Tabor     {
27537bffb703SJames Tabor 
27547bffb703SJames Tabor         if ( pdevmode )
27557bffb703SJames Tabor         {
27567bffb703SJames Tabor             if (!IsValidDevmodeNoSizeW( pdevmode ) )
27577bffb703SJames Tabor             {
275803422451SSerge Gautherie                 ERR("QueryColorProfile : Devode Invalid\n");
27597bffb703SJames Tabor                 return FALSE;
27607bffb703SJames Tabor             }
27617bffb703SJames Tabor         }
27627bffb703SJames Tabor 
27637bffb703SJames Tabor         hLibrary = LoadPrinterDriver( hPrinter );
27647bffb703SJames Tabor 
27657bffb703SJames Tabor         if ( hLibrary )
27667bffb703SJames Tabor         {
27677bffb703SJames Tabor             fpQueryColorProfile = (PVOID)GetProcAddress( hLibrary, "DrvQueryColorProfile" );
27687bffb703SJames Tabor 
27697bffb703SJames Tabor             if ( fpQueryColorProfile )
27707bffb703SJames Tabor             {
27717bffb703SJames Tabor                 Ret = fpQueryColorProfile( hPrinter, pdevmode, ulQueryMode, pvProfileData, pcbProfileData, pflProfileData );
27727bffb703SJames Tabor             }
27737bffb703SJames Tabor             else
27747bffb703SJames Tabor             {
27757bffb703SJames Tabor                 pHandle->bNoColorProfile = TRUE;
27767bffb703SJames Tabor                 Ret = (BOOL)SP_ERROR;
27777bffb703SJames Tabor             }
27787bffb703SJames Tabor 
27797bffb703SJames Tabor             FreeLibrary(hLibrary);
27807bffb703SJames Tabor         }
27817bffb703SJames Tabor     }
27827bffb703SJames Tabor     return Ret;
27837bffb703SJames Tabor }
27847bffb703SJames Tabor 
27857bffb703SJames Tabor // Note from GDI32:printdrv.c
27867bffb703SJames Tabor //
27877bffb703SJames Tabor //  QuerySpoolMode :
27887bffb703SJames Tabor //    BOOL return TRUE if successful.
27897bffb703SJames Tabor //    dlFont 0x0001 for Downloading fonts. 0x0002 unknown XPS_PASS?.
27907bffb703SJames Tabor //    dwVersion is version of EMFSPOOL. Must be 0x00010000. See [MS-EMFSPOOL] page 18.
27917bffb703SJames Tabor //
27927bffb703SJames Tabor 
27937bffb703SJames Tabor #define QSM_DOWNLOADINGFONTS 0x0001
27947bffb703SJames Tabor 
27957bffb703SJames Tabor /*
27967bffb703SJames Tabor    Note from MSDN : "V4 print drivers using RAW mode to send PCL/Postscript have 0 byte spool file"
27977bffb703SJames Tabor 
27987bffb703SJames Tabor    Use XPS_PASS instead of RAW to pass information directly to the print filter pipeline in
27997bffb703SJames Tabor    v4 and v3 XPSDrv drivers. Here's how to proceed with Windows 8:
28007bffb703SJames Tabor 
28017bffb703SJames Tabor     Call GetPrinterDriver to retrieve the DRIVER_INFO_8 structure.
28027bffb703SJames Tabor     Check DRIVER_INFO_8::dwPrinterDriverAttributes for the PRINTER_DRIVER_XPS flag.
28037bffb703SJames Tabor     Choose your datatype based on the presence or absence of the flag:
28047bffb703SJames Tabor         If the flag is set, use XPS_PASS.
28057bffb703SJames Tabor         If the flag isn't set, use RAW.
28067bffb703SJames Tabor  */
28077bffb703SJames Tabor 
28087bffb703SJames Tabor #define QSM_XPS_PASS         0x0002 // Guessing. PRINTER_DRIVER_XPS?
28097bffb703SJames Tabor 
28107bffb703SJames Tabor BOOL WINAPI
QuerySpoolMode(HANDLE hPrinter,PDWORD downloadFontsFlags,PDWORD dwVersion)28117bffb703SJames Tabor QuerySpoolMode( HANDLE hPrinter, PDWORD downloadFontsFlags, PDWORD dwVersion )
28127bffb703SJames Tabor {
28137bffb703SJames Tabor     PRINTER_INFO_2W *pi2 = NULL;
28147bffb703SJames Tabor     DWORD needed = 0;
28157bffb703SJames Tabor     BOOL res;
28167bffb703SJames Tabor 
28177bffb703SJames Tabor     FIXME("QuerySpoolMode(%p, %p, %p)\n", hPrinter, downloadFontsFlags, dwVersion);
28187bffb703SJames Tabor 
28197bffb703SJames Tabor     res = GetPrinterW( hPrinter, 2, NULL, 0, &needed);
28207bffb703SJames Tabor     if (!res && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
28217bffb703SJames Tabor     {
28227bffb703SJames Tabor         pi2 = HeapAlloc(hProcessHeap, 0, needed);
28230e68e27fSTimo Kreuzer         if (!pi2)
28240e68e27fSTimo Kreuzer         {
28250e68e27fSTimo Kreuzer             ERR("Failed to allocate PRINTER_INFO_2W of %u bytes\n", needed);
28260e68e27fSTimo Kreuzer             return FALSE;
28270e68e27fSTimo Kreuzer         }
28287bffb703SJames Tabor         res = GetPrinterW(hPrinter, 2, (LPBYTE)pi2, needed, &needed);
28297bffb703SJames Tabor     }
28307bffb703SJames Tabor 
28317bffb703SJames Tabor     if ( res )
28327bffb703SJames Tabor     {
28337bffb703SJames Tabor         *dwVersion = 0x10000;
28347bffb703SJames Tabor         *downloadFontsFlags = 0;
28357bffb703SJames Tabor 
28367bffb703SJames Tabor         if ( pi2->pServerName )
28377bffb703SJames Tabor         {
28387bffb703SJames Tabor             *downloadFontsFlags |= QSM_DOWNLOADINGFONTS;
28397bffb703SJames Tabor         }
28407bffb703SJames Tabor     }
28417bffb703SJames Tabor //
28427bffb703SJames Tabor //  Guessing,,,
28437bffb703SJames Tabor //  To do : Add GetPrinterDriver for DRIVER_INFO_8, test PRINTER_DRIVER_XPS flag,
28447bffb703SJames Tabor //          to set *downloadFontsFlags |= QSM_XPS_PASS;
28457bffb703SJames Tabor //
28467bffb703SJames Tabor //  Vista+ looks for QSM_XPS_PASS to be set in GDI32.
28477bffb703SJames Tabor //
28487bffb703SJames Tabor     HeapFree(hProcessHeap, 0, pi2);
28497bffb703SJames Tabor     return res;
28507bffb703SJames Tabor }
28517bffb703SJames Tabor 
28527bffb703SJames Tabor //
28537bffb703SJames Tabor // This requires IC support.
28547bffb703SJames Tabor //
28557bffb703SJames Tabor DWORD WINAPI
QueryRemoteFonts(HANDLE hPrinter,PUNIVERSAL_FONT_ID pufi,ULONG NumberOfUFIs)28567bffb703SJames Tabor QueryRemoteFonts( HANDLE hPrinter, PUNIVERSAL_FONT_ID pufi, ULONG NumberOfUFIs )
28577bffb703SJames Tabor {
28587bffb703SJames Tabor     HANDLE hIC;
28597bffb703SJames Tabor     DWORD Result = -1, cOut, cIn = 0;
28607bffb703SJames Tabor     PBYTE pOut;
28617bffb703SJames Tabor 
28627bffb703SJames Tabor     FIXME("QueryRemoteFonts(%p, %p, %lu)\n", hPrinter, pufi, NumberOfUFIs);
28637bffb703SJames Tabor 
28647bffb703SJames Tabor     hIC = CreatePrinterIC( hPrinter, NULL );
28657bffb703SJames Tabor     if ( hIC )
28667bffb703SJames Tabor     {
28677bffb703SJames Tabor         cOut = (NumberOfUFIs * sizeof(UNIVERSAL_FONT_ID)) + sizeof(DWORD); // Include "DWORD" first part to return size.
28687bffb703SJames Tabor 
28697bffb703SJames Tabor         pOut = HeapAlloc( hProcessHeap, 0, cOut );
28707bffb703SJames Tabor         if ( pOut )
28717bffb703SJames Tabor         {
28727bffb703SJames Tabor             if ( PlayGdiScriptOnPrinterIC( hIC, (LPBYTE)&cIn, sizeof(DWORD), pOut, cOut, 0 ) )
28737bffb703SJames Tabor             {
28747bffb703SJames Tabor                 cIn = *((PDWORD)pOut); // Fisrt part is the size of the UFID object.
28757bffb703SJames Tabor 
28767bffb703SJames Tabor                 Result = cIn; // Return the required size.
28777bffb703SJames Tabor 
28787bffb703SJames Tabor                 if( NumberOfUFIs < cIn )
28797bffb703SJames Tabor                 {
28807bffb703SJames Tabor                     cIn = NumberOfUFIs;
28817bffb703SJames Tabor                 }
28827bffb703SJames Tabor                 //     Copy whole object back to GDI32, exclude first DWORD part.
28837bffb703SJames Tabor                 memcpy( pufi, pOut + sizeof(DWORD), cIn * sizeof(UNIVERSAL_FONT_ID) );
28847bffb703SJames Tabor             }
28857bffb703SJames Tabor             HeapFree( hProcessHeap, 0, pOut );
28867bffb703SJames Tabor         }
28877bffb703SJames Tabor         DeletePrinterIC( hIC );
28887bffb703SJames Tabor     }
28897bffb703SJames Tabor     return Result;
28907bffb703SJames Tabor }
28917bffb703SJames Tabor 
2892c2c66affSColin Finck BOOL WINAPI
ReadPrinter(HANDLE hPrinter,PVOID pBuf,DWORD cbBuf,PDWORD pNoBytesRead)2893c2c66affSColin Finck ReadPrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pNoBytesRead)
2894c2c66affSColin Finck {
2895c2c66affSColin Finck     DWORD dwErrorCode;
2896c2c66affSColin Finck     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
2897c2c66affSColin Finck 
28981f6f08ecSColin Finck     TRACE("ReadPrinter(%p, %p, %lu, %p)\n", hPrinter, pBuf, cbBuf, pNoBytesRead);
28991f6f08ecSColin Finck 
2900c2c66affSColin Finck     // Sanity checks.
2901c2c66affSColin Finck     if (!pHandle)
2902c2c66affSColin Finck     {
2903c2c66affSColin Finck         dwErrorCode = ERROR_INVALID_HANDLE;
2904c2c66affSColin Finck         goto Cleanup;
2905c2c66affSColin Finck     }
2906c2c66affSColin Finck 
2907c2c66affSColin Finck     // Do the RPC call
2908c2c66affSColin Finck     RpcTryExcept
2909c2c66affSColin Finck     {
2910c2c66affSColin Finck         dwErrorCode = _RpcReadPrinter(pHandle->hPrinter, pBuf, cbBuf, pNoBytesRead);
2911c2c66affSColin Finck     }
2912c2c66affSColin Finck     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
2913c2c66affSColin Finck     {
2914c2c66affSColin Finck         dwErrorCode = RpcExceptionCode();
2915c2c66affSColin Finck         ERR("_RpcReadPrinter failed with exception code %lu!\n", dwErrorCode);
2916c2c66affSColin Finck     }
2917c2c66affSColin Finck     RpcEndExcept;
2918c2c66affSColin Finck 
2919c2c66affSColin Finck Cleanup:
2920c2c66affSColin Finck     SetLastError(dwErrorCode);
2921c2c66affSColin Finck     return (dwErrorCode == ERROR_SUCCESS);
2922c2c66affSColin Finck }
2923c2c66affSColin Finck 
2924c2c66affSColin Finck BOOL WINAPI
ResetPrinterA(HANDLE hPrinter,PPRINTER_DEFAULTSA pDefault)292546b91659SColin Finck ResetPrinterA(HANDLE hPrinter, PPRINTER_DEFAULTSA pDefault)
292646b91659SColin Finck {
29277bffb703SJames Tabor     BOOL ret;
29287bffb703SJames Tabor     UNICODE_STRING pNameW;
29297bffb703SJames Tabor     PDEVMODEW pdmw = NULL;
29307bffb703SJames Tabor     PPRINTER_DEFAULTSW pdw = (PPRINTER_DEFAULTSW)pDefault;
29317bffb703SJames Tabor 
293246b91659SColin Finck     TRACE("ResetPrinterA(%p, %p)\n", hPrinter, pDefault);
29337bffb703SJames Tabor 
29347bffb703SJames Tabor     if ( pDefault->pDatatype == (LPSTR)-1 )
29357bffb703SJames Tabor     {
29367bffb703SJames Tabor         pdw->pDatatype = (LPWSTR)-1;
29377bffb703SJames Tabor     }
29387bffb703SJames Tabor     else
29397bffb703SJames Tabor     {
29407bffb703SJames Tabor         pdw->pDatatype = AsciiToUnicode( &pNameW, pDefault->pDatatype );
29417bffb703SJames Tabor     }
29427bffb703SJames Tabor     if ( pDefault->pDevMode == (LPDEVMODEA)-1)
29437bffb703SJames Tabor     {
29447bffb703SJames Tabor         pdw->pDevMode = (LPDEVMODEW)-1;
29457bffb703SJames Tabor     }
29467bffb703SJames Tabor     else
29477bffb703SJames Tabor     {
29487bffb703SJames Tabor         if ( pDefault->pDevMode )//&& IsValidDevmodeNoSizeW( pDefault->pDevMode ) )
29497bffb703SJames Tabor         {
29507bffb703SJames Tabor             RosConvertAnsiDevModeToUnicodeDevmode( pDefault->pDevMode, &pdmw );
29517bffb703SJames Tabor             pdw->pDevMode = pdmw;
29527bffb703SJames Tabor         }
29537bffb703SJames Tabor     }
29547bffb703SJames Tabor 
29557bffb703SJames Tabor     ret = ResetPrinterW( hPrinter, pdw );
29567bffb703SJames Tabor 
29577bffb703SJames Tabor     if (pdmw) HeapFree(hProcessHeap, 0, pdmw);
29587bffb703SJames Tabor 
29597bffb703SJames Tabor     RtlFreeUnicodeString( &pNameW );
29607bffb703SJames Tabor 
29617bffb703SJames Tabor     return ret;
296246b91659SColin Finck }
296346b91659SColin Finck 
296446b91659SColin Finck BOOL WINAPI
ResetPrinterW(HANDLE hPrinter,PPRINTER_DEFAULTSW pDefault)2965c2c66affSColin Finck ResetPrinterW(HANDLE hPrinter, PPRINTER_DEFAULTSW pDefault)
2966c2c66affSColin Finck {
29671f6f08ecSColin Finck     TRACE("ResetPrinterW(%p, %p)\n", hPrinter, pDefault);
2968c2c66affSColin Finck     UNIMPLEMENTED;
2969c2c66affSColin Finck     return FALSE;
2970c2c66affSColin Finck }
2971c2c66affSColin Finck 
2972c2c66affSColin Finck BOOL WINAPI
SeekPrinter(HANDLE hPrinter,LARGE_INTEGER liDistanceToMove,PLARGE_INTEGER pliNewPointer,DWORD dwMoveMethod,BOOL bWrite)297362c4b828SJames Tabor SeekPrinter( HANDLE hPrinter, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER pliNewPointer, DWORD dwMoveMethod, BOOL bWrite )
297462c4b828SJames Tabor {
297562c4b828SJames Tabor     DWORD dwErrorCode;
297662c4b828SJames Tabor     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
297762c4b828SJames Tabor 
297862c4b828SJames Tabor     FIXME("SeekPrinter(%p, %I64u, %p, %lu, %d)\n", hPrinter, liDistanceToMove.QuadPart, pliNewPointer, dwMoveMethod, bWrite);
297962c4b828SJames Tabor 
298062c4b828SJames Tabor     // Sanity checks.
298162c4b828SJames Tabor     if (!pHandle)
298262c4b828SJames Tabor     {
298362c4b828SJames Tabor         dwErrorCode = ERROR_INVALID_HANDLE;
298462c4b828SJames Tabor         goto Cleanup;
298562c4b828SJames Tabor     }
298662c4b828SJames Tabor 
298762c4b828SJames Tabor     // Do the RPC call
298862c4b828SJames Tabor     RpcTryExcept
298962c4b828SJames Tabor     {
299062c4b828SJames Tabor         dwErrorCode = _RpcSeekPrinter(pHandle->hPrinter, liDistanceToMove, pliNewPointer, dwMoveMethod, bWrite);
299162c4b828SJames Tabor     }
299262c4b828SJames Tabor     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
299362c4b828SJames Tabor     {
299462c4b828SJames Tabor         dwErrorCode = RpcExceptionCode();
299562c4b828SJames Tabor         ERR("_RpcSeekPrinter failed with exception code %lu!\n", dwErrorCode);
299662c4b828SJames Tabor     }
299762c4b828SJames Tabor     RpcEndExcept;
299862c4b828SJames Tabor 
299962c4b828SJames Tabor Cleanup:
300062c4b828SJames Tabor     SetLastError(dwErrorCode);
300162c4b828SJames Tabor     return (dwErrorCode == ERROR_SUCCESS);
300262c4b828SJames Tabor }
300362c4b828SJames Tabor 
300462c4b828SJames Tabor BOOL WINAPI
SetDefaultPrinterA(LPCSTR pszPrinter)3005c2c66affSColin Finck SetDefaultPrinterA(LPCSTR pszPrinter)
3006c2c66affSColin Finck {
3007c2c66affSColin Finck     BOOL bReturnValue = FALSE;
3008c2c66affSColin Finck     DWORD cch;
3009c2c66affSColin Finck     PWSTR pwszPrinter = NULL;
3010c2c66affSColin Finck 
30111f6f08ecSColin Finck     TRACE("SetDefaultPrinterA(%s)\n", pszPrinter);
30121f6f08ecSColin Finck 
3013c2c66affSColin Finck     if (pszPrinter)
3014c2c66affSColin Finck     {
3015c2c66affSColin Finck         // Convert pszPrinter to a Unicode string pwszPrinter
3016c2c66affSColin Finck         cch = strlen(pszPrinter);
3017c2c66affSColin Finck 
3018c2c66affSColin Finck         pwszPrinter = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
3019c2c66affSColin Finck         if (!pwszPrinter)
3020c2c66affSColin Finck         {
3021c2c66affSColin Finck             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3022c2c66affSColin Finck             ERR("HeapAlloc failed!\n");
3023c2c66affSColin Finck             goto Cleanup;
3024c2c66affSColin Finck         }
3025c2c66affSColin Finck 
3026c2c66affSColin Finck         MultiByteToWideChar(CP_ACP, 0, pszPrinter, -1, pwszPrinter, cch + 1);
3027c2c66affSColin Finck     }
3028c2c66affSColin Finck 
3029c2c66affSColin Finck     bReturnValue = SetDefaultPrinterW(pwszPrinter);
3030c2c66affSColin Finck 
3031c2c66affSColin Finck Cleanup:
3032c2c66affSColin Finck     if (pwszPrinter)
3033c2c66affSColin Finck         HeapFree(hProcessHeap, 0, pwszPrinter);
3034c2c66affSColin Finck 
3035c2c66affSColin Finck     return bReturnValue;
3036c2c66affSColin Finck }
3037c2c66affSColin Finck 
3038c2c66affSColin Finck BOOL WINAPI
SetDefaultPrinterW(LPCWSTR pszPrinter)3039c2c66affSColin Finck SetDefaultPrinterW(LPCWSTR pszPrinter)
3040c2c66affSColin Finck {
3041c2c66affSColin Finck     const WCHAR wszDevicesKey[] = L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Devices";
3042c2c66affSColin Finck 
3043c2c66affSColin Finck     DWORD cbDeviceValueData;
3044c2c66affSColin Finck     DWORD cbPrinterValueData = 0;
3045c2c66affSColin Finck     DWORD cchPrinter;
3046c2c66affSColin Finck     DWORD dwErrorCode;
3047c2c66affSColin Finck     HKEY hDevicesKey = NULL;
3048c2c66affSColin Finck     HKEY hWindowsKey = NULL;
3049c2c66affSColin Finck     PWSTR pwszDeviceValueData = NULL;
3050c2c66affSColin Finck     WCHAR wszPrinter[MAX_PRINTER_NAME + 1];
3051c2c66affSColin Finck 
30521f6f08ecSColin Finck     TRACE("SetDefaultPrinterW(%S)\n", pszPrinter);
30531f6f08ecSColin Finck 
3054c2c66affSColin Finck     // Open the Devices registry key.
3055c2c66affSColin Finck     dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszDevicesKey, 0, KEY_READ, &hDevicesKey);
3056c2c66affSColin Finck     if (dwErrorCode != ERROR_SUCCESS)
3057c2c66affSColin Finck     {
3058c2c66affSColin Finck         ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
3059c2c66affSColin Finck         goto Cleanup;
3060c2c66affSColin Finck     }
3061c2c66affSColin Finck 
3062c2c66affSColin Finck     // Did the caller give us a printer to set as default?
3063c2c66affSColin Finck     if (pszPrinter && *pszPrinter)
3064c2c66affSColin Finck     {
3065c2c66affSColin Finck         // Check if the given printer exists and query the value data size.
3066c2c66affSColin Finck         dwErrorCode = (DWORD)RegQueryValueExW(hDevicesKey, pszPrinter, NULL, NULL, NULL, &cbPrinterValueData);
3067c2c66affSColin Finck         if (dwErrorCode == ERROR_FILE_NOT_FOUND)
3068c2c66affSColin Finck         {
3069c2c66affSColin Finck             dwErrorCode = ERROR_INVALID_PRINTER_NAME;
3070c2c66affSColin Finck             goto Cleanup;
3071c2c66affSColin Finck         }
3072c2c66affSColin Finck         else if (dwErrorCode != ERROR_SUCCESS)
3073c2c66affSColin Finck         {
3074c2c66affSColin Finck             ERR("RegQueryValueExW failed with status %lu!\n", dwErrorCode);
3075c2c66affSColin Finck             goto Cleanup;
3076c2c66affSColin Finck         }
3077c2c66affSColin Finck 
3078c2c66affSColin Finck         cchPrinter = wcslen(pszPrinter);
3079c2c66affSColin Finck     }
3080c2c66affSColin Finck     else
3081c2c66affSColin Finck     {
3082c2c66affSColin Finck         // If there is already a default printer, we're done!
3083c2c66affSColin Finck         cchPrinter = _countof(wszPrinter);
3084c2c66affSColin Finck         if (GetDefaultPrinterW(wszPrinter, &cchPrinter))
3085c2c66affSColin Finck         {
3086c2c66affSColin Finck             dwErrorCode = ERROR_SUCCESS;
3087c2c66affSColin Finck             goto Cleanup;
3088c2c66affSColin Finck         }
3089c2c66affSColin Finck 
3090c2c66affSColin Finck         // Otherwise, get us the first printer from the "Devices" key to later set it as default and query the value data size.
3091c2c66affSColin Finck         cchPrinter = _countof(wszPrinter);
3092c2c66affSColin Finck         dwErrorCode = (DWORD)RegEnumValueW(hDevicesKey, 0, wszPrinter, &cchPrinter, NULL, NULL, NULL, &cbPrinterValueData);
3093c2c66affSColin Finck         if (dwErrorCode != ERROR_MORE_DATA)
3094c2c66affSColin Finck             goto Cleanup;
3095c2c66affSColin Finck 
3096c2c66affSColin Finck         pszPrinter = wszPrinter;
3097c2c66affSColin Finck     }
3098c2c66affSColin Finck 
3099c2c66affSColin Finck     // We now need to query the value data, which has the format "winspool,<Port>:"
3100c2c66affSColin Finck     // and make "<Printer Name>,winspool,<Port>:" out of it.
3101c2c66affSColin Finck     // Allocate a buffer large enough for the final data.
3102c2c66affSColin Finck     cbDeviceValueData = (cchPrinter + 1) * sizeof(WCHAR) + cbPrinterValueData;
3103c2c66affSColin Finck     pwszDeviceValueData = HeapAlloc(hProcessHeap, 0, cbDeviceValueData);
3104c2c66affSColin Finck     if (!pwszDeviceValueData)
3105c2c66affSColin Finck     {
3106c2c66affSColin Finck         dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
3107c2c66affSColin Finck         ERR("HeapAlloc failed!\n");
3108c2c66affSColin Finck         goto Cleanup;
3109c2c66affSColin Finck     }
3110c2c66affSColin Finck 
3111c2c66affSColin Finck     // Copy the Printer Name and a comma into it.
3112c2c66affSColin Finck     CopyMemory(pwszDeviceValueData, pszPrinter, cchPrinter * sizeof(WCHAR));
3113c2c66affSColin Finck     pwszDeviceValueData[cchPrinter] = L',';
3114c2c66affSColin Finck 
3115c2c66affSColin Finck     // Append the value data, which has the format "winspool,<Port>:"
3116c2c66affSColin Finck     dwErrorCode = (DWORD)RegQueryValueExW(hDevicesKey, pszPrinter, NULL, NULL, (PBYTE)&pwszDeviceValueData[cchPrinter + 1], &cbPrinterValueData);
3117c2c66affSColin Finck     if (dwErrorCode != ERROR_SUCCESS)
3118c2c66affSColin Finck         goto Cleanup;
3119c2c66affSColin Finck 
3120c2c66affSColin Finck     // Open the Windows registry key.
3121c2c66affSColin Finck     dwErrorCode = (DWORD)RegOpenKeyExW(HKEY_CURRENT_USER, wszWindowsKey, 0, KEY_SET_VALUE, &hWindowsKey);
3122c2c66affSColin Finck     if (dwErrorCode != ERROR_SUCCESS)
3123c2c66affSColin Finck     {
3124c2c66affSColin Finck         ERR("RegOpenKeyExW failed with status %lu!\n", dwErrorCode);
3125c2c66affSColin Finck         goto Cleanup;
3126c2c66affSColin Finck     }
3127c2c66affSColin Finck 
3128c2c66affSColin Finck     // Store our new default printer.
3129c2c66affSColin Finck     dwErrorCode = (DWORD)RegSetValueExW(hWindowsKey, wszDeviceValue, 0, REG_SZ, (PBYTE)pwszDeviceValueData, cbDeviceValueData);
3130c2c66affSColin Finck     if (dwErrorCode != ERROR_SUCCESS)
3131c2c66affSColin Finck     {
3132c2c66affSColin Finck         ERR("RegSetValueExW failed with status %lu!\n", dwErrorCode);
3133c2c66affSColin Finck         goto Cleanup;
3134c2c66affSColin Finck     }
3135c2c66affSColin Finck 
3136c2c66affSColin Finck Cleanup:
3137c2c66affSColin Finck     if (hDevicesKey)
3138c2c66affSColin Finck         RegCloseKey(hDevicesKey);
3139c2c66affSColin Finck 
3140c2c66affSColin Finck     if (hWindowsKey)
3141c2c66affSColin Finck         RegCloseKey(hWindowsKey);
3142c2c66affSColin Finck 
3143c2c66affSColin Finck     if (pwszDeviceValueData)
3144c2c66affSColin Finck         HeapFree(hProcessHeap, 0, pwszDeviceValueData);
3145c2c66affSColin Finck 
3146c2c66affSColin Finck     SetLastError(dwErrorCode);
3147c2c66affSColin Finck     return (dwErrorCode == ERROR_SUCCESS);
3148c2c66affSColin Finck }
3149c2c66affSColin Finck 
3150c2c66affSColin Finck BOOL WINAPI
SetPrinterA(HANDLE hPrinter,DWORD Level,PBYTE pPrinter,DWORD Command)315146b91659SColin Finck SetPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command)
315246b91659SColin Finck {
31537bffb703SJames Tabor     BOOL Ret = FALSE;
31547bffb703SJames Tabor     UNICODE_STRING usBuffer;
31557bffb703SJames Tabor     PPRINTER_INFO_STRESS ppisa = (PPRINTER_INFO_STRESS)pPrinter;
31567bffb703SJames Tabor     PPRINTER_INFO_STRESS ppisw = (PPRINTER_INFO_STRESS)pPrinter;
31577bffb703SJames Tabor     PPRINTER_INFO_2A ppi2a = (PPRINTER_INFO_2A)pPrinter;
31587bffb703SJames Tabor     PPRINTER_INFO_2W ppi2w = (PPRINTER_INFO_2W)pPrinter;
31597bffb703SJames Tabor     PPRINTER_INFO_7A ppi7a = (PPRINTER_INFO_7A)pPrinter;
31607bffb703SJames Tabor     PPRINTER_INFO_7W ppi7w = (PPRINTER_INFO_7W)pPrinter;
31617bffb703SJames Tabor     PPRINTER_INFO_9A ppi9a = (PPRINTER_INFO_9A)pPrinter;
31627bffb703SJames Tabor     PPRINTER_INFO_9W ppi9w = (PPRINTER_INFO_9W)pPrinter;
31637bffb703SJames Tabor     PWSTR pwszPrinterName = NULL;
31647bffb703SJames Tabor     PWSTR pwszServerName = NULL;
31657bffb703SJames Tabor     PWSTR pwszShareName = NULL;
31667bffb703SJames Tabor     PWSTR pwszPortName = NULL;
31677bffb703SJames Tabor     PWSTR pwszDriverName = NULL;
31687bffb703SJames Tabor     PWSTR pwszComment = NULL;
31697bffb703SJames Tabor     PWSTR pwszLocation = NULL;
31707bffb703SJames Tabor     PWSTR pwszSepFile = NULL;
31717bffb703SJames Tabor     PWSTR pwszPrintProcessor = NULL;
31727bffb703SJames Tabor     PWSTR pwszDatatype = NULL;
31737bffb703SJames Tabor     PWSTR pwszParameters = NULL;
31747bffb703SJames Tabor     PDEVMODEW pdmw = NULL;
31757bffb703SJames Tabor 
31767bffb703SJames Tabor     FIXME("SetPrinterA(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command);
31777bffb703SJames Tabor 
31787bffb703SJames Tabor     switch ( Level )
31797bffb703SJames Tabor     {
31807bffb703SJames Tabor         case 0:
31817bffb703SJames Tabor             if ( Command == 0 )
31827bffb703SJames Tabor             {
31837bffb703SJames Tabor                 if (ppisa->pPrinterName)
31847bffb703SJames Tabor                 {
31857bffb703SJames Tabor                     pwszPrinterName = AsciiToUnicode(&usBuffer, (LPCSTR)ppisa->pPrinterName);
31867bffb703SJames Tabor                     if (!(ppisw->pPrinterName = pwszPrinterName)) goto Cleanup;
31877bffb703SJames Tabor                 }
31887bffb703SJames Tabor                 if (ppisa->pServerName)
31897bffb703SJames Tabor                 {
31907bffb703SJames Tabor                     pwszServerName = AsciiToUnicode(&usBuffer, (LPCSTR)ppisa->pServerName);
31917bffb703SJames Tabor                     if (!(ppisw->pPrinterName = pwszServerName)) goto Cleanup;
31927bffb703SJames Tabor                 }
31937bffb703SJames Tabor             }
31947bffb703SJames Tabor             if ( Command == PRINTER_CONTROL_SET_STATUS )
31957bffb703SJames Tabor             {
31967bffb703SJames Tabor                 // Set the pPrinter parameter to a pointer to a DWORD value that specifies the new printer status.
31977bffb703SJames Tabor                 PRINTER_INFO_6 pi6;
31989d189469SJames Tabor                 pi6.dwStatus = (DWORD_PTR)pPrinter;
31997bffb703SJames Tabor                 pPrinter = (LPBYTE)&pi6;
32007bffb703SJames Tabor                 Level = 6;
32017bffb703SJames Tabor                 Command = 0;
32027bffb703SJames Tabor             }
32037bffb703SJames Tabor             break;
32047bffb703SJames Tabor         case 2:
32057bffb703SJames Tabor             {
32067bffb703SJames Tabor                 if (ppi2a->pShareName)
32077bffb703SJames Tabor                 {
32087bffb703SJames Tabor                     pwszShareName = AsciiToUnicode(&usBuffer, ppi2a->pShareName);
32097bffb703SJames Tabor                     if (!(ppi2w->pShareName = pwszShareName)) goto Cleanup;
32107bffb703SJames Tabor                 }
32117bffb703SJames Tabor                 if (ppi2a->pPortName)
32127bffb703SJames Tabor                 {
32137bffb703SJames Tabor                     pwszPortName = AsciiToUnicode(&usBuffer, ppi2a->pPortName);
32147bffb703SJames Tabor                     if (!(ppi2w->pPortName = pwszPortName)) goto Cleanup;
32157bffb703SJames Tabor                 }
32167bffb703SJames Tabor                 if (ppi2a->pDriverName)
32177bffb703SJames Tabor                 {
32187bffb703SJames Tabor                     pwszDriverName = AsciiToUnicode(&usBuffer, ppi2a->pDriverName);
32197bffb703SJames Tabor                     if (!(ppi2w->pDriverName = pwszDriverName)) goto Cleanup;
32207bffb703SJames Tabor                 }
32217bffb703SJames Tabor                 if (ppi2a->pComment)
32227bffb703SJames Tabor                 {
32237bffb703SJames Tabor                     pwszComment = AsciiToUnicode(&usBuffer, ppi2a->pComment);
32247bffb703SJames Tabor                     if (!(ppi2w->pComment = pwszComment)) goto Cleanup;
32257bffb703SJames Tabor                 }
32267bffb703SJames Tabor                 if (ppi2a->pLocation)
32277bffb703SJames Tabor                 {
32287bffb703SJames Tabor                     pwszLocation = AsciiToUnicode(&usBuffer, ppi2a->pLocation);
32297bffb703SJames Tabor                     if (!(ppi2w->pLocation = pwszLocation)) goto Cleanup;
32307bffb703SJames Tabor                 }
32317bffb703SJames Tabor                 if (ppi2a->pSepFile)
32327bffb703SJames Tabor                 {
32337bffb703SJames Tabor                     pwszSepFile = AsciiToUnicode(&usBuffer, ppi2a->pSepFile);
32347bffb703SJames Tabor                     if (!(ppi2w->pSepFile = pwszSepFile)) goto Cleanup;
32357bffb703SJames Tabor                 }
32367bffb703SJames Tabor                 if (ppi2a->pServerName)
32377bffb703SJames Tabor                 {
32387bffb703SJames Tabor                     pwszPrintProcessor = AsciiToUnicode(&usBuffer, ppi2a->pPrintProcessor);
32397bffb703SJames Tabor                     if (!(ppi2w->pPrintProcessor = pwszPrintProcessor)) goto Cleanup;
32407bffb703SJames Tabor                 }
32417bffb703SJames Tabor                 if (ppi2a->pDatatype)
32427bffb703SJames Tabor                 {
32437bffb703SJames Tabor                     pwszDatatype = AsciiToUnicode(&usBuffer, ppi2a->pDatatype);
32447bffb703SJames Tabor                     if (!(ppi2w->pDatatype = pwszDatatype)) goto Cleanup;
32457bffb703SJames Tabor                 }
32467bffb703SJames Tabor                 if (ppi2a->pParameters)
32477bffb703SJames Tabor                 {
32487bffb703SJames Tabor                     pwszParameters = AsciiToUnicode(&usBuffer, ppi2a->pParameters);
32497bffb703SJames Tabor                     if (!(ppi2w->pParameters = pwszParameters)) goto Cleanup;
32507bffb703SJames Tabor                 }
32517bffb703SJames Tabor 
32527bffb703SJames Tabor                 if ( ppi2a->pDevMode )
32537bffb703SJames Tabor                 {
32547bffb703SJames Tabor                     RosConvertAnsiDevModeToUnicodeDevmode( ppi2a->pDevMode, &pdmw );
32557bffb703SJames Tabor                     ppi2w->pDevMode = pdmw;
32567bffb703SJames Tabor                 }
32577bffb703SJames Tabor             }
32587bffb703SJames Tabor         //
32597bffb703SJames Tabor         //  These two strings are relitive and common to these three Levels.
32607bffb703SJames Tabor         //  Fall through...
32617bffb703SJames Tabor         //
32627bffb703SJames Tabor         case 4:
32637bffb703SJames Tabor         case 5:
32647bffb703SJames Tabor             {
32657bffb703SJames Tabor                 if (ppi2a->pServerName) // 4 & 5 : pPrinterName.
32667bffb703SJames Tabor                 {
32677bffb703SJames Tabor                     pwszServerName = AsciiToUnicode(&usBuffer, ppi2a->pServerName);
32687bffb703SJames Tabor                     if (!(ppi2w->pPrinterName = pwszServerName)) goto Cleanup;
32697bffb703SJames Tabor                 }
32707bffb703SJames Tabor                 if (ppi2a->pPrinterName) // 4 : pServerName, 5 : pPortName.
32717bffb703SJames Tabor                 {
32727bffb703SJames Tabor                     pwszPrinterName = AsciiToUnicode(&usBuffer, ppi2a->pPrinterName);
32737bffb703SJames Tabor                     if (!(ppi2w->pPrinterName = pwszPrinterName)) goto Cleanup;
32747bffb703SJames Tabor                 }
32757bffb703SJames Tabor             }
32767bffb703SJames Tabor             break;
32777bffb703SJames Tabor         case 3:
32787bffb703SJames Tabor         case 6:
32797bffb703SJames Tabor             break;
32807bffb703SJames Tabor         case 7:
32817bffb703SJames Tabor             {
32827bffb703SJames Tabor                 if (ppi7a->pszObjectGUID)
32837bffb703SJames Tabor                 {
32847bffb703SJames Tabor                     pwszPrinterName = AsciiToUnicode(&usBuffer, ppi7a->pszObjectGUID);
32857bffb703SJames Tabor                     if (!(ppi7w->pszObjectGUID = pwszPrinterName)) goto Cleanup;
32867bffb703SJames Tabor                 }
32877bffb703SJames Tabor             }
32887bffb703SJames Tabor             break;
32897bffb703SJames Tabor 
32907bffb703SJames Tabor         case 8:
32917bffb703SJames Tabor         /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
32927bffb703SJames Tabor         /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
32937bffb703SJames Tabor         /* fall through */
32947bffb703SJames Tabor         case 9:
32957bffb703SJames Tabor             {
32967bffb703SJames Tabor                 RosConvertAnsiDevModeToUnicodeDevmode( ppi9a->pDevMode, &pdmw );
32977bffb703SJames Tabor                 ppi9w->pDevMode = pdmw;
32987bffb703SJames Tabor             }
32997bffb703SJames Tabor             break;
33007bffb703SJames Tabor 
33017bffb703SJames Tabor         default:
33027bffb703SJames Tabor             FIXME( "Unsupported level %d\n", Level);
33037bffb703SJames Tabor             SetLastError( ERROR_INVALID_LEVEL );
33047bffb703SJames Tabor     }
33057bffb703SJames Tabor 
33067bffb703SJames Tabor     Ret = SetPrinterW( hPrinter, Level, pPrinter, Command );
33077bffb703SJames Tabor 
33087bffb703SJames Tabor Cleanup:
33097bffb703SJames Tabor     if (pdmw) HeapFree(hProcessHeap, 0, pdmw);
33107bffb703SJames Tabor     if (pwszPrinterName) HeapFree(hProcessHeap, 0, pwszPrinterName);
33117bffb703SJames Tabor     if (pwszServerName) HeapFree(hProcessHeap, 0, pwszServerName);
33127bffb703SJames Tabor     if (pwszShareName) HeapFree(hProcessHeap, 0, pwszShareName);
33137bffb703SJames Tabor     if (pwszPortName) HeapFree(hProcessHeap, 0, pwszPortName);
33147bffb703SJames Tabor     if (pwszDriverName) HeapFree(hProcessHeap, 0, pwszDriverName);
33157bffb703SJames Tabor     if (pwszComment) HeapFree(hProcessHeap, 0, pwszComment);
33167bffb703SJames Tabor     if (pwszLocation) HeapFree(hProcessHeap, 0, pwszLocation);
33177bffb703SJames Tabor     if (pwszSepFile) HeapFree(hProcessHeap, 0, pwszSepFile);
33187bffb703SJames Tabor     if (pwszPrintProcessor) HeapFree(hProcessHeap, 0, pwszPrintProcessor);
33197bffb703SJames Tabor     if (pwszDatatype) HeapFree(hProcessHeap, 0, pwszDatatype);
33207bffb703SJames Tabor     if (pwszParameters) HeapFree(hProcessHeap, 0, pwszParameters);
33217bffb703SJames Tabor     return Ret;
332246b91659SColin Finck }
332346b91659SColin Finck 
332446b91659SColin Finck BOOL WINAPI
SetPrinterW(HANDLE hPrinter,DWORD Level,PBYTE pPrinter,DWORD Command)3325c2c66affSColin Finck SetPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pPrinter, DWORD Command)
3326c2c66affSColin Finck {
33277bffb703SJames Tabor     DWORD dwErrorCode;
33287bffb703SJames Tabor     WINSPOOL_PRINTER_CONTAINER PrinterContainer;
33297bffb703SJames Tabor     WINSPOOL_DEVMODE_CONTAINER DevModeContainer;
33307bffb703SJames Tabor     WINSPOOL_SECURITY_CONTAINER SecurityContainer;
33317bffb703SJames Tabor     SECURITY_DESCRIPTOR *sd = NULL;
33327bffb703SJames Tabor     DWORD size;
33337bffb703SJames Tabor     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
33347bffb703SJames Tabor 
33357bffb703SJames Tabor     FIXME("SetPrinterW(%p, %lu, %p, %lu)\n", hPrinter, Level, pPrinter, Command);
33367bffb703SJames Tabor 
33377bffb703SJames Tabor     // Sanity checks
33387bffb703SJames Tabor     if (!pHandle)
33397bffb703SJames Tabor         return ERROR_INVALID_HANDLE;
33407bffb703SJames Tabor 
33417bffb703SJames Tabor     DevModeContainer.cbBuf = 0;
33427bffb703SJames Tabor     DevModeContainer.pDevMode = NULL;
33437bffb703SJames Tabor 
33447bffb703SJames Tabor     SecurityContainer.cbBuf = 0;
33457bffb703SJames Tabor     SecurityContainer.pSecurity = NULL;
33467bffb703SJames Tabor 
33477bffb703SJames Tabor     switch ( Level )
33487bffb703SJames Tabor     {
33497bffb703SJames Tabor         case 0:
33507bffb703SJames Tabor             if ( Command == PRINTER_CONTROL_SET_STATUS )
33517bffb703SJames Tabor             {
33527bffb703SJames Tabor                 // Set the pPrinter parameter to a pointer to a DWORD value that specifies the new printer status.
33537bffb703SJames Tabor                 PRINTER_INFO_6 pi6;
33549d189469SJames Tabor                 pi6.dwStatus = (DWORD_PTR)pPrinter;
33557bffb703SJames Tabor                 pPrinter = (LPBYTE)&pi6;
33567bffb703SJames Tabor                 Level = 6;
33577bffb703SJames Tabor                 Command = 0;
33587bffb703SJames Tabor             }
33597bffb703SJames Tabor             break;
33607bffb703SJames Tabor         case 2:
33617bffb703SJames Tabor             {
33627bffb703SJames Tabor                 PPRINTER_INFO_2W pi2w = (PPRINTER_INFO_2W)pPrinter;
33637bffb703SJames Tabor                 if ( pi2w )
33647bffb703SJames Tabor                 {
33657bffb703SJames Tabor                     if ( pi2w->pDevMode )
33667bffb703SJames Tabor                     {
33677bffb703SJames Tabor                          if ( IsValidDevmodeNoSizeW( pi2w->pDevMode ) )
33687bffb703SJames Tabor                          {
33697bffb703SJames Tabor                              DevModeContainer.cbBuf = pi2w->pDevMode->dmSize + pi2w->pDevMode->dmDriverExtra;
33707bffb703SJames Tabor                              DevModeContainer.pDevMode = (PBYTE)pi2w->pDevMode;
33717bffb703SJames Tabor                          }
33727bffb703SJames Tabor                     }
33737bffb703SJames Tabor 
33747bffb703SJames Tabor                     if ( pi2w->pSecurityDescriptor )
33757bffb703SJames Tabor                     {
33767bffb703SJames Tabor                         sd = get_sd( pi2w->pSecurityDescriptor, &size );
33777bffb703SJames Tabor                         if ( sd )
33787bffb703SJames Tabor                         {
33797bffb703SJames Tabor                             SecurityContainer.cbBuf = size;
33807bffb703SJames Tabor                             SecurityContainer.pSecurity = (PBYTE)sd;
33817bffb703SJames Tabor                         }
33827bffb703SJames Tabor                     }
33837bffb703SJames Tabor                 }
33847bffb703SJames Tabor                 else
33857bffb703SJames Tabor                 {
33867bffb703SJames Tabor                     SetLastError(ERROR_INVALID_PARAMETER);
3387c2c66affSColin Finck                     return FALSE;
3388c2c66affSColin Finck                 }
33897bffb703SJames Tabor             }
33907bffb703SJames Tabor             break;
33917bffb703SJames Tabor         case 3:
33927bffb703SJames Tabor             {
33937bffb703SJames Tabor                 PPRINTER_INFO_3 pi3 = (PPRINTER_INFO_3)pPrinter;
33947bffb703SJames Tabor                 if ( pi3 )
33957bffb703SJames Tabor                 {
33967bffb703SJames Tabor                     if ( pi3->pSecurityDescriptor )
33977bffb703SJames Tabor                     {
33987bffb703SJames Tabor                         sd = get_sd( pi3->pSecurityDescriptor, &size );
33997bffb703SJames Tabor                         if ( sd )
34007bffb703SJames Tabor                         {
34017bffb703SJames Tabor                             SecurityContainer.cbBuf = size;
34027bffb703SJames Tabor                             SecurityContainer.pSecurity = (PBYTE)sd;
34037bffb703SJames Tabor                         }
34047bffb703SJames Tabor                     }
34057bffb703SJames Tabor                 }
34067bffb703SJames Tabor                 else
34077bffb703SJames Tabor                 {
34087bffb703SJames Tabor                     SetLastError(ERROR_INVALID_PARAMETER);
34097bffb703SJames Tabor                     return FALSE;
34107bffb703SJames Tabor                 }
34117bffb703SJames Tabor             }
34127bffb703SJames Tabor             break;
34137bffb703SJames Tabor 
34147bffb703SJames Tabor         case 4:
34157bffb703SJames Tabor         case 5:
34167bffb703SJames Tabor         case 6:
34177bffb703SJames Tabor         case 7:
34187bffb703SJames Tabor             if ( pPrinter == NULL )
34197bffb703SJames Tabor             {
34207bffb703SJames Tabor                 SetLastError(ERROR_INVALID_PARAMETER);
34217bffb703SJames Tabor                 return FALSE;
34227bffb703SJames Tabor             }
34237bffb703SJames Tabor             break;
34247bffb703SJames Tabor 
34257bffb703SJames Tabor         case 8:
34267bffb703SJames Tabor         /* 8 is the global default printer info and 9 already sets it instead of the per-user one */
34277bffb703SJames Tabor         /* still, PRINTER_INFO_8W is the same as PRINTER_INFO_9W */
34287bffb703SJames Tabor         /* fall through */
34297bffb703SJames Tabor         case 9:
34307bffb703SJames Tabor             {
34317bffb703SJames Tabor                 PPRINTER_INFO_9W pi9w = (PPRINTER_INFO_9W)pPrinter;
34327bffb703SJames Tabor                 if ( pi9w )
34337bffb703SJames Tabor                 {
34347bffb703SJames Tabor                     if ( pi9w->pDevMode )
34357bffb703SJames Tabor                     {
34367bffb703SJames Tabor                          if ( IsValidDevmodeNoSizeW( pi9w->pDevMode ) )
34377bffb703SJames Tabor                          {
34387bffb703SJames Tabor                              DevModeContainer.cbBuf = pi9w->pDevMode->dmSize + pi9w->pDevMode->dmDriverExtra;
34397bffb703SJames Tabor                              DevModeContainer.pDevMode = (LPBYTE)pi9w->pDevMode;
34407bffb703SJames Tabor                          }
34417bffb703SJames Tabor                     }
34427bffb703SJames Tabor                 }
34437bffb703SJames Tabor             }
34447bffb703SJames Tabor             break;
34457bffb703SJames Tabor 
34467bffb703SJames Tabor         default:
34477bffb703SJames Tabor             FIXME( "Unsupported level %d\n", Level );
34487bffb703SJames Tabor             SetLastError( ERROR_INVALID_LEVEL );
34497bffb703SJames Tabor             return FALSE;
34507bffb703SJames Tabor     }
34517bffb703SJames Tabor 
34527bffb703SJames Tabor     PrinterContainer.PrinterInfo.pPrinterInfo1 = (WINSPOOL_PRINTER_INFO_1*)pPrinter;
34537bffb703SJames Tabor     PrinterContainer.Level = Level;
34547bffb703SJames Tabor 
34557bffb703SJames Tabor     // Do the RPC call
34567bffb703SJames Tabor     RpcTryExcept
34577bffb703SJames Tabor     {
34587bffb703SJames Tabor         dwErrorCode = _RpcSetPrinter(pHandle->hPrinter, &PrinterContainer, &DevModeContainer, &SecurityContainer, Command);
34597bffb703SJames Tabor     }
34607bffb703SJames Tabor     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
34617bffb703SJames Tabor     {
34627bffb703SJames Tabor         dwErrorCode = RpcExceptionCode();
34637bffb703SJames Tabor     }
34647bffb703SJames Tabor     RpcEndExcept;
34657bffb703SJames Tabor 
34667bffb703SJames Tabor     if ( sd ) HeapFree( GetProcessHeap(), 0, sd );
34677bffb703SJames Tabor 
34687bffb703SJames Tabor     SetLastError(dwErrorCode);
34697bffb703SJames Tabor     return (dwErrorCode == ERROR_SUCCESS);
34707bffb703SJames Tabor }
3471c2c66affSColin Finck 
3472adffa8eaSJames Tabor BOOL WINAPI
SplDriverUnloadComplete(LPWSTR pDriverFile)3473adffa8eaSJames Tabor SplDriverUnloadComplete(LPWSTR pDriverFile)
3474adffa8eaSJames Tabor {
347506f8f801SSerge Gautherie     TRACE("DriverUnloadComplete(%S)\n", pDriverFile);
3476adffa8eaSJames Tabor     UNIMPLEMENTED;
3477adffa8eaSJames Tabor     return TRUE; // return true for now.
3478adffa8eaSJames Tabor }
34797bffb703SJames Tabor BOOL WINAPI
34807bffb703SJames Tabor 
SpoolerPrinterEvent(LPWSTR pPrinterName,INT DriverEvent,DWORD Flags,LPARAM lParam)34817bffb703SJames Tabor SpoolerPrinterEvent( LPWSTR pPrinterName, INT DriverEvent, DWORD Flags, LPARAM lParam )
34827bffb703SJames Tabor {
34837bffb703SJames Tabor     HMODULE hLibrary;
34847bffb703SJames Tabor     HANDLE hPrinter;
34857bffb703SJames Tabor     BOOL Ret = FALSE;
34867bffb703SJames Tabor 
34877bffb703SJames Tabor     if ( OpenPrinterW( pPrinterName, &hPrinter, NULL ) )
34887bffb703SJames Tabor     {
34897bffb703SJames Tabor         hLibrary = LoadPrinterDriver( hPrinter );
34907bffb703SJames Tabor 
34917bffb703SJames Tabor         if ( hLibrary )
34927bffb703SJames Tabor         {
34937bffb703SJames Tabor             fpPrinterEvent = (PVOID)GetProcAddress( hLibrary, "DrvPrinterEvent" );
34947bffb703SJames Tabor 
34957bffb703SJames Tabor             if ( fpPrinterEvent )
34967bffb703SJames Tabor             {
34977bffb703SJames Tabor                 Ret = fpPrinterEvent( pPrinterName, DriverEvent, Flags, lParam );
34987bffb703SJames Tabor             }
34997bffb703SJames Tabor 
35007bffb703SJames Tabor             FreeLibrary(hLibrary);
35017bffb703SJames Tabor         }
35027bffb703SJames Tabor 
35037bffb703SJames Tabor         ClosePrinter( hPrinter );
35047bffb703SJames Tabor     }
35057bffb703SJames Tabor 
35067bffb703SJames Tabor     return Ret;
35077bffb703SJames Tabor }
35087bffb703SJames Tabor 
file_dlg_proc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)35097bffb703SJames Tabor INT_PTR CALLBACK file_dlg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
35107bffb703SJames Tabor {
35117bffb703SJames Tabor     LPWSTR filename;
35127bffb703SJames Tabor 
35137bffb703SJames Tabor     switch(msg)
35147bffb703SJames Tabor     {
35157bffb703SJames Tabor     case WM_INITDIALOG:
35167bffb703SJames Tabor         SetWindowLongPtrW(hwnd, DWLP_USER, lparam);
35177bffb703SJames Tabor         return TRUE;
35187bffb703SJames Tabor 
35197bffb703SJames Tabor     case WM_COMMAND:
35207bffb703SJames Tabor         if(HIWORD(wparam) == BN_CLICKED)
35217bffb703SJames Tabor         {
35227bffb703SJames Tabor             if(LOWORD(wparam) == IDOK)
35237bffb703SJames Tabor             {
35247bffb703SJames Tabor                 HANDLE hf;
35257bffb703SJames Tabor                 DWORD len = SendDlgItemMessageW(hwnd, EDITBOX, WM_GETTEXTLENGTH, 0, 0);
35267bffb703SJames Tabor                 LPWSTR *output;
35277bffb703SJames Tabor 
35287bffb703SJames Tabor                 filename = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
35290e68e27fSTimo Kreuzer                 if (!filename)
35300e68e27fSTimo Kreuzer                 {
35310e68e27fSTimo Kreuzer                     ERR("Failed to allocate filename of %u bytes\n", (len + 1) * sizeof(WCHAR));
35320e68e27fSTimo Kreuzer                     return FALSE;
35330e68e27fSTimo Kreuzer                 }
35347bffb703SJames Tabor                 GetDlgItemTextW(hwnd, EDITBOX, filename, len + 1);
35357bffb703SJames Tabor 
35367bffb703SJames Tabor                 if(GetFileAttributesW(filename) != INVALID_FILE_ATTRIBUTES)
35377bffb703SJames Tabor                 {
35387bffb703SJames Tabor                     WCHAR caption[200], message[200];
35397bffb703SJames Tabor                     int mb_ret;
35407bffb703SJames Tabor 
35417bffb703SJames Tabor                     LoadStringW(hinstWinSpool, IDS_CAPTION, caption, ARRAYSIZE(caption));
35427bffb703SJames Tabor                     LoadStringW(hinstWinSpool, IDS_FILE_EXISTS, message, ARRAYSIZE(message));
35437bffb703SJames Tabor                     mb_ret = MessageBoxW(hwnd, message, caption, MB_OKCANCEL | MB_ICONEXCLAMATION);
35447bffb703SJames Tabor                     if(mb_ret == IDCANCEL)
35457bffb703SJames Tabor                     {
35467bffb703SJames Tabor                         HeapFree(GetProcessHeap(), 0, filename);
35477bffb703SJames Tabor                         return TRUE;
35487bffb703SJames Tabor                     }
35497bffb703SJames Tabor                 }
35507bffb703SJames Tabor                 hf = CreateFileW(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
35517bffb703SJames Tabor                 if(hf == INVALID_HANDLE_VALUE)
35527bffb703SJames Tabor                 {
35537bffb703SJames Tabor                     WCHAR caption[200], message[200];
35547bffb703SJames Tabor 
35557bffb703SJames Tabor                     LoadStringW(hinstWinSpool, IDS_CAPTION, caption, ARRAYSIZE(caption));
35567bffb703SJames Tabor                     LoadStringW(hinstWinSpool, IDS_CANNOT_OPEN, message, ARRAYSIZE(message));
35577bffb703SJames Tabor                     MessageBoxW(hwnd, message, caption, MB_OK | MB_ICONEXCLAMATION);
35587bffb703SJames Tabor                     HeapFree(GetProcessHeap(), 0, filename);
35597bffb703SJames Tabor                     return TRUE;
35607bffb703SJames Tabor                 }
35617bffb703SJames Tabor                 CloseHandle(hf);
35627bffb703SJames Tabor                 DeleteFileW(filename);
35637bffb703SJames Tabor                 output = (LPWSTR *)GetWindowLongPtrW(hwnd, DWLP_USER);
35647bffb703SJames Tabor                 *output = filename;
35657bffb703SJames Tabor                 EndDialog(hwnd, IDOK);
35667bffb703SJames Tabor                 return TRUE;
35677bffb703SJames Tabor             }
35687bffb703SJames Tabor             if(LOWORD(wparam) == IDCANCEL)
35697bffb703SJames Tabor             {
35707bffb703SJames Tabor                 EndDialog(hwnd, IDCANCEL);
35717bffb703SJames Tabor                 return TRUE;
35727bffb703SJames Tabor             }
35737bffb703SJames Tabor         }
35747bffb703SJames Tabor         return FALSE;
35757bffb703SJames Tabor     }
35767bffb703SJames Tabor     return FALSE;
35777bffb703SJames Tabor }
35787bffb703SJames Tabor 
35797bffb703SJames Tabor static const WCHAR FILE_Port[] = {'F','I','L','E',':',0};
35807bffb703SJames Tabor 
35817bffb703SJames Tabor LPWSTR WINAPI
StartDocDlgW(HANDLE hPrinter,DOCINFOW * doc)35827bffb703SJames Tabor StartDocDlgW( HANDLE hPrinter, DOCINFOW *doc )
35837bffb703SJames Tabor {
35847bffb703SJames Tabor     LPWSTR ret = NULL;
35857bffb703SJames Tabor     DWORD len, attr, retDlg;
35867bffb703SJames Tabor 
35877bffb703SJames Tabor     FIXME("StartDocDlgW(%p, %p)\n", hPrinter, doc);
35887bffb703SJames Tabor 
35897bffb703SJames Tabor     if (doc->lpszOutput == NULL) /* Check whether default port is FILE: */
35907bffb703SJames Tabor     {
35917bffb703SJames Tabor         PRINTER_INFO_5W *pi5;
35927bffb703SJames Tabor         GetPrinterW(hPrinter, 5, NULL, 0, &len);
35937bffb703SJames Tabor         if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
35947bffb703SJames Tabor             return NULL;
35957bffb703SJames Tabor         pi5 = HeapAlloc(GetProcessHeap(), 0, len);
35960e68e27fSTimo Kreuzer         if (!pi5)
35970e68e27fSTimo Kreuzer         {
35980e68e27fSTimo Kreuzer             ERR("Failed to allocate PRINTER_INFO_5W of %u bytes\n", len);
35990e68e27fSTimo Kreuzer             return NULL;
36000e68e27fSTimo Kreuzer         }
36010e68e27fSTimo Kreuzer 
36027bffb703SJames Tabor         GetPrinterW(hPrinter, 5, (LPBYTE)pi5, len, &len);
3603*e4930be4STimo Kreuzer         if (!pi5->pPortName || _wcsicmp(pi5->pPortName, FILE_Port))
36047bffb703SJames Tabor         {
36057bffb703SJames Tabor             HeapFree(GetProcessHeap(), 0, pi5);
36067bffb703SJames Tabor             return NULL;
36077bffb703SJames Tabor         }
36087bffb703SJames Tabor         HeapFree(GetProcessHeap(), 0, pi5);
36097bffb703SJames Tabor     }
36107bffb703SJames Tabor 
3611*e4930be4STimo Kreuzer     if (doc->lpszOutput == NULL || !_wcsicmp(doc->lpszOutput, FILE_Port))
36127bffb703SJames Tabor     {
36137bffb703SJames Tabor         LPWSTR name;
36147bffb703SJames Tabor 
36157bffb703SJames Tabor         retDlg = DialogBoxParamW( hinstWinSpool,
36167bffb703SJames Tabor                                   MAKEINTRESOURCEW(FILENAME_DIALOG),
36177bffb703SJames Tabor                                   GetForegroundWindow(),
36187bffb703SJames Tabor                                   file_dlg_proc,
36197bffb703SJames Tabor                                  (LPARAM)&name );
36207bffb703SJames Tabor 
36217bffb703SJames Tabor         if ( retDlg == IDOK )
36227bffb703SJames Tabor         {
36237bffb703SJames Tabor             if (!(len = GetFullPathNameW(name, 0, NULL, NULL)))
36247bffb703SJames Tabor             {
36257bffb703SJames Tabor                 HeapFree(GetProcessHeap(), 0, name);
36267bffb703SJames Tabor                 return NULL;
36277bffb703SJames Tabor             }
36287bffb703SJames Tabor             ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
36290e68e27fSTimo Kreuzer             if (!ret)
36300e68e27fSTimo Kreuzer             {
36310e68e27fSTimo Kreuzer                 ERR("Failed to allocate path name buffer of %u bytes\n", len * sizeof(WCHAR));
36320e68e27fSTimo Kreuzer                 HeapFree(GetProcessHeap(), 0, name);
36330e68e27fSTimo Kreuzer                 return NULL;
36340e68e27fSTimo Kreuzer             }
36357bffb703SJames Tabor             GetFullPathNameW(name, len, ret, NULL);
36367bffb703SJames Tabor             HeapFree(GetProcessHeap(), 0, name);
36377bffb703SJames Tabor         }
36387bffb703SJames Tabor         else if ( retDlg == 0 ) // FALSE, some type of error occurred.
36397bffb703SJames Tabor         {
36407bffb703SJames Tabor             ret = (LPWSTR)SP_ERROR;
36417bffb703SJames Tabor         }
36427bffb703SJames Tabor         else if ( retDlg == IDCANCEL )
36437bffb703SJames Tabor         {
36447bffb703SJames Tabor             SetLastError( ERROR_CANCELLED );
36457bffb703SJames Tabor             ret = (LPWSTR)SP_APPABORT;
36467bffb703SJames Tabor         }
36477bffb703SJames Tabor         return ret;
36487bffb703SJames Tabor     }
36497bffb703SJames Tabor 
36507bffb703SJames Tabor     if (!(len = GetFullPathNameW(doc->lpszOutput, 0, NULL, NULL)))
36517bffb703SJames Tabor         return NULL;
36527bffb703SJames Tabor 
36537bffb703SJames Tabor     ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
36540e68e27fSTimo Kreuzer     if (!ret)
36550e68e27fSTimo Kreuzer     {
36560e68e27fSTimo Kreuzer         ERR("Failed to allocate path name buffer of %u bytes\n", len * sizeof(WCHAR));
36570e68e27fSTimo Kreuzer         return NULL;
36580e68e27fSTimo Kreuzer     }
36597bffb703SJames Tabor     GetFullPathNameW(doc->lpszOutput, len, ret, NULL);
36607bffb703SJames Tabor 
36617bffb703SJames Tabor     attr = GetFileAttributesW(ret);
36627bffb703SJames Tabor     if (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY))
36637bffb703SJames Tabor     {
36647bffb703SJames Tabor         HeapFree(GetProcessHeap(), 0, ret);
36657bffb703SJames Tabor         ret = NULL;
36667bffb703SJames Tabor     }
36677bffb703SJames Tabor     return ret;
36687bffb703SJames Tabor }
36697bffb703SJames Tabor 
36707bffb703SJames Tabor LPSTR WINAPI
StartDocDlgA(HANDLE hPrinter,DOCINFOA * doc)36717bffb703SJames Tabor StartDocDlgA( HANDLE hPrinter, DOCINFOA *doc )
36727bffb703SJames Tabor {
36737bffb703SJames Tabor     UNICODE_STRING usBuffer;
36747bffb703SJames Tabor     DOCINFOW docW = { 0 };
36757bffb703SJames Tabor     LPWSTR retW;
36767bffb703SJames Tabor     LPWSTR docnameW = NULL, outputW = NULL, datatypeW = NULL;
36777bffb703SJames Tabor     LPSTR ret = NULL;
36787bffb703SJames Tabor 
36797bffb703SJames Tabor     docW.cbSize = sizeof(docW);
36807bffb703SJames Tabor     if (doc->lpszDocName)
36817bffb703SJames Tabor     {
36827bffb703SJames Tabor         docnameW = AsciiToUnicode(&usBuffer, doc->lpszDocName);
36837bffb703SJames Tabor         if (!(docW.lpszDocName = docnameW)) goto failed;
36847bffb703SJames Tabor     }
36857bffb703SJames Tabor     if (doc->lpszOutput)
36867bffb703SJames Tabor     {
36877bffb703SJames Tabor         outputW = AsciiToUnicode(&usBuffer, doc->lpszOutput);
36887bffb703SJames Tabor         if (!(docW.lpszOutput = outputW)) goto failed;
36897bffb703SJames Tabor     }
36907bffb703SJames Tabor     if (doc->lpszDatatype)
36917bffb703SJames Tabor     {
36927bffb703SJames Tabor         datatypeW = AsciiToUnicode(&usBuffer, doc->lpszDatatype);
36937bffb703SJames Tabor         if (!(docW.lpszDatatype = datatypeW)) goto failed;
36947bffb703SJames Tabor     }
36957bffb703SJames Tabor     docW.fwType = doc->fwType;
36967bffb703SJames Tabor 
36977bffb703SJames Tabor     retW = StartDocDlgW(hPrinter, &docW);
36987bffb703SJames Tabor 
36997bffb703SJames Tabor     if (retW)
37007bffb703SJames Tabor     {
37017bffb703SJames Tabor         DWORD len = WideCharToMultiByte(CP_ACP, 0, retW, -1, NULL, 0, NULL, NULL);
37027bffb703SJames Tabor         ret = HeapAlloc(GetProcessHeap(), 0, len);
37030e68e27fSTimo Kreuzer         if (ret)
37040e68e27fSTimo Kreuzer         {
37057bffb703SJames Tabor             WideCharToMultiByte(CP_ACP, 0, retW, -1, ret, len, NULL, NULL);
37060e68e27fSTimo Kreuzer         }
37070e68e27fSTimo Kreuzer         else
37080e68e27fSTimo Kreuzer         {
37090e68e27fSTimo Kreuzer             ERR("Failed to allocate path name buffer of %u bytes\n", len);
37100e68e27fSTimo Kreuzer         }
37117bffb703SJames Tabor         HeapFree(GetProcessHeap(), 0, retW);
37127bffb703SJames Tabor     }
37137bffb703SJames Tabor 
37147bffb703SJames Tabor failed:
37157bffb703SJames Tabor     if (datatypeW) HeapFree(GetProcessHeap(), 0, datatypeW);
37167bffb703SJames Tabor     if (outputW) HeapFree(GetProcessHeap(), 0, outputW);
37177bffb703SJames Tabor     if (docnameW) HeapFree(GetProcessHeap(), 0, docnameW);
37187bffb703SJames Tabor 
37197bffb703SJames Tabor     return ret;
37207bffb703SJames Tabor }
3721adffa8eaSJames Tabor 
3722c2c66affSColin Finck DWORD WINAPI
StartDocPrinterA(HANDLE hPrinter,DWORD Level,PBYTE pDocInfo)3723c2c66affSColin Finck StartDocPrinterA(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
3724c2c66affSColin Finck {
3725c2c66affSColin Finck     DOC_INFO_1W wDocInfo1 = { 0 };
3726c2c66affSColin Finck     DWORD cch;
3727c2c66affSColin Finck     DWORD dwErrorCode;
3728c2c66affSColin Finck     DWORD dwReturnValue = 0;
3729c2c66affSColin Finck     PDOC_INFO_1A pDocInfo1 = (PDOC_INFO_1A)pDocInfo;
3730c2c66affSColin Finck 
37311f6f08ecSColin Finck     TRACE("StartDocPrinterA(%p, %lu, %p)\n", hPrinter, Level, pDocInfo);
37321f6f08ecSColin Finck 
3733c2c66affSColin Finck     // Only check the minimum required for accessing pDocInfo.
3734c2c66affSColin Finck     // Additional sanity checks are done in StartDocPrinterW.
3735c2c66affSColin Finck     if (!pDocInfo1)
3736c2c66affSColin Finck     {
3737c2c66affSColin Finck         dwErrorCode = ERROR_INVALID_PARAMETER;
3738c2c66affSColin Finck         goto Cleanup;
3739c2c66affSColin Finck     }
3740c2c66affSColin Finck 
3741c2c66affSColin Finck     if (Level != 1)
3742c2c66affSColin Finck     {
37437bffb703SJames Tabor         ERR("Level = %d, unsupported!\n", Level);
3744c2c66affSColin Finck         dwErrorCode = ERROR_INVALID_LEVEL;
3745c2c66affSColin Finck         goto Cleanup;
3746c2c66affSColin Finck     }
3747c2c66affSColin Finck 
3748c2c66affSColin Finck     if (pDocInfo1->pDatatype)
3749c2c66affSColin Finck     {
3750c2c66affSColin Finck         // Convert pDocInfo1->pDatatype to a Unicode string wDocInfo1.pDatatype
3751c2c66affSColin Finck         cch = strlen(pDocInfo1->pDatatype);
3752c2c66affSColin Finck 
3753c2c66affSColin Finck         wDocInfo1.pDatatype = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
3754c2c66affSColin Finck         if (!wDocInfo1.pDatatype)
3755c2c66affSColin Finck         {
3756c2c66affSColin Finck             dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
3757c2c66affSColin Finck             ERR("HeapAlloc failed!\n");
3758c2c66affSColin Finck             goto Cleanup;
3759c2c66affSColin Finck         }
3760c2c66affSColin Finck 
3761c2c66affSColin Finck         MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pDatatype, -1, wDocInfo1.pDatatype, cch + 1);
3762c2c66affSColin Finck     }
3763c2c66affSColin Finck 
3764c2c66affSColin Finck     if (pDocInfo1->pDocName)
3765c2c66affSColin Finck     {
3766c2c66affSColin Finck         // Convert pDocInfo1->pDocName to a Unicode string wDocInfo1.pDocName
3767c2c66affSColin Finck         cch = strlen(pDocInfo1->pDocName);
3768c2c66affSColin Finck 
3769c2c66affSColin Finck         wDocInfo1.pDocName = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
3770c2c66affSColin Finck         if (!wDocInfo1.pDocName)
3771c2c66affSColin Finck         {
3772c2c66affSColin Finck             dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
3773c2c66affSColin Finck             ERR("HeapAlloc failed!\n");
3774c2c66affSColin Finck             goto Cleanup;
3775c2c66affSColin Finck         }
3776c2c66affSColin Finck 
3777c2c66affSColin Finck         MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pDocName, -1, wDocInfo1.pDocName, cch + 1);
3778c2c66affSColin Finck     }
3779c2c66affSColin Finck 
3780c2c66affSColin Finck     if (pDocInfo1->pOutputFile)
3781c2c66affSColin Finck     {
3782c2c66affSColin Finck         // Convert pDocInfo1->pOutputFile to a Unicode string wDocInfo1.pOutputFile
3783c2c66affSColin Finck         cch = strlen(pDocInfo1->pOutputFile);
3784c2c66affSColin Finck 
3785c2c66affSColin Finck         wDocInfo1.pOutputFile = HeapAlloc(hProcessHeap, 0, (cch + 1) * sizeof(WCHAR));
3786c2c66affSColin Finck         if (!wDocInfo1.pOutputFile)
3787c2c66affSColin Finck         {
3788c2c66affSColin Finck             dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
3789c2c66affSColin Finck             ERR("HeapAlloc failed!\n");
3790c2c66affSColin Finck             goto Cleanup;
3791c2c66affSColin Finck         }
3792c2c66affSColin Finck 
3793c2c66affSColin Finck         MultiByteToWideChar(CP_ACP, 0, pDocInfo1->pOutputFile, -1, wDocInfo1.pOutputFile, cch + 1);
3794c2c66affSColin Finck     }
3795c2c66affSColin Finck 
3796c2c66affSColin Finck     dwReturnValue = StartDocPrinterW(hPrinter, Level, (PBYTE)&wDocInfo1);
3797c2c66affSColin Finck     dwErrorCode = GetLastError();
3798c2c66affSColin Finck 
3799c2c66affSColin Finck Cleanup:
3800c2c66affSColin Finck     if (wDocInfo1.pDatatype)
3801c2c66affSColin Finck         HeapFree(hProcessHeap, 0, wDocInfo1.pDatatype);
3802c2c66affSColin Finck 
3803c2c66affSColin Finck     if (wDocInfo1.pDocName)
3804c2c66affSColin Finck         HeapFree(hProcessHeap, 0, wDocInfo1.pDocName);
3805c2c66affSColin Finck 
3806c2c66affSColin Finck     if (wDocInfo1.pOutputFile)
3807c2c66affSColin Finck         HeapFree(hProcessHeap, 0, wDocInfo1.pOutputFile);
3808c2c66affSColin Finck 
3809c2c66affSColin Finck     SetLastError(dwErrorCode);
3810c2c66affSColin Finck     return dwReturnValue;
3811c2c66affSColin Finck }
3812c2c66affSColin Finck 
3813c2c66affSColin Finck DWORD WINAPI
StartDocPrinterW(HANDLE hPrinter,DWORD Level,PBYTE pDocInfo)3814c2c66affSColin Finck StartDocPrinterW(HANDLE hPrinter, DWORD Level, PBYTE pDocInfo)
3815c2c66affSColin Finck {
3816c2c66affSColin Finck     DWORD cbAddJobInfo1;
3817c2c66affSColin Finck     DWORD cbNeeded;
3818c2c66affSColin Finck     DWORD dwErrorCode;
3819c2c66affSColin Finck     DWORD dwReturnValue = 0;
3820c2c66affSColin Finck     PADDJOB_INFO_1W pAddJobInfo1 = NULL;
3821c2c66affSColin Finck     PDOC_INFO_1W pDocInfo1 = (PDOC_INFO_1W)pDocInfo;
3822c2c66affSColin Finck     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
3823c2c66affSColin Finck 
38241f6f08ecSColin Finck     TRACE("StartDocPrinterW(%p, %lu, %p)\n", hPrinter, Level, pDocInfo);
38251f6f08ecSColin Finck 
3826c2c66affSColin Finck     // Sanity checks.
3827c2c66affSColin Finck     if (!pHandle)
3828c2c66affSColin Finck     {
3829c2c66affSColin Finck         dwErrorCode = ERROR_INVALID_HANDLE;
3830c2c66affSColin Finck         goto Cleanup;
3831c2c66affSColin Finck     }
3832c2c66affSColin Finck 
3833c2c66affSColin Finck     if (!pDocInfo1)
3834c2c66affSColin Finck     {
3835c2c66affSColin Finck         dwErrorCode = ERROR_INVALID_PARAMETER;
3836c2c66affSColin Finck         goto Cleanup;
3837c2c66affSColin Finck     }
3838c2c66affSColin Finck 
3839c2c66affSColin Finck     if (Level != 1)
3840c2c66affSColin Finck     {
38417bffb703SJames Tabor         ERR("Level = %d, unsupported!\n", Level);
3842c2c66affSColin Finck         dwErrorCode = ERROR_INVALID_LEVEL;
3843c2c66affSColin Finck         goto Cleanup;
3844c2c66affSColin Finck     }
3845c2c66affSColin Finck 
3846c2c66affSColin Finck     if (pHandle->bStartedDoc)
3847c2c66affSColin Finck     {
3848c2c66affSColin Finck         dwErrorCode = ERROR_INVALID_PRINTER_STATE;
3849c2c66affSColin Finck         goto Cleanup;
3850c2c66affSColin Finck     }
3851c2c66affSColin Finck 
3852c2c66affSColin Finck     // Check if we want to redirect output into a file.
3853c2c66affSColin Finck     if (pDocInfo1->pOutputFile)
3854c2c66affSColin Finck     {
3855c2c66affSColin Finck         // Do a StartDocPrinter RPC call in this case.
3856c2c66affSColin Finck         dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1);
3857c2c66affSColin Finck     }
3858c2c66affSColin Finck     else
3859c2c66affSColin Finck     {
3860c2c66affSColin Finck         // Allocate memory for the ADDJOB_INFO_1W structure and a path.
3861c2c66affSColin Finck         cbAddJobInfo1 = sizeof(ADDJOB_INFO_1W) + MAX_PATH * sizeof(WCHAR);
3862c2c66affSColin Finck         pAddJobInfo1 = HeapAlloc(hProcessHeap, 0, cbAddJobInfo1);
3863c2c66affSColin Finck         if (!pAddJobInfo1)
3864c2c66affSColin Finck         {
3865c2c66affSColin Finck             dwErrorCode = ERROR_NOT_ENOUGH_MEMORY;
3866c2c66affSColin Finck             ERR("HeapAlloc failed!\n");
3867c2c66affSColin Finck             goto Cleanup;
3868c2c66affSColin Finck         }
3869c2c66affSColin Finck 
3870c2c66affSColin Finck         // Try to add a new job.
3871c2c66affSColin Finck         // This only succeeds if the printer is set to do spooled printing.
3872c2c66affSColin Finck         if (AddJobW((HANDLE)pHandle, 1, (PBYTE)pAddJobInfo1, cbAddJobInfo1, &cbNeeded))
3873c2c66affSColin Finck         {
3874c2c66affSColin Finck             // Do spooled printing.
3875c2c66affSColin Finck             dwErrorCode = _StartDocPrinterSpooled(pHandle, pDocInfo1, pAddJobInfo1);
3876c2c66affSColin Finck         }
3877c2c66affSColin Finck         else if (GetLastError() == ERROR_INVALID_ACCESS)
3878c2c66affSColin Finck         {
3879c2c66affSColin Finck             // ERROR_INVALID_ACCESS is returned when the printer is set to do direct printing.
3880c2c66affSColin Finck             // In this case, we do a StartDocPrinter RPC call.
3881c2c66affSColin Finck             dwErrorCode = _StartDocPrinterWithRPC(pHandle, pDocInfo1);
3882c2c66affSColin Finck         }
3883c2c66affSColin Finck         else
3884c2c66affSColin Finck         {
3885c2c66affSColin Finck             dwErrorCode = GetLastError();
3886c2c66affSColin Finck             ERR("AddJobW failed with error %lu!\n", dwErrorCode);
3887c2c66affSColin Finck             goto Cleanup;
3888c2c66affSColin Finck         }
3889c2c66affSColin Finck     }
3890c2c66affSColin Finck 
3891c2c66affSColin Finck     if (dwErrorCode == ERROR_SUCCESS)
3892c2c66affSColin Finck     {
3893c2c66affSColin Finck         pHandle->bStartedDoc = TRUE;
3894c2c66affSColin Finck         dwReturnValue = pHandle->dwJobID;
38957bffb703SJames Tabor         if ( !pHandle->bTrayIcon )
38967bffb703SJames Tabor         {
389762c4b828SJames Tabor             UpdateTrayIcon( hPrinter, pHandle->dwJobID );
38987bffb703SJames Tabor         }
3899c2c66affSColin Finck     }
3900c2c66affSColin Finck 
3901c2c66affSColin Finck Cleanup:
3902c2c66affSColin Finck     if (pAddJobInfo1)
3903c2c66affSColin Finck         HeapFree(hProcessHeap, 0, pAddJobInfo1);
3904c2c66affSColin Finck 
3905c2c66affSColin Finck     SetLastError(dwErrorCode);
3906c2c66affSColin Finck     return dwReturnValue;
3907c2c66affSColin Finck }
3908c2c66affSColin Finck 
3909c2c66affSColin Finck BOOL WINAPI
StartPagePrinter(HANDLE hPrinter)3910c2c66affSColin Finck StartPagePrinter(HANDLE hPrinter)
3911c2c66affSColin Finck {
3912c2c66affSColin Finck     DWORD dwErrorCode;
3913c2c66affSColin Finck     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
3914c2c66affSColin Finck 
39151f6f08ecSColin Finck     TRACE("StartPagePrinter(%p)\n", hPrinter);
39161f6f08ecSColin Finck 
3917c2c66affSColin Finck     // Sanity checks.
3918c2c66affSColin Finck     if (!pHandle)
3919c2c66affSColin Finck     {
3920c2c66affSColin Finck         dwErrorCode = ERROR_INVALID_HANDLE;
3921c2c66affSColin Finck         goto Cleanup;
3922c2c66affSColin Finck     }
3923c2c66affSColin Finck 
3924c2c66affSColin Finck     // Do the RPC call
3925c2c66affSColin Finck     RpcTryExcept
3926c2c66affSColin Finck     {
3927c2c66affSColin Finck         dwErrorCode = _RpcStartPagePrinter(pHandle->hPrinter);
3928c2c66affSColin Finck     }
3929c2c66affSColin Finck     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
3930c2c66affSColin Finck     {
3931c2c66affSColin Finck         dwErrorCode = RpcExceptionCode();
3932c2c66affSColin Finck         ERR("_RpcStartPagePrinter failed with exception code %lu!\n", dwErrorCode);
3933c2c66affSColin Finck     }
3934c2c66affSColin Finck     RpcEndExcept;
3935c2c66affSColin Finck 
3936c2c66affSColin Finck Cleanup:
3937c2c66affSColin Finck     SetLastError(dwErrorCode);
3938c2c66affSColin Finck     return (dwErrorCode == ERROR_SUCCESS);
3939c2c66affSColin Finck }
3940c2c66affSColin Finck 
3941c2c66affSColin Finck BOOL WINAPI
WritePrinter(HANDLE hPrinter,PVOID pBuf,DWORD cbBuf,PDWORD pcWritten)3942c2c66affSColin Finck WritePrinter(HANDLE hPrinter, PVOID pBuf, DWORD cbBuf, PDWORD pcWritten)
3943c2c66affSColin Finck {
3944c2c66affSColin Finck     DWORD dwErrorCode;
3945c2c66affSColin Finck     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hPrinter;
3946c2c66affSColin Finck 
39471f6f08ecSColin Finck     TRACE("WritePrinter(%p, %p, %lu, %p)\n", hPrinter, pBuf, cbBuf, pcWritten);
39481f6f08ecSColin Finck 
3949c2c66affSColin Finck     // Sanity checks.
3950c2c66affSColin Finck     if (!pHandle)
3951c2c66affSColin Finck     {
3952c2c66affSColin Finck         dwErrorCode = ERROR_INVALID_HANDLE;
3953c2c66affSColin Finck         goto Cleanup;
3954c2c66affSColin Finck     }
3955c2c66affSColin Finck 
3956c2c66affSColin Finck     if (!pHandle->bStartedDoc)
3957c2c66affSColin Finck     {
3958c2c66affSColin Finck         dwErrorCode = ERROR_SPL_NO_STARTDOC;
3959c2c66affSColin Finck         goto Cleanup;
3960c2c66affSColin Finck     }
3961c2c66affSColin Finck 
3962c2c66affSColin Finck     if (pHandle->hSPLFile != INVALID_HANDLE_VALUE)
3963c2c66affSColin Finck     {
3964c2c66affSColin Finck         // Write to the spool file. This doesn't need an RPC request.
3965c2c66affSColin Finck         if (!WriteFile(pHandle->hSPLFile, pBuf, cbBuf, pcWritten, NULL))
3966c2c66affSColin Finck         {
3967c2c66affSColin Finck             dwErrorCode = GetLastError();
3968c2c66affSColin Finck             ERR("WriteFile failed with error %lu!\n", dwErrorCode);
3969c2c66affSColin Finck             goto Cleanup;
3970c2c66affSColin Finck         }
3971c2c66affSColin Finck 
3972c2c66affSColin Finck         dwErrorCode = ERROR_SUCCESS;
3973c2c66affSColin Finck     }
3974c2c66affSColin Finck     else
3975c2c66affSColin Finck     {
3976c2c66affSColin Finck         // TODO: This case (for direct printing or remote printing) has bad performance if multiple small-sized WritePrinter calls are performed.
3977c2c66affSColin Finck         // We may increase performance by writing into a buffer and only doing a single RPC call when the buffer is full.
3978c2c66affSColin Finck 
3979c2c66affSColin Finck         // Do the RPC call
3980c2c66affSColin Finck         RpcTryExcept
3981c2c66affSColin Finck         {
3982c2c66affSColin Finck             dwErrorCode = _RpcWritePrinter(pHandle->hPrinter, pBuf, cbBuf, pcWritten);
3983c2c66affSColin Finck         }
3984c2c66affSColin Finck         RpcExcept(EXCEPTION_EXECUTE_HANDLER)
3985c2c66affSColin Finck         {
3986c2c66affSColin Finck             dwErrorCode = RpcExceptionCode();
3987c2c66affSColin Finck             ERR("_RpcWritePrinter failed with exception code %lu!\n", dwErrorCode);
3988c2c66affSColin Finck         }
3989c2c66affSColin Finck         RpcEndExcept;
3990c2c66affSColin Finck     }
3991c2c66affSColin Finck 
3992c2c66affSColin Finck Cleanup:
3993c2c66affSColin Finck     SetLastError(dwErrorCode);
3994c2c66affSColin Finck     return (dwErrorCode == ERROR_SUCCESS);
3995c2c66affSColin Finck }
3996c2c66affSColin Finck 
3997c2c66affSColin Finck BOOL WINAPI
XcvDataW(HANDLE hXcv,PCWSTR pszDataName,PBYTE pInputData,DWORD cbInputData,PBYTE pOutputData,DWORD cbOutputData,PDWORD pcbOutputNeeded,PDWORD pdwStatus)3998c2c66affSColin Finck XcvDataW(HANDLE hXcv, PCWSTR pszDataName, PBYTE pInputData, DWORD cbInputData, PBYTE pOutputData, DWORD cbOutputData, PDWORD pcbOutputNeeded, PDWORD pdwStatus)
3999c2c66affSColin Finck {
400062c4b828SJames Tabor     DWORD dwErrorCode, Bogus = 0;
400162c4b828SJames Tabor     PSPOOLER_HANDLE pHandle = (PSPOOLER_HANDLE)hXcv;
400262c4b828SJames Tabor 
40031f6f08ecSColin Finck     TRACE("XcvDataW(%p, %S, %p, %lu, %p, %lu, %p, %p)\n", hXcv, pszDataName, pInputData, cbInputData, pOutputData, cbOutputData, pcbOutputNeeded, pdwStatus);
400462c4b828SJames Tabor 
400562c4b828SJames Tabor     if ( pcbOutputNeeded == NULL )
400662c4b828SJames Tabor     {
400762c4b828SJames Tabor         dwErrorCode = ERROR_INVALID_PARAMETER;
400862c4b828SJames Tabor         goto Cleanup;
400962c4b828SJames Tabor     }
401062c4b828SJames Tabor 
401162c4b828SJames Tabor     // Sanity checks.
401262c4b828SJames Tabor     if (!pHandle) // ( IntProtectHandle( hXcv, FALSE ) )
401362c4b828SJames Tabor     {
401462c4b828SJames Tabor         dwErrorCode = ERROR_INVALID_HANDLE;
401562c4b828SJames Tabor         goto Cleanup;
401662c4b828SJames Tabor     }
401762c4b828SJames Tabor 
401862c4b828SJames Tabor     //
401962c4b828SJames Tabor     // Do fixups.
402062c4b828SJames Tabor     //
402162c4b828SJames Tabor     if ( pInputData == NULL )
402262c4b828SJames Tabor     {
402362c4b828SJames Tabor         if ( !cbInputData )
402462c4b828SJames Tabor         {
402562c4b828SJames Tabor              pInputData = (PBYTE)&Bogus;
402662c4b828SJames Tabor         }
402762c4b828SJames Tabor     }
402862c4b828SJames Tabor 
402962c4b828SJames Tabor     if ( pOutputData == NULL )
403062c4b828SJames Tabor     {
403162c4b828SJames Tabor         if ( !cbOutputData )
403262c4b828SJames Tabor         {
403362c4b828SJames Tabor             pOutputData = (PBYTE)&Bogus;
403462c4b828SJames Tabor         }
403562c4b828SJames Tabor     }
403662c4b828SJames Tabor 
403762c4b828SJames Tabor     // Do the RPC call
403862c4b828SJames Tabor     RpcTryExcept
403962c4b828SJames Tabor     {
404062c4b828SJames Tabor         dwErrorCode = _RpcXcvData( pHandle->hPrinter,
404162c4b828SJames Tabor                                    pszDataName,
404262c4b828SJames Tabor                                    pInputData,
404362c4b828SJames Tabor                                    cbInputData,
404462c4b828SJames Tabor                                    pOutputData,
404562c4b828SJames Tabor                                    cbOutputData,
404662c4b828SJames Tabor                                    pcbOutputNeeded,
404762c4b828SJames Tabor                                    pdwStatus );
404862c4b828SJames Tabor     }
404962c4b828SJames Tabor     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
405062c4b828SJames Tabor     {
405162c4b828SJames Tabor         dwErrorCode = RpcExceptionCode();
405262c4b828SJames Tabor         ERR("_RpcXcvData failed with exception code %lu!\n", dwErrorCode);
405362c4b828SJames Tabor     }
405462c4b828SJames Tabor     RpcEndExcept;
405562c4b828SJames Tabor 
405662c4b828SJames Tabor     //IntUnprotectHandle( hXcv );
405762c4b828SJames Tabor 
405862c4b828SJames Tabor Cleanup:
405962c4b828SJames Tabor     SetLastError(dwErrorCode);
406062c4b828SJames Tabor     return (dwErrorCode == ERROR_SUCCESS);
4061c2c66affSColin Finck }
4062a2a8ce49STimo Kreuzer 
4063a2a8ce49STimo Kreuzer HANDLE
4064a2a8ce49STimo Kreuzer WINAPI
CreatePrinterIC(_In_ HANDLE hPrinter,_In_opt_ LPDEVMODEW pDevMode)4065a2a8ce49STimo Kreuzer CreatePrinterIC(
4066a2a8ce49STimo Kreuzer     _In_ HANDLE hPrinter,
4067a2a8ce49STimo Kreuzer     _In_opt_ LPDEVMODEW pDevMode)
4068a2a8ce49STimo Kreuzer {
4069a2a8ce49STimo Kreuzer     UNIMPLEMENTED;
4070a2a8ce49STimo Kreuzer     return NULL;
4071a2a8ce49STimo Kreuzer }
4072a2a8ce49STimo Kreuzer 
4073a2a8ce49STimo Kreuzer BOOL
4074a2a8ce49STimo Kreuzer WINAPI
DeletePrinterIC(_In_ HANDLE hPrinterIC)4075a2a8ce49STimo Kreuzer DeletePrinterIC(
4076a2a8ce49STimo Kreuzer     _In_ HANDLE hPrinterIC)
4077a2a8ce49STimo Kreuzer {
4078a2a8ce49STimo Kreuzer     UNIMPLEMENTED;
4079a2a8ce49STimo Kreuzer     return FALSE;
4080a2a8ce49STimo Kreuzer }
4081a2a8ce49STimo Kreuzer 
4082a2a8ce49STimo Kreuzer BOOL
4083a2a8ce49STimo Kreuzer WINAPI
PlayGdiScriptOnPrinterIC(_In_ HANDLE hPrinterIC,_In_reads_bytes_ (cIn)LPBYTE pIn,_In_ DWORD cIn,_Out_writes_bytes_ (cOut)LPBYTE pOut,_In_ DWORD cOut,_In_ DWORD ul)4084a2a8ce49STimo Kreuzer PlayGdiScriptOnPrinterIC(
4085a2a8ce49STimo Kreuzer     _In_ HANDLE hPrinterIC,
4086a2a8ce49STimo Kreuzer     _In_reads_bytes_(cIn) LPBYTE pIn,
4087a2a8ce49STimo Kreuzer     _In_ DWORD cIn,
4088a2a8ce49STimo Kreuzer     _Out_writes_bytes_(cOut) LPBYTE pOut,
4089a2a8ce49STimo Kreuzer     _In_ DWORD cOut,
4090a2a8ce49STimo Kreuzer     _In_ DWORD ul)
4091a2a8ce49STimo Kreuzer {
4092a2a8ce49STimo Kreuzer     UNIMPLEMENTED;
4093a2a8ce49STimo Kreuzer     return FALSE;
4094a2a8ce49STimo Kreuzer }
4095