xref: /reactos/win32ss/gdi/gdi32/objects/printdrv.c (revision 40462c92)
1 /*
2  *  COPYRIGHT:        See COPYING in the top level directory
3  *  PROJECT:          ReactOS Kernel
4  *  PURPOSE:          GDI Printing Support
5  *  FILE:             dll/win32/gdi32/objects/printdrv.c
6  *  PROGRAMER:
7  *
8  */
9 
10 // For the wine code:
11 /*
12  * Implementation of some printer driver bits
13  *
14  * Copyright 1996 John Harvey
15  * Copyright 1998 Huw Davies
16  * Copyright 1998 Andreas Mohr
17  * Copyright 1999 Klaas van Gend
18  *
19  * This library is free software; you can redistribute it and/or
20  * modify it under the terms of the GNU Lesser General Public
21  * License as published by the Free Software Foundation; either
22  * version 2.1 of the License, or (at your option) any later version.
23  *
24  * This library is distributed in the hope that it will be useful,
25  * but WITHOUT ANY WARRANTY; without even the implied warranty of
26  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
27  * Lesser General Public License for more details.
28  *
29  * You should have received a copy of the GNU Lesser General Public
30  * License along with this library; if not, write to the Free Software
31  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
32  */
33 
34 #include <precomp.h>
35 
36 #define NDEBUG
37 #include <debug.h>
38 
39 /* GLOBALS *******************************************************************/
40 HANDLE ghSpooler = NULL;
41 
42 static ABORTPRINTER fpAbortPrinter;
43 CLOSEPRINTER fpClosePrinter;
44 static CLOSESPOOLFILEHANDLE fpCloseSpoolFileHandle;
45 static COMMITSPOOLDATA fpCommitSpoolData;
46 //static fpConnectToLd64In32Server;
47 static DOCUMENTEVENT fpDocumentEvent;
48 static DOCUMENTPROPERTIESW fpDocumentPropertiesW;
49 static ENDDOCPRINTER fpEndDocPrinter;
50 static ENDPAGEPRINTER fpEndPagePrinter;
51 static GETSPOOLFILEHANDLE fpGetSpoolFileHandle;
52 static GETPRINTERW fpGetPrinterW;
53 static GETPRINTERDRIVERW fpGetPrinterDriverW;
54 static ISVALIDDEVMODEW fpIsValidDevmodeW;
55 OPENPRINTERW fpOpenPrinterW;
56 static QUERYSPOOLMODE fpQuerySpoolMode;
57 static QUERYREMOTEFONTS fpQueryRemoteFonts;
58 static QUERYCOLORPROFILE fpQueryColorProfile;
59 static READPRINTER fpReadPrinter;
60 static RESETPRINTERW fpResetPrinterW;
61 static SEEKPRINTER fpSeekPrinter;
62 static SPLDRIVERUNLOADCOMPLETE fpSplDriverUnloadComplete;
63 static SPLREADPRINTER fpSplReadPrinter;
64 static STARTDOCDLGW fpStartDocDlgW;
65 static STARTDOCPRINTERW fpStartDocPrinterW;
66 static STARTPAGEPRINTER fpStartPagePrinter;
67 
68 /* PRIVATE FUNCTIONS *********************************************************/
69 
70 static
71 int
72 FASTCALL
73 IntEndPage(
74     HDC hdc,
75     BOOL Form
76 )
77 {
78     PLDC pldc;
79     int Ret = SP_ERROR;
80     ULONG hType = GDI_HANDLE_GET_TYPE(hdc);
81 
82     if (hType == GDILoObjType_LO_DC_TYPE || hType == GDILoObjType_LO_METADC16_TYPE)
83     {
84         SetLastError(ERROR_INVALID_HANDLE);
85         return SP_ERROR;
86     }
87 
88     pldc = GdiGetLDC(hdc);
89     if ( !pldc )
90     {
91         SetLastError(ERROR_INVALID_HANDLE);
92         return SP_ERROR;
93     }
94 
95     if (pldc->Flags & LDC_ATENDPAGE) return 1;
96 
97     if (pldc->Flags & LDC_META_PRINT)
98     {
99         if ( Form )
100         {
101             // Do MF EndPageForm
102         }
103         else
104         {
105             // Do MF EndPage
106         }
107         return Ret;
108     }
109 
110     if (pldc->Flags & LDC_KILL_DOCUMENT || pldc->Flags & LDC_INIT_PAGE)
111     {
112         SetLastError(ERROR_INVALID_PARAMETER);
113         return SP_ERROR;
114     }
115 
116     if (pldc->Flags & LDC_SAPCALLBACK) GdiSAPCallback(pldc);
117 
118     pldc->Flags &= ~LDC_INIT_PAGE;
119 
120     DocumentEventEx(NULL, pldc->hPrinter, hdc, DOCUMENTEVENT_ENDPAGE, 0, NULL, 0, NULL);
121 
122     ((PW32CLIENTINFO)NtCurrentTeb()->Win32ClientInfo)->cSpins = 0;
123 
124     if ( NtGdiEndPage(hdc) )
125     {
126         BOOL Good;
127 //      if (pldc->pUMPDev)
128         Good = EndPagePrinterEx(NULL,pldc->hPrinter);
129 
130         if (Good) pldc->Flags |= LDC_STARTPAGE;
131         Ret = 1;
132     }
133     else
134         SetLastError(ERROR_INVALID_PARAMETER);
135     return Ret;
136 }
137 
138 /* FUNCTIONS *****************************************************************/
139 
140 BOOL
141 FASTCALL
142 AbortPrinterEx(
143     PVOID   pvUMPDev,
144     HANDLE  hPrinter
145 )
146 {
147     return fpAbortPrinter(hPrinter);
148 }
149 
150 int
151 FASTCALL
152 DocumentEventEx(
153     PVOID   pvUMPDev,
154     HANDLE  hPrinter,
155     HDC     hdc,
156     int     iEsc,
157     ULONG   cbIn,
158     PVOID   pvIn,
159     ULONG   cbOut,
160     PVOID   pvOut
161 )
162 {
163     return fpDocumentEvent(hPrinter,hdc,iEsc,cbIn,pvIn,cbOut,pvOut);
164 }
165 
166 BOOL
167 FASTCALL
168 EndDocPrinterEx(
169     PVOID   pvUMPDev,
170     HANDLE  hPrinter
171 )
172 {
173     return fpEndDocPrinter(hPrinter);
174 }
175 
176 BOOL
177 FASTCALL
178 EndPagePrinterEx(
179     PVOID   pvUMPDev,
180     HANDLE  hPrinter
181 )
182 {
183     return fpEndPagePrinter(hPrinter);
184 }
185 
186 BOOL
187 FASTCALL
188 LoadTheSpoolerDrv(VOID)
189 {
190     HMODULE hModWinSpoolDrv;
191 
192     if ( !ghSpooler )
193     {
194         RtlEnterCriticalSection(&semLocal);
195 
196         hModWinSpoolDrv = LoadLibraryW(L"WINSPOOL.DRV");
197 
198         if (hModWinSpoolDrv)
199         {
200             fpAbortPrinter = (PVOID)GetProcAddress(hModWinSpoolDrv, "AbortPrinter");
201             fpClosePrinter = (PVOID)GetProcAddress(hModWinSpoolDrv, "ClosePrinter");
202             fpCloseSpoolFileHandle = (PVOID)GetProcAddress(hModWinSpoolDrv, "CloseSpoolFileHandle");
203             fpCommitSpoolData = (PVOID)GetProcAddress(hModWinSpoolDrv, "CommitSpoolData");
204             // fpConnectToLd64In32Server = (PVOID)GetProcAddress(hModWinSpoolDrv, (LPCSTR)224);
205             fpDocumentEvent = (PVOID)GetProcAddress(hModWinSpoolDrv,"DocumentEvent");
206             fpDocumentPropertiesW = (PVOID)GetProcAddress(hModWinSpoolDrv, "DocumentPropertiesW");
207             fpEndDocPrinter = (PVOID)GetProcAddress(hModWinSpoolDrv, "EndDocPrinter");
208             fpEndPagePrinter = (PVOID)GetProcAddress(hModWinSpoolDrv, "EndPagePrinter");
209             fpGetPrinterW = (PVOID)GetProcAddress( hModWinSpoolDrv,"GetPrinterW");
210             fpGetPrinterDriverW = (PVOID)GetProcAddress(hModWinSpoolDrv,"GetPrinterDriverW");
211             fpGetSpoolFileHandle = (PVOID)GetProcAddress(hModWinSpoolDrv, "GetSpoolFileHandle");
212             fpIsValidDevmodeW = (PVOID)GetProcAddress(hModWinSpoolDrv, "IsValidDevmodeW");
213             fpOpenPrinterW = (PVOID)GetProcAddress(hModWinSpoolDrv, "OpenPrinterW");
214             fpQueryColorProfile = (PVOID)GetProcAddress(hModWinSpoolDrv,"QueryColorProfile");
215             fpQueryRemoteFonts = (PVOID)GetProcAddress(hModWinSpoolDrv, "QueryRemoteFonts");
216             fpQuerySpoolMode = (PVOID)GetProcAddress(hModWinSpoolDrv, "QuerySpoolMode");
217             fpReadPrinter = (PVOID)GetProcAddress(hModWinSpoolDrv, "ReadPrinter");
218             fpResetPrinterW = (PVOID)GetProcAddress(hModWinSpoolDrv, "ResetPrinterW");
219             fpSeekPrinter = (PVOID)GetProcAddress(hModWinSpoolDrv, "SeekPrinter");
220             fpSplDriverUnloadComplete = (PVOID)GetProcAddress(hModWinSpoolDrv, "SplDriverUnloadComplete");
221             fpSplReadPrinter = (PVOID)GetProcAddress(hModWinSpoolDrv, (LPCSTR)205);
222             fpStartDocDlgW = (PVOID)GetProcAddress(hModWinSpoolDrv, "StartDocDlgW");
223             fpStartDocPrinterW = (PVOID)GetProcAddress(hModWinSpoolDrv, "StartDocPrinterW");
224             fpStartPagePrinter = (PVOID)GetProcAddress(hModWinSpoolDrv, "StartPagePrinter");
225 
226             if ( !fpAbortPrinter ||
227                     !fpClosePrinter ||
228                     !fpCloseSpoolFileHandle ||
229                     !fpCommitSpoolData ||
230                     !fpDocumentEvent ||
231                     !fpDocumentPropertiesW ||
232                     !fpEndDocPrinter ||
233                     !fpEndPagePrinter ||
234                     !fpGetPrinterW ||
235                     !fpGetPrinterDriverW ||
236                     !fpGetSpoolFileHandle ||
237                     !fpIsValidDevmodeW ||
238                     !fpOpenPrinterW ||
239                     !fpQueryColorProfile ||
240                     !fpQueryRemoteFonts ||
241                     !fpQuerySpoolMode ||
242                     !fpReadPrinter ||
243                     !fpResetPrinterW ||
244                     !fpSeekPrinter ||
245                     !fpSplDriverUnloadComplete ||
246                     !fpSplReadPrinter ||
247                     !fpStartDocDlgW ||
248                     !fpStartDocPrinterW ||
249                     !fpStartPagePrinter )
250             {
251                 FreeLibrary(hModWinSpoolDrv);
252                 hModWinSpoolDrv = NULL;
253             }
254             ghSpooler = hModWinSpoolDrv;
255         }
256         RtlLeaveCriticalSection(&semLocal);
257     }
258     else
259         return TRUE;
260 
261     if ( !ghSpooler ) SetLastError(ERROR_NOT_ENOUGH_MEMORY);
262 
263     return (ghSpooler != NULL);
264 }
265 
266 /*
267   Note from msdn:
268 
269    The sequence for a print job is as follows:
270 
271    1. To begin a print job, call StartDocPrinter.
272    2. To begin each page, call StartPagePrinter.
273    3. To write data to a page, call WritePrinter.
274    4. To end each page, call EndPagePrinter.
275    5. Repeat 2, 3, and 4 for as many pages as necessary.
276    6. To end the print job, call EndDocPrinter.
277 
278  */
279 DWORD
280 FASTCALL
281 StartDocPrinterWEx(
282     PVOID   pvUMPDev,
283     HANDLE  hPrinter,
284     DWORD   Level,
285     LPBYTE  pDocInfo
286 )
287 {
288     return fpStartDocPrinterW(hPrinter,Level,pDocInfo);
289 }
290 
291 BOOL
292 FASTCALL
293 StartPagePrinterEx(
294     PVOID   pvUMPDev,
295     HANDLE  hPrinter
296 )
297 {
298     return fpStartPagePrinter(hPrinter);
299 }
300 
301 /* SYSCALLS ******************************************************************/
302 
303 /*
304  * @unimplemented
305  */
306 int
307 WINAPI
308 AbortDoc(
309     HDC	hdc
310 )
311 {
312     PLDC pldc;
313     int Ret = SP_ERROR;
314     ULONG hType = GDI_HANDLE_GET_TYPE(hdc);
315 
316     if (hType == GDILoObjType_LO_DC_TYPE || hType == GDILoObjType_LO_METADC16_TYPE)
317     {
318         SetLastError(ERROR_INVALID_HANDLE);
319         return SP_ERROR;
320     }
321 
322     pldc = GdiGetLDC(hdc);
323     if ( !pldc )
324     {
325         SetLastError(ERROR_INVALID_HANDLE);
326         return SP_ERROR;
327     }
328 
329     if ( !(pldc->Flags & LDC_INIT_DOCUMENT) ) return 1;
330 
331     DocumentEventEx(NULL, pldc->hPrinter, hdc, DOCUMENTEVENT_ABORTDOC, 0, NULL, 0, NULL);
332 
333     ((PW32CLIENTINFO)NtCurrentTeb()->Win32ClientInfo)->cSpins = 0;
334 
335     if ( pldc->Flags & LDC_META_PRINT)
336     {
337         UNIMPLEMENTED;
338         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
339         return Ret;
340     }
341 
342     if (NtGdiAbortDoc(hdc))
343     {
344         if (fpAbortPrinter(pldc->hPrinter)) Ret = 1;
345     }
346     else
347         Ret = SP_ERROR;
348 
349     pldc->Flags &= ~(LDC_ATENDPAGE|LDC_META_PRINT|LDC_STARTPAGE|LDC_INIT_PAGE|LDC_INIT_DOCUMENT|LDC_SAPCALLBACK);
350 
351     return Ret;
352 }
353 
354 /*
355  * @unimplemented
356  */
357 int
358 WINAPI
359 EndDoc(
360     HDC	hdc
361 )
362 {
363     PLDC pldc;
364     int Ret = SP_ERROR;
365     ULONG hType = GDI_HANDLE_GET_TYPE(hdc);
366 
367     if (hType == GDILoObjType_LO_DC_TYPE || hType == GDILoObjType_LO_METADC16_TYPE)
368     {
369         SetLastError(ERROR_INVALID_HANDLE);
370         return SP_ERROR;
371     }
372 
373     pldc = GdiGetLDC(hdc);
374     if ( !pldc )
375     {
376         SetLastError(ERROR_INVALID_HANDLE);
377         return SP_ERROR;
378     }
379 
380     if (pldc->Flags & LDC_META_PRINT)
381     {
382         UNIMPLEMENTED;
383         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
384         return Ret;
385     }
386 
387     if (pldc->Flags & LDC_INIT_DOCUMENT)
388     {
389         BOOL Good;
390         if (pldc->Flags & LDC_INIT_PAGE) EndPage(hdc);
391 
392         DocumentEventEx(NULL, pldc->hPrinter, hdc, DOCUMENTEVENT_ENDDOC, 0, NULL, 0, NULL);
393 
394         ((PW32CLIENTINFO)NtCurrentTeb()->Win32ClientInfo)->cSpins = 0;
395 
396         Good = NtGdiEndDoc(hdc);
397 
398 //      if (pldc->pUMPDev)
399         Good = EndDocPrinterEx(NULL,pldc->hPrinter);
400 
401         if (Good)
402         {
403             DocumentEventEx(NULL, pldc->hPrinter, hdc, DOCUMENTEVENT_ENDDOCPOST, 0, NULL, 0, NULL);
404             Ret = 1;
405         }
406         pldc->Flags &= ~(LDC_ATENDPAGE|LDC_STARTPAGE|LDC_INIT_DOCUMENT|LDC_SAPCALLBACK);
407     }
408     return Ret;
409 }
410 
411 /*
412  * @implemented
413  */
414 int
415 WINAPI
416 EndFormPage(HDC hdc)
417 {
418     return IntEndPage(hdc,TRUE);
419 }
420 
421 /*
422  * @implemented
423  */
424 int
425 WINAPI
426 EndPage(HDC hdc	)
427 {
428     return IntEndPage(hdc,FALSE);
429 }
430 
431 /*
432  * @unimplemented
433  */
434 HANDLE
435 WINAPI
436 GdiGetSpoolFileHandle(LPWSTR pwszPrinterName,
437                       LPDEVMODEW pDevmode,
438                       LPWSTR pwszDocName)
439 {
440     UNIMPLEMENTED;
441     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
442     return 0;
443 }
444 
445 /*
446  * @unimplemented
447  */
448 BOOL
449 WINAPI
450 GdiDeleteSpoolFileHandle(HANDLE SpoolFileHandle)
451 {
452     UNIMPLEMENTED;
453     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
454     return 0;
455 }
456 
457 /*
458  * @unimplemented
459  */
460 DWORD
461 WINAPI
462 GdiGetPageCount(HANDLE SpoolFileHandle)
463 {
464     UNIMPLEMENTED;
465     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
466     return 0;
467 }
468 
469 /*
470  * @unimplemented
471  */
472 int
473 WINAPI
474 StartDocW(
475     HDC		hdc,
476     CONST DOCINFOW	*lpdi
477 )
478 {
479     PLDC pldc;
480     DOCINFOW diW;
481     DOC_INFO_1W di1W;
482     LPWSTR lpwstrRet = NULL;
483     BOOL Banding;
484     int PrnJobNo, Ret = SP_ERROR;
485     ULONG hType = GDI_HANDLE_GET_TYPE(hdc);
486 
487     if (hType == GDILoObjType_LO_DC_TYPE || hType == GDILoObjType_LO_METADC16_TYPE)
488         return SP_ERROR;
489 
490     pldc = GdiGetLDC(hdc);
491     if ( !pldc || pldc->Flags & LDC_ATENDPAGE)
492     {
493         SetLastError(ERROR_INVALID_HANDLE);
494         return SP_ERROR;
495     }
496 
497     if (!pldc->hPrinter) return SP_ERROR;
498 
499     pldc->Flags &= ~LDC_KILL_DOCUMENT;
500 
501     if (lpdi)
502         RtlCopyMemory(&diW, lpdi, sizeof(DOCINFOW));
503     else
504     {
505         diW.cbSize = sizeof(DOCINFOW);
506         diW.lpszDocName  = NULL;
507         diW.lpszOutput   = NULL;
508         diW.lpszDatatype = NULL;
509         diW.fwType = 0;
510     }
511 
512     if (!diW.lpszOutput)
513         if (pldc->pwszPort) diW.lpszOutput = pldc->pwszPort;
514 
515     lpwstrRet = fpStartDocDlgW(pldc->hPrinter, &diW);
516     if (lpwstrRet == (LPWSTR)SP_APPABORT)
517     {
518         pldc->Flags |= LDC_KILL_DOCUMENT;
519         return SP_ERROR;
520     }
521     if (lpwstrRet == (LPWSTR)SP_ERROR) return SP_ERROR;
522 
523     if (lpwstrRet != 0) diW.lpszOutput = lpwstrRet;
524 
525     Ret = DocumentEventEx( NULL,
526                            pldc->hPrinter,
527                            hdc,
528                            DOCUMENTEVENT_STARTDOC,
529                            sizeof(ULONG),
530                            &diW,
531                            0,
532                            NULL);
533 
534     if (Ret == SP_APPABORT)
535     {
536         pldc->Flags |= LDC_KILL_DOCUMENT;
537         Ret = SP_ERROR;
538     }
539     if (Ret == SP_ERROR)
540     {
541         if (lpwstrRet) LocalFree(lpwstrRet);
542         return Ret;
543     }
544 
545     di1W.pDocName    = (LPWSTR)diW.lpszDocName;
546     di1W.pOutputFile = (LPWSTR)diW.lpszOutput;
547     di1W.pDatatype   = (LPWSTR)diW.lpszDatatype;
548 
549     Ret = SP_ERROR;
550 
551     PrnJobNo = StartDocPrinterWEx(NULL, pldc->hPrinter, 1, (LPBYTE)&di1W);
552     if (PrnJobNo <= 0)
553     {
554         Ret = NtGdiStartDoc( hdc, &diW, &Banding, PrnJobNo);
555         if (Ret)
556         {
557             if (pldc->pAbortProc)
558             {
559                 GdiSAPCallback(pldc);
560                 pldc->Flags |= LDC_SAPCALLBACK;
561                 pldc->CallBackTick = GetTickCount();
562             }
563             pldc->Flags |= LDC_INIT_DOCUMENT;
564             if (!Banding) pldc->Flags |= LDC_STARTPAGE;
565         }
566     }
567     if (Ret == SP_ERROR)
568     {
569         //if ( pldc->pUMPDev  )
570         AbortPrinterEx(NULL, pldc->hPrinter);
571         DPRINT1("StartDoc Died!!!\n");
572     }
573     else
574     {
575         if ( DocumentEventEx( NULL,
576                               pldc->hPrinter,
577                               hdc,
578                               DOCUMENTEVENT_STARTDOCPOST,
579                               sizeof(ULONG),
580                               &Ret,
581                               0,
582                               NULL) == SP_ERROR)
583         {
584             AbortDoc(hdc);
585             Ret = SP_ERROR;
586         }
587     }
588     if (lpwstrRet) LocalFree(lpwstrRet);
589     return Ret;
590 }
591 
592 /*
593  * @implemented
594  */
595 int
596 WINAPI
597 StartDocA(
598     HDC		hdc,
599     CONST DOCINFOA	*lpdi
600 )
601 {
602     LPWSTR szDocName = NULL, szOutput = NULL, szDatatype = NULL;
603     DOCINFOW docW;
604     INT ret, len;
605 
606     docW.cbSize = lpdi->cbSize;
607     if (lpdi->lpszDocName)
608     {
609         len = MultiByteToWideChar(CP_ACP,0,lpdi->lpszDocName,-1,NULL,0);
610         szDocName = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
611         MultiByteToWideChar(CP_ACP,0,lpdi->lpszDocName,-1,szDocName,len);
612     }
613     if (lpdi->lpszOutput)
614     {
615         len = MultiByteToWideChar(CP_ACP,0,lpdi->lpszOutput,-1,NULL,0);
616         szOutput = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
617         MultiByteToWideChar(CP_ACP,0,lpdi->lpszOutput,-1,szOutput,len);
618     }
619     if (lpdi->lpszDatatype)
620     {
621         len = MultiByteToWideChar(CP_ACP,0,lpdi->lpszDatatype,-1,NULL,0);
622         szDatatype = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
623         MultiByteToWideChar(CP_ACP,0,lpdi->lpszDatatype,-1,szDatatype,len);
624     }
625 
626     docW.lpszDocName = szDocName;
627     docW.lpszOutput = szOutput;
628     docW.lpszDatatype = szDatatype;
629     docW.fwType = lpdi->fwType;
630 
631     ret = StartDocW(hdc, &docW);
632 
633     HeapFree( GetProcessHeap(), 0, szDocName );
634     HeapFree( GetProcessHeap(), 0, szOutput );
635     HeapFree( GetProcessHeap(), 0, szDatatype );
636 
637     return ret;
638 }
639 
640 /*
641  * @unimplemented
642  */
643 int
644 WINAPI
645 StartPage(
646     HDC	hdc
647 )
648 {
649     PLDC pldc;
650     ULONG hType = GDI_HANDLE_GET_TYPE(hdc);
651 
652     if (hType == GDILoObjType_LO_DC_TYPE || hType == GDILoObjType_LO_METADC16_TYPE)
653     {
654         SetLastError(ERROR_INVALID_HANDLE);
655         return SP_ERROR;
656     }
657 
658     pldc = GdiGetLDC(hdc);
659     if ( !pldc )
660     {
661         SetLastError(ERROR_INVALID_HANDLE);
662         return SP_ERROR;
663     }
664 
665     if (pldc->Flags & LDC_META_PRINT)
666     {
667         UNIMPLEMENTED;
668         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
669         return SP_ERROR;
670     }
671 
672     pldc->Flags &= ~(LDC_ATENDPAGE|LDC_STARTPAGE);
673 
674     if (pldc->Flags & LDC_INIT_PAGE) return 1;
675 
676     if (DocumentEventEx(NULL, pldc->hPrinter, hdc, DOCUMENTEVENT_STARTPAGE, 0, NULL, 0, NULL) != SP_ERROR)
677     {
678         pldc->Flags |= LDC_INIT_PAGE;
679 
680         ((PW32CLIENTINFO)NtCurrentTeb()->Win32ClientInfo)->cSpins = 0;
681 
682         if (StartPagePrinterEx(NULL, pldc->hPrinter))
683         {
684             if (NtGdiStartPage(hdc)) return 1;
685         }
686 
687         pldc->Flags &= ~(LDC_INIT_PAGE);
688         EndDoc(hdc);
689         SetLastError(ERROR_INVALID_HANDLE);
690     }
691     return SP_ERROR;
692 }
693 
694 /*
695  * @implemented
696  */
697 int
698 WINAPI
699 StartFormPage(HDC hdc)
700 {
701     return StartPage(hdc);
702 }
703 
704 
705 /*
706  * @implemented
707  */
708 int
709 WINAPI
710 SetAbortProc(
711     HDC hdc,
712     ABORTPROC lpAbortProc)
713 {
714     PLDC pldc;
715     ULONG hType = GDI_HANDLE_GET_TYPE(hdc);
716 
717     if (hType == GDILoObjType_LO_DC_TYPE || hType == GDILoObjType_LO_METADC16_TYPE)
718         return SP_ERROR;
719 
720     pldc = GdiGetLDC(hdc);
721     if ( pldc )
722     {
723         if ( lpAbortProc )
724         {
725             if ( pldc->Flags & LDC_INIT_DOCUMENT )
726             {
727                 pldc->Flags |= LDC_SAPCALLBACK;
728                 pldc->CallBackTick = GetTickCount();
729             }
730         }
731         else
732         {
733             pldc->Flags &= ~LDC_SAPCALLBACK;
734         }
735         pldc->pAbortProc = lpAbortProc;
736         return 1;
737     }
738     else
739     {
740         SetLastError(ERROR_INVALID_HANDLE);
741     }
742     return SP_ERROR;
743 }
744 
745 /*
746  * @unimplemented
747  */
748 DWORD
749 WINAPI
750 gdiPlaySpoolStream(
751     DWORD	a0,
752     DWORD	a1,
753     DWORD	a2,
754     DWORD	a3,
755     DWORD	a4,
756     DWORD	a5
757 )
758 {
759     UNIMPLEMENTED;
760     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
761     return 0;
762 }
763 
764 /*
765  * @unimplemented
766  */
767 HDC
768 WINAPI
769 GdiGetDC(HANDLE SpoolFileHandle)
770 {
771     UNIMPLEMENTED;
772     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
773     return 0;
774 }
775 
776 /*
777  * @unimplemented
778  */
779 HANDLE
780 WINAPI
781 GdiGetPageHandle(HANDLE SpoolFileHandle,
782                  DWORD Page,
783                  LPDWORD pdwPageType)
784 {
785     UNIMPLEMENTED;
786     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
787     return 0;
788 }
789 
790 /*
791  * @unimplemented
792  */
793 BOOL
794 WINAPI
795 GdiStartDocEMF(HANDLE SpoolFileHandle,
796                DOCINFOW *pDocInfo)
797 {
798     UNIMPLEMENTED;
799     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
800     return 0;
801 }
802 
803 /*
804  * @unimplemented
805  */
806 BOOL
807 WINAPI
808 GdiStartPageEMF(HANDLE SpoolFileHandle)
809 {
810     UNIMPLEMENTED;
811     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
812     return 0;
813 }
814 
815 /*
816  * @unimplemented
817  */
818 BOOL
819 WINAPI
820 GdiPlayPageEMF(HANDLE SpoolFileHandle,
821                HANDLE hemf,
822                RECT *prectDocument,
823                RECT *prectBorder,
824                RECT *prectClip)
825 {
826     UNIMPLEMENTED;
827     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
828     return 0;
829 }
830 
831 /*
832  * @unimplemented
833  */
834 BOOL
835 WINAPI
836 GdiEndPageEMF(HANDLE SpoolFileHandle,
837               DWORD dwOptimization)
838 {
839     UNIMPLEMENTED;
840     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
841     return 0;
842 }
843 
844 /*
845  * @unimplemented
846  */
847 BOOL
848 WINAPI
849 GdiEndDocEMF(HANDLE SpoolFileHandle)
850 {
851     UNIMPLEMENTED;
852     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
853     return 0;
854 }
855 
856 /*
857  * @unimplemented
858  */
859 BOOL
860 WINAPI
861 GdiGetDevmodeForPage(HANDLE SpoolFileHandle,
862                      DWORD dwPageNumber,
863                      PDEVMODEW *pCurrDM,
864                      PDEVMODEW *pLastDM)
865 {
866     UNIMPLEMENTED;
867     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
868     return 0;
869 }
870 
871 /*
872  * @unimplemented
873  */
874 BOOL
875 WINAPI
876 GdiResetDCEMF(HANDLE SpoolFileHandle,
877               PDEVMODEW pCurrDM)
878 {
879     UNIMPLEMENTED;
880     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
881     return 0;
882 }
883 
884 
885 /*
886  * @unimplemented
887  */
888 BOOL
889 WINAPI
890 GdiPlayEMF(LPWSTR pwszPrinterName,
891            LPDEVMODEW pDevmode,
892            LPWSTR pwszDocName,
893            EMFPLAYPROC pfnEMFPlayFn,
894            HANDLE hPageQuery
895           )
896 {
897     UNIMPLEMENTED;
898     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
899     return 0;
900 }
901 
902 /*
903  * @unimplemented
904  */
905 BOOL
906 WINAPI
907 GdiPlayPrivatePageEMF(HANDLE SpoolFileHandle,
908                       DWORD unknown,
909                       RECT *prectDocument)
910 {
911     UNIMPLEMENTED;
912     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
913     return 0;
914 }
915 
916 /*
917  * @unimplemented
918  */
919 BOOL
920 WINAPI
921 GdiPrinterThunk(
922     IN HUMPD humpd,
923     DWORD *status,
924     DWORD unuse)
925 {
926     /* FIXME figout the protypes, the HUMPD are a STRUCT or COM object */
927     /* status contain some form of return value that being save, what it is I do not known */
928     /* unsue seam have zero effect, what it is for I do not known */
929 
930     // ? return NtGdiSetPUMPDOBJ(humpd->0x10,TRUE, humpd, ?) <- blackbox, OpenRCE info, and api hooks for anylaysing;
931     return FALSE;
932 }
933 
934 /*
935  * @unimplemented
936  */
937 BOOL
938 WINAPI
939 GdiArtificialDecrementDriver(LPWSTR pDriverName,BOOL unknown)
940 {
941     UNIMPLEMENTED;
942     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
943     return 0;
944 }
945