| /* |
| * Copyright 2001 TAKESHIMA Hidenori <hidenori@a2.ctktv.ne.jp> |
| * |
| * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| * |
| * FIXME - use PropertySheetW. |
| * FIXME - not tested. |
| */ |
| |
| #include "config.h" |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "wingdi.h" |
| #include "winuser.h" |
| #include "wine/debug.h" |
| #include "ole2.h" |
| #include "olectl.h" |
| #include "oleauto.h" |
| #include "commctrl.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(ole); |
| |
| typedef struct CPropertyPageContainerImpl CPropertyPageContainerImpl; |
| |
| static const struct |
| { |
| DLGTEMPLATE templ; |
| WORD wMenuName; |
| WORD wClassName; |
| WCHAR wDummyCaption; |
| BYTE padding[4]; |
| } propsite_dlg = |
| { |
| { |
| WS_VISIBLE | WS_CHILD, /* style */ |
| 0, /* dwExtendedStyle */ |
| 0, /* cdit */ |
| 0, /* x */ |
| 0, /* y */ |
| 0, /* cx */ |
| 0, /* cy */ |
| }, |
| 0, 0, 0, |
| }; |
| |
| typedef struct CPropertyPageSiteImpl |
| { |
| ICOM_VFIELD(IPropertyPageSite); |
| /* IUnknown fields */ |
| ULONG ref; |
| |
| /* IPropertyPageSite fields */ |
| CPropertyPageContainerImpl* pContainer; |
| IPropertyPage* pPage; |
| HWND hwnd; |
| BYTE templ[sizeof(propsite_dlg)]; |
| PROPPAGEINFO info; |
| BOOL bActivate; |
| } CPropertyPageSiteImpl; |
| |
| struct CPropertyPageContainerImpl |
| { |
| ULONG ref; /* for IUnknown(not used now) */ |
| LCID lcid; |
| DWORD m_cSites; |
| CPropertyPageSiteImpl** m_ppSites; |
| PROPSHEETPAGEA* m_pPsp; |
| HRESULT m_hr; |
| }; |
| |
| /* for future use. */ |
| #define CPropertyPageContainerImpl_AddRef(pContainer) (++((pContainer)->ref)) |
| #define CPropertyPageContainerImpl_Release(pContainer) (--((pContainer)->ref)) |
| |
| |
| /***************************************************************************/ |
| |
| #define PropSiteDlg_Return(a) do{SetWindowLongA(hwnd,DWL_MSGRESULT,(LONG)a);return TRUE;}while(1) |
| static BOOL CALLBACK PropSiteDlgProc( |
| HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam ) |
| { |
| CPropertyPageSiteImpl* This = (CPropertyPageSiteImpl*)GetWindowLongA( hwnd, DWL_USER ); |
| HRESULT hr; |
| RECT rc; |
| NMHDR* pnmh; |
| |
| switch ( msg ) |
| { |
| case WM_INITDIALOG: |
| This = (CPropertyPageSiteImpl*)(((PROPSHEETPAGEA*)lParam)->lParam); |
| SetWindowLongA( hwnd, DWL_USER, (LONG)This ); |
| TRACE("WM_INITDIALOG (%p) hwnd = %08x\n", This, hwnd ); |
| |
| This->hwnd = hwnd; |
| ZeroMemory( &rc, sizeof(rc) ); |
| GetClientRect( hwnd, &rc ); |
| hr = IPropertyPage_Activate(This->pPage,hwnd,&rc,TRUE); |
| if ( SUCCEEDED(hr) ) |
| { |
| This->bActivate = TRUE; |
| hr = IPropertyPage_Show(This->pPage,SW_SHOW); |
| } |
| if ( FAILED(hr) ) |
| This->pContainer->m_hr = hr; |
| break; |
| case WM_DESTROY: |
| TRACE("WM_DESTROY (%p)\n",This); |
| if ( This != NULL ) |
| { |
| if ( This->bActivate ) |
| { |
| IPropertyPage_Show(This->pPage,SW_HIDE); |
| IPropertyPage_Deactivate(This->pPage); |
| This->bActivate = FALSE; |
| } |
| This->hwnd = (HWND)NULL; |
| } |
| SetWindowLongA( hwnd, DWL_USER, (LONG)0 ); |
| break; |
| case WM_NOTIFY: |
| pnmh = (NMHDR*)lParam; |
| switch ( pnmh->code ) |
| { |
| case PSN_APPLY: |
| TRACE("PSN_APPLY (%p)\n",This); |
| hr = IPropertyPage_Apply(This->pPage); |
| if ( FAILED(hr) ) |
| PropSiteDlg_Return(PSNRET_INVALID_NOCHANGEPAGE); |
| PropSiteDlg_Return(PSNRET_NOERROR); |
| case PSN_QUERYCANCEL: |
| FIXME("PSN_QUERYCANCEL (%p)\n",This); |
| PropSiteDlg_Return(FALSE); |
| case PSN_RESET: |
| FIXME("PSN_RESET (%p)\n",This); |
| PropSiteDlg_Return(0); |
| case PSN_SETACTIVE: |
| TRACE("PSN_SETACTIVE (%p)\n",This); |
| PropSiteDlg_Return(0); |
| case PSN_KILLACTIVE: |
| TRACE("PSN_KILLACTIVE (%p)\n",This); |
| PropSiteDlg_Return(FALSE); |
| } |
| break; |
| } |
| |
| return FALSE; |
| } |
| |
| /***************************************************************************/ |
| |
| static HRESULT WINAPI |
| CPropertyPageSiteImpl_fnQueryInterface(IPropertyPageSite* iface,REFIID riid,LPVOID *ppobj) |
| { |
| ICOM_THIS(CPropertyPageSiteImpl,iface); |
| |
| TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj); |
| |
| if ( ppobj == NULL ) |
| return E_POINTER; |
| *ppobj = NULL; |
| |
| if ( IsEqualGUID(riid,&IID_IUnknown) || |
| IsEqualGUID(riid,&IID_IPropertyPageSite) ) |
| { |
| *ppobj = (LPVOID)This; |
| IUnknown_AddRef((IUnknown*)(*ppobj)); |
| return S_OK; |
| } |
| |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI |
| CPropertyPageSiteImpl_fnAddRef(IPropertyPageSite* iface) |
| { |
| ICOM_THIS(CPropertyPageSiteImpl,iface); |
| |
| TRACE("(%p)->()\n",This); |
| |
| return InterlockedExchangeAdd(&(This->ref),1) + 1; |
| } |
| |
| static ULONG WINAPI |
| CPropertyPageSiteImpl_fnRelease(IPropertyPageSite* iface) |
| { |
| ICOM_THIS(CPropertyPageSiteImpl,iface); |
| LONG ref; |
| |
| TRACE("(%p)->()\n",This); |
| ref = InterlockedExchangeAdd(&(This->ref),-1) - 1; |
| if ( ref > 0 ) |
| return (ULONG)ref; |
| |
| if ( This->pContainer != NULL ) |
| CPropertyPageContainerImpl_Release(This->pContainer); |
| if ( This->pPage != NULL ) |
| IPropertyPage_Release(This->pPage); |
| if ( This->info.pszTitle != NULL ) |
| CoTaskMemFree( This->info.pszTitle ); |
| if ( This->info.pszDocString != NULL ) |
| CoTaskMemFree( This->info.pszDocString ); |
| if ( This->info.pszHelpFile != NULL ) |
| CoTaskMemFree( This->info.pszHelpFile ); |
| |
| HeapFree(GetProcessHeap(),0,This); |
| |
| return 0; |
| } |
| |
| static HRESULT WINAPI |
| CPropertyPageSiteImpl_fnOnStatusChange(IPropertyPageSite* iface,DWORD dwFlags) |
| { |
| ICOM_THIS(CPropertyPageSiteImpl,iface); |
| |
| TRACE("(%p,%08lx)\n",This,dwFlags); |
| |
| if ( This->hwnd == (HWND)NULL ) |
| return E_UNEXPECTED; |
| |
| switch ( dwFlags ) |
| { |
| case PROPPAGESTATUS_DIRTY: |
| /* dirty */ |
| SendMessageA(GetParent(This->hwnd),PSM_CHANGED,(WPARAM)(This->hwnd),0); |
| break; |
| case PROPPAGESTATUS_VALIDATE: |
| /* validate */ |
| SendMessageA(GetParent(This->hwnd),PSM_UNCHANGED,(WPARAM)(This->hwnd),0); |
| break; |
| default: |
| FIXME("(%p,%08lx) unknown flags\n",This,dwFlags); |
| return E_INVALIDARG; |
| } |
| |
| return NOERROR; |
| } |
| |
| static HRESULT WINAPI |
| CPropertyPageSiteImpl_fnGetLocaleID(IPropertyPageSite* iface,LCID* pLocaleID) |
| { |
| ICOM_THIS(CPropertyPageSiteImpl,iface); |
| |
| TRACE("(%p,%p)\n",This,pLocaleID); |
| |
| if ( pLocaleID == NULL ) |
| return E_POINTER; |
| |
| *pLocaleID = This->pContainer->lcid; |
| |
| return NOERROR; |
| } |
| |
| static HRESULT WINAPI |
| CPropertyPageSiteImpl_fnGetPageContainer(IPropertyPageSite* iface,IUnknown** ppUnk) |
| { |
| ICOM_THIS(CPropertyPageSiteImpl,iface); |
| |
| FIXME("(%p,%p) - Win95 returns E_NOTIMPL\n",This,ppUnk); |
| |
| if ( ppUnk == NULL ) |
| return E_POINTER; |
| |
| *ppUnk = NULL; |
| |
| return E_NOTIMPL; |
| } |
| |
| static HRESULT WINAPI |
| CPropertyPageSiteImpl_fnTranslateAccelerator(IPropertyPageSite* iface,MSG* pMsg) |
| { |
| ICOM_THIS(CPropertyPageSiteImpl,iface); |
| |
| FIXME("(%p,%p) - Win95 returns E_NOTIMPL\n",This,pMsg); |
| |
| if ( pMsg == NULL ) |
| return E_POINTER; |
| |
| return E_NOTIMPL; |
| } |
| |
| static ICOM_VTABLE(IPropertyPageSite) iproppagesite = |
| { |
| ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE |
| /* IUnknown fields */ |
| CPropertyPageSiteImpl_fnQueryInterface, |
| CPropertyPageSiteImpl_fnAddRef, |
| CPropertyPageSiteImpl_fnRelease, |
| /* IPropertyPageSite fields */ |
| CPropertyPageSiteImpl_fnOnStatusChange, |
| CPropertyPageSiteImpl_fnGetLocaleID, |
| CPropertyPageSiteImpl_fnGetPageContainer, |
| CPropertyPageSiteImpl_fnTranslateAccelerator, |
| }; |
| |
| /***************************************************************************/ |
| |
| static |
| HRESULT OLEPRO32_CreatePropertyPageSite( |
| CPropertyPageContainerImpl* pContainer, |
| IPropertyPage* pPage, |
| CPropertyPageSiteImpl** ppSite, |
| PROPSHEETPAGEA* pPspReturned ) |
| { |
| CPropertyPageSiteImpl* This = NULL; |
| HRESULT hr; |
| DLGTEMPLATE* ptempl; |
| |
| *ppSite = NULL; |
| ZeroMemory( pPspReturned, sizeof(PROPSHEETPAGEA) ); |
| |
| This = (CPropertyPageSiteImpl*)HeapAlloc( GetProcessHeap(), 0, |
| sizeof(CPropertyPageSiteImpl) ); |
| if ( This == NULL ) |
| return E_OUTOFMEMORY; |
| ZeroMemory( This, sizeof(CPropertyPageSiteImpl) ); |
| |
| ICOM_VTBL(This) = &iproppagesite; |
| This->ref = 1; |
| This->pContainer = pContainer; CPropertyPageContainerImpl_AddRef(pContainer); |
| This->pPage = pPage; IPropertyPage_AddRef(pPage); |
| This->hwnd = (HWND)NULL; |
| memcpy( &This->templ, &propsite_dlg, sizeof(propsite_dlg) ); |
| This->info.cb = sizeof(PROPPAGEINFO); |
| This->bActivate = FALSE; |
| ptempl = (DLGTEMPLATE*)&This->templ; |
| |
| /* construct */ |
| hr = IPropertyPage_SetPageSite(pPage,(IPropertyPageSite*)This); |
| if ( FAILED(hr) ) |
| goto end; |
| |
| hr = IPropertyPage_GetPageInfo(pPage,&This->info); |
| if ( FAILED(hr) ) |
| goto end; |
| |
| ptempl->cx = This->info.size.cx; |
| ptempl->cy = This->info.size.cy; |
| |
| pPspReturned->dwSize = sizeof(PROPSHEETPAGEA); |
| pPspReturned->dwFlags = PSP_DLGINDIRECT; |
| pPspReturned->u.pResource = ptempl; |
| if ( This->info.pszTitle != NULL ); |
| { |
| pPspReturned->dwFlags |= PSP_USETITLE; |
| pPspReturned->pszTitle = "Title";/*FIXME - This->info.pszTitle;*/ |
| } |
| pPspReturned->pfnDlgProc = PropSiteDlgProc; |
| pPspReturned->lParam = (LONG)This; |
| |
| end: |
| if ( FAILED(hr) ) |
| { |
| IUnknown_Release((IUnknown*)This); |
| return hr; |
| } |
| |
| *ppSite = This; |
| return NOERROR; |
| } |
| |
| /***************************************************************************/ |
| |
| static |
| void OLEPRO32_DestroyPropertyPageContainer( |
| CPropertyPageContainerImpl* This ) |
| { |
| DWORD nIndex; |
| |
| if ( This->m_ppSites != NULL ) |
| { |
| for ( nIndex = 0; nIndex < This->m_cSites; nIndex++ ) |
| { |
| if ( This->m_ppSites[nIndex] != NULL ) |
| { |
| IPropertyPage_SetPageSite(This->m_ppSites[nIndex]->pPage,NULL); |
| IUnknown_Release((IUnknown*)This->m_ppSites[nIndex]); |
| } |
| } |
| HeapFree( GetProcessHeap(), 0, This->m_ppSites ); |
| This->m_ppSites = NULL; |
| } |
| if ( This->m_pPsp != NULL ) |
| { |
| HeapFree( GetProcessHeap(), 0, This->m_pPsp ); |
| This->m_pPsp = NULL; |
| } |
| HeapFree( GetProcessHeap(), 0, This ); |
| } |
| |
| static |
| HRESULT OLEPRO32_CreatePropertyPageContainer( |
| CPropertyPageContainerImpl** ppContainer, |
| ULONG cPages, const CLSID* pclsidPages, |
| LCID lcid ) |
| { |
| CPropertyPageContainerImpl* This = NULL; |
| DWORD nIndex; |
| IPropertyPage* pPage; |
| HRESULT hr; |
| |
| This = (CPropertyPageContainerImpl*)HeapAlloc( GetProcessHeap(), 0, |
| sizeof(CPropertyPageContainerImpl) ); |
| if ( This == NULL ) |
| return E_OUTOFMEMORY; |
| ZeroMemory( This, sizeof(CPropertyPageContainerImpl) ); |
| This->ref = 1; |
| This->lcid = lcid; |
| This->m_cSites = cPages; |
| This->m_ppSites = NULL; |
| This->m_pPsp = NULL; |
| This->m_hr = S_OK; |
| |
| This->m_ppSites = (CPropertyPageSiteImpl**)HeapAlloc( GetProcessHeap(), 0, sizeof(CPropertyPageSiteImpl*) * cPages ); |
| if ( This->m_ppSites == NULL ) |
| { |
| hr = E_OUTOFMEMORY; |
| goto end; |
| } |
| ZeroMemory( This->m_ppSites, sizeof(CPropertyPageSiteImpl*) * cPages ); |
| |
| This->m_pPsp = (PROPSHEETPAGEA*)HeapAlloc( GetProcessHeap(), 0, sizeof(PROPSHEETPAGEA) * cPages ); |
| if ( This->m_pPsp == NULL ) |
| { |
| hr = E_OUTOFMEMORY; |
| goto end; |
| } |
| ZeroMemory( This->m_pPsp, sizeof(PROPSHEETPAGEA) * cPages ); |
| |
| for ( nIndex = 0; nIndex < cPages; nIndex ++ ) |
| { |
| hr = CoCreateInstance( |
| &pclsidPages[nIndex], NULL, CLSCTX_SERVER, |
| &IID_IPropertyPage, (void**)&pPage ); |
| if ( FAILED(hr) ) |
| goto end; |
| hr = OLEPRO32_CreatePropertyPageSite( |
| This, pPage, &This->m_ppSites[nIndex], &This->m_pPsp[nIndex] ); |
| IPropertyPage_Release(pPage); |
| if ( FAILED(hr) ) |
| goto end; |
| } |
| |
| hr = NOERROR; |
| end: |
| if ( FAILED(hr) ) |
| { |
| OLEPRO32_DestroyPropertyPageContainer( This ); |
| return hr; |
| } |
| |
| *ppContainer = This; |
| return NOERROR; |
| } |
| |
| static |
| HRESULT OLEPRO32_SetObjectsToPropertyPages( |
| CPropertyPageContainerImpl* This, |
| ULONG cObjects, IUnknown** ppunk ) |
| { |
| DWORD nIndex; |
| HRESULT hr; |
| |
| for ( nIndex = 0; nIndex < This->m_cSites; nIndex ++ ) |
| { |
| if ( This->m_ppSites[nIndex] == NULL ) |
| return E_UNEXPECTED; |
| hr = IPropertyPage_SetObjects(This->m_ppSites[nIndex]->pPage,cObjects,ppunk); |
| if ( FAILED(hr) ) |
| return hr; |
| } |
| |
| return NOERROR; |
| } |
| |
| |
| /*********************************************************************** |
| * |
| * OleCreatePropertyFrameIndirect (OLEAUT32.416)(OLEPRO32.249) |
| * |
| */ |
| |
| HRESULT WINAPI OleCreatePropertyFrameIndirect( LPOCPFIPARAMS lpParams ) |
| { |
| CPropertyPageContainerImpl* pContainer = NULL; |
| HRESULT hr; |
| PROPSHEETHEADERA psh; |
| int ret; |
| |
| TRACE("(%p)\n",lpParams); |
| |
| if ( lpParams == NULL ) |
| return E_POINTER; |
| if ( lpParams->cbStructSize != sizeof(OCPFIPARAMS) ) |
| { |
| FIXME("lpParams->cbStructSize(%lu) != sizeof(OCPFIPARAMS)(%lu)\n",lpParams->cbStructSize,(unsigned long)sizeof(OCPFIPARAMS)); |
| return E_INVALIDARG; |
| } |
| |
| hr = OLEPRO32_CreatePropertyPageContainer( |
| &pContainer, |
| lpParams->cPages, lpParams->lpPages, |
| lpParams->lcid ); |
| if ( FAILED(hr) ) |
| { |
| TRACE( "OLEPRO32_CreatePropertyPageContainer returns %08lx\n",hr); |
| return hr; |
| } |
| |
| hr = OLEPRO32_SetObjectsToPropertyPages( |
| pContainer, |
| lpParams->cObjects, lpParams->lplpUnk ); |
| if ( FAILED(hr) ) |
| { |
| TRACE("OLEPRO32_SetObjectsToPropertyPages returns %08lx\n",hr); |
| OLEPRO32_DestroyPropertyPageContainer(pContainer); |
| return hr; |
| } |
| |
| /* FIXME - use lpParams.x / lpParams.y */ |
| |
| ZeroMemory( &psh, sizeof(psh) ); |
| psh.dwSize = sizeof(PROPSHEETHEADERA); |
| psh.dwFlags = PSH_PROPSHEETPAGE; |
| psh.hwndParent = lpParams->hWndOwner; |
| psh.pszCaption = "Caption"; /* FIXME - lpParams->lpszCaption; */ |
| psh.nPages = pContainer->m_cSites; |
| psh.u2.nStartPage = lpParams->dispidInitialProperty; |
| psh.u3.ppsp = pContainer->m_pPsp; |
| |
| ret = PropertySheetA( &psh ); |
| OLEPRO32_DestroyPropertyPageContainer(pContainer); |
| |
| if ( ret == -1 ) |
| return E_FAIL; |
| |
| return S_OK; |
| } |
| |
| |
| /*********************************************************************** |
| * |
| * OleCreatePropertyFrame (OLEAUT32.417)(OLEPRO32.250) |
| * |
| */ |
| |
| HRESULT WINAPI OleCreatePropertyFrame( |
| HWND hwndOwner, UINT x, UINT y, LPCOLESTR lpszCaption,ULONG cObjects, |
| LPUNKNOWN* lplpUnk, ULONG cPages, LPCLSID pPageClsID, LCID lcid, |
| DWORD dwReserved, LPVOID pvReserved ) |
| { |
| OCPFIPARAMS params; |
| |
| TRACE("(%x,%d,%d,%s,%ld,%p,%ld,%p,%x,%ld,%p)\n", |
| hwndOwner,x,y,debugstr_w(lpszCaption),cObjects,lplpUnk,cPages, |
| pPageClsID, (int)lcid,dwReserved,pvReserved); |
| |
| if ( dwReserved != 0 || pvReserved != NULL ) |
| { |
| FIXME("(%x,%d,%d,%s,%ld,%p,%ld,%p,%x,%ld,%p) - E_INVALIDARG\n", |
| hwndOwner,x,y,debugstr_w(lpszCaption),cObjects,lplpUnk,cPages, |
| pPageClsID, (int)lcid,dwReserved,pvReserved); |
| return E_INVALIDARG; |
| } |
| |
| ZeroMemory( ¶ms, sizeof(params) ); |
| params.cbStructSize = sizeof(OCPFIPARAMS); |
| params.hWndOwner = hwndOwner; |
| params.x = x; |
| params.y = y; |
| params.lpszCaption = lpszCaption; |
| params.cObjects = cObjects; |
| params.lplpUnk = lplpUnk; |
| params.cPages = cPages; |
| params.lpPages = pPageClsID; |
| params.lcid = lcid; |
| params.dispidInitialProperty = 0; |
| |
| return OleCreatePropertyFrameIndirect( ¶ms ); |
| } |
| |