xref: /reactos/dll/win32/oleaut32/olefont.c (revision 7eead935)
1 /*
2  * OLE Font encapsulation implementation
3  *
4  * This file contains an implementation of the IFont
5  * interface and the OleCreateFontIndirect API call.
6  *
7  * Copyright 1999 Francis Beaudet
8  * Copyright 2006 (Google) Benjamin Arai
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 #include <assert.h>
25 #include <stdarg.h>
26 #include <string.h>
27 
28 #define COBJMACROS
29 #define NONAMELESSUNION
30 #define NONAMELESSSTRUCT
31 
32 #include "winerror.h"
33 #include "windef.h"
34 #include "winbase.h"
35 #include "wingdi.h"
36 #include "winuser.h"
37 #include "wine/list.h"
38 #include "wine/unicode.h"
39 #include "objbase.h"
40 #include "oleauto.h"    /* for SysAllocString(....) */
41 #include "ole2.h"
42 #include "olectl.h"
43 #include "wine/debug.h"
44 #include "connpt.h" /* for CreateConnectionPoint */
45 #include "oaidl.h"
46 
47 WINE_DEFAULT_DEBUG_CHANNEL(ole);
48 
49 /***********************************************************************
50  * Declaration of constants used when serializing the font object.
51  */
52 #define FONTPERSIST_ITALIC        0x02
53 #define FONTPERSIST_UNDERLINE     0x04
54 #define FONTPERSIST_STRIKETHROUGH 0x08
55 
56 static HDC olefont_hdc;
57 
58 /***********************************************************************
59  * List of the HFONTs it has given out, with each one having a separate
60  * ref count.
61  */
62 typedef struct _HFONTItem
63 {
64   struct list entry;
65 
66   /* Reference count of any IFont objects that own this hfont */
67   LONG int_refs;
68 
69   /* Total reference count of any refs held by the application obtained by AddRefHfont plus any internal refs */
70   LONG total_refs;
71 
72   /* The font associated with this object. */
73   HFONT gdiFont;
74 
75 } HFONTItem, *PHFONTItem;
76 
77 static struct list OLEFontImpl_hFontList = LIST_INIT(OLEFontImpl_hFontList);
78 
79 /* Counts how many fonts contain at least one lock */
80 static LONG ifont_cnt = 0;
81 
82 /***********************************************************************
83  * Critical section for OLEFontImpl_hFontList
84  */
85 static CRITICAL_SECTION OLEFontImpl_csHFONTLIST;
86 static CRITICAL_SECTION_DEBUG OLEFontImpl_csHFONTLIST_debug =
87 {
88   0, 0, &OLEFontImpl_csHFONTLIST,
89   { &OLEFontImpl_csHFONTLIST_debug.ProcessLocksList,
90     &OLEFontImpl_csHFONTLIST_debug.ProcessLocksList },
91     0, 0, { (DWORD_PTR)(__FILE__ ": OLEFontImpl_csHFONTLIST") }
92 };
93 static CRITICAL_SECTION OLEFontImpl_csHFONTLIST = { &OLEFontImpl_csHFONTLIST_debug, -1, 0, 0, 0, 0 };
94 
95 static HDC get_dc(void)
96 {
97     HDC hdc;
98     EnterCriticalSection(&OLEFontImpl_csHFONTLIST);
99     if(!olefont_hdc)
100         olefont_hdc = CreateCompatibleDC(NULL);
101     hdc = olefont_hdc;
102     LeaveCriticalSection(&OLEFontImpl_csHFONTLIST);
103     return hdc;
104 }
105 
106 static void delete_dc(void)
107 {
108     EnterCriticalSection(&OLEFontImpl_csHFONTLIST);
109     if(olefont_hdc)
110     {
111         DeleteDC(olefont_hdc);
112         olefont_hdc = NULL;
113     }
114     LeaveCriticalSection(&OLEFontImpl_csHFONTLIST);
115 }
116 
117 static void HFONTItem_Delete(PHFONTItem item)
118 {
119   DeleteObject(item->gdiFont);
120   list_remove(&item->entry);
121   HeapFree(GetProcessHeap(), 0, item);
122 }
123 
124 /* Find hfont item entry in the list.  Should be called while holding the crit sect */
125 static HFONTItem *find_hfontitem(HFONT hfont)
126 {
127     HFONTItem *item;
128 
129     LIST_FOR_EACH_ENTRY(item, &OLEFontImpl_hFontList, HFONTItem, entry)
130     {
131         if (item->gdiFont == hfont)
132             return item;
133     }
134     return NULL;
135 }
136 
137 /* Add an item to the list with one internal reference */
138 static HRESULT add_hfontitem(HFONT hfont)
139 {
140     HFONTItem *new_item = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_item));
141 
142     if(!new_item) return E_OUTOFMEMORY;
143 
144     new_item->int_refs = 1;
145     new_item->total_refs = 1;
146     new_item->gdiFont = hfont;
147     EnterCriticalSection(&OLEFontImpl_csHFONTLIST);
148     list_add_tail(&OLEFontImpl_hFontList,&new_item->entry);
149     LeaveCriticalSection(&OLEFontImpl_csHFONTLIST);
150     return S_OK;
151 }
152 
153 static HRESULT inc_int_ref(HFONT hfont)
154 {
155     HFONTItem *item;
156     HRESULT hr = S_FALSE;
157 
158     EnterCriticalSection(&OLEFontImpl_csHFONTLIST);
159     item = find_hfontitem(hfont);
160 
161     if(item)
162     {
163         item->int_refs++;
164         item->total_refs++;
165         hr = S_OK;
166     }
167     LeaveCriticalSection(&OLEFontImpl_csHFONTLIST);
168 
169     return hr;
170 }
171 
172 /* decrements the internal ref of a hfont item.  If both refs are zero it'll
173    remove the item from the list and delete the hfont */
174 static HRESULT dec_int_ref(HFONT hfont)
175 {
176     HFONTItem *item;
177     HRESULT hr = S_FALSE;
178 
179     EnterCriticalSection(&OLEFontImpl_csHFONTLIST);
180     item = find_hfontitem(hfont);
181 
182     if(item)
183     {
184         item->int_refs--;
185         item->total_refs--;
186         if(item->int_refs == 0 && item->total_refs == 0)
187             HFONTItem_Delete(item);
188         hr = S_OK;
189     }
190     LeaveCriticalSection(&OLEFontImpl_csHFONTLIST);
191 
192     return hr;
193 }
194 
195 static HRESULT inc_ext_ref(HFONT hfont)
196 {
197     HFONTItem *item;
198     HRESULT hr = S_FALSE;
199 
200     EnterCriticalSection(&OLEFontImpl_csHFONTLIST);
201 
202     item = find_hfontitem(hfont);
203     if(item)
204     {
205         item->total_refs++;
206         hr = S_OK;
207     }
208     LeaveCriticalSection(&OLEFontImpl_csHFONTLIST);
209 
210     return hr;
211 }
212 
213 static HRESULT dec_ext_ref(HFONT hfont)
214 {
215     HFONTItem *item;
216     HRESULT hr = S_FALSE;
217 
218     EnterCriticalSection(&OLEFontImpl_csHFONTLIST);
219 
220     item = find_hfontitem(hfont);
221     if(item)
222     {
223         if(--item->total_refs >= 0) hr = S_OK;
224     }
225     LeaveCriticalSection(&OLEFontImpl_csHFONTLIST);
226 
227     return hr;
228 }
229 
230 static WCHAR *strdupW(const WCHAR* str)
231 {
232     WCHAR *ret;
233     DWORD size = (strlenW(str) + 1) * sizeof(WCHAR);
234 
235     ret = HeapAlloc(GetProcessHeap(), 0, size);
236     if(ret)
237         memcpy(ret, str, size);
238     return ret;
239 }
240 
241 /***********************************************************************
242  * Declaration of the implementation class for the IFont interface
243  */
244 typedef struct OLEFontImpl OLEFontImpl;
245 
246 struct OLEFontImpl
247 {
248   /*
249    * This class supports many interfaces. IUnknown, IFont,
250    * IDispatch, IDispFont IPersistStream and IConnectionPointContainer.
251    * The first two are supported by the first vtable, the next two are
252    * supported by the second table and the last two have their own.
253    */
254   IFont                       IFont_iface;
255   IDispatch                   IDispatch_iface;
256   IPersistStream              IPersistStream_iface;
257   IConnectionPointContainer   IConnectionPointContainer_iface;
258   IPersistPropertyBag         IPersistPropertyBag_iface;
259   IPersistStreamInit          IPersistStreamInit_iface;
260   /*
261    * Reference count for that instance of the class.
262    */
263   LONG ref;
264 
265   /*
266    * This structure contains the description of the class.
267    */
268   FONTDESC description;
269 
270   /*
271    * Contain the font associated with this object.
272    */
273   HFONT gdiFont;
274   BOOL dirty;
275   /*
276    * Size ratio
277    */
278   LONG cyLogical;
279   LONG cyHimetric;
280 
281   /*
282    * Stash realized height (pixels) from TEXTMETRIC - used in get_Size()
283    */
284   LONG nRealHeight;
285 
286   IConnectionPoint *pPropertyNotifyCP;
287   IConnectionPoint *pFontEventsCP;
288 };
289 
290 static inline OLEFontImpl *impl_from_IFont(IFont *iface)
291 {
292     return CONTAINING_RECORD(iface, OLEFontImpl, IFont_iface);
293 }
294 
295 static inline OLEFontImpl *impl_from_IDispatch( IDispatch *iface )
296 {
297     return CONTAINING_RECORD(iface, OLEFontImpl, IDispatch_iface);
298 }
299 
300 static inline OLEFontImpl *impl_from_IPersistStream( IPersistStream *iface )
301 {
302     return CONTAINING_RECORD(iface, OLEFontImpl, IPersistStream_iface);
303 }
304 
305 static inline OLEFontImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface )
306 {
307     return CONTAINING_RECORD(iface, OLEFontImpl, IConnectionPointContainer_iface);
308 }
309 
310 static inline OLEFontImpl *impl_from_IPersistPropertyBag( IPersistPropertyBag *iface )
311 {
312     return CONTAINING_RECORD(iface, OLEFontImpl, IPersistPropertyBag_iface);
313 }
314 
315 static inline OLEFontImpl *impl_from_IPersistStreamInit( IPersistStreamInit *iface )
316 {
317     return CONTAINING_RECORD(iface, OLEFontImpl, IPersistStreamInit_iface);
318 }
319 
320 
321 /***********************************************************************
322  * Prototypes for the implementation functions for the IFont
323  * interface
324  */
325 static OLEFontImpl* OLEFontImpl_Construct(const FONTDESC *fontDesc);
326 static void         OLEFontImpl_Destroy(OLEFontImpl* fontDesc);
327 static ULONG        WINAPI OLEFontImpl_AddRef(IFont* iface);
328 
329 /******************************************************************************
330  *		OleCreateFontIndirect	[OLEAUT32.420]
331  */
332 HRESULT WINAPI OleCreateFontIndirect(
333   LPFONTDESC lpFontDesc,
334   REFIID     riid,
335   LPVOID*     ppvObj)
336 {
337   OLEFontImpl* newFont;
338   HRESULT      hr;
339   FONTDESC     fd;
340 
341   TRACE("(%p, %s, %p)\n", lpFontDesc, debugstr_guid(riid), ppvObj);
342 
343   if (!ppvObj) return E_POINTER;
344 
345   *ppvObj = 0;
346 
347   if (!lpFontDesc) {
348     static WCHAR fname[] = { 'S','y','s','t','e','m',0 };
349 
350     fd.cbSizeofstruct = sizeof(fd);
351     fd.lpstrName      = fname;
352     fd.cySize.s.Lo    = 80000;
353     fd.cySize.s.Hi    = 0;
354     fd.sWeight 	      = 0;
355     fd.sCharset       = 0;
356     fd.fItalic        = FALSE;
357     fd.fUnderline     = FALSE;
358     fd.fStrikethrough = FALSE;
359     lpFontDesc = &fd;
360   }
361 
362   newFont = OLEFontImpl_Construct(lpFontDesc);
363   if (!newFont) return E_OUTOFMEMORY;
364 
365   hr = IFont_QueryInterface(&newFont->IFont_iface, riid, ppvObj);
366   IFont_Release(&newFont->IFont_iface);
367 
368   return hr;
369 }
370 
371 
372 /***********************************************************************
373  * Implementation of the OLEFontImpl class.
374  */
375 
376 /***********************************************************************
377  *    OLEFont_SendNotify (internal)
378  *
379  * Sends notification messages of changed properties to any interested
380  * connections.
381  */
382 static void OLEFont_SendNotify(OLEFontImpl* this, DISPID dispID)
383 {
384   static const WCHAR wszName[] = {'N','a','m','e',0};
385   static const WCHAR wszSize[] = {'S','i','z','e',0};
386   static const WCHAR wszBold[] = {'B','o','l','d',0};
387   static const WCHAR wszItalic[] = {'I','t','a','l','i','c',0};
388   static const WCHAR wszUnder[] = {'U','n','d','e','r','l','i','n','e',0};
389   static const WCHAR wszStrike[] = {'S','t','r','i','k','e','t','h','r','o','u','g','h',0};
390   static const WCHAR wszWeight[] = {'W','e','i','g','h','t',0};
391   static const WCHAR wszCharset[] = {'C','h','a','r','s','e','t',0};
392   static const LPCWSTR dispid_mapping[] =
393   {
394     wszName,
395     NULL,
396     wszSize,
397     wszBold,
398     wszItalic,
399     wszUnder,
400     wszStrike,
401     wszWeight,
402     wszCharset
403   };
404 
405   IEnumConnections *pEnum;
406   CONNECTDATA CD;
407   HRESULT hres;
408 
409   this->dirty = TRUE;
410 
411   hres = IConnectionPoint_EnumConnections(this->pPropertyNotifyCP, &pEnum);
412   if (SUCCEEDED(hres))
413   {
414     while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
415       IPropertyNotifySink *sink;
416 
417       IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (void**)&sink);
418       IPropertyNotifySink_OnChanged(sink, dispID);
419       IPropertyNotifySink_Release(sink);
420       IUnknown_Release(CD.pUnk);
421     }
422     IEnumConnections_Release(pEnum);
423   }
424 
425   hres = IConnectionPoint_EnumConnections(this->pFontEventsCP, &pEnum);
426   if (SUCCEEDED(hres))
427   {
428     DISPPARAMS dispparams;
429     VARIANTARG vararg;
430 
431     VariantInit(&vararg);
432     V_VT(&vararg) = VT_BSTR;
433     V_BSTR(&vararg) = SysAllocString(dispid_mapping[dispID]);
434 
435     dispparams.cArgs = 1;
436     dispparams.cNamedArgs = 0;
437     dispparams.rgdispidNamedArgs = NULL;
438     dispparams.rgvarg = &vararg;
439 
440     while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) {
441         IFontEventsDisp *disp;
442 
443         IUnknown_QueryInterface(CD.pUnk, &IID_IFontEventsDisp, (void**)&disp);
444         IFontEventsDisp_Invoke(disp, DISPID_FONT_CHANGED, &IID_NULL,
445                                LOCALE_NEUTRAL, INVOKE_FUNC, &dispparams, NULL,
446                                NULL, NULL);
447 
448         IFontEventsDisp_Release(disp);
449         IUnknown_Release(CD.pUnk);
450     }
451     VariantClear(&vararg);
452     IEnumConnections_Release(pEnum);
453   }
454 }
455 
456 /************************************************************************
457  * OLEFontImpl_QueryInterface (IUnknown)
458  *
459  * See Windows documentation for more details on IUnknown methods.
460  */
461 static HRESULT WINAPI OLEFontImpl_QueryInterface(
462   IFont*  iface,
463   REFIID  riid,
464   void**  ppvObject)
465 {
466   OLEFontImpl *this = impl_from_IFont(iface);
467 
468   TRACE("(%p)->(%s, %p)\n", this, debugstr_guid(riid), ppvObject);
469 
470   *ppvObject = 0;
471 
472   if (IsEqualGUID(&IID_IUnknown, riid) ||
473       IsEqualGUID(&IID_IFont, riid))
474   {
475     *ppvObject = this;
476   }
477   else if (IsEqualGUID(&IID_IDispatch, riid) ||
478            IsEqualGUID(&IID_IFontDisp, riid))
479   {
480     *ppvObject = &this->IDispatch_iface;
481   }
482   else if (IsEqualGUID(&IID_IPersist, riid) ||
483            IsEqualGUID(&IID_IPersistStream, riid))
484   {
485     *ppvObject = &this->IPersistStream_iface;
486   }
487   else if (IsEqualGUID(&IID_IConnectionPointContainer, riid))
488   {
489     *ppvObject = &this->IConnectionPointContainer_iface;
490   }
491   else if (IsEqualGUID(&IID_IPersistPropertyBag, riid))
492   {
493     *ppvObject = &this->IPersistPropertyBag_iface;
494   }
495   else if (IsEqualGUID(&IID_IPersistStreamInit, riid))
496   {
497     *ppvObject = &this->IPersistStreamInit_iface;
498   }
499 
500   if (!*ppvObject)
501   {
502     FIXME("() : asking for unsupported interface %s\n", debugstr_guid(riid));
503     return E_NOINTERFACE;
504   }
505 
506   IFont_AddRef(iface);
507 
508   return S_OK;
509 }
510 
511 /************************************************************************
512  * OLEFontImpl_AddRef (IUnknown)
513  */
514 static ULONG WINAPI OLEFontImpl_AddRef(
515   IFont* iface)
516 {
517   OLEFontImpl *this = impl_from_IFont(iface);
518   TRACE("(%p)->(ref=%d)\n", this, this->ref);
519   return InterlockedIncrement(&this->ref);
520 }
521 
522 /************************************************************************
523  * OLEFontImpl_Release (IUnknown)
524  */
525 static ULONG WINAPI OLEFontImpl_Release(IFont* iface)
526 {
527   OLEFontImpl *this = impl_from_IFont(iface);
528   ULONG ref;
529 
530   TRACE("(%p)->(ref=%d)\n", this, this->ref);
531 
532   ref = InterlockedDecrement(&this->ref);
533 
534   if (ref == 0)
535   {
536     ULONG fontlist_refs = InterlockedDecrement(&ifont_cnt);
537 
538     /* Final IFont object so destroy font cache */
539     if (fontlist_refs == 0)
540     {
541       HFONTItem *item, *cursor2;
542 
543       EnterCriticalSection(&OLEFontImpl_csHFONTLIST);
544       LIST_FOR_EACH_ENTRY_SAFE(item, cursor2, &OLEFontImpl_hFontList, HFONTItem, entry)
545         HFONTItem_Delete(item);
546       LeaveCriticalSection(&OLEFontImpl_csHFONTLIST);
547       delete_dc();
548     }
549     else
550     {
551       dec_int_ref(this->gdiFont);
552     }
553     OLEFontImpl_Destroy(this);
554   }
555 
556   return ref;
557 }
558 
559 typedef struct
560 {
561     short orig_cs;
562     short avail_cs;
563 } enum_data;
564 
565 static int CALLBACK font_enum_proc(const LOGFONTW *elf, const TEXTMETRICW *ntm, DWORD type, LPARAM lp)
566 {
567     enum_data *data = (enum_data*)lp;
568 
569     if(elf->lfCharSet == data->orig_cs)
570     {
571         data->avail_cs = data->orig_cs;
572         return 0;
573     }
574     if(data->avail_cs == -1) data->avail_cs = elf->lfCharSet;
575     return 1;
576 }
577 
578 static void realize_font(OLEFontImpl *This)
579 {
580     LOGFONTW logFont;
581     INT fontHeight;
582     WCHAR text_face[LF_FACESIZE];
583     HDC hdc = get_dc();
584     HFONT old_font;
585     TEXTMETRICW tm;
586 
587     if (!This->dirty) return;
588 
589     text_face[0] = 0;
590 
591     if(This->gdiFont)
592     {
593         old_font = SelectObject(hdc, This->gdiFont);
594         GetTextFaceW(hdc, ARRAY_SIZE(text_face), text_face);
595         SelectObject(hdc, old_font);
596         dec_int_ref(This->gdiFont);
597         This->gdiFont = 0;
598     }
599 
600     memset(&logFont, 0, sizeof(LOGFONTW));
601 
602     lstrcpynW(logFont.lfFaceName, This->description.lpstrName, LF_FACESIZE);
603     logFont.lfCharSet = This->description.sCharset;
604 
605     /* If the font name has been changed then enumerate all charsets
606        and pick one that'll result in the font specified being selected */
607     if(text_face[0] && lstrcmpiW(text_face, This->description.lpstrName))
608     {
609         enum_data data;
610         data.orig_cs = This->description.sCharset;
611         data.avail_cs = -1;
612         logFont.lfCharSet = DEFAULT_CHARSET;
613         EnumFontFamiliesExW(get_dc(), &logFont, font_enum_proc, (LPARAM)&data, 0);
614         if(data.avail_cs != -1) logFont.lfCharSet = data.avail_cs;
615     }
616 
617     /*
618      * The height of the font returned by the get_Size property is the
619      * height of the font in points multiplied by 10000... Using some
620      * simple conversions and the ratio given by the application, it can
621      * be converted to a height in pixels.
622      *
623      * Standard ratio is 72 / 2540, or 18 / 635 in lowest terms.
624      * Ratio is applied here relative to the standard.
625      */
626 
627     fontHeight = MulDiv( This->description.cySize.s.Lo, This->cyLogical*635, This->cyHimetric*18 );
628 
629     logFont.lfHeight          = ((fontHeight%10000L)>5000L) ? (-fontHeight/10000L) - 1 :
630                                                                   (-fontHeight/10000L);
631     logFont.lfItalic          = This->description.fItalic;
632     logFont.lfUnderline       = This->description.fUnderline;
633     logFont.lfStrikeOut       = This->description.fStrikethrough;
634     logFont.lfWeight          = This->description.sWeight;
635     logFont.lfOutPrecision    = OUT_CHARACTER_PRECIS;
636     logFont.lfClipPrecision   = CLIP_DEFAULT_PRECIS;
637     logFont.lfQuality         = DEFAULT_QUALITY;
638     logFont.lfPitchAndFamily  = DEFAULT_PITCH;
639 
640     This->gdiFont = CreateFontIndirectW(&logFont);
641     This->dirty = FALSE;
642 
643     add_hfontitem(This->gdiFont);
644 
645     /* Fixup the name and charset properties so that they match the
646        selected font */
647     old_font = SelectObject(get_dc(), This->gdiFont);
648     GetTextFaceW(hdc, ARRAY_SIZE(text_face), text_face);
649     if(lstrcmpiW(text_face, This->description.lpstrName))
650     {
651         HeapFree(GetProcessHeap(), 0, This->description.lpstrName);
652         This->description.lpstrName = strdupW(text_face);
653     }
654     GetTextMetricsW(hdc, &tm);
655     This->description.sCharset = tm.tmCharSet;
656     /* While we have it handy, stash the realized font height for use by get_Size() */
657     This->nRealHeight = tm.tmHeight - tm.tmInternalLeading; /* corresponds to LOGFONT lfHeight */
658     SelectObject(hdc, old_font);
659 }
660 
661 /************************************************************************
662  * OLEFontImpl_get_Name (IFont)
663  *
664  * See Windows documentation for more details on IFont methods.
665  */
666 static HRESULT WINAPI OLEFontImpl_get_Name(
667   IFont*  iface,
668   BSTR* pname)
669 {
670   OLEFontImpl *this = impl_from_IFont(iface);
671   TRACE("(%p)->(%p)\n", this, pname);
672 
673   if (pname==0)
674     return E_POINTER;
675 
676   realize_font(this);
677 
678   if (this->description.lpstrName!=0)
679     *pname = SysAllocString(this->description.lpstrName);
680   else
681     *pname = 0;
682 
683   return S_OK;
684 }
685 
686 /************************************************************************
687  * OLEFontImpl_put_Name (IFont)
688  */
689 static HRESULT WINAPI OLEFontImpl_put_Name(
690   IFont* iface,
691   BSTR name)
692 {
693   OLEFontImpl *This = impl_from_IFont(iface);
694   TRACE("(%p)->(%p)\n", This, name);
695 
696   if (!name)
697     return CTL_E_INVALIDPROPERTYVALUE;
698 
699   HeapFree(GetProcessHeap(), 0, This->description.lpstrName);
700   This->description.lpstrName = strdupW(name);
701   if (!This->description.lpstrName) return E_OUTOFMEMORY;
702 
703   TRACE("new name %s\n", debugstr_w(This->description.lpstrName));
704   OLEFont_SendNotify(This, DISPID_FONT_NAME);
705   return S_OK;
706 }
707 
708 /************************************************************************
709  * OLEFontImpl_get_Size (IFont)
710  */
711 static HRESULT WINAPI OLEFontImpl_get_Size(
712   IFont* iface,
713   CY*    psize)
714 {
715   OLEFontImpl *this = impl_from_IFont(iface);
716   TRACE("(%p)->(%p)\n", this, psize);
717 
718   if (!psize) return E_POINTER;
719 
720   realize_font(this);
721 
722   /*
723    * Convert realized font height in pixels to points descaled by current
724    * scaling ratio then scaled up by 10000.
725    */
726   psize->s.Lo = MulDiv(this->nRealHeight,
727                        this->cyHimetric * 72 * 10000,
728                        this->cyLogical * 2540);
729   psize->s.Hi = 0;
730 
731   return S_OK;
732 }
733 
734 /************************************************************************
735  * OLEFontImpl_put_Size (IFont)
736  */
737 static HRESULT WINAPI OLEFontImpl_put_Size(
738   IFont* iface,
739   CY     size)
740 {
741   OLEFontImpl *this = impl_from_IFont(iface);
742   TRACE("(%p)->(%d)\n", this, size.s.Lo);
743   this->description.cySize.s.Hi = 0;
744   this->description.cySize.s.Lo = size.s.Lo;
745   OLEFont_SendNotify(this, DISPID_FONT_SIZE);
746 
747   return S_OK;
748 }
749 
750 /************************************************************************
751  * OLEFontImpl_get_Bold (IFont)
752  *
753  * See Windows documentation for more details on IFont methods.
754  */
755 static HRESULT WINAPI OLEFontImpl_get_Bold(
756   IFont*  iface,
757   BOOL* pbold)
758 {
759   OLEFontImpl *this = impl_from_IFont(iface);
760   TRACE("(%p)->(%p)\n", this, pbold);
761 
762   if (!pbold) return E_POINTER;
763 
764   realize_font(this);
765 
766   *pbold = this->description.sWeight > 550;
767 
768   return S_OK;
769 }
770 
771 /************************************************************************
772  * OLEFontImpl_put_Bold (IFont)
773  */
774 static HRESULT WINAPI OLEFontImpl_put_Bold(
775   IFont* iface,
776   BOOL bold)
777 {
778   OLEFontImpl *this = impl_from_IFont(iface);
779   TRACE("(%p)->(%d)\n", this, bold);
780   this->description.sWeight = bold ? FW_BOLD : FW_NORMAL;
781   OLEFont_SendNotify(this, DISPID_FONT_BOLD);
782 
783   return S_OK;
784 }
785 
786 /************************************************************************
787  * OLEFontImpl_get_Italic (IFont)
788  */
789 static HRESULT WINAPI OLEFontImpl_get_Italic(
790   IFont*  iface,
791   BOOL* pitalic)
792 {
793   OLEFontImpl *this = impl_from_IFont(iface);
794   TRACE("(%p)->(%p)\n", this, pitalic);
795 
796   if (pitalic==0)
797     return E_POINTER;
798 
799   realize_font(this);
800 
801   *pitalic = this->description.fItalic;
802 
803   return S_OK;
804 }
805 
806 /************************************************************************
807  * OLEFontImpl_put_Italic (IFont)
808  */
809 static HRESULT WINAPI OLEFontImpl_put_Italic(
810   IFont* iface,
811   BOOL italic)
812 {
813   OLEFontImpl *this = impl_from_IFont(iface);
814   TRACE("(%p)->(%d)\n", this, italic);
815 
816   this->description.fItalic = italic;
817 
818   OLEFont_SendNotify(this, DISPID_FONT_ITALIC);
819   return S_OK;
820 }
821 
822 /************************************************************************
823  * OLEFontImpl_get_Underline (IFont)
824  */
825 static HRESULT WINAPI OLEFontImpl_get_Underline(
826   IFont*  iface,
827   BOOL* punderline)
828 {
829   OLEFontImpl *this = impl_from_IFont(iface);
830   TRACE("(%p)->(%p)\n", this, punderline);
831 
832   if (punderline==0)
833     return E_POINTER;
834 
835   realize_font(this);
836 
837   *punderline = this->description.fUnderline;
838 
839   return S_OK;
840 }
841 
842 /************************************************************************
843  * OLEFontImpl_put_Underline (IFont)
844  */
845 static HRESULT WINAPI OLEFontImpl_put_Underline(
846   IFont* iface,
847   BOOL underline)
848 {
849   OLEFontImpl *this = impl_from_IFont(iface);
850   TRACE("(%p)->(%d)\n", this, underline);
851 
852   this->description.fUnderline = underline;
853 
854   OLEFont_SendNotify(this, DISPID_FONT_UNDER);
855   return S_OK;
856 }
857 
858 /************************************************************************
859  * OLEFontImpl_get_Strikethrough (IFont)
860  */
861 static HRESULT WINAPI OLEFontImpl_get_Strikethrough(
862   IFont*  iface,
863   BOOL* pstrikethrough)
864 {
865   OLEFontImpl *this = impl_from_IFont(iface);
866   TRACE("(%p)->(%p)\n", this, pstrikethrough);
867 
868   if (pstrikethrough==0)
869     return E_POINTER;
870 
871   realize_font(this);
872 
873   *pstrikethrough = this->description.fStrikethrough;
874 
875   return S_OK;
876 }
877 
878 /************************************************************************
879  * OLEFontImpl_put_Strikethrough (IFont)
880  */
881 static HRESULT WINAPI OLEFontImpl_put_Strikethrough(
882  IFont* iface,
883  BOOL strikethrough)
884 {
885   OLEFontImpl *this = impl_from_IFont(iface);
886   TRACE("(%p)->(%d)\n", this, strikethrough);
887 
888   this->description.fStrikethrough = strikethrough;
889   OLEFont_SendNotify(this, DISPID_FONT_STRIKE);
890 
891   return S_OK;
892 }
893 
894 /************************************************************************
895  * OLEFontImpl_get_Weight (IFont)
896  */
897 static HRESULT WINAPI OLEFontImpl_get_Weight(
898   IFont* iface,
899   short* pweight)
900 {
901   OLEFontImpl *this = impl_from_IFont(iface);
902   TRACE("(%p)->(%p)\n", this, pweight);
903 
904   if (pweight==0)
905     return E_POINTER;
906 
907   realize_font(this);
908 
909   *pweight = this->description.sWeight;
910 
911   return S_OK;
912 }
913 
914 /************************************************************************
915  * OLEFontImpl_put_Weight (IFont)
916  */
917 static HRESULT WINAPI OLEFontImpl_put_Weight(
918   IFont* iface,
919   short  weight)
920 {
921   OLEFontImpl *this = impl_from_IFont(iface);
922   TRACE("(%p)->(%d)\n", this, weight);
923 
924   this->description.sWeight = weight;
925 
926   OLEFont_SendNotify(this, DISPID_FONT_WEIGHT);
927   return S_OK;
928 }
929 
930 /************************************************************************
931  * OLEFontImpl_get_Charset (IFont)
932  */
933 static HRESULT WINAPI OLEFontImpl_get_Charset(
934   IFont* iface,
935   short* pcharset)
936 {
937   OLEFontImpl *this = impl_from_IFont(iface);
938   TRACE("(%p)->(%p)\n", this, pcharset);
939 
940   if (pcharset==0)
941     return E_POINTER;
942 
943   realize_font(this);
944 
945   *pcharset = this->description.sCharset;
946 
947   return S_OK;
948 }
949 
950 /************************************************************************
951  * OLEFontImpl_put_Charset (IFont)
952  */
953 static HRESULT WINAPI OLEFontImpl_put_Charset(
954   IFont* iface,
955   short charset)
956 {
957   OLEFontImpl *this = impl_from_IFont(iface);
958   TRACE("(%p)->(%d)\n", this, charset);
959 
960   this->description.sCharset = charset;
961   OLEFont_SendNotify(this, DISPID_FONT_CHARSET);
962 
963   return S_OK;
964 }
965 
966 /************************************************************************
967  * OLEFontImpl_get_hFont (IFont)
968  */
969 static HRESULT WINAPI OLEFontImpl_get_hFont(
970   IFont*   iface,
971   HFONT* phfont)
972 {
973   OLEFontImpl *this = impl_from_IFont(iface);
974   TRACE("(%p)->(%p)\n", this, phfont);
975   if (phfont==NULL)
976     return E_POINTER;
977 
978   realize_font(this);
979 
980   *phfont = this->gdiFont;
981   TRACE("Returning %p\n", *phfont);
982   return S_OK;
983 }
984 
985 /************************************************************************
986  * OLEFontImpl_Clone (IFont)
987  */
988 static HRESULT WINAPI OLEFontImpl_Clone(
989   IFont*  iface,
990   IFont** ppfont)
991 {
992   OLEFontImpl *this = impl_from_IFont(iface);
993   OLEFontImpl* newObject;
994 
995   TRACE("(%p)->(%p)\n", this, ppfont);
996 
997   if (ppfont == NULL)
998     return E_POINTER;
999 
1000   *ppfont = NULL;
1001 
1002   newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(OLEFontImpl));
1003   if (newObject==NULL)
1004     return E_OUTOFMEMORY;
1005 
1006   *newObject = *this;
1007   /* allocate separate buffer */
1008   newObject->description.lpstrName = strdupW(this->description.lpstrName);
1009 
1010   /* Increment internal ref in hfont item list */
1011   if(newObject->gdiFont) inc_int_ref(newObject->gdiFont);
1012 
1013   InterlockedIncrement(&ifont_cnt);
1014 
1015   newObject->pPropertyNotifyCP = NULL;
1016   newObject->pFontEventsCP = NULL;
1017   CreateConnectionPoint((IUnknown*)&newObject->IFont_iface, &IID_IPropertyNotifySink,
1018                          &newObject->pPropertyNotifyCP);
1019   CreateConnectionPoint((IUnknown*)&newObject->IFont_iface, &IID_IFontEventsDisp,
1020                          &newObject->pFontEventsCP);
1021 
1022   if (!newObject->pPropertyNotifyCP || !newObject->pFontEventsCP)
1023   {
1024     OLEFontImpl_Destroy(newObject);
1025     return E_OUTOFMEMORY;
1026   }
1027 
1028   /* The cloned object starts with a reference count of 1 */
1029   newObject->ref = 1;
1030 
1031   *ppfont = &newObject->IFont_iface;
1032 
1033   return S_OK;
1034 }
1035 
1036 /************************************************************************
1037  * OLEFontImpl_IsEqual (IFont)
1038  */
1039 static HRESULT WINAPI OLEFontImpl_IsEqual(
1040   IFont* iface,
1041   IFont* pFontOther)
1042 {
1043   OLEFontImpl *left = impl_from_IFont(iface);
1044   OLEFontImpl *right = impl_from_IFont(pFontOther);
1045   INT ret;
1046   INT left_len,right_len;
1047 
1048   if(pFontOther == NULL)
1049     return E_POINTER;
1050   else if (left->description.cySize.s.Lo != right->description.cySize.s.Lo)
1051     return S_FALSE;
1052   else if (left->description.cySize.s.Hi != right->description.cySize.s.Hi)
1053     return S_FALSE;
1054   else if (left->description.sWeight != right->description.sWeight)
1055     return S_FALSE;
1056   else if (left->description.sCharset != right->description.sCharset)
1057     return S_FALSE;
1058   else if (left->description.fItalic != right->description.fItalic)
1059     return S_FALSE;
1060   else if (left->description.fUnderline != right->description.fUnderline)
1061     return S_FALSE;
1062   else if (left->description.fStrikethrough != right->description.fStrikethrough)
1063     return S_FALSE;
1064 
1065   /* Check from string */
1066   left_len = strlenW(left->description.lpstrName);
1067   right_len = strlenW(right->description.lpstrName);
1068   ret = CompareStringW(0,0,left->description.lpstrName, left_len,
1069     right->description.lpstrName, right_len);
1070   if (ret != CSTR_EQUAL)
1071     return S_FALSE;
1072 
1073   return S_OK;
1074 }
1075 
1076 /************************************************************************
1077  * OLEFontImpl_SetRatio (IFont)
1078  */
1079 static HRESULT WINAPI OLEFontImpl_SetRatio(
1080   IFont* iface,
1081   LONG   cyLogical,
1082   LONG   cyHimetric)
1083 {
1084   OLEFontImpl *this = impl_from_IFont(iface);
1085   TRACE("(%p)->(%d, %d)\n", this, cyLogical, cyHimetric);
1086 
1087   if(cyLogical == 0 || cyHimetric == 0)
1088     return E_FAIL;
1089 
1090   /* cyLogical and cyHimetric both set to 1 is a special case that
1091      does not change the scaling but also does not fail */
1092   if(cyLogical == 1 && cyHimetric == 1)
1093     return S_OK;
1094 
1095   this->cyLogical  = cyLogical;
1096   this->cyHimetric = cyHimetric;
1097   this->dirty = TRUE;
1098 
1099   return S_OK;
1100 }
1101 
1102 /************************************************************************
1103  * OLEFontImpl_QueryTextMetrics (IFont)
1104  */
1105 static HRESULT      WINAPI OLEFontImpl_QueryTextMetrics(
1106   IFont*         iface,
1107   TEXTMETRICOLE* ptm)
1108 {
1109   HDC hdcRef;
1110   HFONT hOldFont, hNewFont;
1111 
1112   hdcRef = GetDC(0);
1113   IFont_get_hFont(iface, &hNewFont);
1114   hOldFont = SelectObject(hdcRef, hNewFont);
1115   GetTextMetricsW(hdcRef, ptm);
1116   SelectObject(hdcRef, hOldFont);
1117   ReleaseDC(0, hdcRef);
1118   return S_OK;
1119 }
1120 
1121 /************************************************************************
1122  * OLEFontImpl_AddRefHfont (IFont)
1123  */
1124 static HRESULT WINAPI OLEFontImpl_AddRefHfont(
1125   IFont*  iface,
1126   HFONT hfont)
1127 {
1128     OLEFontImpl *this = impl_from_IFont(iface);
1129 
1130     TRACE("(%p)->(%p)\n", this, hfont);
1131 
1132     if (!hfont) return E_INVALIDARG;
1133 
1134     return inc_ext_ref(hfont);
1135 }
1136 
1137 /************************************************************************
1138  * OLEFontImpl_ReleaseHfont (IFont)
1139  */
1140 static HRESULT WINAPI OLEFontImpl_ReleaseHfont(
1141   IFont*  iface,
1142   HFONT hfont)
1143 {
1144     OLEFontImpl *this = impl_from_IFont(iface);
1145 
1146     TRACE("(%p)->(%p)\n", this, hfont);
1147 
1148     if (!hfont) return E_INVALIDARG;
1149 
1150     return dec_ext_ref(hfont);
1151 }
1152 
1153 /************************************************************************
1154  * OLEFontImpl_SetHdc (IFont)
1155  */
1156 static HRESULT WINAPI OLEFontImpl_SetHdc(
1157   IFont* iface,
1158   HDC  hdc)
1159 {
1160   OLEFontImpl *this = impl_from_IFont(iface);
1161   FIXME("(%p)->(%p): Stub\n", this, hdc);
1162   return E_NOTIMPL;
1163 }
1164 
1165 static const IFontVtbl OLEFontImpl_VTable =
1166 {
1167   OLEFontImpl_QueryInterface,
1168   OLEFontImpl_AddRef,
1169   OLEFontImpl_Release,
1170   OLEFontImpl_get_Name,
1171   OLEFontImpl_put_Name,
1172   OLEFontImpl_get_Size,
1173   OLEFontImpl_put_Size,
1174   OLEFontImpl_get_Bold,
1175   OLEFontImpl_put_Bold,
1176   OLEFontImpl_get_Italic,
1177   OLEFontImpl_put_Italic,
1178   OLEFontImpl_get_Underline,
1179   OLEFontImpl_put_Underline,
1180   OLEFontImpl_get_Strikethrough,
1181   OLEFontImpl_put_Strikethrough,
1182   OLEFontImpl_get_Weight,
1183   OLEFontImpl_put_Weight,
1184   OLEFontImpl_get_Charset,
1185   OLEFontImpl_put_Charset,
1186   OLEFontImpl_get_hFont,
1187   OLEFontImpl_Clone,
1188   OLEFontImpl_IsEqual,
1189   OLEFontImpl_SetRatio,
1190   OLEFontImpl_QueryTextMetrics,
1191   OLEFontImpl_AddRefHfont,
1192   OLEFontImpl_ReleaseHfont,
1193   OLEFontImpl_SetHdc
1194 };
1195 
1196 /************************************************************************
1197  * OLEFontImpl_IDispatch_QueryInterface (IUnknown)
1198  */
1199 static HRESULT WINAPI OLEFontImpl_IDispatch_QueryInterface(
1200   IDispatch* iface,
1201   REFIID     riid,
1202   VOID**     ppvoid)
1203 {
1204   OLEFontImpl *this = impl_from_IDispatch(iface);
1205   return IFont_QueryInterface(&this->IFont_iface, riid, ppvoid);
1206 }
1207 
1208 /************************************************************************
1209  * OLEFontImpl_IDispatch_Release (IUnknown)
1210  */
1211 static ULONG WINAPI OLEFontImpl_IDispatch_Release(
1212   IDispatch* iface)
1213 {
1214   OLEFontImpl *this = impl_from_IDispatch(iface);
1215   return IFont_Release(&this->IFont_iface);
1216 }
1217 
1218 /************************************************************************
1219  * OLEFontImpl_IDispatch_AddRef (IUnknown)
1220  */
1221 static ULONG WINAPI OLEFontImpl_IDispatch_AddRef(
1222   IDispatch* iface)
1223 {
1224   OLEFontImpl *this = impl_from_IDispatch(iface);
1225   return IFont_AddRef(&this->IFont_iface);
1226 }
1227 
1228 /************************************************************************
1229  * OLEFontImpl_GetTypeInfoCount (IDispatch)
1230  */
1231 static HRESULT WINAPI OLEFontImpl_GetTypeInfoCount(
1232   IDispatch*    iface,
1233   unsigned int* pctinfo)
1234 {
1235   OLEFontImpl *this = impl_from_IDispatch(iface);
1236   TRACE("(%p)->(%p)\n", this, pctinfo);
1237   *pctinfo = 1;
1238 
1239   return S_OK;
1240 }
1241 
1242 /************************************************************************
1243  * OLEFontImpl_GetTypeInfo (IDispatch)
1244  */
1245 static HRESULT WINAPI OLEFontImpl_GetTypeInfo(
1246   IDispatch*  iface,
1247   UINT      iTInfo,
1248   LCID        lcid,
1249   ITypeInfo** ppTInfo)
1250 {
1251   static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0};
1252   ITypeLib *tl;
1253   HRESULT hres;
1254 
1255   OLEFontImpl *this = impl_from_IDispatch(iface);
1256   TRACE("(%p, iTInfo=%d, lcid=%04x, %p)\n", this, iTInfo, (int)lcid, ppTInfo);
1257   if (iTInfo != 0)
1258     return E_FAIL;
1259   hres = LoadTypeLib(stdole2tlb, &tl);
1260   if (FAILED(hres)) {
1261     ERR("Could not load the stdole2.tlb?\n");
1262     return hres;
1263   }
1264   hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IFontDisp, ppTInfo);
1265   ITypeLib_Release(tl);
1266   if (FAILED(hres)) {
1267     FIXME("Did not IDispatch typeinfo from typelib, hres %x\n",hres);
1268   }
1269   return hres;
1270 }
1271 
1272 /************************************************************************
1273  * OLEFontImpl_GetIDsOfNames (IDispatch)
1274  */
1275 static HRESULT WINAPI OLEFontImpl_GetIDsOfNames(
1276   IDispatch*  iface,
1277   REFIID      riid,
1278   LPOLESTR* rgszNames,
1279   UINT      cNames,
1280   LCID        lcid,
1281   DISPID*     rgDispId)
1282 {
1283   ITypeInfo * pTInfo;
1284   HRESULT hres;
1285 
1286   OLEFontImpl *this = impl_from_IDispatch(iface);
1287 
1288   TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", this, debugstr_guid(riid),
1289         rgszNames, cNames, (int)lcid, rgDispId);
1290 
1291   if (cNames == 0) return E_INVALIDARG;
1292 
1293   hres = IDispatch_GetTypeInfo(iface, 0, lcid, &pTInfo);
1294   if (FAILED(hres))
1295   {
1296     ERR("GetTypeInfo failed.\n");
1297     return hres;
1298   }
1299 
1300   /* convert names to DISPIDs */
1301   hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId);
1302   ITypeInfo_Release(pTInfo);
1303 
1304   return hres;
1305 }
1306 
1307 /************************************************************************
1308  * OLEFontImpl_Invoke (IDispatch)
1309  *
1310  */
1311 static HRESULT WINAPI OLEFontImpl_Invoke(
1312   IDispatch*  iface,
1313   DISPID      dispIdMember,
1314   REFIID      riid,
1315   LCID        lcid,
1316   WORD        wFlags,
1317   DISPPARAMS* pDispParams,
1318   VARIANT*    pVarResult,
1319   EXCEPINFO*  pExepInfo,
1320   UINT*     puArgErr)
1321 {
1322   OLEFontImpl *this = impl_from_IDispatch(iface);
1323   HRESULT hr;
1324 
1325   TRACE("%p->(%d,%s,0x%x,0x%x,%p,%p,%p,%p)\n", this, dispIdMember,
1326     debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExepInfo,
1327     puArgErr);
1328 
1329   /* validate parameters */
1330 
1331   if (!IsEqualIID(riid, &IID_NULL))
1332   {
1333     ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid));
1334     return DISP_E_UNKNOWNINTERFACE;
1335   }
1336 
1337   if (wFlags & DISPATCH_PROPERTYGET)
1338   {
1339     if (!pVarResult)
1340     {
1341       ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n");
1342       return DISP_E_PARAMNOTOPTIONAL;
1343     }
1344   }
1345   else if (wFlags & DISPATCH_PROPERTYPUT)
1346   {
1347     if (!pDispParams)
1348     {
1349       ERR("null pDispParams not allowed when DISPATCH_PROPERTYPUT specified\n");
1350       return DISP_E_PARAMNOTOPTIONAL;
1351     }
1352     if (pDispParams->cArgs != 1)
1353     {
1354       ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs);
1355       return DISP_E_BADPARAMCOUNT;
1356     }
1357   }
1358   else
1359   {
1360     ERR("one of DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT must be specified\n");
1361     return DISP_E_MEMBERNOTFOUND;
1362   }
1363 
1364   switch (dispIdMember) {
1365   case DISPID_FONT_NAME:
1366     if (wFlags & DISPATCH_PROPERTYGET) {
1367       V_VT(pVarResult) = VT_BSTR;
1368       return IFont_get_Name(&this->IFont_iface, &V_BSTR(pVarResult));
1369     } else {
1370       VARIANTARG vararg;
1371 
1372       VariantInit(&vararg);
1373       hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_BSTR);
1374       if (FAILED(hr))
1375         return hr;
1376 
1377       hr = IFont_put_Name(&this->IFont_iface, V_BSTR(&vararg));
1378 
1379       VariantClear(&vararg);
1380       return hr;
1381     }
1382     break;
1383   case DISPID_FONT_BOLD:
1384     if (wFlags & DISPATCH_PROPERTYGET) {
1385       BOOL value;
1386       hr = IFont_get_Bold(&this->IFont_iface, &value);
1387       V_VT(pVarResult) = VT_BOOL;
1388       V_BOOL(pVarResult) = value ? VARIANT_TRUE : VARIANT_FALSE;
1389       return hr;
1390     } else {
1391       VARIANTARG vararg;
1392 
1393       VariantInit(&vararg);
1394       hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_BOOL);
1395       if (FAILED(hr))
1396         return hr;
1397 
1398       hr = IFont_put_Bold(&this->IFont_iface, V_BOOL(&vararg));
1399 
1400       VariantClear(&vararg);
1401       return hr;
1402     }
1403     break;
1404   case DISPID_FONT_ITALIC:
1405     if (wFlags & DISPATCH_PROPERTYGET) {
1406       BOOL value;
1407       hr = IFont_get_Italic(&this->IFont_iface, &value);
1408       V_VT(pVarResult) = VT_BOOL;
1409       V_BOOL(pVarResult) = value ? VARIANT_TRUE : VARIANT_FALSE;
1410       return hr;
1411     } else {
1412       VARIANTARG vararg;
1413 
1414       VariantInit(&vararg);
1415       hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_BOOL);
1416       if (FAILED(hr))
1417         return hr;
1418 
1419       hr = IFont_put_Italic(&this->IFont_iface, V_BOOL(&vararg));
1420 
1421       VariantClear(&vararg);
1422       return hr;
1423     }
1424     break;
1425   case DISPID_FONT_UNDER:
1426     if (wFlags & DISPATCH_PROPERTYGET) {
1427       BOOL value;
1428       hr = IFont_get_Underline(&this->IFont_iface, &value);
1429       V_VT(pVarResult) = VT_BOOL;
1430       V_BOOL(pVarResult) = value ? VARIANT_TRUE : VARIANT_FALSE;
1431       return hr;
1432     } else {
1433       VARIANTARG vararg;
1434 
1435       VariantInit(&vararg);
1436       hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_BOOL);
1437       if (FAILED(hr))
1438         return hr;
1439 
1440       hr = IFont_put_Underline(&this->IFont_iface, V_BOOL(&vararg));
1441 
1442       VariantClear(&vararg);
1443       return hr;
1444     }
1445     break;
1446   case DISPID_FONT_STRIKE:
1447     if (wFlags & DISPATCH_PROPERTYGET) {
1448       BOOL value;
1449       hr = IFont_get_Strikethrough(&this->IFont_iface, &value);
1450       V_VT(pVarResult) = VT_BOOL;
1451       V_BOOL(pVarResult) = value ? VARIANT_TRUE : VARIANT_FALSE;
1452       return hr;
1453     } else {
1454       VARIANTARG vararg;
1455 
1456       VariantInit(&vararg);
1457       hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_BOOL);
1458       if (FAILED(hr))
1459         return hr;
1460 
1461       hr = IFont_put_Strikethrough(&this->IFont_iface, V_BOOL(&vararg));
1462 
1463       VariantClear(&vararg);
1464       return hr;
1465     }
1466     break;
1467   case DISPID_FONT_SIZE:
1468     if (wFlags & DISPATCH_PROPERTYGET) {
1469       V_VT(pVarResult) = VT_CY;
1470       return IFont_get_Size(&this->IFont_iface, &V_CY(pVarResult));
1471     } else {
1472       VARIANTARG vararg;
1473 
1474       VariantInit(&vararg);
1475       hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_CY);
1476       if (FAILED(hr))
1477         return hr;
1478 
1479       hr = IFont_put_Size(&this->IFont_iface, V_CY(&vararg));
1480 
1481       VariantClear(&vararg);
1482       return hr;
1483     }
1484     break;
1485   case DISPID_FONT_WEIGHT:
1486     if (wFlags & DISPATCH_PROPERTYGET) {
1487       V_VT(pVarResult) = VT_I2;
1488       return IFont_get_Weight(&this->IFont_iface, &V_I2(pVarResult));
1489     } else {
1490       VARIANTARG vararg;
1491 
1492       VariantInit(&vararg);
1493       hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I2);
1494       if (FAILED(hr))
1495         return hr;
1496 
1497       hr = IFont_put_Weight(&this->IFont_iface, V_I2(&vararg));
1498 
1499       VariantClear(&vararg);
1500       return hr;
1501     }
1502     break;
1503   case DISPID_FONT_CHARSET:
1504     if (wFlags & DISPATCH_PROPERTYGET) {
1505       V_VT(pVarResult) = VT_I2;
1506       return OLEFontImpl_get_Charset(&this->IFont_iface, &V_I2(pVarResult));
1507     } else {
1508       VARIANTARG vararg;
1509 
1510       VariantInit(&vararg);
1511       hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I2);
1512       if (FAILED(hr))
1513         return hr;
1514 
1515       hr = IFont_put_Charset(&this->IFont_iface, V_I2(&vararg));
1516 
1517       VariantClear(&vararg);
1518       return hr;
1519     }
1520     break;
1521   default:
1522     ERR("member not found for dispid 0x%x\n", dispIdMember);
1523     return DISP_E_MEMBERNOTFOUND;
1524   }
1525 }
1526 
1527 static const IDispatchVtbl OLEFontImpl_IDispatch_VTable =
1528 {
1529   OLEFontImpl_IDispatch_QueryInterface,
1530   OLEFontImpl_IDispatch_AddRef,
1531   OLEFontImpl_IDispatch_Release,
1532   OLEFontImpl_GetTypeInfoCount,
1533   OLEFontImpl_GetTypeInfo,
1534   OLEFontImpl_GetIDsOfNames,
1535   OLEFontImpl_Invoke
1536 };
1537 
1538 /************************************************************************
1539  * OLEFontImpl_IPersistStream_QueryInterface (IUnknown)
1540  */
1541 static HRESULT WINAPI OLEFontImpl_IPersistStream_QueryInterface(
1542   IPersistStream* iface,
1543   REFIID     riid,
1544   VOID**     ppvoid)
1545 {
1546   OLEFontImpl *this = impl_from_IPersistStream(iface);
1547 
1548   return IFont_QueryInterface(&this->IFont_iface, riid, ppvoid);
1549 }
1550 
1551 /************************************************************************
1552  * OLEFontImpl_IPersistStream_Release (IUnknown)
1553  */
1554 static ULONG WINAPI OLEFontImpl_IPersistStream_Release(
1555   IPersistStream* iface)
1556 {
1557   OLEFontImpl *this = impl_from_IPersistStream(iface);
1558 
1559   return IFont_Release(&this->IFont_iface);
1560 }
1561 
1562 /************************************************************************
1563  * OLEFontImpl_IPersistStream_AddRef (IUnknown)
1564  */
1565 static ULONG WINAPI OLEFontImpl_IPersistStream_AddRef(
1566   IPersistStream* iface)
1567 {
1568   OLEFontImpl *this = impl_from_IPersistStream(iface);
1569 
1570   return IFont_AddRef(&this->IFont_iface);
1571 }
1572 
1573 /************************************************************************
1574  * OLEFontImpl_GetClassID (IPersistStream)
1575  */
1576 static HRESULT WINAPI OLEFontImpl_GetClassID(
1577   IPersistStream* iface,
1578   CLSID*                pClassID)
1579 {
1580   TRACE("(%p,%p)\n",iface,pClassID);
1581   if (pClassID==0)
1582     return E_POINTER;
1583 
1584   *pClassID = CLSID_StdFont;
1585 
1586   return S_OK;
1587 }
1588 
1589 /************************************************************************
1590  * OLEFontImpl_IsDirty (IPersistStream)
1591  *
1592  * See Windows documentation for more details on IPersistStream methods.
1593  */
1594 static HRESULT WINAPI OLEFontImpl_IsDirty(
1595   IPersistStream*  iface)
1596 {
1597   TRACE("(%p)\n",iface);
1598   return S_OK;
1599 }
1600 
1601 /************************************************************************
1602  * OLEFontImpl_Load (IPersistStream)
1603  *
1604  * See Windows documentation for more details on IPersistStream methods.
1605  *
1606  * This is the format of the standard font serialization as far as I
1607  * know
1608  *
1609  * Offset   Type   Value           Comment
1610  * 0x0000   Byte   Unknown         Probably a version number, contains 0x01
1611  * 0x0001   Short  Charset         Charset value from the FONTDESC structure
1612  * 0x0003   Byte   Attributes      Flags defined as follows:
1613  *                                     00000010 - Italic
1614  *                                     00000100 - Underline
1615  *                                     00001000 - Strikethrough
1616  * 0x0004   Short  Weight          Weight value from FONTDESC structure
1617  * 0x0006   DWORD  size            "Low" portion of the cySize member of the FONTDESC
1618  *                                 structure/
1619  * 0x000A   Byte   name length     Length of the font name string (no null character)
1620  * 0x000B   String name            Name of the font (ASCII, no nul character)
1621  */
1622 static HRESULT WINAPI OLEFontImpl_Load(
1623   IPersistStream*  iface,
1624   IStream*         pLoadStream)
1625 {
1626   OLEFontImpl *this = impl_from_IPersistStream(iface);
1627   BYTE  version, attributes, string_size;
1628   char readBuffer[0x100];
1629   ULONG cbRead;
1630   INT len;
1631 
1632   /* Version */
1633   IStream_Read(pLoadStream, &version, sizeof(BYTE), &cbRead);
1634   if ((cbRead != sizeof(BYTE)) || (version != 0x01)) return E_FAIL;
1635 
1636   /* Charset */
1637   IStream_Read(pLoadStream, &this->description.sCharset, sizeof(WORD), &cbRead);
1638   if (cbRead != sizeof(WORD)) return E_FAIL;
1639 
1640   /* Attributes */
1641   IStream_Read(pLoadStream, &attributes, sizeof(BYTE), &cbRead);
1642   if (cbRead != sizeof(BYTE)) return E_FAIL;
1643 
1644   this->description.fItalic        = (attributes & FONTPERSIST_ITALIC) != 0;
1645   this->description.fStrikethrough = (attributes & FONTPERSIST_STRIKETHROUGH) != 0;
1646   this->description.fUnderline     = (attributes & FONTPERSIST_UNDERLINE) != 0;
1647 
1648   /* Weight */
1649   IStream_Read(pLoadStream, &this->description.sWeight, sizeof(WORD), &cbRead);
1650   if (cbRead != sizeof(WORD)) return E_FAIL;
1651 
1652   /* Size */
1653   IStream_Read(pLoadStream, &this->description.cySize.s.Lo, sizeof(DWORD), &cbRead);
1654   if (cbRead != sizeof(DWORD)) return E_FAIL;
1655 
1656   this->description.cySize.s.Hi = 0;
1657 
1658   /* Name */
1659   IStream_Read(pLoadStream, &string_size, sizeof(BYTE), &cbRead);
1660   if (cbRead != sizeof(BYTE)) return E_FAIL;
1661 
1662   IStream_Read(pLoadStream, readBuffer, string_size, &cbRead);
1663   if (cbRead != string_size) return E_FAIL;
1664 
1665   HeapFree(GetProcessHeap(), 0, this->description.lpstrName);
1666 
1667   len = MultiByteToWideChar( CP_ACP, 0, readBuffer, string_size, NULL, 0 );
1668   this->description.lpstrName = HeapAlloc( GetProcessHeap(), 0, (len+1) * sizeof(WCHAR) );
1669   MultiByteToWideChar( CP_ACP, 0, readBuffer, string_size, this->description.lpstrName, len );
1670   this->description.lpstrName[len] = 0;
1671 
1672   /* Ensure use of this font causes a new one to be created */
1673   dec_int_ref(this->gdiFont);
1674   this->gdiFont = 0;
1675   this->dirty = TRUE;
1676 
1677   return S_OK;
1678 }
1679 
1680 /************************************************************************
1681  * OLEFontImpl_Save (IPersistStream)
1682  */
1683 static HRESULT WINAPI OLEFontImpl_Save(
1684   IPersistStream*  iface,
1685   IStream*         pOutStream,
1686   BOOL             fClearDirty)
1687 {
1688   OLEFontImpl *this = impl_from_IPersistStream(iface);
1689   BYTE  attributes, string_size;
1690   const BYTE version = 0x01;
1691   char* writeBuffer = NULL;
1692   ULONG written;
1693 
1694   TRACE("(%p)->(%p %d)\n", this, pOutStream, fClearDirty);
1695 
1696   /* Version */
1697   IStream_Write(pOutStream, &version, sizeof(BYTE), &written);
1698   if (written != sizeof(BYTE)) return E_FAIL;
1699 
1700   /* Charset */
1701   IStream_Write(pOutStream, &this->description.sCharset, sizeof(WORD), &written);
1702   if (written != sizeof(WORD)) return E_FAIL;
1703 
1704   /* Attributes */
1705   attributes = 0;
1706 
1707   if (this->description.fItalic)
1708     attributes |= FONTPERSIST_ITALIC;
1709 
1710   if (this->description.fStrikethrough)
1711     attributes |= FONTPERSIST_STRIKETHROUGH;
1712 
1713   if (this->description.fUnderline)
1714     attributes |= FONTPERSIST_UNDERLINE;
1715 
1716   IStream_Write(pOutStream, &attributes, sizeof(BYTE), &written);
1717   if (written != sizeof(BYTE)) return E_FAIL;
1718 
1719   /* Weight */
1720   IStream_Write(pOutStream, &this->description.sWeight, sizeof(WORD), &written);
1721   if (written != sizeof(WORD)) return E_FAIL;
1722 
1723   /* Size */
1724   IStream_Write(pOutStream, &this->description.cySize.s.Lo, sizeof(DWORD), &written);
1725   if (written != sizeof(DWORD)) return E_FAIL;
1726 
1727   /* FontName */
1728   if (this->description.lpstrName)
1729     string_size = WideCharToMultiByte( CP_ACP, 0, this->description.lpstrName,
1730                                        strlenW(this->description.lpstrName), NULL, 0, NULL, NULL );
1731   else
1732     string_size = 0;
1733 
1734   IStream_Write(pOutStream, &string_size, sizeof(BYTE), &written);
1735   if (written != sizeof(BYTE)) return E_FAIL;
1736 
1737   if (string_size)
1738   {
1739       if (!(writeBuffer = HeapAlloc( GetProcessHeap(), 0, string_size ))) return E_OUTOFMEMORY;
1740       WideCharToMultiByte( CP_ACP, 0, this->description.lpstrName,
1741                            strlenW(this->description.lpstrName),
1742                            writeBuffer, string_size, NULL, NULL );
1743 
1744       IStream_Write(pOutStream, writeBuffer, string_size, &written);
1745       HeapFree(GetProcessHeap(), 0, writeBuffer);
1746 
1747       if (written != string_size) return E_FAIL;
1748   }
1749 
1750   return S_OK;
1751 }
1752 
1753 /************************************************************************
1754  * OLEFontImpl_GetSizeMax (IPersistStream)
1755  */
1756 static HRESULT WINAPI OLEFontImpl_GetSizeMax(
1757   IPersistStream*  iface,
1758   ULARGE_INTEGER*  pcbSize)
1759 {
1760   OLEFontImpl *this = impl_from_IPersistStream(iface);
1761 
1762   if (pcbSize==NULL)
1763     return E_POINTER;
1764 
1765   pcbSize->u.HighPart = 0;
1766   pcbSize->u.LowPart = 0;
1767 
1768   pcbSize->u.LowPart += sizeof(BYTE);  /* Version */
1769   pcbSize->u.LowPart += sizeof(WORD);  /* Lang code */
1770   pcbSize->u.LowPart += sizeof(BYTE);  /* Flags */
1771   pcbSize->u.LowPart += sizeof(WORD);  /* Weight */
1772   pcbSize->u.LowPart += sizeof(DWORD); /* Size */
1773   pcbSize->u.LowPart += sizeof(BYTE);  /* StrLength */
1774 
1775   if (this->description.lpstrName!=0)
1776       pcbSize->u.LowPart += WideCharToMultiByte( CP_ACP, 0, this->description.lpstrName,
1777                                                  strlenW(this->description.lpstrName),
1778                                                  NULL, 0, NULL, NULL );
1779 
1780   return S_OK;
1781 }
1782 
1783 static const IPersistStreamVtbl OLEFontImpl_IPersistStream_VTable =
1784 {
1785   OLEFontImpl_IPersistStream_QueryInterface,
1786   OLEFontImpl_IPersistStream_AddRef,
1787   OLEFontImpl_IPersistStream_Release,
1788   OLEFontImpl_GetClassID,
1789   OLEFontImpl_IsDirty,
1790   OLEFontImpl_Load,
1791   OLEFontImpl_Save,
1792   OLEFontImpl_GetSizeMax
1793 };
1794 
1795 /************************************************************************
1796  * OLEFontImpl_IConnectionPointContainer_QueryInterface (IUnknown)
1797  */
1798 static HRESULT WINAPI OLEFontImpl_IConnectionPointContainer_QueryInterface(
1799   IConnectionPointContainer* iface,
1800   REFIID     riid,
1801   VOID**     ppvoid)
1802 {
1803   OLEFontImpl *this = impl_from_IConnectionPointContainer(iface);
1804 
1805   return IFont_QueryInterface(&this->IFont_iface, riid, ppvoid);
1806 }
1807 
1808 /************************************************************************
1809  * OLEFontImpl_IConnectionPointContainer_Release (IUnknown)
1810  */
1811 static ULONG WINAPI OLEFontImpl_IConnectionPointContainer_Release(
1812   IConnectionPointContainer* iface)
1813 {
1814   OLEFontImpl *this = impl_from_IConnectionPointContainer(iface);
1815 
1816   return IFont_Release(&this->IFont_iface);
1817 }
1818 
1819 /************************************************************************
1820  * OLEFontImpl_IConnectionPointContainer_AddRef (IUnknown)
1821  */
1822 static ULONG WINAPI OLEFontImpl_IConnectionPointContainer_AddRef(
1823   IConnectionPointContainer* iface)
1824 {
1825   OLEFontImpl *this = impl_from_IConnectionPointContainer(iface);
1826 
1827   return IFont_AddRef(&this->IFont_iface);
1828 }
1829 
1830 /************************************************************************
1831  * OLEFontImpl_EnumConnectionPoints (IConnectionPointContainer)
1832  */
1833 static HRESULT WINAPI OLEFontImpl_EnumConnectionPoints(
1834   IConnectionPointContainer* iface,
1835   IEnumConnectionPoints **ppEnum)
1836 {
1837   OLEFontImpl *this = impl_from_IConnectionPointContainer(iface);
1838 
1839   FIXME("(%p)->(%p): stub\n", this, ppEnum);
1840   return E_NOTIMPL;
1841 }
1842 
1843 /************************************************************************
1844  * OLEFontImpl_FindConnectionPoint (IConnectionPointContainer)
1845  */
1846 static HRESULT WINAPI OLEFontImpl_FindConnectionPoint(
1847    IConnectionPointContainer* iface,
1848    REFIID riid,
1849    IConnectionPoint **ppCp)
1850 {
1851   OLEFontImpl *this = impl_from_IConnectionPointContainer(iface);
1852   TRACE("(%p)->(%s, %p)\n", this, debugstr_guid(riid), ppCp);
1853 
1854   if(IsEqualIID(riid, &IID_IPropertyNotifySink)) {
1855     return IConnectionPoint_QueryInterface(this->pPropertyNotifyCP, &IID_IConnectionPoint,
1856                                            (void**)ppCp);
1857   } else if(IsEqualIID(riid, &IID_IFontEventsDisp)) {
1858     return IConnectionPoint_QueryInterface(this->pFontEventsCP, &IID_IConnectionPoint,
1859                                            (void**)ppCp);
1860   } else {
1861     FIXME("no connection point for %s\n", debugstr_guid(riid));
1862     return CONNECT_E_NOCONNECTION;
1863   }
1864 }
1865 
1866 static const IConnectionPointContainerVtbl
1867      OLEFontImpl_IConnectionPointContainer_VTable =
1868 {
1869   OLEFontImpl_IConnectionPointContainer_QueryInterface,
1870   OLEFontImpl_IConnectionPointContainer_AddRef,
1871   OLEFontImpl_IConnectionPointContainer_Release,
1872   OLEFontImpl_EnumConnectionPoints,
1873   OLEFontImpl_FindConnectionPoint
1874 };
1875 
1876 /************************************************************************
1877  * OLEFontImpl implementation of IPersistPropertyBag.
1878  */
1879 static HRESULT WINAPI OLEFontImpl_IPersistPropertyBag_QueryInterface(
1880    IPersistPropertyBag *iface, REFIID riid, LPVOID *ppvObj
1881 ) {
1882   OLEFontImpl *this = impl_from_IPersistPropertyBag(iface);
1883   return IFont_QueryInterface(&this->IFont_iface,riid,ppvObj);
1884 }
1885 
1886 static ULONG WINAPI OLEFontImpl_IPersistPropertyBag_AddRef(
1887    IPersistPropertyBag *iface
1888 ) {
1889   OLEFontImpl *this = impl_from_IPersistPropertyBag(iface);
1890   return IFont_AddRef(&this->IFont_iface);
1891 }
1892 
1893 static ULONG WINAPI OLEFontImpl_IPersistPropertyBag_Release(
1894    IPersistPropertyBag *iface
1895 ) {
1896   OLEFontImpl *this = impl_from_IPersistPropertyBag(iface);
1897   return IFont_Release(&this->IFont_iface);
1898 }
1899 
1900 static HRESULT WINAPI OLEFontImpl_IPersistPropertyBag_GetClassID(
1901    IPersistPropertyBag *iface, CLSID *classid
1902 ) {
1903   FIXME("(%p,%p), stub!\n", iface, classid);
1904   return E_FAIL;
1905 }
1906 
1907 static HRESULT WINAPI OLEFontImpl_IPersistPropertyBag_InitNew(
1908    IPersistPropertyBag *iface
1909 ) {
1910   FIXME("(%p), stub!\n", iface);
1911   return S_OK;
1912 }
1913 
1914 static HRESULT WINAPI OLEFontImpl_IPersistPropertyBag_Load(
1915    IPersistPropertyBag *iface, IPropertyBag* pPropBag, IErrorLog* pErrorLog
1916 ) {
1917 /* (from Visual Basic 6 property bag)
1918          Name            =   "MS Sans Serif"
1919          Size            =   13.8
1920          Charset         =   0
1921          Weight          =   400
1922          Underline       =   0   'False
1923          Italic          =   0   'False
1924          Strikethrough   =   0   'False
1925 */
1926     static const WCHAR sAttrName[] = {'N','a','m','e',0};
1927     static const WCHAR sAttrSize[] = {'S','i','z','e',0};
1928     static const WCHAR sAttrCharset[] = {'C','h','a','r','s','e','t',0};
1929     static const WCHAR sAttrWeight[] = {'W','e','i','g','h','t',0};
1930     static const WCHAR sAttrUnderline[] = {'U','n','d','e','r','l','i','n','e',0};
1931     static const WCHAR sAttrItalic[] = {'I','t','a','l','i','c',0};
1932     static const WCHAR sAttrStrikethrough[] = {'S','t','r','i','k','e','t','h','r','o','u','g','h',0};
1933     OLEFontImpl *this = impl_from_IPersistPropertyBag(iface);
1934     VARIANT value;
1935     HRESULT iRes;
1936 
1937     VariantInit(&value);
1938 
1939     iRes = IPropertyBag_Read(pPropBag, sAttrName, &value, pErrorLog);
1940     if (iRes == S_OK)
1941     {
1942         iRes = VariantChangeType(&value, &value, 0, VT_BSTR);
1943         if (iRes == S_OK)
1944             iRes = IFont_put_Name(&this->IFont_iface, V_BSTR(&value));
1945     }
1946     else if (iRes == E_INVALIDARG)
1947         iRes = S_OK;
1948 
1949     VariantClear(&value);
1950 
1951     if (iRes == S_OK) {
1952         iRes = IPropertyBag_Read(pPropBag, sAttrSize, &value, pErrorLog);
1953         if (iRes == S_OK)
1954         {
1955             iRes = VariantChangeType(&value, &value, 0, VT_CY);
1956             if (iRes == S_OK)
1957                 iRes = IFont_put_Size(&this->IFont_iface, V_CY(&value));
1958         }
1959         else if (iRes == E_INVALIDARG)
1960             iRes = S_OK;
1961 
1962         VariantClear(&value);
1963     }
1964 
1965     if (iRes == S_OK) {
1966         iRes = IPropertyBag_Read(pPropBag, sAttrCharset, &value, pErrorLog);
1967         if (iRes == S_OK)
1968         {
1969             iRes = VariantChangeType(&value, &value, 0, VT_I2);
1970             if (iRes == S_OK)
1971                 iRes = IFont_put_Charset(&this->IFont_iface, V_I2(&value));
1972         }
1973         else if (iRes == E_INVALIDARG)
1974             iRes = S_OK;
1975 
1976         VariantClear(&value);
1977     }
1978 
1979     if (iRes == S_OK) {
1980         iRes = IPropertyBag_Read(pPropBag, sAttrWeight, &value, pErrorLog);
1981         if (iRes == S_OK)
1982         {
1983             iRes = VariantChangeType(&value, &value, 0, VT_I2);
1984             if (iRes == S_OK)
1985                 iRes = IFont_put_Weight(&this->IFont_iface, V_I2(&value));
1986         }
1987         else if (iRes == E_INVALIDARG)
1988             iRes = S_OK;
1989 
1990         VariantClear(&value);
1991     }
1992 
1993     if (iRes == S_OK) {
1994         iRes = IPropertyBag_Read(pPropBag, sAttrUnderline, &value, pErrorLog);
1995         if (iRes == S_OK)
1996         {
1997             iRes = VariantChangeType(&value, &value, 0, VT_BOOL);
1998             if (iRes == S_OK)
1999                 iRes = IFont_put_Underline(&this->IFont_iface, V_BOOL(&value));
2000         }
2001         else if (iRes == E_INVALIDARG)
2002             iRes = S_OK;
2003 
2004         VariantClear(&value);
2005     }
2006 
2007     if (iRes == S_OK) {
2008         iRes = IPropertyBag_Read(pPropBag, sAttrItalic, &value, pErrorLog);
2009         if (iRes == S_OK)
2010         {
2011             iRes = VariantChangeType(&value, &value, 0, VT_BOOL);
2012             if (iRes == S_OK)
2013                 iRes = IFont_put_Italic(&this->IFont_iface, V_BOOL(&value));
2014         }
2015         else if (iRes == E_INVALIDARG)
2016             iRes = S_OK;
2017 
2018         VariantClear(&value);
2019     }
2020 
2021     if (iRes == S_OK) {
2022         iRes = IPropertyBag_Read(pPropBag, sAttrStrikethrough, &value, pErrorLog);
2023         if (iRes == S_OK)
2024         {
2025             iRes = VariantChangeType(&value, &value, 0, VT_BOOL);
2026             if (iRes == S_OK)
2027                 IFont_put_Strikethrough(&this->IFont_iface, V_BOOL(&value));
2028         }
2029         else if (iRes == E_INVALIDARG)
2030             iRes = S_OK;
2031 
2032         VariantClear(&value);
2033     }
2034 
2035     if (FAILED(iRes))
2036         WARN("-- 0x%08x\n", iRes);
2037     return iRes;
2038 }
2039 
2040 static HRESULT WINAPI OLEFontImpl_IPersistPropertyBag_Save(
2041    IPersistPropertyBag *iface, IPropertyBag* pPropBag, BOOL fClearDirty,
2042    BOOL fSaveAllProperties
2043 ) {
2044   FIXME("(%p,%p,%d,%d), stub!\n", iface, pPropBag, fClearDirty, fSaveAllProperties);
2045   return E_FAIL;
2046 }
2047 
2048 static const IPersistPropertyBagVtbl OLEFontImpl_IPersistPropertyBag_VTable =
2049 {
2050   OLEFontImpl_IPersistPropertyBag_QueryInterface,
2051   OLEFontImpl_IPersistPropertyBag_AddRef,
2052   OLEFontImpl_IPersistPropertyBag_Release,
2053 
2054   OLEFontImpl_IPersistPropertyBag_GetClassID,
2055   OLEFontImpl_IPersistPropertyBag_InitNew,
2056   OLEFontImpl_IPersistPropertyBag_Load,
2057   OLEFontImpl_IPersistPropertyBag_Save
2058 };
2059 
2060 /************************************************************************
2061  * OLEFontImpl implementation of IPersistStreamInit.
2062  */
2063 static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_QueryInterface(
2064    IPersistStreamInit *iface, REFIID riid, LPVOID *ppvObj
2065 ) {
2066   OLEFontImpl *this = impl_from_IPersistStreamInit(iface);
2067   return IFont_QueryInterface(&this->IFont_iface,riid,ppvObj);
2068 }
2069 
2070 static ULONG WINAPI OLEFontImpl_IPersistStreamInit_AddRef(
2071    IPersistStreamInit *iface
2072 ) {
2073   OLEFontImpl *this = impl_from_IPersistStreamInit(iface);
2074   return IFont_AddRef(&this->IFont_iface);
2075 }
2076 
2077 static ULONG WINAPI OLEFontImpl_IPersistStreamInit_Release(
2078    IPersistStreamInit *iface
2079 ) {
2080   OLEFontImpl *this = impl_from_IPersistStreamInit(iface);
2081   return IFont_Release(&this->IFont_iface);
2082 }
2083 
2084 static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_GetClassID(
2085    IPersistStreamInit *iface, CLSID *classid
2086 ) {
2087   FIXME("(%p,%p), stub!\n", iface, classid);
2088   return E_FAIL;
2089 }
2090 
2091 static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_IsDirty(
2092    IPersistStreamInit *iface
2093 ) {
2094   FIXME("(%p), stub!\n", iface);
2095   return E_FAIL;
2096 }
2097 
2098 static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_Load(
2099    IPersistStreamInit *iface, LPSTREAM pStm
2100 ) {
2101   FIXME("(%p,%p), stub!\n", iface, pStm);
2102   return E_FAIL;
2103 }
2104 
2105 static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_Save(
2106    IPersistStreamInit *iface, LPSTREAM pStm, BOOL fClearDirty
2107 ) {
2108   FIXME("(%p,%p,%d), stub!\n", iface, pStm, fClearDirty);
2109   return E_FAIL;
2110 }
2111 
2112 static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_GetSizeMax(
2113    IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize
2114 ) {
2115   FIXME("(%p,%p), stub!\n", iface, pcbSize);
2116   return E_FAIL;
2117 }
2118 
2119 static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_InitNew(
2120    IPersistStreamInit *iface
2121 ) {
2122   FIXME("(%p), stub!\n", iface);
2123   return S_OK;
2124 }
2125 
2126 static const IPersistStreamInitVtbl OLEFontImpl_IPersistStreamInit_VTable =
2127 {
2128   OLEFontImpl_IPersistStreamInit_QueryInterface,
2129   OLEFontImpl_IPersistStreamInit_AddRef,
2130   OLEFontImpl_IPersistStreamInit_Release,
2131 
2132   OLEFontImpl_IPersistStreamInit_GetClassID,
2133   OLEFontImpl_IPersistStreamInit_IsDirty,
2134   OLEFontImpl_IPersistStreamInit_Load,
2135   OLEFontImpl_IPersistStreamInit_Save,
2136   OLEFontImpl_IPersistStreamInit_GetSizeMax,
2137   OLEFontImpl_IPersistStreamInit_InitNew
2138 };
2139 
2140 /************************************************************************
2141  * OLEFontImpl_Construct
2142  *
2143  * This method will construct a new instance of the OLEFontImpl
2144  * class.
2145  *
2146  * The caller of this method must release the object when it's
2147  * done with it.
2148  */
2149 static OLEFontImpl* OLEFontImpl_Construct(const FONTDESC *fontDesc)
2150 {
2151   OLEFontImpl* newObject;
2152 
2153   newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(OLEFontImpl));
2154 
2155   if (newObject==0)
2156     return newObject;
2157 
2158   newObject->IFont_iface.lpVtbl = &OLEFontImpl_VTable;
2159   newObject->IDispatch_iface.lpVtbl = &OLEFontImpl_IDispatch_VTable;
2160   newObject->IPersistStream_iface.lpVtbl = &OLEFontImpl_IPersistStream_VTable;
2161   newObject->IConnectionPointContainer_iface.lpVtbl = &OLEFontImpl_IConnectionPointContainer_VTable;
2162   newObject->IPersistPropertyBag_iface.lpVtbl = &OLEFontImpl_IPersistPropertyBag_VTable;
2163   newObject->IPersistStreamInit_iface.lpVtbl = &OLEFontImpl_IPersistStreamInit_VTable;
2164 
2165   newObject->ref = 1;
2166 
2167   newObject->description.cbSizeofstruct = sizeof(FONTDESC);
2168   newObject->description.lpstrName      = strdupW(fontDesc->lpstrName);
2169   newObject->description.cySize         = fontDesc->cySize;
2170   newObject->description.sWeight        = fontDesc->sWeight;
2171   newObject->description.sCharset       = fontDesc->sCharset;
2172   newObject->description.fItalic        = fontDesc->fItalic;
2173   newObject->description.fUnderline     = fontDesc->fUnderline;
2174   newObject->description.fStrikethrough = fontDesc->fStrikethrough;
2175 
2176   newObject->gdiFont  = 0;
2177   newObject->dirty = TRUE;
2178   newObject->cyLogical  = GetDeviceCaps(get_dc(), LOGPIXELSY);
2179   newObject->cyHimetric = 2540L;
2180   newObject->pPropertyNotifyCP = NULL;
2181   newObject->pFontEventsCP = NULL;
2182 
2183   CreateConnectionPoint((IUnknown*)&newObject->IFont_iface, &IID_IPropertyNotifySink, &newObject->pPropertyNotifyCP);
2184   CreateConnectionPoint((IUnknown*)&newObject->IFont_iface, &IID_IFontEventsDisp, &newObject->pFontEventsCP);
2185 
2186   if (!newObject->pPropertyNotifyCP || !newObject->pFontEventsCP)
2187   {
2188     OLEFontImpl_Destroy(newObject);
2189     return NULL;
2190   }
2191 
2192   InterlockedIncrement(&ifont_cnt);
2193 
2194   TRACE("returning %p\n", newObject);
2195   return newObject;
2196 }
2197 
2198 /************************************************************************
2199  * OLEFontImpl_Destroy
2200  *
2201  * This method is called by the Release method when the reference
2202  * count goes down to 0. It will free all resources used by
2203  * this object.
2204  */
2205 static void OLEFontImpl_Destroy(OLEFontImpl* fontDesc)
2206 {
2207   TRACE("(%p)\n", fontDesc);
2208 
2209   HeapFree(GetProcessHeap(), 0, fontDesc->description.lpstrName);
2210 
2211   if (fontDesc->pPropertyNotifyCP)
2212       IConnectionPoint_Release(fontDesc->pPropertyNotifyCP);
2213   if (fontDesc->pFontEventsCP)
2214       IConnectionPoint_Release(fontDesc->pFontEventsCP);
2215 
2216   HeapFree(GetProcessHeap(), 0, fontDesc);
2217 }
2218 
2219 /*******************************************************************************
2220  * StdFont ClassFactory
2221  */
2222 typedef struct
2223 {
2224     /* IUnknown fields */
2225     IClassFactory IClassFactory_iface;
2226     LONG          ref;
2227 } IClassFactoryImpl;
2228 
2229 static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
2230 {
2231         return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface);
2232 }
2233 
2234 static HRESULT WINAPI SFCF_QueryInterface(IClassFactory *iface, REFIID riid, void **obj)
2235 {
2236     IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2237 
2238     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), obj);
2239 
2240     *obj = NULL;
2241 
2242     if (IsEqualIID(&IID_IClassFactory, riid) || IsEqualIID(&IID_IUnknown, riid))
2243     {
2244         *obj = iface;
2245         IClassFactory_AddRef(iface);
2246         return S_OK;
2247     }
2248 
2249     return E_NOINTERFACE;
2250 }
2251 
2252 static ULONG WINAPI
2253 SFCF_AddRef(LPCLASSFACTORY iface) {
2254 	IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2255 	return InterlockedIncrement(&This->ref);
2256 }
2257 
2258 static ULONG WINAPI SFCF_Release(LPCLASSFACTORY iface) {
2259 	IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2260 	/* static class, won't be  freed */
2261 	return InterlockedDecrement(&This->ref);
2262 }
2263 
2264 static HRESULT WINAPI SFCF_CreateInstance(
2265 	LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj
2266 ) {
2267 	return OleCreateFontIndirect(NULL,riid,ppobj);
2268 
2269 }
2270 
2271 static HRESULT WINAPI SFCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) {
2272 	IClassFactoryImpl *This = impl_from_IClassFactory(iface);
2273 	FIXME("(%p)->(%d),stub!\n",This,dolock);
2274 	return S_OK;
2275 }
2276 
2277 static const IClassFactoryVtbl SFCF_Vtbl = {
2278 	SFCF_QueryInterface,
2279 	SFCF_AddRef,
2280 	SFCF_Release,
2281 	SFCF_CreateInstance,
2282 	SFCF_LockServer
2283 };
2284 static IClassFactoryImpl STDFONT_CF = {{&SFCF_Vtbl}, 1 };
2285 
2286 void _get_STDFONT_CF(LPVOID *ppv) { *ppv = &STDFONT_CF; }
2287