source: trunk/src/winspool/winspool.cpp@ 21342

Last change on this file since 21342 was 21342, checked in by abwillis, 16 years ago

VAC365 build updates. dsound update seems to help VAC308 some here too.

File size: 112.2 KB
Line 
1
2/*
3 *
4 * Project Odin Software License can be found in LICENSE.TXT
5 *
6 * WINSPOOL implemention
7 *
8 * Copyright 1998 Patrick Haller
9 * Copyright 2000 Sander van Leeuwen (sandervl@xs4all.nl)
10 * Copyright 2003-2004 InnoTek Systemberatung GmbH
11 *
12 *
13 * Partially based on WineX code (dlls\winspool\info.c (EnumPrinters, DeviceCapabilitiesA/W)
14 *
15 * Copyright 1996 John Harvey
16 * Copyright 1998 Andreas Mohr
17 * Copyright 1999 Klaas van Gend
18 * Copyright 1999, 2000 Huw D M Davies
19 *
20 *
21 */
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#include <windows.h>
27#include <os2win.h>
28#include <winspool.h>
29#include <odinwrap.h>
30#include <heapstring.h>
31#include <win\winnls.h>
32#include <win\debugstr.h>
33#include <win\debugtools.h>
34
35#include <stdio.h>
36#include <stdlib.h>
37#include <stddef.h>
38#include <string.h>
39#include <misc.h>
40#ifdef __WIN32OS2__
41# include <vmutex.h>
42# include <unicode.h>
43#endif
44#include "oslibspl.h"
45
46
47/*******************************************************************************
48* Defined Constants And Macros *
49*******************************************************************************/
50#ifdef __WIN32OS2__
51/**
52 * Debug assertion macro.
53 * @param expr Assert that this expression is true.
54 * @param msg Message to print if expr isn't true. It's given to dprintf,
55 * and must be inclosed in paratheses.
56 * @todo move this to some header in /include.
57 */
58#ifdef DEBUG
59#define DebugAssert(expr, msg) \
60 do { if (expr) break; \
61 dprintf(("!!!ASSERTION FAILED!!!\nFILE=%s\nLINE=%d\nFUNCTION=%s\n", __FILE__, __LINE__, __FUNCTION__)); \
62 dprintf(msg); DebugInt3(); \
63 } while (0)
64#else
65#define DebugAssert(expr, msg) do {} while (0)
66#endif
67
68/**
69 * Debug assertion failed macro.
70 * @param msg Message to print if expr isn't true. It's given to dprintf,
71 * and must be inclosed in paratheses.
72 * @todo move this to some header in /include.
73 */
74#ifdef DEBUG
75#define DebugAssertFailed(msg) \
76 do { dprintf(("!!!ASSERTION FAILED!!!\nFILE=%s\nLINE=%d\nFUNCTION=%s\n", __FILE__, __LINE__, __FUNCTION__)); \
77 dprintf(msg); DebugInt3(); \
78 } while (0)
79#else
80#define DebugAssertFailed(msg) do {} while (0)
81#endif
82
83#endif
84
85/** Define this to use the OS/2 printer driver names. */
86#define USE_OS2_DRIVERNAME
87
88/*******************************************************************************
89* Structures and Typedefs *
90*******************************************************************************/
91#ifdef __WIN32OS2__
92/**
93 * Open printer instance.
94 * @todo protect the structure while using it. (probably not an issue)
95 */
96typedef struct _OpenPrinter
97{
98 /** The handle of this instance. */
99 HANDLE hOpenPrinter;
100 /** Pointer to the next entry. */
101 struct _OpenPrinter *pNext;
102 /** Printer name. */
103 LPWSTR pwszPrinterName;
104
105 /** Open spool file. */
106 HANDLE hspl;
107 /** Current page number in the job (for StartPagePrinter()). */
108 ULONG ulCurPage;
109} OPENPRINTER, *POPENPRINTER;
110#endif
111
112
113/*******************************************************************************
114* Global Variables *
115*******************************************************************************/
116#ifdef __WIN32OS2__
117/** LIFO of open printers. */
118POPENPRINTER gpOpenPrinters;
119/** Last Printer handle.
120 * This assumes that 4G open printers are enough and that the caller accepts high
121 * values. */
122HANDLE ghOpenPrintersLast;
123/** Mutex protecting gpOpenPrinters and ghOpenPrintersLast.
124 * This protects only the list, not the entries themself. */
125VMutex gOpenPrintersMutex;
126#endif
127
128
129static char Printers[] =
130"System\\CurrentControlSet\\control\\Print\\Printers\\";
131static char Drivers[] =
132"System\\CurrentControlSet\\control\\Print\\Environments\\%s\\Drivers\\";
133
134WINAPI GDI_CallExtDeviceMode16 ( HWND hwnd, LPDEVMODEA lpdmOutput,
135 LPSTR lpszDevice, LPSTR lpszPort,
136 LPDEVMODEA lpdmInput, LPSTR lpszProfile,
137 DWORD fwMode );
138#ifndef __WIN32OS2__
139static LPWSTR *printer_array;
140static int nb_printers;
141#endif
142static WCHAR DefaultEnvironmentW[] = {'W','i','n','e',0};
143
144static WCHAR Configuration_FileW[] = {'C','o','n','f','i','g','u','r','a','t',
145 'i','o','n',' ','F','i','l','e',0};
146static WCHAR DatatypeW[] = {'D','a','t','a','t','y','p','e',0};
147static WCHAR Data_FileW[] = {'D','a','t','a',' ','F','i','l','e',0};
148static WCHAR Default_DevModeW[] = {'D','e','f','a','u','l','t',' ','D','e','v',
149 'M','o','d','e',0};
150static WCHAR Dependent_FilesW[] = {'D','e','p','e','n','d','e','n','t',' ','F',
151 'i','l','e','s',0};
152static WCHAR DescriptionW[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
153static WCHAR DriverW[] = {'D','r','i','v','e','r',0};
154static WCHAR Help_FileW[] = {'H','e','l','p',' ','F','i','l','e',0};
155static WCHAR LocationW[] = {'L','o','c','a','t','i','o','n',0};
156static WCHAR MonitorW[] = {'M','o','n','i','t','o','r',0};
157static WCHAR NameW[] = {'N','a','m','e',0};
158static WCHAR ParametersW[] = {'P','a','r','a','m','e','t','e','r','s',0};
159static WCHAR PortW[] = {'P','o','r','t',0};
160static WCHAR Print_ProcessorW[] = {'P','r','i','n','t',' ','P','r','o','c','e',
161 's','s','o','r',0};
162static WCHAR Printer_DriverW[] = {'P','r','i','n','t','e','r',' ','D','r','i',
163 'v','e','r',0};
164static WCHAR PrinterDriverDataW[] = {'P','r','i','n','t','e','r','D','r','i',
165 'v','e','r','D','a','t','a',0};
166static WCHAR Separator_FileW[] = {'S','e','p','a','r','a','t','o','r',' ','F',
167 'i','l','e',0};
168static WCHAR Share_NameW[] = {'S','h','a','r','e',' ','N','a','m','e',0};
169static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
170
171ODINDEBUGCHANNEL(WINSPOOL)
172
173/*******************************************************************************
174* Internal Functions *
175*******************************************************************************/
176#ifdef __WIN32OS2__
177BOOL WIN32API SplQueryPMQueueFromHandle(HANDLE hPrinter, char *pszQueue, unsigned cchQueue);
178BOOL WIN32API SplQueryPMQueueName(LPSTR pszPrinterName, LPSTR pszQueue, INT cchQueue);
179static POPENPRINTER openprinterNew(LPCWSTR pwszPrinterName);
180static POPENPRINTER openprinterFind(HANDLE hHandle);
181static void openprinterDelete(POPENPRINTER pOpenPrinter);
182static int openprinterOpenSpoolFile(POPENPRINTER pOpenPrinter);
183
184
185/**
186 * Allocates, copies the data from pOpenPrinter into the new node and
187 * inserts it into the list.
188 *
189 * @returns Pointer to the inserted node.
190 * @returns NULL on failure (i.e. out of memory).
191 * @param pwszPrinterName Pointer to printer name. (Duplicated)
192 *
193 */
194static POPENPRINTER openprinterNew(LPCWSTR pwszPrinterName)
195{
196 POPENPRINTER pNew = (POPENPRINTER)malloc(sizeof(*pNew));
197 if (pNew)
198 {
199 memset(pNew, 0, sizeof(*pNew));
200 pNew->pwszPrinterName = HEAP_strdupW(GetProcessHeap(), 0, pwszPrinterName);
201 if (pNew->pwszPrinterName)
202 {
203 gOpenPrintersMutex.enter();
204 pNew->hOpenPrinter = ++ghOpenPrintersLast;
205 pNew->pNext = gpOpenPrinters;
206 gpOpenPrinters = pNew;
207 gOpenPrintersMutex.leave();
208 }
209 else
210 {
211 free(pNew);
212 pNew = NULL;
213 }
214 }
215 return pNew;
216}
217
218
219/**
220 * Finds the data associated with an open printer handle.
221 *
222 * @returns Pointer to the data associated with the handle.
223 * @param hHandle The handle of the open printer.
224 */
225static POPENPRINTER openprinterFind(HANDLE hHandle)
226{
227 POPENPRINTER pOpenPrinter;
228
229 gOpenPrintersMutex.enter();
230 for (pOpenPrinter = gpOpenPrinters; pOpenPrinter; pOpenPrinter = pOpenPrinter->pNext)
231 if (pOpenPrinter->hOpenPrinter == hHandle)
232 break;
233 gOpenPrintersMutex.leave();
234 return pOpenPrinter;
235}
236
237
238/**
239 * Unlinks and frees an open printer node.
240 * The caller must release any other resources associated with it.
241 *
242 * @param pOpenPrinter Pointer to the node to delete.
243 */
244static void openprinterDelete(POPENPRINTER pOpenPrinter)
245{
246 /*
247 * Unlink it.
248 */
249 gOpenPrintersMutex.enter();
250 if (gpOpenPrinters == pOpenPrinter)
251 gpOpenPrinters = gpOpenPrinters->pNext;
252 else
253 {
254 POPENPRINTER p;
255 for (p = gpOpenPrinters; p->pNext; p = pOpenPrinter->pNext)
256 {
257 if (p->pNext == pOpenPrinter)
258 {
259 p->pNext = pOpenPrinter->pNext;
260 break;
261 }
262 }
263 if (!p->pNext)
264 pOpenPrinter = NULL;
265 }
266 gOpenPrintersMutex.leave();
267
268 /*
269 * Delete it.
270 */
271 DebugAssert(pOpenPrinter, ("the node %p was not found!\n", pOpenPrinter));
272 if (pOpenPrinter)
273 {
274 pOpenPrinter->pNext = NULL;
275 free(pOpenPrinter);
276 }
277}
278
279/**
280 * Opens the OS/2 spool file associated with the open printer if not
281 * already opened.
282 *
283 * @returns NO_ERROR on success.
284 * @returns OS/2 error code. May have changed the last error.
285 * @param pOpenPrinter Open printer instance.
286 */
287static int openprinterOpenSpoolFile(POPENPRINTER pOpenPrinter)
288{
289 if (pOpenPrinter->hspl)
290 return NO_ERROR;
291
292 /*
293 * First, get the queue name.
294 */
295 char szQueue[16];
296 int rc = NO_ERROR;
297 if (SplQueryPMQueueFromHandle(pOpenPrinter->hOpenPrinter, &szQueue[0], sizeof(szQueue)))
298 {
299 POSLIB_PRQINFO3 pPrqInfo3 = (POSLIB_PRQINFO3)OSLibSplQueryQueue(NULL, &szQueue[0], 3);
300 if (pPrqInfo3)
301 {
302 OSLIB_DEVOPENSTRUC DevOpen = {0};
303 DevOpen.pszLogAddress = &szQueue[0];
304 DevOpen.pszDriverName = pPrqInfo3->pszDriverName; /* always use default driver */
305 pOpenPrinter->hspl = OSLibSplQmOpen(NULL, 4 /* must be 4 or more */, &DevOpen.pszLogAddress);
306 if (pOpenPrinter->hspl)
307 {
308 dprintf(("WINSPOOL: openprinterOpenSpoolFile: handle %d -> hspl %#x\n",
309 pOpenPrinter->hOpenPrinter, pOpenPrinter->hspl));
310 rc = NO_ERROR;
311 }
312 else
313 {
314 rc = OSLibSplWinGetLastError();
315 DebugAssertFailed(("OSLibSplQmOpen failed! rc=%#x\n", rc));
316 }
317 free(pPrqInfo3);
318 }
319 else
320 {
321 rc = ERROR_GEN_FAILURE;
322 DebugAssertFailed(("OSLibSplQueryQueue(,%s,3) failed\n", szQueue));
323 }
324 }
325 else
326 {
327 rc = ERROR_GEN_FAILURE;
328 DebugAssertFailed(("SplQueryPMQueueFromHandle failed\n"));
329 }
330 return rc;
331}
332
333
334/**
335 * Gets the OS/2 queue name for an open printer device.
336 *
337 * @returns Success indicator.
338 * @param hPrinter Printer handle.
339 * @param pszQueue Where to put the queue name.
340 * @param cchQueue Size of the queue buffer pointed to by pszQueue.
341 */
342BOOL WIN32API SplQueryPMQueueFromHandle(HANDLE hPrinter, char *pszQueue, unsigned cchQueue)
343{
344 BOOL fRc = FALSE;
345 DRIVER_INFO_1A *pInfo;
346 DWORD cbNeeded = 0;
347
348#ifdef USE_OS2_DRIVERNAME
349 /*
350 * Validate the handle.
351 */
352 POPENPRINTER pPrt = openprinterFind(hPrinter);
353 if (pPrt)
354 {
355 /*
356 * Open the printer key in the registry.
357 */
358 HKEY hkeyPrinters;
359 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS)
360 {
361 HKEY hkeyPrinter;
362 if (RegOpenKeyW(hkeyPrinters, pPrt->pwszPrinterName, &hkeyPrinter) == ERROR_SUCCESS)
363 {
364 /*
365 * Get the queue name.
366 */
367 DWORD cb = cchQueue;
368 DWORD dwType = 0;
369 if (RegQueryValueExA(hkeyPrinter, "Description", NULL, &dwType, (LPBYTE)pszQueue, &cb) == ERROR_SUCCESS)
370 {
371 pszQueue[cb] = '\0'; /* paranoia!!!! */
372 dprintf(("WINSPOOL: SplQueryPMQueueFromHandle: queuename=%s\n", pszQueue));
373 fRc = TRUE;
374 }
375 else
376 {
377 DebugAssertFailed(("Could not query value 'Comment'\n"));
378 SetLastError(ERROR_GEN_FAILURE);
379 }
380 RegCloseKey(hkeyPrinter);
381 }
382 else
383 {
384 DebugAssertFailed(("Could not open printer '%ls' in the registry!!!\n",
385 pPrt->pwszPrinterName));
386 SetLastError(ERROR_INVALID_PRINTER_NAME);
387 }
388 RegCloseKey(hkeyPrinters);
389 }
390 else
391 SetLastError(ERROR_GEN_FAILURE);
392 }
393 else
394 DebugAssertFailed(("Invalid handle %#x\n", hPrinter));
395#else
396 /* the old method of storing it in the printer driver name. */
397 GetPrinterDriverA(hPrinter, NULL, 1, NULL, 0, &cbNeeded);
398 pInfo = (DRIVER_INFO_1A *)malloc(cbNeeded);
399 if (pInfo)
400 {
401 fRc = GetPrinterDriverA(hPrinter, NULL, 1, (LPBYTE)pInfo, cbNeeded, &cbNeeded)
402 && cbNeeded - sizeof(DRIVER_INFO_1A) < cchQueue;
403 DebugAssert(fRc, ("GetPrinterDriverA failed or buffer to small.\n"));
404 if (fRc)
405 strcpy(pszQueue, pInfo->pName);
406 free(pInfo);
407 }
408#endif
409
410 if (!fRc)
411 dprintf(("WINSPOOL: SplQueryPMQueueFromHandle failed!\n"));
412 return fRc;
413}
414
415/**
416 * Get the PM printer queue name associated with the printer name
417 *
418 * @returns Success indicator.
419 * @param pszPrinterName Printer device name.
420 * @param pszQueue Where to put the queue name.
421 * @param cchQueue Size of the queue buffer pointed to by pszQueue.
422 */
423BOOL WIN32API SplQueryPMQueueName(LPSTR pszPrinterName, LPSTR pszQueue, INT cchQueue)
424{
425 BOOL fRc = FALSE;
426 HANDLE hPrinter;
427
428 // Get the PM Queue name corresponding to the printer device
429 if (OpenPrinterA(pszPrinterName, &hPrinter, NULL))
430 {
431 fRc = SplQueryPMQueueFromHandle(hPrinter, pszQueue, cchQueue);
432 ClosePrinter(hPrinter);
433 }
434
435 return fRc;
436}
437
438/*************************************************************************
439 * SHDeleteKeyA [SHLWAPI.@]
440 *
441 * Delete a registry key and any sub keys/values present
442 *
443 * PARAMS
444 * hKey [I] Handle to registry key
445 * lpszSubKey [I] Name of sub key to delete
446 *
447 * RETURNS
448 * Success: ERROR_SUCCESS. The key is deleted.
449 * Failure: An error code from RegOpenKeyExA, RegQueryInfoKeyA,
450 * RegEnumKeyExA or RegDeleteKeyA.
451 *
452 *
453 * (Rewind code)
454 *
455 * NOTE: I don't want a dependency on shlwapi in winspool
456 *
457 */
458static DWORD SHDeleteKeyW(HKEY hKey, LPCWSTR lpszSubKey)
459{
460 DWORD dwRet, dwKeyCount = 0, dwMaxSubkeyLen = 0, dwSize, i;
461 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
462 HKEY hSubKey = 0;
463
464 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
465 if(!dwRet)
466 {
467 /* Find how many subkeys there are */
468 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, &dwKeyCount,
469 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
470 if(!dwRet)
471 {
472 dwMaxSubkeyLen++;
473 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
474 /* Name too big: alloc a buffer for it */
475 lpszName = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
476
477 if(!lpszName)
478 dwRet = ERROR_NOT_ENOUGH_MEMORY;
479 else
480 {
481 /* Recursively delete all the subkeys */
482 for(i = 0; i < dwKeyCount && !dwRet; i++)
483 {
484 dwSize = dwMaxSubkeyLen;
485 dwRet = RegEnumKeyExW(hSubKey, i, lpszName, &dwSize, NULL, NULL, NULL, NULL);
486 if(!dwRet)
487 dwRet = SHDeleteKeyW(hSubKey, lpszName);
488 }
489
490 if (lpszName != szNameBuf)
491 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
492 }
493 }
494
495 RegCloseKey(hSubKey);
496 if(!dwRet)
497 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
498 }
499 return dwRet;
500}
501
502#endif /* __WIN32OS2__ */
503
504
505static inline DWORD set_reg_szW(HKEY hkey, WCHAR *keyname, WCHAR *value)
506{
507#if 0 /* bird: On OS/2 the API expects number of chars of unicode strings.
508 * On Win32 you are required to include the '\0' in the count. */
509 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (LPBYTE)value,
510 lstrlenW(value) * sizeof(WCHAR));
511#else
512 return RegSetValueExW(hkey, keyname, 0, REG_SZ, (LPBYTE)value, lstrlenW(value) + 1);
513#endif
514}
515
516/***********************************************************
517 * DEVMODEcpyAtoW
518 */
519static LPDEVMODEW DEVMODEcpyAtoW(DEVMODEW *dmW, const DEVMODEA *dmA)
520{
521 BOOL Formname;
522 ptrdiff_t off_formname = (char *)dmA->dmFormName - (char *)dmA;
523 DWORD size;
524
525 Formname = (dmA->dmSize > off_formname);
526 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
527 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmDeviceName, -1, dmW->dmDeviceName,
528 CCHDEVICENAME);
529 if(!Formname) {
530 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
531 dmA->dmSize - CCHDEVICENAME);
532 } else {
533 memcpy(&dmW->dmSpecVersion, &dmA->dmSpecVersion,
534 off_formname - CCHDEVICENAME);
535 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)dmA->dmFormName, -1, dmW->dmFormName,
536 CCHFORMNAME);
537 memcpy(&dmW->dmLogPixels, &dmA->dmLogPixels, dmA->dmSize -
538 (off_formname + CCHFORMNAME));
539 }
540 dmW->dmSize = size;
541 memcpy((char *)dmW + dmW->dmSize, (char *)dmA + dmA->dmSize,
542 dmA->dmDriverExtra);
543 return dmW;
544}
545
546/***********************************************************
547 * DEVMODEdupAtoW
548 * Creates a unicode copy of supplied devmode on heap
549 */
550static LPDEVMODEW DEVMODEdupAtoW(HANDLE heap, const DEVMODEA *dmA)
551{
552 LPDEVMODEW dmW;
553 DWORD size;
554 BOOL Formname;
555 ptrdiff_t off_formname;
556
557 if(!dmA) return NULL;
558
559 off_formname = (char *)dmA->dmFormName - (char *)dmA;
560 Formname = (dmA->dmSize > off_formname);
561 size = dmA->dmSize + CCHDEVICENAME + (Formname ? CCHFORMNAME : 0);
562 dmW = (LPDEVMODEW) HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmA->dmDriverExtra);
563 return DEVMODEcpyAtoW(dmW, dmA);
564}
565
566/***********************************************************
567 * DEVMODEdupWtoA
568 * Creates an ascii copy of supplied devmode on heap
569 */
570static LPDEVMODEA DEVMODEdupWtoA(HANDLE heap, const DEVMODEW *dmW)
571{
572 LPDEVMODEA dmA;
573 DWORD size;
574 BOOL Formname;
575 ptrdiff_t off_formname = (char *)dmW->dmFormName - (char *)dmW;
576
577 if(!dmW) return NULL;
578 Formname = (dmW->dmSize > off_formname);
579 size = dmW->dmSize - CCHDEVICENAME - (Formname ? CCHFORMNAME : 0);
580 dmA = (LPDEVMODEA)HeapAlloc(heap, HEAP_ZERO_MEMORY, size + dmW->dmDriverExtra);
581 WideCharToMultiByte(CP_ACP, 0, dmW->dmDeviceName, -1, (LPSTR)dmA->dmDeviceName,
582 CCHDEVICENAME, NULL, NULL);
583 if(!Formname) {
584 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
585 dmW->dmSize - CCHDEVICENAME * sizeof(WCHAR));
586 } else {
587 memcpy(&dmA->dmSpecVersion, &dmW->dmSpecVersion,
588 off_formname - CCHDEVICENAME * sizeof(WCHAR));
589 WideCharToMultiByte(CP_ACP, 0, dmW->dmFormName, -1, (LPSTR)dmA->dmFormName,
590 CCHFORMNAME, NULL, NULL);
591 memcpy(&dmA->dmLogPixels, &dmW->dmLogPixels, dmW->dmSize -
592 (off_formname + CCHFORMNAME * sizeof(WCHAR)));
593 }
594 dmA->dmSize = size;
595 memcpy((char *)dmA + dmA->dmSize, (char *)dmW + dmW->dmSize,
596 dmW->dmDriverExtra);
597 return dmA;
598}
599
600/******************************************************************
601 * WINSPOOL_GetOpenedPrinter
602 * Get the pointer to the opened printer referred by the handle
603 */
604static LPCWSTR WINSPOOL_GetOpenedPrinter(HANDLE printerHandle)
605{
606#ifdef __WIN32OS2__
607 POPENPRINTER p = openprinterFind(printerHandle);
608 if (p)
609 return p->pwszPrinterName;
610 SetLastError(ERROR_INVALID_HANDLE);
611 return NULL;
612#else
613 int idx = (int)printerHandle;
614 if ((idx <= 0) || (idx > nb_printers))
615 {
616 SetLastError(ERROR_INVALID_HANDLE);
617 return NULL;
618 }
619 return printer_array[idx - 1];
620#endif
621}
622
623
624/*****************************************************************************
625 * WINSPOOL_OpenDriverReg [internal]
626 *
627 * opens the registry for the printer drivers depending on the given input
628 * variable pEnvironment
629 *
630 * RETURNS:
631 * the opened hkey on success
632 * NULL on error
633 */
634static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode)
635{ HKEY retval;
636 LPSTR lpKey, p = NULL;
637
638#ifdef DEBUG /* __WIN32OS2__ */
639 dprintf(("%s\n",
640 (unicode) ? debugstr_w((LPCWSTR)pEnvironment) : debugstr_a((LPCSTR)pEnvironment)));
641#endif /* __WIN32OS2__ */
642
643 if(pEnvironment)
644 p = (unicode) ? (LPSTR)HEAP_strdupWtoA( GetProcessHeap(), 0, (LPCWSTR)pEnvironment) :
645 (LPSTR) pEnvironment;
646 else {
647 OSVERSIONINFOA ver;
648 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
649
650 if(!GetVersionExA( &ver))
651 return 0;
652
653 switch (ver.dwPlatformId) {
654 case VER_PLATFORM_WIN32s:
655 ERR("win32 style printing used with 16 bits app, try specifying 'win95' Windows version\n");
656 return 0;
657
658 case VER_PLATFORM_WIN32_NT:
659 p = "Windows NT x86";
660 break;
661 default:
662 p = "Windows 4.0";
663 break;
664 }
665 TRACE("set environment to %s\n", p);
666 }
667
668 lpKey = (char*) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
669 strlen(p) + strlen(Drivers));
670 sprintf( lpKey, Drivers, p);
671
672 TRACE("%s\n", lpKey);
673
674 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, lpKey, &retval) !=
675 ERROR_SUCCESS)
676 retval = 0;
677
678 if(pEnvironment && unicode)
679 HeapFree( GetProcessHeap(), 0, p);
680 HeapFree( GetProcessHeap(), 0, lpKey);
681
682 return retval;
683}
684
685
686/*****************************************************************************
687 * WINSPOOL_GetStringFromReg
688 *
689 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
690 * String is stored either as unicode or ascii.
691 * Bit of a hack here to get the ValueName if we want ascii.
692 */
693static BOOL WINSPOOL_GetStringFromReg(HKEY hkey, LPCWSTR ValueName, LPBYTE ptr,
694 DWORD buflen, DWORD *needed,
695 BOOL unicode)
696{
697 DWORD sz = buflen, type;
698 LONG ret;
699
700 if(unicode)
701 ret = RegQueryValueExW(hkey, (LPWSTR)ValueName, 0, &type, ptr, &sz);
702 else {
703 LPSTR ValueNameA = HEAP_strdupWtoA(GetProcessHeap(),0,ValueName);
704 ret = RegQueryValueExA(hkey, ValueNameA, 0, &type, ptr, &sz);
705 HeapFree(GetProcessHeap(),0,ValueNameA);
706 }
707 if(ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA) {
708 WARN("Got ret = %ld\n", ret);
709 *needed = 0;
710 return FALSE;
711 }
712 *needed = sz;
713 return TRUE;
714}
715
716
717/*****************************************************************************
718 * WINSPOOL_SetDevModeFromReg
719 *
720 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
721 * DevMode is stored either as unicode or ascii.
722 */
723static BOOL WINSPOOL_SetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
724 LPBYTE ptr, DWORD buflen)
725{
726 DWORD sz = buflen, type;
727 LONG ret;
728
729 ret = RegSetValueExW(hkey, (LPWSTR)ValueName, 0, REG_BINARY, ptr, sz);
730 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
731 if (sz < sizeof(DEVMODEA))
732 {
733 ERR("failed to write DEVMODEA for %s ( size %ld)\n",debugstr_w(ValueName),sz);
734 return FALSE;
735 }
736 return TRUE;
737}
738
739/*****************************************************************************
740 * WINSPOOL_GetDevModeFromReg
741 *
742 * Get ValueName from hkey storing result in ptr. buflen is space left in ptr
743 * DevMode is stored either as unicode or ascii.
744 */
745static BOOL WINSPOOL_GetDevModeFromReg(HKEY hkey, LPCWSTR ValueName,
746 LPBYTE ptr,
747 DWORD buflen, DWORD *needed,
748 BOOL unicode)
749{
750 DWORD sz = buflen, type;
751 LONG ret;
752
753 if (ptr && buflen>=sizeof(DEVMODEA)) memset(ptr, 0, sizeof(DEVMODEA));
754 ret = RegQueryValueExW(hkey, (LPWSTR)ValueName, 0, &type, ptr, &sz);
755 if ((ret != ERROR_SUCCESS && ret != ERROR_MORE_DATA)) sz = 0;
756 if (sz < sizeof(DEVMODEA))
757 {
758 ERR("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
759 return FALSE;
760 }
761 /* ensures that dmSize is not erratically bogus if registry is invalid */
762 if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
763 ((DEVMODEA*)ptr)->dmSize = sizeof(DEVMODEA);
764 if(unicode) {
765 sz += (CCHDEVICENAME + CCHFORMNAME);
766 if(buflen >= sz) {
767 DEVMODEW *dmW = DEVMODEdupAtoW(GetProcessHeap(), (DEVMODEA*)ptr);
768 memcpy(ptr, dmW, sz);
769 HeapFree(GetProcessHeap(),0,dmW);
770 }
771 }
772 *needed = sz;
773 return TRUE;
774}
775
776/*****************************************************************************
777 * WINSPOOL_GetDWORDFromReg
778 *
779 * Return DWORD associated with ValueName from hkey.
780 */
781static DWORD WINSPOOL_GetDWORDFromReg(HKEY hkey, LPCSTR ValueName)
782{
783 DWORD sz = sizeof(DWORD), type, value = 0;
784 LONG ret;
785
786 ret = RegQueryValueExA(hkey, (LPSTR)ValueName, 0, &type, (LPBYTE)&value, &sz);
787
788 if(ret != ERROR_SUCCESS) {
789 WARN("Got ret = %ld on name %s\n", ret, ValueName);
790 return 0;
791 }
792 if(type != REG_DWORD) {
793 ERR("Got type %ld\n", type);
794 return 0;
795 }
796 return value;
797}
798
799/*****************************************************************************
800 * WINSPOOL_GetDefaultDevMode
801 *
802 * Get a default DevMode values for wineps.
803 * FIXME - use ppd.
804 */
805
806static void WINSPOOL_GetDefaultDevMode(
807 LPBYTE ptr,
808 DWORD buflen, DWORD *needed,
809 BOOL unicode)
810{
811 DEVMODEA dm;
812
813 /* fill default DEVMODE - should be read from ppd... */
814 ZeroMemory( &dm, sizeof(dm) );
815 strcpy((char*)dm.dmDeviceName,"wineps");
816 dm.dmSpecVersion = DM_SPECVERSION;
817 dm.dmDriverVersion = 1;
818 dm.dmSize = sizeof(DEVMODEA);
819 dm.dmDriverExtra = 0;
820 dm.dmFields =
821 DM_ORIENTATION | DM_PAPERSIZE |
822 DM_PAPERLENGTH | DM_PAPERWIDTH |
823 DM_SCALE | DM_COLLATE |
824 DM_COPIES |
825 DM_DEFAULTSOURCE | DM_PRINTQUALITY |
826 DM_YRESOLUTION | DM_TTOPTION;
827
828#if (__IBMCPP__ == 360)
829 dm.dmOrientation = DMORIENT_PORTRAIT;
830 dm.dmPaperSize = DMPAPER_A4;
831 dm.dmPaperLength = 2970;
832 dm.dmPaperWidth = 2100;
833#else
834 dm.s1.dmOrientation = DMORIENT_PORTRAIT;
835 dm.s1.dmPaperSize = DMPAPER_A4;
836 dm.s1.dmPaperLength = 2970;
837 dm.s1.dmPaperWidth = 2100;
838#endif
839
840 dm.dmScale = 100;
841 dm.dmCopies = 1;
842 dm.dmDefaultSource = DMBIN_AUTO;
843 dm.dmPrintQuality = DMRES_MEDIUM;
844 /* dm.dmColor */
845 /* dm.dmDuplex */
846 dm.dmYResolution = 300; /* 300dpi */
847 dm.dmTTOption = DMTT_BITMAP;
848 dm.dmCollate = 1;
849 /* dm.dmFormName */
850 /* dm.dmLogPixels */
851 /* dm.dmBitsPerPel */
852 /* dm.dmPelsWidth */
853 /* dm.dmPelsHeight */
854 /* dm.dmDisplayFlags */
855 /* dm.dmDisplayFrequency */
856 /* dm.dmICMMethod */
857 /* dm.dmICMIntent */
858 /* dm.dmMediaType */
859 /* dm.dmDitherType */
860 /* dm.dmReserved1 */
861 /* dm.dmReserved2 */
862 /* dm.dmPanningWidth */
863 /* dm.dmPanningHeight */
864
865 if(unicode) {
866 if(buflen >= sizeof(DEVMODEW)) {
867 DEVMODEW *pdmW = DEVMODEdupAtoW(GetProcessHeap(), &dm );
868 memcpy(ptr, pdmW, sizeof(DEVMODEW));
869 HeapFree(GetProcessHeap(),0,pdmW);
870 }
871 *needed = sizeof(DEVMODEW);
872 }
873 else
874 {
875 if(buflen >= sizeof(DEVMODEA)) {
876 memcpy(ptr, &dm, sizeof(DEVMODEA));
877 }
878 *needed = sizeof(DEVMODEA);
879 }
880}
881
882
883/*********************************************************************
884 * WINSPOOL_GetPrinter_2
885 *
886 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
887 * The strings are either stored as unicode or ascii.
888 */
889static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
890 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
891 BOOL unicode)
892{
893 DWORD size, left = cbBuf;
894 BOOL space = (cbBuf > 0);
895 LPBYTE ptr = buf;
896
897 *pcbNeeded = 0;
898
899 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
900 unicode)) {
901 if(space && size <= left) {
902 pi2->pPrinterName = (LPWSTR)ptr;
903 ptr += size;
904 left -= size;
905 } else
906 space = FALSE;
907 *pcbNeeded += size;
908 }
909 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
910 unicode)) {
911 if(space && size <= left) {
912 pi2->pShareName = (LPWSTR)ptr;
913 ptr += size;
914 left -= size;
915 } else
916 space = FALSE;
917 *pcbNeeded += size;
918 }
919 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
920 unicode)) {
921 if(space && size <= left) {
922 pi2->pPortName = (LPWSTR)ptr;
923 ptr += size;
924 left -= size;
925 } else
926 space = FALSE;
927 *pcbNeeded += size;
928 }
929 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
930 &size, unicode)) {
931 if(space && size <= left) {
932 pi2->pDriverName = (LPWSTR)ptr;
933 ptr += size;
934 left -= size;
935 } else
936 space = FALSE;
937 *pcbNeeded += size;
938 }
939 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
940 unicode)) {
941 if(space && size <= left) {
942 pi2->pComment = (LPWSTR)ptr;
943 ptr += size;
944 left -= size;
945 } else
946 space = FALSE;
947 *pcbNeeded += size;
948 }
949 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
950 unicode)) {
951 if(space && size <= left) {
952 pi2->pLocation = (LPWSTR)ptr;
953 ptr += size;
954 left -= size;
955 } else
956 space = FALSE;
957 *pcbNeeded += size;
958 }
959 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
960 &size, unicode)) {
961 if(space && size <= left) {
962 pi2->pDevMode = (LPDEVMODEW)ptr;
963 ptr += size;
964 left -= size;
965 } else
966 space = FALSE;
967 *pcbNeeded += size;
968 }
969 else
970 {
971 MESSAGE( "no DevMode in registry. please setup your printer again.\n"
972 "use the default hard-coded DevMode(wineps/A4/300dpi).\n" );
973 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
974 if(space && size <= left) {
975 pi2->pDevMode = (LPDEVMODEW)ptr;
976 ptr += size;
977 left -= size;
978 } else
979 space = FALSE;
980 *pcbNeeded += size;
981 }
982 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
983 &size, unicode)) {
984 if(space && size <= left) {
985 pi2->pSepFile = (LPWSTR)ptr;
986 ptr += size;
987 left -= size;
988 } else
989 space = FALSE;
990 *pcbNeeded += size;
991 }
992 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
993 &size, unicode)) {
994 if(space && size <= left) {
995 pi2->pPrintProcessor = (LPWSTR)ptr;
996 ptr += size;
997 left -= size;
998 } else
999 space = FALSE;
1000 *pcbNeeded += size;
1001 }
1002 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
1003 &size, unicode)) {
1004 if(space && size <= left) {
1005 pi2->pDatatype = (LPWSTR)ptr;
1006 ptr += size;
1007 left -= size;
1008 } else
1009 space = FALSE;
1010 *pcbNeeded += size;
1011 }
1012 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1013 &size, unicode)) {
1014 if(space && size <= left) {
1015 pi2->pParameters = (LPWSTR)ptr;
1016 ptr += size;
1017 left -= size;
1018 } else
1019 space = FALSE;
1020 *pcbNeeded += size;
1021 }
1022 if(pi2) {
1023 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1024 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1025 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1026 "Default Priority");
1027 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1028 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1029 }
1030
1031 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1032 memset(pi2, 0, sizeof(*pi2));
1033
1034 return space;
1035}
1036
1037/*********************************************************************
1038 * WINSPOOL_GetPrinter_4
1039 *
1040 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1041 */
1042static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1043 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1044 BOOL unicode)
1045{
1046 DWORD size, left = cbBuf;
1047 BOOL space = (cbBuf > 0);
1048 LPBYTE ptr = buf;
1049
1050 *pcbNeeded = 0;
1051
1052 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1053 unicode)) {
1054 if(space && size <= left) {
1055 pi4->pPrinterName = (LPWSTR)ptr;
1056 ptr += size;
1057 left -= size;
1058 } else
1059 space = FALSE;
1060 *pcbNeeded += size;
1061 }
1062 if(pi4) {
1063 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1064 }
1065
1066 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1067 memset(pi4, 0, sizeof(*pi4));
1068
1069 return space;
1070}
1071
1072/*********************************************************************
1073 * WINSPOOL_GetPrinter_5
1074 *
1075 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1076 */
1077static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1078 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1079 BOOL unicode)
1080{
1081 DWORD size, left = cbBuf;
1082 BOOL space = (cbBuf > 0);
1083 LPBYTE ptr = buf;
1084
1085 *pcbNeeded = 0;
1086
1087 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1088 unicode)) {
1089 if(space && size <= left) {
1090 pi5->pPrinterName = (LPWSTR)ptr;
1091 ptr += size;
1092 left -= size;
1093 } else
1094 space = FALSE;
1095 *pcbNeeded += size;
1096 }
1097 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1098 unicode)) {
1099 if(space && size <= left) {
1100 pi5->pPortName = (LPWSTR)ptr;
1101 ptr += size;
1102 left -= size;
1103 } else
1104 space = FALSE;
1105 *pcbNeeded += size;
1106 }
1107 if(pi5) {
1108 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1109 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1110 "dnsTimeout");
1111 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1112 "txTimeout");
1113 }
1114
1115 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1116 memset(pi5, 0, sizeof(*pi5));
1117
1118 return space;
1119}
1120
1121
1122/*****************************************************************************
1123 * WINSPOOL_GetPrinter
1124 *
1125 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
1126 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1127 * just a collection of pointers to strings.
1128 */
1129static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1130 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1131{
1132 LPCWSTR name;
1133 DWORD size, needed = 0;
1134 LPBYTE ptr = NULL;
1135 HKEY hkeyPrinter, hkeyPrinters;
1136 BOOL ret;
1137
1138 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1139
1140 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
1141
1142 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1143 ERROR_SUCCESS) {
1144 ERR("Can't create Printers key\n");
1145 return FALSE;
1146 }
1147 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
1148 {
1149 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
1150 RegCloseKey(hkeyPrinters);
1151 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1152 return FALSE;
1153 }
1154
1155 switch(Level) {
1156 case 2:
1157 {
1158 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
1159
1160 size = sizeof(PRINTER_INFO_2W);
1161 if(size <= cbBuf) {
1162 ptr = pPrinter + size;
1163 cbBuf -= size;
1164 memset(pPrinter, 0, size);
1165 } else {
1166 pi2 = NULL;
1167 cbBuf = 0;
1168 }
1169 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
1170 unicode);
1171 needed += size;
1172 break;
1173 }
1174
1175 case 4:
1176 {
1177 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
1178
1179 size = sizeof(PRINTER_INFO_4W);
1180 if(size <= cbBuf) {
1181 ptr = pPrinter + size;
1182 cbBuf -= size;
1183 memset(pPrinter, 0, size);
1184 } else {
1185 pi4 = NULL;
1186 cbBuf = 0;
1187 }
1188 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
1189 unicode);
1190 needed += size;
1191 break;
1192 }
1193
1194
1195 case 5:
1196 {
1197 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
1198
1199 size = sizeof(PRINTER_INFO_5W);
1200 if(size <= cbBuf) {
1201 ptr = pPrinter + size;
1202 cbBuf -= size;
1203 memset(pPrinter, 0, size);
1204 } else {
1205 pi5 = NULL;
1206 cbBuf = 0;
1207 }
1208
1209 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
1210 unicode);
1211 needed += size;
1212 break;
1213 }
1214
1215 default:
1216 FIXME("Unimplemented level %ld\n", Level);
1217 SetLastError(ERROR_INVALID_LEVEL);
1218 RegCloseKey(hkeyPrinters);
1219 RegCloseKey(hkeyPrinter);
1220 return FALSE;
1221 }
1222
1223 RegCloseKey(hkeyPrinter);
1224 RegCloseKey(hkeyPrinters);
1225
1226 TRACE("returing %d needed = %ld\n", ret, needed);
1227 if(pcbNeeded) *pcbNeeded = needed;
1228 if(!ret)
1229 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1230 return ret;
1231}
1232
1233
1234/*****************************************************************************
1235 * WINSPOOL_GetDriverInfoFromReg [internal]
1236 *
1237 * Enters the information from the registry into the DRIVER_INFO struct
1238 *
1239 * RETURNS
1240 * zero if the printer driver does not exist in the registry
1241 * (only if Level > 1) otherwise nonzero
1242 */
1243static BOOL WINSPOOL_GetDriverInfoFromReg(
1244 HKEY hkeyDrivers,
1245 LPWSTR DriverName,
1246 LPWSTR pEnvironment,
1247 DWORD Level,
1248 LPBYTE ptr, /* DRIVER_INFO */
1249 LPBYTE pDriverStrings, /* strings buffer */
1250 DWORD cbBuf, /* size of string buffer */
1251 LPDWORD pcbNeeded, /* space needed for str. */
1252 BOOL unicode) /* type of strings */
1253{ DWORD dw, size, tmp, type;
1254 HKEY hkeyDriver;
1255 LPBYTE strPtr = pDriverStrings;
1256
1257 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
1258 debugstr_w(DriverName), debugstr_w(pEnvironment),
1259 Level, ptr, pDriverStrings, cbBuf, unicode);
1260
1261 if(unicode) {
1262 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
1263 if (*pcbNeeded <= cbBuf)
1264 strcpyW((LPWSTR)strPtr, DriverName);
1265 } else {
1266 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
1267 NULL, NULL);
1268 if(*pcbNeeded <= cbBuf)
1269 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded,
1270 NULL, NULL);
1271 }
1272 if(Level == 1) {
1273 if(ptr)
1274 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
1275 return TRUE;
1276 } else {
1277 if(ptr)
1278 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
1279 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
1280 }
1281
1282 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
1283 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
1284 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
1285 return FALSE;
1286 }
1287
1288 size = sizeof(dw);
1289 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
1290 ERROR_SUCCESS)
1291 WARN("Can't get Version\n");
1292 else if(ptr)
1293 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
1294
1295 if(!pEnvironment)
1296 pEnvironment = DefaultEnvironmentW;
1297 if(unicode)
1298 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
1299 else
1300 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
1301 NULL, NULL);
1302 *pcbNeeded += size;
1303 if(*pcbNeeded <= cbBuf) {
1304 if(unicode)
1305 strcpyW((LPWSTR)strPtr, pEnvironment);
1306 else
1307 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, (LPSTR)strPtr, size,
1308 NULL, NULL);
1309 if(ptr)
1310 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
1311 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
1312 }
1313
1314 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
1315 unicode)) {
1316 *pcbNeeded += size;
1317 if(*pcbNeeded <= cbBuf)
1318 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
1319 unicode);
1320 if(ptr)
1321 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
1322 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
1323 }
1324
1325 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
1326 unicode)) {
1327 *pcbNeeded += size;
1328 if(*pcbNeeded <= cbBuf)
1329 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
1330 &tmp, unicode);
1331 if(ptr)
1332 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
1333 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1334 }
1335
1336 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
1337 0, &size, unicode)) {
1338 *pcbNeeded += size;
1339 if(*pcbNeeded <= cbBuf)
1340 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
1341 size, &tmp, unicode);
1342 if(ptr)
1343 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
1344 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1345 }
1346
1347 if(Level == 2 ) {
1348 RegCloseKey(hkeyDriver);
1349 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
1350 return TRUE;
1351 }
1352
1353 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
1354 unicode)) {
1355 *pcbNeeded += size;
1356 if(*pcbNeeded <= cbBuf)
1357 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
1358 size, &tmp, unicode);
1359 if(ptr)
1360 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
1361 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1362 }
1363
1364 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
1365 &size, unicode)) {
1366 *pcbNeeded += size;
1367 if(*pcbNeeded <= cbBuf)
1368 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
1369 size, &tmp, unicode);
1370 if(ptr)
1371 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
1372 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1373 }
1374
1375 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
1376 unicode)) {
1377 *pcbNeeded += size;
1378 if(*pcbNeeded <= cbBuf)
1379 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
1380 size, &tmp, unicode);
1381 if(ptr)
1382 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
1383 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1384 }
1385
1386 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
1387 unicode)) {
1388 *pcbNeeded += size;
1389 if(*pcbNeeded <= cbBuf)
1390 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
1391 size, &tmp, unicode);
1392 if(ptr)
1393 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
1394 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1395 }
1396
1397 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
1398 RegCloseKey(hkeyDriver);
1399 return TRUE;
1400}
1401
1402/*****************************************************************************
1403 * WINSPOOL_GetPrinterDriver
1404 */
1405static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
1406 DWORD Level, LPBYTE pDriverInfo,
1407 DWORD cbBuf, LPDWORD pcbNeeded,
1408 BOOL unicode)
1409{
1410 LPCWSTR name;
1411 WCHAR DriverName[100];
1412 DWORD ret, type, size, needed = 0;
1413 LPBYTE ptr = NULL;
1414 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
1415
1416 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
1417 Level,pDriverInfo,cbBuf, pcbNeeded);
1418
1419 ZeroMemory(pDriverInfo, cbBuf);
1420
1421 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
1422
1423 if(Level < 1 || Level > 3) {
1424 SetLastError(ERROR_INVALID_LEVEL);
1425 return FALSE;
1426 }
1427 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1428 ERROR_SUCCESS) {
1429 ERR("Can't create Printers key\n");
1430 return FALSE;
1431 }
1432 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
1433 != ERROR_SUCCESS) {
1434 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
1435 RegCloseKey(hkeyPrinters);
1436 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1437 return FALSE;
1438 }
1439 size = sizeof(DriverName);
1440 DriverName[0] = 0;
1441 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
1442 (LPBYTE)DriverName, &size);
1443 RegCloseKey(hkeyPrinter);
1444 RegCloseKey(hkeyPrinters);
1445 if(ret != ERROR_SUCCESS) {
1446 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
1447 return FALSE;
1448 }
1449
1450 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
1451 if(!hkeyDrivers) {
1452 ERR("Can't create Drivers key\n");
1453 return FALSE;
1454 }
1455
1456 switch(Level) {
1457 case 1:
1458 size = sizeof(DRIVER_INFO_1W);
1459 break;
1460 case 2:
1461 size = sizeof(DRIVER_INFO_2W);
1462 break;
1463 case 3:
1464 size = sizeof(DRIVER_INFO_3W);
1465 break;
1466 default:
1467 ERR("Invalid level\n");
1468 return FALSE;
1469 }
1470
1471 if(size <= cbBuf)
1472 ptr = pDriverInfo + size;
1473
1474 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
1475 pEnvironment, Level, pDriverInfo,
1476 (cbBuf < size) ? NULL : ptr,
1477 (cbBuf < size) ? 0 : cbBuf - size,
1478 &needed, unicode)) {
1479 RegCloseKey(hkeyDrivers);
1480 return FALSE;
1481 }
1482
1483 RegCloseKey(hkeyDrivers);
1484
1485 if(pcbNeeded) *pcbNeeded = size + needed;
1486 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
1487 if(cbBuf >= needed) return TRUE;
1488 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1489 return FALSE;
1490}
1491
1492/*****************************************************************************
1493 * WINSPOOL_EnumPrinters
1494 *
1495 * Implementation of EnumPrintersA|W
1496 */
1497static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
1498 DWORD dwLevel, LPBYTE lpbPrinters,
1499 DWORD cbBuf, LPDWORD lpdwNeeded,
1500 LPDWORD lpdwReturned, BOOL unicode)
1501
1502{
1503 HKEY hkeyPrinters, hkeyPrinter;
1504 WCHAR PrinterName[255];
1505 DWORD needed = 0, number = 0;
1506 DWORD used, i, left;
1507 PBYTE pi, buf;
1508
1509 if(lpbPrinters)
1510 memset(lpbPrinters, 0, cbBuf);
1511 if(lpdwReturned)
1512 *lpdwReturned = 0;
1513 if(lpdwNeeded)
1514 *lpdwNeeded = 0;
1515
1516 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
1517 if(dwType == PRINTER_ENUM_DEFAULT)
1518 return TRUE;
1519
1520 if (dwType & PRINTER_ENUM_CONNECTIONS) {
1521 FIXME("We dont handle PRINTER_ENUM_CONNECTIONS\n");
1522 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we dont handle that */
1523 if(!dwType) return TRUE;
1524 }
1525
1526 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
1527 FIXME("dwType = %08lx\n", dwType);
1528 SetLastError(ERROR_INVALID_FLAGS);
1529 return FALSE;
1530 }
1531
1532 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1533 ERROR_SUCCESS) {
1534 ERR("Can't create Printers key\n");
1535 return FALSE;
1536 }
1537
1538 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
1539 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
1540 RegCloseKey(hkeyPrinters);
1541 ERR("Can't query Printers key\n");
1542 return FALSE;
1543 }
1544 TRACE("Found %ld printers\n", number);
1545
1546 switch(dwLevel) {
1547 case 1:
1548 RegCloseKey(hkeyPrinters);
1549 if (lpdwReturned)
1550 *lpdwReturned = number;
1551 return TRUE;
1552
1553 case 2:
1554 used = number * sizeof(PRINTER_INFO_2W);
1555 break;
1556 case 4:
1557 used = number * sizeof(PRINTER_INFO_4W);
1558 break;
1559 case 5:
1560 used = number * sizeof(PRINTER_INFO_5W);
1561 break;
1562
1563 default:
1564 SetLastError(ERROR_INVALID_LEVEL);
1565 RegCloseKey(hkeyPrinters);
1566 return FALSE;
1567 }
1568 pi = (used <= cbBuf) ? lpbPrinters : NULL;
1569
1570 for(i = 0; i < number; i++) {
1571 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
1572 ERROR_SUCCESS) {
1573 ERR("Can't enum key number %ld\n", i);
1574 RegCloseKey(hkeyPrinters);
1575 return FALSE;
1576 }
1577 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
1578 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
1579 ERROR_SUCCESS) {
1580 ERR("Can't open key %s\n", debugstr_w(PrinterName));
1581 RegCloseKey(hkeyPrinters);
1582 return FALSE;
1583 }
1584
1585 if(cbBuf > used) {
1586 buf = lpbPrinters + used;
1587 left = cbBuf - used;
1588 } else {
1589 buf = NULL;
1590 left = 0;
1591 }
1592
1593 switch(dwLevel) {
1594 case 2:
1595 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
1596 left, &needed, unicode);
1597 used += needed;
1598 if(pi) pi += sizeof(PRINTER_INFO_2W);
1599 break;
1600 case 4:
1601 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
1602 left, &needed, unicode);
1603 used += needed;
1604 if(pi) pi += sizeof(PRINTER_INFO_4W);
1605 break;
1606 case 5:
1607 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
1608 left, &needed, unicode);
1609 used += needed;
1610 if(pi) pi += sizeof(PRINTER_INFO_5W);
1611 break;
1612 default:
1613 ERR("Shouldn't be here!\n");
1614 RegCloseKey(hkeyPrinter);
1615 RegCloseKey(hkeyPrinters);
1616 return FALSE;
1617 }
1618 RegCloseKey(hkeyPrinter);
1619 }
1620 RegCloseKey(hkeyPrinters);
1621
1622 if(lpdwNeeded)
1623 *lpdwNeeded = used;
1624
1625 if(used > cbBuf) {
1626 if(lpbPrinters)
1627 memset(lpbPrinters, 0, cbBuf);
1628 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1629 return FALSE;
1630 }
1631 if(lpdwReturned)
1632 *lpdwReturned = number;
1633 SetLastError(ERROR_SUCCESS);
1634 return TRUE;
1635}
1636
1637
1638/******************************************************************
1639 * EnumPrintersA [WINSPOOL.@]
1640 *
1641 */
1642BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
1643 DWORD dwLevel, LPBYTE lpbPrinters,
1644 DWORD cbBuf, LPDWORD lpdwNeeded,
1645 LPDWORD lpdwReturned)
1646{
1647 BOOL ret;
1648 LPWSTR pwstrNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpszName);
1649
1650 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
1651 lpdwNeeded, lpdwReturned, FALSE);
1652 HeapFree(GetProcessHeap(),0,pwstrNameW);
1653 return ret;
1654}
1655
1656
1657/*****************************************************************************
1658 * Name : BOOL ClosePrinter
1659 * Purpose :
1660 * Parameters:
1661 * Variables :
1662 * Result :
1663 * Remark :
1664 * Status : UNTESTED STUB
1665 *
1666 * Author : Markus Montkowski [09.07.98 13:39:08]
1667 *****************************************************************************/
1668
1669BOOL WIN32API ClosePrinter(HANDLE hPrinter)
1670{
1671#ifdef __WIN32OS2__
1672 /*
1673 * Validate handle and get instance data.
1674 */
1675 POPENPRINTER p = openprinterFind(hPrinter);
1676 if (!p)
1677 {
1678 dprintf(("WINSPOOL: ClosePrinter Invalid handle %d\n", hPrinter));
1679 SetLastError(ERROR_INVALID_HANDLE);
1680 return FALSE;
1681 }
1682 dprintf(("WINSPOOL: ClosePrinter(%d) name=%ls\n", hPrinter, p->pwszPrinterName));
1683
1684 /*
1685 * Close any open OS/2 spool file.
1686 */
1687 if (p->hspl)
1688 {
1689 dprintf(("WINSPOOL: ClosePrinter closing OS/2 spool file %#x\n", p->hspl));
1690 if (!OSLibSplQmClose(p->hspl))
1691 DebugAssertFailed(("OSLibSplQmClose(%#x) failed!!!\n", p->hspl));
1692 p->hspl = 0;
1693 }
1694 openprinterDelete(p);
1695 return TRUE;
1696#else
1697 int i = (int)hPrinter;
1698
1699 TRACE("Handle %p\n", hPrinter);
1700
1701 if ((i <= 0) || (i > nb_printers)) return FALSE;
1702 HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
1703 printer_array[i - 1] = NULL;
1704 return TRUE;
1705#endif
1706}
1707
1708
1709/**
1710 * Opens a printer.
1711 *
1712 * @returns Success indicator, last error set on failure.
1713 * @param lpPrinterName Pointer to printer name.
1714 * @param phPrinter Where to store the handle to the opned printer instance.
1715 * @param pDefault Printer defaults. (Current ignored)
1716 * @status partially implemented.
1717 * @author Wine???
1718 */
1719BOOL WIN32API OpenPrinterA(LPSTR lpPrinterName, HANDLE * phPrinter,
1720 PRINTER_DEFAULTSA * pDefault)
1721{
1722 LPWSTR lpPrinterNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpPrinterName);
1723 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1724 BOOL ret;
1725
1726 if(pDefault) {
1727 DefaultW.pDatatype = HEAP_strdupAtoW(GetProcessHeap(), 0,
1728 pDefault->pDatatype);
1729 DefaultW.pDevMode = DEVMODEdupAtoW(GetProcessHeap(),
1730 pDefault->pDevMode);
1731 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1732 pDefaultW = &DefaultW;
1733 }
1734 ret = OpenPrinterW(lpPrinterNameW, phPrinter, pDefaultW);
1735 if(pDefault) {
1736 HeapFree(GetProcessHeap(), 0, DefaultW.pDatatype);
1737 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1738 }
1739 HeapFree(GetProcessHeap(), 0, lpPrinterNameW);
1740 return ret;
1741}
1742
1743
1744/*****************************************************************************
1745 * Name : LONG DocumentPropertiesA
1746 * Purpose :
1747 * Parameters:
1748 * Variables :
1749 * Result :
1750 * Remark :
1751 * Status : UNTESTED STUB
1752 *
1753 * Author : Markus Montkowski [09.07.98 13:39:08]
1754 *****************************************************************************/
1755
1756LONG WIN32API DocumentPropertiesA(HWND hWnd, HANDLE hPrinter,
1757 LPSTR pDeviceName,
1758 LPDEVMODEA pDevModeOutput,
1759 LPDEVMODEA pDevModeInput,
1760 DWORD fMode)
1761{
1762 LPSTR lpName = pDeviceName;
1763 LONG ret;
1764
1765 dprintf(("DocumentPropertiesA(%p,%p,%s,%p,%p,%ld)\n",
1766 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1767 ));
1768
1769 if (hWnd)
1770 {
1771 char szPMQueue[256];
1772 if(SplQueryPMQueueName(pDeviceName, szPMQueue, sizeof(szPMQueue)) == TRUE) {
1773 ret = OSLibShowPrinterDialog(hWnd, szPMQueue);
1774 }
1775 }
1776
1777 if(!pDeviceName) {
1778 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1779 if(!lpNameW) {
1780 ERR("no name from hPrinter?\n");
1781 return -1;
1782 }
1783 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
1784 }
1785
1786#if 0
1787 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
1788 pDevModeInput, NULL, fMode);
1789#endif
1790
1791 switch (fMode & ~DM_PROMPT) {
1792 case 0:
1793 /* TODO - Printer driver specific data */
1794 ret = (sizeof(DEVMODEA));
1795 break;
1796
1797 case DM_IN_BUFFER:
1798 case DM_IN_BUFFER | DM_OUT_BUFFER:
1799 {
1800 HKEY hkey,hkeyPrinters,hkeyPrinter;
1801
1802 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1803 ERROR_SUCCESS)
1804 {
1805 ERR("Can't open Printers key\n");
1806 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1807 ret = -1;
1808 break;
1809 }
1810
1811 if(RegOpenKeyA(hkeyPrinters, lpName, &hkeyPrinter) != ERROR_SUCCESS)
1812 {
1813 ERR("Can't find opened printer %s in registry\n", lpName);
1814 RegCloseKey(hkeyPrinters);
1815 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1816 ret = -1;
1817 break;
1818 }
1819
1820 WINSPOOL_SetDevModeFromReg(hkeyPrinter, Default_DevModeW, (LPBYTE)pDevModeInput,
1821 sizeof(DEVMODEA));
1822 if (pDevModeOutput) {
1823 memcpy(pDevModeOutput, pDevModeInput, sizeof(DEVMODEA));
1824 }
1825 RegCloseKey(hkeyPrinter);
1826 RegCloseKey(hkeyPrinters);
1827 ret = IDOK;
1828 break;
1829 }
1830
1831 case DM_OUT_BUFFER:
1832 if(pDevModeOutput)
1833 {
1834 PRINTER_INFO_2A *pInfo;
1835 DWORD needed;
1836
1837 GetPrinterA(hPrinter, 2, NULL, 0, &needed);
1838 pInfo = (PRINTER_INFO_2A*)HeapAlloc(GetProcessHeap(),0,needed);
1839 if(GetPrinterA(hPrinter, 2, (LPBYTE)pInfo, needed, &needed) == FALSE) {
1840 dprintf(("GetPrinterA failed"));
1841 ret = -1;
1842 break;
1843 }
1844 if (pInfo->pDevMode) {
1845 memcpy(pDevModeOutput, pInfo->pDevMode, sizeof(DEVMODEA));
1846 }
1847 HeapFree(GetProcessHeap(),0,pInfo);
1848 }
1849 ret = IDOK;
1850 break;
1851
1852 default:
1853 dprintf(("Unsupported fMode = %d",fMode));
1854 ret = -1;
1855 break;
1856 }
1857
1858 if(!pDeviceName)
1859 HeapFree(GetProcessHeap(),0,lpName);
1860 return ret;
1861}
1862
1863
1864
1865/***********************************************************
1866 * PRINTER_INFO_2AtoW
1867 * Creates a unicode copy of PRINTER_INFO_2A on heap
1868 */
1869static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1870{
1871 LPPRINTER_INFO_2W piW;
1872 if(!piA) return NULL;
1873 piW = (LPPRINTER_INFO_2W) HeapAlloc(heap, 0, sizeof(*piW));
1874 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1875 piW->pServerName = HEAP_strdupAtoW(heap, 0, piA->pServerName);
1876 piW->pPrinterName = HEAP_strdupAtoW(heap, 0, piA->pPrinterName);
1877 piW->pShareName = HEAP_strdupAtoW(heap, 0, piA->pShareName);
1878 piW->pPortName = HEAP_strdupAtoW(heap, 0, piA->pPortName);
1879 piW->pDriverName = HEAP_strdupAtoW(heap, 0, piA->pDriverName);
1880 piW->pComment = HEAP_strdupAtoW(heap, 0, piA->pComment);
1881 piW->pLocation = HEAP_strdupAtoW(heap, 0, piA->pLocation);
1882 piW->pDevMode = DEVMODEdupAtoW(heap, piA->pDevMode);
1883 piW->pSepFile = HEAP_strdupAtoW(heap, 0, piA->pSepFile);
1884 piW->pPrintProcessor = HEAP_strdupAtoW(heap, 0, piA->pPrintProcessor);
1885 piW->pDatatype = HEAP_strdupAtoW(heap, 0, piA->pDatatype);
1886 piW->pParameters = HEAP_strdupAtoW(heap, 0, piA->pParameters);
1887 return piW;
1888}
1889
1890/***********************************************************
1891 * FREE_PRINTER_INFO_2W
1892 * Free PRINTER_INFO_2W and all strings
1893 */
1894static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1895{
1896 if(!piW) return;
1897
1898 HeapFree(heap,0,piW->pServerName);
1899 HeapFree(heap,0,piW->pPrinterName);
1900 HeapFree(heap,0,piW->pShareName);
1901 HeapFree(heap,0,piW->pPortName);
1902 HeapFree(heap,0,piW->pDriverName);
1903 HeapFree(heap,0,piW->pComment);
1904 HeapFree(heap,0,piW->pLocation);
1905 HeapFree(heap,0,piW->pDevMode);
1906 HeapFree(heap,0,piW->pSepFile);
1907 HeapFree(heap,0,piW->pPrintProcessor);
1908 HeapFree(heap,0,piW->pDatatype);
1909 HeapFree(heap,0,piW->pParameters);
1910 HeapFree(heap,0,piW);
1911 return;
1912}
1913
1914
1915/*****************************************************************************
1916 * Name : HANDLE AddPrinterA
1917 * Purpose :
1918 * Parameters: LPSTR pName pointer to server name
1919 * DWORD Level printer info. structure level
1920 * LPBYTE pPrinter pointer to structure
1921 * Variables :
1922 * Result :
1923 * Remark :
1924 * Status : UNTESTED STUB
1925 *
1926 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
1927 *
1928 * Author : Markus Montkowski [09.07.98 14:18:56]
1929 *****************************************************************************/
1930
1931HANDLE WIN32API AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1932{
1933 WCHAR *pNameW = NULL;
1934 PRINTER_INFO_2W *piW;
1935 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1936 HANDLE ret;
1937
1938 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1939 if(Level != 2) {
1940 ERR("Level = %ld, unsupported!\n", Level);
1941 SetLastError(ERROR_INVALID_LEVEL);
1942 return 0;
1943 }
1944 if (pName)
1945 pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
1946 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1947
1948 ret = AddPrinterW(pNameW, Level, (LPBYTE)piW);
1949
1950 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1951 HeapFree(GetProcessHeap(),0,pNameW);
1952 return ret;
1953}
1954
1955
1956/*****************************************************************************
1957 * Name : HANDLE AddPrinterW
1958 * Purpose :
1959 * Parameters: LPWSTR pName pointer to server name
1960 * DWORD Level printer info. structure level
1961 * LPBYTE pPrinter pointer to structure
1962 * Variables :
1963 * Result :
1964 * Remark :
1965 * Status : UNTESTED STUB
1966 *
1967 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
1968 *
1969 * Author : Markus Montkowski [09.07.98 14:18:56]
1970 *****************************************************************************/
1971
1972HANDLE WIN32API AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1973{
1974 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1975 LPDEVMODEA dmA;
1976 LPDEVMODEW dmW;
1977 HANDLE retval;
1978 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1979 LONG size;
1980
1981 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1982
1983 if(pName != NULL) {
1984 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1985 SetLastError(ERROR_INVALID_PARAMETER);
1986 return 0;
1987 }
1988 if(Level != 2) {
1989 ERR("Level = %ld, unsupported!\n", Level);
1990 SetLastError(ERROR_INVALID_LEVEL);
1991 return 0;
1992 }
1993#if 0
1994 // SvL: OS/2 printer names can be up to 48 characters, whereas this limit
1995 // is 32 chars. We don't actually copy the full printer name into the
1996 // dmDeviceName string, so it's fairly safe to remove this check.
1997 // (Acrobat Reader Defect 937)
1998 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1999 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
2000 debugstr_w(pi->pPrinterName)
2001 );
2002 SetLastError(ERROR_INVALID_LEVEL);
2003 return 0;
2004 }
2005#endif
2006 if(!pPrinter) {
2007 SetLastError(ERROR_INVALID_PARAMETER);
2008 return 0;
2009 }
2010 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2011 ERROR_SUCCESS) {
2012 ERR("Can't create Printers key\n");
2013 return 0;
2014 }
2015 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2016 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
2017 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2018 RegCloseKey(hkeyPrinter);
2019 RegCloseKey(hkeyPrinters);
2020 return 0;
2021 }
2022 RegCloseKey(hkeyPrinter);
2023 }
2024 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2025 if(!hkeyDrivers) {
2026 ERR("Can't create Drivers key\n");
2027 RegCloseKey(hkeyPrinters);
2028 return 0;
2029 }
2030 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2031 ERROR_SUCCESS) {
2032 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2033 RegCloseKey(hkeyPrinters);
2034 RegCloseKey(hkeyDrivers);
2035 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2036 return 0;
2037 }
2038 RegCloseKey(hkeyDriver);
2039 RegCloseKey(hkeyDrivers);
2040
2041 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2042 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2043 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2044 RegCloseKey(hkeyPrinters);
2045 return 0;
2046 }
2047
2048 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2049 ERROR_SUCCESS) {
2050 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2051 SetLastError(ERROR_INVALID_PRINTER_NAME);
2052 RegCloseKey(hkeyPrinters);
2053 return 0;
2054 }
2055 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
2056 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2057 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2058
2059 /* See if we can load the driver. We may need the devmode structure anyway
2060 *
2061 * FIXME:
2062 * Note that DocumentPropertiesW will briefly try to open the printer we
2063 * just create to find a DEVMODEA struct (it will use the WINEPS default
2064 * one in case it is not there, so we are ok).
2065 */
2066 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2067 if(size < 0) {
2068 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
2069 size = sizeof(DEVMODEW);
2070 }
2071#if 0
2072 if(pi->pDevMode)
2073 dmW = pi->pDevMode;
2074 else {
2075 dmW = (LPDEVMODEW) HeapAlloc(GetProcessHeap(), 0, size);
2076 dmW->dmSize = size;
2077 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER)) {
2078 ERR("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
2079 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2080 return 0;
2081 }
2082 /* set devmode to printer name */
2083 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
2084 }
2085
2086 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2087 and we support these drivers. NT writes DEVMODEW so somehow
2088 we'll need to distinguish between these when we support NT
2089 drivers */
2090 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2091 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY, (LPBYTE)dmA,
2092 dmA->dmSize + dmA->dmDriverExtra);
2093 HeapFree(GetProcessHeap(), 0, dmA);
2094 if(!pi->pDevMode)
2095 HeapFree(GetProcessHeap(), 0, dmW);
2096#endif
2097 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2098 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2099 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2100 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2101
2102 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2103 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2104 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2105 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
2106 (LPBYTE)&pi->Priority, sizeof(DWORD));
2107 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2108 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2109 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
2110 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2111 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
2112 (LPBYTE)&pi->Status, sizeof(DWORD));
2113 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
2114 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2115
2116 RegCloseKey(hkeyPrinter);
2117 RegCloseKey(hkeyPrinters);
2118 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2119 ERR("OpenPrinter failing\n");
2120 return 0;
2121 }
2122 return retval;
2123}
2124
2125
2126
2127/*****************************************************************************
2128 * Name : BOOL AddPrinterDriverA
2129 * Purpose :
2130 * Parameters: LPSTR pName pointer to server name
2131 * DWORD Level printer info. structure level
2132 * LPBYTE pDriverInfo pointer to printer info. structure
2133 * Variables :
2134 * Result :
2135 * Remark :
2136 * Status : UNTESTED STUB
2137 *
2138 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
2139 *
2140 * Author : Markus Montkowski [09.07.98 14:20:04]
2141 *****************************************************************************/
2142
2143BOOL WIN32API AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2144{
2145 DRIVER_INFO_3A di3;
2146 HKEY hkeyDrivers, hkeyName;
2147
2148 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
2149
2150 if(level != 2 && level != 3) {
2151 SetLastError(ERROR_INVALID_LEVEL);
2152 return FALSE;
2153 }
2154 if(pName != NULL) {
2155 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
2156 SetLastError(ERROR_INVALID_PARAMETER);
2157 return FALSE;
2158 }
2159 if(!pDriverInfo) {
2160 WARN("pDriverInfo == NULL\n");
2161 SetLastError(ERROR_INVALID_PARAMETER);
2162 return FALSE;
2163 }
2164
2165 if(level == 3)
2166 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2167 else {
2168 memset(&di3, 0, sizeof(di3));
2169 *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
2170 }
2171
2172 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2173 !di3.pDataFile) {
2174 SetLastError(ERROR_INVALID_PARAMETER);
2175 return FALSE;
2176 }
2177 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2178 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2179 if(!di3.pHelpFile) di3.pHelpFile = "";
2180 if(!di3.pMonitorName) di3.pMonitorName = "";
2181
2182 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2183
2184 if(!hkeyDrivers) {
2185 ERR("Can't create Drivers key\n");
2186 return FALSE;
2187 }
2188
2189 if(level == 2) { /* apparently can't overwrite with level2 */
2190 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2191 RegCloseKey(hkeyName);
2192 RegCloseKey(hkeyDrivers);
2193 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
2194 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2195 return FALSE;
2196 }
2197 }
2198 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2199 RegCloseKey(hkeyDrivers);
2200 ERR("Can't create Name key\n");
2201 return FALSE;
2202 }
2203 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE)di3.pConfigFile,
2204 strlen(di3.pConfigFile)+1);
2205 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE)di3.pDataFile, strlen(di3.pDataFile)+1);
2206 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE)di3.pDriverPath, strlen(di3.pDriverPath)+1);
2207 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE)&di3.cVersion,
2208 sizeof(DWORD));
2209 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE)di3.pDefaultDataType, strlen(di3.pDefaultDataType)+1);
2210 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2211 (LPBYTE)di3.pDependentFiles, strlen(di3.pDependentFiles)+1);
2212 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE)di3.pHelpFile, strlen(di3.pHelpFile)+1);
2213 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE)di3.pMonitorName, strlen(di3.pMonitorName)+1);
2214 RegCloseKey(hkeyName);
2215 RegCloseKey(hkeyDrivers);
2216
2217 return TRUE;
2218}
2219
2220
2221/*****************************************************************************
2222 * Name : BOOL AddPrinterDriverW
2223 * Purpose :
2224 * Parameters: LPWSTR pName pointer to server name
2225 * DWORD Level printer info. structure level
2226 * LPBYTE pDriverInfo pointer to printer info. structure
2227 * Variables :
2228 * Result :
2229 * Remark :
2230 * Status : UNTESTED STUB
2231 *
2232 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
2233 *
2234 * Author : Markus Montkowski [09.07.98 14:20:04]
2235 *****************************************************************************/
2236
2237BOOL WIN32API AddPrinterDriverW(LPWSTR pName, DWORD Level, LPBYTE pDriverInfo)
2238{
2239 dprintf(("WINSPOOL: AddPrinterDriverW not implemented\n"));
2240 return (FALSE);
2241}
2242
2243/*****************************************************************************
2244 * Name : BOOL DeletePrinter
2245 * Purpose :
2246 * Parameters: HANDLE hPrinter handle to printer object
2247 * Variables :
2248 * Result :
2249 * Remark :
2250 * Status : UNTESTED STUB
2251 *
2252 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
2253 *
2254 * Author : Markus Montkowski [09.07.98 14:30:50]
2255 *****************************************************************************/
2256
2257BOOL WIN32API DeletePrinter(HANDLE hPrinter)
2258{
2259 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
2260 HKEY hkeyPrinters;
2261
2262 if(!lpNameW) return FALSE;
2263
2264 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
2265 SHDeleteKeyW(hkeyPrinters, lpNameW);
2266 RegCloseKey(hkeyPrinters);
2267 return TRUE;
2268 }
2269 else {
2270 dprintf(("Can't open Printers key"));
2271 return FALSE;
2272 }
2273}
2274
2275
2276/*****************************************************************************
2277 * Name : DWORD DeviceCapabilitiesA
2278 * Purpose :
2279 * Parameters: LPCSTR pDevice pointer to a printer-name string
2280 * LPCSTR pPort pointer to a port-name string
2281 * WORD fwCapability device capability to query
2282 * LPSTR pOutput pointer to the output
2283 * CONST DEVMODE *pDevMode pointer to structure with device data
2284 * Variables :
2285 * Result :
2286 * Remark :
2287 * Status : UNTESTED STUB
2288 *
2289 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
2290 *
2291 * Author : Markus Montkowski [09.07.98 14:27:08]
2292 *****************************************************************************/
2293
2294INT WIN32API DeviceCapabilitiesA(LPCSTR pDevice,
2295 LPCSTR pPort,
2296 WORD fwCapability,
2297 LPSTR pOutput,
2298 DEVMODEA * pDevMode)
2299{
2300 char szPMQueue[256];
2301
2302 dprintf(("WINSPOOL: DeviceCapabilitiesA %s %s %x %x %x", pDevice, pPort, fwCapability, pOutput, pDevMode));
2303
2304 //Get the PM Queue name corresponding to the printer device
2305 if(SplQueryPMQueueName((LPSTR)pDevice, szPMQueue, sizeof(szPMQueue)) == TRUE) {
2306 return O32_DeviceCapabilities(szPMQueue, pPort, fwCapability, pOutput, pDevMode);
2307 }
2308 return -1;
2309}
2310
2311
2312/*****************************************************************************
2313 * DeviceCapabilitiesW [WINSPOOL.152]
2314 *
2315 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2316 *
2317 */
2318INT WIN32API DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2319 WORD fwCapability, LPWSTR pOutput,
2320 CONST DEVMODEW * pDevMode)
2321{
2322 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
2323 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
2324 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
2325 INT ret;
2326
2327 if(pOutput && (fwCapability == DC_BINNAMES ||
2328 fwCapability == DC_FILEDEPENDENCIES ||
2329 fwCapability == DC_PAPERNAMES)) {
2330 /* These need A -> W translation */
2331 INT size = 0, i;
2332 LPSTR pOutputA;
2333 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2334 dmA);
2335 if(ret == -1)
2336 return ret;
2337 switch(fwCapability) {
2338 case DC_BINNAMES:
2339 size = 24;
2340 break;
2341 case DC_PAPERNAMES:
2342 case DC_FILEDEPENDENCIES:
2343 size = 64;
2344 break;
2345 }
2346 pOutputA = (LPSTR)HeapAlloc(GetProcessHeap(), 0, size * ret);
2347 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2348 dmA);
2349 for(i = 0; i < ret; i++)
2350 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2351 pOutput + (i * size), size);
2352 HeapFree(GetProcessHeap(), 0, pOutputA);
2353 } else {
2354 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2355 (LPSTR)pOutput, dmA);
2356 }
2357 HeapFree(GetProcessHeap(),0,pPortA);
2358 HeapFree(GetProcessHeap(),0,pDeviceA);
2359 HeapFree(GetProcessHeap(),0,dmA);
2360 return ret;
2361}
2362
2363
2364
2365
2366/******************************************************************
2367 * EnumPrintersW [WINSPOOL.@]
2368 *
2369 * Enumerates the available printers, print servers and print
2370 * providers, depending on the specified flags, name and level.
2371 *
2372 * RETURNS:
2373 *
2374 * If level is set to 1:
2375 * Not implemented yet!
2376 * Returns TRUE with an empty list.
2377 *
2378 * If level is set to 2:
2379 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2380 * Returns an array of PRINTER_INFO_2 data structures in the
2381 * lpbPrinters buffer. Note that according to MSDN also an
2382 * OpenPrinter should be performed on every remote printer.
2383 *
2384 * If level is set to 4 (officially WinNT only):
2385 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2386 * Fast: Only the registry is queried to retrieve printer names,
2387 * no connection to the driver is made.
2388 * Returns an array of PRINTER_INFO_4 data structures in the
2389 * lpbPrinters buffer.
2390 *
2391 * If level is set to 5 (officially WinNT4/Win9x only):
2392 * Fast: Only the registry is queried to retrieve printer names,
2393 * no connection to the driver is made.
2394 * Returns an array of PRINTER_INFO_5 data structures in the
2395 * lpbPrinters buffer.
2396 *
2397 * If level set to 3 or 6+:
2398 * returns zero (failure!)
2399 *
2400 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2401 * for information.
2402 *
2403 * BUGS:
2404 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2405 * - Only levels 2, 4 and 5 are implemented at the moment.
2406 * - 16-bit printer drivers are not enumerated.
2407 * - Returned amount of bytes used/needed does not match the real Windoze
2408 * implementation (as in this implementation, all strings are part
2409 * of the buffer, whereas Win32 keeps them somewhere else)
2410 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2411 *
2412 * NOTE:
2413 * - In a regular Wine installation, no registry settings for printers
2414 * exist, which makes this function return an empty list.
2415 */
2416BOOL WINAPI EnumPrintersW(
2417 DWORD dwType, /* [in] Types of print objects to enumerate */
2418 LPWSTR lpszName, /* [in] name of objects to enumerate */
2419 DWORD dwLevel, /* [in] type of printer info structure */
2420 LPBYTE lpbPrinters, /* [out] buffer which receives info */
2421 DWORD cbBuf, /* [in] max size of buffer in bytes */
2422 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
2423 LPDWORD lpdwReturned /* [out] number of entries returned */
2424 )
2425{
2426 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2427 lpdwNeeded, lpdwReturned, TRUE);
2428}
2429
2430
2431
2432
2433/*****************************************************************************
2434 * Name : BOOL GetPrinterA
2435 * Purpose :
2436 * Parameters: HANDLE hPrinter handle to printer of interest
2437 * DWORD Level version of printer info data structure
2438 * LPBYTE pPrinter pointer to array of bytes that receives printer info. structure
2439 * DWORD cbBuf size, in bytes, of array of bytes
2440 * LPDWORD pcbNeeded pointer to variable with count of bytes retrieved (or required)
2441 * Variables :
2442 * Result :
2443 * Remark :
2444 * Status : UNTESTED STUB
2445 *
2446 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
2447 *
2448 * Author : Markus Montkowski [09.07.98 14:45:36]
2449 *****************************************************************************/
2450
2451BOOL WIN32API GetPrinterA(
2452 HANDLE hPrinter,
2453 DWORD Level,
2454 LPBYTE pPrinter,
2455 DWORD cbBuf,
2456 LPDWORD pcbNeeded)
2457{
2458 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2459 FALSE);
2460}
2461
2462
2463/*****************************************************************************
2464 * Name : BOOL GetPrinterW
2465 * Purpose :
2466 * Parameters: HANDLE hPrinter handle to printer of interest
2467 * DWORD Level version of printer info data structure
2468 * LPBYTE pPrinter pointer to array of bytes that receives printer info. structure
2469 * DWORD cbBuf size, in bytes, of array of bytes
2470 * LPDWORD pcbNeeded pointer to variable with count of bytes retrieved (or required)
2471 * Variables :
2472 * Result :
2473 * Remark :
2474 * Status : UNTESTED STUB
2475 *
2476 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
2477 *
2478 * Author : Markus Montkowski [09.07.98 14:45:36]
2479 *****************************************************************************/
2480
2481BOOL WIN32API GetPrinterW(
2482 HANDLE hPrinter,
2483 DWORD Level,
2484 LPBYTE pPrinter,
2485 DWORD cbBuf,
2486 LPDWORD pcbNeeded)
2487{
2488 dprintf(("WINSPOOL: GetPrinterW not implemented\n"));
2489 return (FALSE);
2490}
2491
2492
2493
2494/*****************************************************************************
2495 * Name : BOOL GetPrinterDriverA
2496 * Purpose :
2497 * Parameters: HANDLE hPrinter printer object
2498 * LPSTR pEnvironment address of environment
2499 * DWORD Level structure level
2500 * LPBYTE pDriverInfo address of structure array
2501 * DWORD cbBuf size, in bytes, of array
2502 * LPDWORD pcbNeeded address of variable with number of bytes retrieved (or required)
2503 * Variables :
2504 * Result :
2505 * Remark :
2506 * Status : UNTESTED STUB
2507 *
2508 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
2509 *
2510 * Author : Markus Montkowski [09.07.98 14:47:01]
2511 *****************************************************************************/
2512
2513BOOL WIN32API GetPrinterDriverA(
2514 HANDLE hPrinter,
2515 LPSTR pEnvironment,
2516 DWORD Level,
2517 LPBYTE pDriverInfo,
2518 DWORD cbBuf,
2519 LPDWORD pcbNeeded)
2520{
2521 BOOL ret;
2522 LPWSTR pEnvW = HEAP_strdupAtoW(GetProcessHeap(),0,pEnvironment);
2523 ret = WINSPOOL_GetPrinterDriver(hPrinter, pEnvW, Level, pDriverInfo,
2524 cbBuf, pcbNeeded, FALSE);
2525 HeapFree(GetProcessHeap(),0,pEnvW);
2526 return ret;
2527}
2528
2529
2530/*****************************************************************************
2531 * Name : BOOL GetPrinterDriverW
2532 * Purpose :
2533 * Parameters: HANDLE hPrinter printer object
2534 * LPWSTR pEnvironment address of environment
2535 * DWORD Level structure level
2536 * LPBYTE pDriverInfo address of structure array
2537 * DWORD cbBuf size, in bytes, of array
2538 * LPDWORD pcbNeeded address of variable with number of bytes retrieved (or required)
2539 * Variables :
2540 * Result :
2541 * Remark :
2542 * Status : UNTESTED STUB
2543 *
2544 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
2545 *
2546 * Author : Markus Montkowski [09.07.98 14:47:01]
2547 *****************************************************************************/
2548
2549BOOL WIN32API GetPrinterDriverW(
2550 HANDLE hPrinter,
2551 LPWSTR pEnvironment,
2552 DWORD Level,
2553 LPBYTE pDriverInfo,
2554 DWORD cbBuf,
2555 LPDWORD pcbNeeded)
2556{
2557 dprintf(("WINSPOOL: GetPrinterDriverW not implemented\n"));
2558 return (FALSE);
2559}
2560
2561
2562/*****************************************************************************
2563 * Name : BOOL GetPrinterDriverDirectoryA
2564 * Purpose :
2565 * Parameters: LPSTR pName address of server name
2566 * LPSTR pEnvironment address of environment
2567 * DWORD Level address of structure
2568 * LPBYTE pDriverDirectory address of structure array that receives path
2569 * DWORD cbBuf size, in bytes, of array
2570 * LPDWORD pcbNeeded address of variable with number of bytes retrieved (or required)
2571 * Variables :
2572 * Result :
2573 * Remark :
2574 * Status : UNTESTED STUB
2575 *
2576 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
2577 *
2578 * Author : Markus Montkowski [09.07.98 14:47:16]
2579 *****************************************************************************/
2580
2581BOOL WIN32API GetPrinterDriverDirectoryA(
2582 LPSTR pName,
2583 LPSTR pEnvironment,
2584 DWORD Level,
2585 LPBYTE pDriverDirectory,
2586 DWORD cbBuf,
2587 LPDWORD pcbNeeded)
2588{
2589 DWORD needed;
2590
2591 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", pName, pEnvironment, Level,
2592 pDriverDirectory, cbBuf, pcbNeeded);
2593 if(pName != NULL) {
2594 FIXME("pName = `%s' - unsupported\n", pName);
2595 SetLastError(ERROR_INVALID_PARAMETER);
2596 return FALSE;
2597 }
2598 if(pEnvironment != NULL) {
2599 FIXME("pEnvironment = `%s' - unsupported\n", pEnvironment);
2600 SetLastError(ERROR_INVALID_ENVIRONMENT);
2601 return FALSE;
2602 }
2603 if(Level != 1) /* win95 ignores this so we just carry on */
2604 WARN("Level = %ld - assuming 1\n", Level);
2605
2606 /* FIXME should read from registry */
2607 needed = GetSystemDirectoryA((LPSTR)pDriverDirectory, cbBuf);
2608 needed++;
2609 if(pcbNeeded)
2610 *pcbNeeded = needed;
2611 if(needed > cbBuf) {
2612 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2613 return FALSE;
2614 }
2615 return TRUE;
2616
2617}
2618
2619
2620/*****************************************************************************
2621 * Name : BOOL GetPrinterDriverDirectoryW
2622 * Purpose :
2623 * Parameters: LPWSTR pName address of server name
2624 * LPWSTR pEnvironment address of environment
2625 * DWORD Level address of structure
2626 * LPBYTE pDriverDirectory address of structure array that receives path
2627 * DWORD cbBuf size, in bytes, of array
2628 * LPDWORD pcbNeeded address of variable with number of bytes retrieved (or required)
2629 * Variables :
2630 * Result :
2631 * Remark :
2632 * Status : UNTESTED STUB
2633 *
2634 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
2635 *
2636 * Author : Markus Montkowski [09.07.98 14:47:16]
2637 *****************************************************************************/
2638
2639BOOL WIN32API GetPrinterDriverDirectoryW(
2640 LPWSTR pName,
2641 LPWSTR pEnvironment,
2642 DWORD Level,
2643 LPBYTE pDriverDirectory,
2644 DWORD cbBuf,
2645 LPDWORD pcbNeeded)
2646{
2647 dprintf(("WINSPOOL: GetPrinterDriverDirectoryW not implemented\n"));
2648 return (FALSE);
2649}
2650
2651#ifndef __WIN32OS2__
2652/******************************************************************
2653 * WINSPOOL_GetOpenedPrinterEntry
2654 * Get the first place empty in the opened printer table
2655 */
2656static HANDLE WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name )
2657{
2658 int i;
2659
2660 for (i = 0; i < nb_printers; i++) if (!printer_array[i]) break;
2661
2662 if (i >= nb_printers)
2663 {
2664 LPWSTR *new_array = (LPWSTR*)HeapReAlloc( GetProcessHeap(), 0, printer_array,
2665 (nb_printers + 16) * sizeof(*new_array) );
2666 if (!new_array) return 0;
2667 printer_array = new_array;
2668 nb_printers += 16;
2669 }
2670
2671 if ((printer_array[i] = (WCHAR*)HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )) != NULL)
2672 {
2673 strcpyW( printer_array[i], name );
2674 return (HANDLE)(i + 1);
2675 }
2676 return 0;
2677}
2678#endif
2679
2680/**
2681 * Opens a printer.
2682 *
2683 * @returns Success indicator, last error set on failure.
2684 * @param lpPrinterName Pointer to printer name.
2685 * @param phPrinter Where to store the handle to the opned printer instance.
2686 * @param pDefault Printer defaults. (Current ignored)
2687 * @status partially implemented.
2688 * @author ???
2689 * @author knut st. osmundsen <bird-srcspam@anduin.net>
2690 */
2691BOOL WIN32API OpenPrinterW(LPWSTR lpPrinterName, HANDLE *phPrinter, PRINTER_DEFAULTSW *pDefault)
2692{
2693 HKEY hkeyPrinters, hkeyPrinter;
2694
2695 /*
2696 * Validate input.
2697 */
2698 if (!lpPrinterName)
2699 {
2700 dprintf(("WINSPOOL: OpenPrinterW: printerName=NULL pDefault=%p returning false!\n", pDefault));
2701 SetLastError(ERROR_INVALID_PARAMETER);
2702 return FALSE;
2703 }
2704 dprintf(("WINSPOOL: OpenPrinterW: printerName='%ls' pDefault=%p\n", lpPrinterName, pDefault));
2705
2706 /*
2707 * Check if the Printer exists.
2708 */
2709 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) != ERROR_SUCCESS)
2710 {
2711 dprintf(("Can't create Printers key\n"));
2712 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
2713 return FALSE;
2714 }
2715
2716 if ( lpPrinterName[0] == '\0' /* explicitly fail on "" */
2717 || RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter) != ERROR_SUCCESS)
2718 {
2719 dprintf(("Can't find printer '%ls' in registry\n", lpPrinterName));
2720 RegCloseKey(hkeyPrinters);
2721 SetLastError(ERROR_INVALID_PRINTER_NAME);
2722 return FALSE;
2723 }
2724 RegCloseKey(hkeyPrinter);
2725 RegCloseKey(hkeyPrinters);
2726
2727 /*
2728 * Seems like win95 doesn't care if there is no where to store
2729 * the handle. We'll do the same.
2730 */
2731 if (!phPrinter) /* This seems to be what win95 does anyway */
2732 {
2733 dprintf(("WINSPOOL: OpenPrinterW: phPrinter is NULL, returning succesfully anyhow\n"));
2734 return TRUE;
2735 }
2736
2737 /*
2738 * Create a handle for this open instance.
2739 */
2740 *phPrinter = NULL; /* crash here */
2741#ifdef __WIN32OS2__
2742 POPENPRINTER p = openprinterNew(lpPrinterName);
2743 if (!p)
2744 {
2745 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2746 dprintf(("WINSPOOL: OpenPrinterW: out of memory allocating handle\n"));
2747 return FALSE;
2748 }
2749 *phPrinter = p->hOpenPrinter;
2750#else
2751 *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
2752#endif
2753
2754 if (pDefault != NULL)
2755 dprintf(("Not handling pDefault\n"));
2756
2757 dprintf(("WINSPOOL: OpenPrinterW: returning successfully *phPrinter=%d\n", *phPrinter));
2758 return TRUE;
2759}
2760
2761
2762
2763
2764/*********************************************************************
2765 * DocumentPropertiesW (WINSPOOL.166)
2766 */
2767LONG WIN32API DocumentPropertiesW(
2768 HWND hWnd,
2769 HANDLE hPrinter,
2770 LPWSTR pDeviceName,
2771 PDEVMODEW pDevModeOutput,
2772 PDEVMODEW pDevModeInput,
2773 DWORD fMode)
2774{
2775 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
2776 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
2777 LPDEVMODEA pDevModeOutputA = NULL;
2778 LONG ret;
2779
2780 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
2781 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2782 fMode);
2783 if(pDevModeOutput) {
2784 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2785 if(ret < 0) return ret;
2786 pDevModeOutputA = (LPDEVMODEA)HeapAlloc(GetProcessHeap(), 0, ret);
2787 }
2788 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2789 pDevModeInputA, fMode);
2790 if(ret < 0) return ret;
2791
2792 if(pDevModeOutput) {
2793 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2794 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2795 }
2796 if(fMode == 0 && ret > 0)
2797 ret += (CCHDEVICENAME + CCHFORMNAME);
2798 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2799 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2800 return ret;
2801}
2802
2803
2804
2805#ifdef __WIN32OS2__
2806
2807/**
2808 * Start a new printer job.
2809 *
2810 * @returns Print job identifier.
2811 * @returns 0 on failure with last error set.
2812 * @param hPrinter Handle to the printer object.
2813 * @param Level Structure level.
2814 * @param pDocInfo Pointer to structure.
2815 * @status partially implemented.
2816 * @author knut st. osmundsen <bird-srcspam@anduin.net>
2817 */
2818DWORD WIN32API StartDocPrinterA(
2819 HANDLE hPrinter,
2820 DWORD Level,
2821 LPBYTE pDocInfo)
2822{
2823 DWORD rc = 0;
2824 dprintf(("WINSPOOL: StartDocPrinterA\n"));
2825
2826 /*
2827 * Get printer instance data.
2828 */
2829 POPENPRINTER pPrt = openprinterFind(hPrinter);
2830 if (!pPrt)
2831 {
2832 dprintf(("WINSPOOL: StartDocPrinterA: Invalid handle %d\n", hPrinter));
2833 SetLastError(ERROR_INVALID_HANDLE);
2834 return 0;
2835 }
2836
2837 /*
2838 * Switch out based on input data.
2839 */
2840 switch (Level)
2841 {
2842 case 1:
2843 {
2844 PDOC_INFO_1A pDocInfoA = (PDOC_INFO_1A)pDocInfo;
2845 dprintf(("WINSPOOL: pDocName =%s\n", pDocInfoA->pDocName));
2846 dprintf(("WINSPOOL: pDatatype =%s\n", pDocInfoA->pDatatype));
2847 dprintf(("WINSPOOL: pOutputFile=%s\n", pDocInfoA->pOutputFile));
2848
2849 /*
2850 * Validate input.
2851 * ASSUMES: default is RAW as it is on OS/2.
2852 */
2853 if ( pDocInfoA->pDatatype
2854 && !strstr(pDocInfoA->pDatatype, "RAW"))
2855 {
2856 SetLastError(ERROR_INVALID_PARAMETER);
2857 dprintf(("WINSPOOL: data type not supported\n"));
2858 break;
2859 }
2860
2861 /*
2862 * Make sure the OS/2 spool file is opened.
2863 */
2864 int rcOs2 = openprinterOpenSpoolFile(pPrt);
2865 if (!rcOs2)
2866 {
2867 /*
2868 * Start the document.
2869 */
2870 if (OSLibSplQmStartDoc(pPrt->hspl, pDocInfoA->pDocName))
2871 {
2872 rc = (DWORD)pPrt->hspl; /** @todo get the proper job id! */
2873 pPrt->ulCurPage = 0; //reset current page counter
2874 dprintf(("WINSPOOL: StartDocPrinterA: returning jobid %d\n", rc));
2875 return rc;
2876 }
2877 else
2878 SetLastError(OSLibSplWinGetLastError()); /** @todo convert error code!!!!!!!! */
2879 }
2880 else
2881 SetLastError(rcOs2); /** @todo convert error code!!!!!!!! */
2882 break;
2883 }
2884
2885 default:
2886 dprintf(("WINSPOOL: level %d is not supported\n", Level));
2887 SetLastError(ERROR_INVALID_LEVEL); /* not verified. */
2888 break;
2889 }
2890 dprintf(("WINSPOOL: returning failure\n"));
2891 return 0;
2892}
2893
2894
2895/**
2896 * Start a new printer job.
2897 *
2898 * @returns Print job identifier.
2899 * @returns 0 on failure with last error set.
2900 * @param hPrinter Handle to the printer object.
2901 * @param Level Structure level.
2902 * @param pDocInfo Pointer to structure.
2903 * @status partially implemented.
2904 * @author knut st. osmundsen <bird-srcspam@anduin.net>
2905 */
2906DWORD WIN32API StartDocPrinterW(
2907 HANDLE hPrinter,
2908 DWORD Level,
2909 LPBYTE pDocInfo)
2910{
2911 DWORD rc = 0;
2912 dprintf(("WINSPOOL: StartDocPrinterW\n"));
2913 switch (Level)
2914 {
2915 case 1:
2916 {
2917 PDOC_INFO_1W pDocInfoW = (PDOC_INFO_1W)pDocInfo;
2918
2919 DOC_INFO_1A DocInfoA;
2920 DocInfoA.pDocName = UnicodeToAsciiString(pDocInfoW->pDocName);
2921 DocInfoA.pDatatype = UnicodeToAsciiString(pDocInfoW->pDatatype);
2922 DocInfoA.pOutputFile = UnicodeToAsciiString(pDocInfoW->pOutputFile);
2923 rc = StartDocPrinterA(hPrinter, Level, (LPBYTE)&DocInfoA);
2924 FreeAsciiString(DocInfoA.pOutputFile);
2925 FreeAsciiString(DocInfoA.pDatatype);
2926 FreeAsciiString(DocInfoA.pDocName);
2927 break;
2928 }
2929
2930 default:
2931 dprintf(("WINSPOOL: level %d is not supported\n", Level));
2932 SetLastError(ERROR_INVALID_LEVEL); /* not verified. */
2933 break;
2934 }
2935 dprintf(("WINSPOOL: returns %d\n", rc));
2936 return rc;
2937}
2938
2939
2940/**
2941 * Notifies the spooler that a new page is to be written to the
2942 * current printer job.
2943 *
2944 * This is an informational API without much significance I think.
2945 * The implementation assumes StartDocPrinterA/W() must be called first.
2946 *
2947 * @returns Success indicator. last error set on failure.
2948 * @param hPrinter Handle to printer object.
2949 * @status completely implemented.
2950 * @author knut st. osmundsen <bird-srcspam@anduin.net>
2951 */
2952BOOL WIN32API StartPagePrinter(HANDLE hPrinter)
2953{
2954 dprintf(("WINSPOOL: StartPagePrinter: hPrinter=%d\n", hPrinter));
2955 /*
2956 * Get printer instance data.
2957 */
2958 POPENPRINTER pPrt = openprinterFind(hPrinter);
2959 if (!pPrt)
2960 {
2961 dprintf(("WINSPOOL: StartPagePrinter: Invalid handle %d\n", hPrinter));
2962 SetLastError(ERROR_INVALID_HANDLE);
2963 return FALSE;
2964 }
2965
2966 /*
2967 * Not quite sure what should happen here if no StartDocPrinter was issued.
2968 * For now we'll just freak out.
2969 */
2970 if (!pPrt->hspl)
2971 {
2972 DebugAssertFailed(("StartPagePrinter called with no StartDocPrinter issued\n"));
2973 SetLastError(ERROR_INVALID_PRINTER_STATE); /** @todo test on w2k */
2974 return FALSE;
2975 }
2976
2977 if (OSLibSplQmNewPage(pPrt->hspl, pPrt->ulCurPage + 1))
2978 {
2979 pPrt->ulCurPage++;
2980 dprintf(("WINSPOOL: StartPagePrinter: returning successfully (ulCurPage=%lu)\n", pPrt->ulCurPage));
2981 return TRUE;
2982 }
2983
2984 /* failure */
2985 SetLastError(OSLibSplWinGetLastError()); /** @todo convert error code!!! */
2986 dprintf(("WINSPOOL: StartPagePrinter failed. last err=%#x\n", OSLibSplWinGetLastError()));
2987 return FALSE;
2988}
2989
2990
2991/**
2992 * Write raw data to printer.
2993 * @returns Successindicator. lasterr set on failure.
2994 * @param hPrinter Handle to printer object.
2995 * @param pBuf Pointer to the data to write.
2996 * @param cbBuf Size of the data to write.
2997 * @param pcWritten Where to put the number of bytes actually written.
2998 * @status partially implemented.
2999 * @author knut st. osmundsen <bird-srcspam@anduin.net>
3000 * @remark Current implementation relies on StartDocPrinterA/W being called first.
3001 */
3002BOOL WIN32API WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
3003{
3004 BOOL fRc = FALSE;
3005 dprintf(("WINSPOOL: WritePrinter hPrinter=%#x pBuf=%p cbBuf=%d pcWritten=%p\n",
3006 hPrinter, pBuf, cbBuf, pcWritten));
3007
3008 /*
3009 * Get printer instance data.
3010 */
3011 POPENPRINTER pPrt = openprinterFind(hPrinter);
3012 if (!pPrt)
3013 {
3014 dprintf(("WINSPOOL: WritePrinter: Invalid handle %d\n", hPrinter));
3015 SetLastError(ERROR_INVALID_HANDLE);
3016 return FALSE;
3017 }
3018
3019 /*
3020 * Not quite sure what should happen here if no StartDocPrinter was issued.
3021 * For now we'll just freak out.
3022 */
3023 if (!pPrt->hspl)
3024 {
3025 DebugAssertFailed(("WritePrinter called with no StartDocPrinter issued\n"));
3026 SetLastError(ERROR_INVALID_PRINTER_STATE); /** @todo test on w2k */
3027 return FALSE;
3028 }
3029
3030 /*
3031 * Push the data thru to the spooler.
3032 */
3033 if (OSLibSplQmWrite(pPrt->hspl, cbBuf, pBuf))
3034 {
3035 if (pcWritten)
3036 *pcWritten = cbBuf;
3037 dprintf(("WINSPOOL: WritePrinter succceeded writing %d bytes\n", cbBuf));
3038 return TRUE;
3039 }
3040
3041 /* failure */
3042 SetLastError(OSLibSplWinGetLastError()); /** @todo convert error code!!! */
3043 dprintf(("WINSPOOL: WritePrinter failed. last err=%#x\n", OSLibSplWinGetLastError()));
3044 return FALSE;
3045}
3046
3047
3048/**
3049 * Notifies the spooler that the writing of a page to the current
3050 * printer job is completed.
3051 *
3052 * This is an informational API without much significance I think.
3053 * The implementation assumes StartDocPrinterA/W() must be called first.
3054 *
3055 * @returns Success indicator, last error set on failure.
3056 * @param hPrinter Handle to printer object which job is to be ended (completed.
3057 * @status partially implemented
3058 * @author knut st. osmundsen <bird-srcspam@anduin.net>
3059 * @remark Current implementation relies on StartDocPrinterA/W being called first.
3060 */
3061BOOL WIN32API EndPagePrinter(HANDLE hPrinter)
3062{
3063 dprintf(("WINSPOOL: EndPagePrinter: hPrinter=%d\n", hPrinter));
3064
3065 /*
3066 * Get printer instance data.
3067 */
3068 POPENPRINTER pPrt = openprinterFind(hPrinter);
3069 if (!pPrt)
3070 {
3071 dprintf(("WINSPOOL: EndPagePrinter: Invalid handle %d\n", hPrinter));
3072 SetLastError(ERROR_INVALID_HANDLE);
3073 return FALSE;
3074 }
3075
3076 /*
3077 * Not quite sure what should happen here if no StartDocPrinter was issued.
3078 * For now we'll just freak out.
3079 */
3080 if (!pPrt->hspl)
3081 {
3082 DebugAssertFailed(("EndPagePrinter called with no StartDocPrinter issued\n"));
3083 SetLastError(ERROR_INVALID_PRINTER_STATE); /** @todo test on w2k */
3084 return FALSE;
3085 }
3086
3087 /* There is no OS/2 equivalent. */
3088 dprintf(("WINSPOOL: EndPagePrinter: returning successfully (ulCurPage=%lu)\n", pPrt->ulCurPage));
3089 return TRUE;
3090}
3091
3092
3093/**
3094 * Ends a printer job.
3095 *
3096 * @returns Success indicator, last error set on failure.
3097 * @param hPrinter Handle to printer object which job is to be ended (completed.
3098 * @status partially implemented
3099 * @author knut st. osmundsen <bird-srcspam@anduin.net>
3100 * @remark Current implementation relies on StartDocPrinterA/W being called first.
3101 */
3102BOOL WIN32API EndDocPrinter(HANDLE hPrinter)
3103{
3104 BOOL fRc = FALSE;
3105 dprintf(("WINSPOOL: WritePrinter hPrinter=%#x\n", hPrinter));
3106
3107 /*
3108 * Get printer instance data.
3109 */
3110 POPENPRINTER pPrt = openprinterFind(hPrinter);
3111 if (!pPrt)
3112 {
3113 dprintf(("WINSPOOL: WritePrinter: Invalid handle %d\n", hPrinter));
3114 SetLastError(ERROR_INVALID_HANDLE);
3115 return FALSE;
3116 }
3117
3118 /*
3119 * Not quite sure what should happen here if no StartDocPrinter was issued.
3120 * For now we'll just freak out.
3121 */
3122 if (!pPrt->hspl)
3123 {
3124 DebugAssertFailed(("EndDocPrinter called with no StartDocPrinter issued\n"));
3125 SetLastError(ERROR_INVALID_PRINTER_STATE); /** @todo test on w2k */
3126 return FALSE;
3127 }
3128
3129 /*
3130 * End the document, thus closing all Spl related stuff.
3131 */
3132 if (OSLibSplQmEndDoc(pPrt->hspl))
3133 {
3134 dprintf(("WINSPOOL: EndDocPrinter returns successfully\n"));
3135 return TRUE;
3136 }
3137
3138 SetLastError(OSLibSplWinGetLastError()); /** @todo convert error code!!! */
3139 dprintf(("WINSPOOL: EndDocPrinter returns failure\n"));
3140 return FALSE;
3141}
3142
3143
3144
3145/**
3146 * Setup the OS/2 Printer Information in the registry and profile.
3147 *
3148 * We will only enumerate local printer queues.
3149 *
3150 * The mapping between Odin32 and OS/2 is as follows:
3151 * Odin32 OS/2
3152 * Printer Name Queue Comment (WPS object title)
3153 * Driver Name Queue Name
3154 * Printer Comment Queue Comment (= WPS object title)
3155 * Printer Location Device Logical address (port sort of)
3156 * Printer Port Device Logical address (port sort of)
3157 *
3158 * On OS/2 only queue names are unique. It's very easy to make duplicate
3159 * printer names, just create printer objects in more than one WPS folder.
3160 * For duplicate names the queue name will be appended to the name in
3161 * paratheses so the user can actually print to both printers. (Odin32
3162 * only have a concept of printer names and they must thus be unique.)
3163 *
3164 * @returns Success indicator. May possibly have changed the last error on
3165 * both failure and success.
3166 *
3167 * @remark We're only enumerating local printers. This makes sense as remote
3168 * printers (on Lan Servers/Managers) isn't normally stored in the
3169 * registry (IIRC).
3170 */
3171BOOL ExportPrintersToRegistry(void)
3172{
3173 BOOL fRc = FALSE;
3174 DWORD cbNeeded;
3175 DWORD cUnused;
3176
3177 dprintf(("WINSPOOL: ExportPrintersToRegistry"));
3178
3179 /*
3180 * Get printers.
3181 */
3182 ULONG cQueues = 0;
3183 POSLIB_PRQINFO3 paQueues;
3184 paQueues = (POSLIB_PRQINFO3)OSLibSplEnumQueue(NULL, 3, &cQueues, &cUnused);
3185 if (paQueues)
3186 {
3187 /*
3188 * Get printer devices.
3189 */
3190 ULONG cDevices;
3191 POSLIB_PRDINFO3 paDevices;
3192 paDevices = (POSLIB_PRDINFO3)OSLibSplEnumDevice(NULL, 3, &cDevices, &cUnused);
3193 if (paDevices)
3194 {
3195 fRc = TRUE; /* getting this far is pretty much a success I'd say.... */
3196
3197 /*
3198 * Make printer WPS names (queue comment) unique by appending the
3199 * queuename for conflicting names.
3200 */
3201 unsigned i;
3202 char **papszNewNames = (char**)calloc(sizeof(char*), cQueues);
3203 for (i = 0; i < cQueues; i++)
3204 {
3205 char *psz = paQueues[i].pszComment;
3206 for (unsigned j = 0; j < cQueues; j++)
3207 if (j != i && !stricmp(paQueues[j].pszComment, psz))
3208 {
3209 dprintf(("duplicate printer names '%s'. appending queue name", psz));
3210 papszNewNames[i] = (char*)malloc(strlen(psz) + strlen(paQueues[i].pszName) + 4);
3211 sprintf(papszNewNames[i], "%s (%s)", psz, paQueues[i].pszName);
3212 paQueues[i].pszComment = papszNewNames[i];
3213
3214 papszNewNames[j] = (char*)malloc(strlen(psz) + strlen(paQueues[j].pszName) + 4);
3215 sprintf(papszNewNames[j], "%s (%s)", psz, paQueues[j].pszName);
3216 paQueues[j].pszComment = papszNewNames[j];
3217 }
3218 }
3219
3220 /*
3221 * Add the printers.
3222 */
3223 PRINTER_INFO_2A *papi2 = (PRINTER_INFO_2A *)calloc(cQueues, sizeof(PRINTER_INFO_2A));
3224 dprintf(("cQueues=%d cDevices=%d", cQueues, cDevices));
3225 for (i = 0; i < cQueues; i++)
3226 {
3227 /* Make printer driver. */
3228 DRIVER_INFO_3A di3 = {0};
3229 di3.cVersion = 0x400;
3230 #ifdef USE_OS2_DRIVERNAME
3231 char *pszDot = strchr(paQueues[i].pszDriverName, '.');
3232 if (pszDot && pszDot != paQueues[i].pszDriverName) /* we're very careful :-) */
3233 { /* split the driver name, getting something very similar to window.s */
3234 *pszDot++ = '\0';
3235 di3.pName = pszDot;
3236 di3.pDriverPath = paQueues[i].pszDriverName; /* This is important! */
3237 }
3238 else
3239 { /* bad printer driver name? try cover up. */
3240 di3.pName = paQueues[i].pszDriverName;
3241 di3.pDriverPath = "WINSPOOL"; /* This is important! */
3242 }
3243 #else
3244 di3.pName = paQueues[i].pszName; /* printer driver == queue name */
3245 di3.pDriverPath = "WINSPOOL"; /* This is important! */
3246 #endif
3247 di3.pEnvironment = NULL; /* NULL means auto */
3248 di3.pDataFile = "<datafile?>";
3249 di3.pConfigFile = "winodin.drv";
3250 di3.pHelpFile = "<helpfile?>";
3251 di3.pDependentFiles = "<dependend files?>";
3252 di3.pMonitorName = "<monitor name?>";
3253 di3.pDefaultDataType = "RAW";
3254 if (!AddPrinterDriverA(NULL, 3, (LPBYTE)&di3))
3255 {
3256 DebugAssertFailed(("Failed adding Driver (%ld)\n", GetLastError()));
3257 fRc = FALSE;
3258 }
3259
3260 /* Make printer. */
3261 papi2[i].pDatatype = "RAW";
3262 papi2[i].pPrintProcessor = "WinPrint";
3263 #ifdef USE_OS2_DRIVERNAME
3264 papi2[i].pComment = paQueues[i].pszName; /* Queue name. Don't allow any changes of the comment! */
3265 #else
3266 papi2[i].pComment = paQueues[i].pszComment; /* WPS printer name */
3267 #endif
3268 papi2[i].pDriverName = di3.pName;
3269 papi2[i].pParameters = "<parameters?>";
3270 papi2[i].pShareName = "<share name?>";
3271 papi2[i].pSepFile = "<sep file?>";
3272 #if 0 /* only 'local', remember */
3273 if (paPrinters[i].pszComputerName) /* this is currnetly not used as we only enum locals. */
3274 {
3275 papi2[i].Attributes |= PRINTER_ATTRIBUTE_NETWORK;
3276 papi2[i].pServerName = paPrinters[i].pszComputerName; /** @todo: format!! */
3277 }
3278 #endif
3279
3280 /*
3281 * We need to make sure the name is valid.
3282 * The registry decides what's illegal, slashes evedently are.
3283 */
3284 papi2[i].pPrinterName = paQueues[i].pszComment;
3285 char *psz = papi2[i].pPrinterName;
3286 while ((psz = strpbrk(psz, "/\\")) != NULL)
3287 *psz = '|'; /* change slashes to pipes... */
3288
3289
3290 /*
3291 * The queue pszPrinters member links with pszPrinterName of the device.
3292 * pszPrinters can contain several printer (device) names, separated by commas.
3293 * - We only handle the first printer listed. No idea how to get more than one
3294 * the anyway.
3295 */
3296 papi2[i].pLocation = "";
3297 papi2[i].pPortName = "";
3298 psz = strchr(paQueues[i].pszPrinters, ',');
3299 if (psz)
3300 *psz = '\0';
3301 for (unsigned k = 0; k < cDevices; k++)
3302 {
3303 if (!stricmp(paDevices[k].pszPrinterName, paQueues[i].pszPrinters))
3304 {
3305 papi2[i].pLocation = paDevices[k].pszLogAddr;
3306 papi2[i].pPortName = paDevices[k].pszLogAddr;
3307 break;
3308 }
3309 }
3310
3311 /*
3312 * Check if default printer and set attribute and write to profile.
3313 */
3314 if (paQueues[i].fsType & OSLIB_PRQ3_TYPE_APPDEFAULT)
3315 {
3316 char szWinDefPrn[256];
3317 dprintf(("Default printer %s,%s,%s", papi2[i].pPrinterName, papi2[i].pDriverName, papi2[i].pPortName));
3318 sprintf(szWinDefPrn, "%s,%s,%s", papi2[i].pPrinterName, papi2[i].pDriverName, papi2[i].pPortName);
3319 WriteProfileStringA("windows", "device", szWinDefPrn);
3320 papi2[i].Attributes |= PRINTER_ATTRIBUTE_DEFAULT;
3321 }
3322
3323 /*
3324 * Finally, we can add the printer
3325 */
3326 dprintf(("Add printer %s,%s,%s", papi2[i].pPrinterName, papi2[i].pDriverName, papi2[i].pPortName));
3327 if (!AddPrinterA(NULL, 2, (LPBYTE)&papi2[i]))
3328 {
3329 DebugAssert(GetLastError() == ERROR_PRINTER_ALREADY_EXISTS,
3330 ("AddPrinterA(%s) failed with rc=%ld\n", papi2[i].pPrinterName, GetLastError()));
3331 fRc = FALSE;
3332 }
3333 } /* loop thru printers */
3334
3335
3336 /*
3337 * Purge dead printers.
3338 * (It's important that we don't bail out before this when there is zero printers/devices!)
3339 */
3340 PPRINTER_INFO_2A pi2;
3341 DWORD cOdinPrinters = 0;
3342 cbNeeded = 0;
3343 if ( EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &cbNeeded, &cOdinPrinters)
3344 || GetLastError() == ERROR_INSUFFICIENT_BUFFER)
3345 {
3346 pi2 = (PPRINTER_INFO_2A)malloc(cbNeeded);
3347 if (EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pi2, cbNeeded, &cbNeeded, &cOdinPrinters))
3348 {
3349 for (i = 0; i < cOdinPrinters; i++)
3350 {
3351 /* look if we added it */
3352 BOOL fFound = FALSE;
3353 for (unsigned j = 0; j < cQueues && !fFound; j++)
3354 fFound = !strcmp(papi2[j].pPrinterName,pi2[i].pPrinterName)
3355 && !strcmp(papi2[j].pDriverName, pi2[i].pDriverName)
3356 && !strcmp(papi2[j].pPortName, pi2[i].pPortName);
3357 /* nuke it */
3358 if (!fFound)
3359 {
3360 HANDLE hPrinter;
3361 if (OpenPrinterA(pi2[i].pPrinterName, &hPrinter, NULL) == TRUE)
3362 {
3363 dprintf(("Delete printer %s,%s,%s", papi2[i].pPrinterName, papi2[i].pDriverName, papi2[i].pPortName));
3364 DeletePrinter(hPrinter);
3365 ClosePrinter(hPrinter);
3366 }
3367 else
3368 {
3369 DebugAssertFailed(("Failed to open a printer returned by EnumPrintersA, %s\n",
3370 pi2[i].pPrinterName));
3371 fRc = FALSE;
3372 }
3373 }
3374 }
3375 }
3376 else
3377 {
3378 DebugAssertFailed(("EnumPrintersA failed!\n"));
3379 fRc = FALSE;
3380 }
3381 free(pi2);
3382 }
3383 else
3384 {
3385 DebugAssertFailed(("EnumPrintersA failed!\n"));
3386 fRc = FALSE;
3387 }
3388 free(papi2);
3389 free(paDevices);
3390 for (i = 0; i < cQueues; i++)
3391 if (papszNewNames[i])
3392 free(papszNewNames[i]);
3393 }
3394 else
3395 dprintf(("OSLibSplEnumDevice -> %d, cDevices=%d", fRc, cDevices));
3396 }
3397 else
3398 dprintf(("OSLibSplEnumPrinter failed\n"));
3399
3400 free(paQueues);
3401 dprintf(("ExportPrintersToRegistry returns %s", fRc ? "success" : "failure"));
3402 return fRc;
3403}
3404
3405#endif /* __WIN32OS2__ */
Note: See TracBrowser for help on using the repository browser.