/* * OLE Font encapsulation implementation * * This file contains an implementation of the IFont * interface and the OleCreateFontIndirect API call. * * Copyright 1999 Francis Beaudet * Copyright 2006 (Google) Benjamin Arai * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include <assert.h> #include <stdarg.h> #include <string.h> #define COBJMACROS #define NONAMELESSUNION #define NONAMELESSSTRUCT #include "winerror.h" #include "windef.h" #include "winbase.h" #include "wingdi.h" #include "winuser.h" #include "wine/list.h" #include "wine/unicode.h" #include "objbase.h" #include "oleauto.h" /* for SysAllocString(....) */ #include "ole2.h" #include "olectl.h" #include "wine/debug.h" #include "connpt.h" /* for CreateConnectionPoint */ #include "oaidl.h" WINE_DEFAULT_DEBUG_CHANNEL(ole); /*********************************************************************** * Declaration of constants used when serializing the font object. */ #define FONTPERSIST_ITALIC 0x02 #define FONTPERSIST_UNDERLINE 0x04 #define FONTPERSIST_STRIKETHROUGH 0x08 static HDC olefont_hdc; /*********************************************************************** * List of the HFONTs it has given out, with each one having a separate * ref count. */ typedef struct _HFONTItem { struct list entry; /* Reference count of any IFont objects that own this hfont */ LONG int_refs; /* Total reference count of any refs held by the application obtained by AddRefHfont plus any internal refs */ LONG total_refs; /* The font associated with this object. */ HFONT gdiFont; } HFONTItem, *PHFONTItem; static struct list OLEFontImpl_hFontList = LIST_INIT(OLEFontImpl_hFontList); /* Counts how many fonts contain at least one lock */ static LONG ifont_cnt = 0; /*********************************************************************** * Critical section for OLEFontImpl_hFontList */ static CRITICAL_SECTION OLEFontImpl_csHFONTLIST; static CRITICAL_SECTION_DEBUG OLEFontImpl_csHFONTLIST_debug = { 0, 0, &OLEFontImpl_csHFONTLIST, { &OLEFontImpl_csHFONTLIST_debug.ProcessLocksList, &OLEFontImpl_csHFONTLIST_debug.ProcessLocksList }, 0, 0, { (DWORD_PTR)(__FILE__ ": OLEFontImpl_csHFONTLIST") } }; static CRITICAL_SECTION OLEFontImpl_csHFONTLIST = { &OLEFontImpl_csHFONTLIST_debug, -1, 0, 0, 0, 0 }; static HDC get_dc(void) { HDC hdc; EnterCriticalSection(&OLEFontImpl_csHFONTLIST); if(!olefont_hdc) olefont_hdc = CreateCompatibleDC(NULL); hdc = olefont_hdc; LeaveCriticalSection(&OLEFontImpl_csHFONTLIST); return hdc; } static void delete_dc(void) { EnterCriticalSection(&OLEFontImpl_csHFONTLIST); if(olefont_hdc) { DeleteDC(olefont_hdc); olefont_hdc = NULL; } LeaveCriticalSection(&OLEFontImpl_csHFONTLIST); } static void HFONTItem_Delete(PHFONTItem item) { DeleteObject(item->gdiFont); list_remove(&item->entry); HeapFree(GetProcessHeap(), 0, item); } /* Find hfont item entry in the list. Should be called while holding the crit sect */ static HFONTItem *find_hfontitem(HFONT hfont) { HFONTItem *item; LIST_FOR_EACH_ENTRY(item, &OLEFontImpl_hFontList, HFONTItem, entry) { if (item->gdiFont == hfont) return item; } return NULL; } /* Add an item to the list with one internal reference */ static HRESULT add_hfontitem(HFONT hfont) { HFONTItem *new_item = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_item)); if(!new_item) return E_OUTOFMEMORY; new_item->int_refs = 1; new_item->total_refs = 1; new_item->gdiFont = hfont; EnterCriticalSection(&OLEFontImpl_csHFONTLIST); list_add_tail(&OLEFontImpl_hFontList,&new_item->entry); LeaveCriticalSection(&OLEFontImpl_csHFONTLIST); return S_OK; } static HRESULT inc_int_ref(HFONT hfont) { HFONTItem *item; HRESULT hr = S_FALSE; EnterCriticalSection(&OLEFontImpl_csHFONTLIST); item = find_hfontitem(hfont); if(item) { item->int_refs++; item->total_refs++; hr = S_OK; } LeaveCriticalSection(&OLEFontImpl_csHFONTLIST); return hr; } /* decrements the internal ref of a hfont item. If both refs are zero it'll remove the item from the list and delete the hfont */ static HRESULT dec_int_ref(HFONT hfont) { HFONTItem *item; HRESULT hr = S_FALSE; EnterCriticalSection(&OLEFontImpl_csHFONTLIST); item = find_hfontitem(hfont); if(item) { item->int_refs--; item->total_refs--; if(item->int_refs == 0 && item->total_refs == 0) HFONTItem_Delete(item); hr = S_OK; } LeaveCriticalSection(&OLEFontImpl_csHFONTLIST); return hr; } static HRESULT inc_ext_ref(HFONT hfont) { HFONTItem *item; HRESULT hr = S_FALSE; EnterCriticalSection(&OLEFontImpl_csHFONTLIST); item = find_hfontitem(hfont); if(item) { item->total_refs++; hr = S_OK; } LeaveCriticalSection(&OLEFontImpl_csHFONTLIST); return hr; } static HRESULT dec_ext_ref(HFONT hfont) { HFONTItem *item; HRESULT hr = S_FALSE; EnterCriticalSection(&OLEFontImpl_csHFONTLIST); item = find_hfontitem(hfont); if(item) { if(--item->total_refs >= 0) hr = S_OK; } LeaveCriticalSection(&OLEFontImpl_csHFONTLIST); return hr; } static WCHAR *strdupW(const WCHAR* str) { WCHAR *ret; DWORD size = (strlenW(str) + 1) * sizeof(WCHAR); ret = HeapAlloc(GetProcessHeap(), 0, size); if(ret) memcpy(ret, str, size); return ret; } /*********************************************************************** * Declaration of the implementation class for the IFont interface */ typedef struct OLEFontImpl OLEFontImpl; struct OLEFontImpl { /* * This class supports many interfaces. IUnknown, IFont, * IDispatch, IDispFont IPersistStream and IConnectionPointContainer. * The first two are supported by the first vtable, the next two are * supported by the second table and the last two have their own. */ IFont IFont_iface; IDispatch IDispatch_iface; IPersistStream IPersistStream_iface; IConnectionPointContainer IConnectionPointContainer_iface; IPersistPropertyBag IPersistPropertyBag_iface; IPersistStreamInit IPersistStreamInit_iface; /* * Reference count for that instance of the class. */ LONG ref; /* * This structure contains the description of the class. */ FONTDESC description; /* * Contain the font associated with this object. */ HFONT gdiFont; BOOL dirty; /* * Size ratio */ LONG cyLogical; LONG cyHimetric; /* * Stash realized height (pixels) from TEXTMETRIC - used in get_Size() */ LONG nRealHeight; IConnectionPoint *pPropertyNotifyCP; IConnectionPoint *pFontEventsCP; }; static inline OLEFontImpl *impl_from_IFont(IFont *iface) { return CONTAINING_RECORD(iface, OLEFontImpl, IFont_iface); } static inline OLEFontImpl *impl_from_IDispatch( IDispatch *iface ) { return CONTAINING_RECORD(iface, OLEFontImpl, IDispatch_iface); } static inline OLEFontImpl *impl_from_IPersistStream( IPersistStream *iface ) { return CONTAINING_RECORD(iface, OLEFontImpl, IPersistStream_iface); } static inline OLEFontImpl *impl_from_IConnectionPointContainer( IConnectionPointContainer *iface ) { return CONTAINING_RECORD(iface, OLEFontImpl, IConnectionPointContainer_iface); } static inline OLEFontImpl *impl_from_IPersistPropertyBag( IPersistPropertyBag *iface ) { return CONTAINING_RECORD(iface, OLEFontImpl, IPersistPropertyBag_iface); } static inline OLEFontImpl *impl_from_IPersistStreamInit( IPersistStreamInit *iface ) { return CONTAINING_RECORD(iface, OLEFontImpl, IPersistStreamInit_iface); } /*********************************************************************** * Prototypes for the implementation functions for the IFont * interface */ static OLEFontImpl* OLEFontImpl_Construct(const FONTDESC *fontDesc); static void OLEFontImpl_Destroy(OLEFontImpl* fontDesc); static ULONG WINAPI OLEFontImpl_AddRef(IFont* iface); /****************************************************************************** * OleCreateFontIndirect [OLEAUT32.420] */ HRESULT WINAPI OleCreateFontIndirect( LPFONTDESC lpFontDesc, REFIID riid, LPVOID* ppvObj) { OLEFontImpl* newFont; HRESULT hr; FONTDESC fd; TRACE("(%p, %s, %p)\n", lpFontDesc, debugstr_guid(riid), ppvObj); if (!ppvObj) return E_POINTER; *ppvObj = 0; if (!lpFontDesc) { static WCHAR fname[] = { 'S','y','s','t','e','m',0 }; fd.cbSizeofstruct = sizeof(fd); fd.lpstrName = fname; fd.cySize.s.Lo = 80000; fd.cySize.s.Hi = 0; fd.sWeight = 0; fd.sCharset = 0; fd.fItalic = 0; fd.fUnderline = 0; fd.fStrikethrough = 0; lpFontDesc = &fd; } newFont = OLEFontImpl_Construct(lpFontDesc); if (!newFont) return E_OUTOFMEMORY; hr = IFont_QueryInterface(&newFont->IFont_iface, riid, ppvObj); IFont_Release(&newFont->IFont_iface); return hr; } /*********************************************************************** * Implementation of the OLEFontImpl class. */ /*********************************************************************** * OLEFont_SendNotify (internal) * * Sends notification messages of changed properties to any interested * connections. */ static void OLEFont_SendNotify(OLEFontImpl* this, DISPID dispID) { static const WCHAR wszName[] = {'N','a','m','e',0}; static const WCHAR wszSize[] = {'S','i','z','e',0}; static const WCHAR wszBold[] = {'B','o','l','d',0}; static const WCHAR wszItalic[] = {'I','t','a','l','i','c',0}; static const WCHAR wszUnder[] = {'U','n','d','e','r','l','i','n','e',0}; static const WCHAR wszStrike[] = {'S','t','r','i','k','e','t','h','r','o','u','g','h',0}; static const WCHAR wszWeight[] = {'W','e','i','g','h','t',0}; static const WCHAR wszCharset[] = {'C','h','a','r','s','s','e','t',0}; static const LPCWSTR dispid_mapping[] = { wszName, NULL, wszSize, wszBold, wszItalic, wszUnder, wszStrike, wszWeight, wszCharset }; IEnumConnections *pEnum; CONNECTDATA CD; HRESULT hres; this->dirty = TRUE; hres = IConnectionPoint_EnumConnections(this->pPropertyNotifyCP, &pEnum); if (SUCCEEDED(hres)) { while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) { IPropertyNotifySink *sink; IUnknown_QueryInterface(CD.pUnk, &IID_IPropertyNotifySink, (LPVOID)&sink); IPropertyNotifySink_OnChanged(sink, dispID); IPropertyNotifySink_Release(sink); IUnknown_Release(CD.pUnk); } IEnumConnections_Release(pEnum); } hres = IConnectionPoint_EnumConnections(this->pFontEventsCP, &pEnum); if (SUCCEEDED(hres)) { DISPPARAMS dispparams; VARIANTARG vararg; VariantInit(&vararg); V_VT(&vararg) = VT_BSTR; V_BSTR(&vararg) = SysAllocString(dispid_mapping[dispID]); dispparams.cArgs = 1; dispparams.cNamedArgs = 0; dispparams.rgdispidNamedArgs = NULL; dispparams.rgvarg = &vararg; while(IEnumConnections_Next(pEnum, 1, &CD, NULL) == S_OK) { IFontEventsDisp *disp; IUnknown_QueryInterface(CD.pUnk, &IID_IFontEventsDisp, (LPVOID)&disp); IFontEventsDisp_Invoke(disp, DISPID_FONT_CHANGED, &IID_NULL, LOCALE_NEUTRAL, INVOKE_FUNC, &dispparams, NULL, NULL, NULL); IFontEventsDisp_Release(disp); IUnknown_Release(CD.pUnk); } VariantClear(&vararg); IEnumConnections_Release(pEnum); } } /************************************************************************ * OLEFontImpl_QueryInterface (IUnknown) * * See Windows documentation for more details on IUnknown methods. */ static HRESULT WINAPI OLEFontImpl_QueryInterface( IFont* iface, REFIID riid, void** ppvObject) { OLEFontImpl *this = impl_from_IFont(iface); TRACE("(%p)->(%s, %p)\n", this, debugstr_guid(riid), ppvObject); *ppvObject = 0; if (IsEqualGUID(&IID_IUnknown, riid) || IsEqualGUID(&IID_IFont, riid)) { *ppvObject = this; } else if (IsEqualGUID(&IID_IDispatch, riid) || IsEqualGUID(&IID_IFontDisp, riid)) { *ppvObject = &this->IDispatch_iface; } else if (IsEqualGUID(&IID_IPersist, riid) || IsEqualGUID(&IID_IPersistStream, riid)) { *ppvObject = &this->IPersistStream_iface; } else if (IsEqualGUID(&IID_IConnectionPointContainer, riid)) { *ppvObject = &this->IConnectionPointContainer_iface; } else if (IsEqualGUID(&IID_IPersistPropertyBag, riid)) { *ppvObject = &this->IPersistPropertyBag_iface; } else if (IsEqualGUID(&IID_IPersistStreamInit, riid)) { *ppvObject = &this->IPersistStreamInit_iface; } if (!*ppvObject) { FIXME("() : asking for unsupported interface %s\n", debugstr_guid(riid)); return E_NOINTERFACE; } IFont_AddRef(iface); return S_OK; } /************************************************************************ * OLEFontImpl_AddRef (IUnknown) */ static ULONG WINAPI OLEFontImpl_AddRef( IFont* iface) { OLEFontImpl *this = impl_from_IFont(iface); TRACE("(%p)->(ref=%d)\n", this, this->ref); return InterlockedIncrement(&this->ref); } /************************************************************************ * OLEFontImpl_Release (IUnknown) */ static ULONG WINAPI OLEFontImpl_Release(IFont* iface) { OLEFontImpl *this = impl_from_IFont(iface); ULONG ref; TRACE("(%p)->(ref=%d)\n", this, this->ref); ref = InterlockedDecrement(&this->ref); if (ref == 0) { ULONG fontlist_refs = InterlockedDecrement(&ifont_cnt); /* Final IFont object so destroy font cache */ if (fontlist_refs == 0) { HFONTItem *item, *cursor2; EnterCriticalSection(&OLEFontImpl_csHFONTLIST); LIST_FOR_EACH_ENTRY_SAFE(item, cursor2, &OLEFontImpl_hFontList, HFONTItem, entry) HFONTItem_Delete(item); LeaveCriticalSection(&OLEFontImpl_csHFONTLIST); delete_dc(); } else { dec_int_ref(this->gdiFont); } OLEFontImpl_Destroy(this); } return ref; } typedef struct { short orig_cs; short avail_cs; } enum_data; static int CALLBACK font_enum_proc(const LOGFONTW *elf, const TEXTMETRICW *ntm, DWORD type, LPARAM lp) { enum_data *data = (enum_data*)lp; if(elf->lfCharSet == data->orig_cs) { data->avail_cs = data->orig_cs; return 0; } if(data->avail_cs == -1) data->avail_cs = elf->lfCharSet; return 1; } static void realize_font(OLEFontImpl *This) { LOGFONTW logFont; INT fontHeight; WCHAR text_face[LF_FACESIZE]; HDC hdc = get_dc(); HFONT old_font; TEXTMETRICW tm; if (!This->dirty) return; text_face[0] = 0; if(This->gdiFont) { old_font = SelectObject(hdc, This->gdiFont); GetTextFaceW(hdc, sizeof(text_face) / sizeof(text_face[0]), text_face); SelectObject(hdc, old_font); dec_int_ref(This->gdiFont); This->gdiFont = 0; } memset(&logFont, 0, sizeof(LOGFONTW)); lstrcpynW(logFont.lfFaceName, This->description.lpstrName, LF_FACESIZE); logFont.lfCharSet = This->description.sCharset; /* If the font name has been changed then enumerate all charsets and pick one that'll result in the font specified being selected */ if(text_face[0] && lstrcmpiW(text_face, This->description.lpstrName)) { enum_data data; data.orig_cs = This->description.sCharset; data.avail_cs = -1; logFont.lfCharSet = DEFAULT_CHARSET; EnumFontFamiliesExW(get_dc(), &logFont, font_enum_proc, (LPARAM)&data, 0); if(data.avail_cs != -1) logFont.lfCharSet = data.avail_cs; } /* * The height of the font returned by the get_Size property is the * height of the font in points multiplied by 10000... Using some * simple conversions and the ratio given by the application, it can * be converted to a height in pixels. * * Standard ratio is 72 / 2540, or 18 / 635 in lowest terms. * Ratio is applied here relative to the standard. */ fontHeight = MulDiv( This->description.cySize.s.Lo, This->cyLogical*635, This->cyHimetric*18 ); logFont.lfHeight = ((fontHeight%10000L)>5000L) ? (-fontHeight/10000L) - 1 : (-fontHeight/10000L); logFont.lfItalic = This->description.fItalic; logFont.lfUnderline = This->description.fUnderline; logFont.lfStrikeOut = This->description.fStrikethrough; logFont.lfWeight = This->description.sWeight; logFont.lfOutPrecision = OUT_CHARACTER_PRECIS; logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS; logFont.lfQuality = DEFAULT_QUALITY; logFont.lfPitchAndFamily = DEFAULT_PITCH; This->gdiFont = CreateFontIndirectW(&logFont); This->dirty = FALSE; add_hfontitem(This->gdiFont); /* Fixup the name and charset properties so that they match the selected font */ old_font = SelectObject(get_dc(), This->gdiFont); GetTextFaceW(hdc, sizeof(text_face) / sizeof(text_face[0]), text_face); if(lstrcmpiW(text_face, This->description.lpstrName)) { HeapFree(GetProcessHeap(), 0, This->description.lpstrName); This->description.lpstrName = strdupW(text_face); } GetTextMetricsW(hdc, &tm); This->description.sCharset = tm.tmCharSet; /* While we have it handy, stash the realized font height for use by get_Size() */ This->nRealHeight = tm.tmHeight - tm.tmInternalLeading; /* corresponds to LOGFONT lfHeight */ SelectObject(hdc, old_font); } /************************************************************************ * OLEFontImpl_get_Name (IFont) * * See Windows documentation for more details on IFont methods. */ static HRESULT WINAPI OLEFontImpl_get_Name( IFont* iface, BSTR* pname) { OLEFontImpl *this = impl_from_IFont(iface); TRACE("(%p)->(%p)\n", this, pname); if (pname==0) return E_POINTER; realize_font(this); if (this->description.lpstrName!=0) *pname = SysAllocString(this->description.lpstrName); else *pname = 0; return S_OK; } /************************************************************************ * OLEFontImpl_put_Name (IFont) */ static HRESULT WINAPI OLEFontImpl_put_Name( IFont* iface, BSTR name) { OLEFontImpl *This = impl_from_IFont(iface); TRACE("(%p)->(%p)\n", This, name); if (!name) return CTL_E_INVALIDPROPERTYVALUE; HeapFree(GetProcessHeap(), 0, This->description.lpstrName); This->description.lpstrName = strdupW(name); if (!This->description.lpstrName) return E_OUTOFMEMORY; TRACE("new name %s\n", debugstr_w(This->description.lpstrName)); OLEFont_SendNotify(This, DISPID_FONT_NAME); return S_OK; } /************************************************************************ * OLEFontImpl_get_Size (IFont) */ static HRESULT WINAPI OLEFontImpl_get_Size( IFont* iface, CY* psize) { OLEFontImpl *this = impl_from_IFont(iface); TRACE("(%p)->(%p)\n", this, psize); if (!psize) return E_POINTER; realize_font(this); /* * Convert realized font height in pixels to points descaled by current * scaling ratio then scaled up by 10000. */ psize->s.Lo = MulDiv(this->nRealHeight, this->cyHimetric * 72 * 10000, this->cyLogical * 2540); psize->s.Hi = 0; return S_OK; } /************************************************************************ * OLEFontImpl_put_Size (IFont) */ static HRESULT WINAPI OLEFontImpl_put_Size( IFont* iface, CY size) { OLEFontImpl *this = impl_from_IFont(iface); TRACE("(%p)->(%d)\n", this, size.s.Lo); this->description.cySize.s.Hi = 0; this->description.cySize.s.Lo = size.s.Lo; OLEFont_SendNotify(this, DISPID_FONT_SIZE); return S_OK; } /************************************************************************ * OLEFontImpl_get_Bold (IFont) * * See Windows documentation for more details on IFont methods. */ static HRESULT WINAPI OLEFontImpl_get_Bold( IFont* iface, BOOL* pbold) { OLEFontImpl *this = impl_from_IFont(iface); TRACE("(%p)->(%p)\n", this, pbold); if (!pbold) return E_POINTER; realize_font(this); *pbold = this->description.sWeight > 550; return S_OK; } /************************************************************************ * OLEFontImpl_put_Bold (IFont) */ static HRESULT WINAPI OLEFontImpl_put_Bold( IFont* iface, BOOL bold) { OLEFontImpl *this = impl_from_IFont(iface); TRACE("(%p)->(%d)\n", this, bold); this->description.sWeight = bold ? FW_BOLD : FW_NORMAL; OLEFont_SendNotify(this, DISPID_FONT_BOLD); return S_OK; } /************************************************************************ * OLEFontImpl_get_Italic (IFont) */ static HRESULT WINAPI OLEFontImpl_get_Italic( IFont* iface, BOOL* pitalic) { OLEFontImpl *this = impl_from_IFont(iface); TRACE("(%p)->(%p)\n", this, pitalic); if (pitalic==0) return E_POINTER; realize_font(this); *pitalic = this->description.fItalic; return S_OK; } /************************************************************************ * OLEFontImpl_put_Italic (IFont) */ static HRESULT WINAPI OLEFontImpl_put_Italic( IFont* iface, BOOL italic) { OLEFontImpl *this = impl_from_IFont(iface); TRACE("(%p)->(%d)\n", this, italic); this->description.fItalic = italic; OLEFont_SendNotify(this, DISPID_FONT_ITALIC); return S_OK; } /************************************************************************ * OLEFontImpl_get_Underline (IFont) */ static HRESULT WINAPI OLEFontImpl_get_Underline( IFont* iface, BOOL* punderline) { OLEFontImpl *this = impl_from_IFont(iface); TRACE("(%p)->(%p)\n", this, punderline); if (punderline==0) return E_POINTER; realize_font(this); *punderline = this->description.fUnderline; return S_OK; } /************************************************************************ * OLEFontImpl_put_Underline (IFont) */ static HRESULT WINAPI OLEFontImpl_put_Underline( IFont* iface, BOOL underline) { OLEFontImpl *this = impl_from_IFont(iface); TRACE("(%p)->(%d)\n", this, underline); this->description.fUnderline = underline; OLEFont_SendNotify(this, DISPID_FONT_UNDER); return S_OK; } /************************************************************************ * OLEFontImpl_get_Strikethrough (IFont) */ static HRESULT WINAPI OLEFontImpl_get_Strikethrough( IFont* iface, BOOL* pstrikethrough) { OLEFontImpl *this = impl_from_IFont(iface); TRACE("(%p)->(%p)\n", this, pstrikethrough); if (pstrikethrough==0) return E_POINTER; realize_font(this); *pstrikethrough = this->description.fStrikethrough; return S_OK; } /************************************************************************ * OLEFontImpl_put_Strikethrough (IFont) */ static HRESULT WINAPI OLEFontImpl_put_Strikethrough( IFont* iface, BOOL strikethrough) { OLEFontImpl *this = impl_from_IFont(iface); TRACE("(%p)->(%d)\n", this, strikethrough); this->description.fStrikethrough = strikethrough; OLEFont_SendNotify(this, DISPID_FONT_STRIKE); return S_OK; } /************************************************************************ * OLEFontImpl_get_Weight (IFont) */ static HRESULT WINAPI OLEFontImpl_get_Weight( IFont* iface, short* pweight) { OLEFontImpl *this = impl_from_IFont(iface); TRACE("(%p)->(%p)\n", this, pweight); if (pweight==0) return E_POINTER; realize_font(this); *pweight = this->description.sWeight; return S_OK; } /************************************************************************ * OLEFontImpl_put_Weight (IFont) */ static HRESULT WINAPI OLEFontImpl_put_Weight( IFont* iface, short weight) { OLEFontImpl *this = impl_from_IFont(iface); TRACE("(%p)->(%d)\n", this, weight); this->description.sWeight = weight; OLEFont_SendNotify(this, DISPID_FONT_WEIGHT); return S_OK; } /************************************************************************ * OLEFontImpl_get_Charset (IFont) */ static HRESULT WINAPI OLEFontImpl_get_Charset( IFont* iface, short* pcharset) { OLEFontImpl *this = impl_from_IFont(iface); TRACE("(%p)->(%p)\n", this, pcharset); if (pcharset==0) return E_POINTER; realize_font(this); *pcharset = this->description.sCharset; return S_OK; } /************************************************************************ * OLEFontImpl_put_Charset (IFont) */ static HRESULT WINAPI OLEFontImpl_put_Charset( IFont* iface, short charset) { OLEFontImpl *this = impl_from_IFont(iface); TRACE("(%p)->(%d)\n", this, charset); this->description.sCharset = charset; OLEFont_SendNotify(this, DISPID_FONT_CHARSET); return S_OK; } /************************************************************************ * OLEFontImpl_get_hFont (IFont) */ static HRESULT WINAPI OLEFontImpl_get_hFont( IFont* iface, HFONT* phfont) { OLEFontImpl *this = impl_from_IFont(iface); TRACE("(%p)->(%p)\n", this, phfont); if (phfont==NULL) return E_POINTER; realize_font(this); *phfont = this->gdiFont; TRACE("Returning %p\n", *phfont); return S_OK; } /************************************************************************ * OLEFontImpl_Clone (IFont) */ static HRESULT WINAPI OLEFontImpl_Clone( IFont* iface, IFont** ppfont) { OLEFontImpl *this = impl_from_IFont(iface); OLEFontImpl* newObject; TRACE("(%p)->(%p)\n", this, ppfont); if (ppfont == NULL) return E_POINTER; *ppfont = NULL; newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(OLEFontImpl)); if (newObject==NULL) return E_OUTOFMEMORY; *newObject = *this; /* allocate separate buffer */ newObject->description.lpstrName = strdupW(this->description.lpstrName); /* Increment internal ref in hfont item list */ if(newObject->gdiFont) inc_int_ref(newObject->gdiFont); InterlockedIncrement(&ifont_cnt); newObject->pPropertyNotifyCP = NULL; newObject->pFontEventsCP = NULL; CreateConnectionPoint((IUnknown*)newObject, &IID_IPropertyNotifySink, &newObject->pPropertyNotifyCP); CreateConnectionPoint((IUnknown*)newObject, &IID_IFontEventsDisp, &newObject->pFontEventsCP); if (!newObject->pPropertyNotifyCP || !newObject->pFontEventsCP) { OLEFontImpl_Destroy(newObject); return E_OUTOFMEMORY; } /* The cloned object starts with a reference count of 1 */ newObject->ref = 1; *ppfont = &newObject->IFont_iface; return S_OK; } /************************************************************************ * OLEFontImpl_IsEqual (IFont) */ static HRESULT WINAPI OLEFontImpl_IsEqual( IFont* iface, IFont* pFontOther) { OLEFontImpl *left = impl_from_IFont(iface); OLEFontImpl *right = impl_from_IFont(pFontOther); INT ret; INT left_len,right_len; if(pFontOther == NULL) return E_POINTER; else if (left->description.cySize.s.Lo != right->description.cySize.s.Lo) return S_FALSE; else if (left->description.cySize.s.Hi != right->description.cySize.s.Hi) return S_FALSE; else if (left->description.sWeight != right->description.sWeight) return S_FALSE; else if (left->description.sCharset != right->description.sCharset) return S_FALSE; else if (left->description.fItalic != right->description.fItalic) return S_FALSE; else if (left->description.fUnderline != right->description.fUnderline) return S_FALSE; else if (left->description.fStrikethrough != right->description.fStrikethrough) return S_FALSE; /* Check from string */ left_len = strlenW(left->description.lpstrName); right_len = strlenW(right->description.lpstrName); ret = CompareStringW(0,0,left->description.lpstrName, left_len, right->description.lpstrName, right_len); if (ret != CSTR_EQUAL) return S_FALSE; return S_OK; } /************************************************************************ * OLEFontImpl_SetRatio (IFont) */ static HRESULT WINAPI OLEFontImpl_SetRatio( IFont* iface, LONG cyLogical, LONG cyHimetric) { OLEFontImpl *this = impl_from_IFont(iface); TRACE("(%p)->(%d, %d)\n", this, cyLogical, cyHimetric); if(cyLogical == 0 || cyHimetric == 0) return E_INVALIDARG; this->cyLogical = cyLogical; this->cyHimetric = cyHimetric; this->dirty = TRUE; return S_OK; } /************************************************************************ * OLEFontImpl_QueryTextMetrics (IFont) */ static HRESULT WINAPI OLEFontImpl_QueryTextMetrics( IFont* iface, TEXTMETRICOLE* ptm) { HDC hdcRef; HFONT hOldFont, hNewFont; hdcRef = GetDC(0); IFont_get_hFont(iface, &hNewFont); hOldFont = SelectObject(hdcRef, hNewFont); GetTextMetricsW(hdcRef, ptm); SelectObject(hdcRef, hOldFont); ReleaseDC(0, hdcRef); return S_OK; } /************************************************************************ * OLEFontImpl_AddRefHfont (IFont) */ static HRESULT WINAPI OLEFontImpl_AddRefHfont( IFont* iface, HFONT hfont) { OLEFontImpl *this = impl_from_IFont(iface); TRACE("(%p)->(%p)\n", this, hfont); if (!hfont) return E_INVALIDARG; return inc_ext_ref(hfont); } /************************************************************************ * OLEFontImpl_ReleaseHfont (IFont) */ static HRESULT WINAPI OLEFontImpl_ReleaseHfont( IFont* iface, HFONT hfont) { OLEFontImpl *this = impl_from_IFont(iface); TRACE("(%p)->(%p)\n", this, hfont); if (!hfont) return E_INVALIDARG; return dec_ext_ref(hfont); } /************************************************************************ * OLEFontImpl_SetHdc (IFont) */ static HRESULT WINAPI OLEFontImpl_SetHdc( IFont* iface, HDC hdc) { OLEFontImpl *this = impl_from_IFont(iface); FIXME("(%p)->(%p): Stub\n", this, hdc); return E_NOTIMPL; } static const IFontVtbl OLEFontImpl_VTable = { OLEFontImpl_QueryInterface, OLEFontImpl_AddRef, OLEFontImpl_Release, OLEFontImpl_get_Name, OLEFontImpl_put_Name, OLEFontImpl_get_Size, OLEFontImpl_put_Size, OLEFontImpl_get_Bold, OLEFontImpl_put_Bold, OLEFontImpl_get_Italic, OLEFontImpl_put_Italic, OLEFontImpl_get_Underline, OLEFontImpl_put_Underline, OLEFontImpl_get_Strikethrough, OLEFontImpl_put_Strikethrough, OLEFontImpl_get_Weight, OLEFontImpl_put_Weight, OLEFontImpl_get_Charset, OLEFontImpl_put_Charset, OLEFontImpl_get_hFont, OLEFontImpl_Clone, OLEFontImpl_IsEqual, OLEFontImpl_SetRatio, OLEFontImpl_QueryTextMetrics, OLEFontImpl_AddRefHfont, OLEFontImpl_ReleaseHfont, OLEFontImpl_SetHdc }; /************************************************************************ * OLEFontImpl_IDispatch_QueryInterface (IUnknown) */ static HRESULT WINAPI OLEFontImpl_IDispatch_QueryInterface( IDispatch* iface, REFIID riid, VOID** ppvoid) { OLEFontImpl *this = impl_from_IDispatch(iface); return IFont_QueryInterface(&this->IFont_iface, riid, ppvoid); } /************************************************************************ * OLEFontImpl_IDispatch_Release (IUnknown) */ static ULONG WINAPI OLEFontImpl_IDispatch_Release( IDispatch* iface) { OLEFontImpl *this = impl_from_IDispatch(iface); return IFont_Release(&this->IFont_iface); } /************************************************************************ * OLEFontImpl_IDispatch_AddRef (IUnknown) */ static ULONG WINAPI OLEFontImpl_IDispatch_AddRef( IDispatch* iface) { OLEFontImpl *this = impl_from_IDispatch(iface); return IFont_AddRef(&this->IFont_iface); } /************************************************************************ * OLEFontImpl_GetTypeInfoCount (IDispatch) */ static HRESULT WINAPI OLEFontImpl_GetTypeInfoCount( IDispatch* iface, unsigned int* pctinfo) { OLEFontImpl *this = impl_from_IDispatch(iface); TRACE("(%p)->(%p)\n", this, pctinfo); *pctinfo = 1; return S_OK; } /************************************************************************ * OLEFontImpl_GetTypeInfo (IDispatch) */ static HRESULT WINAPI OLEFontImpl_GetTypeInfo( IDispatch* iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo) { static const WCHAR stdole2tlb[] = {'s','t','d','o','l','e','2','.','t','l','b',0}; ITypeLib *tl; HRESULT hres; OLEFontImpl *this = impl_from_IDispatch(iface); TRACE("(%p, iTInfo=%d, lcid=%04x, %p)\n", this, iTInfo, (int)lcid, ppTInfo); if (iTInfo != 0) return E_FAIL; hres = LoadTypeLib(stdole2tlb, &tl); if (FAILED(hres)) { ERR("Could not load the stdole2.tlb?\n"); return hres; } hres = ITypeLib_GetTypeInfoOfGuid(tl, &IID_IFontDisp, ppTInfo); ITypeLib_Release(tl); if (FAILED(hres)) { FIXME("Did not IDispatch typeinfo from typelib, hres %x\n",hres); } return hres; } /************************************************************************ * OLEFontImpl_GetIDsOfNames (IDispatch) */ static HRESULT WINAPI OLEFontImpl_GetIDsOfNames( IDispatch* iface, REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgDispId) { ITypeInfo * pTInfo; HRESULT hres; OLEFontImpl *this = impl_from_IDispatch(iface); TRACE("(%p,%s,%p,cNames=%d,lcid=%04x,%p)\n", this, debugstr_guid(riid), rgszNames, cNames, (int)lcid, rgDispId); if (cNames == 0) return E_INVALIDARG; hres = IDispatch_GetTypeInfo(iface, 0, lcid, &pTInfo); if (FAILED(hres)) { ERR("GetTypeInfo failed.\n"); return hres; } /* convert names to DISPIDs */ hres = DispGetIDsOfNames (pTInfo, rgszNames, cNames, rgDispId); ITypeInfo_Release(pTInfo); return hres; } /************************************************************************ * OLEFontImpl_Invoke (IDispatch) * * Note: Do not call _put_Xxx methods, since setting things here * should not call notify functions as I found out debugging the generic * MS VB5 installer. */ static HRESULT WINAPI OLEFontImpl_Invoke( IDispatch* iface, DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult, EXCEPINFO* pExepInfo, UINT* puArgErr) { OLEFontImpl *this = impl_from_IDispatch(iface); HRESULT hr; TRACE("%p->(%d,%s,0x%x,0x%x,%p,%p,%p,%p)\n", this, dispIdMember, debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExepInfo, puArgErr); /* validate parameters */ if (!IsEqualIID(riid, &IID_NULL)) { ERR("riid was %s instead of IID_NULL\n", debugstr_guid(riid)); return DISP_E_UNKNOWNINTERFACE; } if (wFlags & DISPATCH_PROPERTYGET) { if (!pVarResult) { ERR("null pVarResult not allowed when DISPATCH_PROPERTYGET specified\n"); return DISP_E_PARAMNOTOPTIONAL; } } else if (wFlags & DISPATCH_PROPERTYPUT) { if (!pDispParams) { ERR("null pDispParams not allowed when DISPATCH_PROPERTYPUT specified\n"); return DISP_E_PARAMNOTOPTIONAL; } if (pDispParams->cArgs != 1) { ERR("param count for DISPATCH_PROPERTYPUT was %d instead of 1\n", pDispParams->cArgs); return DISP_E_BADPARAMCOUNT; } } else { ERR("one of DISPATCH_PROPERTYGET or DISPATCH_PROPERTYPUT must be specified\n"); return DISP_E_MEMBERNOTFOUND; } switch (dispIdMember) { case DISPID_FONT_NAME: if (wFlags & DISPATCH_PROPERTYGET) { V_VT(pVarResult) = VT_BSTR; return IFont_get_Name(&this->IFont_iface, &V_BSTR(pVarResult)); } else { VARIANTARG vararg; VariantInit(&vararg); hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_BSTR); if (FAILED(hr)) return hr; hr = IFont_put_Name(&this->IFont_iface, V_BSTR(&vararg)); VariantClear(&vararg); return hr; } break; case DISPID_FONT_BOLD: if (wFlags & DISPATCH_PROPERTYGET) { BOOL value; hr = IFont_get_Bold(&this->IFont_iface, &value); V_VT(pVarResult) = VT_BOOL; V_BOOL(pVarResult) = value ? VARIANT_TRUE : VARIANT_FALSE; return hr; } else { VARIANTARG vararg; VariantInit(&vararg); hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_BOOL); if (FAILED(hr)) return hr; hr = IFont_put_Bold(&this->IFont_iface, V_BOOL(&vararg)); VariantClear(&vararg); return hr; } break; case DISPID_FONT_ITALIC: if (wFlags & DISPATCH_PROPERTYGET) { BOOL value; hr = IFont_get_Italic(&this->IFont_iface, &value); V_VT(pVarResult) = VT_BOOL; V_BOOL(pVarResult) = value ? VARIANT_TRUE : VARIANT_FALSE; return hr; } else { VARIANTARG vararg; VariantInit(&vararg); hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_BOOL); if (FAILED(hr)) return hr; hr = IFont_put_Italic(&this->IFont_iface, V_BOOL(&vararg)); VariantClear(&vararg); return hr; } break; case DISPID_FONT_UNDER: if (wFlags & DISPATCH_PROPERTYGET) { BOOL value; hr = IFont_get_Underline(&this->IFont_iface, &value); V_VT(pVarResult) = VT_BOOL; V_BOOL(pVarResult) = value ? VARIANT_TRUE : VARIANT_FALSE; return hr; } else { VARIANTARG vararg; VariantInit(&vararg); hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_BOOL); if (FAILED(hr)) return hr; hr = IFont_put_Underline(&this->IFont_iface, V_BOOL(&vararg)); VariantClear(&vararg); return hr; } break; case DISPID_FONT_STRIKE: if (wFlags & DISPATCH_PROPERTYGET) { BOOL value; hr = IFont_get_Strikethrough(&this->IFont_iface, &value); V_VT(pVarResult) = VT_BOOL; V_BOOL(pVarResult) = value ? VARIANT_TRUE : VARIANT_FALSE; return hr; } else { VARIANTARG vararg; VariantInit(&vararg); hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_BOOL); if (FAILED(hr)) return hr; hr = IFont_put_Strikethrough(&this->IFont_iface, V_BOOL(&vararg)); VariantClear(&vararg); return hr; } break; case DISPID_FONT_SIZE: if (wFlags & DISPATCH_PROPERTYGET) { V_VT(pVarResult) = VT_CY; return IFont_get_Size(&this->IFont_iface, &V_CY(pVarResult)); } else { VARIANTARG vararg; VariantInit(&vararg); hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_CY); if (FAILED(hr)) return hr; hr = IFont_put_Size(&this->IFont_iface, V_CY(&vararg)); VariantClear(&vararg); return hr; } break; case DISPID_FONT_WEIGHT: if (wFlags & DISPATCH_PROPERTYGET) { V_VT(pVarResult) = VT_I2; return IFont_get_Weight(&this->IFont_iface, &V_I2(pVarResult)); } else { VARIANTARG vararg; VariantInit(&vararg); hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I2); if (FAILED(hr)) return hr; hr = IFont_put_Weight(&this->IFont_iface, V_I2(&vararg)); VariantClear(&vararg); return hr; } break; case DISPID_FONT_CHARSET: if (wFlags & DISPATCH_PROPERTYGET) { V_VT(pVarResult) = VT_I2; return OLEFontImpl_get_Charset(&this->IFont_iface, &V_I2(pVarResult)); } else { VARIANTARG vararg; VariantInit(&vararg); hr = VariantChangeTypeEx(&vararg, &pDispParams->rgvarg[0], lcid, 0, VT_I2); if (FAILED(hr)) return hr; hr = IFont_put_Charset(&this->IFont_iface, V_I2(&vararg)); VariantClear(&vararg); return hr; } break; default: ERR("member not found for dispid 0x%x\n", dispIdMember); return DISP_E_MEMBERNOTFOUND; } } static const IDispatchVtbl OLEFontImpl_IDispatch_VTable = { OLEFontImpl_IDispatch_QueryInterface, OLEFontImpl_IDispatch_AddRef, OLEFontImpl_IDispatch_Release, OLEFontImpl_GetTypeInfoCount, OLEFontImpl_GetTypeInfo, OLEFontImpl_GetIDsOfNames, OLEFontImpl_Invoke }; /************************************************************************ * OLEFontImpl_IPersistStream_QueryInterface (IUnknown) */ static HRESULT WINAPI OLEFontImpl_IPersistStream_QueryInterface( IPersistStream* iface, REFIID riid, VOID** ppvoid) { OLEFontImpl *this = impl_from_IPersistStream(iface); return IFont_QueryInterface(&this->IFont_iface, riid, ppvoid); } /************************************************************************ * OLEFontImpl_IPersistStream_Release (IUnknown) */ static ULONG WINAPI OLEFontImpl_IPersistStream_Release( IPersistStream* iface) { OLEFontImpl *this = impl_from_IPersistStream(iface); return IFont_Release(&this->IFont_iface); } /************************************************************************ * OLEFontImpl_IPersistStream_AddRef (IUnknown) */ static ULONG WINAPI OLEFontImpl_IPersistStream_AddRef( IPersistStream* iface) { OLEFontImpl *this = impl_from_IPersistStream(iface); return IFont_AddRef(&this->IFont_iface); } /************************************************************************ * OLEFontImpl_GetClassID (IPersistStream) */ static HRESULT WINAPI OLEFontImpl_GetClassID( IPersistStream* iface, CLSID* pClassID) { TRACE("(%p,%p)\n",iface,pClassID); if (pClassID==0) return E_POINTER; *pClassID = CLSID_StdFont; return S_OK; } /************************************************************************ * OLEFontImpl_IsDirty (IPersistStream) * * See Windows documentation for more details on IPersistStream methods. */ static HRESULT WINAPI OLEFontImpl_IsDirty( IPersistStream* iface) { TRACE("(%p)\n",iface); return S_OK; } /************************************************************************ * OLEFontImpl_Load (IPersistStream) * * See Windows documentation for more details on IPersistStream methods. * * This is the format of the standard font serialization as far as I * know * * Offset Type Value Comment * 0x0000 Byte Unknown Probably a version number, contains 0x01 * 0x0001 Short Charset Charset value from the FONTDESC structure * 0x0003 Byte Attributes Flags defined as follows: * 00000010 - Italic * 00000100 - Underline * 00001000 - Strikethrough * 0x0004 Short Weight Weight value from FONTDESC structure * 0x0006 DWORD size "Low" portion of the cySize member of the FONTDESC * structure/ * 0x000A Byte name length Length of the font name string (no null character) * 0x000B String name Name of the font (ASCII, no nul character) */ static HRESULT WINAPI OLEFontImpl_Load( IPersistStream* iface, IStream* pLoadStream) { OLEFontImpl *this = impl_from_IPersistStream(iface); BYTE version, attributes, string_size; char readBuffer[0x100]; ULONG cbRead; INT len; /* Version */ IStream_Read(pLoadStream, &version, sizeof(BYTE), &cbRead); if ((cbRead != sizeof(BYTE)) || (version != 0x01)) return E_FAIL; /* Charset */ IStream_Read(pLoadStream, &this->description.sCharset, sizeof(WORD), &cbRead); if (cbRead != sizeof(WORD)) return E_FAIL; /* Attributes */ IStream_Read(pLoadStream, &attributes, sizeof(BYTE), &cbRead); if (cbRead != sizeof(BYTE)) return E_FAIL; this->description.fItalic = (attributes & FONTPERSIST_ITALIC) != 0; this->description.fStrikethrough = (attributes & FONTPERSIST_STRIKETHROUGH) != 0; this->description.fUnderline = (attributes & FONTPERSIST_UNDERLINE) != 0; /* Weight */ IStream_Read(pLoadStream, &this->description.sWeight, sizeof(WORD), &cbRead); if (cbRead != sizeof(WORD)) return E_FAIL; /* Size */ IStream_Read(pLoadStream, &this->description.cySize.s.Lo, sizeof(DWORD), &cbRead); if (cbRead != sizeof(DWORD)) return E_FAIL; this->description.cySize.s.Hi = 0; /* Name */ IStream_Read(pLoadStream, &string_size, sizeof(BYTE), &cbRead); if (cbRead != sizeof(BYTE)) return E_FAIL; IStream_Read(pLoadStream, readBuffer, string_size, &cbRead); if (cbRead != string_size) return E_FAIL; HeapFree(GetProcessHeap(), 0, this->description.lpstrName); len = MultiByteToWideChar( CP_ACP, 0, readBuffer, string_size, NULL, 0 ); this->description.lpstrName = HeapAlloc( GetProcessHeap(), 0, (len+1) * sizeof(WCHAR) ); MultiByteToWideChar( CP_ACP, 0, readBuffer, string_size, this->description.lpstrName, len ); this->description.lpstrName[len] = 0; /* Ensure use of this font causes a new one to be created */ dec_int_ref(this->gdiFont); this->gdiFont = 0; this->dirty = TRUE; return S_OK; } /************************************************************************ * OLEFontImpl_Save (IPersistStream) */ static HRESULT WINAPI OLEFontImpl_Save( IPersistStream* iface, IStream* pOutStream, BOOL fClearDirty) { OLEFontImpl *this = impl_from_IPersistStream(iface); BYTE attributes, string_size; const BYTE version = 0x01; char* writeBuffer = NULL; ULONG written; TRACE("(%p)->(%p %d)\n", this, pOutStream, fClearDirty); /* Version */ IStream_Write(pOutStream, &version, sizeof(BYTE), &written); if (written != sizeof(BYTE)) return E_FAIL; /* Charset */ IStream_Write(pOutStream, &this->description.sCharset, sizeof(WORD), &written); if (written != sizeof(WORD)) return E_FAIL; /* Attributes */ attributes = 0; if (this->description.fItalic) attributes |= FONTPERSIST_ITALIC; if (this->description.fStrikethrough) attributes |= FONTPERSIST_STRIKETHROUGH; if (this->description.fUnderline) attributes |= FONTPERSIST_UNDERLINE; IStream_Write(pOutStream, &attributes, sizeof(BYTE), &written); if (written != sizeof(BYTE)) return E_FAIL; /* Weight */ IStream_Write(pOutStream, &this->description.sWeight, sizeof(WORD), &written); if (written != sizeof(WORD)) return E_FAIL; /* Size */ IStream_Write(pOutStream, &this->description.cySize.s.Lo, sizeof(DWORD), &written); if (written != sizeof(DWORD)) return E_FAIL; /* FontName */ if (this->description.lpstrName) string_size = WideCharToMultiByte( CP_ACP, 0, this->description.lpstrName, strlenW(this->description.lpstrName), NULL, 0, NULL, NULL ); else string_size = 0; IStream_Write(pOutStream, &string_size, sizeof(BYTE), &written); if (written != sizeof(BYTE)) return E_FAIL; if (string_size) { if (!(writeBuffer = HeapAlloc( GetProcessHeap(), 0, string_size ))) return E_OUTOFMEMORY; WideCharToMultiByte( CP_ACP, 0, this->description.lpstrName, strlenW(this->description.lpstrName), writeBuffer, string_size, NULL, NULL ); IStream_Write(pOutStream, writeBuffer, string_size, &written); HeapFree(GetProcessHeap(), 0, writeBuffer); if (written != string_size) return E_FAIL; } return S_OK; } /************************************************************************ * OLEFontImpl_GetSizeMax (IPersistStream) */ static HRESULT WINAPI OLEFontImpl_GetSizeMax( IPersistStream* iface, ULARGE_INTEGER* pcbSize) { OLEFontImpl *this = impl_from_IPersistStream(iface); if (pcbSize==NULL) return E_POINTER; pcbSize->u.HighPart = 0; pcbSize->u.LowPart = 0; pcbSize->u.LowPart += sizeof(BYTE); /* Version */ pcbSize->u.LowPart += sizeof(WORD); /* Lang code */ pcbSize->u.LowPart += sizeof(BYTE); /* Flags */ pcbSize->u.LowPart += sizeof(WORD); /* Weight */ pcbSize->u.LowPart += sizeof(DWORD); /* Size */ pcbSize->u.LowPart += sizeof(BYTE); /* StrLength */ if (this->description.lpstrName!=0) pcbSize->u.LowPart += WideCharToMultiByte( CP_ACP, 0, this->description.lpstrName, strlenW(this->description.lpstrName), NULL, 0, NULL, NULL ); return S_OK; } static const IPersistStreamVtbl OLEFontImpl_IPersistStream_VTable = { OLEFontImpl_IPersistStream_QueryInterface, OLEFontImpl_IPersistStream_AddRef, OLEFontImpl_IPersistStream_Release, OLEFontImpl_GetClassID, OLEFontImpl_IsDirty, OLEFontImpl_Load, OLEFontImpl_Save, OLEFontImpl_GetSizeMax }; /************************************************************************ * OLEFontImpl_IConnectionPointContainer_QueryInterface (IUnknown) */ static HRESULT WINAPI OLEFontImpl_IConnectionPointContainer_QueryInterface( IConnectionPointContainer* iface, REFIID riid, VOID** ppvoid) { OLEFontImpl *this = impl_from_IConnectionPointContainer(iface); return IFont_QueryInterface(&this->IFont_iface, riid, ppvoid); } /************************************************************************ * OLEFontImpl_IConnectionPointContainer_Release (IUnknown) */ static ULONG WINAPI OLEFontImpl_IConnectionPointContainer_Release( IConnectionPointContainer* iface) { OLEFontImpl *this = impl_from_IConnectionPointContainer(iface); return IFont_Release(&this->IFont_iface); } /************************************************************************ * OLEFontImpl_IConnectionPointContainer_AddRef (IUnknown) */ static ULONG WINAPI OLEFontImpl_IConnectionPointContainer_AddRef( IConnectionPointContainer* iface) { OLEFontImpl *this = impl_from_IConnectionPointContainer(iface); return IFont_AddRef(&this->IFont_iface); } /************************************************************************ * OLEFontImpl_EnumConnectionPoints (IConnectionPointContainer) */ static HRESULT WINAPI OLEFontImpl_EnumConnectionPoints( IConnectionPointContainer* iface, IEnumConnectionPoints **ppEnum) { OLEFontImpl *this = impl_from_IConnectionPointContainer(iface); FIXME("(%p)->(%p): stub\n", this, ppEnum); return E_NOTIMPL; } /************************************************************************ * OLEFontImpl_FindConnectionPoint (IConnectionPointContainer) */ static HRESULT WINAPI OLEFontImpl_FindConnectionPoint( IConnectionPointContainer* iface, REFIID riid, IConnectionPoint **ppCp) { OLEFontImpl *this = impl_from_IConnectionPointContainer(iface); TRACE("(%p)->(%s, %p)\n", this, debugstr_guid(riid), ppCp); if(IsEqualIID(riid, &IID_IPropertyNotifySink)) { return IConnectionPoint_QueryInterface(this->pPropertyNotifyCP, &IID_IConnectionPoint, (LPVOID)ppCp); } else if(IsEqualIID(riid, &IID_IFontEventsDisp)) { return IConnectionPoint_QueryInterface(this->pFontEventsCP, &IID_IConnectionPoint, (LPVOID)ppCp); } else { FIXME("no connection point for %s\n", debugstr_guid(riid)); return CONNECT_E_NOCONNECTION; } } static const IConnectionPointContainerVtbl OLEFontImpl_IConnectionPointContainer_VTable = { OLEFontImpl_IConnectionPointContainer_QueryInterface, OLEFontImpl_IConnectionPointContainer_AddRef, OLEFontImpl_IConnectionPointContainer_Release, OLEFontImpl_EnumConnectionPoints, OLEFontImpl_FindConnectionPoint }; /************************************************************************ * OLEFontImpl implementation of IPersistPropertyBag. */ static HRESULT WINAPI OLEFontImpl_IPersistPropertyBag_QueryInterface( IPersistPropertyBag *iface, REFIID riid, LPVOID *ppvObj ) { OLEFontImpl *this = impl_from_IPersistPropertyBag(iface); return IFont_QueryInterface(&this->IFont_iface,riid,ppvObj); } static ULONG WINAPI OLEFontImpl_IPersistPropertyBag_AddRef( IPersistPropertyBag *iface ) { OLEFontImpl *this = impl_from_IPersistPropertyBag(iface); return IFont_AddRef(&this->IFont_iface); } static ULONG WINAPI OLEFontImpl_IPersistPropertyBag_Release( IPersistPropertyBag *iface ) { OLEFontImpl *this = impl_from_IPersistPropertyBag(iface); return IFont_Release(&this->IFont_iface); } static HRESULT WINAPI OLEFontImpl_IPersistPropertyBag_GetClassID( IPersistPropertyBag *iface, CLSID *classid ) { FIXME("(%p,%p), stub!\n", iface, classid); return E_FAIL; } static HRESULT WINAPI OLEFontImpl_IPersistPropertyBag_InitNew( IPersistPropertyBag *iface ) { FIXME("(%p), stub!\n", iface); return S_OK; } static HRESULT WINAPI OLEFontImpl_IPersistPropertyBag_Load( IPersistPropertyBag *iface, IPropertyBag* pPropBag, IErrorLog* pErrorLog ) { /* (from Visual Basic 6 property bag) Name = "MS Sans Serif" Size = 13.8 Charset = 0 Weight = 400 Underline = 0 'False Italic = 0 'False Strikethrough = 0 'False */ static const WCHAR sAttrName[] = {'N','a','m','e',0}; static const WCHAR sAttrSize[] = {'S','i','z','e',0}; static const WCHAR sAttrCharset[] = {'C','h','a','r','s','e','t',0}; static const WCHAR sAttrWeight[] = {'W','e','i','g','h','t',0}; static const WCHAR sAttrUnderline[] = {'U','n','d','e','r','l','i','n','e',0}; static const WCHAR sAttrItalic[] = {'I','t','a','l','i','c',0}; static const WCHAR sAttrStrikethrough[] = {'S','t','r','i','k','e','t','h','r','o','u','g','h',0}; OLEFontImpl *this = impl_from_IPersistPropertyBag(iface); VARIANT value; HRESULT iRes; VariantInit(&value); iRes = IPropertyBag_Read(pPropBag, sAttrName, &value, pErrorLog); if (iRes == S_OK) { iRes = VariantChangeType(&value, &value, 0, VT_BSTR); if (iRes == S_OK) iRes = IFont_put_Name(&this->IFont_iface, V_BSTR(&value)); } else if (iRes == E_INVALIDARG) iRes = S_OK; VariantClear(&value); if (iRes == S_OK) { iRes = IPropertyBag_Read(pPropBag, sAttrSize, &value, pErrorLog); if (iRes == S_OK) { iRes = VariantChangeType(&value, &value, 0, VT_CY); if (iRes == S_OK) iRes = IFont_put_Size(&this->IFont_iface, V_CY(&value)); } else if (iRes == E_INVALIDARG) iRes = S_OK; VariantClear(&value); } if (iRes == S_OK) { iRes = IPropertyBag_Read(pPropBag, sAttrCharset, &value, pErrorLog); if (iRes == S_OK) { iRes = VariantChangeType(&value, &value, 0, VT_I2); if (iRes == S_OK) iRes = IFont_put_Charset(&this->IFont_iface, V_I2(&value)); } else if (iRes == E_INVALIDARG) iRes = S_OK; VariantClear(&value); } if (iRes == S_OK) { iRes = IPropertyBag_Read(pPropBag, sAttrWeight, &value, pErrorLog); if (iRes == S_OK) { iRes = VariantChangeType(&value, &value, 0, VT_I2); if (iRes == S_OK) iRes = IFont_put_Weight(&this->IFont_iface, V_I2(&value)); } else if (iRes == E_INVALIDARG) iRes = S_OK; VariantClear(&value); } if (iRes == S_OK) { iRes = IPropertyBag_Read(pPropBag, sAttrUnderline, &value, pErrorLog); if (iRes == S_OK) { iRes = VariantChangeType(&value, &value, 0, VT_BOOL); if (iRes == S_OK) iRes = IFont_put_Underline(&this->IFont_iface, V_BOOL(&value)); } else if (iRes == E_INVALIDARG) iRes = S_OK; VariantClear(&value); } if (iRes == S_OK) { iRes = IPropertyBag_Read(pPropBag, sAttrItalic, &value, pErrorLog); if (iRes == S_OK) { iRes = VariantChangeType(&value, &value, 0, VT_BOOL); if (iRes == S_OK) iRes = IFont_put_Italic(&this->IFont_iface, V_BOOL(&value)); } else if (iRes == E_INVALIDARG) iRes = S_OK; VariantClear(&value); } if (iRes == S_OK) { iRes = IPropertyBag_Read(pPropBag, sAttrStrikethrough, &value, pErrorLog); if (iRes == S_OK) { iRes = VariantChangeType(&value, &value, 0, VT_BOOL); if (iRes == S_OK) IFont_put_Strikethrough(&this->IFont_iface, V_BOOL(&value)); } else if (iRes == E_INVALIDARG) iRes = S_OK; VariantClear(&value); } if (FAILED(iRes)) WARN("-- 0x%08x\n", iRes); return iRes; } static HRESULT WINAPI OLEFontImpl_IPersistPropertyBag_Save( IPersistPropertyBag *iface, IPropertyBag* pPropBag, BOOL fClearDirty, BOOL fSaveAllProperties ) { FIXME("(%p,%p,%d,%d), stub!\n", iface, pPropBag, fClearDirty, fSaveAllProperties); return E_FAIL; } static const IPersistPropertyBagVtbl OLEFontImpl_IPersistPropertyBag_VTable = { OLEFontImpl_IPersistPropertyBag_QueryInterface, OLEFontImpl_IPersistPropertyBag_AddRef, OLEFontImpl_IPersistPropertyBag_Release, OLEFontImpl_IPersistPropertyBag_GetClassID, OLEFontImpl_IPersistPropertyBag_InitNew, OLEFontImpl_IPersistPropertyBag_Load, OLEFontImpl_IPersistPropertyBag_Save }; /************************************************************************ * OLEFontImpl implementation of IPersistStreamInit. */ static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_QueryInterface( IPersistStreamInit *iface, REFIID riid, LPVOID *ppvObj ) { OLEFontImpl *this = impl_from_IPersistStreamInit(iface); return IFont_QueryInterface(&this->IFont_iface,riid,ppvObj); } static ULONG WINAPI OLEFontImpl_IPersistStreamInit_AddRef( IPersistStreamInit *iface ) { OLEFontImpl *this = impl_from_IPersistStreamInit(iface); return IFont_AddRef(&this->IFont_iface); } static ULONG WINAPI OLEFontImpl_IPersistStreamInit_Release( IPersistStreamInit *iface ) { OLEFontImpl *this = impl_from_IPersistStreamInit(iface); return IFont_Release(&this->IFont_iface); } static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_GetClassID( IPersistStreamInit *iface, CLSID *classid ) { FIXME("(%p,%p), stub!\n", iface, classid); return E_FAIL; } static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_IsDirty( IPersistStreamInit *iface ) { FIXME("(%p), stub!\n", iface); return E_FAIL; } static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_Load( IPersistStreamInit *iface, LPSTREAM pStm ) { FIXME("(%p,%p), stub!\n", iface, pStm); return E_FAIL; } static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_Save( IPersistStreamInit *iface, LPSTREAM pStm, BOOL fClearDirty ) { FIXME("(%p,%p,%d), stub!\n", iface, pStm, fClearDirty); return E_FAIL; } static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_GetSizeMax( IPersistStreamInit *iface, ULARGE_INTEGER *pcbSize ) { FIXME("(%p,%p), stub!\n", iface, pcbSize); return E_FAIL; } static HRESULT WINAPI OLEFontImpl_IPersistStreamInit_InitNew( IPersistStreamInit *iface ) { FIXME("(%p), stub!\n", iface); return S_OK; } static const IPersistStreamInitVtbl OLEFontImpl_IPersistStreamInit_VTable = { OLEFontImpl_IPersistStreamInit_QueryInterface, OLEFontImpl_IPersistStreamInit_AddRef, OLEFontImpl_IPersistStreamInit_Release, OLEFontImpl_IPersistStreamInit_GetClassID, OLEFontImpl_IPersistStreamInit_IsDirty, OLEFontImpl_IPersistStreamInit_Load, OLEFontImpl_IPersistStreamInit_Save, OLEFontImpl_IPersistStreamInit_GetSizeMax, OLEFontImpl_IPersistStreamInit_InitNew }; /************************************************************************ * OLEFontImpl_Construct * * This method will construct a new instance of the OLEFontImpl * class. * * The caller of this method must release the object when it's * done with it. */ static OLEFontImpl* OLEFontImpl_Construct(const FONTDESC *fontDesc) { OLEFontImpl* newObject; newObject = HeapAlloc(GetProcessHeap(), 0, sizeof(OLEFontImpl)); if (newObject==0) return newObject; newObject->IFont_iface.lpVtbl = &OLEFontImpl_VTable; newObject->IDispatch_iface.lpVtbl = &OLEFontImpl_IDispatch_VTable; newObject->IPersistStream_iface.lpVtbl = &OLEFontImpl_IPersistStream_VTable; newObject->IConnectionPointContainer_iface.lpVtbl = &OLEFontImpl_IConnectionPointContainer_VTable; newObject->IPersistPropertyBag_iface.lpVtbl = &OLEFontImpl_IPersistPropertyBag_VTable; newObject->IPersistStreamInit_iface.lpVtbl = &OLEFontImpl_IPersistStreamInit_VTable; newObject->ref = 1; newObject->description.cbSizeofstruct = sizeof(FONTDESC); newObject->description.lpstrName = strdupW(fontDesc->lpstrName); newObject->description.cySize = fontDesc->cySize; newObject->description.sWeight = fontDesc->sWeight; newObject->description.sCharset = fontDesc->sCharset; newObject->description.fItalic = fontDesc->fItalic; newObject->description.fUnderline = fontDesc->fUnderline; newObject->description.fStrikethrough = fontDesc->fStrikethrough; newObject->gdiFont = 0; newObject->dirty = TRUE; newObject->cyLogical = GetDeviceCaps(get_dc(), LOGPIXELSY); newObject->cyHimetric = 2540L; newObject->pPropertyNotifyCP = NULL; newObject->pFontEventsCP = NULL; CreateConnectionPoint((IUnknown*)&newObject->IFont_iface, &IID_IPropertyNotifySink, &newObject->pPropertyNotifyCP); CreateConnectionPoint((IUnknown*)&newObject->IFont_iface, &IID_IFontEventsDisp, &newObject->pFontEventsCP); if (!newObject->pPropertyNotifyCP || !newObject->pFontEventsCP) { OLEFontImpl_Destroy(newObject); return NULL; } InterlockedIncrement(&ifont_cnt); TRACE("returning %p\n", newObject); return newObject; } /************************************************************************ * OLEFontImpl_Destroy * * This method is called by the Release method when the reference * count goes down to 0. It will free all resources used by * this object. */ static void OLEFontImpl_Destroy(OLEFontImpl* fontDesc) { TRACE("(%p)\n", fontDesc); HeapFree(GetProcessHeap(), 0, fontDesc->description.lpstrName); if (fontDesc->pPropertyNotifyCP) IConnectionPoint_Release(fontDesc->pPropertyNotifyCP); if (fontDesc->pFontEventsCP) IConnectionPoint_Release(fontDesc->pFontEventsCP); HeapFree(GetProcessHeap(), 0, fontDesc); } /******************************************************************************* * StdFont ClassFactory */ typedef struct { /* IUnknown fields */ IClassFactory IClassFactory_iface; LONG ref; } IClassFactoryImpl; static inline IClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface) { return CONTAINING_RECORD(iface, IClassFactoryImpl, IClassFactory_iface); } static HRESULT WINAPI SFCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) { IClassFactoryImpl *This = impl_from_IClassFactory(iface); FIXME("(%p)->(%s,%p),stub!\n",This,debugstr_guid(riid),ppobj); return E_NOINTERFACE; } static ULONG WINAPI SFCF_AddRef(LPCLASSFACTORY iface) { IClassFactoryImpl *This = impl_from_IClassFactory(iface); return InterlockedIncrement(&This->ref); } static ULONG WINAPI SFCF_Release(LPCLASSFACTORY iface) { IClassFactoryImpl *This = impl_from_IClassFactory(iface); /* static class, won't be freed */ return InterlockedDecrement(&This->ref); } static HRESULT WINAPI SFCF_CreateInstance( LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj ) { return OleCreateFontIndirect(NULL,riid,ppobj); } static HRESULT WINAPI SFCF_LockServer(LPCLASSFACTORY iface,BOOL dolock) { IClassFactoryImpl *This = impl_from_IClassFactory(iface); FIXME("(%p)->(%d),stub!\n",This,dolock); return S_OK; } static const IClassFactoryVtbl SFCF_Vtbl = { SFCF_QueryInterface, SFCF_AddRef, SFCF_Release, SFCF_CreateInstance, SFCF_LockServer }; static IClassFactoryImpl STDFONT_CF = {{&SFCF_Vtbl}, 1 }; void _get_STDFONT_CF(LPVOID *ppv) { *ppv = &STDFONT_CF; }