| /* | |
| * Implementation of some printer driver bits | |
| * | |
| * Copyright 1996 John Harvey | |
| * Copyright 1998 Huw Davies | |
| * Copyright 1998 Andreas Mohr | |
| * Copyright 1999 Klaas van Gend | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
| */ | |
| #include "config.h" | |
| #include "wine/port.h" | |
| #include <stdarg.h> | |
| #include <stdio.h> | |
| #include <signal.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <ctype.h> | |
| #include <errno.h> | |
| #ifdef HAVE_IO_H | |
| # include <io.h> | |
| #endif | |
| #ifdef HAVE_UNISTD_H | |
| # include <unistd.h> | |
| #endif | |
| #include <fcntl.h> | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "winuser.h" | |
| #include "wine/winbase16.h" | |
| #include "wine/wingdi16.h" | |
| #include "winspool.h" | |
| #include "winerror.h" | |
| #include "winreg.h" | |
| #include "wownt32.h" | |
| #include "wine/debug.h" | |
| #include "gdi.h" | |
| #include "gdi_private.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(print); | |
| static const char PrinterModel[] = "Printer Model"; | |
| static const char DefaultDevMode[] = "Default DevMode"; | |
| static const char PrinterDriverData[] = "PrinterDriverData"; | |
| static const char Printers[] = "System\\CurrentControlSet\\Control\\Print\\Printers\\"; | |
| /****************************************************************** | |
| * StartDocA [GDI32.@] | |
| * | |
| * StartDoc calls the STARTDOC Escape with the input data pointing to DocName | |
| * and the output data (which is used as a second input parameter).pointing at | |
| * the whole docinfo structure. This seems to be an undocumented feature of | |
| * the STARTDOC Escape. | |
| * | |
| * Note: we now do it the other way, with the STARTDOC Escape calling StartDoc. | |
| */ | |
| INT WINAPI StartDocW(HDC hdc, const DOCINFOW* doc) | |
| { | |
| INT ret = 0; | |
| DC *dc = DC_GetDCPtr( hdc ); | |
| TRACE("DocName = %s Output = %s Datatype = %s\n", | |
| debugstr_w(doc->lpszDocName), debugstr_w(doc->lpszOutput), | |
| debugstr_w(doc->lpszDatatype)); | |
| if(!dc) return SP_ERROR; | |
| if (dc->funcs->pStartDoc) ret = dc->funcs->pStartDoc( dc->physDev, doc ); | |
| GDI_ReleaseObj( hdc ); | |
| return ret; | |
| } | |
| /************************************************************************* | |
| * StartDocA [GDI32.@] | |
| * | |
| */ | |
| INT WINAPI StartDocA(HDC hdc, const DOCINFOA* doc) | |
| { | |
| LPWSTR szDocName = NULL, szOutput = NULL, szDatatype = NULL; | |
| DOCINFOW docW; | |
| INT ret, len; | |
| docW.cbSize = doc->cbSize; | |
| if (doc->lpszDocName) | |
| { | |
| len = MultiByteToWideChar(CP_ACP,0,doc->lpszDocName,-1,NULL,0); | |
| szDocName = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR)); | |
| MultiByteToWideChar(CP_ACP,0,doc->lpszDocName,-1,szDocName,len); | |
| } | |
| if (doc->lpszOutput) | |
| { | |
| len = MultiByteToWideChar(CP_ACP,0,doc->lpszOutput,-1,NULL,0); | |
| szOutput = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR)); | |
| MultiByteToWideChar(CP_ACP,0,doc->lpszOutput,-1,szOutput,len); | |
| } | |
| if (doc->lpszDatatype) | |
| { | |
| len = MultiByteToWideChar(CP_ACP,0,doc->lpszDatatype,-1,NULL,0); | |
| szDatatype = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR)); | |
| MultiByteToWideChar(CP_ACP,0,doc->lpszDatatype,-1,szDatatype,len); | |
| } | |
| docW.lpszDocName = szDocName; | |
| docW.lpszOutput = szOutput; | |
| docW.lpszDatatype = szDatatype; | |
| docW.fwType = doc->fwType; | |
| ret = StartDocW(hdc, &docW); | |
| HeapFree( GetProcessHeap(), 0, szDocName ); | |
| HeapFree( GetProcessHeap(), 0, szOutput ); | |
| HeapFree( GetProcessHeap(), 0, szDatatype ); | |
| return ret; | |
| } | |
| /****************************************************************** | |
| * EndDoc [GDI32.@] | |
| * | |
| */ | |
| INT WINAPI EndDoc(HDC hdc) | |
| { | |
| INT ret = 0; | |
| DC *dc = DC_GetDCPtr( hdc ); | |
| if(!dc) return SP_ERROR; | |
| if (dc->funcs->pEndDoc) ret = dc->funcs->pEndDoc( dc->physDev ); | |
| GDI_ReleaseObj( hdc ); | |
| return ret; | |
| } | |
| /****************************************************************** | |
| * StartPage [GDI32.@] | |
| * | |
| */ | |
| INT WINAPI StartPage(HDC hdc) | |
| { | |
| INT ret = 1; | |
| DC *dc = DC_GetDCPtr( hdc ); | |
| if(!dc) return SP_ERROR; | |
| if(dc->funcs->pStartPage) | |
| ret = dc->funcs->pStartPage( dc->physDev ); | |
| else | |
| FIXME("stub\n"); | |
| GDI_ReleaseObj( hdc ); | |
| return ret; | |
| } | |
| /****************************************************************** | |
| * EndPage [GDI32.@] | |
| * | |
| */ | |
| INT WINAPI EndPage(HDC hdc) | |
| { | |
| ABORTPROC abort_proc; | |
| INT ret = 0; | |
| DC *dc = DC_GetDCPtr( hdc ); | |
| if(!dc) return SP_ERROR; | |
| if (dc->funcs->pEndPage) ret = dc->funcs->pEndPage( dc->physDev ); | |
| abort_proc = dc->pAbortProc; | |
| GDI_ReleaseObj( hdc ); | |
| if (abort_proc && !abort_proc( hdc, 0 )) | |
| { | |
| EndDoc( hdc ); | |
| ret = 0; | |
| } | |
| return ret; | |
| } | |
| /****************************************************************************** | |
| * AbortDoc [GDI32.@] | |
| */ | |
| INT WINAPI AbortDoc(HDC hdc) | |
| { | |
| INT ret = 0; | |
| DC *dc = DC_GetDCPtr( hdc ); | |
| if(!dc) return SP_ERROR; | |
| if (dc->funcs->pAbortDoc) ret = dc->funcs->pAbortDoc( dc->physDev ); | |
| GDI_ReleaseObj( hdc ); | |
| return ret; | |
| } | |
| /********************************************************************** | |
| * QueryAbort (GDI.155) | |
| * | |
| * Calls the app's AbortProc function if avail. | |
| * | |
| * RETURNS | |
| * TRUE if no AbortProc avail or AbortProc wants to continue printing. | |
| * FALSE if AbortProc wants to abort printing. | |
| */ | |
| BOOL16 WINAPI QueryAbort16(HDC16 hdc16, INT16 reserved) | |
| { | |
| BOOL ret = TRUE; | |
| HDC hdc = HDC_32( hdc16 ); | |
| DC *dc = DC_GetDCPtr( hdc ); | |
| ABORTPROC abproc; | |
| if(!dc) { | |
| ERR("Invalid hdc %p\n", hdc); | |
| return FALSE; | |
| } | |
| abproc = dc->pAbortProc; | |
| GDI_ReleaseObj( hdc ); | |
| if (abproc) | |
| ret = abproc(hdc, 0); | |
| return ret; | |
| } | |
| /********************************************************************** | |
| * call_abort_proc16 | |
| */ | |
| static BOOL CALLBACK call_abort_proc16( HDC hdc, INT code ) | |
| { | |
| ABORTPROC16 proc16; | |
| DC *dc = DC_GetDCPtr( hdc ); | |
| if (!dc) return FALSE; | |
| proc16 = dc->pAbortProc16; | |
| GDI_ReleaseObj( hdc ); | |
| if (proc16) | |
| { | |
| WORD args[2]; | |
| DWORD ret; | |
| args[1] = HDC_16(hdc); | |
| args[0] = code; | |
| WOWCallback16Ex( (DWORD)proc16, WCB16_PASCAL, sizeof(args), args, &ret ); | |
| return LOWORD(ret); | |
| } | |
| return TRUE; | |
| } | |
| /********************************************************************** | |
| * SetAbortProc (GDI.381) | |
| */ | |
| INT16 WINAPI SetAbortProc16(HDC16 hdc16, ABORTPROC16 abrtprc) | |
| { | |
| HDC hdc = HDC_32( hdc16 ); | |
| DC *dc = DC_GetDCPtr( hdc ); | |
| if (!dc) return FALSE; | |
| dc->pAbortProc16 = abrtprc; | |
| GDI_ReleaseObj( hdc ); | |
| return SetAbortProc( hdc, call_abort_proc16 ); | |
| } | |
| /********************************************************************** | |
| * SetAbortProc (GDI32.@) | |
| * | |
| */ | |
| INT WINAPI SetAbortProc(HDC hdc, ABORTPROC abrtprc) | |
| { | |
| DC *dc = DC_GetDCPtr( hdc ); | |
| if (!dc) return FALSE; | |
| dc->pAbortProc = abrtprc; | |
| GDI_ReleaseObj( hdc ); | |
| return TRUE; | |
| } | |
| /****************** misc. printer related functions */ | |
| /* | |
| * The following function should implement a queing system | |
| */ | |
| struct hpq | |
| { | |
| struct hpq *next; | |
| int tag; | |
| int key; | |
| }; | |
| static struct hpq *hpqueue; | |
| /********************************************************************** | |
| * CreatePQ (GDI.230) | |
| * | |
| */ | |
| HPQ16 WINAPI CreatePQ16(INT16 size) | |
| { | |
| #if 0 | |
| HGLOBAL16 hpq = 0; | |
| WORD tmp_size; | |
| LPWORD pPQ; | |
| tmp_size = size << 2; | |
| if (!(hpq = GlobalAlloc16(GMEM_SHARE|GMEM_MOVEABLE, tmp_size + 8))) | |
| return 0xffff; | |
| pPQ = GlobalLock16(hpq); | |
| *pPQ++ = 0; | |
| *pPQ++ = tmp_size; | |
| *pPQ++ = 0; | |
| *pPQ++ = 0; | |
| GlobalUnlock16(hpq); | |
| return (HPQ16)hpq; | |
| #else | |
| FIXME("(%d): stub\n",size); | |
| return 1; | |
| #endif | |
| } | |
| /********************************************************************** | |
| * DeletePQ (GDI.235) | |
| * | |
| */ | |
| INT16 WINAPI DeletePQ16(HPQ16 hPQ) | |
| { | |
| return GlobalFree16((HGLOBAL16)hPQ); | |
| } | |
| /********************************************************************** | |
| * ExtractPQ (GDI.232) | |
| * | |
| */ | |
| INT16 WINAPI ExtractPQ16(HPQ16 hPQ) | |
| { | |
| struct hpq *queue, *prev, *current, *currentPrev; | |
| int key = 0, tag = -1; | |
| currentPrev = prev = NULL; | |
| queue = current = hpqueue; | |
| if (current) | |
| key = current->key; | |
| while (current) | |
| { | |
| currentPrev = current; | |
| current = current->next; | |
| if (current) | |
| { | |
| if (current->key < key) | |
| { | |
| queue = current; | |
| prev = currentPrev; | |
| } | |
| } | |
| } | |
| if (queue) | |
| { | |
| tag = queue->tag; | |
| if (prev) | |
| prev->next = queue->next; | |
| else | |
| hpqueue = queue->next; | |
| HeapFree(GetProcessHeap(), 0, queue); | |
| } | |
| TRACE("%x got tag %d key %d\n", hPQ, tag, key); | |
| return tag; | |
| } | |
| /********************************************************************** | |
| * InsertPQ (GDI.233) | |
| * | |
| */ | |
| INT16 WINAPI InsertPQ16(HPQ16 hPQ, INT16 tag, INT16 key) | |
| { | |
| struct hpq *queueItem = HeapAlloc(GetProcessHeap(), 0, sizeof(struct hpq)); | |
| if(queueItem == NULL) { | |
| ERR("Memory exausted!\n"); | |
| return FALSE; | |
| } | |
| queueItem->next = hpqueue; | |
| hpqueue = queueItem; | |
| queueItem->key = key; | |
| queueItem->tag = tag; | |
| FIXME("(%x %d %d): stub???\n", hPQ, tag, key); | |
| return TRUE; | |
| } | |
| /********************************************************************** | |
| * MinPQ (GDI.231) | |
| * | |
| */ | |
| INT16 WINAPI MinPQ16(HPQ16 hPQ) | |
| { | |
| FIXME("(%x): stub\n", hPQ); | |
| return 0; | |
| } | |
| /********************************************************************** | |
| * SizePQ (GDI.234) | |
| * | |
| */ | |
| INT16 WINAPI SizePQ16(HPQ16 hPQ, INT16 sizechange) | |
| { | |
| FIXME("(%x %d): stub\n", hPQ, sizechange); | |
| return -1; | |
| } | |
| /* | |
| * The following functions implement part of the spooling process to | |
| * print manager. I would like to see wine have a version of print managers | |
| * that used LPR/LPD. For simplicity print jobs will be sent to a file for | |
| * now. | |
| */ | |
| typedef struct PRINTJOB | |
| { | |
| char *pszOutput; | |
| char *pszTitle; | |
| HDC16 hDC; | |
| HANDLE16 hHandle; | |
| int nIndex; | |
| int fd; | |
| } PRINTJOB, *PPRINTJOB; | |
| #define MAX_PRINT_JOBS 1 | |
| #define SP_OK 1 | |
| PPRINTJOB gPrintJobsTable[MAX_PRINT_JOBS]; | |
| static PPRINTJOB FindPrintJobFromHandle(HANDLE16 hHandle) | |
| { | |
| return gPrintJobsTable[0]; | |
| } | |
| static int CreateSpoolFile(LPCSTR pszOutput) | |
| { | |
| int fd=-1; | |
| char psCmd[1024]; | |
| char *psCmdP = psCmd; | |
| HKEY hkey; | |
| /* TTD convert the 'output device' into a spool file name */ | |
| if (pszOutput == NULL || *pszOutput == '\0') | |
| return -1; | |
| psCmd[0] = 0; | |
| if (!strncmp("LPR:",pszOutput,4)) | |
| { | |
| if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\spooler", &hkey)) | |
| { | |
| DWORD type, count = sizeof(psCmd); | |
| RegQueryValueExA(hkey, pszOutput, 0, &type, psCmd, &count); | |
| RegCloseKey(hkey); | |
| } | |
| if(psCmd[0] == 0) | |
| sprintf(psCmd,"|lpr -P%s",pszOutput+4); | |
| } | |
| else | |
| { | |
| if(!RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\spooler", &hkey)) | |
| { | |
| DWORD type, count = sizeof(psCmd); | |
| RegQueryValueExA(hkey, pszOutput, 0, &type, psCmd, &count); | |
| RegCloseKey(hkey); | |
| } | |
| } | |
| TRACE("Got printerSpoolCommand '%s' for output device '%s'\n", | |
| psCmd, pszOutput); | |
| if (!*psCmd) | |
| psCmdP = (char *)pszOutput; | |
| else | |
| { | |
| while (*psCmdP && isspace(*psCmdP)) | |
| { | |
| psCmdP++; | |
| } | |
| if (!*psCmdP) | |
| return -1; | |
| } | |
| TRACE("command: '%s'\n", psCmdP); | |
| #ifdef HAVE_FORK | |
| if (*psCmdP == '|') | |
| { | |
| int fds[2]; | |
| if (pipe(fds)) { | |
| ERR("pipe() failed!\n"); | |
| return -1; | |
| } | |
| if (fork() == 0) | |
| { | |
| psCmdP++; | |
| TRACE("In child need to exec %s\n",psCmdP); | |
| close(0); | |
| dup2(fds[0],0); | |
| close (fds[1]); | |
| /* reset signals that we previously set to SIG_IGN */ | |
| signal( SIGPIPE, SIG_DFL ); | |
| signal( SIGCHLD, SIG_DFL ); | |
| system(psCmdP); | |
| exit(0); | |
| } | |
| close (fds[0]); | |
| fd = fds[1]; | |
| TRACE("Need to execute a cmnd and pipe the output to it\n"); | |
| } | |
| else | |
| #endif | |
| { | |
| char *buffer; | |
| WCHAR psCmdPW[MAX_PATH]; | |
| TRACE("Just assume it's a file\n"); | |
| /** | |
| * The file name can be dos based, we have to find its | |
| * Unix correspondant file name | |
| */ | |
| MultiByteToWideChar(CP_ACP, 0, psCmdP, -1, psCmdPW, MAX_PATH); | |
| if ((buffer = wine_get_unix_file_name(psCmdPW))) | |
| { | |
| if ((fd = open(buffer, O_CREAT | O_TRUNC | O_WRONLY , 0600)) < 0) | |
| { | |
| ERR("Failed to create spool file '%s' ('%s'). (error %s)\n", | |
| buffer, psCmdP, strerror(errno)); | |
| } | |
| HeapFree(GetProcessHeap(), 0, buffer); | |
| } | |
| } | |
| return fd; | |
| } | |
| static int FreePrintJob(HANDLE16 hJob) | |
| { | |
| int nRet = SP_ERROR; | |
| PPRINTJOB pPrintJob; | |
| pPrintJob = FindPrintJobFromHandle(hJob); | |
| if (pPrintJob != NULL) | |
| { | |
| gPrintJobsTable[pPrintJob->nIndex] = NULL; | |
| HeapFree(GetProcessHeap(), 0, pPrintJob->pszOutput); | |
| HeapFree(GetProcessHeap(), 0, pPrintJob->pszTitle); | |
| if (pPrintJob->fd >= 0) close(pPrintJob->fd); | |
| HeapFree(GetProcessHeap(), 0, pPrintJob); | |
| nRet = SP_OK; | |
| } | |
| return nRet; | |
| } | |
| /********************************************************************** | |
| * OpenJob (GDI.240) | |
| * | |
| */ | |
| HPJOB16 WINAPI OpenJob16(LPCSTR lpOutput, LPCSTR lpTitle, HDC16 hDC) | |
| { | |
| HPJOB16 hHandle = (HPJOB16)SP_ERROR; | |
| PPRINTJOB pPrintJob; | |
| TRACE("'%s' '%s' %04x\n", lpOutput, lpTitle, hDC); | |
| pPrintJob = gPrintJobsTable[0]; | |
| if (pPrintJob == NULL) | |
| { | |
| int fd; | |
| /* Try and create a spool file */ | |
| fd = CreateSpoolFile(lpOutput); | |
| if (fd >= 0) | |
| { | |
| pPrintJob = HeapAlloc(GetProcessHeap(), 0, sizeof(PRINTJOB)); | |
| if(pPrintJob == NULL) { | |
| WARN("Memory exausted!\n"); | |
| return hHandle; | |
| } | |
| hHandle = 1; | |
| pPrintJob->pszOutput = HeapAlloc(GetProcessHeap(), 0, strlen(lpOutput)+1); | |
| strcpy( pPrintJob->pszOutput, lpOutput ); | |
| if(lpTitle) | |
| { | |
| pPrintJob->pszTitle = HeapAlloc(GetProcessHeap(), 0, strlen(lpTitle)+1); | |
| strcpy( pPrintJob->pszTitle, lpTitle ); | |
| } | |
| pPrintJob->hDC = hDC; | |
| pPrintJob->fd = fd; | |
| pPrintJob->nIndex = 0; | |
| pPrintJob->hHandle = hHandle; | |
| gPrintJobsTable[pPrintJob->nIndex] = pPrintJob; | |
| } | |
| } | |
| TRACE("return %04x\n", hHandle); | |
| return hHandle; | |
| } | |
| /********************************************************************** | |
| * CloseJob (GDI.243) | |
| * | |
| */ | |
| INT16 WINAPI CloseJob16(HPJOB16 hJob) | |
| { | |
| int nRet = SP_ERROR; | |
| PPRINTJOB pPrintJob = NULL; | |
| TRACE("%04x\n", hJob); | |
| pPrintJob = FindPrintJobFromHandle(hJob); | |
| if (pPrintJob != NULL) | |
| { | |
| /* Close the spool file */ | |
| close(pPrintJob->fd); | |
| FreePrintJob(hJob); | |
| nRet = 1; | |
| } | |
| return nRet; | |
| } | |
| /********************************************************************** | |
| * WriteSpool (GDI.241) | |
| * | |
| */ | |
| INT16 WINAPI WriteSpool16(HPJOB16 hJob, LPSTR lpData, INT16 cch) | |
| { | |
| int nRet = SP_ERROR; | |
| PPRINTJOB pPrintJob = NULL; | |
| TRACE("%04x %08lx %04x\n", hJob, (DWORD)lpData, cch); | |
| pPrintJob = FindPrintJobFromHandle(hJob); | |
| if (pPrintJob != NULL && pPrintJob->fd >= 0 && cch) | |
| { | |
| if (write(pPrintJob->fd, lpData, cch) != cch) | |
| nRet = SP_OUTOFDISK; | |
| else | |
| nRet = cch; | |
| #if 0 | |
| /* FIXME: We just cannot call 16 bit functions from here, since we | |
| * have acquired several locks (DC). And we do not really need to. | |
| */ | |
| if (pPrintJob->hDC == 0) { | |
| TRACE("hDC == 0 so no QueryAbort\n"); | |
| } | |
| else if (!(QueryAbort16(pPrintJob->hDC, (nRet == SP_OUTOFDISK) ? nRet : 0 ))) | |
| { | |
| CloseJob16(hJob); /* printing aborted */ | |
| nRet = SP_APPABORT; | |
| } | |
| #endif | |
| } | |
| return nRet; | |
| } | |
| typedef INT (WINAPI *MSGBOX_PROC)( HWND, LPCSTR, LPCSTR, UINT ); | |
| /********************************************************************** | |
| * WriteDialog (GDI.242) | |
| * | |
| */ | |
| INT16 WINAPI WriteDialog16(HPJOB16 hJob, LPSTR lpMsg, INT16 cchMsg) | |
| { | |
| HMODULE mod; | |
| MSGBOX_PROC pMessageBoxA; | |
| INT16 ret = 0; | |
| TRACE("%04x %04x '%s'\n", hJob, cchMsg, lpMsg); | |
| if ((mod = GetModuleHandleA("user32.dll"))) | |
| { | |
| if ((pMessageBoxA = (MSGBOX_PROC)GetProcAddress( mod, "MessageBoxA" ))) | |
| ret = pMessageBoxA(0, lpMsg, "Printing Error", MB_OKCANCEL); | |
| } | |
| return ret; | |
| } | |
| /********************************************************************** | |
| * DeleteJob (GDI.244) | |
| * | |
| */ | |
| INT16 WINAPI DeleteJob16(HPJOB16 hJob, INT16 nNotUsed) | |
| { | |
| int nRet; | |
| TRACE("%04x\n", hJob); | |
| nRet = FreePrintJob(hJob); | |
| return nRet; | |
| } | |
| /* | |
| * The following two function would allow a page to be sent to the printer | |
| * when it has been processed. For simplicity they havn't been implemented. | |
| * This means a whole job has to be processed before it is sent to the printer. | |
| */ | |
| /********************************************************************** | |
| * StartSpoolPage (GDI.246) | |
| * | |
| */ | |
| INT16 WINAPI StartSpoolPage16(HPJOB16 hJob) | |
| { | |
| FIXME("StartSpoolPage GDI.246 unimplemented\n"); | |
| return 1; | |
| } | |
| /********************************************************************** | |
| * EndSpoolPage (GDI.247) | |
| * | |
| */ | |
| INT16 WINAPI EndSpoolPage16(HPJOB16 hJob) | |
| { | |
| FIXME("EndSpoolPage GDI.247 unimplemented\n"); | |
| return 1; | |
| } | |
| /********************************************************************** | |
| * GetSpoolJob (GDI.245) | |
| * | |
| */ | |
| DWORD WINAPI GetSpoolJob16(int nOption, LONG param) | |
| { | |
| DWORD retval = 0; | |
| TRACE("In GetSpoolJob param 0x%lx noption %d\n",param, nOption); | |
| return retval; | |
| } | |
| /****************************************************************** | |
| * DrvGetPrinterDataInternal | |
| * | |
| * Helper for DrvGetPrinterData | |
| */ | |
| static DWORD DrvGetPrinterDataInternal(LPSTR RegStr_Printer, | |
| LPBYTE lpPrinterData, int cbData, int what) | |
| { | |
| DWORD res = -1; | |
| HKEY hkey; | |
| DWORD dwType, cbQueryData; | |
| if (!(RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey))) { | |
| if (what == INT_PD_DEFAULT_DEVMODE) { /* "Default DevMode" */ | |
| if (!(RegQueryValueExA(hkey, DefaultDevMode, 0, &dwType, 0, &cbQueryData))) { | |
| if (!lpPrinterData) | |
| res = cbQueryData; | |
| else if ((cbQueryData) && (cbQueryData <= cbData)) { | |
| cbQueryData = cbData; | |
| if (RegQueryValueExA(hkey, DefaultDevMode, 0, | |
| &dwType, lpPrinterData, &cbQueryData)) | |
| res = cbQueryData; | |
| } | |
| } | |
| } else { /* "Printer Driver" */ | |
| cbQueryData = 32; | |
| RegQueryValueExA(hkey, "Printer Driver", 0, | |
| &dwType, lpPrinterData, &cbQueryData); | |
| res = cbQueryData; | |
| } | |
| } | |
| if (hkey) RegCloseKey(hkey); | |
| return res; | |
| } | |
| /****************************************************************** | |
| * DrvGetPrinterData (GDI.282) | |
| * | |
| */ | |
| DWORD WINAPI DrvGetPrinterData16(LPSTR lpPrinter, LPSTR lpProfile, | |
| LPDWORD lpType, LPBYTE lpPrinterData, | |
| int cbData, LPDWORD lpNeeded) | |
| { | |
| LPSTR RegStr_Printer; | |
| HKEY hkey = 0, hkey2 = 0; | |
| DWORD res = 0; | |
| DWORD dwType, PrinterAttr, cbPrinterAttr, SetData, size; | |
| if (HIWORD(lpPrinter)) | |
| TRACE("printer %s\n",lpPrinter); | |
| else | |
| TRACE("printer %p\n",lpPrinter); | |
| if (HIWORD(lpProfile)) | |
| TRACE("profile %s\n",lpProfile); | |
| else | |
| TRACE("profile %p\n",lpProfile); | |
| TRACE("lpType %p\n",lpType); | |
| if ((!lpPrinter) || (!lpProfile) || (!lpNeeded)) | |
| return ERROR_INVALID_PARAMETER; | |
| RegStr_Printer = HeapAlloc(GetProcessHeap(), 0, | |
| strlen(Printers) + strlen(lpPrinter) + 2); | |
| strcpy(RegStr_Printer, Printers); | |
| strcat(RegStr_Printer, lpPrinter); | |
| if (((DWORD)lpProfile == INT_PD_DEFAULT_DEVMODE) || (HIWORD(lpProfile) && | |
| (!strcmp(lpProfile, DefaultDevMode)))) { | |
| size = DrvGetPrinterDataInternal(RegStr_Printer, lpPrinterData, cbData, | |
| INT_PD_DEFAULT_DEVMODE); | |
| if (size+1) { | |
| *lpNeeded = size; | |
| if ((lpPrinterData) && (*lpNeeded > cbData)) | |
| res = ERROR_MORE_DATA; | |
| } | |
| else res = ERROR_INVALID_PRINTER_NAME; | |
| } | |
| else | |
| if (((DWORD)lpProfile == INT_PD_DEFAULT_MODEL) || (HIWORD(lpProfile) && | |
| (!strcmp(lpProfile, PrinterModel)))) { | |
| *lpNeeded = 32; | |
| if (!lpPrinterData) goto failed; | |
| if (cbData < 32) { | |
| res = ERROR_MORE_DATA; | |
| goto failed; | |
| } | |
| size = DrvGetPrinterDataInternal(RegStr_Printer, lpPrinterData, cbData, | |
| INT_PD_DEFAULT_MODEL); | |
| if ((size+1) && (lpType)) | |
| *lpType = REG_SZ; | |
| else | |
| res = ERROR_INVALID_PRINTER_NAME; | |
| } | |
| else | |
| { | |
| if ((res = RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey))) | |
| goto failed; | |
| cbPrinterAttr = 4; | |
| if ((res = RegQueryValueExA(hkey, "Attributes", 0, | |
| &dwType, (LPBYTE)&PrinterAttr, &cbPrinterAttr))) | |
| goto failed; | |
| if ((res = RegOpenKeyA(hkey, PrinterDriverData, &hkey2))) | |
| goto failed; | |
| *lpNeeded = cbData; | |
| res = RegQueryValueExA(hkey2, lpProfile, 0, | |
| lpType, lpPrinterData, lpNeeded); | |
| if ((res != ERROR_CANTREAD) && | |
| ((PrinterAttr & | |
| (PRINTER_ATTRIBUTE_ENABLE_BIDI|PRINTER_ATTRIBUTE_NETWORK)) | |
| == PRINTER_ATTRIBUTE_NETWORK)) | |
| { | |
| if (!(res) && (*lpType == REG_DWORD) && (*(LPDWORD)lpPrinterData == -1)) | |
| res = ERROR_INVALID_DATA; | |
| } | |
| else | |
| { | |
| SetData = -1; | |
| RegSetValueExA(hkey2, lpProfile, 0, REG_DWORD, (LPBYTE)&SetData, 4); /* no result returned */ | |
| } | |
| } | |
| failed: | |
| if (hkey2) RegCloseKey(hkey2); | |
| if (hkey) RegCloseKey(hkey); | |
| HeapFree(GetProcessHeap(), 0, RegStr_Printer); | |
| return res; | |
| } | |
| /****************************************************************** | |
| * DrvSetPrinterData (GDI.281) | |
| * | |
| */ | |
| DWORD WINAPI DrvSetPrinterData16(LPSTR lpPrinter, LPSTR lpProfile, | |
| DWORD lpType, LPBYTE lpPrinterData, | |
| DWORD dwSize) | |
| { | |
| LPSTR RegStr_Printer; | |
| HKEY hkey = 0; | |
| DWORD res = 0; | |
| if (HIWORD(lpPrinter)) | |
| TRACE("printer %s\n",lpPrinter); | |
| else | |
| TRACE("printer %p\n",lpPrinter); | |
| if (HIWORD(lpProfile)) | |
| TRACE("profile %s\n",lpProfile); | |
| else | |
| TRACE("profile %p\n",lpProfile); | |
| TRACE("lpType %08lx\n",lpType); | |
| if ((!lpPrinter) || (!lpProfile) || | |
| ((DWORD)lpProfile == INT_PD_DEFAULT_MODEL) || (HIWORD(lpProfile) && | |
| (!strcmp(lpProfile, PrinterModel)))) | |
| return ERROR_INVALID_PARAMETER; | |
| RegStr_Printer = HeapAlloc(GetProcessHeap(), 0, | |
| strlen(Printers) + strlen(lpPrinter) + 2); | |
| strcpy(RegStr_Printer, Printers); | |
| strcat(RegStr_Printer, lpPrinter); | |
| if (((DWORD)lpProfile == INT_PD_DEFAULT_DEVMODE) || (HIWORD(lpProfile) && | |
| (!strcmp(lpProfile, DefaultDevMode)))) { | |
| if ( RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey) | |
| != ERROR_SUCCESS || | |
| RegSetValueExA(hkey, DefaultDevMode, 0, REG_BINARY, | |
| lpPrinterData, dwSize) != ERROR_SUCCESS ) | |
| res = ERROR_INVALID_PRINTER_NAME; | |
| } | |
| else | |
| { | |
| strcat(RegStr_Printer, "\\"); | |
| if( (res = RegOpenKeyA(HKEY_LOCAL_MACHINE, RegStr_Printer, &hkey)) == | |
| ERROR_SUCCESS ) { | |
| if (!lpPrinterData) | |
| res = RegDeleteValueA(hkey, lpProfile); | |
| else | |
| res = RegSetValueExA(hkey, lpProfile, 0, lpType, | |
| lpPrinterData, dwSize); | |
| } | |
| } | |
| if (hkey) RegCloseKey(hkey); | |
| HeapFree(GetProcessHeap(), 0, RegStr_Printer); | |
| return res; | |
| } |