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

Last change on this file since 21305 was 21305, checked in by ydario, 16 years ago

winspool updates.

File size: 112.1 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 dm.s1.dmOrientation = DMORIENT_PORTRAIT;
829 dm.s1.dmPaperSize = DMPAPER_A4;
830 dm.s1.dmPaperLength = 2970;
831 dm.s1.dmPaperWidth = 2100;
832
833 dm.dmScale = 100;
834 dm.dmCopies = 1;
835 dm.dmDefaultSource = DMBIN_AUTO;
836 dm.dmPrintQuality = DMRES_MEDIUM;
837 /* dm.dmColor */
838 /* dm.dmDuplex */
839 dm.dmYResolution = 300; /* 300dpi */
840 dm.dmTTOption = DMTT_BITMAP;
841 dm.dmCollate = 1;
842 /* dm.dmFormName */
843 /* dm.dmLogPixels */
844 /* dm.dmBitsPerPel */
845 /* dm.dmPelsWidth */
846 /* dm.dmPelsHeight */
847 /* dm.dmDisplayFlags */
848 /* dm.dmDisplayFrequency */
849 /* dm.dmICMMethod */
850 /* dm.dmICMIntent */
851 /* dm.dmMediaType */
852 /* dm.dmDitherType */
853 /* dm.dmReserved1 */
854 /* dm.dmReserved2 */
855 /* dm.dmPanningWidth */
856 /* dm.dmPanningHeight */
857
858 if(unicode) {
859 if(buflen >= sizeof(DEVMODEW)) {
860 DEVMODEW *pdmW = DEVMODEdupAtoW(GetProcessHeap(), &dm );
861 memcpy(ptr, pdmW, sizeof(DEVMODEW));
862 HeapFree(GetProcessHeap(),0,pdmW);
863 }
864 *needed = sizeof(DEVMODEW);
865 }
866 else
867 {
868 if(buflen >= sizeof(DEVMODEA)) {
869 memcpy(ptr, &dm, sizeof(DEVMODEA));
870 }
871 *needed = sizeof(DEVMODEA);
872 }
873}
874
875
876/*********************************************************************
877 * WINSPOOL_GetPrinter_2
878 *
879 * Fills out a PRINTER_INFO_2A|W struct storing the strings in buf.
880 * The strings are either stored as unicode or ascii.
881 */
882static BOOL WINSPOOL_GetPrinter_2(HKEY hkeyPrinter, PRINTER_INFO_2W *pi2,
883 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
884 BOOL unicode)
885{
886 DWORD size, left = cbBuf;
887 BOOL space = (cbBuf > 0);
888 LPBYTE ptr = buf;
889
890 *pcbNeeded = 0;
891
892 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
893 unicode)) {
894 if(space && size <= left) {
895 pi2->pPrinterName = (LPWSTR)ptr;
896 ptr += size;
897 left -= size;
898 } else
899 space = FALSE;
900 *pcbNeeded += size;
901 }
902 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Share_NameW, ptr, left, &size,
903 unicode)) {
904 if(space && size <= left) {
905 pi2->pShareName = (LPWSTR)ptr;
906 ptr += size;
907 left -= size;
908 } else
909 space = FALSE;
910 *pcbNeeded += size;
911 }
912 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
913 unicode)) {
914 if(space && size <= left) {
915 pi2->pPortName = (LPWSTR)ptr;
916 ptr += size;
917 left -= size;
918 } else
919 space = FALSE;
920 *pcbNeeded += size;
921 }
922 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Printer_DriverW, ptr, left,
923 &size, unicode)) {
924 if(space && size <= left) {
925 pi2->pDriverName = (LPWSTR)ptr;
926 ptr += size;
927 left -= size;
928 } else
929 space = FALSE;
930 *pcbNeeded += size;
931 }
932 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DescriptionW, ptr, left, &size,
933 unicode)) {
934 if(space && size <= left) {
935 pi2->pComment = (LPWSTR)ptr;
936 ptr += size;
937 left -= size;
938 } else
939 space = FALSE;
940 *pcbNeeded += size;
941 }
942 if(WINSPOOL_GetStringFromReg(hkeyPrinter, LocationW, ptr, left, &size,
943 unicode)) {
944 if(space && size <= left) {
945 pi2->pLocation = (LPWSTR)ptr;
946 ptr += size;
947 left -= size;
948 } else
949 space = FALSE;
950 *pcbNeeded += size;
951 }
952 if(WINSPOOL_GetDevModeFromReg(hkeyPrinter, Default_DevModeW, ptr, left,
953 &size, unicode)) {
954 if(space && size <= left) {
955 pi2->pDevMode = (LPDEVMODEW)ptr;
956 ptr += size;
957 left -= size;
958 } else
959 space = FALSE;
960 *pcbNeeded += size;
961 }
962 else
963 {
964 MESSAGE( "no DevMode in registry. please setup your printer again.\n"
965 "use the default hard-coded DevMode(wineps/A4/300dpi).\n" );
966 WINSPOOL_GetDefaultDevMode(ptr, left, &size, unicode);
967 if(space && size <= left) {
968 pi2->pDevMode = (LPDEVMODEW)ptr;
969 ptr += size;
970 left -= size;
971 } else
972 space = FALSE;
973 *pcbNeeded += size;
974 }
975 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Separator_FileW, ptr, left,
976 &size, unicode)) {
977 if(space && size <= left) {
978 pi2->pSepFile = (LPWSTR)ptr;
979 ptr += size;
980 left -= size;
981 } else
982 space = FALSE;
983 *pcbNeeded += size;
984 }
985 if(WINSPOOL_GetStringFromReg(hkeyPrinter, Print_ProcessorW, ptr, left,
986 &size, unicode)) {
987 if(space && size <= left) {
988 pi2->pPrintProcessor = (LPWSTR)ptr;
989 ptr += size;
990 left -= size;
991 } else
992 space = FALSE;
993 *pcbNeeded += size;
994 }
995 if(WINSPOOL_GetStringFromReg(hkeyPrinter, DatatypeW, ptr, left,
996 &size, unicode)) {
997 if(space && size <= left) {
998 pi2->pDatatype = (LPWSTR)ptr;
999 ptr += size;
1000 left -= size;
1001 } else
1002 space = FALSE;
1003 *pcbNeeded += size;
1004 }
1005 if(WINSPOOL_GetStringFromReg(hkeyPrinter, ParametersW, ptr, left,
1006 &size, unicode)) {
1007 if(space && size <= left) {
1008 pi2->pParameters = (LPWSTR)ptr;
1009 ptr += size;
1010 left -= size;
1011 } else
1012 space = FALSE;
1013 *pcbNeeded += size;
1014 }
1015 if(pi2) {
1016 pi2->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1017 pi2->Priority = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Priority");
1018 pi2->DefaultPriority = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1019 "Default Priority");
1020 pi2->StartTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "StartTime");
1021 pi2->UntilTime = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "UntilTime");
1022 }
1023
1024 if(!space && pi2) /* zero out pi2 if we can't completely fill buf */
1025 memset(pi2, 0, sizeof(*pi2));
1026
1027 return space;
1028}
1029
1030/*********************************************************************
1031 * WINSPOOL_GetPrinter_4
1032 *
1033 * Fills out a PRINTER_INFO_4 struct storing the strings in buf.
1034 */
1035static BOOL WINSPOOL_GetPrinter_4(HKEY hkeyPrinter, PRINTER_INFO_4W *pi4,
1036 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1037 BOOL unicode)
1038{
1039 DWORD size, left = cbBuf;
1040 BOOL space = (cbBuf > 0);
1041 LPBYTE ptr = buf;
1042
1043 *pcbNeeded = 0;
1044
1045 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1046 unicode)) {
1047 if(space && size <= left) {
1048 pi4->pPrinterName = (LPWSTR)ptr;
1049 ptr += size;
1050 left -= size;
1051 } else
1052 space = FALSE;
1053 *pcbNeeded += size;
1054 }
1055 if(pi4) {
1056 pi4->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1057 }
1058
1059 if(!space && pi4) /* zero out pi4 if we can't completely fill buf */
1060 memset(pi4, 0, sizeof(*pi4));
1061
1062 return space;
1063}
1064
1065/*********************************************************************
1066 * WINSPOOL_GetPrinter_5
1067 *
1068 * Fills out a PRINTER_INFO_5 struct storing the strings in buf.
1069 */
1070static BOOL WINSPOOL_GetPrinter_5(HKEY hkeyPrinter, PRINTER_INFO_5W *pi5,
1071 LPBYTE buf, DWORD cbBuf, LPDWORD pcbNeeded,
1072 BOOL unicode)
1073{
1074 DWORD size, left = cbBuf;
1075 BOOL space = (cbBuf > 0);
1076 LPBYTE ptr = buf;
1077
1078 *pcbNeeded = 0;
1079
1080 if(WINSPOOL_GetStringFromReg(hkeyPrinter, NameW, ptr, left, &size,
1081 unicode)) {
1082 if(space && size <= left) {
1083 pi5->pPrinterName = (LPWSTR)ptr;
1084 ptr += size;
1085 left -= size;
1086 } else
1087 space = FALSE;
1088 *pcbNeeded += size;
1089 }
1090 if(WINSPOOL_GetStringFromReg(hkeyPrinter, PortW, ptr, left, &size,
1091 unicode)) {
1092 if(space && size <= left) {
1093 pi5->pPortName = (LPWSTR)ptr;
1094 ptr += size;
1095 left -= size;
1096 } else
1097 space = FALSE;
1098 *pcbNeeded += size;
1099 }
1100 if(pi5) {
1101 pi5->Attributes = WINSPOOL_GetDWORDFromReg(hkeyPrinter, "Attributes");
1102 pi5->DeviceNotSelectedTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1103 "dnsTimeout");
1104 pi5->TransmissionRetryTimeout = WINSPOOL_GetDWORDFromReg(hkeyPrinter,
1105 "txTimeout");
1106 }
1107
1108 if(!space && pi5) /* zero out pi5 if we can't completely fill buf */
1109 memset(pi5, 0, sizeof(*pi5));
1110
1111 return space;
1112}
1113
1114
1115/*****************************************************************************
1116 * WINSPOOL_GetPrinter
1117 *
1118 * Implementation of GetPrinterA|W. Relies on PRINTER_INFO_*W being
1119 * essentially the same as PRINTER_INFO_*A. i.e. the structure itself is
1120 * just a collection of pointers to strings.
1121 */
1122static BOOL WINSPOOL_GetPrinter(HANDLE hPrinter, DWORD Level, LPBYTE pPrinter,
1123 DWORD cbBuf, LPDWORD pcbNeeded, BOOL unicode)
1124{
1125 LPCWSTR name;
1126 DWORD size, needed = 0;
1127 LPBYTE ptr = NULL;
1128 HKEY hkeyPrinter, hkeyPrinters;
1129 BOOL ret;
1130
1131 TRACE("(%p,%ld,%p,%ld,%p)\n",hPrinter,Level,pPrinter,cbBuf, pcbNeeded);
1132
1133 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
1134
1135 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1136 ERROR_SUCCESS) {
1137 ERR("Can't create Printers key\n");
1138 return FALSE;
1139 }
1140 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter) != ERROR_SUCCESS)
1141 {
1142 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
1143 RegCloseKey(hkeyPrinters);
1144 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1145 return FALSE;
1146 }
1147
1148 switch(Level) {
1149 case 2:
1150 {
1151 PRINTER_INFO_2W *pi2 = (PRINTER_INFO_2W *)pPrinter;
1152
1153 size = sizeof(PRINTER_INFO_2W);
1154 if(size <= cbBuf) {
1155 ptr = pPrinter + size;
1156 cbBuf -= size;
1157 memset(pPrinter, 0, size);
1158 } else {
1159 pi2 = NULL;
1160 cbBuf = 0;
1161 }
1162 ret = WINSPOOL_GetPrinter_2(hkeyPrinter, pi2, ptr, cbBuf, &needed,
1163 unicode);
1164 needed += size;
1165 break;
1166 }
1167
1168 case 4:
1169 {
1170 PRINTER_INFO_4W *pi4 = (PRINTER_INFO_4W *)pPrinter;
1171
1172 size = sizeof(PRINTER_INFO_4W);
1173 if(size <= cbBuf) {
1174 ptr = pPrinter + size;
1175 cbBuf -= size;
1176 memset(pPrinter, 0, size);
1177 } else {
1178 pi4 = NULL;
1179 cbBuf = 0;
1180 }
1181 ret = WINSPOOL_GetPrinter_4(hkeyPrinter, pi4, ptr, cbBuf, &needed,
1182 unicode);
1183 needed += size;
1184 break;
1185 }
1186
1187
1188 case 5:
1189 {
1190 PRINTER_INFO_5W *pi5 = (PRINTER_INFO_5W *)pPrinter;
1191
1192 size = sizeof(PRINTER_INFO_5W);
1193 if(size <= cbBuf) {
1194 ptr = pPrinter + size;
1195 cbBuf -= size;
1196 memset(pPrinter, 0, size);
1197 } else {
1198 pi5 = NULL;
1199 cbBuf = 0;
1200 }
1201
1202 ret = WINSPOOL_GetPrinter_5(hkeyPrinter, pi5, ptr, cbBuf, &needed,
1203 unicode);
1204 needed += size;
1205 break;
1206 }
1207
1208 default:
1209 FIXME("Unimplemented level %ld\n", Level);
1210 SetLastError(ERROR_INVALID_LEVEL);
1211 RegCloseKey(hkeyPrinters);
1212 RegCloseKey(hkeyPrinter);
1213 return FALSE;
1214 }
1215
1216 RegCloseKey(hkeyPrinter);
1217 RegCloseKey(hkeyPrinters);
1218
1219 TRACE("returing %d needed = %ld\n", ret, needed);
1220 if(pcbNeeded) *pcbNeeded = needed;
1221 if(!ret)
1222 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1223 return ret;
1224}
1225
1226
1227/*****************************************************************************
1228 * WINSPOOL_GetDriverInfoFromReg [internal]
1229 *
1230 * Enters the information from the registry into the DRIVER_INFO struct
1231 *
1232 * RETURNS
1233 * zero if the printer driver does not exist in the registry
1234 * (only if Level > 1) otherwise nonzero
1235 */
1236static BOOL WINSPOOL_GetDriverInfoFromReg(
1237 HKEY hkeyDrivers,
1238 LPWSTR DriverName,
1239 LPWSTR pEnvironment,
1240 DWORD Level,
1241 LPBYTE ptr, /* DRIVER_INFO */
1242 LPBYTE pDriverStrings, /* strings buffer */
1243 DWORD cbBuf, /* size of string buffer */
1244 LPDWORD pcbNeeded, /* space needed for str. */
1245 BOOL unicode) /* type of strings */
1246{ DWORD dw, size, tmp, type;
1247 HKEY hkeyDriver;
1248 LPBYTE strPtr = pDriverStrings;
1249
1250 TRACE("%s,%s,%ld,%p,%p,%ld,%d\n",
1251 debugstr_w(DriverName), debugstr_w(pEnvironment),
1252 Level, ptr, pDriverStrings, cbBuf, unicode);
1253
1254 if(unicode) {
1255 *pcbNeeded = (lstrlenW(DriverName) + 1) * sizeof(WCHAR);
1256 if (*pcbNeeded <= cbBuf)
1257 strcpyW((LPWSTR)strPtr, DriverName);
1258 } else {
1259 *pcbNeeded = WideCharToMultiByte(CP_ACP, 0, DriverName, -1, NULL, 0,
1260 NULL, NULL);
1261 if(*pcbNeeded <= cbBuf)
1262 WideCharToMultiByte(CP_ACP, 0, DriverName, -1, (LPSTR)strPtr, *pcbNeeded,
1263 NULL, NULL);
1264 }
1265 if(Level == 1) {
1266 if(ptr)
1267 ((PDRIVER_INFO_1W) ptr)->pName = (LPWSTR) strPtr;
1268 return TRUE;
1269 } else {
1270 if(ptr)
1271 ((PDRIVER_INFO_3W) ptr)->pName = (LPWSTR) strPtr;
1272 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
1273 }
1274
1275 if(!DriverName[0] || RegOpenKeyW(hkeyDrivers, DriverName, &hkeyDriver) != ERROR_SUCCESS) {
1276 ERR("Can't find driver '%s' in registry\n", debugstr_w(DriverName));
1277 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER); /* ? */
1278 return FALSE;
1279 }
1280
1281 size = sizeof(dw);
1282 if(RegQueryValueExA(hkeyDriver, "Version", 0, &type, (PBYTE)&dw, &size) !=
1283 ERROR_SUCCESS)
1284 WARN("Can't get Version\n");
1285 else if(ptr)
1286 ((PDRIVER_INFO_3A) ptr)->cVersion = dw;
1287
1288 if(!pEnvironment)
1289 pEnvironment = DefaultEnvironmentW;
1290 if(unicode)
1291 size = (lstrlenW(pEnvironment) + 1) * sizeof(WCHAR);
1292 else
1293 size = WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, NULL, 0,
1294 NULL, NULL);
1295 *pcbNeeded += size;
1296 if(*pcbNeeded <= cbBuf) {
1297 if(unicode)
1298 strcpyW((LPWSTR)strPtr, pEnvironment);
1299 else
1300 WideCharToMultiByte(CP_ACP, 0, pEnvironment, -1, (LPSTR)strPtr, size,
1301 NULL, NULL);
1302 if(ptr)
1303 ((PDRIVER_INFO_3W) ptr)->pEnvironment = (LPWSTR)strPtr;
1304 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
1305 }
1306
1307 if(WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, 0, &size,
1308 unicode)) {
1309 *pcbNeeded += size;
1310 if(*pcbNeeded <= cbBuf)
1311 WINSPOOL_GetStringFromReg(hkeyDriver, DriverW, strPtr, size, &tmp,
1312 unicode);
1313 if(ptr)
1314 ((PDRIVER_INFO_3W) ptr)->pDriverPath = (LPWSTR)strPtr;
1315 strPtr = (pDriverStrings) ? (pDriverStrings + (*pcbNeeded)) : NULL;
1316 }
1317
1318 if(WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, 0, &size,
1319 unicode)) {
1320 *pcbNeeded += size;
1321 if(*pcbNeeded <= cbBuf)
1322 WINSPOOL_GetStringFromReg(hkeyDriver, Data_FileW, strPtr, size,
1323 &tmp, unicode);
1324 if(ptr)
1325 ((PDRIVER_INFO_3W) ptr)->pDataFile = (LPWSTR)strPtr;
1326 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1327 }
1328
1329 if(WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
1330 0, &size, unicode)) {
1331 *pcbNeeded += size;
1332 if(*pcbNeeded <= cbBuf)
1333 WINSPOOL_GetStringFromReg(hkeyDriver, Configuration_FileW, strPtr,
1334 size, &tmp, unicode);
1335 if(ptr)
1336 ((PDRIVER_INFO_3W) ptr)->pConfigFile = (LPWSTR)strPtr;
1337 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1338 }
1339
1340 if(Level == 2 ) {
1341 RegCloseKey(hkeyDriver);
1342 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
1343 return TRUE;
1344 }
1345
1346 if(WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr, 0, &size,
1347 unicode)) {
1348 *pcbNeeded += size;
1349 if(*pcbNeeded <= cbBuf)
1350 WINSPOOL_GetStringFromReg(hkeyDriver, Help_FileW, strPtr,
1351 size, &tmp, unicode);
1352 if(ptr)
1353 ((PDRIVER_INFO_3W) ptr)->pHelpFile = (LPWSTR)strPtr;
1354 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1355 }
1356
1357 if(WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr, 0,
1358 &size, unicode)) {
1359 *pcbNeeded += size;
1360 if(*pcbNeeded <= cbBuf)
1361 WINSPOOL_GetStringFromReg(hkeyDriver, Dependent_FilesW, strPtr,
1362 size, &tmp, unicode);
1363 if(ptr)
1364 ((PDRIVER_INFO_3W) ptr)->pDependentFiles = (LPWSTR)strPtr;
1365 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1366 }
1367
1368 if(WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr, 0, &size,
1369 unicode)) {
1370 *pcbNeeded += size;
1371 if(*pcbNeeded <= cbBuf)
1372 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
1373 size, &tmp, unicode);
1374 if(ptr)
1375 ((PDRIVER_INFO_3W) ptr)->pMonitorName = (LPWSTR)strPtr;
1376 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1377 }
1378
1379 if(WINSPOOL_GetStringFromReg(hkeyDriver, DatatypeW, strPtr, 0, &size,
1380 unicode)) {
1381 *pcbNeeded += size;
1382 if(*pcbNeeded <= cbBuf)
1383 WINSPOOL_GetStringFromReg(hkeyDriver, MonitorW, strPtr,
1384 size, &tmp, unicode);
1385 if(ptr)
1386 ((PDRIVER_INFO_3W) ptr)->pDefaultDataType = (LPWSTR)strPtr;
1387 strPtr = (pDriverStrings) ? pDriverStrings + (*pcbNeeded) : NULL;
1388 }
1389
1390 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
1391 RegCloseKey(hkeyDriver);
1392 return TRUE;
1393}
1394
1395/*****************************************************************************
1396 * WINSPOOL_GetPrinterDriver
1397 */
1398static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
1399 DWORD Level, LPBYTE pDriverInfo,
1400 DWORD cbBuf, LPDWORD pcbNeeded,
1401 BOOL unicode)
1402{
1403 LPCWSTR name;
1404 WCHAR DriverName[100];
1405 DWORD ret, type, size, needed = 0;
1406 LPBYTE ptr = NULL;
1407 HKEY hkeyPrinter, hkeyPrinters, hkeyDrivers;
1408
1409 TRACE("(%p,%s,%ld,%p,%ld,%p)\n",hPrinter,debugstr_w(pEnvironment),
1410 Level,pDriverInfo,cbBuf, pcbNeeded);
1411
1412 ZeroMemory(pDriverInfo, cbBuf);
1413
1414 if (!(name = WINSPOOL_GetOpenedPrinter(hPrinter))) return FALSE;
1415
1416 if(Level < 1 || Level > 3) {
1417 SetLastError(ERROR_INVALID_LEVEL);
1418 return FALSE;
1419 }
1420 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1421 ERROR_SUCCESS) {
1422 ERR("Can't create Printers key\n");
1423 return FALSE;
1424 }
1425 if(RegOpenKeyW(hkeyPrinters, name, &hkeyPrinter)
1426 != ERROR_SUCCESS) {
1427 ERR("Can't find opened printer %s in registry\n", debugstr_w(name));
1428 RegCloseKey(hkeyPrinters);
1429 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1430 return FALSE;
1431 }
1432 size = sizeof(DriverName);
1433 DriverName[0] = 0;
1434 ret = RegQueryValueExW(hkeyPrinter, Printer_DriverW, 0, &type,
1435 (LPBYTE)DriverName, &size);
1436 RegCloseKey(hkeyPrinter);
1437 RegCloseKey(hkeyPrinters);
1438 if(ret != ERROR_SUCCESS) {
1439 ERR("Can't get DriverName for printer %s\n", debugstr_w(name));
1440 return FALSE;
1441 }
1442
1443 hkeyDrivers = WINSPOOL_OpenDriverReg( pEnvironment, TRUE);
1444 if(!hkeyDrivers) {
1445 ERR("Can't create Drivers key\n");
1446 return FALSE;
1447 }
1448
1449 switch(Level) {
1450 case 1:
1451 size = sizeof(DRIVER_INFO_1W);
1452 break;
1453 case 2:
1454 size = sizeof(DRIVER_INFO_2W);
1455 break;
1456 case 3:
1457 size = sizeof(DRIVER_INFO_3W);
1458 break;
1459 default:
1460 ERR("Invalid level\n");
1461 return FALSE;
1462 }
1463
1464 if(size <= cbBuf)
1465 ptr = pDriverInfo + size;
1466
1467 if(!WINSPOOL_GetDriverInfoFromReg(hkeyDrivers, DriverName,
1468 pEnvironment, Level, pDriverInfo,
1469 (cbBuf < size) ? NULL : ptr,
1470 (cbBuf < size) ? 0 : cbBuf - size,
1471 &needed, unicode)) {
1472 RegCloseKey(hkeyDrivers);
1473 return FALSE;
1474 }
1475
1476 RegCloseKey(hkeyDrivers);
1477
1478 if(pcbNeeded) *pcbNeeded = size + needed;
1479 TRACE("buffer space %ld required %ld\n", cbBuf, *pcbNeeded);
1480 if(cbBuf >= needed) return TRUE;
1481 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1482 return FALSE;
1483}
1484
1485/*****************************************************************************
1486 * WINSPOOL_EnumPrinters
1487 *
1488 * Implementation of EnumPrintersA|W
1489 */
1490static BOOL WINSPOOL_EnumPrinters(DWORD dwType, LPWSTR lpszName,
1491 DWORD dwLevel, LPBYTE lpbPrinters,
1492 DWORD cbBuf, LPDWORD lpdwNeeded,
1493 LPDWORD lpdwReturned, BOOL unicode)
1494
1495{
1496 HKEY hkeyPrinters, hkeyPrinter;
1497 WCHAR PrinterName[255];
1498 DWORD needed = 0, number = 0;
1499 DWORD used, i, left;
1500 PBYTE pi, buf;
1501
1502 if(lpbPrinters)
1503 memset(lpbPrinters, 0, cbBuf);
1504 if(lpdwReturned)
1505 *lpdwReturned = 0;
1506 if(lpdwNeeded)
1507 *lpdwNeeded = 0;
1508
1509 /* PRINTER_ENUM_DEFAULT is only supported under win9x, we behave like NT */
1510 if(dwType == PRINTER_ENUM_DEFAULT)
1511 return TRUE;
1512
1513 if (dwType & PRINTER_ENUM_CONNECTIONS) {
1514 FIXME("We dont handle PRINTER_ENUM_CONNECTIONS\n");
1515 dwType &= ~PRINTER_ENUM_CONNECTIONS; /* we dont handle that */
1516 if(!dwType) return TRUE;
1517 }
1518
1519 if (!((dwType & PRINTER_ENUM_LOCAL) || (dwType & PRINTER_ENUM_NAME))) {
1520 FIXME("dwType = %08lx\n", dwType);
1521 SetLastError(ERROR_INVALID_FLAGS);
1522 return FALSE;
1523 }
1524
1525 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1526 ERROR_SUCCESS) {
1527 ERR("Can't create Printers key\n");
1528 return FALSE;
1529 }
1530
1531 if(RegQueryInfoKeyA(hkeyPrinters, NULL, NULL, NULL, &number, NULL, NULL,
1532 NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
1533 RegCloseKey(hkeyPrinters);
1534 ERR("Can't query Printers key\n");
1535 return FALSE;
1536 }
1537 TRACE("Found %ld printers\n", number);
1538
1539 switch(dwLevel) {
1540 case 1:
1541 RegCloseKey(hkeyPrinters);
1542 if (lpdwReturned)
1543 *lpdwReturned = number;
1544 return TRUE;
1545
1546 case 2:
1547 used = number * sizeof(PRINTER_INFO_2W);
1548 break;
1549 case 4:
1550 used = number * sizeof(PRINTER_INFO_4W);
1551 break;
1552 case 5:
1553 used = number * sizeof(PRINTER_INFO_5W);
1554 break;
1555
1556 default:
1557 SetLastError(ERROR_INVALID_LEVEL);
1558 RegCloseKey(hkeyPrinters);
1559 return FALSE;
1560 }
1561 pi = (used <= cbBuf) ? lpbPrinters : NULL;
1562
1563 for(i = 0; i < number; i++) {
1564 if(RegEnumKeyW(hkeyPrinters, i, PrinterName, sizeof(PrinterName)) !=
1565 ERROR_SUCCESS) {
1566 ERR("Can't enum key number %ld\n", i);
1567 RegCloseKey(hkeyPrinters);
1568 return FALSE;
1569 }
1570 TRACE("Printer %ld is %s\n", i, debugstr_w(PrinterName));
1571 if(RegOpenKeyW(hkeyPrinters, PrinterName, &hkeyPrinter) !=
1572 ERROR_SUCCESS) {
1573 ERR("Can't open key %s\n", debugstr_w(PrinterName));
1574 RegCloseKey(hkeyPrinters);
1575 return FALSE;
1576 }
1577
1578 if(cbBuf > used) {
1579 buf = lpbPrinters + used;
1580 left = cbBuf - used;
1581 } else {
1582 buf = NULL;
1583 left = 0;
1584 }
1585
1586 switch(dwLevel) {
1587 case 2:
1588 WINSPOOL_GetPrinter_2(hkeyPrinter, (PRINTER_INFO_2W *)pi, buf,
1589 left, &needed, unicode);
1590 used += needed;
1591 if(pi) pi += sizeof(PRINTER_INFO_2W);
1592 break;
1593 case 4:
1594 WINSPOOL_GetPrinter_4(hkeyPrinter, (PRINTER_INFO_4W *)pi, buf,
1595 left, &needed, unicode);
1596 used += needed;
1597 if(pi) pi += sizeof(PRINTER_INFO_4W);
1598 break;
1599 case 5:
1600 WINSPOOL_GetPrinter_5(hkeyPrinter, (PRINTER_INFO_5W *)pi, buf,
1601 left, &needed, unicode);
1602 used += needed;
1603 if(pi) pi += sizeof(PRINTER_INFO_5W);
1604 break;
1605 default:
1606 ERR("Shouldn't be here!\n");
1607 RegCloseKey(hkeyPrinter);
1608 RegCloseKey(hkeyPrinters);
1609 return FALSE;
1610 }
1611 RegCloseKey(hkeyPrinter);
1612 }
1613 RegCloseKey(hkeyPrinters);
1614
1615 if(lpdwNeeded)
1616 *lpdwNeeded = used;
1617
1618 if(used > cbBuf) {
1619 if(lpbPrinters)
1620 memset(lpbPrinters, 0, cbBuf);
1621 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1622 return FALSE;
1623 }
1624 if(lpdwReturned)
1625 *lpdwReturned = number;
1626 SetLastError(ERROR_SUCCESS);
1627 return TRUE;
1628}
1629
1630
1631/******************************************************************
1632 * EnumPrintersA [WINSPOOL.@]
1633 *
1634 */
1635BOOL WINAPI EnumPrintersA(DWORD dwType, LPSTR lpszName,
1636 DWORD dwLevel, LPBYTE lpbPrinters,
1637 DWORD cbBuf, LPDWORD lpdwNeeded,
1638 LPDWORD lpdwReturned)
1639{
1640 BOOL ret;
1641 LPWSTR pwstrNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpszName);
1642
1643 ret = WINSPOOL_EnumPrinters(dwType, pwstrNameW, dwLevel, lpbPrinters, cbBuf,
1644 lpdwNeeded, lpdwReturned, FALSE);
1645 HeapFree(GetProcessHeap(),0,pwstrNameW);
1646 return ret;
1647}
1648
1649
1650/*****************************************************************************
1651 * Name : BOOL ClosePrinter
1652 * Purpose :
1653 * Parameters:
1654 * Variables :
1655 * Result :
1656 * Remark :
1657 * Status : UNTESTED STUB
1658 *
1659 * Author : Markus Montkowski [09.07.98 13:39:08]
1660 *****************************************************************************/
1661
1662BOOL WIN32API ClosePrinter(HANDLE hPrinter)
1663{
1664#ifdef __WIN32OS2__
1665 /*
1666 * Validate handle and get instance data.
1667 */
1668 POPENPRINTER p = openprinterFind(hPrinter);
1669 if (!p)
1670 {
1671 dprintf(("WINSPOOL: ClosePrinter Invalid handle %d\n", hPrinter));
1672 SetLastError(ERROR_INVALID_HANDLE);
1673 return FALSE;
1674 }
1675 dprintf(("WINSPOOL: ClosePrinter(%d) name=%ls\n", hPrinter, p->pwszPrinterName));
1676
1677 /*
1678 * Close any open OS/2 spool file.
1679 */
1680 if (p->hspl)
1681 {
1682 dprintf(("WINSPOOL: ClosePrinter closing OS/2 spool file %#x\n", p->hspl));
1683 if (!OSLibSplQmClose(p->hspl))
1684 DebugAssertFailed(("OSLibSplQmClose(%#x) failed!!!\n", p->hspl));
1685 p->hspl = 0;
1686 }
1687 openprinterDelete(p);
1688 return TRUE;
1689#else
1690 int i = (int)hPrinter;
1691
1692 TRACE("Handle %p\n", hPrinter);
1693
1694 if ((i <= 0) || (i > nb_printers)) return FALSE;
1695 HeapFree( GetProcessHeap(), 0, printer_array[i - 1] );
1696 printer_array[i - 1] = NULL;
1697 return TRUE;
1698#endif
1699}
1700
1701
1702/**
1703 * Opens a printer.
1704 *
1705 * @returns Success indicator, last error set on failure.
1706 * @param lpPrinterName Pointer to printer name.
1707 * @param phPrinter Where to store the handle to the opned printer instance.
1708 * @param pDefault Printer defaults. (Current ignored)
1709 * @status partially implemented.
1710 * @author Wine???
1711 */
1712BOOL WIN32API OpenPrinterA(LPSTR lpPrinterName, HANDLE * phPrinter,
1713 PRINTER_DEFAULTSA * pDefault)
1714{
1715 LPWSTR lpPrinterNameW = HEAP_strdupAtoW(GetProcessHeap(),0,lpPrinterName);
1716 PRINTER_DEFAULTSW DefaultW, *pDefaultW = NULL;
1717 BOOL ret;
1718
1719 if(pDefault) {
1720 DefaultW.pDatatype = HEAP_strdupAtoW(GetProcessHeap(), 0,
1721 pDefault->pDatatype);
1722 DefaultW.pDevMode = DEVMODEdupAtoW(GetProcessHeap(),
1723 pDefault->pDevMode);
1724 DefaultW.DesiredAccess = pDefault->DesiredAccess;
1725 pDefaultW = &DefaultW;
1726 }
1727 ret = OpenPrinterW(lpPrinterNameW, phPrinter, pDefaultW);
1728 if(pDefault) {
1729 HeapFree(GetProcessHeap(), 0, DefaultW.pDatatype);
1730 HeapFree(GetProcessHeap(), 0, DefaultW.pDevMode);
1731 }
1732 HeapFree(GetProcessHeap(), 0, lpPrinterNameW);
1733 return ret;
1734}
1735
1736
1737/*****************************************************************************
1738 * Name : LONG DocumentPropertiesA
1739 * Purpose :
1740 * Parameters:
1741 * Variables :
1742 * Result :
1743 * Remark :
1744 * Status : UNTESTED STUB
1745 *
1746 * Author : Markus Montkowski [09.07.98 13:39:08]
1747 *****************************************************************************/
1748
1749LONG WIN32API DocumentPropertiesA(HWND hWnd, HANDLE hPrinter,
1750 LPSTR pDeviceName,
1751 LPDEVMODEA pDevModeOutput,
1752 LPDEVMODEA pDevModeInput,
1753 DWORD fMode)
1754{
1755 LPSTR lpName = pDeviceName;
1756 LONG ret;
1757
1758 dprintf(("DocumentPropertiesA(%p,%p,%s,%p,%p,%ld)\n",
1759 hWnd,hPrinter,pDeviceName,pDevModeOutput,pDevModeInput,fMode
1760 ));
1761
1762 if (hWnd)
1763 {
1764 char szPMQueue[256];
1765 if(SplQueryPMQueueName(pDeviceName, szPMQueue, sizeof(szPMQueue)) == TRUE) {
1766 ret = OSLibShowPrinterDialog(hWnd, szPMQueue);
1767 }
1768 }
1769
1770 if(!pDeviceName) {
1771 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
1772 if(!lpNameW) {
1773 ERR("no name from hPrinter?\n");
1774 return -1;
1775 }
1776 lpName = HEAP_strdupWtoA(GetProcessHeap(),0,lpNameW);
1777 }
1778
1779#if 0
1780 ret = GDI_CallExtDeviceMode16(hWnd, pDevModeOutput, lpName, "LPT1:",
1781 pDevModeInput, NULL, fMode);
1782#endif
1783
1784 switch (fMode & ~DM_PROMPT) {
1785 case 0:
1786 /* TODO - Printer driver specific data */
1787 ret = (sizeof(DEVMODEA));
1788 break;
1789
1790 case DM_IN_BUFFER:
1791 case DM_IN_BUFFER | DM_OUT_BUFFER:
1792 {
1793 HKEY hkey,hkeyPrinters,hkeyPrinter;
1794
1795 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
1796 ERROR_SUCCESS)
1797 {
1798 ERR("Can't open Printers key\n");
1799 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1800 ret = -1;
1801 break;
1802 }
1803
1804 if(RegOpenKeyA(hkeyPrinters, lpName, &hkeyPrinter) != ERROR_SUCCESS)
1805 {
1806 ERR("Can't find opened printer %s in registry\n", lpName);
1807 RegCloseKey(hkeyPrinters);
1808 SetLastError(ERROR_INVALID_PRINTER_NAME); /* ? */
1809 ret = -1;
1810 break;
1811 }
1812
1813 WINSPOOL_SetDevModeFromReg(hkeyPrinter, Default_DevModeW, (LPBYTE)pDevModeInput,
1814 sizeof(DEVMODEA));
1815 if (pDevModeOutput) {
1816 memcpy(pDevModeOutput, pDevModeInput, sizeof(DEVMODEA));
1817 }
1818 RegCloseKey(hkeyPrinter);
1819 RegCloseKey(hkeyPrinters);
1820 ret = IDOK;
1821 break;
1822 }
1823
1824 case DM_OUT_BUFFER:
1825 if(pDevModeOutput)
1826 {
1827 PRINTER_INFO_2A *pInfo;
1828 DWORD needed;
1829
1830 GetPrinterA(hPrinter, 2, NULL, 0, &needed);
1831 pInfo = (PRINTER_INFO_2A*)HeapAlloc(GetProcessHeap(),0,needed);
1832 if(GetPrinterA(hPrinter, 2, (LPBYTE)pInfo, needed, &needed) == FALSE) {
1833 dprintf(("GetPrinterA failed"));
1834 ret = -1;
1835 break;
1836 }
1837 if (pInfo->pDevMode) {
1838 memcpy(pDevModeOutput, pInfo->pDevMode, sizeof(DEVMODEA));
1839 }
1840 HeapFree(GetProcessHeap(),0,pInfo);
1841 }
1842 ret = IDOK;
1843 break;
1844
1845 default:
1846 dprintf(("Unsupported fMode = %d",fMode));
1847 ret = -1;
1848 break;
1849 }
1850
1851 if(!pDeviceName)
1852 HeapFree(GetProcessHeap(),0,lpName);
1853 return ret;
1854}
1855
1856
1857
1858/***********************************************************
1859 * PRINTER_INFO_2AtoW
1860 * Creates a unicode copy of PRINTER_INFO_2A on heap
1861 */
1862static LPPRINTER_INFO_2W PRINTER_INFO_2AtoW(HANDLE heap, LPPRINTER_INFO_2A piA)
1863{
1864 LPPRINTER_INFO_2W piW;
1865 if(!piA) return NULL;
1866 piW = (LPPRINTER_INFO_2W) HeapAlloc(heap, 0, sizeof(*piW));
1867 memcpy(piW, piA, sizeof(*piW)); /* copy everything first */
1868 piW->pServerName = HEAP_strdupAtoW(heap, 0, piA->pServerName);
1869 piW->pPrinterName = HEAP_strdupAtoW(heap, 0, piA->pPrinterName);
1870 piW->pShareName = HEAP_strdupAtoW(heap, 0, piA->pShareName);
1871 piW->pPortName = HEAP_strdupAtoW(heap, 0, piA->pPortName);
1872 piW->pDriverName = HEAP_strdupAtoW(heap, 0, piA->pDriverName);
1873 piW->pComment = HEAP_strdupAtoW(heap, 0, piA->pComment);
1874 piW->pLocation = HEAP_strdupAtoW(heap, 0, piA->pLocation);
1875 piW->pDevMode = DEVMODEdupAtoW(heap, piA->pDevMode);
1876 piW->pSepFile = HEAP_strdupAtoW(heap, 0, piA->pSepFile);
1877 piW->pPrintProcessor = HEAP_strdupAtoW(heap, 0, piA->pPrintProcessor);
1878 piW->pDatatype = HEAP_strdupAtoW(heap, 0, piA->pDatatype);
1879 piW->pParameters = HEAP_strdupAtoW(heap, 0, piA->pParameters);
1880 return piW;
1881}
1882
1883/***********************************************************
1884 * FREE_PRINTER_INFO_2W
1885 * Free PRINTER_INFO_2W and all strings
1886 */
1887static void FREE_PRINTER_INFO_2W(HANDLE heap, LPPRINTER_INFO_2W piW)
1888{
1889 if(!piW) return;
1890
1891 HeapFree(heap,0,piW->pServerName);
1892 HeapFree(heap,0,piW->pPrinterName);
1893 HeapFree(heap,0,piW->pShareName);
1894 HeapFree(heap,0,piW->pPortName);
1895 HeapFree(heap,0,piW->pDriverName);
1896 HeapFree(heap,0,piW->pComment);
1897 HeapFree(heap,0,piW->pLocation);
1898 HeapFree(heap,0,piW->pDevMode);
1899 HeapFree(heap,0,piW->pSepFile);
1900 HeapFree(heap,0,piW->pPrintProcessor);
1901 HeapFree(heap,0,piW->pDatatype);
1902 HeapFree(heap,0,piW->pParameters);
1903 HeapFree(heap,0,piW);
1904 return;
1905}
1906
1907
1908/*****************************************************************************
1909 * Name : HANDLE AddPrinterA
1910 * Purpose :
1911 * Parameters: LPSTR pName pointer to server name
1912 * DWORD Level printer info. structure level
1913 * LPBYTE pPrinter pointer to structure
1914 * Variables :
1915 * Result :
1916 * Remark :
1917 * Status : UNTESTED STUB
1918 *
1919 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
1920 *
1921 * Author : Markus Montkowski [09.07.98 14:18:56]
1922 *****************************************************************************/
1923
1924HANDLE WIN32API AddPrinterA(LPSTR pName, DWORD Level, LPBYTE pPrinter)
1925{
1926 WCHAR *pNameW = NULL;
1927 PRINTER_INFO_2W *piW;
1928 PRINTER_INFO_2A *piA = (PRINTER_INFO_2A*)pPrinter;
1929 HANDLE ret;
1930
1931 TRACE("(%s,%ld,%p): stub\n", debugstr_a(pName), Level, pPrinter);
1932 if(Level != 2) {
1933 ERR("Level = %ld, unsupported!\n", Level);
1934 SetLastError(ERROR_INVALID_LEVEL);
1935 return 0;
1936 }
1937 if (pName)
1938 pNameW = HEAP_strdupAtoW(GetProcessHeap(), 0, pName);
1939 piW = PRINTER_INFO_2AtoW(GetProcessHeap(), piA);
1940
1941 ret = AddPrinterW(pNameW, Level, (LPBYTE)piW);
1942
1943 FREE_PRINTER_INFO_2W(GetProcessHeap(), piW);
1944 HeapFree(GetProcessHeap(),0,pNameW);
1945 return ret;
1946}
1947
1948
1949/*****************************************************************************
1950 * Name : HANDLE AddPrinterW
1951 * Purpose :
1952 * Parameters: LPWSTR pName pointer to server name
1953 * DWORD Level printer info. structure level
1954 * LPBYTE pPrinter pointer to structure
1955 * Variables :
1956 * Result :
1957 * Remark :
1958 * Status : UNTESTED STUB
1959 *
1960 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
1961 *
1962 * Author : Markus Montkowski [09.07.98 14:18:56]
1963 *****************************************************************************/
1964
1965HANDLE WIN32API AddPrinterW(LPWSTR pName, DWORD Level, LPBYTE pPrinter)
1966{
1967 PRINTER_INFO_2W *pi = (PRINTER_INFO_2W *) pPrinter;
1968 LPDEVMODEA dmA;
1969 LPDEVMODEW dmW;
1970 HANDLE retval;
1971 HKEY hkeyPrinter, hkeyPrinters, hkeyDriver, hkeyDrivers;
1972 LONG size;
1973
1974 TRACE("(%s,%ld,%p)\n", debugstr_w(pName), Level, pPrinter);
1975
1976 if(pName != NULL) {
1977 ERR("pName = %s - unsupported\n", debugstr_w(pName));
1978 SetLastError(ERROR_INVALID_PARAMETER);
1979 return 0;
1980 }
1981 if(Level != 2) {
1982 ERR("Level = %ld, unsupported!\n", Level);
1983 SetLastError(ERROR_INVALID_LEVEL);
1984 return 0;
1985 }
1986#if 0
1987 // SvL: OS/2 printer names can be up to 48 characters, whereas this limit
1988 // is 32 chars. We don't actually copy the full printer name into the
1989 // dmDeviceName string, so it's fairly safe to remove this check.
1990 // (Acrobat Reader Defect 937)
1991 if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
1992 ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
1993 debugstr_w(pi->pPrinterName)
1994 );
1995 SetLastError(ERROR_INVALID_LEVEL);
1996 return 0;
1997 }
1998#endif
1999 if(!pPrinter) {
2000 SetLastError(ERROR_INVALID_PARAMETER);
2001 return 0;
2002 }
2003 if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
2004 ERROR_SUCCESS) {
2005 ERR("Can't create Printers key\n");
2006 return 0;
2007 }
2008 if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
2009 if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
2010 SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
2011 RegCloseKey(hkeyPrinter);
2012 RegCloseKey(hkeyPrinters);
2013 return 0;
2014 }
2015 RegCloseKey(hkeyPrinter);
2016 }
2017 hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
2018 if(!hkeyDrivers) {
2019 ERR("Can't create Drivers key\n");
2020 RegCloseKey(hkeyPrinters);
2021 return 0;
2022 }
2023 if(RegOpenKeyW(hkeyDrivers, pi->pDriverName, &hkeyDriver) !=
2024 ERROR_SUCCESS) {
2025 WARN("Can't find driver %s\n", debugstr_w(pi->pDriverName));
2026 RegCloseKey(hkeyPrinters);
2027 RegCloseKey(hkeyDrivers);
2028 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2029 return 0;
2030 }
2031 RegCloseKey(hkeyDriver);
2032 RegCloseKey(hkeyDrivers);
2033
2034 if(lstrcmpiW(pi->pPrintProcessor, WinPrintW)) { /* FIXME */
2035 FIXME("Can't find processor %s\n", debugstr_w(pi->pPrintProcessor));
2036 SetLastError(ERROR_UNKNOWN_PRINTPROCESSOR);
2037 RegCloseKey(hkeyPrinters);
2038 return 0;
2039 }
2040
2041 if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
2042 ERROR_SUCCESS) {
2043 FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
2044 SetLastError(ERROR_INVALID_PRINTER_NAME);
2045 RegCloseKey(hkeyPrinters);
2046 return 0;
2047 }
2048 RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
2049 (LPBYTE)&pi->Attributes, sizeof(DWORD));
2050 set_reg_szW(hkeyPrinter, DatatypeW, pi->pDatatype);
2051
2052 /* See if we can load the driver. We may need the devmode structure anyway
2053 *
2054 * FIXME:
2055 * Note that DocumentPropertiesW will briefly try to open the printer we
2056 * just create to find a DEVMODEA struct (it will use the WINEPS default
2057 * one in case it is not there, so we are ok).
2058 */
2059 size = DocumentPropertiesW(0, 0, pi->pPrinterName, NULL, NULL, 0);
2060 if(size < 0) {
2061 FIXME("DocumentPropertiesW on printer '%s' fails\n", debugstr_w(pi->pPrinterName));
2062 size = sizeof(DEVMODEW);
2063 }
2064#if 0
2065 if(pi->pDevMode)
2066 dmW = pi->pDevMode;
2067 else {
2068 dmW = (LPDEVMODEW) HeapAlloc(GetProcessHeap(), 0, size);
2069 dmW->dmSize = size;
2070 if (0>DocumentPropertiesW(0,0,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER)) {
2071 ERR("DocumentPropertiesW on printer '%s' failed!\n", debugstr_w(pi->pPrinterName));
2072 SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
2073 return 0;
2074 }
2075 /* set devmode to printer name */
2076 strcpyW(dmW->dmDeviceName,pi->pPrinterName);
2077 }
2078
2079 /* Write DEVMODEA not DEVMODEW into reg. This is what win9x does
2080 and we support these drivers. NT writes DEVMODEW so somehow
2081 we'll need to distinguish between these when we support NT
2082 drivers */
2083 dmA = DEVMODEdupWtoA(GetProcessHeap(), dmW);
2084 RegSetValueExA(hkeyPrinter, "Default DevMode", 0, REG_BINARY, (LPBYTE)dmA,
2085 dmA->dmSize + dmA->dmDriverExtra);
2086 HeapFree(GetProcessHeap(), 0, dmA);
2087 if(!pi->pDevMode)
2088 HeapFree(GetProcessHeap(), 0, dmW);
2089#endif
2090 set_reg_szW(hkeyPrinter, DescriptionW, pi->pComment);
2091 set_reg_szW(hkeyPrinter, LocationW, pi->pLocation);
2092 set_reg_szW(hkeyPrinter, NameW, pi->pPrinterName);
2093 set_reg_szW(hkeyPrinter, ParametersW, pi->pParameters);
2094
2095 set_reg_szW(hkeyPrinter, PortW, pi->pPortName);
2096 set_reg_szW(hkeyPrinter, Print_ProcessorW, pi->pPrintProcessor);
2097 set_reg_szW(hkeyPrinter, Printer_DriverW, pi->pDriverName);
2098 RegSetValueExA(hkeyPrinter, "Priority", 0, REG_DWORD,
2099 (LPBYTE)&pi->Priority, sizeof(DWORD));
2100 set_reg_szW(hkeyPrinter, Separator_FileW, pi->pSepFile);
2101 set_reg_szW(hkeyPrinter, Share_NameW, pi->pShareName);
2102 RegSetValueExA(hkeyPrinter, "StartTime", 0, REG_DWORD,
2103 (LPBYTE)&pi->StartTime, sizeof(DWORD));
2104 RegSetValueExA(hkeyPrinter, "Status", 0, REG_DWORD,
2105 (LPBYTE)&pi->Status, sizeof(DWORD));
2106 RegSetValueExA(hkeyPrinter, "UntilTime", 0, REG_DWORD,
2107 (LPBYTE)&pi->UntilTime, sizeof(DWORD));
2108
2109 RegCloseKey(hkeyPrinter);
2110 RegCloseKey(hkeyPrinters);
2111 if(!OpenPrinterW(pi->pPrinterName, &retval, NULL)) {
2112 ERR("OpenPrinter failing\n");
2113 return 0;
2114 }
2115 return retval;
2116}
2117
2118
2119
2120/*****************************************************************************
2121 * Name : BOOL AddPrinterDriverA
2122 * Purpose :
2123 * Parameters: LPSTR pName pointer to server name
2124 * DWORD Level printer info. structure level
2125 * LPBYTE pDriverInfo pointer to printer info. structure
2126 * Variables :
2127 * Result :
2128 * Remark :
2129 * Status : UNTESTED STUB
2130 *
2131 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
2132 *
2133 * Author : Markus Montkowski [09.07.98 14:20:04]
2134 *****************************************************************************/
2135
2136BOOL WIN32API AddPrinterDriverA(LPSTR pName, DWORD level, LPBYTE pDriverInfo)
2137{
2138 DRIVER_INFO_3A di3;
2139 HKEY hkeyDrivers, hkeyName;
2140
2141 TRACE("(%s,%ld,%p)\n",debugstr_a(pName),level,pDriverInfo);
2142
2143 if(level != 2 && level != 3) {
2144 SetLastError(ERROR_INVALID_LEVEL);
2145 return FALSE;
2146 }
2147 if(pName != NULL) {
2148 FIXME("pName= %s - unsupported\n", debugstr_a(pName));
2149 SetLastError(ERROR_INVALID_PARAMETER);
2150 return FALSE;
2151 }
2152 if(!pDriverInfo) {
2153 WARN("pDriverInfo == NULL\n");
2154 SetLastError(ERROR_INVALID_PARAMETER);
2155 return FALSE;
2156 }
2157
2158 if(level == 3)
2159 di3 = *(DRIVER_INFO_3A *)pDriverInfo;
2160 else {
2161 memset(&di3, 0, sizeof(di3));
2162 *(DRIVER_INFO_2A *)&di3 = *(DRIVER_INFO_2A *)pDriverInfo;
2163 }
2164
2165 if(!di3.pName || !di3.pDriverPath || !di3.pConfigFile ||
2166 !di3.pDataFile) {
2167 SetLastError(ERROR_INVALID_PARAMETER);
2168 return FALSE;
2169 }
2170 if(!di3.pDefaultDataType) di3.pDefaultDataType = "";
2171 if(!di3.pDependentFiles) di3.pDependentFiles = "\0";
2172 if(!di3.pHelpFile) di3.pHelpFile = "";
2173 if(!di3.pMonitorName) di3.pMonitorName = "";
2174
2175 hkeyDrivers = WINSPOOL_OpenDriverReg(di3.pEnvironment, FALSE);
2176
2177 if(!hkeyDrivers) {
2178 ERR("Can't create Drivers key\n");
2179 return FALSE;
2180 }
2181
2182 if(level == 2) { /* apparently can't overwrite with level2 */
2183 if(RegOpenKeyA(hkeyDrivers, di3.pName, &hkeyName) == ERROR_SUCCESS) {
2184 RegCloseKey(hkeyName);
2185 RegCloseKey(hkeyDrivers);
2186 WARN("Trying to create existing printer driver %s\n", debugstr_a(di3.pName));
2187 SetLastError(ERROR_PRINTER_DRIVER_ALREADY_INSTALLED);
2188 return FALSE;
2189 }
2190 }
2191 if(RegCreateKeyA(hkeyDrivers, di3.pName, &hkeyName) != ERROR_SUCCESS) {
2192 RegCloseKey(hkeyDrivers);
2193 ERR("Can't create Name key\n");
2194 return FALSE;
2195 }
2196 RegSetValueExA(hkeyName, "Configuration File", 0, REG_SZ, (LPBYTE)di3.pConfigFile,
2197 strlen(di3.pConfigFile)+1);
2198 RegSetValueExA(hkeyName, "Data File", 0, REG_SZ, (LPBYTE)di3.pDataFile, strlen(di3.pDataFile)+1);
2199 RegSetValueExA(hkeyName, "Driver", 0, REG_SZ, (LPBYTE)di3.pDriverPath, strlen(di3.pDriverPath)+1);
2200 RegSetValueExA(hkeyName, "Version", 0, REG_DWORD, (LPBYTE)&di3.cVersion,
2201 sizeof(DWORD));
2202 RegSetValueExA(hkeyName, "Datatype", 0, REG_SZ, (LPBYTE)di3.pDefaultDataType, strlen(di3.pDefaultDataType)+1);
2203 RegSetValueExA(hkeyName, "Dependent Files", 0, REG_MULTI_SZ,
2204 (LPBYTE)di3.pDependentFiles, strlen(di3.pDependentFiles)+1);
2205 RegSetValueExA(hkeyName, "Help File", 0, REG_SZ, (LPBYTE)di3.pHelpFile, strlen(di3.pHelpFile)+1);
2206 RegSetValueExA(hkeyName, "Monitor", 0, REG_SZ, (LPBYTE)di3.pMonitorName, strlen(di3.pMonitorName)+1);
2207 RegCloseKey(hkeyName);
2208 RegCloseKey(hkeyDrivers);
2209
2210 return TRUE;
2211}
2212
2213
2214/*****************************************************************************
2215 * Name : BOOL AddPrinterDriverW
2216 * Purpose :
2217 * Parameters: LPWSTR pName pointer to server name
2218 * DWORD Level printer info. structure level
2219 * LPBYTE pDriverInfo pointer to printer info. structure
2220 * Variables :
2221 * Result :
2222 * Remark :
2223 * Status : UNTESTED STUB
2224 *
2225 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
2226 *
2227 * Author : Markus Montkowski [09.07.98 14:20:04]
2228 *****************************************************************************/
2229
2230BOOL WIN32API AddPrinterDriverW(LPWSTR pName, DWORD Level, LPBYTE pDriverInfo)
2231{
2232 dprintf(("WINSPOOL: AddPrinterDriverW not implemented\n"));
2233 return (FALSE);
2234}
2235
2236/*****************************************************************************
2237 * Name : BOOL DeletePrinter
2238 * Purpose :
2239 * Parameters: HANDLE hPrinter handle to printer object
2240 * Variables :
2241 * Result :
2242 * Remark :
2243 * Status : UNTESTED STUB
2244 *
2245 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
2246 *
2247 * Author : Markus Montkowski [09.07.98 14:30:50]
2248 *****************************************************************************/
2249
2250BOOL WIN32API DeletePrinter(HANDLE hPrinter)
2251{
2252 LPCWSTR lpNameW = WINSPOOL_GetOpenedPrinter(hPrinter);
2253 HKEY hkeyPrinters;
2254
2255 if(!lpNameW) return FALSE;
2256
2257 if(RegOpenKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) == ERROR_SUCCESS) {
2258 SHDeleteKeyW(hkeyPrinters, lpNameW);
2259 RegCloseKey(hkeyPrinters);
2260 return TRUE;
2261 }
2262 else {
2263 dprintf(("Can't open Printers key"));
2264 return FALSE;
2265 }
2266}
2267
2268
2269/*****************************************************************************
2270 * Name : DWORD DeviceCapabilitiesA
2271 * Purpose :
2272 * Parameters: LPCSTR pDevice pointer to a printer-name string
2273 * LPCSTR pPort pointer to a port-name string
2274 * WORD fwCapability device capability to query
2275 * LPSTR pOutput pointer to the output
2276 * CONST DEVMODE *pDevMode pointer to structure with device data
2277 * Variables :
2278 * Result :
2279 * Remark :
2280 * Status : UNTESTED STUB
2281 *
2282 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
2283 *
2284 * Author : Markus Montkowski [09.07.98 14:27:08]
2285 *****************************************************************************/
2286
2287INT WIN32API DeviceCapabilitiesA(LPCSTR pDevice,
2288 LPCSTR pPort,
2289 WORD fwCapability,
2290 LPSTR pOutput,
2291 DEVMODEA * pDevMode)
2292{
2293 char szPMQueue[256];
2294
2295 dprintf(("WINSPOOL: DeviceCapabilitiesA %s %s %x %x %x", pDevice, pPort, fwCapability, pOutput, pDevMode));
2296
2297 //Get the PM Queue name corresponding to the printer device
2298 if(SplQueryPMQueueName((LPSTR)pDevice, szPMQueue, sizeof(szPMQueue)) == TRUE) {
2299 return O32_DeviceCapabilities(szPMQueue, pPort, fwCapability, pOutput, pDevMode);
2300 }
2301 return -1;
2302}
2303
2304
2305/*****************************************************************************
2306 * DeviceCapabilitiesW [WINSPOOL.152]
2307 *
2308 * Call DeviceCapabilitiesA since we later call 16bit stuff anyway
2309 *
2310 */
2311INT WIN32API DeviceCapabilitiesW(LPCWSTR pDevice, LPCWSTR pPort,
2312 WORD fwCapability, LPWSTR pOutput,
2313 CONST DEVMODEW * pDevMode)
2314{
2315 LPDEVMODEA dmA = DEVMODEdupWtoA(GetProcessHeap(), pDevMode);
2316 LPSTR pDeviceA = HEAP_strdupWtoA(GetProcessHeap(),0,pDevice);
2317 LPSTR pPortA = HEAP_strdupWtoA(GetProcessHeap(),0,pPort);
2318 INT ret;
2319
2320 if(pOutput && (fwCapability == DC_BINNAMES ||
2321 fwCapability == DC_FILEDEPENDENCIES ||
2322 fwCapability == DC_PAPERNAMES)) {
2323 /* These need A -> W translation */
2324 INT size = 0, i;
2325 LPSTR pOutputA;
2326 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, NULL,
2327 dmA);
2328 if(ret == -1)
2329 return ret;
2330 switch(fwCapability) {
2331 case DC_BINNAMES:
2332 size = 24;
2333 break;
2334 case DC_PAPERNAMES:
2335 case DC_FILEDEPENDENCIES:
2336 size = 64;
2337 break;
2338 }
2339 pOutputA = (LPSTR)HeapAlloc(GetProcessHeap(), 0, size * ret);
2340 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability, pOutputA,
2341 dmA);
2342 for(i = 0; i < ret; i++)
2343 MultiByteToWideChar(CP_ACP, 0, pOutputA + (i * size), -1,
2344 pOutput + (i * size), size);
2345 HeapFree(GetProcessHeap(), 0, pOutputA);
2346 } else {
2347 ret = DeviceCapabilitiesA(pDeviceA, pPortA, fwCapability,
2348 (LPSTR)pOutput, dmA);
2349 }
2350 HeapFree(GetProcessHeap(),0,pPortA);
2351 HeapFree(GetProcessHeap(),0,pDeviceA);
2352 HeapFree(GetProcessHeap(),0,dmA);
2353 return ret;
2354}
2355
2356
2357
2358
2359/******************************************************************
2360 * EnumPrintersW [WINSPOOL.@]
2361 *
2362 * Enumerates the available printers, print servers and print
2363 * providers, depending on the specified flags, name and level.
2364 *
2365 * RETURNS:
2366 *
2367 * If level is set to 1:
2368 * Not implemented yet!
2369 * Returns TRUE with an empty list.
2370 *
2371 * If level is set to 2:
2372 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2373 * Returns an array of PRINTER_INFO_2 data structures in the
2374 * lpbPrinters buffer. Note that according to MSDN also an
2375 * OpenPrinter should be performed on every remote printer.
2376 *
2377 * If level is set to 4 (officially WinNT only):
2378 * Possible flags: PRINTER_ENUM_CONNECTIONS, PRINTER_ENUM_LOCAL.
2379 * Fast: Only the registry is queried to retrieve printer names,
2380 * no connection to the driver is made.
2381 * Returns an array of PRINTER_INFO_4 data structures in the
2382 * lpbPrinters buffer.
2383 *
2384 * If level is set to 5 (officially WinNT4/Win9x only):
2385 * Fast: Only the registry is queried to retrieve printer names,
2386 * no connection to the driver is made.
2387 * Returns an array of PRINTER_INFO_5 data structures in the
2388 * lpbPrinters buffer.
2389 *
2390 * If level set to 3 or 6+:
2391 * returns zero (failure!)
2392 *
2393 * Returns nonzero (TRUE) on success, or zero on failure, use GetLastError
2394 * for information.
2395 *
2396 * BUGS:
2397 * - Only PRINTER_ENUM_LOCAL and PRINTER_ENUM_NAME are implemented.
2398 * - Only levels 2, 4 and 5 are implemented at the moment.
2399 * - 16-bit printer drivers are not enumerated.
2400 * - Returned amount of bytes used/needed does not match the real Windoze
2401 * implementation (as in this implementation, all strings are part
2402 * of the buffer, whereas Win32 keeps them somewhere else)
2403 * - At level 2, EnumPrinters should also call OpenPrinter for remote printers.
2404 *
2405 * NOTE:
2406 * - In a regular Wine installation, no registry settings for printers
2407 * exist, which makes this function return an empty list.
2408 */
2409BOOL WINAPI EnumPrintersW(
2410 DWORD dwType, /* [in] Types of print objects to enumerate */
2411 LPWSTR lpszName, /* [in] name of objects to enumerate */
2412 DWORD dwLevel, /* [in] type of printer info structure */
2413 LPBYTE lpbPrinters, /* [out] buffer which receives info */
2414 DWORD cbBuf, /* [in] max size of buffer in bytes */
2415 LPDWORD lpdwNeeded, /* [out] pointer to var: # bytes used/needed */
2416 LPDWORD lpdwReturned /* [out] number of entries returned */
2417 )
2418{
2419 return WINSPOOL_EnumPrinters(dwType, lpszName, dwLevel, lpbPrinters, cbBuf,
2420 lpdwNeeded, lpdwReturned, TRUE);
2421}
2422
2423
2424
2425
2426/*****************************************************************************
2427 * Name : BOOL GetPrinterA
2428 * Purpose :
2429 * Parameters: HANDLE hPrinter handle to printer of interest
2430 * DWORD Level version of printer info data structure
2431 * LPBYTE pPrinter pointer to array of bytes that receives printer info. structure
2432 * DWORD cbBuf size, in bytes, of array of bytes
2433 * LPDWORD pcbNeeded pointer to variable with count of bytes retrieved (or required)
2434 * Variables :
2435 * Result :
2436 * Remark :
2437 * Status : UNTESTED STUB
2438 *
2439 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
2440 *
2441 * Author : Markus Montkowski [09.07.98 14:45:36]
2442 *****************************************************************************/
2443
2444BOOL WIN32API GetPrinterA(
2445 HANDLE hPrinter,
2446 DWORD Level,
2447 LPBYTE pPrinter,
2448 DWORD cbBuf,
2449 LPDWORD pcbNeeded)
2450{
2451 return WINSPOOL_GetPrinter(hPrinter, Level, pPrinter, cbBuf, pcbNeeded,
2452 FALSE);
2453}
2454
2455
2456/*****************************************************************************
2457 * Name : BOOL GetPrinterW
2458 * Purpose :
2459 * Parameters: HANDLE hPrinter handle to printer of interest
2460 * DWORD Level version of printer info data structure
2461 * LPBYTE pPrinter pointer to array of bytes that receives printer info. structure
2462 * DWORD cbBuf size, in bytes, of array of bytes
2463 * LPDWORD pcbNeeded pointer to variable with count of bytes retrieved (or required)
2464 * Variables :
2465 * Result :
2466 * Remark :
2467 * Status : UNTESTED STUB
2468 *
2469 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
2470 *
2471 * Author : Markus Montkowski [09.07.98 14:45:36]
2472 *****************************************************************************/
2473
2474BOOL WIN32API GetPrinterW(
2475 HANDLE hPrinter,
2476 DWORD Level,
2477 LPBYTE pPrinter,
2478 DWORD cbBuf,
2479 LPDWORD pcbNeeded)
2480{
2481 dprintf(("WINSPOOL: GetPrinterW not implemented\n"));
2482 return (FALSE);
2483}
2484
2485
2486
2487/*****************************************************************************
2488 * Name : BOOL GetPrinterDriverA
2489 * Purpose :
2490 * Parameters: HANDLE hPrinter printer object
2491 * LPSTR pEnvironment address of environment
2492 * DWORD Level structure level
2493 * LPBYTE pDriverInfo address of structure array
2494 * DWORD cbBuf size, in bytes, of array
2495 * LPDWORD pcbNeeded address of variable with number of bytes retrieved (or required)
2496 * Variables :
2497 * Result :
2498 * Remark :
2499 * Status : UNTESTED STUB
2500 *
2501 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
2502 *
2503 * Author : Markus Montkowski [09.07.98 14:47:01]
2504 *****************************************************************************/
2505
2506BOOL WIN32API GetPrinterDriverA(
2507 HANDLE hPrinter,
2508 LPSTR pEnvironment,
2509 DWORD Level,
2510 LPBYTE pDriverInfo,
2511 DWORD cbBuf,
2512 LPDWORD pcbNeeded)
2513{
2514 BOOL ret;
2515 LPWSTR pEnvW = HEAP_strdupAtoW(GetProcessHeap(),0,pEnvironment);
2516 ret = WINSPOOL_GetPrinterDriver(hPrinter, pEnvW, Level, pDriverInfo,
2517 cbBuf, pcbNeeded, FALSE);
2518 HeapFree(GetProcessHeap(),0,pEnvW);
2519 return ret;
2520}
2521
2522
2523/*****************************************************************************
2524 * Name : BOOL GetPrinterDriverW
2525 * Purpose :
2526 * Parameters: HANDLE hPrinter printer object
2527 * LPWSTR pEnvironment address of environment
2528 * DWORD Level structure level
2529 * LPBYTE pDriverInfo address of structure array
2530 * DWORD cbBuf size, in bytes, of array
2531 * LPDWORD pcbNeeded address of variable with number of bytes retrieved (or required)
2532 * Variables :
2533 * Result :
2534 * Remark :
2535 * Status : UNTESTED STUB
2536 *
2537 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
2538 *
2539 * Author : Markus Montkowski [09.07.98 14:47:01]
2540 *****************************************************************************/
2541
2542BOOL WIN32API GetPrinterDriverW(
2543 HANDLE hPrinter,
2544 LPWSTR pEnvironment,
2545 DWORD Level,
2546 LPBYTE pDriverInfo,
2547 DWORD cbBuf,
2548 LPDWORD pcbNeeded)
2549{
2550 dprintf(("WINSPOOL: GetPrinterDriverW not implemented\n"));
2551 return (FALSE);
2552}
2553
2554
2555/*****************************************************************************
2556 * Name : BOOL GetPrinterDriverDirectoryA
2557 * Purpose :
2558 * Parameters: LPSTR pName address of server name
2559 * LPSTR pEnvironment address of environment
2560 * DWORD Level address of structure
2561 * LPBYTE pDriverDirectory address of structure array that receives path
2562 * DWORD cbBuf size, in bytes, of array
2563 * LPDWORD pcbNeeded address of variable with number of bytes retrieved (or required)
2564 * Variables :
2565 * Result :
2566 * Remark :
2567 * Status : UNTESTED STUB
2568 *
2569 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
2570 *
2571 * Author : Markus Montkowski [09.07.98 14:47:16]
2572 *****************************************************************************/
2573
2574BOOL WIN32API GetPrinterDriverDirectoryA(
2575 LPSTR pName,
2576 LPSTR pEnvironment,
2577 DWORD Level,
2578 LPBYTE pDriverDirectory,
2579 DWORD cbBuf,
2580 LPDWORD pcbNeeded)
2581{
2582 DWORD needed;
2583
2584 TRACE("(%s, %s, %ld, %p, %ld, %p)\n", pName, pEnvironment, Level,
2585 pDriverDirectory, cbBuf, pcbNeeded);
2586 if(pName != NULL) {
2587 FIXME("pName = `%s' - unsupported\n", pName);
2588 SetLastError(ERROR_INVALID_PARAMETER);
2589 return FALSE;
2590 }
2591 if(pEnvironment != NULL) {
2592 FIXME("pEnvironment = `%s' - unsupported\n", pEnvironment);
2593 SetLastError(ERROR_INVALID_ENVIRONMENT);
2594 return FALSE;
2595 }
2596 if(Level != 1) /* win95 ignores this so we just carry on */
2597 WARN("Level = %ld - assuming 1\n", Level);
2598
2599 /* FIXME should read from registry */
2600 needed = GetSystemDirectoryA((LPSTR)pDriverDirectory, cbBuf);
2601 needed++;
2602 if(pcbNeeded)
2603 *pcbNeeded = needed;
2604 if(needed > cbBuf) {
2605 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2606 return FALSE;
2607 }
2608 return TRUE;
2609
2610}
2611
2612
2613/*****************************************************************************
2614 * Name : BOOL GetPrinterDriverDirectoryW
2615 * Purpose :
2616 * Parameters: LPWSTR pName address of server name
2617 * LPWSTR pEnvironment address of environment
2618 * DWORD Level address of structure
2619 * LPBYTE pDriverDirectory address of structure array that receives path
2620 * DWORD cbBuf size, in bytes, of array
2621 * LPDWORD pcbNeeded address of variable with number of bytes retrieved (or required)
2622 * Variables :
2623 * Result :
2624 * Remark :
2625 * Status : UNTESTED STUB
2626 *
2627 * Stub Generated through PE2LX Stubwizard 0.02 from Markus Montkowski
2628 *
2629 * Author : Markus Montkowski [09.07.98 14:47:16]
2630 *****************************************************************************/
2631
2632BOOL WIN32API GetPrinterDriverDirectoryW(
2633 LPWSTR pName,
2634 LPWSTR pEnvironment,
2635 DWORD Level,
2636 LPBYTE pDriverDirectory,
2637 DWORD cbBuf,
2638 LPDWORD pcbNeeded)
2639{
2640 dprintf(("WINSPOOL: GetPrinterDriverDirectoryW not implemented\n"));
2641 return (FALSE);
2642}
2643
2644#ifndef __WIN32OS2__
2645/******************************************************************
2646 * WINSPOOL_GetOpenedPrinterEntry
2647 * Get the first place empty in the opened printer table
2648 */
2649static HANDLE WINSPOOL_GetOpenedPrinterEntry( LPCWSTR name )
2650{
2651 int i;
2652
2653 for (i = 0; i < nb_printers; i++) if (!printer_array[i]) break;
2654
2655 if (i >= nb_printers)
2656 {
2657 LPWSTR *new_array = (LPWSTR*)HeapReAlloc( GetProcessHeap(), 0, printer_array,
2658 (nb_printers + 16) * sizeof(*new_array) );
2659 if (!new_array) return 0;
2660 printer_array = new_array;
2661 nb_printers += 16;
2662 }
2663
2664 if ((printer_array[i] = (WCHAR*)HeapAlloc( GetProcessHeap(), 0, (strlenW(name)+1)*sizeof(WCHAR) )) != NULL)
2665 {
2666 strcpyW( printer_array[i], name );
2667 return (HANDLE)(i + 1);
2668 }
2669 return 0;
2670}
2671#endif
2672
2673/**
2674 * Opens a printer.
2675 *
2676 * @returns Success indicator, last error set on failure.
2677 * @param lpPrinterName Pointer to printer name.
2678 * @param phPrinter Where to store the handle to the opned printer instance.
2679 * @param pDefault Printer defaults. (Current ignored)
2680 * @status partially implemented.
2681 * @author ???
2682 * @author knut st. osmundsen <bird-srcspam@anduin.net>
2683 */
2684BOOL WIN32API OpenPrinterW(LPWSTR lpPrinterName, HANDLE *phPrinter, PRINTER_DEFAULTSW *pDefault)
2685{
2686 HKEY hkeyPrinters, hkeyPrinter;
2687
2688 /*
2689 * Validate input.
2690 */
2691 if (!lpPrinterName)
2692 {
2693 dprintf(("WINSPOOL: OpenPrinterW: printerName=NULL pDefault=%p returning false!\n", pDefault));
2694 SetLastError(ERROR_INVALID_PARAMETER);
2695 return FALSE;
2696 }
2697 dprintf(("WINSPOOL: OpenPrinterW: printerName='%ls' pDefault=%p\n", lpPrinterName, pDefault));
2698
2699 /*
2700 * Check if the Printer exists.
2701 */
2702 if (RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) != ERROR_SUCCESS)
2703 {
2704 dprintf(("Can't create Printers key\n"));
2705 SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
2706 return FALSE;
2707 }
2708
2709 if ( lpPrinterName[0] == '\0' /* explicitly fail on "" */
2710 || RegOpenKeyW(hkeyPrinters, lpPrinterName, &hkeyPrinter) != ERROR_SUCCESS)
2711 {
2712 dprintf(("Can't find printer '%ls' in registry\n", lpPrinterName));
2713 RegCloseKey(hkeyPrinters);
2714 SetLastError(ERROR_INVALID_PRINTER_NAME);
2715 return FALSE;
2716 }
2717 RegCloseKey(hkeyPrinter);
2718 RegCloseKey(hkeyPrinters);
2719
2720 /*
2721 * Seems like win95 doesn't care if there is no where to store
2722 * the handle. We'll do the same.
2723 */
2724 if (!phPrinter) /* This seems to be what win95 does anyway */
2725 {
2726 dprintf(("WINSPOOL: OpenPrinterW: phPrinter is NULL, returning succesfully anyhow\n"));
2727 return TRUE;
2728 }
2729
2730 /*
2731 * Create a handle for this open instance.
2732 */
2733 *phPrinter = NULL; /* crash here */
2734#ifdef __WIN32OS2__
2735 POPENPRINTER p = openprinterNew(lpPrinterName);
2736 if (!p)
2737 {
2738 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2739 dprintf(("WINSPOOL: OpenPrinterW: out of memory allocating handle\n"));
2740 return FALSE;
2741 }
2742 *phPrinter = p->hOpenPrinter;
2743#else
2744 *phPrinter = WINSPOOL_GetOpenedPrinterEntry( lpPrinterName );
2745#endif
2746
2747 if (pDefault != NULL)
2748 dprintf(("Not handling pDefault\n"));
2749
2750 dprintf(("WINSPOOL: OpenPrinterW: returning successfully *phPrinter=%d\n", *phPrinter));
2751 return TRUE;
2752}
2753
2754
2755
2756
2757/*********************************************************************
2758 * DocumentPropertiesW (WINSPOOL.166)
2759 */
2760LONG WIN32API DocumentPropertiesW(
2761 HWND hWnd,
2762 HANDLE hPrinter,
2763 LPWSTR pDeviceName,
2764 PDEVMODEW pDevModeOutput,
2765 PDEVMODEW pDevModeInput,
2766 DWORD fMode)
2767{
2768 LPSTR pDeviceNameA = HEAP_strdupWtoA(GetProcessHeap(),0,pDeviceName);
2769 LPDEVMODEA pDevModeInputA = DEVMODEdupWtoA(GetProcessHeap(),pDevModeInput);
2770 LPDEVMODEA pDevModeOutputA = NULL;
2771 LONG ret;
2772
2773 TRACE("(%p,%p,%s,%p,%p,%ld)\n",
2774 hWnd,hPrinter,debugstr_w(pDeviceName),pDevModeOutput,pDevModeInput,
2775 fMode);
2776 if(pDevModeOutput) {
2777 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, NULL, NULL, 0);
2778 if(ret < 0) return ret;
2779 pDevModeOutputA = (LPDEVMODEA)HeapAlloc(GetProcessHeap(), 0, ret);
2780 }
2781 ret = DocumentPropertiesA(hWnd, hPrinter, pDeviceNameA, pDevModeOutputA,
2782 pDevModeInputA, fMode);
2783 if(ret < 0) return ret;
2784
2785 if(pDevModeOutput) {
2786 DEVMODEcpyAtoW(pDevModeOutput, pDevModeOutputA);
2787 HeapFree(GetProcessHeap(),0,pDevModeOutputA);
2788 }
2789 if(fMode == 0 && ret > 0)
2790 ret += (CCHDEVICENAME + CCHFORMNAME);
2791 HeapFree(GetProcessHeap(),0,pDevModeInputA);
2792 HeapFree(GetProcessHeap(),0,pDeviceNameA);
2793 return ret;
2794}
2795
2796
2797
2798#ifdef __WIN32OS2__
2799
2800/**
2801 * Start a new printer job.
2802 *
2803 * @returns Print job identifier.
2804 * @returns 0 on failure with last error set.
2805 * @param hPrinter Handle to the printer object.
2806 * @param Level Structure level.
2807 * @param pDocInfo Pointer to structure.
2808 * @status partially implemented.
2809 * @author knut st. osmundsen <bird-srcspam@anduin.net>
2810 */
2811DWORD WIN32API StartDocPrinterA(
2812 HANDLE hPrinter,
2813 DWORD Level,
2814 LPBYTE pDocInfo)
2815{
2816 DWORD rc = 0;
2817 dprintf(("WINSPOOL: StartDocPrinterA\n"));
2818
2819 /*
2820 * Get printer instance data.
2821 */
2822 POPENPRINTER pPrt = openprinterFind(hPrinter);
2823 if (!pPrt)
2824 {
2825 dprintf(("WINSPOOL: StartDocPrinterA: Invalid handle %d\n", hPrinter));
2826 SetLastError(ERROR_INVALID_HANDLE);
2827 return 0;
2828 }
2829
2830 /*
2831 * Switch out based on input data.
2832 */
2833 switch (Level)
2834 {
2835 case 1:
2836 {
2837 PDOC_INFO_1A pDocInfoA = (PDOC_INFO_1A)pDocInfo;
2838 dprintf(("WINSPOOL: pDocName =%s\n", pDocInfoA->pDocName));
2839 dprintf(("WINSPOOL: pDatatype =%s\n", pDocInfoA->pDatatype));
2840 dprintf(("WINSPOOL: pOutputFile=%s\n", pDocInfoA->pOutputFile));
2841
2842 /*
2843 * Validate input.
2844 * ASSUMES: default is RAW as it is on OS/2.
2845 */
2846 if ( pDocInfoA->pDatatype
2847 && !strstr(pDocInfoA->pDatatype, "RAW"))
2848 {
2849 SetLastError(ERROR_INVALID_PARAMETER);
2850 dprintf(("WINSPOOL: data type not supported\n"));
2851 break;
2852 }
2853
2854 /*
2855 * Make sure the OS/2 spool file is opened.
2856 */
2857 int rcOs2 = openprinterOpenSpoolFile(pPrt);
2858 if (!rcOs2)
2859 {
2860 /*
2861 * Start the document.
2862 */
2863 if (OSLibSplQmStartDoc(pPrt->hspl, pDocInfoA->pDocName))
2864 {
2865 rc = (DWORD)pPrt->hspl; /** @todo get the proper job id! */
2866 pPrt->ulCurPage = 0; //reset current page counter
2867 dprintf(("WINSPOOL: StartDocPrinterA: returning jobid %d\n", rc));
2868 return rc;
2869 }
2870 else
2871 SetLastError(OSLibSplWinGetLastError()); /** @todo convert error code!!!!!!!! */
2872 }
2873 else
2874 SetLastError(rcOs2); /** @todo convert error code!!!!!!!! */
2875 break;
2876 }
2877
2878 default:
2879 dprintf(("WINSPOOL: level %d is not supported\n", Level));
2880 SetLastError(ERROR_INVALID_LEVEL); /* not verified. */
2881 break;
2882 }
2883 dprintf(("WINSPOOL: returning failure\n"));
2884 return 0;
2885}
2886
2887
2888/**
2889 * Start a new printer job.
2890 *
2891 * @returns Print job identifier.
2892 * @returns 0 on failure with last error set.
2893 * @param hPrinter Handle to the printer object.
2894 * @param Level Structure level.
2895 * @param pDocInfo Pointer to structure.
2896 * @status partially implemented.
2897 * @author knut st. osmundsen <bird-srcspam@anduin.net>
2898 */
2899DWORD WIN32API StartDocPrinterW(
2900 HANDLE hPrinter,
2901 DWORD Level,
2902 LPBYTE pDocInfo)
2903{
2904 DWORD rc = 0;
2905 dprintf(("WINSPOOL: StartDocPrinterW\n"));
2906 switch (Level)
2907 {
2908 case 1:
2909 {
2910 PDOC_INFO_1W pDocInfoW = (PDOC_INFO_1W)pDocInfo;
2911
2912 DOC_INFO_1A DocInfoA;
2913 DocInfoA.pDocName = UnicodeToAsciiString(pDocInfoW->pDocName);
2914 DocInfoA.pDatatype = UnicodeToAsciiString(pDocInfoW->pDatatype);
2915 DocInfoA.pOutputFile = UnicodeToAsciiString(pDocInfoW->pOutputFile);
2916 rc = StartDocPrinterA(hPrinter, Level, (LPBYTE)&DocInfoA);
2917 FreeAsciiString(DocInfoA.pOutputFile);
2918 FreeAsciiString(DocInfoA.pDatatype);
2919 FreeAsciiString(DocInfoA.pDocName);
2920 break;
2921 }
2922
2923 default:
2924 dprintf(("WINSPOOL: level %d is not supported\n", Level));
2925 SetLastError(ERROR_INVALID_LEVEL); /* not verified. */
2926 break;
2927 }
2928 dprintf(("WINSPOOL: returns %d\n", rc));
2929 return rc;
2930}
2931
2932
2933/**
2934 * Notifies the spooler that a new page is to be written to the
2935 * current printer job.
2936 *
2937 * This is an informational API without much significance I think.
2938 * The implementation assumes StartDocPrinterA/W() must be called first.
2939 *
2940 * @returns Success indicator. last error set on failure.
2941 * @param hPrinter Handle to printer object.
2942 * @status completely implemented.
2943 * @author knut st. osmundsen <bird-srcspam@anduin.net>
2944 */
2945BOOL WIN32API StartPagePrinter(HANDLE hPrinter)
2946{
2947 dprintf(("WINSPOOL: StartPagePrinter: hPrinter=%d\n", hPrinter));
2948 /*
2949 * Get printer instance data.
2950 */
2951 POPENPRINTER pPrt = openprinterFind(hPrinter);
2952 if (!pPrt)
2953 {
2954 dprintf(("WINSPOOL: StartPagePrinter: Invalid handle %d\n", hPrinter));
2955 SetLastError(ERROR_INVALID_HANDLE);
2956 return FALSE;
2957 }
2958
2959 /*
2960 * Not quite sure what should happen here if no StartDocPrinter was issued.
2961 * For now we'll just freak out.
2962 */
2963 if (!pPrt->hspl)
2964 {
2965 DebugAssertFailed(("StartPagePrinter called with no StartDocPrinter issued\n"));
2966 SetLastError(ERROR_INVALID_PRINTER_STATE); /** @todo test on w2k */
2967 return FALSE;
2968 }
2969
2970 if (OSLibSplQmNewPage(pPrt->hspl, pPrt->ulCurPage + 1))
2971 {
2972 pPrt->ulCurPage++;
2973 dprintf(("WINSPOOL: StartPagePrinter: returning successfully (ulCurPage=%lu)\n", pPrt->ulCurPage));
2974 return TRUE;
2975 }
2976
2977 /* failure */
2978 SetLastError(OSLibSplWinGetLastError()); /** @todo convert error code!!! */
2979 dprintf(("WINSPOOL: StartPagePrinter failed. last err=%#x\n", OSLibSplWinGetLastError()));
2980 return FALSE;
2981}
2982
2983
2984/**
2985 * Write raw data to printer.
2986 * @returns Successindicator. lasterr set on failure.
2987 * @param hPrinter Handle to printer object.
2988 * @param pBuf Pointer to the data to write.
2989 * @param cbBuf Size of the data to write.
2990 * @param pcWritten Where to put the number of bytes actually written.
2991 * @status partially implemented.
2992 * @author knut st. osmundsen <bird-srcspam@anduin.net>
2993 * @remark Current implementation relies on StartDocPrinterA/W being called first.
2994 */
2995BOOL WIN32API WritePrinter(HANDLE hPrinter, LPVOID pBuf, DWORD cbBuf, LPDWORD pcWritten)
2996{
2997 BOOL fRc = FALSE;
2998 dprintf(("WINSPOOL: WritePrinter hPrinter=%#x pBuf=%p cbBuf=%d pcWritten=%p\n",
2999 hPrinter, pBuf, cbBuf, pcWritten));
3000
3001 /*
3002 * Get printer instance data.
3003 */
3004 POPENPRINTER pPrt = openprinterFind(hPrinter);
3005 if (!pPrt)
3006 {
3007 dprintf(("WINSPOOL: WritePrinter: Invalid handle %d\n", hPrinter));
3008 SetLastError(ERROR_INVALID_HANDLE);
3009 return FALSE;
3010 }
3011
3012 /*
3013 * Not quite sure what should happen here if no StartDocPrinter was issued.
3014 * For now we'll just freak out.
3015 */
3016 if (!pPrt->hspl)
3017 {
3018 DebugAssertFailed(("WritePrinter called with no StartDocPrinter issued\n"));
3019 SetLastError(ERROR_INVALID_PRINTER_STATE); /** @todo test on w2k */
3020 return FALSE;
3021 }
3022
3023 /*
3024 * Push the data thru to the spooler.
3025 */
3026 if (OSLibSplQmWrite(pPrt->hspl, cbBuf, pBuf))
3027 {
3028 if (pcWritten)
3029 *pcWritten = cbBuf;
3030 dprintf(("WINSPOOL: WritePrinter succceeded writing %d bytes\n", cbBuf));
3031 return TRUE;
3032 }
3033
3034 /* failure */
3035 SetLastError(OSLibSplWinGetLastError()); /** @todo convert error code!!! */
3036 dprintf(("WINSPOOL: WritePrinter failed. last err=%#x\n", OSLibSplWinGetLastError()));
3037 return FALSE;
3038}
3039
3040
3041/**
3042 * Notifies the spooler that the writing of a page to the current
3043 * printer job is completed.
3044 *
3045 * This is an informational API without much significance I think.
3046 * The implementation assumes StartDocPrinterA/W() must be called first.
3047 *
3048 * @returns Success indicator, last error set on failure.
3049 * @param hPrinter Handle to printer object which job is to be ended (completed.
3050 * @status partially implemented
3051 * @author knut st. osmundsen <bird-srcspam@anduin.net>
3052 * @remark Current implementation relies on StartDocPrinterA/W being called first.
3053 */
3054BOOL WIN32API EndPagePrinter(HANDLE hPrinter)
3055{
3056 dprintf(("WINSPOOL: EndPagePrinter: hPrinter=%d\n", hPrinter));
3057
3058 /*
3059 * Get printer instance data.
3060 */
3061 POPENPRINTER pPrt = openprinterFind(hPrinter);
3062 if (!pPrt)
3063 {
3064 dprintf(("WINSPOOL: EndPagePrinter: Invalid handle %d\n", hPrinter));
3065 SetLastError(ERROR_INVALID_HANDLE);
3066 return FALSE;
3067 }
3068
3069 /*
3070 * Not quite sure what should happen here if no StartDocPrinter was issued.
3071 * For now we'll just freak out.
3072 */
3073 if (!pPrt->hspl)
3074 {
3075 DebugAssertFailed(("EndPagePrinter called with no StartDocPrinter issued\n"));
3076 SetLastError(ERROR_INVALID_PRINTER_STATE); /** @todo test on w2k */
3077 return FALSE;
3078 }
3079
3080 /* There is no OS/2 equivalent. */
3081 dprintf(("WINSPOOL: EndPagePrinter: returning successfully (ulCurPage=%lu)\n", pPrt->ulCurPage));
3082 return TRUE;
3083}
3084
3085
3086/**
3087 * Ends a printer job.
3088 *
3089 * @returns Success indicator, last error set on failure.
3090 * @param hPrinter Handle to printer object which job is to be ended (completed.
3091 * @status partially implemented
3092 * @author knut st. osmundsen <bird-srcspam@anduin.net>
3093 * @remark Current implementation relies on StartDocPrinterA/W being called first.
3094 */
3095BOOL WIN32API EndDocPrinter(HANDLE hPrinter)
3096{
3097 BOOL fRc = FALSE;
3098 dprintf(("WINSPOOL: WritePrinter hPrinter=%#x\n", hPrinter));
3099
3100 /*
3101 * Get printer instance data.
3102 */
3103 POPENPRINTER pPrt = openprinterFind(hPrinter);
3104 if (!pPrt)
3105 {
3106 dprintf(("WINSPOOL: WritePrinter: Invalid handle %d\n", hPrinter));
3107 SetLastError(ERROR_INVALID_HANDLE);
3108 return FALSE;
3109 }
3110
3111 /*
3112 * Not quite sure what should happen here if no StartDocPrinter was issued.
3113 * For now we'll just freak out.
3114 */
3115 if (!pPrt->hspl)
3116 {
3117 DebugAssertFailed(("EndDocPrinter called with no StartDocPrinter issued\n"));
3118 SetLastError(ERROR_INVALID_PRINTER_STATE); /** @todo test on w2k */
3119 return FALSE;
3120 }
3121
3122 /*
3123 * End the document, thus closing all Spl related stuff.
3124 */
3125 if (OSLibSplQmEndDoc(pPrt->hspl))
3126 {
3127 dprintf(("WINSPOOL: EndDocPrinter returns successfully\n"));
3128 return TRUE;
3129 }
3130
3131 SetLastError(OSLibSplWinGetLastError()); /** @todo convert error code!!! */
3132 dprintf(("WINSPOOL: EndDocPrinter returns failure\n"));
3133 return FALSE;
3134}
3135
3136
3137
3138/**
3139 * Setup the OS/2 Printer Information in the registry and profile.
3140 *
3141 * We will only enumerate local printer queues.
3142 *
3143 * The mapping between Odin32 and OS/2 is as follows:
3144 * Odin32 OS/2
3145 * Printer Name Queue Comment (WPS object title)
3146 * Driver Name Queue Name
3147 * Printer Comment Queue Comment (= WPS object title)
3148 * Printer Location Device Logical address (port sort of)
3149 * Printer Port Device Logical address (port sort of)
3150 *
3151 * On OS/2 only queue names are unique. It's very easy to make duplicate
3152 * printer names, just create printer objects in more than one WPS folder.
3153 * For duplicate names the queue name will be appended to the name in
3154 * paratheses so the user can actually print to both printers. (Odin32
3155 * only have a concept of printer names and they must thus be unique.)
3156 *
3157 * @returns Success indicator. May possibly have changed the last error on
3158 * both failure and success.
3159 *
3160 * @remark We're only enumerating local printers. This makes sense as remote
3161 * printers (on Lan Servers/Managers) isn't normally stored in the
3162 * registry (IIRC).
3163 */
3164BOOL ExportPrintersToRegistry(void)
3165{
3166 BOOL fRc = FALSE;
3167 DWORD cbNeeded;
3168 DWORD cUnused;
3169
3170 dprintf(("WINSPOOL: ExportPrintersToRegistry"));
3171
3172 /*
3173 * Get printers.
3174 */
3175 ULONG cQueues = 0;
3176 POSLIB_PRQINFO3 paQueues;
3177 paQueues = (POSLIB_PRQINFO3)OSLibSplEnumQueue(NULL, 3, &cQueues, &cUnused);
3178 if (paQueues)
3179 {
3180 /*
3181 * Get printer devices.
3182 */
3183 ULONG cDevices;
3184 POSLIB_PRDINFO3 paDevices;
3185 paDevices = (POSLIB_PRDINFO3)OSLibSplEnumDevice(NULL, 3, &cDevices, &cUnused);
3186 if (paDevices)
3187 {
3188 fRc = TRUE; /* getting this far is pretty much a success I'd say.... */
3189
3190 /*
3191 * Make printer WPS names (queue comment) unique by appending the
3192 * queuename for conflicting names.
3193 */
3194 unsigned i;
3195 char **papszNewNames = (char**)calloc(sizeof(char*), cQueues);
3196 for (i = 0; i < cQueues; i++)
3197 {
3198 char *psz = paQueues[i].pszComment;
3199 for (unsigned j = 0; j < cQueues; j++)
3200 if (j != i && !stricmp(paQueues[j].pszComment, psz))
3201 {
3202 dprintf(("duplicate printer names '%s'. appending queue name", psz));
3203 papszNewNames[i] = (char*)malloc(strlen(psz) + strlen(paQueues[i].pszName) + 4);
3204 sprintf(papszNewNames[i], "%s (%s)", psz, paQueues[i].pszName);
3205 paQueues[i].pszComment = papszNewNames[i];
3206
3207 papszNewNames[j] = (char*)malloc(strlen(psz) + strlen(paQueues[j].pszName) + 4);
3208 sprintf(papszNewNames[j], "%s (%s)", psz, paQueues[j].pszName);
3209 paQueues[j].pszComment = papszNewNames[j];
3210 }
3211 }
3212
3213 /*
3214 * Add the printers.
3215 */
3216 PRINTER_INFO_2A *papi2 = (PRINTER_INFO_2A *)calloc(cQueues, sizeof(PRINTER_INFO_2A));
3217 dprintf(("cQueues=%d cDevices=%d", cQueues, cDevices));
3218 for (i = 0; i < cQueues; i++)
3219 {
3220 /* Make printer driver. */
3221 DRIVER_INFO_3A di3 = {0};
3222 di3.cVersion = 0x400;
3223 #ifdef USE_OS2_DRIVERNAME
3224 char *pszDot = strchr(paQueues[i].pszDriverName, '.');
3225 if (pszDot && pszDot != paQueues[i].pszDriverName) /* we're very careful :-) */
3226 { /* split the driver name, getting something very similar to window.s */
3227 *pszDot++ = '\0';
3228 di3.pName = pszDot;
3229 di3.pDriverPath = paQueues[i].pszDriverName; /* This is important! */
3230 }
3231 else
3232 { /* bad printer driver name? try cover up. */
3233 di3.pName = paQueues[i].pszDriverName;
3234 di3.pDriverPath = "WINSPOOL"; /* This is important! */
3235 }
3236 #else
3237 di3.pName = paQueues[i].pszName; /* printer driver == queue name */
3238 di3.pDriverPath = "WINSPOOL"; /* This is important! */
3239 #endif
3240 di3.pEnvironment = NULL; /* NULL means auto */
3241 di3.pDataFile = "<datafile?>";
3242 di3.pConfigFile = "winodin.drv";
3243 di3.pHelpFile = "<helpfile?>";
3244 di3.pDependentFiles = "<dependend files?>";
3245 di3.pMonitorName = "<monitor name?>";
3246 di3.pDefaultDataType = "RAW";
3247 if (!AddPrinterDriverA(NULL, 3, (LPBYTE)&di3))
3248 {
3249 DebugAssertFailed(("Failed adding Driver (%ld)\n", GetLastError()));
3250 fRc = FALSE;
3251 }
3252
3253 /* Make printer. */
3254 papi2[i].pDatatype = "RAW";
3255 papi2[i].pPrintProcessor = "WinPrint";
3256 #ifdef USE_OS2_DRIVERNAME
3257 papi2[i].pComment = paQueues[i].pszName; /* Queue name. Don't allow any changes of the comment! */
3258 #else
3259 papi2[i].pComment = paQueues[i].pszComment; /* WPS printer name */
3260 #endif
3261 papi2[i].pDriverName = di3.pName;
3262 papi2[i].pParameters = "<parameters?>";
3263 papi2[i].pShareName = "<share name?>";
3264 papi2[i].pSepFile = "<sep file?>";
3265 #if 0 /* only 'local', remember */
3266 if (paPrinters[i].pszComputerName) /* this is currnetly not used as we only enum locals. */
3267 {
3268 papi2[i].Attributes |= PRINTER_ATTRIBUTE_NETWORK;
3269 papi2[i].pServerName = paPrinters[i].pszComputerName; /** @todo: format!! */
3270 }
3271 #endif
3272
3273 /*
3274 * We need to make sure the name is valid.
3275 * The registry decides what's illegal, slashes evedently are.
3276 */
3277 papi2[i].pPrinterName = paQueues[i].pszComment;
3278 char *psz = papi2[i].pPrinterName;
3279 while ((psz = strpbrk(psz, "/\\")) != NULL)
3280 *psz = '|'; /* change slashes to pipes... */
3281
3282
3283 /*
3284 * The queue pszPrinters member links with pszPrinterName of the device.
3285 * pszPrinters can contain several printer (device) names, separated by commas.
3286 * - We only handle the first printer listed. No idea how to get more than one
3287 * the anyway.
3288 */
3289 papi2[i].pLocation = "";
3290 papi2[i].pPortName = "";
3291 psz = strchr(paQueues[i].pszPrinters, ',');
3292 if (psz)
3293 *psz = '\0';
3294 for (unsigned k = 0; k < cDevices; k++)
3295 {
3296 if (!stricmp(paDevices[k].pszPrinterName, paQueues[i].pszPrinters))
3297 {
3298 papi2[i].pLocation = paDevices[k].pszLogAddr;
3299 papi2[i].pPortName = paDevices[k].pszLogAddr;
3300 break;
3301 }
3302 }
3303
3304 /*
3305 * Check if default printer and set attribute and write to profile.
3306 */
3307 if (paQueues[i].fsType & OSLIB_PRQ3_TYPE_APPDEFAULT)
3308 {
3309 char szWinDefPrn[256];
3310 dprintf(("Default printer %s,%s,%s", papi2[i].pPrinterName, papi2[i].pDriverName, papi2[i].pPortName));
3311 sprintf(szWinDefPrn, "%s,%s,%s", papi2[i].pPrinterName, papi2[i].pDriverName, papi2[i].pPortName);
3312 WriteProfileStringA("windows", "device", szWinDefPrn);
3313 papi2[i].Attributes |= PRINTER_ATTRIBUTE_DEFAULT;
3314 }
3315
3316 /*
3317 * Finally, we can add the printer
3318 */
3319 dprintf(("Add printer %s,%s,%s", papi2[i].pPrinterName, papi2[i].pDriverName, papi2[i].pPortName));
3320 if (!AddPrinterA(NULL, 2, (LPBYTE)&papi2[i]))
3321 {
3322 DebugAssert(GetLastError() == ERROR_PRINTER_ALREADY_EXISTS,
3323 ("AddPrinterA(%s) failed with rc=%ld\n", papi2[i].pPrinterName, GetLastError()));
3324 fRc = FALSE;
3325 }
3326 } /* loop thru printers */
3327
3328
3329 /*
3330 * Purge dead printers.
3331 * (It's important that we don't bail out before this when there is zero printers/devices!)
3332 */
3333 PPRINTER_INFO_2A pi2;
3334 DWORD cOdinPrinters = 0;
3335 cbNeeded = 0;
3336 if ( EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &cbNeeded, &cOdinPrinters)
3337 || GetLastError() == ERROR_INSUFFICIENT_BUFFER)
3338 {
3339 pi2 = (PPRINTER_INFO_2A)malloc(cbNeeded);
3340 if (EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 2, (LPBYTE)pi2, cbNeeded, &cbNeeded, &cOdinPrinters))
3341 {
3342 for (i = 0; i < cOdinPrinters; i++)
3343 {
3344 /* look if we added it */
3345 BOOL fFound = FALSE;
3346 for (unsigned j = 0; j < cQueues && !fFound; j++)
3347 fFound = !strcmp(papi2[j].pPrinterName,pi2[i].pPrinterName)
3348 && !strcmp(papi2[j].pDriverName, pi2[i].pDriverName)
3349 && !strcmp(papi2[j].pPortName, pi2[i].pPortName);
3350 /* nuke it */
3351 if (!fFound)
3352 {
3353 HANDLE hPrinter;
3354 if (OpenPrinterA(pi2[i].pPrinterName, &hPrinter, NULL) == TRUE)
3355 {
3356 dprintf(("Delete printer %s,%s,%s", papi2[i].pPrinterName, papi2[i].pDriverName, papi2[i].pPortName));
3357 DeletePrinter(hPrinter);
3358 ClosePrinter(hPrinter);
3359 }
3360 else
3361 {
3362 DebugAssertFailed(("Failed to open a printer returned by EnumPrintersA, %s\n",
3363 pi2[i].pPrinterName));
3364 fRc = FALSE;
3365 }
3366 }
3367 }
3368 }
3369 else
3370 {
3371 DebugAssertFailed(("EnumPrintersA failed!\n"));
3372 fRc = FALSE;
3373 }
3374 free(pi2);
3375 }
3376 else
3377 {
3378 DebugAssertFailed(("EnumPrintersA failed!\n"));
3379 fRc = FALSE;
3380 }
3381 free(papi2);
3382 free(paDevices);
3383 for (i = 0; i < cQueues; i++)
3384 if (papszNewNames[i])
3385 free(papszNewNames[i]);
3386 }
3387 else
3388 dprintf(("OSLibSplEnumDevice -> %d, cDevices=%d", fRc, cDevices));
3389 }
3390 else
3391 dprintf(("OSLibSplEnumPrinter failed\n"));
3392
3393 free(paQueues);
3394 dprintf(("ExportPrintersToRegistry returns %s", fRc ? "success" : "failure"));
3395 return fRc;
3396}
3397
3398#endif /* __WIN32OS2__ */
Note: See TracBrowser for help on using the repository browser.