More named pipes tests.
[wine/multimedia.git] / objects / dc.c
blobd8bc9993536759158267ea1aa685473a20eaaec0
1 /*
2 * GDI Device Context functions
4 * Copyright 1993 Alexandre Julliard
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.
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.
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
21 #include "config.h"
23 #include <stdlib.h>
24 #include <string.h>
25 #include "windef.h"
26 #include "wingdi.h"
27 #include "winerror.h"
28 #include "wownt32.h"
29 #include "wine/winuser16.h"
30 #include "gdi.h"
31 #include "heap.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(dc);
36 static BOOL DC_DeleteObject( HGDIOBJ handle, void *obj );
38 static const struct gdi_obj_funcs dc_funcs =
40 NULL, /* pSelectObject */
41 NULL, /* pGetObject16 */
42 NULL, /* pGetObjectA */
43 NULL, /* pGetObjectW */
44 NULL, /* pUnrealizeObject */
45 DC_DeleteObject /* pDeleteObject */
48 /***********************************************************************
49 * DC_AllocDC
51 DC *DC_AllocDC( const DC_FUNCTIONS *funcs, WORD magic )
53 HDC hdc;
54 DC *dc;
56 if (!(dc = GDI_AllocObject( sizeof(*dc), magic, (HGDIOBJ*)&hdc, &dc_funcs ))) return NULL;
58 dc->hSelf = hdc;
59 dc->funcs = funcs;
60 dc->physDev = NULL;
61 dc->saveLevel = 0;
62 dc->dwHookData = 0;
63 dc->hookProc = NULL;
64 dc->hookThunk = NULL;
65 dc->wndOrgX = 0;
66 dc->wndOrgY = 0;
67 dc->wndExtX = 1;
68 dc->wndExtY = 1;
69 dc->vportOrgX = 0;
70 dc->vportOrgY = 0;
71 dc->vportExtX = 1;
72 dc->vportExtY = 1;
73 dc->flags = 0;
74 dc->hClipRgn = 0;
75 dc->hVisRgn = 0;
76 dc->hGCClipRgn = 0;
77 dc->hPen = GetStockObject( BLACK_PEN );
78 dc->hBrush = GetStockObject( WHITE_BRUSH );
79 dc->hFont = GetStockObject( SYSTEM_FONT );
80 dc->hBitmap = 0;
81 dc->hDevice = 0;
82 dc->hPalette = GetStockObject( DEFAULT_PALETTE );
83 dc->gdiFont = 0;
84 dc->ROPmode = R2_COPYPEN;
85 dc->polyFillMode = ALTERNATE;
86 dc->stretchBltMode = BLACKONWHITE;
87 dc->relAbsMode = ABSOLUTE;
88 dc->backgroundMode = OPAQUE;
89 dc->backgroundColor = RGB( 255, 255, 255 );
90 dc->textColor = RGB( 0, 0, 0 );
91 dc->brushOrgX = 0;
92 dc->brushOrgY = 0;
93 dc->textAlign = TA_LEFT | TA_TOP | TA_NOUPDATECP;
94 dc->charExtra = 0;
95 dc->breakTotalExtra = 0;
96 dc->breakCount = 0;
97 dc->breakExtra = 0;
98 dc->breakRem = 0;
99 dc->totalExtent.left = 0;
100 dc->totalExtent.top = 0;
101 dc->totalExtent.right = 0;
102 dc->totalExtent.bottom = 0;
103 dc->bitsPerPixel = 1;
104 dc->MapMode = MM_TEXT;
105 dc->GraphicsMode = GM_COMPATIBLE;
106 dc->pAbortProc = NULL;
107 dc->CursPosX = 0;
108 dc->CursPosY = 0;
109 dc->ArcDirection = AD_COUNTERCLOCKWISE;
110 dc->xformWorld2Wnd.eM11 = 1.0f;
111 dc->xformWorld2Wnd.eM12 = 0.0f;
112 dc->xformWorld2Wnd.eM21 = 0.0f;
113 dc->xformWorld2Wnd.eM22 = 1.0f;
114 dc->xformWorld2Wnd.eDx = 0.0f;
115 dc->xformWorld2Wnd.eDy = 0.0f;
116 dc->xformWorld2Vport = dc->xformWorld2Wnd;
117 dc->xformVport2World = dc->xformWorld2Wnd;
118 dc->vport2WorldValid = TRUE;
119 PATH_InitGdiPath(&dc->path);
120 return dc;
125 /***********************************************************************
126 * DC_GetDCPtr
128 DC *DC_GetDCPtr( HDC hdc )
130 GDIOBJHDR *ptr = GDI_GetObjPtr( hdc, MAGIC_DONTCARE );
131 if (!ptr) return NULL;
132 if ((GDIMAGIC(ptr->wMagic) == DC_MAGIC) ||
133 (GDIMAGIC(ptr->wMagic) == MEMORY_DC_MAGIC) ||
134 (GDIMAGIC(ptr->wMagic) == METAFILE_DC_MAGIC) ||
135 (GDIMAGIC(ptr->wMagic) == ENHMETAFILE_DC_MAGIC))
136 return (DC *)ptr;
137 GDI_ReleaseObj( hdc );
138 SetLastError( ERROR_INVALID_HANDLE );
139 return NULL;
142 /***********************************************************************
143 * DC_GetDCUpdate
145 * Retrieve a DC ptr while making sure the visRgn is updated.
146 * This function may call up to USER so the GDI lock should _not_
147 * be held when calling it.
149 DC *DC_GetDCUpdate( HDC hdc )
151 DC *dc = DC_GetDCPtr( hdc );
152 if (!dc) return NULL;
153 while (dc->flags & DC_DIRTY)
155 DCHOOKPROC proc = dc->hookThunk;
156 dc->flags &= ~DC_DIRTY;
157 if (proc)
159 DWORD data = dc->dwHookData;
160 GDI_ReleaseObj( hdc );
161 proc( HDC_16(hdc), DCHC_INVALIDVISRGN, data, 0 );
162 if (!(dc = DC_GetDCPtr( hdc ))) break;
163 /* otherwise restart the loop in case it became dirty again in the meantime */
166 return dc;
170 /***********************************************************************
171 * DC_DeleteObject
173 static BOOL DC_DeleteObject( HGDIOBJ handle, void *obj )
175 GDI_ReleaseObj( handle );
176 return DeleteDC( handle );
180 /***********************************************************************
181 * DC_InitDC
183 * Setup device-specific DC values for a newly created DC.
185 void DC_InitDC( DC* dc )
187 if (dc->funcs->pRealizeDefaultPalette) dc->funcs->pRealizeDefaultPalette( dc->physDev );
188 SetTextColor( dc->hSelf, dc->textColor );
189 SetBkColor( dc->hSelf, dc->backgroundColor );
190 SelectObject( dc->hSelf, dc->hPen );
191 SelectObject( dc->hSelf, dc->hBrush );
192 SelectObject( dc->hSelf, dc->hFont );
193 CLIPPING_UpdateGCRegion( dc );
197 /***********************************************************************
198 * DC_InvertXform
200 * Computes the inverse of the transformation xformSrc and stores it to
201 * xformDest. Returns TRUE if successful or FALSE if the xformSrc matrix
202 * is singular.
204 static BOOL DC_InvertXform( const XFORM *xformSrc, XFORM *xformDest )
206 FLOAT determinant;
208 determinant = xformSrc->eM11*xformSrc->eM22 -
209 xformSrc->eM12*xformSrc->eM21;
210 if (determinant > -1e-12 && determinant < 1e-12)
211 return FALSE;
213 xformDest->eM11 = xformSrc->eM22 / determinant;
214 xformDest->eM12 = -xformSrc->eM12 / determinant;
215 xformDest->eM21 = -xformSrc->eM21 / determinant;
216 xformDest->eM22 = xformSrc->eM11 / determinant;
217 xformDest->eDx = -xformSrc->eDx * xformDest->eM11 -
218 xformSrc->eDy * xformDest->eM21;
219 xformDest->eDy = -xformSrc->eDx * xformDest->eM12 -
220 xformSrc->eDy * xformDest->eM22;
222 return TRUE;
226 /***********************************************************************
227 * DC_UpdateXforms
229 * Updates the xformWorld2Vport, xformVport2World and vport2WorldValid
230 * fields of the specified DC by creating a transformation that
231 * represents the current mapping mode and combining it with the DC's
232 * world transform. This function should be called whenever the
233 * parameters associated with the mapping mode (window and viewport
234 * extents and origins) or the world transform change.
236 void DC_UpdateXforms( DC *dc )
238 XFORM xformWnd2Vport;
239 FLOAT scaleX, scaleY;
241 /* Construct a transformation to do the window-to-viewport conversion */
242 scaleX = (FLOAT)dc->vportExtX / (FLOAT)dc->wndExtX;
243 scaleY = (FLOAT)dc->vportExtY / (FLOAT)dc->wndExtY;
244 xformWnd2Vport.eM11 = scaleX;
245 xformWnd2Vport.eM12 = 0.0;
246 xformWnd2Vport.eM21 = 0.0;
247 xformWnd2Vport.eM22 = scaleY;
248 xformWnd2Vport.eDx = (FLOAT)dc->vportOrgX -
249 scaleX * (FLOAT)dc->wndOrgX;
250 xformWnd2Vport.eDy = (FLOAT)dc->vportOrgY -
251 scaleY * (FLOAT)dc->wndOrgY;
253 /* Combine with the world transformation */
254 CombineTransform( &dc->xformWorld2Vport, &dc->xformWorld2Wnd,
255 &xformWnd2Vport );
257 /* Create inverse of world-to-viewport transformation */
258 dc->vport2WorldValid = DC_InvertXform( &dc->xformWorld2Vport,
259 &dc->xformVport2World );
263 /***********************************************************************
264 * GetDCState (Not a Windows API)
266 HDC WINAPI GetDCState( HDC hdc )
268 DC * newdc, * dc;
269 HGDIOBJ handle;
271 if (!(dc = DC_GetDCPtr( hdc ))) return 0;
272 if (!(newdc = GDI_AllocObject( sizeof(DC), GDIMAGIC(dc->header.wMagic), &handle, &dc_funcs )))
274 GDI_ReleaseObj( hdc );
275 return 0;
277 TRACE("(%p): returning %p\n", hdc, handle );
279 newdc->flags = dc->flags | DC_SAVED;
280 newdc->hPen = dc->hPen;
281 newdc->hBrush = dc->hBrush;
282 newdc->hFont = dc->hFont;
283 newdc->hBitmap = dc->hBitmap;
284 newdc->hDevice = dc->hDevice;
285 newdc->hPalette = dc->hPalette;
286 newdc->totalExtent = dc->totalExtent;
287 newdc->bitsPerPixel = dc->bitsPerPixel;
288 newdc->ROPmode = dc->ROPmode;
289 newdc->polyFillMode = dc->polyFillMode;
290 newdc->stretchBltMode = dc->stretchBltMode;
291 newdc->relAbsMode = dc->relAbsMode;
292 newdc->backgroundMode = dc->backgroundMode;
293 newdc->backgroundColor = dc->backgroundColor;
294 newdc->textColor = dc->textColor;
295 newdc->brushOrgX = dc->brushOrgX;
296 newdc->brushOrgY = dc->brushOrgY;
297 newdc->textAlign = dc->textAlign;
298 newdc->charExtra = dc->charExtra;
299 newdc->breakTotalExtra = dc->breakTotalExtra;
300 newdc->breakCount = dc->breakCount;
301 newdc->breakExtra = dc->breakExtra;
302 newdc->breakRem = dc->breakRem;
303 newdc->MapMode = dc->MapMode;
304 newdc->GraphicsMode = dc->GraphicsMode;
305 newdc->CursPosX = dc->CursPosX;
306 newdc->CursPosY = dc->CursPosY;
307 newdc->ArcDirection = dc->ArcDirection;
308 newdc->xformWorld2Wnd = dc->xformWorld2Wnd;
309 newdc->xformWorld2Vport = dc->xformWorld2Vport;
310 newdc->xformVport2World = dc->xformVport2World;
311 newdc->vport2WorldValid = dc->vport2WorldValid;
312 newdc->wndOrgX = dc->wndOrgX;
313 newdc->wndOrgY = dc->wndOrgY;
314 newdc->wndExtX = dc->wndExtX;
315 newdc->wndExtY = dc->wndExtY;
316 newdc->vportOrgX = dc->vportOrgX;
317 newdc->vportOrgY = dc->vportOrgY;
318 newdc->vportExtX = dc->vportExtX;
319 newdc->vportExtY = dc->vportExtY;
321 newdc->hSelf = (HDC)handle;
322 newdc->saveLevel = 0;
324 PATH_InitGdiPath( &newdc->path );
326 newdc->pAbortProc = NULL;
327 newdc->hookThunk = NULL;
328 newdc->hookProc = 0;
330 /* Get/SetDCState() don't change hVisRgn field ("Undoc. Windows" p.559). */
332 newdc->hGCClipRgn = newdc->hVisRgn = 0;
333 if (dc->hClipRgn)
335 newdc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
336 CombineRgn( newdc->hClipRgn, dc->hClipRgn, 0, RGN_COPY );
338 else
339 newdc->hClipRgn = 0;
341 if(dc->gdiFont) {
342 newdc->gdiFont = dc->gdiFont;
343 } else
344 newdc->gdiFont = 0;
346 GDI_ReleaseObj( handle );
347 GDI_ReleaseObj( hdc );
348 return handle;
352 /***********************************************************************
353 * SetDCState (Not a Windows API)
355 void WINAPI SetDCState( HDC hdc, HDC hdcs )
357 DC *dc, *dcs;
359 if (!(dc = DC_GetDCUpdate( hdc ))) return;
360 if (!(dcs = DC_GetDCPtr( hdcs )))
362 GDI_ReleaseObj( hdc );
363 return;
365 if (!dcs->flags & DC_SAVED)
367 GDI_ReleaseObj( hdc );
368 GDI_ReleaseObj( hdcs );
369 return;
371 TRACE("%p %p\n", hdc, hdcs );
373 dc->flags = dcs->flags & ~(DC_SAVED | DC_DIRTY);
374 dc->hDevice = dcs->hDevice;
375 dc->totalExtent = dcs->totalExtent;
376 dc->ROPmode = dcs->ROPmode;
377 dc->polyFillMode = dcs->polyFillMode;
378 dc->stretchBltMode = dcs->stretchBltMode;
379 dc->relAbsMode = dcs->relAbsMode;
380 dc->backgroundMode = dcs->backgroundMode;
381 dc->backgroundColor = dcs->backgroundColor;
382 dc->textColor = dcs->textColor;
383 dc->brushOrgX = dcs->brushOrgX;
384 dc->brushOrgY = dcs->brushOrgY;
385 dc->textAlign = dcs->textAlign;
386 dc->charExtra = dcs->charExtra;
387 dc->breakTotalExtra = dcs->breakTotalExtra;
388 dc->breakCount = dcs->breakCount;
389 dc->breakExtra = dcs->breakExtra;
390 dc->breakRem = dcs->breakRem;
391 dc->MapMode = dcs->MapMode;
392 dc->GraphicsMode = dcs->GraphicsMode;
393 dc->CursPosX = dcs->CursPosX;
394 dc->CursPosY = dcs->CursPosY;
395 dc->ArcDirection = dcs->ArcDirection;
396 dc->xformWorld2Wnd = dcs->xformWorld2Wnd;
397 dc->xformWorld2Vport = dcs->xformWorld2Vport;
398 dc->xformVport2World = dcs->xformVport2World;
399 dc->vport2WorldValid = dcs->vport2WorldValid;
401 dc->wndOrgX = dcs->wndOrgX;
402 dc->wndOrgY = dcs->wndOrgY;
403 dc->wndExtX = dcs->wndExtX;
404 dc->wndExtY = dcs->wndExtY;
405 dc->vportOrgX = dcs->vportOrgX;
406 dc->vportOrgY = dcs->vportOrgY;
407 dc->vportExtX = dcs->vportExtX;
408 dc->vportExtY = dcs->vportExtY;
410 if (GDIMAGIC(dc->header.wMagic) != MEMORY_DC_MAGIC) dc->bitsPerPixel = dcs->bitsPerPixel;
412 if (dcs->hClipRgn)
414 if (!dc->hClipRgn) dc->hClipRgn = CreateRectRgn( 0, 0, 0, 0 );
415 CombineRgn( dc->hClipRgn, dcs->hClipRgn, 0, RGN_COPY );
417 else
419 if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
420 dc->hClipRgn = 0;
422 CLIPPING_UpdateGCRegion( dc );
424 SelectObject( hdc, dcs->hBitmap );
425 SelectObject( hdc, dcs->hBrush );
426 SelectObject( hdc, dcs->hFont );
427 SelectObject( hdc, dcs->hPen );
428 SetBkColor( hdc, dcs->backgroundColor);
429 SetTextColor( hdc, dcs->textColor);
430 GDISelectPalette( hdc, dcs->hPalette, FALSE );
431 GDI_ReleaseObj( hdcs );
432 GDI_ReleaseObj( hdc );
436 /***********************************************************************
437 * GetDCState (GDI.179)
439 HDC16 WINAPI GetDCState16( HDC16 hdc )
441 return HDC_16( GetDCState( HDC_32(hdc) ));
445 /***********************************************************************
446 * SetDCState (GDI.180)
448 void WINAPI SetDCState16( HDC16 hdc, HDC16 hdcs )
450 SetDCState( HDC_32(hdc), HDC_32(hdcs) );
454 /***********************************************************************
455 * SaveDC (GDI32.@)
457 INT WINAPI SaveDC( HDC hdc )
459 HDC hdcs;
460 DC * dc, * dcs;
461 INT ret;
463 dc = DC_GetDCPtr( hdc );
464 if (!dc) return 0;
466 if(dc->funcs->pSaveDC)
468 ret = dc->funcs->pSaveDC( dc->physDev );
469 GDI_ReleaseObj( hdc );
470 return ret;
473 if (!(hdcs = GetDCState( hdc )))
475 GDI_ReleaseObj( hdc );
476 return 0;
478 dcs = DC_GetDCPtr( hdcs );
480 /* Copy path. The reason why path saving / restoring is in SaveDC/
481 * RestoreDC and not in GetDCState/SetDCState is that the ...DCState
482 * functions are only in Win16 (which doesn't have paths) and that
483 * SetDCState doesn't allow us to signal an error (which can happen
484 * when copying paths).
486 if (!PATH_AssignGdiPath( &dcs->path, &dc->path ))
488 GDI_ReleaseObj( hdc );
489 GDI_ReleaseObj( hdcs );
490 DeleteDC( hdcs );
491 return 0;
494 dcs->header.hNext = dc->header.hNext;
495 dc->header.hNext = HDC_16(hdcs);
496 TRACE("(%p): returning %d\n", hdc, dc->saveLevel+1 );
497 ret = ++dc->saveLevel;
498 GDI_ReleaseObj( hdcs );
499 GDI_ReleaseObj( hdc );
500 return ret;
504 /***********************************************************************
505 * RestoreDC (GDI32.@)
507 BOOL WINAPI RestoreDC( HDC hdc, INT level )
509 DC * dc, * dcs;
510 BOOL success;
512 TRACE("%p %d\n", hdc, level );
513 dc = DC_GetDCUpdate( hdc );
514 if(!dc) return FALSE;
515 if(dc->funcs->pRestoreDC)
517 success = dc->funcs->pRestoreDC( dc->physDev, level );
518 GDI_ReleaseObj( hdc );
519 return success;
522 if (level == -1) level = dc->saveLevel;
523 if ((level < 1)
524 /* This pair of checks disagrees with MSDN "Platform SDK:
525 Windows GDI" July 2000 which says all negative values
526 for level will be interpreted as an instance relative
527 to the current state. Restricting it to just -1 does
528 not satisfy this */
529 || (level > dc->saveLevel))
531 GDI_ReleaseObj( hdc );
532 return FALSE;
535 success=TRUE;
536 while (dc->saveLevel >= level)
538 HDC hdcs = HDC_32(dc->header.hNext);
539 if (!(dcs = DC_GetDCPtr( hdcs )))
541 GDI_ReleaseObj( hdc );
542 return FALSE;
544 dc->header.hNext = dcs->header.hNext;
545 if (--dc->saveLevel < level)
547 SetDCState( hdc, hdcs );
548 if (!PATH_AssignGdiPath( &dc->path, &dcs->path ))
549 /* FIXME: This might not be quite right, since we're
550 * returning FALSE but still destroying the saved DC state */
551 success=FALSE;
553 GDI_ReleaseObj( hdcs );
554 GDI_ReleaseObj( hdc );
555 DeleteDC( hdcs );
556 if (!(dc = DC_GetDCPtr( hdc ))) return FALSE;
558 GDI_ReleaseObj( hdc );
559 return success;
563 /***********************************************************************
564 * CreateDCA (GDI32.@)
566 HDC WINAPI CreateDCA( LPCSTR driver, LPCSTR device, LPCSTR output,
567 const DEVMODEA *initData )
569 HDC hdc;
570 DC * dc;
571 const DC_FUNCTIONS *funcs;
572 char buf[300];
574 GDI_CheckNotLock();
576 if (!device || !DRIVER_GetDriverName( device, buf, sizeof(buf) ))
578 if (!driver) return 0;
579 strcpy(buf, driver);
582 if (!(funcs = DRIVER_load_driver( buf )))
584 ERR( "no driver found for %s\n", buf );
585 return 0;
587 if (!(dc = DC_AllocDC( funcs, DC_MAGIC )))
589 DRIVER_release_driver( funcs );
590 return 0;
593 dc->hBitmap = GetStockObject( DEFAULT_BITMAP );
595 TRACE("(driver=%s, device=%s, output=%s): returning %p\n",
596 debugstr_a(driver), debugstr_a(device), debugstr_a(output), dc->hSelf );
598 if (dc->funcs->pCreateDC &&
599 !dc->funcs->pCreateDC( dc, &dc->physDev, buf, device, output, initData ))
601 WARN("creation aborted by device\n" );
602 GDI_FreeObject( dc->hSelf, dc );
603 DRIVER_release_driver( funcs );
604 return 0;
607 dc->totalExtent.left = 0;
608 dc->totalExtent.top = 0;
609 dc->totalExtent.right = GetDeviceCaps( dc->hSelf, HORZRES );
610 dc->totalExtent.bottom = GetDeviceCaps( dc->hSelf, VERTRES );
611 dc->hVisRgn = CreateRectRgnIndirect( &dc->totalExtent );
613 DC_InitDC( dc );
614 hdc = dc->hSelf;
615 GDI_ReleaseObj( hdc );
616 return hdc;
620 /***********************************************************************
621 * CreateDCW (GDI32.@)
623 HDC WINAPI CreateDCW( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
624 const DEVMODEW *initData )
626 LPSTR driverA = HEAP_strdupWtoA( GetProcessHeap(), 0, driver );
627 LPSTR deviceA = HEAP_strdupWtoA( GetProcessHeap(), 0, device );
628 LPSTR outputA = HEAP_strdupWtoA( GetProcessHeap(), 0, output );
629 HDC res = CreateDCA( driverA, deviceA, outputA,
630 (const DEVMODEA *)initData /*FIXME*/ );
631 HeapFree( GetProcessHeap(), 0, driverA );
632 HeapFree( GetProcessHeap(), 0, deviceA );
633 HeapFree( GetProcessHeap(), 0, outputA );
634 return res;
638 /***********************************************************************
639 * CreateICA (GDI32.@)
641 HDC WINAPI CreateICA( LPCSTR driver, LPCSTR device, LPCSTR output,
642 const DEVMODEA* initData )
644 /* Nothing special yet for ICs */
645 return CreateDCA( driver, device, output, initData );
649 /***********************************************************************
650 * CreateICW (GDI32.@)
652 HDC WINAPI CreateICW( LPCWSTR driver, LPCWSTR device, LPCWSTR output,
653 const DEVMODEW* initData )
655 /* Nothing special yet for ICs */
656 return CreateDCW( driver, device, output, initData );
660 /***********************************************************************
661 * CreateCompatibleDC (GDI32.@)
663 HDC WINAPI CreateCompatibleDC( HDC hdc )
665 DC *dc, *origDC;
666 const DC_FUNCTIONS *funcs;
667 PHYSDEV physDev;
669 GDI_CheckNotLock();
671 if ((origDC = GDI_GetObjPtr( hdc, DC_MAGIC )))
673 funcs = origDC->funcs;
674 physDev = origDC->physDev;
675 GDI_ReleaseObj( hdc ); /* can't hold the lock while loading the driver */
676 funcs = DRIVER_get_driver( funcs );
678 else
680 funcs = DRIVER_load_driver( "DISPLAY" );
681 physDev = NULL;
684 if (!funcs) return 0;
686 if (!(dc = DC_AllocDC( funcs, MEMORY_DC_MAGIC )))
688 DRIVER_release_driver( funcs );
689 return 0;
692 TRACE("(%p): returning %p\n", hdc, dc->hSelf );
694 dc->bitsPerPixel = 1;
695 dc->hBitmap = GetStockObject( DEFAULT_BITMAP );
697 /* Copy the driver-specific physical device info into
698 * the new DC. The driver may use this read-only info
699 * while creating the compatible DC below. */
700 dc->physDev = physDev;
702 if (dc->funcs->pCreateDC &&
703 !dc->funcs->pCreateDC( dc, &dc->physDev, NULL, NULL, NULL, NULL ))
705 WARN("creation aborted by device\n");
706 GDI_FreeObject( dc->hSelf, dc );
707 DRIVER_release_driver( funcs );
708 return 0;
711 dc->totalExtent.left = 0;
712 dc->totalExtent.top = 0;
713 dc->totalExtent.right = 1; /* default bitmap is 1x1 */
714 dc->totalExtent.bottom = 1;
715 dc->hVisRgn = CreateRectRgnIndirect( &dc->totalExtent );
717 DC_InitDC( dc );
718 GDI_ReleaseObj( dc->hSelf );
719 return dc->hSelf;
723 /***********************************************************************
724 * DeleteDC (GDI32.@)
726 BOOL WINAPI DeleteDC( HDC hdc )
728 const DC_FUNCTIONS *funcs = NULL;
729 DC * dc;
731 TRACE("%p\n", hdc );
733 GDI_CheckNotLock();
735 if (!(dc = DC_GetDCPtr( hdc ))) return FALSE;
737 /* Call hook procedure to check whether is it OK to delete this DC */
738 if (dc->hookThunk)
740 DCHOOKPROC proc = dc->hookThunk;
741 DWORD data = dc->dwHookData;
742 GDI_ReleaseObj( hdc );
743 if (!proc( HDC_16(hdc), DCHC_DELETEDC, data, 0 )) return FALSE;
744 if (!(dc = DC_GetDCPtr( hdc ))) return TRUE; /* deleted by the hook */
747 while (dc->saveLevel)
749 DC * dcs;
750 HDC hdcs = HDC_32(dc->header.hNext);
751 if (!(dcs = DC_GetDCPtr( hdcs ))) break;
752 dc->header.hNext = dcs->header.hNext;
753 dc->saveLevel--;
754 if (dcs->hClipRgn) DeleteObject( dcs->hClipRgn );
755 if (dcs->hVisRgn) DeleteObject( dcs->hVisRgn );
756 if (dcs->hGCClipRgn) DeleteObject( dcs->hGCClipRgn );
757 PATH_DestroyGdiPath(&dcs->path);
758 GDI_FreeObject( hdcs, dcs );
761 if (!(dc->flags & DC_SAVED))
763 SelectObject( hdc, GetStockObject(BLACK_PEN) );
764 SelectObject( hdc, GetStockObject(WHITE_BRUSH) );
765 SelectObject( hdc, GetStockObject(SYSTEM_FONT) );
766 SelectObject( hdc, GetStockObject(DEFAULT_BITMAP) );
767 funcs = dc->funcs;
768 if (dc->funcs->pDeleteDC) dc->funcs->pDeleteDC(dc->physDev);
769 dc->physDev = NULL;
772 if (dc->hClipRgn) DeleteObject( dc->hClipRgn );
773 if (dc->hVisRgn) DeleteObject( dc->hVisRgn );
774 if (dc->hGCClipRgn) DeleteObject( dc->hGCClipRgn );
775 PATH_DestroyGdiPath(&dc->path);
777 GDI_FreeObject( hdc, dc );
778 if (funcs) DRIVER_release_driver( funcs ); /* do that after releasing the GDI lock */
779 return TRUE;
783 /***********************************************************************
784 * ResetDCA (GDI32.@)
786 HDC WINAPI ResetDCA( HDC hdc, const DEVMODEA *devmode )
788 DC *dc;
789 HDC ret = hdc;
791 if ((dc = DC_GetDCPtr( hdc )))
793 if (dc->funcs->pResetDC) ret = dc->funcs->pResetDC( dc->physDev, devmode );
794 GDI_ReleaseObj( hdc );
796 return ret;
800 /***********************************************************************
801 * ResetDCW (GDI32.@)
803 HDC WINAPI ResetDCW( HDC hdc, const DEVMODEW *devmode )
805 return ResetDCA(hdc, (const DEVMODEA*)devmode); /* FIXME */
809 /***********************************************************************
810 * GetDeviceCaps (GDI32.@)
812 INT WINAPI GetDeviceCaps( HDC hdc, INT cap )
814 DC *dc;
815 INT ret = 0;
817 if ((dc = DC_GetDCPtr( hdc )))
819 if (dc->funcs->pGetDeviceCaps) ret = dc->funcs->pGetDeviceCaps( dc->physDev, cap );
820 GDI_ReleaseObj( hdc );
822 return ret;
826 /***********************************************************************
827 * SetBkColor (GDI32.@)
829 COLORREF WINAPI SetBkColor( HDC hdc, COLORREF color )
831 COLORREF oldColor;
832 DC * dc = DC_GetDCPtr( hdc );
834 if (!dc) return CLR_INVALID;
835 oldColor = dc->backgroundColor;
836 if (dc->funcs->pSetBkColor)
838 color = dc->funcs->pSetBkColor(dc->physDev, color);
839 if (color == CLR_INVALID) /* don't change it */
841 color = oldColor;
842 oldColor = CLR_INVALID;
845 dc->backgroundColor = color;
846 GDI_ReleaseObj( hdc );
847 return oldColor;
851 /***********************************************************************
852 * SetTextColor (GDI32.@)
854 COLORREF WINAPI SetTextColor( HDC hdc, COLORREF color )
856 COLORREF oldColor;
857 DC * dc = DC_GetDCPtr( hdc );
859 if (!dc) return CLR_INVALID;
860 oldColor = dc->textColor;
861 if (dc->funcs->pSetTextColor)
863 color = dc->funcs->pSetTextColor(dc->physDev, color);
864 if (color == CLR_INVALID) /* don't change it */
866 color = oldColor;
867 oldColor = CLR_INVALID;
870 dc->textColor = color;
871 GDI_ReleaseObj( hdc );
872 return oldColor;
876 /***********************************************************************
877 * SetTextAlign (GDI32.@)
879 UINT WINAPI SetTextAlign( HDC hdc, UINT align )
881 UINT prevAlign;
882 DC *dc = DC_GetDCPtr( hdc );
883 if (!dc) return 0x0;
884 if (dc->funcs->pSetTextAlign)
885 prevAlign = dc->funcs->pSetTextAlign(dc->physDev, align);
886 else {
887 prevAlign = dc->textAlign;
888 dc->textAlign = align;
890 GDI_ReleaseObj( hdc );
891 return prevAlign;
894 /***********************************************************************
895 * GetDCOrgEx (GDI32.@)
897 BOOL WINAPI GetDCOrgEx( HDC hDC, LPPOINT lpp )
899 DC * dc;
901 if (!lpp) return FALSE;
902 if (!(dc = DC_GetDCPtr( hDC ))) return FALSE;
904 lpp->x = lpp->y = 0;
905 if (dc->funcs->pGetDCOrgEx) dc->funcs->pGetDCOrgEx( dc->physDev, lpp );
906 GDI_ReleaseObj( hDC );
907 return TRUE;
911 /***********************************************************************
912 * SetDCOrg (GDI.117)
914 DWORD WINAPI SetDCOrg16( HDC16 hdc16, INT16 x, INT16 y )
916 DWORD prevOrg = 0;
917 HDC hdc = HDC_32( hdc16 );
918 DC *dc = DC_GetDCPtr( hdc );
919 if (!dc) return 0;
920 if (dc->funcs->pSetDCOrg) prevOrg = dc->funcs->pSetDCOrg( dc->physDev, x, y );
921 GDI_ReleaseObj( hdc );
922 return prevOrg;
926 /***********************************************************************
927 * SetGraphicsMode (GDI32.@)
929 INT WINAPI SetGraphicsMode( HDC hdc, INT mode )
931 INT ret = 0;
932 DC *dc = DC_GetDCPtr( hdc );
934 /* One would think that setting the graphics mode to GM_COMPATIBLE
935 * would also reset the world transformation matrix to the unity
936 * matrix. However, in Windows, this is not the case. This doesn't
937 * make a lot of sense to me, but that's the way it is.
939 if (!dc) return 0;
940 if ((mode > 0) && (mode <= GM_LAST))
942 ret = dc->GraphicsMode;
943 dc->GraphicsMode = mode;
945 GDI_ReleaseObj( hdc );
946 return ret;
950 /***********************************************************************
951 * SetArcDirection (GDI32.@)
953 INT WINAPI SetArcDirection( HDC hdc, INT nDirection )
955 DC * dc;
956 INT nOldDirection = 0;
958 if (nDirection!=AD_COUNTERCLOCKWISE && nDirection!=AD_CLOCKWISE)
960 SetLastError(ERROR_INVALID_PARAMETER);
961 return 0;
964 if ((dc = DC_GetDCPtr( hdc )))
966 nOldDirection = dc->ArcDirection;
967 dc->ArcDirection = nDirection;
968 GDI_ReleaseObj( hdc );
970 return nOldDirection;
974 /***********************************************************************
975 * GetWorldTransform (GDI32.@)
977 BOOL WINAPI GetWorldTransform( HDC hdc, LPXFORM xform )
979 DC * dc;
980 if (!xform) return FALSE;
981 if (!(dc = DC_GetDCPtr( hdc ))) return FALSE;
982 *xform = dc->xformWorld2Wnd;
983 GDI_ReleaseObj( hdc );
984 return TRUE;
988 /***********************************************************************
989 * GetTransform (GDI32.@)
991 BOOL WINAPI GetTransform( HDC hdc, DWORD unknown, LPXFORM xform )
993 if (unknown == 0x0203) return GetWorldTransform( hdc, xform );
994 ERR("stub: don't know what to do for code %lx\n", unknown );
995 return FALSE;
999 /***********************************************************************
1000 * SetWorldTransform (GDI32.@)
1002 BOOL WINAPI SetWorldTransform( HDC hdc, const XFORM *xform )
1004 BOOL ret = FALSE;
1005 DC *dc = DC_GetDCPtr( hdc );
1007 if (!dc) return FALSE;
1008 if (!xform) goto done;
1010 /* Check that graphics mode is GM_ADVANCED */
1011 if (dc->GraphicsMode!=GM_ADVANCED) goto done;
1013 dc->xformWorld2Wnd = *xform;
1014 DC_UpdateXforms( dc );
1015 ret = TRUE;
1016 done:
1017 GDI_ReleaseObj( hdc );
1018 return ret;
1022 /****************************************************************************
1023 * ModifyWorldTransform [GDI32.@]
1024 * Modifies the world transformation for a device context.
1026 * PARAMS
1027 * hdc [I] Handle to device context
1028 * xform [I] XFORM structure that will be used to modify the world
1029 * transformation
1030 * iMode [I] Specifies in what way to modify the world transformation
1031 * Possible values:
1032 * MWT_IDENTITY
1033 * Resets the world transformation to the identity matrix.
1034 * The parameter xform is ignored.
1035 * MWT_LEFTMULTIPLY
1036 * Multiplies xform into the world transformation matrix from
1037 * the left.
1038 * MWT_RIGHTMULTIPLY
1039 * Multiplies xform into the world transformation matrix from
1040 * the right.
1042 * RETURNS STD
1044 BOOL WINAPI ModifyWorldTransform( HDC hdc, const XFORM *xform,
1045 DWORD iMode )
1047 BOOL ret = FALSE;
1048 DC *dc = DC_GetDCPtr( hdc );
1050 /* Check for illegal parameters */
1051 if (!dc) return FALSE;
1052 if (!xform) goto done;
1054 /* Check that graphics mode is GM_ADVANCED */
1055 if (dc->GraphicsMode!=GM_ADVANCED) goto done;
1057 switch (iMode)
1059 case MWT_IDENTITY:
1060 dc->xformWorld2Wnd.eM11 = 1.0f;
1061 dc->xformWorld2Wnd.eM12 = 0.0f;
1062 dc->xformWorld2Wnd.eM21 = 0.0f;
1063 dc->xformWorld2Wnd.eM22 = 1.0f;
1064 dc->xformWorld2Wnd.eDx = 0.0f;
1065 dc->xformWorld2Wnd.eDy = 0.0f;
1066 break;
1067 case MWT_LEFTMULTIPLY:
1068 CombineTransform( &dc->xformWorld2Wnd, xform,
1069 &dc->xformWorld2Wnd );
1070 break;
1071 case MWT_RIGHTMULTIPLY:
1072 CombineTransform( &dc->xformWorld2Wnd, &dc->xformWorld2Wnd,
1073 xform );
1074 break;
1075 default:
1076 goto done;
1079 DC_UpdateXforms( dc );
1080 ret = TRUE;
1081 done:
1082 GDI_ReleaseObj( hdc );
1083 return ret;
1087 /****************************************************************************
1088 * CombineTransform [GDI32.@]
1089 * Combines two transformation matrices.
1091 * PARAMS
1092 * xformResult [O] Stores the result of combining the two matrices
1093 * xform1 [I] Specifies the first matrix to apply
1094 * xform2 [I] Specifies the second matrix to apply
1096 * REMARKS
1097 * The same matrix can be passed in for more than one of the parameters.
1099 * RETURNS STD
1101 BOOL WINAPI CombineTransform( LPXFORM xformResult, const XFORM *xform1,
1102 const XFORM *xform2 )
1104 XFORM xformTemp;
1106 /* Check for illegal parameters */
1107 if (!xformResult || !xform1 || !xform2)
1108 return FALSE;
1110 /* Create the result in a temporary XFORM, since xformResult may be
1111 * equal to xform1 or xform2 */
1112 xformTemp.eM11 = xform1->eM11 * xform2->eM11 +
1113 xform1->eM12 * xform2->eM21;
1114 xformTemp.eM12 = xform1->eM11 * xform2->eM12 +
1115 xform1->eM12 * xform2->eM22;
1116 xformTemp.eM21 = xform1->eM21 * xform2->eM11 +
1117 xform1->eM22 * xform2->eM21;
1118 xformTemp.eM22 = xform1->eM21 * xform2->eM12 +
1119 xform1->eM22 * xform2->eM22;
1120 xformTemp.eDx = xform1->eDx * xform2->eM11 +
1121 xform1->eDy * xform2->eM21 +
1122 xform2->eDx;
1123 xformTemp.eDy = xform1->eDx * xform2->eM12 +
1124 xform1->eDy * xform2->eM22 +
1125 xform2->eDy;
1127 /* Copy the result to xformResult */
1128 *xformResult = xformTemp;
1130 return TRUE;
1134 /***********************************************************************
1135 * SetDCHook (GDI32.@)
1137 * Note: this doesn't exist in Win32, we add it here because user32 needs it.
1139 BOOL WINAPI SetDCHook( HDC hdc, DCHOOKPROC hookProc, DWORD dwHookData )
1141 DC *dc = GDI_GetObjPtr( hdc, DC_MAGIC );
1143 if (!dc) return FALSE;
1145 if (!(dc->flags & DC_SAVED))
1147 dc->dwHookData = dwHookData;
1148 dc->hookThunk = hookProc;
1150 GDI_ReleaseObj( hdc );
1151 return TRUE;
1155 /* relay function to call the 16-bit DC hook proc */
1156 static BOOL16 WINAPI call_dc_hook16( HDC16 hdc16, WORD code, DWORD data, LPARAM lParam )
1158 WORD args[6];
1159 DWORD ret;
1160 FARPROC16 proc = NULL;
1161 HDC hdc = HDC_32( hdc16 );
1162 DC *dc = DC_GetDCPtr( hdc );
1164 if (!dc) return FALSE;
1165 proc = dc->hookProc;
1166 GDI_ReleaseObj( hdc );
1167 if (!proc) return FALSE;
1168 args[5] = hdc16;
1169 args[4] = code;
1170 args[3] = HIWORD(data);
1171 args[2] = LOWORD(data);
1172 args[1] = HIWORD(lParam);
1173 args[0] = LOWORD(lParam);
1174 WOWCallback16Ex( (DWORD)proc, WCB16_PASCAL, sizeof(args), args, &ret );
1175 return LOWORD(ret);
1178 /***********************************************************************
1179 * SetDCHook (GDI.190)
1181 BOOL16 WINAPI SetDCHook16( HDC16 hdc16, FARPROC16 hookProc, DWORD dwHookData )
1183 HDC hdc = HDC_32( hdc16 );
1184 DC *dc = DC_GetDCPtr( hdc );
1185 if (!dc) return FALSE;
1187 dc->hookProc = hookProc;
1188 GDI_ReleaseObj( hdc );
1189 return SetDCHook( hdc, call_dc_hook16, dwHookData );
1193 /***********************************************************************
1194 * GetDCHook (GDI.191)
1196 DWORD WINAPI GetDCHook16( HDC16 hdc16, FARPROC16 *phookProc )
1198 HDC hdc = HDC_32( hdc16 );
1199 DC *dc = DC_GetDCPtr( hdc );
1200 DWORD ret;
1202 if (!dc) return 0;
1203 *phookProc = dc->hookProc;
1204 ret = dc->dwHookData;
1205 GDI_ReleaseObj( hdc );
1206 return ret;
1210 /***********************************************************************
1211 * SetHookFlags (GDI.192)
1213 WORD WINAPI SetHookFlags16(HDC16 hdc16, WORD flags)
1215 HDC hdc = HDC_32( hdc16 );
1216 DC *dc = DC_GetDCPtr( hdc );
1218 if( dc )
1220 WORD wRet = dc->flags & DC_DIRTY;
1222 /* "Undocumented Windows" info is slightly confusing.
1225 TRACE("hDC %p, flags %04x\n",hdc,flags);
1227 if( flags & DCHF_INVALIDATEVISRGN )
1228 dc->flags |= DC_DIRTY;
1229 else if( flags & DCHF_VALIDATEVISRGN || !flags )
1230 dc->flags &= ~DC_DIRTY;
1231 GDI_ReleaseObj( hdc );
1232 return wRet;
1234 return 0;
1237 /***********************************************************************
1238 * SetICMMode (GDI32.@)
1240 INT WINAPI SetICMMode(HDC hdc, INT iEnableICM)
1242 /*FIXME Asuming that ICM is always off, and cannot be turned on */
1243 if (iEnableICM == ICM_OFF) return ICM_OFF;
1244 if (iEnableICM == ICM_ON) return 0;
1245 if (iEnableICM == ICM_QUERY) return ICM_OFF;
1246 return 0;
1249 /***********************************************************************
1250 * GetDeviceGammaRamp (GDI32.@)
1252 BOOL WINAPI GetDeviceGammaRamp(HDC hDC, LPVOID ptr)
1254 BOOL ret = FALSE;
1255 DC *dc = DC_GetDCPtr( hDC );
1257 if( dc )
1259 if (dc->funcs->pGetDeviceGammaRamp)
1260 ret = dc->funcs->pGetDeviceGammaRamp(dc->physDev, ptr);
1261 GDI_ReleaseObj( hDC );
1263 return ret;
1266 /***********************************************************************
1267 * SetDeviceGammaRamp (GDI32.@)
1269 BOOL WINAPI SetDeviceGammaRamp(HDC hDC, LPVOID ptr)
1271 BOOL ret = FALSE;
1272 DC *dc = DC_GetDCPtr( hDC );
1274 if( dc )
1276 if (dc->funcs->pSetDeviceGammaRamp)
1277 ret = dc->funcs->pSetDeviceGammaRamp(dc->physDev, ptr);
1278 GDI_ReleaseObj( hDC );
1280 return ret;
1283 /***********************************************************************
1284 * GetColorSpace (GDI32.@)
1286 HCOLORSPACE WINAPI GetColorSpace(HDC hdc)
1288 /*FIXME Need to to whatever GetColorSpace actually does */
1289 return 0;
1292 /***********************************************************************
1293 * CreateColorSpaceA (GDI32.@)
1295 HCOLORSPACE WINAPI CreateColorSpaceA( LPLOGCOLORSPACEA lpLogColorSpace )
1297 FIXME( "stub\n" );
1298 return 0;
1301 /***********************************************************************
1302 * CreateColorSpaceW (GDI32.@)
1304 HCOLORSPACE WINAPI CreateColorSpaceW( LPLOGCOLORSPACEW lpLogColorSpace )
1306 FIXME( "stub\n" );
1307 return 0;
1310 /***********************************************************************
1311 * DeleteColorSpace (GDI32.@)
1313 BOOL WINAPI DeleteColorSpace( HCOLORSPACE hColorSpace )
1315 FIXME( "stub\n" );
1317 return TRUE;
1320 /***********************************************************************
1321 * SetColorSpace (GDI32.@)
1323 HCOLORSPACE WINAPI SetColorSpace( HDC hDC, HCOLORSPACE hColorSpace )
1325 FIXME( "stub\n" );
1327 return hColorSpace;
1330 /***********************************************************************
1331 * GetBoundsRect (GDI.194)
1333 UINT16 WINAPI GetBoundsRect16(HDC16 hdc, LPRECT16 rect, UINT16 flags)
1335 return DCB_RESET | DCB_DISABLE; /* bounding rectangle always empty and disabled*/
1338 /***********************************************************************
1339 * GetBoundsRect (GDI32.@)
1341 UINT WINAPI GetBoundsRect(HDC hdc, LPRECT rect, UINT flags)
1343 FIXME("(): stub\n");
1344 return DCB_RESET; /* bounding rectangle always empty */
1347 /***********************************************************************
1348 * SetBoundsRect (GDI.193)
1350 UINT16 WINAPI SetBoundsRect16(HDC16 hdc, const RECT16* rect, UINT16 flags)
1352 if ( (flags & DCB_ACCUMULATE) || (flags & DCB_ENABLE) )
1353 FIXME("(%04x, %p, %04x): stub\n", hdc, rect, flags );
1355 return DCB_RESET | DCB_DISABLE; /* bounding rectangle always empty and disabled*/
1358 /***********************************************************************
1359 * SetBoundsRect (GDI32.@)
1361 UINT WINAPI SetBoundsRect(HDC hdc, const RECT* rect, UINT flags)
1363 FIXME("(): stub\n");
1364 return DCB_DISABLE; /* bounding rectangle always empty */
1368 /***********************************************************************
1369 * GetRelAbs (GDI32.@)
1371 INT WINAPI GetRelAbs( HDC hdc, DWORD dwIgnore )
1373 INT ret = 0;
1374 DC *dc = DC_GetDCPtr( hdc );
1375 if (dc) ret = dc->relAbsMode;
1376 GDI_ReleaseObj( hdc );
1377 return ret;
1380 /***********************************************************************
1381 * GetLayout (GDI32.@)
1383 * Gets left->right or right->left text layout flags of a dc.
1384 * win98 just returns 0 and sets ERROR_CALL_NOT_IMPLEMENTED so we do the same
1387 DWORD WINAPI GetLayout(HDC hdc)
1389 FIXME("(%p): stub\n", hdc);
1390 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1391 return 0;
1394 /***********************************************************************
1395 * SetLayout (GDI32.@)
1397 * Sets left->right or right->left text layout flags of a dc.
1398 * win98 just returns 0 and sets ERROR_CALL_NOT_IMPLEMENTED so we do the same
1401 DWORD WINAPI SetLayout(HDC hdc, DWORD layout)
1403 FIXME("(%p,%08lx): stub\n", hdc, layout);
1404 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1405 return 0;
1408 /***********************************************************************
1409 * SetDCBrushColor (GDI32.@)
1411 * Sets the current device context (DC) brush color to the specified
1412 * color value. If the device cannot represent the specified color
1413 * value, the color is set to the nearest physical color.
1416 COLORREF WINAPI SetDCBrushColor(HDC hdc, COLORREF crColor)
1418 FIXME("(%p, %08lx): stub\n", hdc, crColor);
1419 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1420 return CLR_INVALID;
1423 /***********************************************************************
1424 * SetVirtualResolution (GDI32.@)
1426 * Undocumented on msdn. Called when powerpoint xp saves a file.
1428 DWORD WINAPI SetVirtualResolution(HDC hdc, DWORD dw2, DWORD dw3, DWORD dw4, DWORD dw5)
1430 FIXME("(%p %08lx %08lx %08lx %08lx): stub!\n", hdc, dw2, dw3, dw4, dw5);
1431 return FALSE;