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

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

Merge branch gcc-kmk to trunk.

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