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