| /* | |
| * Copyright 1999 Corel Corporation | |
| * Sean Langley | |
| * Copyright 2010 Geoffrey Hausheer | |
| * Copyright 2010 Piotr Caban for CodeWeavers | |
| * | |
| * 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 <stdarg.h> | |
| #define COBJMACROS | |
| #define NONAMELESSUNION | |
| #include "windef.h" | |
| #include "winbase.h" | |
| #include "wingdi.h" | |
| #include "ole2.h" | |
| #include "olectl.h" | |
| #include "oledlg.h" | |
| #include "wine/debug.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(ole); | |
| typedef struct { | |
| IPropertyPageSite IPropertyPageSite_iface; | |
| LCID lcid; | |
| LONG ref; | |
| } PropertyPageSite; | |
| static inline PropertyPageSite *impl_from_IPropertyPageSite(IPropertyPageSite *iface) | |
| { | |
| return CONTAINING_RECORD(iface, PropertyPageSite, IPropertyPageSite_iface); | |
| } | |
| static INT_PTR CALLBACK property_sheet_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) | |
| { | |
| IPropertyPage *property_page = (IPropertyPage*)GetWindowLongPtrW(hwnd, DWLP_USER); | |
| switch(msg) { | |
| case WM_INITDIALOG: { | |
| RECT rect; | |
| property_page = (IPropertyPage*)((LPPROPSHEETPAGEW)lparam)->lParam; | |
| GetClientRect(hwnd, &rect); | |
| IPropertyPage_Activate(property_page, hwnd, &rect, TRUE); | |
| IPropertyPage_Show(property_page, SW_SHOW); | |
| SetWindowLongPtrW(hwnd, DWLP_USER, (LONG_PTR)property_page); | |
| return FALSE; | |
| } | |
| case WM_DESTROY: | |
| IPropertyPage_Show(property_page, SW_HIDE); | |
| IPropertyPage_Deactivate(property_page); | |
| return FALSE; | |
| default: | |
| return FALSE; | |
| } | |
| } | |
| static HRESULT WINAPI PropertyPageSite_QueryInterface(IPropertyPageSite* iface, | |
| REFIID riid, void** ppv) | |
| { | |
| TRACE("(%p riid: %s)\n",iface, debugstr_guid(riid)); | |
| if(IsEqualGUID(&IID_IUnknown, riid) | |
| || IsEqualGUID(&IID_IPropertyPageSite, riid)) | |
| *ppv = iface; | |
| else { | |
| *ppv = NULL; | |
| return E_NOINTERFACE; | |
| } | |
| IUnknown_AddRef((IUnknown*)*ppv); | |
| return S_OK; | |
| } | |
| static ULONG WINAPI PropertyPageSite_AddRef(IPropertyPageSite* iface) | |
| { | |
| PropertyPageSite *this = impl_from_IPropertyPageSite(iface); | |
| LONG ref = InterlockedIncrement(&this->ref); | |
| TRACE("(%p) ref=%d\n", this, ref); | |
| return ref; | |
| } | |
| static ULONG WINAPI PropertyPageSite_Release(IPropertyPageSite* iface) | |
| { | |
| PropertyPageSite *this = impl_from_IPropertyPageSite(iface); | |
| LONG ref = InterlockedDecrement(&this->ref); | |
| TRACE("(%p) ref=%d\n", this, ref); | |
| if(!ref) | |
| HeapFree(GetProcessHeap(), 0, this); | |
| return ref; | |
| } | |
| static HRESULT WINAPI PropertyPageSite_OnStatusChange( | |
| IPropertyPageSite *iface, DWORD dwFlags) | |
| { | |
| TRACE("(%p, %x)\n", iface, dwFlags); | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI PropertyPageSite_GetLocaleID( | |
| IPropertyPageSite *iface, LCID *pLocaleID) | |
| { | |
| PropertyPageSite *this = impl_from_IPropertyPageSite(iface); | |
| TRACE("(%p, %p)\n", iface, pLocaleID); | |
| *pLocaleID = this->lcid; | |
| return S_OK; | |
| } | |
| static HRESULT WINAPI PropertyPageSite_GetPageContainer( | |
| IPropertyPageSite* iface, IUnknown** ppUnk) | |
| { | |
| FIXME("(%p, %p)\n", iface, ppUnk); | |
| return E_NOTIMPL; | |
| } | |
| static HRESULT WINAPI PropertyPageSite_TranslateAccelerator( | |
| IPropertyPageSite* iface, MSG *pMsg) | |
| { | |
| FIXME("(%p, %p)\n", iface, pMsg); | |
| return E_NOTIMPL; | |
| } | |
| static IPropertyPageSiteVtbl PropertyPageSiteVtbl = { | |
| PropertyPageSite_QueryInterface, | |
| PropertyPageSite_AddRef, | |
| PropertyPageSite_Release, | |
| PropertyPageSite_OnStatusChange, | |
| PropertyPageSite_GetLocaleID, | |
| PropertyPageSite_GetPageContainer, | |
| PropertyPageSite_TranslateAccelerator | |
| }; | |
| /*********************************************************************** | |
| * OleCreatePropertyFrameIndirect (OLEAUT32.416) | |
| */ | |
| HRESULT WINAPI OleCreatePropertyFrameIndirect(LPOCPFIPARAMS lpParams) | |
| { | |
| static const WCHAR comctlW[] = { 'c','o','m','c','t','l','3','2','.','d','l','l',0 }; | |
| PROPSHEETHEADERW property_sheet; | |
| PROPSHEETPAGEW property_sheet_page; | |
| struct { | |
| DLGTEMPLATE template; | |
| WORD menu; | |
| WORD class; | |
| WORD title; | |
| } *dialogs; | |
| IPropertyPage **property_page; | |
| PropertyPageSite *property_page_site; | |
| HRESULT res; | |
| ULONG i; | |
| HMODULE hcomctl; | |
| HRSRC property_sheet_dialog_find = NULL; | |
| HGLOBAL property_sheet_dialog_load = NULL; | |
| WCHAR *property_sheet_dialog_data = NULL; | |
| HDC hdc; | |
| LOGFONTW font_desc; | |
| HFONT hfont; | |
| LONG font_width = 4, font_height = 8; | |
| if(!lpParams) | |
| return E_POINTER; | |
| TRACE("(%d %p %d %d %s %d %p %d %p %d %d)\n", lpParams->cbStructSize, | |
| lpParams->hWndOwner, lpParams->x, lpParams->y, | |
| debugstr_w(lpParams->lpszCaption), lpParams->cObjects, | |
| lpParams->lplpUnk, lpParams->cPages, lpParams->lpPages, | |
| lpParams->lcid, lpParams->dispidInitialProperty); | |
| if(!lpParams->lplpUnk || !lpParams->lpPages) | |
| return E_POINTER; | |
| if(lpParams->cbStructSize != sizeof(OCPFIPARAMS)) { | |
| WARN("incorrect structure size\n"); | |
| return E_INVALIDARG; | |
| } | |
| if(lpParams->dispidInitialProperty) | |
| FIXME("dispidInitialProperty not yet implemented\n"); | |
| hdc = GetDC(NULL); | |
| hcomctl = LoadLibraryW(comctlW); | |
| if(hcomctl) | |
| property_sheet_dialog_find = FindResourceW(hcomctl, | |
| MAKEINTRESOURCEW(1006 /*IDD_PROPSHEET*/), (LPWSTR)RT_DIALOG); | |
| if(property_sheet_dialog_find) | |
| property_sheet_dialog_load = LoadResource(hcomctl, property_sheet_dialog_find); | |
| if(property_sheet_dialog_load) | |
| property_sheet_dialog_data = LockResource(property_sheet_dialog_load); | |
| if(property_sheet_dialog_data) { | |
| if(property_sheet_dialog_data[1] == 0xffff) { | |
| ERR("Expected DLGTEMPLATE structure\n"); | |
| FreeLibrary(hcomctl); | |
| return E_OUTOFMEMORY; | |
| } | |
| property_sheet_dialog_data += sizeof(DLGTEMPLATE)/sizeof(WCHAR); | |
| /* Skip menu, class and title */ | |
| property_sheet_dialog_data += lstrlenW(property_sheet_dialog_data)+1; | |
| property_sheet_dialog_data += lstrlenW(property_sheet_dialog_data)+1; | |
| property_sheet_dialog_data += lstrlenW(property_sheet_dialog_data)+1; | |
| memset(&font_desc, 0, sizeof(LOGFONTW)); | |
| /* Calculate logical height */ | |
| font_desc.lfHeight = -MulDiv(property_sheet_dialog_data[0], | |
| GetDeviceCaps(hdc, LOGPIXELSY), 72); | |
| font_desc.lfCharSet = DEFAULT_CHARSET; | |
| memcpy(font_desc.lfFaceName, property_sheet_dialog_data+1, | |
| sizeof(WCHAR)*(lstrlenW(property_sheet_dialog_data+1)+1)); | |
| hfont = CreateFontIndirectW(&font_desc); | |
| if(hfont) { | |
| hfont = SelectObject(hdc, hfont); | |
| font_width = GdiGetCharDimensions(hdc, NULL, &font_height); | |
| SelectObject(hdc, hfont); | |
| } | |
| } | |
| if(hcomctl) | |
| FreeLibrary(hcomctl); | |
| ReleaseDC(NULL, hdc); | |
| memset(&property_sheet, 0, sizeof(property_sheet)); | |
| property_sheet.dwSize = sizeof(property_sheet); | |
| if(lpParams->lpszCaption) { | |
| property_sheet.dwFlags = PSH_PROPTITLE; | |
| property_sheet.pszCaption = lpParams->lpszCaption; | |
| } | |
| property_sheet.u3.phpage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, | |
| lpParams->cPages*sizeof(HPROPSHEETPAGE)); | |
| property_page = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, | |
| lpParams->cPages*sizeof(IPropertyPage*)); | |
| dialogs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, | |
| lpParams->cPages*sizeof(*dialogs)); | |
| if(!property_sheet.u3.phpage || !property_page || !dialogs) { | |
| HeapFree(GetProcessHeap(), 0, property_sheet.u3.phpage); | |
| HeapFree(GetProcessHeap(), 0, property_page); | |
| HeapFree(GetProcessHeap(), 0, dialogs); | |
| return E_OUTOFMEMORY; | |
| } | |
| memset(&property_sheet_page, 0, sizeof(PROPSHEETPAGEW)); | |
| property_sheet_page.dwSize = sizeof(PROPSHEETPAGEW); | |
| property_sheet_page.dwFlags = PSP_DLGINDIRECT|PSP_USETITLE; | |
| property_sheet_page.pfnDlgProc = property_sheet_proc; | |
| for(i=0; i<lpParams->cPages; i++) { | |
| PROPPAGEINFO page_info; | |
| res = CoCreateInstance(&lpParams->lpPages[i], NULL, CLSCTX_INPROC_SERVER, | |
| &IID_IPropertyPage, (void**)&property_page[i]); | |
| if(FAILED(res)) | |
| continue; | |
| property_page_site = HeapAlloc(GetProcessHeap(), 0, sizeof(PropertyPageSite)); | |
| if(!property_page_site) | |
| continue; | |
| property_page_site->IPropertyPageSite_iface.lpVtbl = &PropertyPageSiteVtbl; | |
| property_page_site->ref = 1; | |
| property_page_site->lcid = lpParams->lcid; | |
| res = IPropertyPage_SetPageSite(property_page[i], | |
| &property_page_site->IPropertyPageSite_iface); | |
| IPropertyPageSite_Release(&property_page_site->IPropertyPageSite_iface); | |
| if(FAILED(res)) | |
| continue; | |
| res = IPropertyPage_SetObjects(property_page[i], | |
| lpParams->cObjects, lpParams->lplpUnk); | |
| if(FAILED(res)) | |
| continue; | |
| res = IPropertyPage_GetPageInfo(property_page[i], &page_info); | |
| if(FAILED(res)) | |
| continue; | |
| dialogs[i].template.cx = MulDiv(page_info.size.cx, 4, font_width); | |
| dialogs[i].template.cy = MulDiv(page_info.size.cy, 8, font_height); | |
| property_sheet_page.u.pResource = &dialogs[i].template; | |
| property_sheet_page.lParam = (LPARAM)property_page[i]; | |
| property_sheet_page.pszTitle = page_info.pszTitle; | |
| property_sheet.u3.phpage[property_sheet.nPages++] = | |
| CreatePropertySheetPageW(&property_sheet_page); | |
| } | |
| PropertySheetW(&property_sheet); | |
| for(i=0; i<lpParams->cPages; i++) { | |
| if(property_page[i]) { | |
| IPropertyPage_SetPageSite(property_page[i], NULL); | |
| IPropertyPage_Release(property_page[i]); | |
| } | |
| } | |
| HeapFree(GetProcessHeap(), 0, dialogs); | |
| HeapFree(GetProcessHeap(), 0, property_page); | |
| HeapFree(GetProcessHeap(), 0, property_sheet.u3.phpage); | |
| return S_OK; | |
| } | |
| /*********************************************************************** | |
| * OleCreatePropertyFrame (OLEAUT32.417) | |
| */ | |
| HRESULT WINAPI OleCreatePropertyFrame( | |
| HWND hwndOwner, UINT x, UINT y, LPCOLESTR lpszCaption, ULONG cObjects, | |
| LPUNKNOWN* ppUnk, ULONG cPages, LPCLSID pPageClsID, LCID lcid, | |
| DWORD dwReserved, LPVOID pvReserved) | |
| { | |
| OCPFIPARAMS ocpf; | |
| ocpf.cbStructSize = sizeof(OCPFIPARAMS); | |
| ocpf.hWndOwner = hwndOwner; | |
| ocpf.x = x; | |
| ocpf.y = y; | |
| ocpf.lpszCaption = lpszCaption; | |
| ocpf.cObjects = cObjects; | |
| ocpf.lplpUnk = ppUnk; | |
| ocpf.cPages = cPages; | |
| ocpf.lpPages = pPageClsID; | |
| ocpf.lcid = lcid; | |
| ocpf.dispidInitialProperty = 0; | |
| return OleCreatePropertyFrameIndirect(&ocpf); | |
| } |