| /* |
| * 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); |
| } |