xref: /reactos/dll/win32/oleaut32/olepropframe.c (revision 527f2f90)
1 /*
2  * Copyright 1999 Corel Corporation
3  * Sean Langley
4  * Copyright 2010  Geoffrey Hausheer
5  * Copyright 2010 Piotr Caban for CodeWeavers
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21 
22 #include "precomp.h"
23 
24 #include <oledlg.h>
25 
26 WINE_DEFAULT_DEBUG_CHANNEL(ole);
27 
28 typedef struct {
29     IPropertyPageSite IPropertyPageSite_iface;
30     LCID lcid;
31     LONG ref;
32 } PropertyPageSite;
33 
34 static inline PropertyPageSite *impl_from_IPropertyPageSite(IPropertyPageSite *iface)
35 {
36     return CONTAINING_RECORD(iface, PropertyPageSite, IPropertyPageSite_iface);
37 }
38 
39 static INT_PTR CALLBACK property_sheet_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
40 {
41     IPropertyPage *property_page = (IPropertyPage*)GetWindowLongPtrW(hwnd, DWLP_USER);
42 
43     switch(msg) {
44     case WM_INITDIALOG: {
45         RECT rect;
46 
47         property_page = (IPropertyPage*)((LPPROPSHEETPAGEW)lparam)->lParam;
48 
49         GetClientRect(hwnd, &rect);
50         IPropertyPage_Activate(property_page, hwnd, &rect, TRUE);
51         IPropertyPage_Show(property_page, SW_SHOW);
52 
53         SetWindowLongPtrW(hwnd, DWLP_USER, (LONG_PTR)property_page);
54         return FALSE;
55     }
56     case WM_DESTROY:
57         IPropertyPage_Show(property_page, SW_HIDE);
58         IPropertyPage_Deactivate(property_page);
59         return FALSE;
60     default:
61         return FALSE;
62     }
63 }
64 
65 static HRESULT WINAPI PropertyPageSite_QueryInterface(IPropertyPageSite*  iface,
66         REFIID  riid, void**  ppv)
67 {
68     TRACE("(%p riid: %s)\n",iface, debugstr_guid(riid));
69 
70     if(IsEqualGUID(&IID_IUnknown, riid)
71             || IsEqualGUID(&IID_IPropertyPageSite, riid))
72         *ppv = iface;
73     else {
74         *ppv = NULL;
75         return E_NOINTERFACE;
76     }
77 
78     IUnknown_AddRef((IUnknown*)*ppv);
79     return S_OK;
80 }
81 
82 static ULONG WINAPI PropertyPageSite_AddRef(IPropertyPageSite* iface)
83 {
84     PropertyPageSite *this = impl_from_IPropertyPageSite(iface);
85     LONG ref = InterlockedIncrement(&this->ref);
86 
87     TRACE("(%p) ref=%d\n", this, ref);
88     return ref;
89 }
90 
91 static ULONG WINAPI PropertyPageSite_Release(IPropertyPageSite* iface)
92 {
93     PropertyPageSite *this = impl_from_IPropertyPageSite(iface);
94     LONG ref = InterlockedDecrement(&this->ref);
95 
96     TRACE("(%p) ref=%d\n", this, ref);
97     if(!ref)
98         HeapFree(GetProcessHeap(), 0, this);
99     return ref;
100 }
101 
102 static HRESULT WINAPI PropertyPageSite_OnStatusChange(
103         IPropertyPageSite *iface, DWORD dwFlags)
104 {
105     TRACE("(%p, %x)\n", iface, dwFlags);
106     return S_OK;
107 }
108 
109 static HRESULT WINAPI PropertyPageSite_GetLocaleID(
110         IPropertyPageSite *iface, LCID *pLocaleID)
111 {
112     PropertyPageSite *this = impl_from_IPropertyPageSite(iface);
113 
114     TRACE("(%p, %p)\n", iface, pLocaleID);
115     *pLocaleID = this->lcid;
116     return S_OK;
117 }
118 
119 static HRESULT WINAPI PropertyPageSite_GetPageContainer(
120         IPropertyPageSite* iface, IUnknown** ppUnk)
121 {
122     FIXME("(%p, %p)\n", iface, ppUnk);
123     return E_NOTIMPL;
124 }
125 
126 static HRESULT WINAPI PropertyPageSite_TranslateAccelerator(
127         IPropertyPageSite* iface, MSG *pMsg)
128 {
129     FIXME("(%p, %p)\n", iface, pMsg);
130     return E_NOTIMPL;
131 }
132 
133 static IPropertyPageSiteVtbl PropertyPageSiteVtbl = {
134     PropertyPageSite_QueryInterface,
135     PropertyPageSite_AddRef,
136     PropertyPageSite_Release,
137     PropertyPageSite_OnStatusChange,
138     PropertyPageSite_GetLocaleID,
139     PropertyPageSite_GetPageContainer,
140     PropertyPageSite_TranslateAccelerator
141 };
142 
143 /***********************************************************************
144  * OleCreatePropertyFrameIndirect (OLEAUT32.416)
145  */
146 HRESULT WINAPI OleCreatePropertyFrameIndirect(LPOCPFIPARAMS lpParams)
147 {
148     static const WCHAR comctlW[] = { 'c','o','m','c','t','l','3','2','.','d','l','l',0 };
149 
150     PROPSHEETHEADERW property_sheet;
151     PROPSHEETPAGEW property_sheet_page;
152     struct {
153         DLGTEMPLATE template;
154         WORD menu;
155         WORD class;
156         WORD title;
157     } *dialogs;
158     IPropertyPage **property_page;
159     PropertyPageSite *property_page_site;
160     HRESULT res;
161     ULONG i;
162     HMODULE hcomctl;
163     HRSRC property_sheet_dialog_find = NULL;
164     HGLOBAL property_sheet_dialog_load = NULL;
165     WCHAR *property_sheet_dialog_data = NULL;
166     HDC hdc;
167     LOGFONTW font_desc;
168     HFONT hfont;
169     LONG font_width = 4, font_height = 8;
170 
171     if(!lpParams)
172         return E_POINTER;
173 
174     TRACE("(%d %p %d %d %s %d %p %d %p %d %d)\n", lpParams->cbStructSize,
175             lpParams->hWndOwner, lpParams->x, lpParams->y,
176             debugstr_w(lpParams->lpszCaption), lpParams->cObjects,
177             lpParams->lplpUnk, lpParams->cPages, lpParams->lpPages,
178             lpParams->lcid, lpParams->dispidInitialProperty);
179 
180     if(!lpParams->lplpUnk || !lpParams->lpPages)
181         return E_POINTER;
182 
183     if(lpParams->cbStructSize != sizeof(OCPFIPARAMS)) {
184         WARN("incorrect structure size\n");
185         return E_INVALIDARG;
186     }
187 
188     if(lpParams->dispidInitialProperty)
189         FIXME("dispidInitialProperty not yet implemented\n");
190 
191     hdc = GetDC(NULL);
192     hcomctl = LoadLibraryW(comctlW);
193     if(hcomctl)
194         property_sheet_dialog_find = FindResourceW(hcomctl,
195                 MAKEINTRESOURCEW(1006 /*IDD_PROPSHEET*/), (LPWSTR)RT_DIALOG);
196     if(property_sheet_dialog_find)
197         property_sheet_dialog_load = LoadResource(hcomctl, property_sheet_dialog_find);
198     if(property_sheet_dialog_load)
199         property_sheet_dialog_data = LockResource(property_sheet_dialog_load);
200 
201     if(property_sheet_dialog_data) {
202         if(property_sheet_dialog_data[1] == 0xffff) {
203             ERR("Expected DLGTEMPLATE structure\n");
204             return E_OUTOFMEMORY;
205         }
206 
207         property_sheet_dialog_data += sizeof(DLGTEMPLATE)/sizeof(WCHAR);
208         /* Skip menu, class and title */
209         property_sheet_dialog_data += lstrlenW(property_sheet_dialog_data)+1;
210         property_sheet_dialog_data += lstrlenW(property_sheet_dialog_data)+1;
211         property_sheet_dialog_data += lstrlenW(property_sheet_dialog_data)+1;
212 
213         memset(&font_desc, 0, sizeof(LOGFONTW));
214         /* Calculate logical height */
215         font_desc.lfHeight = -MulDiv(property_sheet_dialog_data[0],
216                 GetDeviceCaps(hdc, LOGPIXELSY), 72);
217         font_desc.lfCharSet = DEFAULT_CHARSET;
218         memcpy(font_desc.lfFaceName, property_sheet_dialog_data+1,
219                 sizeof(WCHAR)*(lstrlenW(property_sheet_dialog_data+1)+1));
220         hfont = CreateFontIndirectW(&font_desc);
221 
222         if(hfont) {
223             hfont = SelectObject(hdc, hfont);
224             font_width = GdiGetCharDimensions(hdc, NULL, &font_height);
225             SelectObject(hdc, hfont);
226         }
227     }
228     if(hcomctl)
229         FreeLibrary(hcomctl);
230     ReleaseDC(NULL, hdc);
231 
232     memset(&property_sheet, 0, sizeof(property_sheet));
233     property_sheet.dwSize = sizeof(property_sheet);
234     if(lpParams->lpszCaption) {
235         property_sheet.dwFlags = PSH_PROPTITLE;
236         property_sheet.pszCaption = lpParams->lpszCaption;
237     }
238 
239     property_sheet.u3.phpage = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
240             lpParams->cPages*sizeof(HPROPSHEETPAGE));
241     property_page = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
242             lpParams->cPages*sizeof(IPropertyPage*));
243     dialogs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
244             lpParams->cPages*sizeof(*dialogs));
245     if(!property_sheet.u3.phpage || !property_page || !dialogs) {
246         HeapFree(GetProcessHeap(), 0, property_sheet.u3.phpage);
247         HeapFree(GetProcessHeap(), 0, property_page);
248         HeapFree(GetProcessHeap(), 0, dialogs);
249         return E_OUTOFMEMORY;
250     }
251 
252     memset(&property_sheet_page, 0, sizeof(PROPSHEETPAGEW));
253     property_sheet_page.dwSize = sizeof(PROPSHEETPAGEW);
254     property_sheet_page.dwFlags = PSP_DLGINDIRECT|PSP_USETITLE;
255     property_sheet_page.pfnDlgProc = property_sheet_proc;
256 
257     for(i=0; i<lpParams->cPages; i++) {
258         PROPPAGEINFO page_info;
259 
260         res = CoCreateInstance(&lpParams->lpPages[i], NULL, CLSCTX_INPROC_SERVER,
261                 &IID_IPropertyPage, (void**)&property_page[i]);
262         if(FAILED(res))
263             continue;
264 
265         property_page_site = HeapAlloc(GetProcessHeap(), 0, sizeof(PropertyPageSite));
266         if(!property_page_site)
267             continue;
268         property_page_site->IPropertyPageSite_iface.lpVtbl = &PropertyPageSiteVtbl;
269         property_page_site->ref = 1;
270         property_page_site->lcid = lpParams->lcid;
271 
272         res = IPropertyPage_SetPageSite(property_page[i],
273                 &property_page_site->IPropertyPageSite_iface);
274         IPropertyPageSite_Release(&property_page_site->IPropertyPageSite_iface);
275         if(FAILED(res))
276             continue;
277 
278         res = IPropertyPage_SetObjects(property_page[i],
279                 lpParams->cObjects, lpParams->lplpUnk);
280         if(FAILED(res))
281             continue;
282 
283         res = IPropertyPage_GetPageInfo(property_page[i], &page_info);
284         if(FAILED(res))
285             continue;
286 
287         dialogs[i].template.cx = MulDiv(page_info.size.cx, 4, font_width);
288         dialogs[i].template.cy = MulDiv(page_info.size.cy, 8, font_height);
289 
290         property_sheet_page.u.pResource = &dialogs[i].template;
291         property_sheet_page.lParam = (LPARAM)property_page[i];
292         property_sheet_page.pszTitle = page_info.pszTitle;
293 
294         property_sheet.u3.phpage[property_sheet.nPages++] =
295             CreatePropertySheetPageW(&property_sheet_page);
296     }
297 
298     PropertySheetW(&property_sheet);
299 
300     for(i=0; i<lpParams->cPages; i++) {
301         if(property_page[i]) {
302             IPropertyPage_SetPageSite(property_page[i], NULL);
303             IPropertyPage_Release(property_page[i]);
304         }
305     }
306 
307     HeapFree(GetProcessHeap(), 0, dialogs);
308     HeapFree(GetProcessHeap(), 0, property_page);
309     HeapFree(GetProcessHeap(), 0, property_sheet.u3.phpage);
310     return S_OK;
311 }
312 
313 /***********************************************************************
314  * OleCreatePropertyFrame (OLEAUT32.417)
315  */
316 HRESULT WINAPI OleCreatePropertyFrame(
317         HWND hwndOwner, UINT x, UINT y, LPCOLESTR lpszCaption, ULONG cObjects,
318         LPUNKNOWN* ppUnk, ULONG cPages, LPCLSID pPageClsID, LCID lcid,
319         DWORD dwReserved, LPVOID pvReserved)
320 {
321     OCPFIPARAMS ocpf;
322 
323     ocpf.cbStructSize =  sizeof(OCPFIPARAMS);
324     ocpf.hWndOwner    = hwndOwner;
325     ocpf.x            = x;
326     ocpf.y            = y;
327     ocpf.lpszCaption  = lpszCaption;
328     ocpf.cObjects     = cObjects;
329     ocpf.lplpUnk      = ppUnk;
330     ocpf.cPages       = cPages;
331     ocpf.lpPages      = pPageClsID;
332     ocpf.lcid         = lcid;
333     ocpf.dispidInitialProperty = 0;
334 
335     return OleCreatePropertyFrameIndirect(&ocpf);
336 }
337