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

Last change on this file since 21629 was 21629, checked in by dmik, 14 years ago

Spacing.

File size: 112.9 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 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2489 TRUE);
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 return WINSPOOL_GetPrinterDriver(hPrinter, pEnvironment, Level, pDriverInfo,
2558 cbBuf, pcbNeeded, TRUE);
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 * Name : BOOL GetPrinterDriverDirectoryW
2621 * Purpose :
2622 * Parameters: LPWSTR pName address of server name
2623 * LPWSTR pEnvironment address of environment
2624 * DWORD Level address of structure
2625 * LPBYTE pDriverDirectory address of structure array that receives path
2626 * DWORD cbBuf size, in bytes, of array
2627 * LPDWORD pcbNeeded address of variable with number of bytes retrieved (or required)
2628 * Variables :
2629 * Result :
2630 * Remark :
2631 * Status : UNTESTED STUB
2632 *
2633 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
2634 *
2635 * Author : Markus Montkowski [09.07.98 14:47:16]
2636 *****************************************************************************/
2637
2638BOOL WIN32API GetPrinterDriverDirectoryW(
2639 LPWSTR pName,
2640 LPWSTR pEnvironment,
2641 DWORD Level,
2642 LPBYTE pDriverDirectory,
2643 DWORD cbBuf,
2644 LPDWORD pcbNeeded)
2645{
2646 DWORD needed;
2647
2648 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", debugstr_w(pName), pEnvironment, Level,
2649 pDriverDirectory, cbBuf, pcbNeeded);
2650 if(pName != NULL) {
2651 FIXME("pName = `%s' - unsupported\n", debugstr_w(pName));
2652 SetLastError(ERROR_INVALID_PARAMETER);
2653 return FALSE;
2654 }
2655 if(pEnvironment != NULL) {
2656 FIXME("pEnvironment = `%s' - unsupported\n", debugstr_w(pEnvironment));
2657 SetLastError(ERROR_INVALID_ENVIRONMENT);
2658 return FALSE;
2659 }
2660 if(Level != 1) /* win95 ignores this so we just carry on */
2661 WARN("Level = %ld - assuming 1\n", Level);
2662
2663 /* FIXME should read from registry */
2664 needed = GetSystemDirectoryW((LPWSTR)pDriverDirectory, cbBuf);
2665 needed++;
2666 if(pcbNeeded)
2667 *pcbNeeded = needed;
2668 if(needed > cbBuf) {
2669 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2670 return FALSE;
2671 }
2672 return TRUE;
2673}
2674
2675#ifndef __WIN32OS2__
2676/******************************************************************
2677 * WINSPOOL_GetOpenedPrinterEntry
2678 * Get the first place empty in the opened printer table
2679 */
2680static HANDLE WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name )
2681{
2682 int i;
2683
2684 for (i = 0; i < nb_printers; i++) if (!printer_array[i]) break;
2685
2686 if (i >= nb_printers)
2687 {
2688 LPWSTR *new_array = (LPWSTR*)HeapReAlloc( GetProcessHeap(), 0, printer_array,
2689 (nb_printers + 16) * sizeof(*new_array) );
2690 if (!new_array) return 0;
2691 printer_array = new_array;
2692 nb_printers += 16;
2693 }
2694
2695 if ((printer_array[i] = (WCHAR*)HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )) != NULL)
2696 {
2697 strcpyW( printer_array[i], name );
2698 return (HANDLE)(i + 1);
2699 }
2700 return 0;
2701}
2702#endif
2703
2704/**
2705 * Opens a printer.
2706 *
2707 * @returns Success indicator, last error set on failure.
2708 * @param lpPrinterName Pointer to printer name.
2709 * @param phPrinter Where to store the handle to the opned printer instance.
2710 * @param pDefault Printer defaults. (Current ignored)
2711 * @status partially implemented.
2712 * @author ???
2713 * @author knut st. osmundsen <bird-srcspam@anduin.net>
2714 */
2715BOOL WIN32API OpenPrinterW(LPWSTR lpPrinterName, HANDLE *phPrinter, PRINTER_DEFAULTSW *pDefault)
2716{
2717 HKEY hkeyPrinters, hkeyPrinter;
2718
2719 /*
2720 * Validate input.
2721 */
2722 if (!lpPrinterName)
2723 {
2724 dprintf(("WINSPOOL: OpenPrinterW: printerName=NULL pDefault=%p returning false!\n", pDefault));
2725 SetLastError(ERROR_INVALID_PARAMETER);
2726 return FALSE;
2727 }
2728 dprintf(("WINSPOOL: OpenPrinterW: printerName='%ls' pDefault=%p\n", lpPrinterName, pDefault));
2729
2730 /*
2731 * Check if the Printer exists.
2732 */
2733 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) != ERROR_SUCCESS)
2734 {
2735 dprintf(("Can't create Printers key\n"));
2736 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
2737 return FALSE;
2738 }
2739
2740 if ( lpPrinterName[0] == '\0' /* explicitly fail on "" */
2741 || RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter) != ERROR_SUCCESS)
2742 {
2743 dprintf(("Can't find printer '%ls' in registry\n", lpPrinterName));
2744 RegCloseKey(hkeyPrinters);
2745 SetLastError(ERROR_INVALID_PRINTER_NAME);
2746 return FALSE;
2747 }
2748 RegCloseKey(hkeyPrinter);
2749 RegCloseKey(hkeyPrinters);
2750
2751 /*
2752 * Seems like win95 doesn't care if there is no where to store
2753 * the handle. We'll do the same.
2754 */
2755 if (!phPrinter) /* This seems to be what win95 does anyway */
2756 {
2757 dprintf(("WINSPOOL: OpenPrinterW: phPrinter is NULL, returning succesfully anyhow\n"));
2758 return TRUE;
2759 }
2760
2761 /*
2762 * Create a handle for this open instance.
2763 */
2764 *phPrinter = NULL; /* crash here */
2765#ifdef __WIN32OS2__
2766 POPENPRINTER p = openprinterNew(lpPrinterName);
2767 if (!p)
2768 {
2769 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2770 dprintf(("WINSPOOL: OpenPrinterW: out of memory allocating handle\n"));
2771 return FALSE;
2772 }
2773 *phPrinter = p->hOpenPrinter;
2774#else
2775 *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
2776#endif
2777
2778 if (pDefault != NULL)
2779 dprintf(("Not handling pDefault\n"));
2780
2781 dprintf(("WINSPOOL: OpenPrinterW: returning successfully *phPrinter=%d\n", *phPrinter));
2782 return TRUE;
2783}
2784
2785
2786
2787
2788/*********************************************************************
2789 * DocumentPropertiesW (WINSPOOL.166)
2790 */
2791LONG WIN32API DocumentPropertiesW(
2792 HWND hWnd,
2793 HANDLE hPrinter,
2794 LPWSTR pDeviceName,
2795 PDEVMODEW pDevModeOutput,
2796 PDEVMODEW pDevModeInput,
2797 DWORD fMode)
2798{
2799 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
2800 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
2801 LPDEVMODEA pDevModeOutputA = NULL;
2802 LONG ret;
2803
2804 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
2805 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2806 fMode);
2807 if(pDevModeOutput) {
2808 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2809 if(ret < 0) return ret;
2810 pDevModeOutputA = (LPDEVMODEA)HeapAlloc(GetProcessHeap(), 0, ret);
2811 }
2812 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2813 pDevModeInputA, fMode);
2814 if(ret < 0) return ret;
2815
2816 if(pDevModeOutput) {
2817 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2818 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2819 }
2820 if(fMode == 0 && ret > 0)
2821 ret += (CCHDEVICENAME + CCHFORMNAME);
2822 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2823 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2824 return ret;
2825}
2826
2827
2828
2829#ifdef __WIN32OS2__
2830
2831/**
2832 * Start a new printer job.
2833 *
2834 * @returns Print job identifier.
2835 * @returns 0 on failure with last error set.
2836 * @param hPrinter Handle to the printer object.
2837 * @param Level Structure level.
2838 * @param pDocInfo Pointer to structure.
2839 * @status partially implemented.
2840 * @author knut st. osmundsen <bird-srcspam@anduin.net>
2841 */
2842DWORD WIN32API StartDocPrinterA(
2843 HANDLE hPrinter,
2844 DWORD Level,
2845 LPBYTE pDocInfo)
2846{
2847 DWORD rc = 0;
2848 dprintf(("WINSPOOL: StartDocPrinterA\n"));
2849
2850 /*
2851 * Get printer instance data.
2852 */
2853 POPENPRINTER pPrt = openprinterFind(hPrinter);
2854 if (!pPrt)
2855 {
2856 dprintf(("WINSPOOL: StartDocPrinterA: Invalid handle %d\n", hPrinter));
2857 SetLastError(ERROR_INVALID_HANDLE);
2858 return 0;
2859 }
2860
2861 /*
2862 * Switch out based on input data.
2863 */
2864 switch (Level)
2865 {
2866 case 1:
2867 {
2868 PDOC_INFO_1A pDocInfoA = (PDOC_INFO_1A)pDocInfo;
2869 dprintf(("WINSPOOL: pDocName =%s\n", pDocInfoA->pDocName));
2870 dprintf(("WINSPOOL: pDatatype =%s\n", pDocInfoA->pDatatype));
2871 dprintf(("WINSPOOL: pOutputFile=%s\n", pDocInfoA->pOutputFile));
2872
2873 /*
2874 * Validate input.
2875 * ASSUMES: default is RAW as it is on OS/2.
2876 */
2877 if ( pDocInfoA->pDatatype
2878 && !strstr(pDocInfoA->pDatatype, "RAW"))
2879 {
2880 SetLastError(ERROR_INVALID_PARAMETER);
2881 dprintf(("WINSPOOL: data type not supported\n"));
2882 break;
2883 }
2884
2885 /*
2886 * Make sure the OS/2 spool file is opened.
2887 */
2888 int rcOs2 = openprinterOpenSpoolFile(pPrt);
2889 if (!rcOs2)
2890 {
2891 /*
2892 * Start the document.
2893 */
2894 if (OSLibSplQmStartDoc(pPrt->hspl, pDocInfoA->pDocName))
2895 {
2896 rc = (DWORD)pPrt->hspl; /** @todo get the proper job id! */
2897 pPrt->ulCurPage = 0; //reset current page counter
2898 dprintf(("WINSPOOL: StartDocPrinterA: returning jobid %d\n", rc));
2899 return rc;
2900 }
2901 else
2902 SetLastError(OSLibSplWinGetLastError()); /** @todo convert error code!!!!!!!! */
2903 }
2904 else
2905 SetLastError(rcOs2); /** @todo convert error code!!!!!!!! */
2906 break;
2907 }
2908
2909 default:
2910 dprintf(("WINSPOOL: level %d is not supported\n", Level));
2911 SetLastError(ERROR_INVALID_LEVEL); /* not verified. */
2912 break;
2913 }
2914 dprintf(("WINSPOOL: returning failure\n"));
2915 return 0;
2916}
2917
2918
2919/**
2920 * Start a new printer job.
2921 *
2922 * @returns Print job identifier.
2923 * @returns 0 on failure with last error set.
2924 * @param hPrinter Handle to the printer object.
2925 * @param Level Structure level.
2926 * @param pDocInfo Pointer to structure.
2927 * @status partially implemented.
2928 * @author knut st. osmundsen <bird-srcspam@anduin.net>
2929 */
2930DWORD WIN32API StartDocPrinterW(
2931 HANDLE hPrinter,
2932 DWORD Level,
2933 LPBYTE pDocInfo)
2934{
2935 DWORD rc = 0;
2936 dprintf(("WINSPOOL: StartDocPrinterW\n"));
2937 switch (Level)
2938 {
2939 case 1:
2940 {
2941 PDOC_INFO_1W pDocInfoW = (PDOC_INFO_1W)pDocInfo;
2942
2943 DOC_INFO_1A DocInfoA;
2944 DocInfoA.pDocName = UnicodeToAsciiString(pDocInfoW->pDocName);
2945 DocInfoA.pDatatype = UnicodeToAsciiString(pDocInfoW->pDatatype);
2946 DocInfoA.pOutputFile = UnicodeToAsciiString(pDocInfoW->pOutputFile);
2947 rc = StartDocPrinterA(hPrinter, Level, (LPBYTE)&DocInfoA);
2948 FreeAsciiString(DocInfoA.pOutputFile);
2949 FreeAsciiString(DocInfoA.pDatatype);
2950 FreeAsciiString(DocInfoA.pDocName);
2951 break;
2952 }
2953
2954 default:
2955 dprintf(("WINSPOOL: level %d is not supported\n", Level));
2956 SetLastError(ERROR_INVALID_LEVEL); /* not verified. */
2957 break;
2958 }
2959 dprintf(("WINSPOOL: returns %d\n", rc));
2960 return rc;
2961}
2962
2963
2964/**
2965 * Notifies the spooler that a new page is to be written to the
2966 * current printer job.
2967 *
2968 * This is an informational API without much significance I think.
2969 * The implementation assumes StartDocPrinterA/W() must be called first.
2970 *
2971 * @returns Success indicator. last error set on failure.
2972 * @param hPrinter Handle to printer object.
2973 * @status completely implemented.
2974 * @author knut st. osmundsen <bird-srcspam@anduin.net>
2975 */
2976BOOL WIN32API StartPagePrinter(HANDLE hPrinter)
2977{
2978 dprintf(("WINSPOOL: StartPagePrinter: hPrinter=%d\n", hPrinter));
2979 /*
2980 * Get printer instance data.
2981 */
2982 POPENPRINTER pPrt = openprinterFind(hPrinter);
2983 if (!pPrt)
2984 {
2985 dprintf(("WINSPOOL: StartPagePrinter: Invalid handle %d\n", hPrinter));
2986 SetLastError(ERROR_INVALID_HANDLE);
2987 return FALSE;
2988 }
2989
2990 /*
2991 * Not quite sure what should happen here if no StartDocPrinter was issued.
2992 * For now we'll just freak out.
2993 */
2994 if (!pPrt->hspl)
2995 {
2996 DebugAssertFailed(("StartPagePrinter called with no StartDocPrinter issued\n"));
2997 SetLastError(ERROR_INVALID_PRINTER_STATE); /** @todo test on w2k */
2998 return FALSE;
2999 }
3000
3001 if (OSLibSplQmNewPage(pPrt->hspl, pPrt->ulCurPage + 1))
3002 {
3003 pPrt->ulCurPage++;
3004 dprintf(("WINSPOOL: StartPagePrinter: returning successfully (ulCurPage=%lu)\n", pPrt->ulCurPage));
3005 return TRUE;
3006 }
3007
3008 /* failure */
3009 SetLastError(OSLibSplWinGetLastError()); /** @todo convert error code!!! */
3010 dprintf(("WINSPOOL: StartPagePrinter failed. last err=%#x\n", OSLibSplWinGetLastError()));
3011 return FALSE;
3012}
3013
3014
3015/**
3016 * Write raw data to printer.
3017 * @returns Successindicator. lasterr set on failure.
3018 * @param hPrinter Handle to printer object.
3019 * @param pBuf Pointer to the data to write.
3020 * @param cbBuf Size of the data to write.
3021 * @param pcWritten Where to put the number of bytes actually written.
3022 * @status partially implemented.
3023 * @author knut st. osmundsen <bird-srcspam@anduin.net>
3024 * @remark Current implementation relies on StartDocPrinterA/W being called first.
3025 */
3026BOOL WIN32API WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
3027{
3028 BOOL fRc = FALSE;
3029 dprintf(("WINSPOOL: WritePrinter hPrinter=%#x pBuf=%p cbBuf=%d pcWritten=%p\n",
3030 hPrinter, pBuf, cbBuf, pcWritten));
3031
3032 /*
3033 * Get printer instance data.
3034 */
3035 POPENPRINTER pPrt = openprinterFind(hPrinter);
3036 if (!pPrt)
3037 {
3038 dprintf(("WINSPOOL: WritePrinter: Invalid handle %d\n", hPrinter));
3039 SetLastError(ERROR_INVALID_HANDLE);
3040 return FALSE;
3041 }
3042
3043 /*
3044 * Not quite sure what should happen here if no StartDocPrinter was issued.
3045 * For now we'll just freak out.
3046 */
3047 if (!pPrt->hspl)
3048 {
3049 DebugAssertFailed(("WritePrinter called with no StartDocPrinter issued\n"));
3050 SetLastError(ERROR_INVALID_PRINTER_STATE); /** @todo test on w2k */
3051 return FALSE;
3052 }
3053
3054 /*
3055 * Push the data thru to the spooler.
3056 */
3057 if (OSLibSplQmWrite(pPrt->hspl, cbBuf, pBuf))
3058 {
3059 if (pcWritten)
3060 *pcWritten = cbBuf;
3061 dprintf(("WINSPOOL: WritePrinter succceeded writing %d bytes\n", cbBuf));
3062 return TRUE;
3063 }
3064
3065 /* failure */
3066 SetLastError(OSLibSplWinGetLastError()); /** @todo convert error code!!! */
3067 dprintf(("WINSPOOL: WritePrinter failed. last err=%#x\n", OSLibSplWinGetLastError()));
3068 return FALSE;
3069}
3070
3071
3072/**
3073 * Notifies the spooler that the writing of a page to the current
3074 * printer job is completed.
3075 *
3076 * This is an informational API without much significance I think.
3077 * The implementation assumes StartDocPrinterA/W() must be called first.
3078 *
3079 * @returns Success indicator, last error set on failure.
3080 * @param hPrinter Handle to printer object which job is to be ended (completed.
3081 * @status partially implemented
3082 * @author knut st. osmundsen <bird-srcspam@anduin.net>
3083 * @remark Current implementation relies on StartDocPrinterA/W being called first.
3084 */
3085BOOL WIN32API EndPagePrinter(HANDLE hPrinter)
3086{
3087 dprintf(("WINSPOOL: EndPagePrinter: hPrinter=%d\n", hPrinter));
3088
3089 /*
3090 * Get printer instance data.
3091 */
3092 POPENPRINTER pPrt = openprinterFind(hPrinter);
3093 if (!pPrt)
3094 {
3095 dprintf(("WINSPOOL: EndPagePrinter: Invalid handle %d\n", hPrinter));
3096 SetLastError(ERROR_INVALID_HANDLE);
3097 return FALSE;
3098 }
3099
3100 /*
3101 * Not quite sure what should happen here if no StartDocPrinter was issued.
3102 * For now we'll just freak out.
3103 */
3104 if (!pPrt->hspl)
3105 {
3106 DebugAssertFailed(("EndPagePrinter called with no StartDocPrinter issued\n"));
3107 SetLastError(ERROR_INVALID_PRINTER_STATE); /** @todo test on w2k */
3108 return FALSE;
3109 }
3110
3111 /* There is no OS/2 equivalent. */
3112 dprintf(("WINSPOOL: EndPagePrinter: returning successfully (ulCurPage=%lu)\n", pPrt->ulCurPage));
3113 return TRUE;
3114}
3115
3116
3117/**
3118 * Ends a printer job.
3119 *
3120 * @returns Success indicator, last error set on failure.
3121 * @param hPrinter Handle to printer object which job is to be ended (completed.
3122 * @status partially implemented
3123 * @author knut st. osmundsen <bird-srcspam@anduin.net>
3124 * @remark Current implementation relies on StartDocPrinterA/W being called first.
3125 */
3126BOOL WIN32API EndDocPrinter(HANDLE hPrinter)
3127{
3128 BOOL fRc = FALSE;
3129 dprintf(("WINSPOOL: WritePrinter hPrinter=%#x\n", hPrinter));
3130
3131 /*
3132 * Get printer instance data.
3133 */
3134 POPENPRINTER pPrt = openprinterFind(hPrinter);
3135 if (!pPrt)
3136 {
3137 dprintf(("WINSPOOL: WritePrinter: Invalid handle %d\n", hPrinter));
3138 SetLastError(ERROR_INVALID_HANDLE);
3139 return FALSE;
3140 }
3141
3142 /*
3143 * Not quite sure what should happen here if no StartDocPrinter was issued.
3144 * For now we'll just freak out.
3145 */
3146 if (!pPrt->hspl)
3147 {
3148 DebugAssertFailed(("EndDocPrinter called with no StartDocPrinter issued\n"));
3149 SetLastError(ERROR_INVALID_PRINTER_STATE); /** @todo test on w2k */
3150 return FALSE;
3151 }
3152
3153 /*
3154 * End the document, thus closing all Spl related stuff.
3155 */
3156 if (OSLibSplQmEndDoc(pPrt->hspl))
3157 {
3158 dprintf(("WINSPOOL: EndDocPrinter returns successfully\n"));
3159 return TRUE;
3160 }
3161
3162 SetLastError(OSLibSplWinGetLastError()); /** @todo convert error code!!! */
3163 dprintf(("WINSPOOL: EndDocPrinter returns failure\n"));
3164 return FALSE;
3165}
3166
3167
3168
3169/**
3170 * Setup the OS/2 Printer Information in the registry and profile.
3171 *
3172 * We will only enumerate local printer queues.
3173 *
3174 * The mapping between Odin32 and OS/2 is as follows:
3175 * Odin32 OS/2
3176 * Printer Name Queue Comment (WPS object title)
3177 * Driver Name Queue Name
3178 * Printer Comment Queue Comment (= WPS object title)
3179 * Printer Location Device Logical address (port sort of)
3180 * Printer Port Device Logical address (port sort of)
3181 *
3182 * On OS/2 only queue names are unique. It's very easy to make duplicate
3183 * printer names, just create printer objects in more than one WPS folder.
3184 * For duplicate names the queue name will be appended to the name in
3185 * paratheses so the user can actually print to both printers. (Odin32
3186 * only have a concept of printer names and they must thus be unique.)
3187 *
3188 * @returns Success indicator. May possibly have changed the last error on
3189 * both failure and success.
3190 *
3191 * @remark We're only enumerating local printers. This makes sense as remote
3192 * printers (on Lan Servers/Managers) isn't normally stored in the
3193 * registry (IIRC).
3194 */
3195BOOL ExportPrintersToRegistry(void)
3196{
3197 BOOL fRc = FALSE;
3198 DWORD cbNeeded;
3199 DWORD cUnused;
3200
3201 dprintf(("WINSPOOL: ExportPrintersToRegistry"));
3202
3203 /*
3204 * Get printers.
3205 */
3206 ULONG cQueues = 0;
3207 POSLIB_PRQINFO3 paQueues;
3208 paQueues = (POSLIB_PRQINFO3)OSLibSplEnumQueue(NULL, 3, &cQueues, &cUnused);
3209 if (paQueues)
3210 {
3211 /*
3212 * Get printer devices.
3213 */
3214 ULONG cDevices;
3215 POSLIB_PRDINFO3 paDevices;
3216 paDevices = (POSLIB_PRDINFO3)OSLibSplEnumDevice(NULL, 3, &cDevices, &cUnused);
3217 if (paDevices)
3218 {
3219 fRc = TRUE; /* getting this far is pretty much a success I'd say.... */
3220
3221 /*
3222 * Make printer WPS names (queue comment) unique by appending the
3223 * queuename for conflicting names.
3224 */
3225 unsigned i;
3226 char **papszNewNames = (char**)calloc(sizeof(char*), cQueues);
3227 for (i = 0; i < cQueues; i++)
3228 {
3229 char *psz = paQueues[i].pszComment;
3230 for (unsigned j = 0; j < cQueues; j++)
3231 if (j != i && !stricmp(paQueues[j].pszComment, psz))
3232 {
3233 dprintf(("duplicate printer names '%s'. appending queue name", psz));
3234 papszNewNames[i] = (char*)malloc(strlen(psz) + strlen(paQueues[i].pszName) + 4);
3235 sprintf(papszNewNames[i], "%s (%s)", psz, paQueues[i].pszName);
3236 paQueues[i].pszComment = papszNewNames[i];
3237
3238 papszNewNames[j] = (char*)malloc(strlen(psz) + strlen(paQueues[j].pszName) + 4);
3239 sprintf(papszNewNames[j], "%s (%s)", psz, paQueues[j].pszName);
3240 paQueues[j].pszComment = papszNewNames[j];
3241 }
3242 }
3243
3244 /*
3245 * Add the printers.
3246 */
3247 PRINTER_INFO_2A *papi2 = (PRINTER_INFO_2A *)calloc(cQueues, sizeof(PRINTER_INFO_2A));
3248 dprintf(("cQueues=%d cDevices=%d", cQueues, cDevices));
3249 for (i = 0; i < cQueues; i++)
3250 {
3251 /* Make printer driver. */
3252 DRIVER_INFO_3A di3 = {0};
3253 di3.cVersion = 0x400;
3254#ifdef USE_OS2_DRIVERNAME
3255 char *pszDot = strchr(paQueues[i].pszDriverName, '.');
3256 if (pszDot && pszDot != paQueues[i].pszDriverName) /* we're very careful :-) */
3257 { /* split the driver name, getting something very similar to window.s */
3258 *pszDot++ = '\0';
3259 di3.pName = pszDot;
3260 di3.pDriverPath = paQueues[i].pszDriverName; /* This is important! */
3261 }
3262 else
3263 { /* bad printer driver name? try cover up. */
3264 di3.pName = paQueues[i].pszDriverName;
3265 di3.pDriverPath = "WINSPOOL"; /* This is important! */
3266 }
3267#else
3268 di3.pName = paQueues[i].pszName; /* printer driver == queue name */
3269 di3.pDriverPath = "WINSPOOL"; /* This is important! */
3270#endif
3271 di3.pEnvironment = NULL; /* NULL means auto */
3272 di3.pDataFile = "<datafile?>";
3273 di3.pConfigFile = "winodin.drv";
3274 di3.pHelpFile = "<helpfile?>";
3275 di3.pDependentFiles = "<dependend files?>";
3276 di3.pMonitorName = "<monitor name?>";
3277 di3.pDefaultDataType = "RAW";
3278 if (!AddPrinterDriverA(NULL, 3, (LPBYTE)&di3))
3279 {
3280 DebugAssertFailed(("Failed adding Driver (%ld)\n", GetLastError()));
3281 fRc = FALSE;
3282 }
3283
3284 /* Make printer. */
3285 papi2[i].pDatatype = "RAW";
3286 papi2[i].pPrintProcessor = "WinPrint";
3287#ifdef USE_OS2_DRIVERNAME
3288 papi2[i].pComment = paQueues[i].pszName; /* Queue name. Don't allow any changes of the comment! */
3289#else
3290 papi2[i].pComment = paQueues[i].pszComment; /* WPS printer name */
3291#endif
3292 papi2[i].pDriverName = di3.pName;
3293 papi2[i].pParameters = "<parameters?>";
3294 papi2[i].pShareName = "<share name?>";
3295 papi2[i].pSepFile = "<sep file?>";
3296#if 0 /* only 'local', remember */
3297 if (paPrinters[i].pszComputerName) /* this is currnetly not used as we only enum locals. */
3298 {
3299 papi2[i].Attributes |= PRINTER_ATTRIBUTE_NETWORK;
3300 papi2[i].pServerName = paPrinters[i].pszComputerName; /** @todo: format!! */
3301 }
3302#endif
3303
3304 /*
3305 * We need to make sure the name is valid.
3306 * The registry decides what's illegal, slashes evedently are.
3307 */
3308 papi2[i].pPrinterName = paQueues[i].pszComment;
3309 char *psz = papi2[i].pPrinterName;
3310 while ((psz = strpbrk(psz, "/\\")) != NULL)
3311 *psz = '|'; /* change slashes to pipes... */
3312
3313
3314 /*
3315 * The queue pszPrinters member links with pszPrinterName of the device.
3316 * pszPrinters can contain several printer (device) names, separated by commas.
3317 * - We only handle the first printer listed. No idea how to get more than one
3318 * the anyway.
3319 */
3320 papi2[i].pLocation = "";
3321 papi2[i].pPortName = "";
3322 psz = strchr(paQueues[i].pszPrinters, ',');
3323 if (psz)
3324 *psz = '\0';
3325 for (unsigned k = 0; k < cDevices; k++)
3326 {
3327 if (!stricmp(paDevices[k].pszPrinterName, paQueues[i].pszPrinters))
3328 {
3329 papi2[i].pLocation = paDevices[k].pszLogAddr;
3330 papi2[i].pPortName = paDevices[k].pszLogAddr;
3331 break;
3332 }
3333 }
3334
3335 /*
3336 * Check if default printer and set attribute and write to profile.
3337 */
3338 if (paQueues[i].fsType & OSLIB_PRQ3_TYPE_APPDEFAULT)
3339 {
3340 char szWinDefPrn[256];
3341 dprintf(("Default printer %s,%s,%s", papi2[i].pPrinterName, papi2[i].pDriverName, papi2[i].pPortName));
3342 sprintf(szWinDefPrn, "%s,%s,%s", papi2[i].pPrinterName, papi2[i].pDriverName, papi2[i].pPortName);
3343 WriteProfileStringA("windows", "device", szWinDefPrn);
3344 papi2[i].Attributes |= PRINTER_ATTRIBUTE_DEFAULT;
3345 }
3346
3347 /*
3348 * Finally, we can add the printer
3349 */
3350 dprintf(("Add printer %s,%s,%s", papi2[i].pPrinterName, papi2[i].pDriverName, papi2[i].pPortName));
3351 if (!AddPrinterA(NULL, 2, (LPBYTE)&papi2[i]))
3352 {
3353 DebugAssert(GetLastError() == ERROR_PRINTER_ALREADY_EXISTS,
3354 ("AddPrinterA(%s) failed with rc=%ld\n", papi2[i].pPrinterName, GetLastError()));
3355 fRc = FALSE;
3356 }
3357 } /* loop thru printers */
3358
3359
3360 /*
3361 * Purge dead printers.
3362 * (It's important that we don't bail out before this when there is zero printers/devices!)
3363 */
3364 PPRINTER_INFO_2A pi2;
3365 DWORD cOdinPrinters = 0;
3366 cbNeeded = 0;
3367 if ( EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &cbNeeded, &cOdinPrinters)
3368 || GetLastError() == ERROR_INSUFFICIENT_BUFFER)
3369 {
3370 pi2 = (PPRINTER_INFO_2A)malloc(cbNeeded);
3371 if (EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pi2, cbNeeded, &cbNeeded, &cOdinPrinters))
3372 {
3373 for (i = 0; i < cOdinPrinters; i++)
3374 {
3375 /* look if we added it */
3376 BOOL fFound = FALSE;
3377 for (unsigned j = 0; j < cQueues && !fFound; j++)
3378 fFound = !strcmp(papi2[j].pPrinterName,pi2[i].pPrinterName)
3379 && !strcmp(papi2[j].pDriverName, pi2[i].pDriverName)
3380 && !strcmp(papi2[j].pPortName, pi2[i].pPortName);
3381 /* nuke it */
3382 if (!fFound)
3383 {
3384 HANDLE hPrinter;
3385 if (OpenPrinterA(pi2[i].pPrinterName, &hPrinter, NULL) == TRUE)
3386 {
3387 dprintf(("Delete printer %s,%s,%s", papi2[i].pPrinterName, papi2[i].pDriverName, papi2[i].pPortName));
3388 DeletePrinter(hPrinter);
3389 ClosePrinter(hPrinter);
3390 }
3391 else
3392 {
3393 DebugAssertFailed(("Failed to open a printer returned by EnumPrintersA, %s\n",
3394 pi2[i].pPrinterName));
3395 fRc = FALSE;
3396 }
3397 }
3398 }
3399 }
3400 else
3401 {
3402 DebugAssertFailed(("EnumPrintersA failed!\n"));
3403 fRc = FALSE;
3404 }
3405 free(pi2);
3406 }
3407 else
3408 {
3409 DebugAssertFailed(("EnumPrintersA failed!\n"));
3410 fRc = FALSE;
3411 }
3412 free(papi2);
3413 free(paDevices);
3414 for (i = 0; i < cQueues; i++)
3415 if (papszNewNames[i])
3416 free(papszNewNames[i]);
3417 }
3418 else
3419 dprintf(("OSLibSplEnumDevice -> %d, cDevices=%d", fRc, cDevices));
3420 }
3421 else
3422 dprintf(("OSLibSplEnumPrinter failed\n"));
3423
3424 free(paQueues);
3425 dprintf(("ExportPrintersToRegistry returns %s", fRc ? "success" : "failure"));
3426 return fRc;
3427}
3428
3429#endif /* __WIN32OS2__ */
Note: See TracBrowser for help on using the repository browser.