Rob Shearman | de75fe0 | 2008-02-29 11:48:47 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Implementation of some printer driver bits |
| 3 | * |
| 4 | * Copyright 1996 John Harvey |
| 5 | * Copyright 1998 Huw Davies |
| 6 | * Copyright 1998 Andreas Mohr |
| 7 | * Copyright 1999 Klaas van Gend |
| 8 | * |
| 9 | * This library is free software; you can redistribute it and/or |
| 10 | * modify it under the terms of the GNU Lesser General Public |
| 11 | * License as published by the Free Software Foundation; either |
| 12 | * version 2.1 of the License, or (at your option) any later version. |
| 13 | * |
| 14 | * This library is distributed in the hope that it will be useful, |
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 17 | * Lesser General Public License for more details. |
| 18 | * |
| 19 | * You should have received a copy of the GNU Lesser General Public |
| 20 | * License along with this library; if not, write to the Free Software |
| 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| 22 | */ |
| 23 | |
| 24 | #include "config.h" |
| 25 | #include "wine/port.h" |
| 26 | |
| 27 | #include <stdarg.h> |
| 28 | #include <stdio.h> |
| 29 | #include <signal.h> |
| 30 | #include <stdlib.h> |
| 31 | #include <string.h> |
| 32 | #include <ctype.h> |
| 33 | #include <errno.h> |
| 34 | #ifdef HAVE_IO_H |
| 35 | # include <io.h> |
| 36 | #endif |
Ken Thomases | 6c8929f | 2011-11-30 16:49:06 -0600 | [diff] [blame] | 37 | #ifdef HAVE_SYS_WAIT_H |
| 38 | # include <sys/wait.h> |
| 39 | #endif |
Rob Shearman | de75fe0 | 2008-02-29 11:48:47 +0000 | [diff] [blame] | 40 | #ifdef HAVE_UNISTD_H |
| 41 | # include <unistd.h> |
| 42 | #endif |
| 43 | #include <fcntl.h> |
| 44 | #include "windef.h" |
| 45 | #include "winbase.h" |
| 46 | #include "winuser.h" |
| 47 | #include "wine/winbase16.h" |
| 48 | #include "wine/wingdi16.h" |
| 49 | #include "winspool.h" |
| 50 | #include "winerror.h" |
| 51 | #include "winreg.h" |
| 52 | #include "wownt32.h" |
| 53 | #include "wine/debug.h" |
Rob Shearman | de75fe0 | 2008-02-29 11:48:47 +0000 | [diff] [blame] | 54 | |
| 55 | WINE_DEFAULT_DEBUG_CHANNEL(print); |
| 56 | |
| 57 | static const char PrinterModel[] = "Printer Model"; |
| 58 | static const char DefaultDevMode[] = "Default DevMode"; |
| 59 | static const char PrinterDriverData[] = "PrinterDriverData"; |
| 60 | static const char Printers[] = "System\\CurrentControlSet\\Control\\Print\\Printers\\"; |
| 61 | |
Rob Shearman | de75fe0 | 2008-02-29 11:48:47 +0000 | [diff] [blame] | 62 | /****************** misc. printer related functions */ |
| 63 | |
| 64 | /* |
| 65 | * The following function should implement a queing system |
| 66 | */ |
| 67 | struct hpq |
| 68 | { |
| 69 | struct hpq *next; |
| 70 | int tag; |
| 71 | int key; |
| 72 | }; |
| 73 | |
| 74 | static struct hpq *hpqueue; |
| 75 | |
| 76 | /********************************************************************** |
| 77 | * CreatePQ (GDI.230) |
| 78 | * |
| 79 | */ |
| 80 | HPQ16 WINAPI CreatePQ16(INT16 size) |
| 81 | { |
| 82 | #if 0 |
| 83 | HGLOBAL16 hpq = 0; |
| 84 | WORD tmp_size; |
| 85 | LPWORD pPQ; |
| 86 | |
| 87 | tmp_size = size << 2; |
| 88 | if (!(hpq = GlobalAlloc16(GMEM_SHARE|GMEM_MOVEABLE, tmp_size + 8))) |
| 89 | return 0xffff; |
| 90 | pPQ = GlobalLock16(hpq); |
| 91 | *pPQ++ = 0; |
| 92 | *pPQ++ = tmp_size; |
| 93 | *pPQ++ = 0; |
| 94 | *pPQ++ = 0; |
| 95 | GlobalUnlock16(hpq); |
| 96 | |
| 97 | return (HPQ16)hpq; |
| 98 | #else |
| 99 | FIXME("(%d): stub\n",size); |
| 100 | return 1; |
| 101 | #endif |
| 102 | } |
| 103 | |
| 104 | /********************************************************************** |
| 105 | * DeletePQ (GDI.235) |
| 106 | * |
| 107 | */ |
| 108 | INT16 WINAPI DeletePQ16(HPQ16 hPQ) |
| 109 | { |
| 110 | return GlobalFree16(hPQ); |
| 111 | } |
| 112 | |
| 113 | /********************************************************************** |
| 114 | * ExtractPQ (GDI.232) |
| 115 | * |
| 116 | */ |
| 117 | INT16 WINAPI ExtractPQ16(HPQ16 hPQ) |
| 118 | { |
| 119 | struct hpq *queue, *prev, *current, *currentPrev; |
| 120 | int key = 0, tag = -1; |
Frédéric Delanoy | fccb440 | 2011-07-06 10:34:43 +0200 | [diff] [blame] | 121 | prev = NULL; |
Rob Shearman | de75fe0 | 2008-02-29 11:48:47 +0000 | [diff] [blame] | 122 | queue = current = hpqueue; |
| 123 | if (current) |
| 124 | key = current->key; |
| 125 | |
| 126 | while (current) |
| 127 | { |
| 128 | currentPrev = current; |
| 129 | current = current->next; |
| 130 | if (current) |
| 131 | { |
| 132 | if (current->key < key) |
| 133 | { |
| 134 | queue = current; |
| 135 | prev = currentPrev; |
| 136 | } |
| 137 | } |
| 138 | } |
| 139 | if (queue) |
| 140 | { |
| 141 | tag = queue->tag; |
| 142 | |
| 143 | if (prev) |
| 144 | prev->next = queue->next; |
| 145 | else |
| 146 | hpqueue = queue->next; |
| 147 | HeapFree(GetProcessHeap(), 0, queue); |
| 148 | } |
| 149 | |
| 150 | TRACE("%x got tag %d key %d\n", hPQ, tag, key); |
| 151 | |
| 152 | return tag; |
| 153 | } |
| 154 | |
| 155 | /********************************************************************** |
| 156 | * InsertPQ (GDI.233) |
| 157 | * |
| 158 | */ |
| 159 | INT16 WINAPI InsertPQ16(HPQ16 hPQ, INT16 tag, INT16 key) |
| 160 | { |
| 161 | struct hpq *queueItem = HeapAlloc(GetProcessHeap(), 0, sizeof(struct hpq)); |
| 162 | if(queueItem == NULL) { |
| 163 | ERR("Memory exausted!\n"); |
| 164 | return FALSE; |
| 165 | } |
| 166 | queueItem->next = hpqueue; |
| 167 | hpqueue = queueItem; |
| 168 | queueItem->key = key; |
| 169 | queueItem->tag = tag; |
| 170 | |
| 171 | FIXME("(%x %d %d): stub???\n", hPQ, tag, key); |
| 172 | return TRUE; |
| 173 | } |
| 174 | |
| 175 | /********************************************************************** |
| 176 | * MinPQ (GDI.231) |
| 177 | * |
| 178 | */ |
| 179 | INT16 WINAPI MinPQ16(HPQ16 hPQ) |
| 180 | { |
| 181 | FIXME("(%x): stub\n", hPQ); |
| 182 | return 0; |
| 183 | } |
| 184 | |
| 185 | /********************************************************************** |
| 186 | * SizePQ (GDI.234) |
| 187 | * |
| 188 | */ |
| 189 | INT16 WINAPI SizePQ16(HPQ16 hPQ, INT16 sizechange) |
| 190 | { |
| 191 | FIXME("(%x %d): stub\n", hPQ, sizechange); |
| 192 | return -1; |
| 193 | } |
| 194 | |
| 195 | |
| 196 | |
| 197 | /* |
| 198 | * The following functions implement part of the spooling process to |
| 199 | * print manager. I would like to see wine have a version of print managers |
| 200 | * that used LPR/LPD. For simplicity print jobs will be sent to a file for |
| 201 | * now. |
| 202 | */ |
| 203 | typedef struct PRINTJOB |
| 204 | { |
| 205 | char *pszOutput; |
| 206 | char *pszTitle; |
| 207 | HDC16 hDC; |
| 208 | HANDLE16 hHandle; |
| 209 | int nIndex; |
| 210 | int fd; |
Ken Thomases | 6c8929f | 2011-11-30 16:49:06 -0600 | [diff] [blame] | 211 | pid_t pid; |
Rob Shearman | de75fe0 | 2008-02-29 11:48:47 +0000 | [diff] [blame] | 212 | } PRINTJOB, *PPRINTJOB; |
| 213 | |
| 214 | #define MAX_PRINT_JOBS 1 |
| 215 | #define SP_OK 1 |
| 216 | |
| 217 | static PPRINTJOB gPrintJobsTable[MAX_PRINT_JOBS]; |
| 218 | |
| 219 | |
| 220 | static PPRINTJOB FindPrintJobFromHandle(HANDLE16 hHandle) |
| 221 | { |
| 222 | return gPrintJobsTable[0]; |
| 223 | } |
| 224 | |
Ken Thomases | 6c8929f | 2011-11-30 16:49:06 -0600 | [diff] [blame] | 225 | static int CreateSpoolFile(LPCSTR pszOutput, pid_t *out_pid) |
Rob Shearman | de75fe0 | 2008-02-29 11:48:47 +0000 | [diff] [blame] | 226 | { |
| 227 | int fd=-1; |
| 228 | char psCmd[1024]; |
| 229 | const char *psCmdP = psCmd; |
| 230 | HKEY hkey; |
| 231 | |
| 232 | /* TTD convert the 'output device' into a spool file name */ |
| 233 | |
Ken Thomases | 6c8929f | 2011-11-30 16:49:06 -0600 | [diff] [blame] | 234 | if (pszOutput == NULL || *pszOutput == '\0' || out_pid == NULL) |
Rob Shearman | de75fe0 | 2008-02-29 11:48:47 +0000 | [diff] [blame] | 235 | return -1; |
| 236 | |
Ken Thomases | 6c8929f | 2011-11-30 16:49:06 -0600 | [diff] [blame] | 237 | *out_pid = -1; |
| 238 | |
Rob Shearman | de75fe0 | 2008-02-29 11:48:47 +0000 | [diff] [blame] | 239 | psCmd[0] = 0; |
| 240 | /* @@ Wine registry key: HKCU\Software\Wine\Printing\Spooler */ |
| 241 | if(!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Printing\\Spooler", &hkey)) |
| 242 | { |
| 243 | DWORD type, count = sizeof(psCmd); |
| 244 | RegQueryValueExA(hkey, pszOutput, 0, &type, (LPBYTE)psCmd, &count); |
| 245 | RegCloseKey(hkey); |
| 246 | } |
| 247 | if (!psCmd[0] && !strncmp("LPR:",pszOutput,4)) |
| 248 | sprintf(psCmd,"|lpr -P'%s'",pszOutput+4); |
| 249 | |
| 250 | TRACE("Got printerSpoolCommand '%s' for output device '%s'\n", |
| 251 | psCmd, pszOutput); |
| 252 | if (!*psCmd) |
| 253 | psCmdP = pszOutput; |
| 254 | else |
| 255 | { |
| 256 | while (*psCmdP && isspace(*psCmdP)) |
| 257 | { |
| 258 | psCmdP++; |
| 259 | } |
| 260 | if (!*psCmdP) |
| 261 | return -1; |
| 262 | } |
| 263 | TRACE("command: '%s'\n", psCmdP); |
| 264 | #ifdef HAVE_FORK |
| 265 | if (*psCmdP == '|') |
| 266 | { |
| 267 | int fds[2]; |
| 268 | if (pipe(fds)) { |
| 269 | ERR("pipe() failed!\n"); |
| 270 | return -1; |
| 271 | } |
Ken Thomases | 6c8929f | 2011-11-30 16:49:06 -0600 | [diff] [blame] | 272 | if ((*out_pid = fork()) == 0) |
Rob Shearman | de75fe0 | 2008-02-29 11:48:47 +0000 | [diff] [blame] | 273 | { |
| 274 | psCmdP++; |
| 275 | |
| 276 | TRACE("In child need to exec %s\n",psCmdP); |
| 277 | close(0); |
| 278 | dup2(fds[0],0); |
| 279 | close (fds[1]); |
| 280 | |
| 281 | /* reset signals that we previously set to SIG_IGN */ |
| 282 | signal( SIGPIPE, SIG_DFL ); |
Rob Shearman | de75fe0 | 2008-02-29 11:48:47 +0000 | [diff] [blame] | 283 | |
Michael Stefaniuc | ec1c949 | 2008-11-25 10:14:23 +0100 | [diff] [blame] | 284 | execl("/bin/sh", "/bin/sh", "-c", psCmdP, NULL); |
Rob Shearman | de75fe0 | 2008-02-29 11:48:47 +0000 | [diff] [blame] | 285 | _exit(1); |
| 286 | |
| 287 | } |
| 288 | close (fds[0]); |
| 289 | fd = fds[1]; |
| 290 | TRACE("Need to execute a cmnd and pipe the output to it\n"); |
| 291 | } |
| 292 | else |
| 293 | #endif |
| 294 | { |
| 295 | char *buffer; |
| 296 | WCHAR psCmdPW[MAX_PATH]; |
| 297 | |
| 298 | TRACE("Just assume it's a file\n"); |
| 299 | |
| 300 | /** |
| 301 | * The file name can be dos based, we have to find its |
Austin English | 45b944e | 2008-03-25 12:35:45 -0500 | [diff] [blame] | 302 | * corresponding Unix file name. |
Rob Shearman | de75fe0 | 2008-02-29 11:48:47 +0000 | [diff] [blame] | 303 | */ |
| 304 | MultiByteToWideChar(CP_ACP, 0, psCmdP, -1, psCmdPW, MAX_PATH); |
| 305 | if ((buffer = wine_get_unix_file_name(psCmdPW))) |
| 306 | { |
| 307 | if ((fd = open(buffer, O_CREAT | O_TRUNC | O_WRONLY, 0666)) < 0) |
| 308 | { |
| 309 | ERR("Failed to create spool file '%s' ('%s'). (error %s)\n", |
| 310 | buffer, psCmdP, strerror(errno)); |
| 311 | } |
| 312 | HeapFree(GetProcessHeap(), 0, buffer); |
| 313 | } |
| 314 | } |
| 315 | return fd; |
| 316 | } |
| 317 | |
| 318 | static int FreePrintJob(HANDLE16 hJob) |
| 319 | { |
| 320 | int nRet = SP_ERROR; |
| 321 | PPRINTJOB pPrintJob; |
| 322 | |
| 323 | pPrintJob = FindPrintJobFromHandle(hJob); |
| 324 | if (pPrintJob != NULL) |
| 325 | { |
Ken Thomases | 6c8929f | 2011-11-30 16:49:06 -0600 | [diff] [blame] | 326 | nRet = SP_OK; |
Rob Shearman | de75fe0 | 2008-02-29 11:48:47 +0000 | [diff] [blame] | 327 | gPrintJobsTable[pPrintJob->nIndex] = NULL; |
| 328 | HeapFree(GetProcessHeap(), 0, pPrintJob->pszOutput); |
| 329 | HeapFree(GetProcessHeap(), 0, pPrintJob->pszTitle); |
| 330 | if (pPrintJob->fd >= 0) close(pPrintJob->fd); |
Ken Thomases | 6c8929f | 2011-11-30 16:49:06 -0600 | [diff] [blame] | 331 | if (pPrintJob->pid > 0) |
| 332 | { |
| 333 | pid_t wret; |
| 334 | int status; |
| 335 | do { |
| 336 | wret = waitpid(pPrintJob->pid, &status, 0); |
| 337 | } while (wret < 0 && errno == EINTR); |
| 338 | if (wret < 0 || !WIFEXITED(status) || WEXITSTATUS(status)) |
| 339 | nRet = SP_ERROR; |
| 340 | } |
Rob Shearman | de75fe0 | 2008-02-29 11:48:47 +0000 | [diff] [blame] | 341 | HeapFree(GetProcessHeap(), 0, pPrintJob); |
Rob Shearman | de75fe0 | 2008-02-29 11:48:47 +0000 | [diff] [blame] | 342 | } |
| 343 | return nRet; |
| 344 | } |
| 345 | |
| 346 | /********************************************************************** |
| 347 | * OpenJob (GDI.240) |
| 348 | * |
| 349 | */ |
| 350 | HPJOB16 WINAPI OpenJob16(LPCSTR lpOutput, LPCSTR lpTitle, HDC16 hDC) |
| 351 | { |
| 352 | HPJOB16 hHandle = (HPJOB16)SP_ERROR; |
| 353 | PPRINTJOB pPrintJob; |
| 354 | |
| 355 | TRACE("'%s' '%s' %04x\n", lpOutput, lpTitle, hDC); |
| 356 | |
| 357 | pPrintJob = gPrintJobsTable[0]; |
| 358 | if (pPrintJob == NULL) |
| 359 | { |
| 360 | int fd; |
Ken Thomases | 6c8929f | 2011-11-30 16:49:06 -0600 | [diff] [blame] | 361 | pid_t pid; |
Rob Shearman | de75fe0 | 2008-02-29 11:48:47 +0000 | [diff] [blame] | 362 | |
| 363 | /* Try and create a spool file */ |
Ken Thomases | 6c8929f | 2011-11-30 16:49:06 -0600 | [diff] [blame] | 364 | fd = CreateSpoolFile(lpOutput, &pid); |
Rob Shearman | de75fe0 | 2008-02-29 11:48:47 +0000 | [diff] [blame] | 365 | if (fd >= 0) |
| 366 | { |
| 367 | pPrintJob = HeapAlloc(GetProcessHeap(), 0, sizeof(PRINTJOB)); |
| 368 | if(pPrintJob == NULL) { |
| 369 | WARN("Memory exausted!\n"); |
| 370 | return hHandle; |
| 371 | } |
| 372 | |
| 373 | hHandle = 1; |
| 374 | |
| 375 | pPrintJob->pszOutput = HeapAlloc(GetProcessHeap(), 0, strlen(lpOutput)+1); |
| 376 | strcpy( pPrintJob->pszOutput, lpOutput ); |
| 377 | if(lpTitle) |
| 378 | { |
| 379 | pPrintJob->pszTitle = HeapAlloc(GetProcessHeap(), 0, strlen(lpTitle)+1); |
| 380 | strcpy( pPrintJob->pszTitle, lpTitle ); |
| 381 | } |
| 382 | pPrintJob->hDC = hDC; |
| 383 | pPrintJob->fd = fd; |
Ken Thomases | 6c8929f | 2011-11-30 16:49:06 -0600 | [diff] [blame] | 384 | pPrintJob->pid = pid; |
Rob Shearman | de75fe0 | 2008-02-29 11:48:47 +0000 | [diff] [blame] | 385 | pPrintJob->nIndex = 0; |
| 386 | pPrintJob->hHandle = hHandle; |
| 387 | gPrintJobsTable[pPrintJob->nIndex] = pPrintJob; |
| 388 | } |
| 389 | } |
| 390 | TRACE("return %04x\n", hHandle); |
| 391 | return hHandle; |
| 392 | } |
| 393 | |
| 394 | /********************************************************************** |
| 395 | * CloseJob (GDI.243) |
| 396 | * |
| 397 | */ |
| 398 | INT16 WINAPI CloseJob16(HPJOB16 hJob) |
| 399 | { |
| 400 | int nRet = SP_ERROR; |
Ken Thomases | 96720df | 2012-03-14 15:12:17 -0500 | [diff] [blame] | 401 | PPRINTJOB pPrintJob; |
Rob Shearman | de75fe0 | 2008-02-29 11:48:47 +0000 | [diff] [blame] | 402 | |
| 403 | TRACE("%04x\n", hJob); |
| 404 | |
| 405 | pPrintJob = FindPrintJobFromHandle(hJob); |
| 406 | if (pPrintJob != NULL) |
| 407 | { |
Rob Shearman | de75fe0 | 2008-02-29 11:48:47 +0000 | [diff] [blame] | 408 | FreePrintJob(hJob); |
| 409 | nRet = 1; |
| 410 | } |
| 411 | return nRet; |
| 412 | } |
| 413 | |
| 414 | /********************************************************************** |
| 415 | * WriteSpool (GDI.241) |
| 416 | * |
| 417 | */ |
| 418 | INT16 WINAPI WriteSpool16(HPJOB16 hJob, LPSTR lpData, INT16 cch) |
| 419 | { |
| 420 | int nRet = SP_ERROR; |
Ken Thomases | 96720df | 2012-03-14 15:12:17 -0500 | [diff] [blame] | 421 | PPRINTJOB pPrintJob; |
Rob Shearman | de75fe0 | 2008-02-29 11:48:47 +0000 | [diff] [blame] | 422 | |
| 423 | TRACE("%04x %p %04x\n", hJob, lpData, cch); |
| 424 | |
| 425 | pPrintJob = FindPrintJobFromHandle(hJob); |
| 426 | if (pPrintJob != NULL && pPrintJob->fd >= 0 && cch) |
| 427 | { |
| 428 | if (write(pPrintJob->fd, lpData, cch) != cch) |
| 429 | nRet = SP_OUTOFDISK; |
| 430 | else |
| 431 | nRet = cch; |
| 432 | #if 0 |
| 433 | /* FIXME: We just cannot call 16 bit functions from here, since we |
| 434 | * have acquired several locks (DC). And we do not really need to. |
| 435 | */ |
| 436 | if (pPrintJob->hDC == 0) { |
| 437 | TRACE("hDC == 0 so no QueryAbort\n"); |
| 438 | } |
| 439 | else if (!(QueryAbort16(pPrintJob->hDC, (nRet == SP_OUTOFDISK) ? nRet : 0 ))) |
| 440 | { |
| 441 | CloseJob16(hJob); /* printing aborted */ |
| 442 | nRet = SP_APPABORT; |
| 443 | } |
| 444 | #endif |
| 445 | } |
| 446 | return nRet; |
| 447 | } |
| 448 | |
| 449 | typedef INT (WINAPI *MSGBOX_PROC)( HWND, LPCSTR, LPCSTR, UINT ); |
| 450 | |
| 451 | /********************************************************************** |
| 452 | * WriteDialog (GDI.242) |
| 453 | * |
| 454 | */ |
| 455 | INT16 WINAPI WriteDialog16(HPJOB16 hJob, LPSTR lpMsg, INT16 cchMsg) |
| 456 | { |
| 457 | HMODULE mod; |
| 458 | MSGBOX_PROC pMessageBoxA; |
| 459 | INT16 ret = 0; |
| 460 | |
| 461 | TRACE("%04x %04x '%s'\n", hJob, cchMsg, lpMsg); |
| 462 | |
| 463 | if ((mod = GetModuleHandleA("user32.dll"))) |
| 464 | { |
| 465 | if ((pMessageBoxA = (MSGBOX_PROC)GetProcAddress( mod, "MessageBoxA" ))) |
| 466 | ret = pMessageBoxA(0, lpMsg, "Printing Error", MB_OKCANCEL); |
| 467 | } |
| 468 | return ret; |
| 469 | } |
| 470 | |
| 471 | |
| 472 | /********************************************************************** |
| 473 | * DeleteJob (GDI.244) |
| 474 | * |
| 475 | */ |
| 476 | INT16 WINAPI DeleteJob16(HPJOB16 hJob, INT16 nNotUsed) |
| 477 | { |
| 478 | int nRet; |
| 479 | |
| 480 | TRACE("%04x\n", hJob); |
| 481 | |
| 482 | nRet = FreePrintJob(hJob); |
| 483 | return nRet; |
| 484 | } |
| 485 | |
| 486 | /* |
| 487 | * The following two function would allow a page to be sent to the printer |
| 488 | * when it has been processed. For simplicity they haven't been implemented. |
| 489 | * This means a whole job has to be processed before it is sent to the printer. |
| 490 | */ |
| 491 | |
| 492 | /********************************************************************** |
| 493 | * StartSpoolPage (GDI.246) |
| 494 | * |
| 495 | */ |
| 496 | INT16 WINAPI StartSpoolPage16(HPJOB16 hJob) |
| 497 | { |
| 498 | FIXME("StartSpoolPage GDI.246 unimplemented\n"); |
| 499 | return 1; |
| 500 | |
| 501 | } |
| 502 | |
| 503 | |
| 504 | /********************************************************************** |
| 505 | * EndSpoolPage (GDI.247) |
| 506 | * |
| 507 | */ |
| 508 | INT16 WINAPI EndSpoolPage16(HPJOB16 hJob) |
| 509 | { |
| 510 | FIXME("EndSpoolPage GDI.247 unimplemented\n"); |
| 511 | return 1; |
| 512 | } |
| 513 | |
| 514 | |
| 515 | /********************************************************************** |
| 516 | * GetSpoolJob (GDI.245) |
| 517 | * |
| 518 | */ |
| 519 | DWORD WINAPI GetSpoolJob16(int nOption, LONG param) |
| 520 | { |
| 521 | DWORD retval = 0; |
| 522 | TRACE("In GetSpoolJob param 0x%x noption %d\n",param, nOption); |
| 523 | return retval; |
| 524 | } |
| 525 | |
| 526 | |
| 527 | /****************************************************************** |
| 528 | * DrvGetPrinterDataInternal |
| 529 | * |
| 530 | * Helper for DrvGetPrinterData |
| 531 | */ |
Andrew Talbot | 73efb62 | 2010-10-03 10:13:41 +0100 | [diff] [blame] | 532 | static DWORD DrvGetPrinterDataInternal(LPCSTR RegStr_Printer, |
Rob Shearman | de75fe0 | 2008-02-29 11:48:47 +0000 | [diff] [blame] | 533 | LPBYTE lpPrinterData, int cbData, int what) |
| 534 | { |
| 535 | DWORD res = -1; |
| 536 | HKEY hkey; |
| 537 | DWORD dwType, cbQueryData; |
| 538 | |
| 539 | if (!(RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey))) { |
| 540 | if (what == INT_PD_DEFAULT_DEVMODE) { /* "Default DevMode" */ |
| 541 | if (!(RegQueryValueExA(hkey, DefaultDevMode, 0, &dwType, 0, &cbQueryData))) { |
| 542 | if (!lpPrinterData) |
| 543 | res = cbQueryData; |
| 544 | else if ((cbQueryData) && (cbQueryData <= cbData)) { |
| 545 | cbQueryData = cbData; |
| 546 | if (RegQueryValueExA(hkey, DefaultDevMode, 0, |
| 547 | &dwType, lpPrinterData, &cbQueryData)) |
| 548 | res = cbQueryData; |
| 549 | } |
| 550 | } |
| 551 | } else { /* "Printer Driver" */ |
| 552 | cbQueryData = 32; |
| 553 | RegQueryValueExA(hkey, "Printer Driver", 0, |
| 554 | &dwType, lpPrinterData, &cbQueryData); |
| 555 | res = cbQueryData; |
| 556 | } |
| 557 | } |
| 558 | if (hkey) RegCloseKey(hkey); |
| 559 | return res; |
| 560 | } |
| 561 | |
| 562 | /****************************************************************** |
| 563 | * DrvGetPrinterData (GDI.282) |
| 564 | * |
| 565 | */ |
| 566 | DWORD WINAPI DrvGetPrinterData16(LPSTR lpPrinter, LPSTR lpProfile, |
| 567 | LPDWORD lpType, LPBYTE lpPrinterData, |
| 568 | int cbData, LPDWORD lpNeeded) |
| 569 | { |
| 570 | LPSTR RegStr_Printer; |
| 571 | HKEY hkey = 0, hkey2 = 0; |
| 572 | DWORD res = 0; |
| 573 | DWORD dwType, PrinterAttr, cbPrinterAttr, SetData, size; |
| 574 | |
| 575 | if (HIWORD(lpPrinter)) |
| 576 | TRACE("printer %s\n",lpPrinter); |
| 577 | else |
| 578 | TRACE("printer %p\n",lpPrinter); |
| 579 | if (HIWORD(lpProfile)) |
| 580 | TRACE("profile %s\n",lpProfile); |
| 581 | else |
| 582 | TRACE("profile %p\n",lpProfile); |
| 583 | TRACE("lpType %p\n",lpType); |
| 584 | |
| 585 | if ((!lpPrinter) || (!lpProfile) || (!lpNeeded)) |
| 586 | return ERROR_INVALID_PARAMETER; |
| 587 | |
| 588 | RegStr_Printer = HeapAlloc(GetProcessHeap(), 0, |
| 589 | strlen(Printers) + strlen(lpPrinter) + 2); |
| 590 | strcpy(RegStr_Printer, Printers); |
| 591 | strcat(RegStr_Printer, lpPrinter); |
| 592 | |
| 593 | if ((PtrToUlong(lpProfile) == INT_PD_DEFAULT_DEVMODE) || (HIWORD(lpProfile) && |
| 594 | (!strcmp(lpProfile, DefaultDevMode)))) { |
| 595 | size = DrvGetPrinterDataInternal(RegStr_Printer, lpPrinterData, cbData, |
| 596 | INT_PD_DEFAULT_DEVMODE); |
| 597 | if (size+1) { |
| 598 | *lpNeeded = size; |
| 599 | if ((lpPrinterData) && (*lpNeeded > cbData)) |
| 600 | res = ERROR_MORE_DATA; |
| 601 | } |
| 602 | else res = ERROR_INVALID_PRINTER_NAME; |
| 603 | } |
| 604 | else |
| 605 | if ((PtrToUlong(lpProfile) == INT_PD_DEFAULT_MODEL) || (HIWORD(lpProfile) && |
| 606 | (!strcmp(lpProfile, PrinterModel)))) { |
| 607 | *lpNeeded = 32; |
| 608 | if (!lpPrinterData) goto failed; |
| 609 | if (cbData < 32) { |
| 610 | res = ERROR_MORE_DATA; |
| 611 | goto failed; |
| 612 | } |
| 613 | size = DrvGetPrinterDataInternal(RegStr_Printer, lpPrinterData, cbData, |
| 614 | INT_PD_DEFAULT_MODEL); |
| 615 | if ((size+1) && (lpType)) |
| 616 | *lpType = REG_SZ; |
| 617 | else |
| 618 | res = ERROR_INVALID_PRINTER_NAME; |
| 619 | } |
| 620 | else |
| 621 | { |
| 622 | if ((res = RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey))) |
| 623 | goto failed; |
| 624 | cbPrinterAttr = 4; |
| 625 | if ((res = RegQueryValueExA(hkey, "Attributes", 0, |
| 626 | &dwType, (LPBYTE)&PrinterAttr, &cbPrinterAttr))) |
| 627 | goto failed; |
| 628 | if ((res = RegOpenKeyA(hkey, PrinterDriverData, &hkey2))) |
| 629 | goto failed; |
| 630 | *lpNeeded = cbData; |
| 631 | res = RegQueryValueExA(hkey2, lpProfile, 0, |
| 632 | lpType, lpPrinterData, lpNeeded); |
| 633 | if ((res != ERROR_CANTREAD) && |
| 634 | ((PrinterAttr & |
| 635 | (PRINTER_ATTRIBUTE_ENABLE_BIDI|PRINTER_ATTRIBUTE_NETWORK)) |
| 636 | == PRINTER_ATTRIBUTE_NETWORK)) |
| 637 | { |
| 638 | if (!(res) && (*lpType == REG_DWORD) && (*(LPDWORD)lpPrinterData == -1)) |
| 639 | res = ERROR_INVALID_DATA; |
| 640 | } |
| 641 | else |
| 642 | { |
| 643 | SetData = -1; |
| 644 | RegSetValueExA(hkey2, lpProfile, 0, REG_DWORD, (LPBYTE)&SetData, 4); /* no result returned */ |
| 645 | } |
| 646 | } |
| 647 | |
| 648 | failed: |
| 649 | if (hkey2) RegCloseKey(hkey2); |
| 650 | if (hkey) RegCloseKey(hkey); |
| 651 | HeapFree(GetProcessHeap(), 0, RegStr_Printer); |
| 652 | return res; |
| 653 | } |
| 654 | |
| 655 | |
| 656 | /****************************************************************** |
| 657 | * DrvSetPrinterData (GDI.281) |
| 658 | * |
| 659 | */ |
| 660 | DWORD WINAPI DrvSetPrinterData16(LPSTR lpPrinter, LPSTR lpProfile, |
| 661 | DWORD lpType, LPBYTE lpPrinterData, |
| 662 | DWORD dwSize) |
| 663 | { |
| 664 | LPSTR RegStr_Printer; |
| 665 | HKEY hkey = 0; |
| 666 | DWORD res = 0; |
| 667 | |
| 668 | if (HIWORD(lpPrinter)) |
| 669 | TRACE("printer %s\n",lpPrinter); |
| 670 | else |
| 671 | TRACE("printer %p\n",lpPrinter); |
| 672 | if (HIWORD(lpProfile)) |
| 673 | TRACE("profile %s\n",lpProfile); |
| 674 | else |
| 675 | TRACE("profile %p\n",lpProfile); |
| 676 | TRACE("lpType %08x\n",lpType); |
| 677 | |
| 678 | if ((!lpPrinter) || (!lpProfile) || |
| 679 | (PtrToUlong(lpProfile) == INT_PD_DEFAULT_MODEL) || (HIWORD(lpProfile) && |
| 680 | (!strcmp(lpProfile, PrinterModel)))) |
| 681 | return ERROR_INVALID_PARAMETER; |
| 682 | |
| 683 | RegStr_Printer = HeapAlloc(GetProcessHeap(), 0, |
| 684 | strlen(Printers) + strlen(lpPrinter) + 2); |
| 685 | strcpy(RegStr_Printer, Printers); |
| 686 | strcat(RegStr_Printer, lpPrinter); |
| 687 | |
| 688 | if ((PtrToUlong(lpProfile) == INT_PD_DEFAULT_DEVMODE) || (HIWORD(lpProfile) && |
| 689 | (!strcmp(lpProfile, DefaultDevMode)))) { |
| 690 | if ( RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey) |
| 691 | != ERROR_SUCCESS || |
| 692 | RegSetValueExA(hkey, DefaultDevMode, 0, REG_BINARY, |
| 693 | lpPrinterData, dwSize) != ERROR_SUCCESS ) |
| 694 | res = ERROR_INVALID_PRINTER_NAME; |
| 695 | } |
| 696 | else |
| 697 | { |
| 698 | strcat(RegStr_Printer, "\\"); |
| 699 | |
| 700 | if( (res = RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey)) == |
| 701 | ERROR_SUCCESS ) { |
| 702 | |
| 703 | if (!lpPrinterData) |
| 704 | res = RegDeleteValueA(hkey, lpProfile); |
| 705 | else |
| 706 | res = RegSetValueExA(hkey, lpProfile, 0, lpType, |
| 707 | lpPrinterData, dwSize); |
| 708 | } |
| 709 | } |
| 710 | |
| 711 | if (hkey) RegCloseKey(hkey); |
| 712 | HeapFree(GetProcessHeap(), 0, RegStr_Printer); |
| 713 | return res; |
| 714 | } |