Handle wParam in WM_PAINT properly: if non-null, it is the hdc we are
[wine] / dlls / gdi / dc.c
1 /*
2  * GDI Device Context functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winreg.h"
30 #include "winternl.h"
31 #include "winerror.h"
32 #include "wownt32.h"
33 #include "wine/winuser16.h"
34 #include "gdi.h"
35 #include "gdi_private.h"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(dc);
40
41 static BOOL DC_DeleteObject( HGDIOBJ handle, void *obj );
42
43 static const struct gdi_obj_funcs dc_funcs =
44 {
45     NULL,             /* pSelectObject */
46     NULL,             /* pGetObject16 */
47     NULL,             /* pGetObjectA */
48     NULL,             /* pGetObjectW */
49     NULL,             /* pUnrealizeObject */
50     DC_DeleteObject   /* pDeleteObject */
51 };
52
53 /***********************************************************************
54  *           DC_AllocDC
55  */
56 DC *DC_AllocDC( const DC_FUNCTIONS *funcs, WORD magic )
57 {
58     HDC hdc;
59     DC *dc;
60
61     if (!(dc = GDI_AllocObject( sizeof(*dc), magic, (HGDIOBJ*)&hdc, &dc_funcs ))) return NULL;
62
63     dc->hSelf               = hdc;
64     dc->funcs               = funcs;
65     dc->physDev             = NULL;
66     dc->saveLevel           = 0;
67     dc->dwHookData          = 0;
68     dc->hookProc            = NULL;
69     dc->hookThunk           = NULL;
70     dc->wndOrgX             = 0;
71     dc->wndOrgY             = 0;
72     dc->wndExtX             = 1;
73     dc->wndExtY             = 1;
74     dc->vportOrgX           = 0;
75     dc->vportOrgY           = 0;
76     dc->vportExtX           = 1;
77     dc->vportExtY           = 1;
78     dc->miterLimit          = 10.0f; /* 10.0 is the default, from MSDN */
79     dc->flags               = 0;
80     dc->layout              = 0;
81     dc->hClipRgn            = 0;
82     dc->hVisRgn             = 0;
83     dc->hPen                = GetStockObject( BLACK_PEN );
84     dc->hBrush              = GetStockObject( WHITE_BRUSH );
85     dc->hFont               = GetStockObject( SYSTEM_FONT );
86     dc->hBitmap             = 0;
87     dc->hDevice             = 0;
88     dc->hPalette            = GetStockObject( DEFAULT_PALETTE );
89     dc->gdiFont             = 0;
90     dc->ROPmode             = R2_COPYPEN;
91     dc->polyFillMode        = ALTERNATE;
92     dc->stretchBltMode      = BLACKONWHITE;
93     dc->relAbsMode          = ABSOLUTE;
94     dc->backgroundMode      = OPAQUE;
95     dc->backgroundColor     = RGB( 255, 255, 255 );
96     dc->dcBrushColor        = RGB( 255, 255, 255 );
97     dc->dcPenColor          = RGB( 0, 0, 0 );
98     dc->textColor           = RGB( 0, 0, 0 );
99     dc->brushOrgX           = 0;
100     dc->brushOrgY           = 0;
101     dc->textAlign           = TA_LEFT | TA_TOP | TA_NOUPDATECP;
102     dc->charExtra           = 0;
103     dc->breakExtra          = 0;
104     dc->breakRem            = 0;
105     dc->MapMode             = MM_TEXT;
106     dc->GraphicsMode        = GM_COMPATIBLE;
107     dc->pAbortProc          = NULL;
108     dc->CursPosX            = 0;
109     dc->CursPosY            = 0;
110     dc->ArcDirection        = AD_COUNTERCLOCKWISE;
111     dc->xformWorld2Wnd.eM11 = 1.0f;
112     dc->xformWorld2Wnd.eM12 = 0.0f;
113     dc->xformWorld2Wnd.eM21 = 0.0f;
114     dc->xformWorld2Wnd.eM22 = 1.0f;
115     dc->xformWorld2Wnd.eDx  = 0.0f;
116     dc->xformWorld2Wnd.eDy  = 0.0f;
117     dc->xformWorld2Vport    = dc->xformWorld2Wnd;
118     dc->xformVport2World    = dc->xformWorld2Wnd;
119     dc->vport2WorldValid    = TRUE;
120     dc->BoundsRect.left     = 0;
121     dc->BoundsRect.top      = 0;
122     dc->BoundsRect.right    = 0;
123     dc->BoundsRect.bottom   = 0;
124     PATH_InitGdiPath(&dc->path);
125     return dc;
126 }
127
128
129
130 /***********************************************************************
131  *           DC_GetDCPtr
132  */
133 DC *DC_GetDCPtr( HDC hdc )
134 {
135     GDIOBJHDR *ptr = GDI_GetObjPtr( hdc, MAGIC_DONTCARE );
136     if (!ptr) return NULL;
137     if ((GDIMAGIC(ptr->wMagic) == DC_MAGIC) ||
138         (GDIMAGIC(ptr->wMagic) == MEMORY_DC_MAGIC) ||
139         (GDIMAGIC(ptr->wMagic) == METAFILE_DC_MAGIC) ||
140         (GDIMAGIC(ptr->wMagic) == ENHMETAFILE_DC_MAGIC))
141         return (DC *)ptr;
142     GDI_ReleaseObj( hdc );
143     SetLastError( ERROR_INVALID_HANDLE );
144     return NULL;
145 }
146
147 /***********************************************************************
148  *           DC_GetDCUpdate
149  *
150  * Retrieve a DC ptr while making sure the visRgn is updated.
151  * This function may call up to USER so the GDI lock should _not_
152  * be held when calling it.
153  */
154 DC *DC_GetDCUpdate( HDC hdc )
155 {
156     DC *dc = DC_GetDCPtr( hdc );
157     if (!dc) return NULL;
158     while (dc->flags & DC_DIRTY)
159     {
160         DCHOOKPROC proc = dc->hookThunk;
161         dc->flags &= ~DC_DIRTY;
162         if (proc)
163         {
164             DWORD data = dc->dwHookData;
165             GDI_ReleaseObj( hdc );
166             proc( HDC_16(hdc), DCHC_INVALIDVISRGN, data, 0 );
167             if (!(dc = DC_GetDCPtr( hdc ))) break;
168             /* otherwise restart the loop in case it became dirty again in the meantime */
169         }
170     }
171     return dc;
172 }
173
174
175 /***********************************************************************
176  *           DC_DeleteObject
177  */
178 static BOOL DC_DeleteObject( HGDIOBJ handle, void *obj )
179 {
180     GDI_ReleaseObj( handle );
181     return DeleteDC( handle );
182 }
183
184
185 /***********************************************************************
186  *           DC_InitDC
187  *
188  * Setup device-specific DC values for a newly created DC.
189  */
190 void DC_InitDC( DC* dc )
191 {
192     if (dc->funcs->pRealizeDefaultPalette) dc->funcs->pRealizeDefaultPalette( dc->physDev );
193     SetTextColor( dc->hSelf, dc->textColor );
194     SetBkColor( dc->hSelf, dc->backgroundColor );
195     SelectObject( dc->hSelf, dc->hPen );
196     SelectObject( dc->hSelf, dc->hBrush );
197     SelectObject( dc->hSelf, dc->hFont );
198     CLIPPING_UpdateGCRegion( dc );
199 }
200
201
202 /***********************************************************************
203  *           DC_InvertXform
204  *
205  * Computes the inverse of the transformation xformSrc and stores it to
206  * xformDest. Returns TRUE if successful or FALSE if the xformSrc matrix
207  * is singular.
208  */
209 static BOOL DC_InvertXform( const XFORM *xformSrc, XFORM *xformDest )
210 {
211     FLOAT determinant;
212
213     determinant = xformSrc->eM11*xformSrc->eM22 -
214         xformSrc->eM12*xformSrc->eM21;
215     if (determinant > -1e-12 && determinant < 1e-12)
216         return FALSE;
217
218     xformDest->eM11 =  xformSrc->eM22 / determinant;
219     xformDest->eM12 = -xformSrc->eM12 / determinant;
220     xformDest->eM21 = -xformSrc->eM21 / determinant;
221     xformDest->eM22 =  xformSrc->eM11 / determinant;
222     xformDest->eDx  = -xformSrc->eDx * xformDest->eM11 -
223                        xformSrc->eDy * xformDest->eM21;
224     xformDest->eDy  = -xformSrc->eDx * xformDest->eM12 -
225                        xformSrc->eDy * xformDest->eM22;
226
227     return TRUE;
228 }
229
230
231 /***********************************************************************
232  *           DC_UpdateXforms
233  *
234  * Updates the xformWorld2Vport, xformVport2World and vport2WorldValid
235  * fields of the specified DC by creating a transformation that
236  * represents the current mapping mode and combining it with the DC's
237  * world transform. This function should be called whenever the
238  * parameters associated with the mapping mode (window and viewport
239  * extents and origins) or the world transform change.
240  */
241 void DC_UpdateXforms( DC *dc )
242 {
243     XFORM xformWnd2Vport, oldworld2vport;
244     FLOAT scaleX, scaleY;
245
246     /* Construct a transformation to do the window-to-viewport conversion */
247     scaleX = (FLOAT)dc->vportExtX / (FLOAT)dc->wndExtX;
248     scaleY = (FLOAT)dc->vportExtY / (FLOAT)dc->wndExtY;
249     xformWnd2Vport.eM11 = scaleX;
250     xformWnd2Vport.eM12 = 0.0;
251     xformWnd2Vport.eM21 = 0.0;
252     xformWnd2Vport.eM22 = scaleY;
253     xformWnd2Vport.eDx  = (FLOAT)dc->vportOrgX -
254         scaleX * (FLOAT)dc->wndOrgX;
255     xformWnd2Vport.eDy  = (FLOAT)dc->vportOrgY -
256         scaleY * (FLOAT)dc->wndOrgY;
257
258     oldworld2vport = dc->xformWorld2Vport;
259     /* Combine with the world transformation */
260     CombineTransform( &dc->xformWorld2Vport, &dc->xformWorld2Wnd,
261         &xformWnd2Vport );
262
263     /* Create inverse of world-to-viewport transformation */
264     dc->vport2WorldValid = DC_InvertXform( &dc->xformWorld2Vport,
265         &dc->xformVport2World );
266
267     /* Reselect the font and pen back into the dc so that the size
268        gets updated. */
269     if(memcmp(&oldworld2vport, &dc->xformWorld2Vport, sizeof(oldworld2vport)))
270     {
271         SelectObject(dc->hSelf, GetCurrentObject(dc->hSelf, OBJ_FONT));
272         SelectObject(dc->hSelf, GetCurrentObject(dc->hSelf, OBJ_PEN));
273     }
274 }
275
276
277 /***********************************************************************
278  *           GetDCState   (Not a Windows API)
279  */
280 HDC WINAPI GetDCState( HDC hdc )
281 {
282     DC * newdc, * dc;
283     HGDIOBJ handle;
284
285     if (!(dc = DC_GetDCPtr( hdc ))) return 0;
286     if (!(newdc = GDI_AllocObject( sizeof(DC), GDIMAGIC(dc->header.wMagic), &handle, &dc_funcs )))
287     {
288       GDI_ReleaseObj( hdc );
289       return 0;
290     }
291     TRACE("(%p): returning %p\n", hdc, handle );
292
293     newdc->flags            = dc->flags | DC_SAVED;
294     newdc->layout           = dc->layout;
295     newdc->hPen             = dc->hPen;
296     newdc->hBrush           = dc->hBrush;
297     newdc->hFont            = dc->hFont;
298     newdc->hBitmap          = dc->hBitmap;
299     newdc->hDevice          = dc->hDevice;
300     newdc->hPalette         = dc->hPalette;
301     newdc->ROPmode          = dc->ROPmode;
302     newdc->polyFillMode     = dc->polyFillMode;
303     newdc->stretchBltMode   = dc->stretchBltMode;
304     newdc->relAbsMode       = dc->relAbsMode;
305     newdc->backgroundMode   = dc->backgroundMode;
306     newdc->backgroundColor  = dc->backgroundColor;
307     newdc->textColor        = dc->textColor;
308     newdc->dcBrushColor     = dc->dcBrushColor;
309     newdc->dcPenColor       = dc->dcPenColor;
310     newdc->brushOrgX        = dc->brushOrgX;
311     newdc->brushOrgY        = dc->brushOrgY;
312     newdc->textAlign        = dc->textAlign;
313     newdc->charExtra        = dc->charExtra;
314     newdc->breakExtra       = dc->breakExtra;
315     newdc->breakRem         = dc->breakRem;
316     newdc->MapMode          = dc->MapMode;
317     newdc->GraphicsMode     = dc->GraphicsMode;
318     newdc->CursPosX         = dc->CursPosX;
319     newdc->CursPosY         = dc->CursPosY;
320     newdc->ArcDirection     = dc->ArcDirection;
321     newdc->xformWorld2Wnd   = dc->xformWorld2Wnd;
322     newdc->xformWorld2Vport = dc->xformWorld2Vport;
323     newdc->xformVport2World = dc->xformVport2World;
324     newdc->vport2WorldValid = dc->vport2WorldValid;
325     newdc->wndOrgX          = dc->wndOrgX;
326     newdc->wndOrgY          = dc->wndOrgY;
327     newdc->wndExtX          = dc->wndExtX;
328     newdc->wndExtY          = dc->wndExtY;
329     newdc->vportOrgX        = dc->vportOrgX;
330     newdc->vportOrgY        = dc->vportOrgY;
331     newdc->vportExtX        = dc->vportExtX;
332     newdc->vportExtY        = dc->vportExtY;
333     newdc->BoundsRect       = dc->BoundsRect;
334
335     newdc->hSelf = (HDC)handle;
336     newdc->saveLevel = 0;
337
338     PATH_InitGdiPath( &newdc->path );
339
340     newdc->pAbortProc = NULL;
341     newdc->hookThunk  = NULL;
342     newdc->hookProc   = 0;
343
344     /* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
345
346     newdc->hVisRgn = 0;
347     if (dc->hClipRgn)
348     {
349         newdc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
350         CombineRgn( newdc->hClipRgn, dc->hClipRgn, 0, RGN_COPY );
351     }
352     else
353         newdc->hClipRgn = 0;
354
355     if(dc->gdiFont) {
356         newdc->gdiFont = dc->gdiFont;
357     } else
358         newdc->gdiFont = 0;
359
360     GDI_ReleaseObj( handle );
361     GDI_ReleaseObj( hdc );
362     return handle;
363 }
364
365
366 /***********************************************************************
367  *           SetDCState   (Not a Windows API)
368  */
369 void WINAPI SetDCState( HDC hdc, HDC hdcs )
370 {
371     DC *dc, *dcs;
372
373     if (!(dc = DC_GetDCUpdate( hdc ))) return;
374     if (!(dcs = DC_GetDCPtr( hdcs )))
375     {
376       GDI_ReleaseObj( hdc );
377       return;
378     }
379     if (!dcs->flags & DC_SAVED)
380     {
381       GDI_ReleaseObj( hdc );
382       GDI_ReleaseObj( hdcs );
383       return;
384     }
385     TRACE("%p %p\n", hdc, hdcs );
386
387     dc->flags            = dcs->flags & ~(DC_SAVED | DC_DIRTY);
388     dc->layout           = dcs->layout;
389     dc->hDevice          = dcs->hDevice;
390     dc->ROPmode          = dcs->ROPmode;
391     dc->polyFillMode     = dcs->polyFillMode;
392     dc->stretchBltMode   = dcs->stretchBltMode;
393     dc->relAbsMode       = dcs->relAbsMode;
394     dc->backgroundMode   = dcs->backgroundMode;
395     dc->backgroundColor  = dcs->backgroundColor;
396     dc->textColor        = dcs->textColor;
397     dc->dcBrushColor     = dcs->dcBrushColor;
398     dc->dcPenColor       = dcs->dcPenColor;
399     dc->brushOrgX        = dcs->brushOrgX;
400     dc->brushOrgY        = dcs->brushOrgY;
401     dc->textAlign        = dcs->textAlign;
402     dc->charExtra        = dcs->charExtra;
403     dc->breakExtra       = dcs->breakExtra;
404     dc->breakRem         = dcs->breakRem;
405     dc->MapMode          = dcs->MapMode;
406     dc->GraphicsMode     = dcs->GraphicsMode;
407     dc->CursPosX         = dcs->CursPosX;
408     dc->CursPosY         = dcs->CursPosY;
409     dc->ArcDirection     = dcs->ArcDirection;
410     dc->xformWorld2Wnd   = dcs->xformWorld2Wnd;
411     dc->xformWorld2Vport = dcs->xformWorld2Vport;
412     dc->xformVport2World = dcs->xformVport2World;
413     dc->vport2WorldValid = dcs->vport2WorldValid;
414     dc->BoundsRect       = dcs->BoundsRect;
415
416     dc->wndOrgX          = dcs->wndOrgX;
417     dc->wndOrgY          = dcs->wndOrgY;
418     dc->wndExtX          = dcs->wndExtX;
419     dc->wndExtY          = dcs->wndExtY;
420     dc->vportOrgX        = dcs->vportOrgX;
421     dc->vportOrgY        = dcs->vportOrgY;
422     dc->vportExtX        = dcs->vportExtX;
423     dc->vportExtY        = dcs->vportExtY;
424
425     if (dcs->hClipRgn)
426     {
427         if (!dc->hClipRgn) dc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
428         CombineRgn( dc->hClipRgn, dcs->hClipRgn, 0, RGN_COPY );
429     }
430     else
431     {
432         if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
433         dc->hClipRgn = 0;
434     }
435     CLIPPING_UpdateGCRegion( dc );
436
437     SelectObject( hdc, dcs->hBitmap );
438     SelectObject( hdc, dcs->hBrush );
439     SelectObject( hdc, dcs->hFont );
440     SelectObject( hdc, dcs->hPen );
441     SetBkColor( hdc, dcs->backgroundColor);
442     SetTextColor( hdc, dcs->textColor);
443     GDISelectPalette( hdc, dcs->hPalette, FALSE );
444     GDI_ReleaseObj( hdcs );
445     GDI_ReleaseObj( hdc );
446 }
447
448
449 /***********************************************************************
450  *           GetDCState   (GDI.179)
451  */
452 HDC16 WINAPI GetDCState16( HDC16 hdc )
453 {
454     return HDC_16( GetDCState( HDC_32(hdc) ));
455 }
456
457
458 /***********************************************************************
459  *           SetDCState   (GDI.180)
460  */
461 void WINAPI SetDCState16( HDC16 hdc, HDC16 hdcs )
462 {
463     SetDCState( HDC_32(hdc), HDC_32(hdcs) );
464 }
465
466
467 /***********************************************************************
468  *           SaveDC    (GDI32.@)
469  */
470 INT WINAPI SaveDC( HDC hdc )
471 {
472     HDC hdcs;
473     DC * dc, * dcs;
474     INT ret;
475
476     dc = DC_GetDCPtr( hdc );
477     if (!dc) return 0;
478
479     if(dc->funcs->pSaveDC)
480     {
481         ret = dc->funcs->pSaveDC( dc->physDev );
482         GDI_ReleaseObj( hdc );
483         return ret;
484     }
485
486     if (!(hdcs = GetDCState( hdc )))
487     {
488       GDI_ReleaseObj( hdc );
489       return 0;
490     }
491     dcs = DC_GetDCPtr( hdcs );
492
493     /* Copy path. The reason why path saving / restoring is in SaveDC/
494      * RestoreDC and not in GetDCState/SetDCState is that the ...DCState
495      * functions are only in Win16 (which doesn't have paths) and that
496      * SetDCState doesn't allow us to signal an error (which can happen
497      * when copying paths).
498      */
499     if (!PATH_AssignGdiPath( &dcs->path, &dc->path ))
500     {
501         GDI_ReleaseObj( hdc );
502         GDI_ReleaseObj( hdcs );
503         DeleteDC( hdcs );
504         return 0;
505     }
506
507     dcs->header.hNext = dc->header.hNext;
508     dc->header.hNext = HDC_16(hdcs);
509     TRACE("(%p): returning %d\n", hdc, dc->saveLevel+1 );
510     ret = ++dc->saveLevel;
511     GDI_ReleaseObj( hdcs );
512     GDI_ReleaseObj( hdc );
513     return ret;
514 }
515
516
517 /***********************************************************************
518  *           RestoreDC    (GDI32.@)
519  */
520 BOOL WINAPI RestoreDC( HDC hdc, INT level )
521 {
522     DC * dc, * dcs;
523     BOOL success;
524
525     TRACE("%p %d\n", hdc, level );
526     dc = DC_GetDCUpdate( hdc );
527     if(!dc) return FALSE;
528     if(dc->funcs->pRestoreDC)
529     {
530         success = dc->funcs->pRestoreDC( dc->physDev, level );
531         GDI_ReleaseObj( hdc );
532         return success;
533     }
534
535     if (level == -1) level = dc->saveLevel;
536     if ((level < 1)
537             /* This pair of checks disagrees with MSDN "Platform SDK:
538                Windows GDI" July 2000 which says all negative values
539                for level will be interpreted as an instance relative
540                to the current state.  Restricting it to just -1 does
541                not satisfy this */
542         || (level > dc->saveLevel))
543     {
544         GDI_ReleaseObj( hdc );
545         return FALSE;
546     }
547
548     success=TRUE;
549     while (dc->saveLevel >= level)
550     {
551         HDC hdcs = HDC_32(dc->header.hNext);
552         if (!(dcs = DC_GetDCPtr( hdcs )))
553         {
554           GDI_ReleaseObj( hdc );
555           return FALSE;
556         }
557         dc->header.hNext = dcs->header.hNext;
558         if (--dc->saveLevel < level)
559         {
560             SetDCState( hdc, hdcs );
561             if (!PATH_AssignGdiPath( &dc->path, &dcs->path ))
562                 /* FIXME: This might not be quite right, since we're
563                  * returning FALSE but still destroying the saved DC state */
564                 success=FALSE;
565         }
566         GDI_ReleaseObj( hdcs );
567         GDI_ReleaseObj( hdc );
568         DeleteDC( hdcs );
569         if (!(dc = DC_GetDCPtr( hdc ))) return FALSE;
570     }
571     GDI_ReleaseObj( hdc );
572     return success;
573 }
574
575
576 /***********************************************************************
577  *           CreateDCW    (GDI32.@)
578  */
579 HDC WINAPI CreateDCW( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
580                       const DEVMODEW *initData )
581 {
582     HDC hdc;
583     DC * dc;
584     const DC_FUNCTIONS *funcs;
585     WCHAR buf[300];
586
587     GDI_CheckNotLock();
588
589     if (!device || !DRIVER_GetDriverName( device, buf, 300 ))
590     {
591         if (!driver) return 0;
592         strcpyW(buf, driver);
593     }
594
595     if (!(funcs = DRIVER_load_driver( buf )))
596     {
597         ERR( "no driver found for %s\n", debugstr_w(buf) );
598         return 0;
599     }
600     if (!(dc = DC_AllocDC( funcs, DC_MAGIC )))
601     {
602         DRIVER_release_driver( funcs );
603         return 0;
604     }
605     hdc = dc->hSelf;
606
607     dc->hBitmap = GetStockObject( DEFAULT_BITMAP );
608
609     TRACE("(driver=%s, device=%s, output=%s): returning %p\n",
610           debugstr_w(driver), debugstr_w(device), debugstr_w(output), dc->hSelf );
611
612     if (dc->funcs->pCreateDC &&
613         !dc->funcs->pCreateDC( hdc, &dc->physDev, buf, device, output, initData ))
614     {
615         WARN("creation aborted by device\n" );
616         GDI_FreeObject( dc->hSelf, dc );
617         DRIVER_release_driver( funcs );
618         return 0;
619     }
620
621     dc->hVisRgn = CreateRectRgn( 0, 0, GetDeviceCaps( hdc, HORZRES ),
622                                  GetDeviceCaps( hdc, VERTRES ) );
623
624     DC_InitDC( dc );
625     GDI_ReleaseObj( hdc );
626     return hdc;
627 }
628
629
630 /***********************************************************************
631  *           CreateDCA    (GDI32.@)
632  */
633 HDC WINAPI CreateDCA( LPCSTR driver, LPCSTR device, LPCSTR output,
634                       const DEVMODEA *initData )
635 {
636     UNICODE_STRING driverW, deviceW, outputW;
637     DEVMODEW *initDataW;
638     HDC ret;
639
640     if (driver) RtlCreateUnicodeStringFromAsciiz(&driverW, driver);
641     else driverW.Buffer = NULL;
642
643     if (device) RtlCreateUnicodeStringFromAsciiz(&deviceW, device);
644     else deviceW.Buffer = NULL;
645
646     if (output) RtlCreateUnicodeStringFromAsciiz(&outputW, output);
647     else outputW.Buffer = NULL;
648
649     if (initData) initDataW = GdiConvertToDevmodeW(initData);
650     else initDataW = NULL;
651
652     ret = CreateDCW( driverW.Buffer, deviceW.Buffer, outputW.Buffer, initDataW );
653
654     RtlFreeUnicodeString(&driverW);
655     RtlFreeUnicodeString(&deviceW);
656     RtlFreeUnicodeString(&outputW);
657     HeapFree(GetProcessHeap(), 0, initDataW);
658     return ret;
659 }
660
661
662 /***********************************************************************
663  *           CreateICA    (GDI32.@)
664  */
665 HDC WINAPI CreateICA( LPCSTR driver, LPCSTR device, LPCSTR output,
666                           const DEVMODEA* initData )
667 {
668       /* Nothing special yet for ICs */
669     return CreateDCA( driver, device, output, initData );
670 }
671
672
673 /***********************************************************************
674  *           CreateICW    (GDI32.@)
675  */
676 HDC WINAPI CreateICW( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
677                           const DEVMODEW* initData )
678 {
679       /* Nothing special yet for ICs */
680     return CreateDCW( driver, device, output, initData );
681 }
682
683
684 /***********************************************************************
685  *           CreateCompatibleDC   (GDI32.@)
686  */
687 HDC WINAPI CreateCompatibleDC( HDC hdc )
688 {
689     DC *dc, *origDC;
690     const DC_FUNCTIONS *funcs;
691     PHYSDEV physDev;
692
693     GDI_CheckNotLock();
694
695     if ((origDC = GDI_GetObjPtr( hdc, DC_MAGIC )))
696     {
697         funcs = origDC->funcs;
698         physDev = origDC->physDev;
699         GDI_ReleaseObj( hdc ); /* can't hold the lock while loading the driver */
700         funcs = DRIVER_get_driver( funcs );
701     }
702     else
703     {
704         static const WCHAR displayW[] = { 'd','i','s','p','l','a','y',0 };
705         funcs = DRIVER_load_driver( displayW );
706         physDev = NULL;
707     }
708
709     if (!funcs) return 0;
710
711     if (!(dc = DC_AllocDC( funcs, MEMORY_DC_MAGIC )))
712     {
713         DRIVER_release_driver( funcs );
714         return 0;
715     }
716
717     TRACE("(%p): returning %p\n", hdc, dc->hSelf );
718
719     dc->hBitmap = GetStockObject( DEFAULT_BITMAP );
720
721     /* Copy the driver-specific physical device info into
722      * the new DC. The driver may use this read-only info
723      * while creating the compatible DC below. */
724     dc->physDev = physDev;
725
726     if (dc->funcs->pCreateDC &&
727         !dc->funcs->pCreateDC( dc->hSelf, &dc->physDev, NULL, NULL, NULL, NULL ))
728     {
729         WARN("creation aborted by device\n");
730         GDI_FreeObject( dc->hSelf, dc );
731         DRIVER_release_driver( funcs );
732         return 0;
733     }
734
735     dc->hVisRgn = CreateRectRgn( 0, 0, 1, 1 );  /* default bitmap is 1x1 */
736
737     DC_InitDC( dc );
738     GDI_ReleaseObj( dc->hSelf );
739     return dc->hSelf;
740 }
741
742
743 /***********************************************************************
744  *           DeleteDC    (GDI32.@)
745  */
746 BOOL WINAPI DeleteDC( HDC hdc )
747 {
748     const DC_FUNCTIONS *funcs = NULL;
749     DC * dc;
750
751     TRACE("%p\n", hdc );
752
753     GDI_CheckNotLock();
754
755     if (!(dc = DC_GetDCPtr( hdc ))) return FALSE;
756
757     /* Call hook procedure to check whether is it OK to delete this DC */
758     if (dc->hookThunk)
759     {
760         DCHOOKPROC proc = dc->hookThunk;
761         DWORD data = dc->dwHookData;
762         GDI_ReleaseObj( hdc );
763         if (!proc( HDC_16(hdc), DCHC_DELETEDC, data, 0 )) return FALSE;
764         if (!(dc = DC_GetDCPtr( hdc ))) return TRUE;  /* deleted by the hook */
765     }
766
767     while (dc->saveLevel)
768     {
769         DC * dcs;
770         HDC hdcs = HDC_32(dc->header.hNext);
771         if (!(dcs = DC_GetDCPtr( hdcs ))) break;
772         dc->header.hNext = dcs->header.hNext;
773         dc->saveLevel--;
774         if (dcs->hClipRgn) DeleteObject( dcs->hClipRgn );
775         if (dcs->hVisRgn) DeleteObject( dcs->hVisRgn );
776         PATH_DestroyGdiPath(&dcs->path);
777         GDI_FreeObject( hdcs, dcs );
778     }
779
780     if (!(dc->flags & DC_SAVED))
781     {
782         SelectObject( hdc, GetStockObject(BLACK_PEN) );
783         SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
784         SelectObject( hdc, GetStockObject(SYSTEM_FONT) );
785         SelectObject( hdc, GetStockObject(DEFAULT_BITMAP) );
786         funcs = dc->funcs;
787         if (dc->funcs->pDeleteDC) dc->funcs->pDeleteDC(dc->physDev);
788         dc->physDev = NULL;
789     }
790
791     if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
792     if (dc->hVisRgn) DeleteObject( dc->hVisRgn );
793     PATH_DestroyGdiPath(&dc->path);
794
795     GDI_FreeObject( hdc, dc );
796     if (funcs) DRIVER_release_driver( funcs );  /* do that after releasing the GDI lock */
797     return TRUE;
798 }
799
800
801 /***********************************************************************
802  *           ResetDCW    (GDI32.@)
803  */
804 HDC WINAPI ResetDCW( HDC hdc, const DEVMODEW *devmode )
805 {
806     DC *dc;
807     HDC ret = hdc;
808
809     if ((dc = DC_GetDCPtr( hdc )))
810     {
811         if (dc->funcs->pResetDC) ret = dc->funcs->pResetDC( dc->physDev, devmode );
812         GDI_ReleaseObj( hdc );
813     }
814     return ret;
815 }
816
817
818 /***********************************************************************
819  *           ResetDCA    (GDI32.@)
820  */
821 HDC WINAPI ResetDCA( HDC hdc, const DEVMODEA *devmode )
822 {
823     DEVMODEW *devmodeW;
824     HDC ret;
825
826     if (devmode) devmodeW = GdiConvertToDevmodeW(devmode);
827     else devmodeW = NULL;
828
829     ret = ResetDCW(hdc, devmodeW);
830
831     HeapFree(GetProcessHeap(), 0, devmodeW);
832     return ret;
833 }
834
835
836 /***********************************************************************
837  *           GetDeviceCaps    (GDI32.@)
838  */
839 INT WINAPI GetDeviceCaps( HDC hdc, INT cap )
840 {
841     DC *dc;
842     INT ret = 0;
843
844     if ((dc = DC_GetDCPtr( hdc )))
845     {
846         if (dc->funcs->pGetDeviceCaps) ret = dc->funcs->pGetDeviceCaps( dc->physDev, cap );
847         GDI_ReleaseObj( hdc );
848     }
849     return ret;
850 }
851
852
853 /***********************************************************************
854  *              GetBkColor (GDI32.@)
855  */
856 COLORREF WINAPI GetBkColor( HDC hdc )
857 {
858     COLORREF ret = 0;
859     DC * dc = DC_GetDCPtr( hdc );
860     if (dc)
861     {
862         ret = dc->backgroundColor;
863         GDI_ReleaseObj( hdc );
864     }
865     return ret;
866 }
867
868
869 /***********************************************************************
870  *           SetBkColor    (GDI32.@)
871  */
872 COLORREF WINAPI SetBkColor( HDC hdc, COLORREF color )
873 {
874     COLORREF oldColor;
875     DC * dc = DC_GetDCPtr( hdc );
876
877     TRACE("hdc=%p color=0x%08lx\n", hdc, color);
878
879     if (!dc) return CLR_INVALID;
880     oldColor = dc->backgroundColor;
881     if (dc->funcs->pSetBkColor)
882     {
883         color = dc->funcs->pSetBkColor(dc->physDev, color);
884         if (color == CLR_INVALID)  /* don't change it */
885         {
886             color = oldColor;
887             oldColor = CLR_INVALID;
888         }
889     }
890     dc->backgroundColor = color;
891     GDI_ReleaseObj( hdc );
892     return oldColor;
893 }
894
895
896 /***********************************************************************
897  *              GetTextColor (GDI32.@)
898  */
899 COLORREF WINAPI GetTextColor( HDC hdc )
900 {
901     COLORREF ret = 0;
902     DC * dc = DC_GetDCPtr( hdc );
903     if (dc)
904     {
905         ret = dc->textColor;
906         GDI_ReleaseObj( hdc );
907     }
908     return ret;
909 }
910
911
912 /***********************************************************************
913  *           SetTextColor    (GDI32.@)
914  */
915 COLORREF WINAPI SetTextColor( HDC hdc, COLORREF color )
916 {
917     COLORREF oldColor;
918     DC * dc = DC_GetDCPtr( hdc );
919
920     TRACE(" hdc=%p color=0x%08lx\n", hdc, color);
921
922     if (!dc) return CLR_INVALID;
923     oldColor = dc->textColor;
924     if (dc->funcs->pSetTextColor)
925     {
926         color = dc->funcs->pSetTextColor(dc->physDev, color);
927         if (color == CLR_INVALID)  /* don't change it */
928         {
929             color = oldColor;
930             oldColor = CLR_INVALID;
931         }
932     }
933     dc->textColor = color;
934     GDI_ReleaseObj( hdc );
935     return oldColor;
936 }
937
938
939 /***********************************************************************
940  *              GetTextAlign (GDI32.@)
941  */
942 UINT WINAPI GetTextAlign( HDC hdc )
943 {
944     UINT ret = 0;
945     DC * dc = DC_GetDCPtr( hdc );
946     if (dc)
947     {
948         ret = dc->textAlign;
949         GDI_ReleaseObj( hdc );
950     }
951     return ret;
952 }
953
954
955 /***********************************************************************
956  *           SetTextAlign    (GDI32.@)
957  */
958 UINT WINAPI SetTextAlign( HDC hdc, UINT align )
959 {
960     UINT prevAlign;
961     DC *dc = DC_GetDCPtr( hdc );
962
963     TRACE("hdc=%p align=%d\n", hdc, align);
964
965     if (!dc) return 0x0;
966     if (dc->funcs->pSetTextAlign)
967         prevAlign = dc->funcs->pSetTextAlign(dc->physDev, align);
968     else {
969         prevAlign = dc->textAlign;
970         dc->textAlign = align;
971     }
972     GDI_ReleaseObj( hdc );
973     return prevAlign;
974 }
975
976 /***********************************************************************
977  *           GetDCOrgEx  (GDI32.@)
978  */
979 BOOL WINAPI GetDCOrgEx( HDC hDC, LPPOINT lpp )
980 {
981     DC * dc;
982
983     if (!lpp) return FALSE;
984     if (!(dc = DC_GetDCPtr( hDC ))) return FALSE;
985
986     lpp->x = lpp->y = 0;
987     if (dc->funcs->pGetDCOrgEx) dc->funcs->pGetDCOrgEx( dc->physDev, lpp );
988     GDI_ReleaseObj( hDC );
989     return TRUE;
990 }
991
992
993 /***********************************************************************
994  *           SetDCOrg   (GDI.117)
995  */
996 DWORD WINAPI SetDCOrg16( HDC16 hdc16, INT16 x, INT16 y )
997 {
998     DWORD prevOrg = 0;
999     HDC hdc = HDC_32( hdc16 );
1000     DC *dc = DC_GetDCPtr( hdc );
1001     if (!dc) return 0;
1002     if (dc->funcs->pSetDCOrg) prevOrg = dc->funcs->pSetDCOrg( dc->physDev, x, y );
1003     GDI_ReleaseObj( hdc );
1004     return prevOrg;
1005 }
1006
1007
1008 /***********************************************************************
1009  *              GetGraphicsMode (GDI32.@)
1010  */
1011 INT WINAPI GetGraphicsMode( HDC hdc )
1012 {
1013     INT ret = 0;
1014     DC * dc = DC_GetDCPtr( hdc );
1015     if (dc)
1016     {
1017         ret = dc->GraphicsMode;
1018         GDI_ReleaseObj( hdc );
1019     }
1020     return ret;
1021 }
1022
1023
1024 /***********************************************************************
1025  *           SetGraphicsMode    (GDI32.@)
1026  */
1027 INT WINAPI SetGraphicsMode( HDC hdc, INT mode )
1028 {
1029     INT ret = 0;
1030     DC *dc = DC_GetDCPtr( hdc );
1031
1032     /* One would think that setting the graphics mode to GM_COMPATIBLE
1033      * would also reset the world transformation matrix to the unity
1034      * matrix. However, in Windows, this is not the case. This doesn't
1035      * make a lot of sense to me, but that's the way it is.
1036      */
1037     if (!dc) return 0;
1038     if ((mode > 0) && (mode <= GM_LAST))
1039     {
1040         ret = dc->GraphicsMode;
1041         dc->GraphicsMode = mode;
1042     }
1043     GDI_ReleaseObj( hdc );
1044     return ret;
1045 }
1046
1047
1048 /***********************************************************************
1049  *              GetArcDirection (GDI32.@)
1050  */
1051 INT WINAPI GetArcDirection( HDC hdc )
1052 {
1053     INT ret = 0;
1054     DC * dc = DC_GetDCPtr( hdc );
1055     if (dc)
1056     {
1057         ret = dc->ArcDirection;
1058         GDI_ReleaseObj( hdc );
1059     }
1060     return ret;
1061 }
1062
1063
1064 /***********************************************************************
1065  *           SetArcDirection    (GDI32.@)
1066  */
1067 INT WINAPI SetArcDirection( HDC hdc, INT nDirection )
1068 {
1069     DC * dc;
1070     INT nOldDirection = 0;
1071
1072     if (nDirection!=AD_COUNTERCLOCKWISE && nDirection!=AD_CLOCKWISE)
1073     {
1074         SetLastError(ERROR_INVALID_PARAMETER);
1075         return 0;
1076     }
1077
1078     if ((dc = DC_GetDCPtr( hdc )))
1079     {
1080         if (dc->funcs->pSetArcDirection)
1081         {
1082             dc->funcs->pSetArcDirection(dc->physDev, nDirection);
1083         }
1084         nOldDirection = dc->ArcDirection;
1085         dc->ArcDirection = nDirection;
1086         GDI_ReleaseObj( hdc );
1087     }
1088     return nOldDirection;
1089 }
1090
1091
1092 /***********************************************************************
1093  *           GetWorldTransform    (GDI32.@)
1094  */
1095 BOOL WINAPI GetWorldTransform( HDC hdc, LPXFORM xform )
1096 {
1097     DC * dc;
1098     if (!xform) return FALSE;
1099     if (!(dc = DC_GetDCPtr( hdc ))) return FALSE;
1100     *xform = dc->xformWorld2Wnd;
1101     GDI_ReleaseObj( hdc );
1102     return TRUE;
1103 }
1104
1105
1106 /***********************************************************************
1107  *           GetTransform    (GDI32.@)
1108  */
1109 BOOL WINAPI GetTransform( HDC hdc, DWORD unknown, LPXFORM xform )
1110 {
1111     if (unknown == 0x0203) return GetWorldTransform( hdc, xform );
1112     FIXME("stub: don't know what to do for code %lx\n", unknown );
1113     return FALSE;
1114 }
1115
1116
1117 /***********************************************************************
1118  *           SetWorldTransform    (GDI32.@)
1119  */
1120 BOOL WINAPI SetWorldTransform( HDC hdc, const XFORM *xform )
1121 {
1122     BOOL ret = FALSE;
1123     DC *dc = DC_GetDCPtr( hdc );
1124
1125     if (!dc) return FALSE;
1126     if (!xform) goto done;
1127
1128     /* Check that graphics mode is GM_ADVANCED */
1129     if (dc->GraphicsMode!=GM_ADVANCED) goto done;
1130
1131     if (dc->funcs->pSetWorldTransform)
1132     {
1133         ret = dc->funcs->pSetWorldTransform(dc->physDev, xform);
1134         if (!ret) goto done;
1135     }
1136
1137     dc->xformWorld2Wnd = *xform;
1138     DC_UpdateXforms( dc );
1139     ret = TRUE;
1140  done:
1141     GDI_ReleaseObj( hdc );
1142     return ret;
1143 }
1144
1145
1146 /****************************************************************************
1147  * ModifyWorldTransform [GDI32.@]
1148  * Modifies the world transformation for a device context.
1149  *
1150  * PARAMS
1151  *    hdc   [I] Handle to device context
1152  *    xform [I] XFORM structure that will be used to modify the world
1153  *              transformation
1154  *    iMode [I] Specifies in what way to modify the world transformation
1155  *              Possible values:
1156  *              MWT_IDENTITY
1157  *                 Resets the world transformation to the identity matrix.
1158  *                 The parameter xform is ignored.
1159  *              MWT_LEFTMULTIPLY
1160  *                 Multiplies xform into the world transformation matrix from
1161  *                 the left.
1162  *              MWT_RIGHTMULTIPLY
1163  *                 Multiplies xform into the world transformation matrix from
1164  *                 the right.
1165  *
1166  * RETURNS
1167  *  Success: TRUE.
1168  *  Failure: FALSE. Use GetLastError() to determine the cause.
1169  */
1170 BOOL WINAPI ModifyWorldTransform( HDC hdc, const XFORM *xform,
1171     DWORD iMode )
1172 {
1173     BOOL ret = FALSE;
1174     DC *dc = DC_GetDCPtr( hdc );
1175
1176     /* Check for illegal parameters */
1177     if (!dc) return FALSE;
1178     if (!xform) goto done;
1179
1180     /* Check that graphics mode is GM_ADVANCED */
1181     if (dc->GraphicsMode!=GM_ADVANCED) goto done;
1182
1183     if (dc->funcs->pModifyWorldTransform)
1184     {
1185         ret = dc->funcs->pModifyWorldTransform(dc->physDev, xform, iMode);
1186         if (!ret) goto done;
1187     }
1188
1189     switch (iMode)
1190     {
1191         case MWT_IDENTITY:
1192             dc->xformWorld2Wnd.eM11 = 1.0f;
1193             dc->xformWorld2Wnd.eM12 = 0.0f;
1194             dc->xformWorld2Wnd.eM21 = 0.0f;
1195             dc->xformWorld2Wnd.eM22 = 1.0f;
1196             dc->xformWorld2Wnd.eDx  = 0.0f;
1197             dc->xformWorld2Wnd.eDy  = 0.0f;
1198             break;
1199         case MWT_LEFTMULTIPLY:
1200             CombineTransform( &dc->xformWorld2Wnd, xform,
1201                 &dc->xformWorld2Wnd );
1202             break;
1203         case MWT_RIGHTMULTIPLY:
1204             CombineTransform( &dc->xformWorld2Wnd, &dc->xformWorld2Wnd,
1205                 xform );
1206             break;
1207         default:
1208             goto done;
1209     }
1210
1211     DC_UpdateXforms( dc );
1212     ret = TRUE;
1213  done:
1214     GDI_ReleaseObj( hdc );
1215     return ret;
1216 }
1217
1218
1219 /****************************************************************************
1220  * CombineTransform [GDI32.@]
1221  * Combines two transformation matrices.
1222  *
1223  * PARAMS
1224  *    xformResult [O] Stores the result of combining the two matrices
1225  *    xform1      [I] Specifies the first matrix to apply
1226  *    xform2      [I] Specifies the second matrix to apply
1227  *
1228  * REMARKS
1229  *    The same matrix can be passed in for more than one of the parameters.
1230  *
1231  * RETURNS
1232  *  Success: TRUE.
1233  *  Failure: FALSE. Use GetLastError() to determine the cause.
1234  */
1235 BOOL WINAPI CombineTransform( LPXFORM xformResult, const XFORM *xform1,
1236     const XFORM *xform2 )
1237 {
1238     XFORM xformTemp;
1239
1240     /* Check for illegal parameters */
1241     if (!xformResult || !xform1 || !xform2)
1242         return FALSE;
1243
1244     /* Create the result in a temporary XFORM, since xformResult may be
1245      * equal to xform1 or xform2 */
1246     xformTemp.eM11 = xform1->eM11 * xform2->eM11 +
1247                      xform1->eM12 * xform2->eM21;
1248     xformTemp.eM12 = xform1->eM11 * xform2->eM12 +
1249                      xform1->eM12 * xform2->eM22;
1250     xformTemp.eM21 = xform1->eM21 * xform2->eM11 +
1251                      xform1->eM22 * xform2->eM21;
1252     xformTemp.eM22 = xform1->eM21 * xform2->eM12 +
1253                      xform1->eM22 * xform2->eM22;
1254     xformTemp.eDx  = xform1->eDx  * xform2->eM11 +
1255                      xform1->eDy  * xform2->eM21 +
1256                      xform2->eDx;
1257     xformTemp.eDy  = xform1->eDx  * xform2->eM12 +
1258                      xform1->eDy  * xform2->eM22 +
1259                      xform2->eDy;
1260
1261     /* Copy the result to xformResult */
1262     *xformResult = xformTemp;
1263
1264     return TRUE;
1265 }
1266
1267
1268 /***********************************************************************
1269  *           SetDCHook   (GDI32.@)
1270  *
1271  * Note: this doesn't exist in Win32, we add it here because user32 needs it.
1272  */
1273 BOOL WINAPI SetDCHook( HDC hdc, DCHOOKPROC hookProc, DWORD dwHookData )
1274 {
1275     DC *dc = GDI_GetObjPtr( hdc, DC_MAGIC );
1276
1277     if (!dc) return FALSE;
1278
1279     if (!(dc->flags & DC_SAVED))
1280     {
1281         dc->dwHookData = dwHookData;
1282         dc->hookThunk = hookProc;
1283     }
1284     GDI_ReleaseObj( hdc );
1285     return TRUE;
1286 }
1287
1288
1289 /* relay function to call the 16-bit DC hook proc */
1290 static BOOL16 WINAPI call_dc_hook16( HDC16 hdc16, WORD code, DWORD data, LPARAM lParam )
1291 {
1292     WORD args[6];
1293     DWORD ret;
1294     FARPROC16 proc = NULL;
1295     HDC hdc = HDC_32( hdc16 );
1296     DC *dc = DC_GetDCPtr( hdc );
1297
1298     if (!dc) return FALSE;
1299     proc = dc->hookProc;
1300     GDI_ReleaseObj( hdc );
1301     if (!proc) return FALSE;
1302     args[5] = hdc16;
1303     args[4] = code;
1304     args[3] = HIWORD(data);
1305     args[2] = LOWORD(data);
1306     args[1] = HIWORD(lParam);
1307     args[0] = LOWORD(lParam);
1308     WOWCallback16Ex( (DWORD)proc, WCB16_PASCAL, sizeof(args), args, &ret );
1309     return LOWORD(ret);
1310 }
1311
1312 /***********************************************************************
1313  *           SetDCHook   (GDI.190)
1314  */
1315 BOOL16 WINAPI SetDCHook16( HDC16 hdc16, FARPROC16 hookProc, DWORD dwHookData )
1316 {
1317     HDC hdc = HDC_32( hdc16 );
1318     DC *dc = DC_GetDCPtr( hdc );
1319     if (!dc) return FALSE;
1320
1321     dc->hookProc = hookProc;
1322     GDI_ReleaseObj( hdc );
1323     return SetDCHook( hdc, call_dc_hook16, dwHookData );
1324 }
1325
1326
1327 /***********************************************************************
1328  *           GetDCHook   (GDI.191)
1329  */
1330 DWORD WINAPI GetDCHook16( HDC16 hdc16, FARPROC16 *phookProc )
1331 {
1332     HDC hdc = HDC_32( hdc16 );
1333     DC *dc = DC_GetDCPtr( hdc );
1334     DWORD ret;
1335
1336     if (!dc) return 0;
1337     *phookProc = dc->hookProc;
1338     ret = dc->dwHookData;
1339     GDI_ReleaseObj( hdc );
1340     return ret;
1341 }
1342
1343
1344 /***********************************************************************
1345  *           SetHookFlags   (GDI.192)
1346  */
1347 WORD WINAPI SetHookFlags16(HDC16 hdc16, WORD flags)
1348 {
1349     HDC hdc = HDC_32( hdc16 );
1350     DC *dc = DC_GetDCPtr( hdc );
1351
1352     if( dc )
1353     {
1354         WORD wRet = dc->flags & DC_DIRTY;
1355
1356         /* "Undocumented Windows" info is slightly confusing.
1357          */
1358
1359         TRACE("hDC %p, flags %04x\n",hdc,flags);
1360
1361         if( flags & DCHF_INVALIDATEVISRGN )
1362             dc->flags |= DC_DIRTY;
1363         else if( flags & DCHF_VALIDATEVISRGN || !flags )
1364             dc->flags &= ~DC_DIRTY;
1365         GDI_ReleaseObj( hdc );
1366         return wRet;
1367     }
1368     return 0;
1369 }
1370
1371 /***********************************************************************
1372  *           SetICMMode    (GDI32.@)
1373  */
1374 INT WINAPI SetICMMode(HDC hdc, INT iEnableICM)
1375 {
1376 /*FIXME  Asuming that ICM is always off, and cannot be turned on */
1377     if (iEnableICM == ICM_OFF) return ICM_OFF;
1378     if (iEnableICM == ICM_ON) return 0;
1379     if (iEnableICM == ICM_QUERY) return ICM_OFF;
1380     return 0;
1381 }
1382
1383 /***********************************************************************
1384  *           GetDeviceGammaRamp    (GDI32.@)
1385  */
1386 BOOL WINAPI GetDeviceGammaRamp(HDC hDC, LPVOID ptr)
1387 {
1388     BOOL ret = FALSE;
1389     DC *dc = DC_GetDCPtr( hDC );
1390
1391     if( dc )
1392     {
1393         if (dc->funcs->pGetDeviceGammaRamp)
1394             ret = dc->funcs->pGetDeviceGammaRamp(dc->physDev, ptr);
1395         GDI_ReleaseObj( hDC );
1396     }
1397     return ret;
1398 }
1399
1400 /***********************************************************************
1401  *           SetDeviceGammaRamp    (GDI32.@)
1402  */
1403 BOOL WINAPI SetDeviceGammaRamp(HDC hDC, LPVOID ptr)
1404 {
1405     BOOL ret = FALSE;
1406     DC *dc = DC_GetDCPtr( hDC );
1407
1408     if( dc )
1409     {
1410         if (dc->funcs->pSetDeviceGammaRamp)
1411             ret = dc->funcs->pSetDeviceGammaRamp(dc->physDev, ptr);
1412         GDI_ReleaseObj( hDC );
1413     }
1414     return ret;
1415 }
1416
1417 /***********************************************************************
1418  *           GetColorSpace    (GDI32.@)
1419  */
1420 HCOLORSPACE WINAPI GetColorSpace(HDC hdc)
1421 {
1422 /*FIXME    Need to to whatever GetColorSpace actually does */
1423     return 0;
1424 }
1425
1426 /***********************************************************************
1427  *           CreateColorSpaceA    (GDI32.@)
1428  */
1429 HCOLORSPACE WINAPI CreateColorSpaceA( LPLOGCOLORSPACEA lpLogColorSpace )
1430 {
1431   FIXME( "stub\n" );
1432   return 0;
1433 }
1434
1435 /***********************************************************************
1436  *           CreateColorSpaceW    (GDI32.@)
1437  */
1438 HCOLORSPACE WINAPI CreateColorSpaceW( LPLOGCOLORSPACEW lpLogColorSpace )
1439 {
1440   FIXME( "stub\n" );
1441   return 0;
1442 }
1443
1444 /***********************************************************************
1445  *           DeleteColorSpace     (GDI32.@)
1446  */
1447 BOOL WINAPI DeleteColorSpace( HCOLORSPACE hColorSpace )
1448 {
1449   FIXME( "stub\n" );
1450
1451   return TRUE;
1452 }
1453
1454 /***********************************************************************
1455  *           SetColorSpace     (GDI32.@)
1456  */
1457 HCOLORSPACE WINAPI SetColorSpace( HDC hDC, HCOLORSPACE hColorSpace )
1458 {
1459   FIXME( "stub\n" );
1460
1461   return hColorSpace;
1462 }
1463
1464 /***********************************************************************
1465  *           GetBoundsRect    (GDI32.@)
1466  */
1467 UINT WINAPI GetBoundsRect(HDC hdc, LPRECT rect, UINT flags)
1468 {
1469     UINT ret;
1470     DC *dc = DC_GetDCPtr( hdc );
1471
1472     if ( !dc ) return 0;
1473
1474     if (rect) *rect = dc->BoundsRect;
1475
1476     ret = ((dc->flags & DC_BOUNDS_SET) ? DCB_SET : DCB_RESET);
1477
1478     if (flags & DCB_RESET)
1479     {
1480         dc->BoundsRect.left   = 0;
1481         dc->BoundsRect.top    = 0;
1482         dc->BoundsRect.right  = 0;
1483         dc->BoundsRect.bottom = 0;
1484         dc->flags &= ~DC_BOUNDS_SET;
1485     }
1486     GDI_ReleaseObj( hdc );
1487     return ret;
1488 }
1489
1490
1491 /***********************************************************************
1492  *           SetBoundsRect    (GDI32.@)
1493  */
1494 UINT WINAPI SetBoundsRect(HDC hdc, const RECT* rect, UINT flags)
1495 {
1496     UINT ret;
1497     DC *dc;
1498
1499     if ((flags & DCB_ENABLE) && (flags & DCB_DISABLE)) return 0;
1500     if (!(dc = DC_GetDCPtr( hdc ))) return 0;
1501
1502     ret = ((dc->flags & DC_BOUNDS_ENABLE) ? DCB_ENABLE : DCB_DISABLE) |
1503           ((dc->flags & DC_BOUNDS_SET) ? DCB_SET : DCB_RESET);
1504
1505     if (flags & DCB_RESET)
1506     {
1507         dc->BoundsRect.left   = 0;
1508         dc->BoundsRect.top    = 0;
1509         dc->BoundsRect.right  = 0;
1510         dc->BoundsRect.bottom = 0;
1511         dc->flags &= ~DC_BOUNDS_SET;
1512     }
1513
1514     if ((flags & DCB_ACCUMULATE) && rect && rect->left < rect->right && rect->top < rect->bottom)
1515     {
1516         if (dc->flags & DC_BOUNDS_SET)
1517         {
1518             dc->BoundsRect.left   = min( dc->BoundsRect.left, rect->left );
1519             dc->BoundsRect.top    = min( dc->BoundsRect.top, rect->top );
1520             dc->BoundsRect.right  = max( dc->BoundsRect.right, rect->right );
1521             dc->BoundsRect.bottom = max( dc->BoundsRect.bottom, rect->bottom );
1522         }
1523         else
1524         {
1525             dc->BoundsRect = *rect;
1526             dc->flags |= DC_BOUNDS_SET;
1527         }
1528     }
1529
1530     if (flags & DCB_ENABLE) dc->flags |= DC_BOUNDS_ENABLE;
1531     if (flags & DCB_DISABLE) dc->flags &= ~DC_BOUNDS_ENABLE;
1532
1533     GDI_ReleaseObj( hdc );
1534     return ret;
1535 }
1536
1537
1538 /***********************************************************************
1539  *              GetRelAbs               (GDI32.@)
1540  */
1541 INT WINAPI GetRelAbs( HDC hdc, DWORD dwIgnore )
1542 {
1543     INT ret = 0;
1544     DC *dc = DC_GetDCPtr( hdc );
1545     if (dc) ret = dc->relAbsMode;
1546     GDI_ReleaseObj( hdc );
1547     return ret;
1548 }
1549
1550
1551
1552
1553 /***********************************************************************
1554  *              GetBkMode (GDI32.@)
1555  */
1556 INT WINAPI GetBkMode( HDC hdc )
1557 {
1558     INT ret = 0;
1559     DC * dc = DC_GetDCPtr( hdc );
1560     if (dc)
1561     {
1562         ret = dc->backgroundMode;
1563         GDI_ReleaseObj( hdc );
1564     }
1565     return ret;
1566 }
1567
1568
1569 /***********************************************************************
1570  *              SetBkMode (GDI32.@)
1571  */
1572 INT WINAPI SetBkMode( HDC hdc, INT mode )
1573 {
1574     INT ret;
1575     DC *dc;
1576     if ((mode <= 0) || (mode > BKMODE_LAST))
1577     {
1578         SetLastError(ERROR_INVALID_PARAMETER);
1579         return 0;
1580     }
1581     if (!(dc = DC_GetDCPtr( hdc ))) return 0;
1582     if (dc->funcs->pSetBkMode)
1583         ret = dc->funcs->pSetBkMode( dc->physDev, mode );
1584     else
1585     {
1586         ret = dc->backgroundMode;
1587         dc->backgroundMode = mode;
1588     }
1589     GDI_ReleaseObj( hdc );
1590     return ret;
1591 }
1592
1593
1594 /***********************************************************************
1595  *              GetROP2 (GDI32.@)
1596  */
1597 INT WINAPI GetROP2( HDC hdc )
1598 {
1599     INT ret = 0;
1600     DC * dc = DC_GetDCPtr( hdc );
1601     if (dc)
1602     {
1603         ret = dc->ROPmode;
1604         GDI_ReleaseObj( hdc );
1605     }
1606     return ret;
1607 }
1608
1609
1610 /***********************************************************************
1611  *              SetROP2 (GDI32.@)
1612  */
1613 INT WINAPI SetROP2( HDC hdc, INT mode )
1614 {
1615     INT ret;
1616     DC *dc;
1617     if ((mode < R2_BLACK) || (mode > R2_WHITE))
1618     {
1619         SetLastError(ERROR_INVALID_PARAMETER);
1620         return 0;
1621     }
1622     if (!(dc = DC_GetDCPtr( hdc ))) return 0;
1623     if (dc->funcs->pSetROP2)
1624         ret = dc->funcs->pSetROP2( dc->physDev, mode );
1625     else
1626     {
1627         ret = dc->ROPmode;
1628         dc->ROPmode = mode;
1629     }
1630     GDI_ReleaseObj( hdc );
1631     return ret;
1632 }
1633
1634
1635 /***********************************************************************
1636  *              SetRelAbs (GDI32.@)
1637  */
1638 INT WINAPI SetRelAbs( HDC hdc, INT mode )
1639 {
1640     INT ret;
1641     DC *dc;
1642     if ((mode != ABSOLUTE) && (mode != RELATIVE))
1643     {
1644         SetLastError(ERROR_INVALID_PARAMETER);
1645         return 0;
1646     }
1647     if (!(dc = DC_GetDCPtr( hdc ))) return 0;
1648     if (dc->funcs->pSetRelAbs)
1649         ret = dc->funcs->pSetRelAbs( dc->physDev, mode );
1650     else
1651     {
1652         ret = dc->relAbsMode;
1653         dc->relAbsMode = mode;
1654     }
1655     GDI_ReleaseObj( hdc );
1656     return ret;
1657 }
1658
1659
1660 /***********************************************************************
1661  *              GetPolyFillMode (GDI32.@)
1662  */
1663 INT WINAPI GetPolyFillMode( HDC hdc )
1664 {
1665     INT ret = 0;
1666     DC * dc = DC_GetDCPtr( hdc );
1667     if (dc)
1668     {
1669         ret = dc->polyFillMode;
1670         GDI_ReleaseObj( hdc );
1671     }
1672     return ret;
1673 }
1674
1675
1676 /***********************************************************************
1677  *              SetPolyFillMode (GDI32.@)
1678  */
1679 INT WINAPI SetPolyFillMode( HDC hdc, INT mode )
1680 {
1681     INT ret;
1682     DC *dc;
1683     if ((mode <= 0) || (mode > POLYFILL_LAST))
1684     {
1685         SetLastError(ERROR_INVALID_PARAMETER);
1686         return 0;
1687     }
1688     if (!(dc = DC_GetDCPtr( hdc ))) return 0;
1689     if (dc->funcs->pSetPolyFillMode)
1690         ret = dc->funcs->pSetPolyFillMode( dc->physDev, mode );
1691     else
1692     {
1693         ret = dc->polyFillMode;
1694         dc->polyFillMode = mode;
1695     }
1696     GDI_ReleaseObj( hdc );
1697     return ret;
1698 }
1699
1700
1701 /***********************************************************************
1702  *              GetStretchBltMode (GDI32.@)
1703  */
1704 INT WINAPI GetStretchBltMode( HDC hdc )
1705 {
1706     INT ret = 0;
1707     DC * dc = DC_GetDCPtr( hdc );
1708     if (dc)
1709     {
1710         ret = dc->stretchBltMode;
1711         GDI_ReleaseObj( hdc );
1712     }
1713     return ret;
1714 }
1715
1716
1717 /***********************************************************************
1718  *              SetStretchBltMode (GDI32.@)
1719  */
1720 INT WINAPI SetStretchBltMode( HDC hdc, INT mode )
1721 {
1722     INT ret;
1723     DC *dc;
1724     if ((mode <= 0) || (mode > MAXSTRETCHBLTMODE))
1725     {
1726         SetLastError(ERROR_INVALID_PARAMETER);
1727         return 0;
1728     }
1729     if (!(dc = DC_GetDCPtr( hdc ))) return 0;
1730     if (dc->funcs->pSetStretchBltMode)
1731         ret = dc->funcs->pSetStretchBltMode( dc->physDev, mode );
1732     else
1733     {
1734         ret = dc->stretchBltMode;
1735         dc->stretchBltMode = mode;
1736     }
1737     GDI_ReleaseObj( hdc );
1738     return ret;
1739 }
1740
1741
1742 /***********************************************************************
1743  *              GetMapMode (GDI32.@)
1744  */
1745 INT WINAPI GetMapMode( HDC hdc )
1746 {
1747     INT ret = 0;
1748     DC * dc = DC_GetDCPtr( hdc );
1749     if (dc)
1750     {
1751         ret = dc->MapMode;
1752         GDI_ReleaseObj( hdc );
1753     }
1754     return ret;
1755 }
1756
1757
1758 /***********************************************************************
1759  *              GetBrushOrgEx (GDI32.@)
1760  */
1761 BOOL WINAPI GetBrushOrgEx( HDC hdc, LPPOINT pt )
1762 {
1763     DC * dc = DC_GetDCPtr( hdc );
1764     if (!dc) return FALSE;
1765     pt->x = dc->brushOrgX;
1766     pt->y = dc->brushOrgY;
1767     GDI_ReleaseObj( hdc );
1768     return TRUE;
1769 }
1770
1771
1772 /***********************************************************************
1773  *              GetCurrentPositionEx (GDI32.@)
1774  */
1775 BOOL WINAPI GetCurrentPositionEx( HDC hdc, LPPOINT pt )
1776 {
1777     DC * dc = DC_GetDCPtr( hdc );
1778     if (!dc) return FALSE;
1779     pt->x = dc->CursPosX;
1780     pt->y = dc->CursPosY;
1781     GDI_ReleaseObj( hdc );
1782     return TRUE;
1783 }
1784
1785
1786 /***********************************************************************
1787  *              GetViewportExtEx (GDI32.@)
1788  */
1789 BOOL WINAPI GetViewportExtEx( HDC hdc, LPSIZE size )
1790 {
1791     DC * dc = DC_GetDCPtr( hdc );
1792     if (!dc) return FALSE;
1793     size->cx = dc->vportExtX;
1794     size->cy = dc->vportExtY;
1795     GDI_ReleaseObj( hdc );
1796     return TRUE;
1797 }
1798
1799
1800 /***********************************************************************
1801  *              GetViewportOrgEx (GDI32.@)
1802  */
1803 BOOL WINAPI GetViewportOrgEx( HDC hdc, LPPOINT pt )
1804 {
1805     DC * dc = DC_GetDCPtr( hdc );
1806     if (!dc) return FALSE;
1807     pt->x = dc->vportOrgX;
1808     pt->y = dc->vportOrgY;
1809     GDI_ReleaseObj( hdc );
1810     return TRUE;
1811 }
1812
1813
1814 /***********************************************************************
1815  *              GetWindowExtEx (GDI32.@)
1816  */
1817 BOOL WINAPI GetWindowExtEx( HDC hdc, LPSIZE size )
1818 {
1819     DC * dc = DC_GetDCPtr( hdc );
1820     if (!dc) return FALSE;
1821     size->cx = dc->wndExtX;
1822     size->cy = dc->wndExtY;
1823     GDI_ReleaseObj( hdc );
1824     return TRUE;
1825 }
1826
1827
1828 /***********************************************************************
1829  *              GetWindowOrgEx (GDI32.@)
1830  */
1831 BOOL WINAPI GetWindowOrgEx( HDC hdc, LPPOINT pt )
1832 {
1833     DC * dc = DC_GetDCPtr( hdc );
1834     if (!dc) return FALSE;
1835     pt->x = dc->wndOrgX;
1836     pt->y = dc->wndOrgY;
1837     GDI_ReleaseObj( hdc );
1838     return TRUE;
1839 }
1840
1841
1842 /***********************************************************************
1843  *              InquireVisRgn   (GDI.131)
1844  */
1845 HRGN16 WINAPI InquireVisRgn16( HDC16 hdc )
1846 {
1847     HRGN16 ret = 0;
1848     DC * dc = DC_GetDCPtr( HDC_32(hdc) );
1849     if (dc)
1850     {
1851         ret = HRGN_16(dc->hVisRgn);
1852         GDI_ReleaseObj( HDC_32(hdc) );
1853     }
1854     return ret;
1855 }
1856
1857
1858 /***********************************************************************
1859  *              GetClipRgn (GDI.173)
1860  */
1861 HRGN16 WINAPI GetClipRgn16( HDC16 hdc )
1862 {
1863     HRGN16 ret = 0;
1864     DC * dc = DC_GetDCPtr( HDC_32(hdc) );
1865     if (dc)
1866     {
1867         ret = HRGN_16(dc->hClipRgn);
1868         GDI_ReleaseObj( HDC_32(hdc) );
1869     }
1870     return ret;
1871 }
1872
1873
1874 /***********************************************************************
1875  *           GetLayout    (GDI32.@)
1876  *
1877  * Gets left->right or right->left text layout flags of a dc.
1878  *
1879  */
1880 DWORD WINAPI GetLayout(HDC hdc)
1881 {
1882     DWORD layout = GDI_ERROR;
1883
1884     DC * dc = DC_GetDCPtr( hdc );
1885     if (dc)
1886     {
1887         layout = dc->layout;
1888         GDI_ReleaseObj( hdc );
1889     }
1890
1891     TRACE("hdc : %p, layout : %08lx\n", hdc, layout);
1892
1893     return layout;
1894 }
1895
1896 /***********************************************************************
1897  *           SetLayout    (GDI32.@)
1898  *
1899  * Sets left->right or right->left text layout flags of a dc.
1900  *
1901  */
1902 DWORD WINAPI SetLayout(HDC hdc, DWORD layout)
1903 {
1904     DWORD oldlayout = GDI_ERROR;
1905
1906     DC * dc = DC_GetDCPtr( hdc );
1907     if (dc)
1908     {
1909         oldlayout = dc->layout;
1910         dc->layout = layout;
1911         GDI_ReleaseObj( hdc );
1912     }
1913
1914     TRACE("hdc : %p, old layout : %08lx, new layout : %08lx\n", hdc, oldlayout, layout);
1915
1916     return oldlayout;
1917 }
1918
1919 /***********************************************************************
1920  *           GetDCBrushColor    (GDI32.@)
1921  *
1922  * Retrieves the current brush color for the specified device
1923  * context (DC).
1924  *
1925  */
1926 COLORREF WINAPI GetDCBrushColor(HDC hdc)
1927 {
1928     DC *dc;
1929     COLORREF dcBrushColor = CLR_INVALID;
1930
1931     TRACE("hdc(%p)\n", hdc);
1932
1933     dc = DC_GetDCPtr( hdc );
1934     if (dc)
1935     {
1936         dcBrushColor = dc->dcBrushColor;
1937         GDI_ReleaseObj( hdc );
1938     }
1939
1940     return dcBrushColor;
1941 }
1942
1943 /***********************************************************************
1944  *           SetDCBrushColor    (GDI32.@)
1945  *
1946  * Sets the current device context (DC) brush color to the specified
1947  * color value. If the device cannot represent the specified color
1948  * value, the color is set to the nearest physical color.
1949  *
1950  */
1951 COLORREF WINAPI SetDCBrushColor(HDC hdc, COLORREF crColor)
1952 {
1953     DC *dc;
1954     COLORREF oldClr = CLR_INVALID;
1955
1956     TRACE("hdc(%p) crColor(%08lx)\n", hdc, crColor);
1957
1958     dc = DC_GetDCPtr( hdc );
1959     if (dc)
1960     {
1961         if (dc->funcs->pSetDCBrushColor)
1962             crColor = dc->funcs->pSetDCBrushColor( dc->physDev, crColor );
1963         else if (dc->hBrush == GetStockObject( DC_BRUSH ))
1964         {
1965             /* If DC_BRUSH is selected, update driver pen color */
1966             HBRUSH hBrush = CreateSolidBrush( crColor );
1967             dc->funcs->pSelectBrush( dc->physDev, hBrush );
1968             DeleteObject( hBrush );
1969         }
1970
1971         if (crColor != CLR_INVALID)
1972         {
1973             oldClr = dc->dcBrushColor;
1974             dc->dcBrushColor = crColor;
1975         }
1976
1977         GDI_ReleaseObj( hdc );
1978     }
1979
1980     return oldClr;
1981 }
1982
1983 /***********************************************************************
1984  *           GetDCPenColor    (GDI32.@)
1985  *
1986  * Retrieves the current pen color for the specified device
1987  * context (DC).
1988  *
1989  */
1990 COLORREF WINAPI GetDCPenColor(HDC hdc)
1991 {
1992     DC *dc;
1993     COLORREF dcPenColor = CLR_INVALID;
1994
1995     TRACE("hdc(%p)\n", hdc);
1996
1997     dc = DC_GetDCPtr( hdc );
1998     if (dc)
1999     {
2000         dcPenColor = dc->dcPenColor;
2001         GDI_ReleaseObj( hdc );
2002     }
2003
2004     return dcPenColor;
2005 }
2006
2007 /***********************************************************************
2008  *           SetDCPenColor    (GDI32.@)
2009  *
2010  * Sets the current device context (DC) pen color to the specified
2011  * color value. If the device cannot represent the specified color
2012  * value, the color is set to the nearest physical color.
2013  *
2014  */
2015 COLORREF WINAPI SetDCPenColor(HDC hdc, COLORREF crColor)
2016 {
2017     DC *dc;
2018     COLORREF oldClr = CLR_INVALID;
2019
2020     TRACE("hdc(%p) crColor(%08lx)\n", hdc, crColor);
2021
2022     dc = DC_GetDCPtr( hdc );
2023     if (dc)
2024     {
2025         if (dc->funcs->pSetDCPenColor)
2026             crColor = dc->funcs->pSetDCPenColor( dc->physDev, crColor );
2027         else if (dc->hPen == GetStockObject( DC_PEN ))
2028         {
2029             /* If DC_PEN is selected, update the driver pen color */
2030             LOGPEN logpen = { PS_SOLID, { 0, 0 }, crColor };
2031             HPEN hPen = CreatePenIndirect( &logpen );
2032             dc->funcs->pSelectPen( dc->physDev, hPen );
2033             DeleteObject( hPen );
2034         }
2035
2036         if (crColor != CLR_INVALID)
2037         {
2038             oldClr = dc->dcPenColor;
2039             dc->dcPenColor = crColor;
2040         }
2041
2042         GDI_ReleaseObj( hdc );
2043     }
2044
2045     return oldClr;
2046 }
2047
2048 /***********************************************************************
2049  *           SetVirtualResolution   (GDI32.@)
2050  *
2051  * Undocumented on msdn.  Called when PowerPoint XP saves a file.
2052  */
2053 DWORD WINAPI SetVirtualResolution(HDC hdc, DWORD dw2, DWORD dw3, DWORD dw4, DWORD dw5)
2054 {
2055     FIXME("(%p %08lx %08lx %08lx %08lx): stub!\n", hdc, dw2, dw3, dw4, dw5);
2056     return FALSE;
2057 }
2058
2059 /*******************************************************************
2060  *      GetMiterLimit [GDI32.@]
2061  *
2062  *
2063  */
2064 BOOL WINAPI GetMiterLimit(HDC hdc, PFLOAT peLimit)
2065 {
2066     BOOL bRet = FALSE;
2067     DC *dc;
2068
2069     TRACE("(%p,%p)\n", hdc, peLimit);
2070
2071     dc = DC_GetDCPtr( hdc );
2072     if (dc)
2073     {
2074         if (peLimit)
2075             *peLimit = dc->miterLimit;
2076
2077         GDI_ReleaseObj( hdc );
2078         bRet = TRUE;
2079     }
2080     return bRet;
2081 }
2082
2083 /*******************************************************************
2084  *      SetMiterLimit [GDI32.@]
2085  *
2086  *
2087  */
2088 BOOL WINAPI SetMiterLimit(HDC hdc, FLOAT eNewLimit, PFLOAT peOldLimit)
2089 {
2090     BOOL bRet = FALSE;
2091     DC *dc;
2092
2093     TRACE("(%p,%f,%p)\n", hdc, eNewLimit, peOldLimit);
2094
2095     dc = DC_GetDCPtr( hdc );
2096     if (dc)
2097     {
2098         if (peOldLimit)
2099             *peOldLimit = dc->miterLimit;
2100         dc->miterLimit = eNewLimit;
2101         GDI_ReleaseObj( hdc );
2102         bRet = TRUE;
2103     }
2104     return bRet;
2105 }