po: Update French translation.
[wine] / dlls / gdi32 / gdiobj.c
1 /*
2  * GDI 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22
23 #include <assert.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winreg.h"
32 #include "winnls.h"
33 #include "winerror.h"
34 #include "winternl.h"
35
36 #include "gdi_private.h"
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(gdi);
40
41 #define HGDIOBJ_32(h16)   ((HGDIOBJ)(ULONG_PTR)(h16))
42
43 #define GDI_HEAP_SIZE 0xffe0
44
45 HMODULE gdi32_module = 0;
46
47 /***********************************************************************
48  *          GDI stock objects
49  */
50
51 static const LOGBRUSH WhiteBrush = { BS_SOLID, RGB(255,255,255), 0 };
52 static const LOGBRUSH BlackBrush = { BS_SOLID, RGB(0,0,0), 0 };
53 static const LOGBRUSH NullBrush  = { BS_NULL, 0, 0 };
54
55 static const LOGBRUSH LtGrayBrush = { BS_SOLID, RGB(192,192,192), 0 };
56 static const LOGBRUSH GrayBrush   = { BS_SOLID, RGB(128,128,128), 0 };
57 static const LOGBRUSH DkGrayBrush = { BS_SOLID, RGB(64,64,64), 0 };
58
59 static const LOGPEN WhitePen = { PS_SOLID, { 0, 0 }, RGB(255,255,255) };
60 static const LOGPEN BlackPen = { PS_SOLID, { 0, 0 }, RGB(0,0,0) };
61 static const LOGPEN NullPen  = { PS_NULL,  { 0, 0 }, 0 };
62
63 static const LOGBRUSH DCBrush = { BS_SOLID, RGB(255,255,255), 0 };
64 static const LOGPEN DCPen     = { PS_SOLID, { 0, 0 }, RGB(0,0,0) };
65
66 /* reserve one extra entry for the stock default bitmap */
67 /* this is what Windows does too */
68 #define NB_STOCK_OBJECTS (STOCK_LAST+2)
69
70 static HGDIOBJ stock_objects[NB_STOCK_OBJECTS];
71
72 static CRITICAL_SECTION gdi_section;
73 static CRITICAL_SECTION_DEBUG critsect_debug =
74 {
75     0, 0, &gdi_section,
76     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
77       0, 0, { (DWORD_PTR)(__FILE__ ": gdi_section") }
78 };
79 static CRITICAL_SECTION gdi_section = { &critsect_debug, -1, 0, 0, 0, 0 };
80
81
82 /****************************************************************************
83  *
84  *      language-independent stock fonts
85  *
86  */
87
88 static const LOGFONTW OEMFixedFont =
89 { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, OEM_CHARSET,
90   0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, {'\0'} };
91
92 static const LOGFONTW AnsiFixedFont =
93 { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
94   0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
95   {'C','o','u','r','i','e','r','\0'} };
96
97 static const LOGFONTW AnsiVarFont =
98 { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
99   0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
100   {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'} };
101
102 /******************************************************************************
103  *
104  *      language-dependent stock fonts
105  *
106  *      'ANSI' charset and 'DEFAULT' charset is not same.
107  *      The chars in CP_ACP should be drawn with 'DEFAULT' charset.
108  *      'ANSI' charset seems to be identical with ISO-8859-1.
109  *      'DEFAULT' charset is a language-dependent charset.
110  *
111  *      'System' font seems to be an alias for language-dependent font.
112  */
113
114 /*
115  * language-dependent stock fonts for all known charsets
116  * please see TranslateCharsetInfo (dlls/gdi/font.c) and
117  * CharsetBindingInfo (dlls/x11drv/xfont.c),
118  * and modify entries for your language if needed.
119  */
120 struct DefaultFontInfo
121 {
122         UINT            charset;
123         LOGFONTW        SystemFont;
124         LOGFONTW        DeviceDefaultFont;
125         LOGFONTW        SystemFixedFont;
126         LOGFONTW        DefaultGuiFont; /* Note for this font the lfHeight member should be the point size */
127 };
128
129 static const struct DefaultFontInfo default_fonts[] =
130 {
131     {   ANSI_CHARSET,
132         { /* System */
133           16, 7, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
134            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
135            {'S','y','s','t','e','m','\0'}
136         },
137         { /* Device Default */
138           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
139            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
140            {'\0'}
141         },
142         { /* System Fixed */
143           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
144            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
145            {'\0'}
146         },
147         { /* DefaultGuiFont */
148            8, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
149            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
150            {'M','S',' ','S','h','e','l','l',' ','D','l','g','\0'}
151         },
152     },
153     {   EASTEUROPE_CHARSET,
154         { /* System */
155           16, 7, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, EASTEUROPE_CHARSET,
156            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
157            {'S','y','s','t','e','m','\0'}
158         },
159         { /* Device Default */
160           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, EASTEUROPE_CHARSET,
161            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
162            {'\0'}
163         },
164         { /* System Fixed */
165           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, EASTEUROPE_CHARSET,
166            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
167            {'\0'}
168         },
169         { /* DefaultGuiFont */
170            8, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, EASTEUROPE_CHARSET,
171            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
172            {'M','S',' ','S','h','e','l','l',' ','D','l','g','\0'}
173         },
174     },
175     {   RUSSIAN_CHARSET,
176         { /* System */
177           16, 7, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, RUSSIAN_CHARSET,
178            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
179            {'S','y','s','t','e','m','\0'}
180         },
181         { /* Device Default */
182           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, RUSSIAN_CHARSET,
183            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
184            {'\0'}
185         },
186         { /* System Fixed */
187           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, RUSSIAN_CHARSET,
188            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
189            {'\0'}
190         },
191         { /* DefaultGuiFont */
192            8, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, RUSSIAN_CHARSET,
193            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
194            {'M','S',' ','S','h','e','l','l',' ','D','l','g','\0'}
195         },
196     },
197     {   GREEK_CHARSET,
198         { /* System */
199           16, 7, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GREEK_CHARSET,
200            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
201            {'S','y','s','t','e','m','\0'}
202         },
203         { /* Device Default */
204           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GREEK_CHARSET,
205            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
206            {'\0'}
207         },
208         { /* System Fixed */
209           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GREEK_CHARSET,
210            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
211            {'\0'}
212         },
213         { /* DefaultGuiFont */
214            8, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GREEK_CHARSET,
215            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
216            {'M','S',' ','S','h','e','l','l',' ','D','l','g','\0'}
217         },
218     },
219     {   TURKISH_CHARSET,
220         { /* System */
221           16, 7, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, TURKISH_CHARSET,
222            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
223            {'S','y','s','t','e','m','\0'}
224         },
225         { /* Device Default */
226           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, TURKISH_CHARSET,
227            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
228            {'\0'}
229         },
230         { /* System Fixed */
231           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, TURKISH_CHARSET,
232            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
233            {'\0'}
234         },
235         { /* DefaultGuiFont */
236            8, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, TURKISH_CHARSET,
237            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
238            {'M','S',' ','S','h','e','l','l',' ','D','l','g','\0'}
239         },
240     },
241     {   HEBREW_CHARSET,
242         { /* System */
243           16, 7, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HEBREW_CHARSET,
244            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
245            {'S','y','s','t','e','m','\0'}
246         },
247         { /* Device Default */
248           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HEBREW_CHARSET,
249            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
250            {'\0'}
251         },
252         { /* System Fixed */
253           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HEBREW_CHARSET,
254            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
255            {'\0'}
256         },
257         { /* DefaultGuiFont */
258            8, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HEBREW_CHARSET,
259            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
260            {'M','S',' ','S','h','e','l','l',' ','D','l','g','\0'}
261         },
262     },
263     {   ARABIC_CHARSET,
264         { /* System */
265           16, 7, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ARABIC_CHARSET,
266            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
267            {'S','y','s','t','e','m','\0'}
268         },
269         { /* Device Default */
270           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ARABIC_CHARSET,
271            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
272            {'\0'}
273         },
274         { /* System Fixed */
275           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ARABIC_CHARSET,
276            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
277            {'\0'}
278         },
279         { /* DefaultGuiFont */
280            8, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ARABIC_CHARSET,
281            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
282            {'M','S',' ','S','h','e','l','l',' ','D','l','g','\0'}
283         },
284     },
285     {   BALTIC_CHARSET,
286         { /* System */
287           16, 7, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, BALTIC_CHARSET,
288            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
289            {'S','y','s','t','e','m','\0'}
290         },
291         { /* Device Default */
292           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, BALTIC_CHARSET,
293            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
294            {'\0'}
295         },
296         { /* System Fixed */
297           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, BALTIC_CHARSET,
298            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
299            {'\0'}
300         },
301         { /* DefaultGuiFont */
302            8, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, BALTIC_CHARSET,
303            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
304            {'M','S',' ','S','h','e','l','l',' ','D','l','g','\0'}
305         },
306     },
307     {   THAI_CHARSET,
308         { /* System */
309           16, 7, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, THAI_CHARSET,
310            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
311            {'S','y','s','t','e','m','\0'}
312         },
313         { /* Device Default */
314           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, THAI_CHARSET,
315            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
316            {'\0'}
317         },
318         { /* System Fixed */
319           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, THAI_CHARSET,
320            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
321            {'\0'}
322         },
323         { /* DefaultGuiFont */
324            8, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, THAI_CHARSET,
325            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
326            {'M','S',' ','S','h','e','l','l',' ','D','l','g','\0'}
327         },
328     },
329     {   SHIFTJIS_CHARSET,
330         { /* System */
331           16, 7, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, SHIFTJIS_CHARSET,
332            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
333            {'S','y','s','t','e','m','\0'}
334         },
335         { /* Device Default */
336           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, SHIFTJIS_CHARSET,
337            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
338            {'\0'}
339         },
340         { /* System Fixed */
341           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, SHIFTJIS_CHARSET,
342            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
343            {'\0'}
344         },
345         { /* DefaultGuiFont */
346            9, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, SHIFTJIS_CHARSET,
347            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
348            {'M','S',' ','S','h','e','l','l',' ','D','l','g','\0'}
349         },
350     },
351     {   GB2312_CHARSET,
352         { /* System */
353           16, 7, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GB2312_CHARSET,
354            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
355            {'S','y','s','t','e','m','\0'}
356         },
357         { /* Device Default */
358           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GB2312_CHARSET,
359            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
360            {'\0'}
361         },
362         { /* System Fixed */
363           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GB2312_CHARSET,
364            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
365            {'\0'}
366         },
367         { /* DefaultGuiFont */
368            9, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GB2312_CHARSET,
369            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
370            {'M','S',' ','S','h','e','l','l',' ','D','l','g','\0'}
371         },
372     },
373     {   HANGEUL_CHARSET,
374         { /* System */
375           16, 7, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HANGEUL_CHARSET,
376            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
377            {'S','y','s','t','e','m','\0'}
378         },
379         { /* Device Default */
380           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HANGEUL_CHARSET,
381            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
382            {'\0'}
383         },
384         { /* System Fixed */
385           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HANGEUL_CHARSET,
386            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
387            {'\0'}
388         },
389         { /* DefaultGuiFont */
390            9, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HANGEUL_CHARSET,
391            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
392            {'M','S',' ','S','h','e','l','l',' ','D','l','g','\0'}
393         },
394     },
395     {   CHINESEBIG5_CHARSET,
396         { /* System */
397           16, 7, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, CHINESEBIG5_CHARSET,
398            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
399            {'S','y','s','t','e','m','\0'}
400         },
401         { /* Device Default */
402           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, CHINESEBIG5_CHARSET,
403            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
404            {'\0'}
405         },
406         { /* System Fixed */
407           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, CHINESEBIG5_CHARSET,
408            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
409            {'\0'}
410         },
411         { /* DefaultGuiFont */
412            9, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, CHINESEBIG5_CHARSET,
413            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
414            {'M','S',' ','S','h','e','l','l',' ','D','l','g','\0'}
415         },
416     },
417     {   JOHAB_CHARSET,
418         { /* System */
419           16, 7, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, JOHAB_CHARSET,
420            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
421            {'S','y','s','t','e','m','\0'}
422         },
423         { /* Device Default */
424           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, JOHAB_CHARSET,
425            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
426            {'\0'}
427         },
428         { /* System Fixed */
429           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, JOHAB_CHARSET,
430            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
431            {'\0'}
432         },
433         { /* DefaultGuiFont */
434            8, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, JOHAB_CHARSET,
435            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
436            {'M','S',' ','S','h','e','l','l',' ','D','l','g','\0'}
437         },
438     },
439 };
440
441
442 /*************************************************************************
443  * __wine_make_gdi_object_system    (GDI32.@)
444  *
445  * USER has to tell GDI that its system brushes and pens are non-deletable.
446  * For a description of the GDI object magics and their flags,
447  * see "Undocumented Windows" (wrong about the OBJECT_NOSYSTEM flag, though).
448  */
449 void CDECL __wine_make_gdi_object_system( HGDIOBJ handle, BOOL set)
450 {
451     GDIOBJHDR *ptr = GDI_GetObjPtr( handle, 0 );
452     ptr->system = !!set;
453     GDI_ReleaseObj( handle );
454 }
455
456 /******************************************************************************
457  *      get_default_fonts
458  */
459 static const struct DefaultFontInfo* get_default_fonts(UINT charset)
460 {
461         unsigned int n;
462
463         for(n=0;n<(sizeof(default_fonts)/sizeof(default_fonts[0]));n++)
464         {
465                 if ( default_fonts[n].charset == charset )
466                         return &default_fonts[n];
467         }
468
469         FIXME( "unhandled charset 0x%08x - use ANSI_CHARSET for default stock objects\n", charset );
470         return &default_fonts[0];
471 }
472
473
474 /******************************************************************************
475  *      get_default_charset    (internal)
476  *
477  * get the language-dependent charset that can handle CP_ACP correctly.
478  */
479 static UINT get_default_charset( void )
480 {
481     CHARSETINFO     csi;
482     UINT    uACP;
483
484     uACP = GetACP();
485     csi.ciCharset = ANSI_CHARSET;
486     if ( !TranslateCharsetInfo( ULongToPtr(uACP), &csi, TCI_SRCCODEPAGE ) )
487     {
488         FIXME( "unhandled codepage %u - use ANSI_CHARSET for default stock objects\n", uACP );
489         return ANSI_CHARSET;
490     }
491
492     return csi.ciCharset;
493 }
494
495 static const WCHAR dpi_key_name[] = {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s','\0'};
496 static const WCHAR dpi_value_name[] = {'L','o','g','P','i','x','e','l','s','\0'};
497
498 /******************************************************************************
499  *      get_dpi   (internal)
500  *
501  * get the dpi from the registry
502  */
503 static DWORD get_dpi( void )
504 {
505     DWORD dpi = 96;
506     HKEY hkey;
507
508     if (RegOpenKeyW(HKEY_CURRENT_CONFIG, dpi_key_name, &hkey) == ERROR_SUCCESS)
509     {
510         DWORD type, size, new_dpi;
511
512         size = sizeof(new_dpi);
513         if(RegQueryValueExW(hkey, dpi_value_name, NULL, &type, (void *)&new_dpi, &size) == ERROR_SUCCESS)
514         {
515             if(type == REG_DWORD && new_dpi != 0)
516                 dpi = new_dpi;
517         }
518         RegCloseKey(hkey);
519     }
520     return dpi;
521 }
522
523
524 /***********************************************************************
525  *           GDI_inc_ref_count
526  *
527  * Increment the reference count of a GDI object.
528  */
529 HGDIOBJ GDI_inc_ref_count( HGDIOBJ handle )
530 {
531     GDIOBJHDR *header;
532
533     if ((header = GDI_GetObjPtr( handle, 0 )))
534     {
535         header->selcount++;
536         GDI_ReleaseObj( handle );
537     }
538     else handle = 0;
539
540     return handle;
541 }
542
543
544 /***********************************************************************
545  *           GDI_dec_ref_count
546  *
547  * Decrement the reference count of a GDI object.
548  */
549 BOOL GDI_dec_ref_count( HGDIOBJ handle )
550 {
551     GDIOBJHDR *header;
552
553     if ((header = GDI_GetObjPtr( handle, 0 )))
554     {
555         assert( header->selcount );
556         if (!--header->selcount && header->deleted)
557         {
558             /* handle delayed DeleteObject*/
559             header->deleted = 0;
560             GDI_ReleaseObj( handle );
561             TRACE( "executing delayed DeleteObject for %p\n", handle );
562             DeleteObject( handle );
563         }
564         else GDI_ReleaseObj( handle );
565     }
566     return header != NULL;
567 }
568
569
570 /***********************************************************************
571  *           DllMain
572  *
573  * GDI initialization.
574  */
575 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
576 {
577     LOGFONTW default_gui_font;
578     const struct DefaultFontInfo* deffonts;
579     int i;
580
581     if (reason != DLL_PROCESS_ATTACH) return TRUE;
582
583     gdi32_module = inst;
584     DisableThreadLibraryCalls( inst );
585     WineEngInit();
586
587     /* create stock objects */
588     stock_objects[WHITE_BRUSH]  = CreateBrushIndirect( &WhiteBrush );
589     stock_objects[LTGRAY_BRUSH] = CreateBrushIndirect( &LtGrayBrush );
590     stock_objects[GRAY_BRUSH]   = CreateBrushIndirect( &GrayBrush );
591     stock_objects[DKGRAY_BRUSH] = CreateBrushIndirect( &DkGrayBrush );
592     stock_objects[BLACK_BRUSH]  = CreateBrushIndirect( &BlackBrush );
593     stock_objects[NULL_BRUSH]   = CreateBrushIndirect( &NullBrush );
594
595     stock_objects[WHITE_PEN]    = CreatePenIndirect( &WhitePen );
596     stock_objects[BLACK_PEN]    = CreatePenIndirect( &BlackPen );
597     stock_objects[NULL_PEN]     = CreatePenIndirect( &NullPen );
598
599     stock_objects[DEFAULT_PALETTE] = PALETTE_Init();
600     stock_objects[DEFAULT_BITMAP]  = CreateBitmap( 1, 1, 1, 1, NULL );
601
602     /* language-independent stock fonts */
603     stock_objects[OEM_FIXED_FONT]      = CreateFontIndirectW( &OEMFixedFont );
604     stock_objects[ANSI_FIXED_FONT]     = CreateFontIndirectW( &AnsiFixedFont );
605     stock_objects[ANSI_VAR_FONT]       = CreateFontIndirectW( &AnsiVarFont );
606
607     /* language-dependent stock fonts */
608     deffonts = get_default_fonts(get_default_charset());
609     stock_objects[SYSTEM_FONT]         = CreateFontIndirectW( &deffonts->SystemFont );
610     stock_objects[DEVICE_DEFAULT_FONT] = CreateFontIndirectW( &deffonts->DeviceDefaultFont );
611     stock_objects[SYSTEM_FIXED_FONT]   = CreateFontIndirectW( &deffonts->SystemFixedFont );
612
613     /* For the default gui font, we use the lfHeight member in deffonts as a place-holder
614        for the point size so we must convert this into a true height */
615     default_gui_font = deffonts->DefaultGuiFont;
616     default_gui_font.lfHeight = -MulDiv(default_gui_font.lfHeight, get_dpi(), 72);
617     stock_objects[DEFAULT_GUI_FONT]    = CreateFontIndirectW( &default_gui_font );
618
619     stock_objects[DC_BRUSH]     = CreateBrushIndirect( &DCBrush );
620     stock_objects[DC_PEN]       = CreatePenIndirect( &DCPen );
621
622     /* clear the NOSYSTEM bit on all stock objects*/
623     for (i = 0; i < NB_STOCK_OBJECTS; i++)
624     {
625         if (!stock_objects[i])
626         {
627             if (i == 9) continue;  /* there's no stock object 9 */
628             ERR( "could not create stock object %d\n", i );
629             return FALSE;
630         }
631         __wine_make_gdi_object_system( stock_objects[i], TRUE );
632     }
633
634     return TRUE;
635 }
636
637 #define FIRST_LARGE_HANDLE 16
638 #define MAX_LARGE_HANDLES ((GDI_HEAP_SIZE >> 2) - FIRST_LARGE_HANDLE)
639 static GDIOBJHDR *large_handles[MAX_LARGE_HANDLES];
640 static int next_large_handle;
641 static LONG debug_count;
642
643 static const char *gdi_obj_type( unsigned type )
644 {
645     switch ( type )
646     {
647         case OBJ_PEN: return "OBJ_PEN";
648         case OBJ_BRUSH: return "OBJ_BRUSH";
649         case OBJ_DC: return "OBJ_DC";
650         case OBJ_METADC: return "OBJ_METADC";
651         case OBJ_PAL: return "OBJ_PAL";
652         case OBJ_FONT: return "OBJ_FONT";
653         case OBJ_BITMAP: return "OBJ_BITMAP";
654         case OBJ_REGION: return "OBJ_REGION";
655         case OBJ_METAFILE: return "OBJ_METAFILE";
656         case OBJ_MEMDC: return "OBJ_MEMDC";
657         case OBJ_EXTPEN: return "OBJ_EXTPEN";
658         case OBJ_ENHMETADC: return "OBJ_ENHMETADC";
659         case OBJ_ENHMETAFILE: return "OBJ_ENHMETAFILE";
660         case OBJ_COLORSPACE: return "OBJ_COLORSPACE";
661         default: return "UNKNOWN";
662     }
663 }
664
665 static void dump_gdi_objects( void )
666 {
667     int i;
668
669     TRACE( "%u objects:\n", MAX_LARGE_HANDLES );
670
671     EnterCriticalSection( &gdi_section );
672     for (i = 0; i < MAX_LARGE_HANDLES; i++)
673     {
674         if (!large_handles[i])
675         {
676             TRACE( "index %d handle %p FREE\n", i, (HGDIOBJ)(ULONG_PTR)((i + FIRST_LARGE_HANDLE) << 2) );
677             continue;
678         }
679         TRACE( "handle %p obj %p type %s selcount %u deleted %u\n",
680                (HGDIOBJ)(ULONG_PTR)((i + FIRST_LARGE_HANDLE) << 2),
681                large_handles[i], gdi_obj_type( large_handles[i]->type ),
682                large_handles[i]->selcount, large_handles[i]->deleted );
683     }
684     LeaveCriticalSection( &gdi_section );
685 }
686
687 /***********************************************************************
688  *           alloc_gdi_handle
689  *
690  * Allocate a GDI handle for an object, which must have been allocated on the process heap.
691  */
692 HGDIOBJ alloc_gdi_handle( GDIOBJHDR *obj, WORD type, const struct gdi_obj_funcs *funcs )
693 {
694     int i;
695
696     /* initialize the object header */
697     obj->type     = type;
698     obj->system   = 0;
699     obj->deleted  = 0;
700     obj->selcount = 0;
701     obj->funcs    = funcs;
702     obj->hdcs     = NULL;
703
704     EnterCriticalSection( &gdi_section );
705     for (i = next_large_handle + 1; i < MAX_LARGE_HANDLES; i++)
706         if (!large_handles[i]) goto found;
707     for (i = 0; i <= next_large_handle; i++)
708         if (!large_handles[i]) goto found;
709     LeaveCriticalSection( &gdi_section );
710
711     ERR( "out of GDI object handles, expect a crash\n" );
712     if (TRACE_ON(gdi)) dump_gdi_objects();
713     return 0;
714
715  found:
716     large_handles[i] = obj;
717     next_large_handle = i;
718     LeaveCriticalSection( &gdi_section );
719     TRACE( "allocated %s %p %u/%u\n",
720            gdi_obj_type(type), (HGDIOBJ)(ULONG_PTR)((i + FIRST_LARGE_HANDLE) << 2),
721            InterlockedIncrement( &debug_count ), MAX_LARGE_HANDLES );
722     return (HGDIOBJ)(ULONG_PTR)((i + FIRST_LARGE_HANDLE) << 2);
723 }
724
725
726 /***********************************************************************
727  *           free_gdi_handle
728  *
729  * Free a GDI handle and return a pointer to the object.
730  */
731 void *free_gdi_handle( HGDIOBJ handle )
732 {
733     GDIOBJHDR *object = NULL;
734     int i;
735
736     i = ((ULONG_PTR)handle >> 2) - FIRST_LARGE_HANDLE;
737     if (i >= 0 && i < MAX_LARGE_HANDLES)
738     {
739         EnterCriticalSection( &gdi_section );
740         object = large_handles[i];
741         large_handles[i] = NULL;
742         LeaveCriticalSection( &gdi_section );
743     }
744     if (object)
745     {
746         TRACE( "freed %s %p %u/%u\n", gdi_obj_type( object->type ), handle,
747                InterlockedDecrement( &debug_count ) + 1, MAX_LARGE_HANDLES );
748         object->type  = 0;  /* mark it as invalid */
749         object->funcs = NULL;
750     }
751     return object;
752 }
753
754
755 /***********************************************************************
756  *           GDI_GetObjPtr
757  *
758  * Return a pointer to the GDI object associated to the handle.
759  * Return NULL if the object has the wrong magic number.
760  * The object must be released with GDI_ReleaseObj.
761  */
762 void *GDI_GetObjPtr( HGDIOBJ handle, WORD type )
763 {
764     GDIOBJHDR *ptr = NULL;
765     int i;
766
767     EnterCriticalSection( &gdi_section );
768
769     i = ((UINT_PTR)handle >> 2) - FIRST_LARGE_HANDLE;
770     if (i >= 0 && i < MAX_LARGE_HANDLES)
771     {
772         ptr = large_handles[i];
773         if (ptr && type && ptr->type != type) ptr = NULL;
774     }
775
776     if (!ptr)
777     {
778         LeaveCriticalSection( &gdi_section );
779         WARN( "Invalid handle %p\n", handle );
780     }
781
782     return ptr;
783 }
784
785
786 /***********************************************************************
787  *           GDI_ReleaseObj
788  *
789  */
790 void GDI_ReleaseObj( HGDIOBJ handle )
791 {
792     LeaveCriticalSection( &gdi_section );
793 }
794
795
796 /***********************************************************************
797  *           GDI_CheckNotLock
798  */
799 void GDI_CheckNotLock(void)
800 {
801     if (gdi_section.OwningThread == ULongToHandle(GetCurrentThreadId()) && gdi_section.RecursionCount)
802     {
803         ERR( "BUG: holding GDI lock\n" );
804         DebugBreak();
805     }
806 }
807
808
809 /***********************************************************************
810  *           DeleteObject    (GDI32.@)
811  *
812  * Delete a Gdi object.
813  *
814  * PARAMS
815  *  obj [I] Gdi object to delete
816  *
817  * RETURNS
818  *  Success: TRUE. If obj was not returned from GetStockObject(), any resources
819  *           it consumed are released.
820  *  Failure: FALSE, if obj is not a valid Gdi object, or is currently selected
821  *           into a DC.
822  */
823 BOOL WINAPI DeleteObject( HGDIOBJ obj )
824 {
825       /* Check if object is valid */
826
827     struct hdc_list *hdcs_head;
828     const struct gdi_obj_funcs *funcs;
829     GDIOBJHDR * header;
830
831     if (HIWORD(obj)) return FALSE;
832
833     if (!(header = GDI_GetObjPtr( obj, 0 ))) return FALSE;
834
835     if (header->system)
836     {
837         TRACE("Preserving system object %p\n", obj);
838         GDI_ReleaseObj( obj );
839         return TRUE;
840     }
841
842     while ((hdcs_head = header->hdcs) != NULL)
843     {
844         DC *dc = get_dc_ptr(hdcs_head->hdc);
845
846         header->hdcs = hdcs_head->next;
847         TRACE("hdc %p has interest in %p\n", hdcs_head->hdc, obj);
848
849         if(dc)
850         {
851             PHYSDEV physdev = GET_DC_PHYSDEV( dc, pDeleteObject );
852             GDI_ReleaseObj( obj );  /* release the GDI lock */
853             physdev->funcs->pDeleteObject( physdev, obj );
854             header = GDI_GetObjPtr( obj, 0 );  /* and grab it again */
855             release_dc_ptr( dc );
856         }
857         HeapFree(GetProcessHeap(), 0, hdcs_head);
858         if (!header) return FALSE;
859     }
860
861     if (header->selcount)
862     {
863         TRACE("delayed for %p because object in use, count %u\n", obj, header->selcount );
864         header->deleted = 1;  /* mark for delete */
865         GDI_ReleaseObj( obj );
866         return TRUE;
867     }
868
869     TRACE("%p\n", obj );
870
871       /* Delete object */
872
873     funcs = header->funcs;
874     GDI_ReleaseObj( obj );
875     if (funcs && funcs->pDeleteObject)
876         return funcs->pDeleteObject( obj );
877     else
878         return FALSE;
879 }
880
881 /***********************************************************************
882  *           GDI_hdc_using_object
883  *
884  * Call this if the dc requires DeleteObject notification
885  */
886 BOOL GDI_hdc_using_object(HGDIOBJ obj, HDC hdc)
887 {
888     GDIOBJHDR * header;
889     struct hdc_list **pphdc;
890
891     TRACE("obj %p hdc %p\n", obj, hdc);
892
893     if (!(header = GDI_GetObjPtr( obj, 0 ))) return FALSE;
894
895     if (header->system)
896     {
897         GDI_ReleaseObj(obj);
898         return FALSE;
899     }
900
901     for(pphdc = &header->hdcs; *pphdc; pphdc = &(*pphdc)->next)
902         if((*pphdc)->hdc == hdc)
903             break;
904
905     if(!*pphdc) {
906         *pphdc = HeapAlloc(GetProcessHeap(), 0, sizeof(**pphdc));
907         (*pphdc)->hdc = hdc;
908         (*pphdc)->next = NULL;
909     }
910
911     GDI_ReleaseObj(obj);
912     return TRUE;
913 }
914
915 /***********************************************************************
916  *           GDI_hdc_not_using_object
917  *
918  */
919 BOOL GDI_hdc_not_using_object(HGDIOBJ obj, HDC hdc)
920 {
921     GDIOBJHDR * header;
922     struct hdc_list *phdc, **prev;
923
924     TRACE("obj %p hdc %p\n", obj, hdc);
925
926     if (!(header = GDI_GetObjPtr( obj, 0 ))) return FALSE;
927
928     if (header->system)
929     {
930         GDI_ReleaseObj(obj);
931         return FALSE;
932     }
933
934     phdc = header->hdcs;
935     prev = &header->hdcs;
936
937     while(phdc) {
938         if(phdc->hdc == hdc) {
939             *prev = phdc->next;
940             HeapFree(GetProcessHeap(), 0, phdc);
941             phdc = *prev;
942         } else {
943             prev = &phdc->next;
944             phdc = phdc->next;
945         }
946     }
947
948     GDI_ReleaseObj(obj);
949     return TRUE;
950 }
951
952 /***********************************************************************
953  *           GetStockObject    (GDI32.@)
954  */
955 HGDIOBJ WINAPI GetStockObject( INT obj )
956 {
957     HGDIOBJ ret;
958     if ((obj < 0) || (obj >= NB_STOCK_OBJECTS)) return 0;
959     ret = stock_objects[obj];
960     TRACE("returning %p\n", ret );
961     return ret;
962 }
963
964
965 /***********************************************************************
966  *           GetObjectA    (GDI32.@)
967  */
968 INT WINAPI GetObjectA( HGDIOBJ handle, INT count, LPVOID buffer )
969 {
970     const struct gdi_obj_funcs *funcs;
971     GDIOBJHDR * ptr;
972     INT result = 0;
973
974     TRACE("%p %d %p\n", handle, count, buffer );
975
976     if (!(ptr = GDI_GetObjPtr( handle, 0 ))) return 0;
977     funcs = ptr->funcs;
978     GDI_ReleaseObj( handle );
979
980     if (funcs && funcs->pGetObjectA)
981     {
982         if (buffer && ((ULONG_PTR)buffer >> 16) == 0) /* catch apps getting argument order wrong */
983             SetLastError( ERROR_NOACCESS );
984         else
985             result = funcs->pGetObjectA( handle, count, buffer );
986     }
987     else
988         SetLastError( ERROR_INVALID_HANDLE );
989
990     return result;
991 }
992
993 /***********************************************************************
994  *           GetObjectW    (GDI32.@)
995  */
996 INT WINAPI GetObjectW( HGDIOBJ handle, INT count, LPVOID buffer )
997 {
998     const struct gdi_obj_funcs *funcs;
999     GDIOBJHDR * ptr;
1000     INT result = 0;
1001     TRACE("%p %d %p\n", handle, count, buffer );
1002
1003     if (!(ptr = GDI_GetObjPtr( handle, 0 ))) return 0;
1004     funcs = ptr->funcs;
1005     GDI_ReleaseObj( handle );
1006
1007     if (funcs && funcs->pGetObjectW)
1008     {
1009         if (buffer && ((ULONG_PTR)buffer >> 16) == 0) /* catch apps getting argument order wrong */
1010             SetLastError( ERROR_NOACCESS );
1011         else
1012             result = funcs->pGetObjectW( handle, count, buffer );
1013     }
1014     else
1015         SetLastError( ERROR_INVALID_HANDLE );
1016
1017     return result;
1018 }
1019
1020 /***********************************************************************
1021  *           GetObjectType    (GDI32.@)
1022  */
1023 DWORD WINAPI GetObjectType( HGDIOBJ handle )
1024 {
1025     GDIOBJHDR * ptr;
1026     DWORD result;
1027
1028     if (!(ptr = GDI_GetObjPtr( handle, 0 )))
1029     {
1030         SetLastError( ERROR_INVALID_HANDLE );
1031         return 0;
1032     }
1033     result = ptr->type;
1034     GDI_ReleaseObj( handle );
1035     TRACE("%p -> %u\n", handle, result );
1036     return result;
1037 }
1038
1039 /***********************************************************************
1040  *           GetCurrentObject           (GDI32.@)
1041  *
1042  * Get the currently selected object of a given type in a device context.
1043  *
1044  * PARAMS
1045  *  hdc  [I] Device context to get the current object from
1046  *  type [I] Type of current object to get (OBJ_* defines from "wingdi.h")
1047  *
1048  * RETURNS
1049  *  Success: The current object of the given type selected in hdc.
1050  *  Failure: A NULL handle.
1051  *
1052  * NOTES
1053  * - only the following object types are supported:
1054  *| OBJ_PEN
1055  *| OBJ_BRUSH
1056  *| OBJ_PAL
1057  *| OBJ_FONT
1058  *| OBJ_BITMAP
1059  */
1060 HGDIOBJ WINAPI GetCurrentObject(HDC hdc,UINT type)
1061 {
1062     HGDIOBJ ret = 0;
1063     DC * dc = get_dc_ptr( hdc );
1064
1065     if (!dc) return 0;
1066
1067     switch (type) {
1068         case OBJ_EXTPEN: /* fall through */
1069         case OBJ_PEN:    ret = dc->hPen; break;
1070         case OBJ_BRUSH:  ret = dc->hBrush; break;
1071         case OBJ_PAL:    ret = dc->hPalette; break;
1072         case OBJ_FONT:   ret = dc->hFont; break;
1073         case OBJ_BITMAP: ret = dc->hBitmap; break;
1074
1075         /* tests show that OBJ_REGION is explicitly ignored */
1076         case OBJ_REGION: break;
1077         default:
1078             /* the SDK only mentions those above */
1079             FIXME("(%p,%d): unknown type.\n",hdc,type);
1080             break;
1081     }
1082     release_dc_ptr( dc );
1083     return ret;
1084 }
1085
1086
1087 /***********************************************************************
1088  *           SelectObject    (GDI32.@)
1089  *
1090  * Select a Gdi object into a device context.
1091  *
1092  * PARAMS
1093  *  hdc  [I] Device context to associate the object with
1094  *  hObj [I] Gdi object to associate with hdc
1095  *
1096  * RETURNS
1097  *  Success: A non-NULL handle representing the previously selected object of
1098  *           the same type as hObj.
1099  *  Failure: A NULL object. If hdc is invalid, GetLastError() returns ERROR_INVALID_HANDLE.
1100  *           if hObj is not a valid object handle, no last error is set. In either
1101  *           case, hdc is unaffected by the call.
1102  */
1103 HGDIOBJ WINAPI SelectObject( HDC hdc, HGDIOBJ hObj )
1104 {
1105     HGDIOBJ ret = 0;
1106     GDIOBJHDR *header;
1107
1108     TRACE( "(%p,%p)\n", hdc, hObj );
1109
1110     header = GDI_GetObjPtr( hObj, 0 );
1111     if (header)
1112     {
1113         const struct gdi_obj_funcs *funcs = header->funcs;
1114         GDI_ReleaseObj( hObj );
1115         if (funcs && funcs->pSelectObject) ret = funcs->pSelectObject( hObj, hdc );
1116     }
1117     return ret;
1118 }
1119
1120
1121 /***********************************************************************
1122  *           UnrealizeObject    (GDI32.@)
1123  */
1124 BOOL WINAPI UnrealizeObject( HGDIOBJ obj )
1125 {
1126     BOOL result = FALSE;
1127     GDIOBJHDR * header = GDI_GetObjPtr( obj, 0 );
1128
1129     if (header)
1130     {
1131         const struct gdi_obj_funcs *funcs = header->funcs;
1132
1133         GDI_ReleaseObj( obj );
1134         if (funcs && funcs->pUnrealizeObject)
1135             result = header->funcs->pUnrealizeObject( obj );
1136         else
1137             result = TRUE;
1138     }
1139     return result;
1140 }
1141
1142
1143 /* Solid colors to enumerate */
1144 static const COLORREF solid_colors[] =
1145 { RGB(0x00,0x00,0x00), RGB(0xff,0xff,0xff),
1146 RGB(0xff,0x00,0x00), RGB(0x00,0xff,0x00),
1147 RGB(0x00,0x00,0xff), RGB(0xff,0xff,0x00),
1148 RGB(0xff,0x00,0xff), RGB(0x00,0xff,0xff),
1149 RGB(0x80,0x00,0x00), RGB(0x00,0x80,0x00),
1150 RGB(0x80,0x80,0x00), RGB(0x00,0x00,0x80),
1151 RGB(0x80,0x00,0x80), RGB(0x00,0x80,0x80),
1152 RGB(0x80,0x80,0x80), RGB(0xc0,0xc0,0xc0)
1153 };
1154
1155
1156 /***********************************************************************
1157  *           EnumObjects    (GDI32.@)
1158  */
1159 INT WINAPI EnumObjects( HDC hdc, INT nObjType,
1160                             GOBJENUMPROC lpEnumFunc, LPARAM lParam )
1161 {
1162     UINT i;
1163     INT retval = 0;
1164     LOGPEN pen;
1165     LOGBRUSH brush;
1166
1167     TRACE("%p %d %p %08lx\n", hdc, nObjType, lpEnumFunc, lParam );
1168     switch(nObjType)
1169     {
1170     case OBJ_PEN:
1171         /* Enumerate solid pens */
1172         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
1173         {
1174             pen.lopnStyle   = PS_SOLID;
1175             pen.lopnWidth.x = 1;
1176             pen.lopnWidth.y = 0;
1177             pen.lopnColor   = solid_colors[i];
1178             retval = lpEnumFunc( &pen, lParam );
1179             TRACE("solid pen %08x, ret=%d\n",
1180                          solid_colors[i], retval);
1181             if (!retval) break;
1182         }
1183         break;
1184
1185     case OBJ_BRUSH:
1186         /* Enumerate solid brushes */
1187         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
1188         {
1189             brush.lbStyle = BS_SOLID;
1190             brush.lbColor = solid_colors[i];
1191             brush.lbHatch = 0;
1192             retval = lpEnumFunc( &brush, lParam );
1193             TRACE("solid brush %08x, ret=%d\n",
1194                          solid_colors[i], retval);
1195             if (!retval) break;
1196         }
1197
1198         /* Now enumerate hatched brushes */
1199         if (retval) for (i = HS_HORIZONTAL; i <= HS_DIAGCROSS; i++)
1200         {
1201             brush.lbStyle = BS_HATCHED;
1202             brush.lbColor = RGB(0,0,0);
1203             brush.lbHatch = i;
1204             retval = lpEnumFunc( &brush, lParam );
1205             TRACE("hatched brush %d, ret=%d\n",
1206                          i, retval);
1207             if (!retval) break;
1208         }
1209         break;
1210
1211     default:
1212         /* FIXME: implement Win32 types */
1213         WARN("(%d): Invalid type\n", nObjType );
1214         break;
1215     }
1216     return retval;
1217 }
1218
1219
1220 /***********************************************************************
1221  *           SetObjectOwner    (GDI32.@)
1222  */
1223 void WINAPI SetObjectOwner( HGDIOBJ handle, HANDLE owner )
1224 {
1225     /* Nothing to do */
1226 }
1227
1228 /***********************************************************************
1229  *           GdiInitializeLanguagePack    (GDI32.@)
1230  */
1231 DWORD WINAPI GdiInitializeLanguagePack( DWORD arg )
1232 {
1233     FIXME("stub\n");
1234     return 0;
1235 }
1236
1237 /***********************************************************************
1238  *           GdiFlush    (GDI32.@)
1239  */
1240 BOOL WINAPI GdiFlush(void)
1241 {
1242     return TRUE;  /* FIXME */
1243 }
1244
1245
1246 /***********************************************************************
1247  *           GdiGetBatchLimit    (GDI32.@)
1248  */
1249 DWORD WINAPI GdiGetBatchLimit(void)
1250 {
1251     return 1;  /* FIXME */
1252 }
1253
1254
1255 /***********************************************************************
1256  *           GdiSetBatchLimit    (GDI32.@)
1257  */
1258 DWORD WINAPI GdiSetBatchLimit( DWORD limit )
1259 {
1260     return 1; /* FIXME */
1261 }
1262
1263
1264 /*******************************************************************
1265  *      GetColorAdjustment [GDI32.@]
1266  *
1267  *
1268  */
1269 BOOL WINAPI GetColorAdjustment(HDC hdc, LPCOLORADJUSTMENT lpca)
1270 {
1271         FIXME("stub\n");
1272         return 0;
1273 }
1274
1275 /*******************************************************************
1276  *      GdiComment [GDI32.@]
1277  *
1278  *
1279  */
1280 BOOL WINAPI GdiComment(HDC hdc, UINT cbSize, const BYTE *lpData)
1281 {
1282     DC *dc = get_dc_ptr(hdc);
1283     BOOL ret = FALSE;
1284
1285     if(dc)
1286     {
1287         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pGdiComment );
1288         ret = physdev->funcs->pGdiComment( physdev, cbSize, lpData );
1289         release_dc_ptr( dc );
1290     }
1291     return ret;
1292 }
1293
1294 /*******************************************************************
1295  *      SetColorAdjustment [GDI32.@]
1296  *
1297  *
1298  */
1299 BOOL WINAPI SetColorAdjustment(HDC hdc, const COLORADJUSTMENT* lpca)
1300 {
1301         FIXME("stub\n");
1302         return 0;
1303 }