From fb5c516dfdff07395c5d90289fe747e4e208d749 Mon Sep 17 00:00:00 2001 From: Thomas Weidenmueller Date: Fri, 19 Jan 2007 14:15:45 +0100 Subject: [PATCH] shell32: Implement the property sheet extension array functions. Implement the SHAddFromPropSheetExtArray, SHCreatePropSheetExtArray, SHReplaceFromPropSheetExtArray and SHDestroyPropSheetExtArray functions that are used to extend/replace property sheets by shell extensions. --- dlls/shell32/shellord.c | 198 ++++++++++++++++++++++++++++++++++++++-- include/shlguid.h | 2 +- include/shobjidl.idl | 39 ++++++-- 3 files changed, 224 insertions(+), 15 deletions(-) diff --git a/dlls/shell32/shellord.c b/dlls/shell32/shellord.c index 7c22e6bab78..f85c533b64f 100644 --- a/dlls/shell32/shellord.c +++ b/dlls/shell32/shellord.c @@ -1513,13 +1513,68 @@ DWORD WINAPI SHELL32_714(LPVOID x) return 0; } +typedef struct _PSXA +{ + UINT uiCount; + UINT uiAllocated; + IShellPropSheetExt *pspsx[1]; +} PSXA, *PPSXA; + +typedef struct _PSXA_CALL +{ + LPFNADDPROPSHEETPAGE lpfnAddReplaceWith; + LPARAM lParam; + BOOL bCalled; + BOOL bMultiple; + UINT uiCount; +} PSXA_CALL, *PPSXA_CALL; + +static BOOL CALLBACK PsxaCall(HPROPSHEETPAGE hpage, LPARAM lParam) +{ + PPSXA_CALL Call = (PPSXA_CALL)lParam; + + if (Call != NULL) + { + if ((Call->bMultiple || !Call->bCalled) && + Call->lpfnAddReplaceWith(hpage, Call->lParam)) + { + Call->bCalled = TRUE; + Call->uiCount++; + return TRUE; + } + } + + return FALSE; +} + /************************************************************************* * SHAddFromPropSheetExtArray [SHELL32.167] */ UINT WINAPI SHAddFromPropSheetExtArray(HPSXA hpsxa, LPFNADDPROPSHEETPAGE lpfnAddPage, LPARAM lParam) { - FIXME("(%p,%p,%08lx)stub\n", hpsxa, lpfnAddPage, lParam); - return 0; + PSXA_CALL Call; + UINT i; + PPSXA psxa = (PPSXA)hpsxa; + + TRACE("(%p,%p,%08lx)\n", hpsxa, lpfnAddPage, lParam); + + if (psxa) + { + ZeroMemory(&Call, sizeof(Call)); + Call.lpfnAddReplaceWith = lpfnAddPage; + Call.lParam = lParam; + Call.bMultiple = TRUE; + + /* Call the AddPage method of all registered IShellPropSheetExt interfaces */ + for (i = 0; i != psxa->uiCount; i++) + { + psxa->pspsx[i]->lpVtbl->AddPages(psxa->pspsx[i], PsxaCall, (LPARAM)&Call); + } + + return Call.uiCount; + } + + return 0; } /************************************************************************* @@ -1527,8 +1582,102 @@ UINT WINAPI SHAddFromPropSheetExtArray(HPSXA hpsxa, LPFNADDPROPSHEETPAGE lpfnAdd */ HPSXA WINAPI SHCreatePropSheetExtArray(HKEY hKey, LPCWSTR pszSubKey, UINT max_iface) { - FIXME("(%p,%s,%u)stub\n", hKey, debugstr_w(pszSubKey), max_iface); - return NULL; + static const WCHAR szPropSheetSubKey[] = {'s','h','e','l','l','e','x','\\','P','r','o','p','e','r','t','y','S','h','e','e','t','H','a','n','d','l','e','r','s',0}; + WCHAR szHandler[64]; + DWORD dwHandlerLen; + WCHAR szClsidHandler[39]; + DWORD dwClsidSize; + CLSID clsid; + LONG lRet; + DWORD dwIndex; + IShellExtInit *psxi; + IShellPropSheetExt *pspsx; + HKEY hkBase, hkPropSheetHandlers; + PPSXA psxa = NULL; + + TRACE("(%p,%s,%u)\n", hKey, debugstr_w(pszSubKey), max_iface); + + if (max_iface == 0) + return NULL; + + /* Open the registry key */ + lRet = RegOpenKeyW(hKey, pszSubKey, &hkBase); + if (lRet != ERROR_SUCCESS) + return NULL; + + lRet = RegOpenKeyExW(hkBase, szPropSheetSubKey, 0, KEY_ENUMERATE_SUB_KEYS, &hkPropSheetHandlers); + RegCloseKey(hkBase); + if (lRet == ERROR_SUCCESS) + { + /* Create and initialize the Property Sheet Extensions Array */ + psxa = (PPSXA)LocalAlloc(LMEM_FIXED, FIELD_OFFSET(PSXA, pspsx[max_iface])); + if (psxa) + { + ZeroMemory(psxa, FIELD_OFFSET(PSXA, pspsx[max_iface])); + psxa->uiAllocated = max_iface; + + /* Enumerate all subkeys and attempt to load the shell extensions */ + dwIndex = 0; + do + { + dwHandlerLen = sizeof(szHandler) / sizeof(szHandler[0]); + lRet = RegEnumKeyExW(hkPropSheetHandlers, dwIndex++, szHandler, &dwHandlerLen, NULL, NULL, NULL, NULL); + if (lRet != ERROR_SUCCESS) + { + if (lRet == ERROR_MORE_DATA) + continue; + + if (lRet == ERROR_NO_MORE_ITEMS) + lRet = ERROR_SUCCESS; + break; + } + + dwClsidSize = sizeof(szClsidHandler); + if (SHGetValueW(hkPropSheetHandlers, szHandler, NULL, NULL, szClsidHandler, &dwClsidSize) == ERROR_SUCCESS) + { + /* Force a NULL-termination and convert the string */ + szClsidHandler[(sizeof(szClsidHandler) / sizeof(szClsidHandler[0])) - 1] = 0; + if (SUCCEEDED(SHCLSIDFromStringW(szClsidHandler, &clsid))) + { + /* Attempt to get an IShellPropSheetExt and an IShellExtInit instance. + Only if both interfaces are supported it's a real shell extension. + Then call IShellExtInit's Initialize method. */ + if (SUCCEEDED(CoCreateInstance(&clsid, NULL, CLSCTX_INPROC_SERVER/* | CLSCTX_NO_CODE_DOWNLOAD */, &IID_IShellPropSheetExt, (LPVOID *)&pspsx))) + { + if (SUCCEEDED(pspsx->lpVtbl->QueryInterface(pspsx, &IID_IShellExtInit, (PVOID *)&psxi))) + { + if (SUCCEEDED(psxi->lpVtbl->Initialize(psxi, NULL, NULL, hKey))) + { + /* Add the IShellPropSheetExt instance to the array */ + psxa->pspsx[psxa->uiCount++] = pspsx; + } + else + { + psxi->lpVtbl->Release(psxi); + pspsx->lpVtbl->Release(pspsx); + } + } + else + pspsx->lpVtbl->Release(pspsx); + } + } + } + + } while (psxa->uiCount != psxa->uiAllocated); + } + else + lRet = ERROR_NOT_ENOUGH_MEMORY; + + RegCloseKey(hkPropSheetHandlers); + } + + if (lRet != ERROR_SUCCESS && psxa) + { + SHDestroyPropSheetExtArray((HPSXA)psxa); + psxa = NULL; + } + + return (HPSXA)psxa; } /************************************************************************* @@ -1536,8 +1685,30 @@ HPSXA WINAPI SHCreatePropSheetExtArray(HKEY hKey, LPCWSTR pszSubKey, UINT max_if */ UINT WINAPI SHReplaceFromPropSheetExtArray(HPSXA hpsxa, UINT uPageID, LPFNADDPROPSHEETPAGE lpfnReplaceWith, LPARAM lParam) { - FIXME("(%p,%u,%p,%08lx)stub\n", hpsxa, uPageID, lpfnReplaceWith, lParam); - return 0; + PSXA_CALL Call; + UINT i; + PPSXA psxa = (PPSXA)hpsxa; + + TRACE("(%p,%u,%p,%08lx)\n", hpsxa, uPageID, lpfnReplaceWith, lParam); + + if (psxa) + { + ZeroMemory(&Call, sizeof(Call)); + Call.lpfnAddReplaceWith = lpfnReplaceWith; + Call.lParam = lParam; + + /* Call the ReplacePage method of all registered IShellPropSheetExt interfaces. + Each shell extension is only allowed to call the callback once during the callback. */ + for (i = 0; i != psxa->uiCount; i++) + { + Call.bCalled = FALSE; + psxa->pspsx[i]->lpVtbl->ReplacePage(psxa->pspsx[i], uPageID, PsxaCall, (LPARAM)&Call); + } + + return Call.uiCount; + } + + return 0; } /************************************************************************* @@ -1545,7 +1716,20 @@ UINT WINAPI SHReplaceFromPropSheetExtArray(HPSXA hpsxa, UINT uPageID, LPFNADDPRO */ void WINAPI SHDestroyPropSheetExtArray(HPSXA hpsxa) { - FIXME("(%p)stub\n", hpsxa); + UINT i; + PPSXA psxa = (PPSXA)hpsxa; + + TRACE("(%p)\n", hpsxa); + + if (psxa) + { + for (i = 0; i != psxa->uiCount; i++) + { + psxa->pspsx[i]->lpVtbl->Release(psxa->pspsx[i]); + } + + LocalFree((HLOCAL)psxa); + } } /************************************************************************* diff --git a/include/shlguid.h b/include/shlguid.h index e5a7aff5e8c..e07c38473e0 100644 --- a/include/shlguid.h +++ b/include/shlguid.h @@ -41,7 +41,6 @@ DEFINE_SHLGUID(CGID_ShellServiceObject, 0x000214D2L, 0, 0); DEFINE_SHLGUID(CGID_ExplorerBarDoc, 0x000214D3L, 0, 0); DEFINE_SHLGUID(IID_IShellIcon, 0x000214E5L, 0, 0); -DEFINE_SHLGUID(IID_IShellPropSheetExt, 0x000214E9L, 0, 0); DEFINE_SHLGUID(IID_IShellDetails, 0x000214ECL, 0, 0); DEFINE_SHLGUID(IID_IDelayedRelease, 0x000214EDL, 0, 0); DEFINE_SHLGUID(IID_IShellCopyHookA, 0x000214EFL, 0, 0); @@ -54,6 +53,7 @@ DEFINE_SHLGUID(IID_IRemoteComputer, 0x000214FEL, 0, 0); DEFINE_SHLGUID(IID_IQueryInfo, 0x00021500L, 0, 0); /* avoid duplicate definitions with shobjidl.h (FIXME) */ +/* DEFINE_SHLGUID(IID_IShellPropSheetExt, 0x000214E9L, 0, 0); */ /* DEFINE_SHLGUID(IID_IExtractIconA, 0x000214EBL, 0, 0); */ /* DEFINE_SHLGUID(IID_IExtractIconW, 0x000214FAL, 0, 0); */ /* DEFINE_SHLGUID(IID_IContextMenu, 0x000214E4L, 0, 0); */ diff --git a/include/shobjidl.idl b/include/shobjidl.idl index 751437f5f01..474b2643918 100644 --- a/include/shobjidl.idl +++ b/include/shobjidl.idl @@ -84,6 +84,38 @@ interface IEnumIDList : IUnknown HRESULT Clone( [out] IEnumIDList **ppenum ); } +/***************************************************************************** + * IShellPropSheetExt interface + */ +cpp_quote("#if 0") + typedef LPARAM LPFNSVADDPROPSHEETPAGE; +cpp_quote("#else") +cpp_quote("#include ") +cpp_quote("typedef LPFNADDPROPSHEETPAGE LPFNSVADDPROPSHEETPAGE;") +cpp_quote("#endif") + +[ + object, + uuid(000214E9-0000-0000-C000-000000000046), + pointer_default(unique) +] +interface IShellPropSheetExt : IUnknown +{ + enum tagSHELLPROPSHEETEXTPAGEID { + EXPPS_FILETYPES = 0x1 + }; + + typedef UINT EXPPS; + + HRESULT AddPages( + [in] LPFNSVADDPROPSHEETPAGE pfnAddPage, + [in] LPARAM lParam); + HRESULT ReplacePage( + [in] EXPPS uPageID, + [in] LPFNSVADDPROPSHEETPAGE pfnReplaceWith, + [in] LPARAM lParam); +} +typedef IShellPropSheetExt *LPSHELLPROPSHEETEXT; /***************************************************************************** * IShellFolder interface @@ -394,13 +426,6 @@ interface IShellView : IOleWindow SVUIA_INPLACEACTIVATE = 3 } SVUIA_STATUS; -cpp_quote("#if 0") - typedef LPARAM LPFNSVADDPROPSHEETPAGE; -cpp_quote("#else") -cpp_quote("#include ") -cpp_quote("typedef LPFNADDPROPSHEETPAGE LPFNSVADDPROPSHEETPAGE;") -cpp_quote("#endif") - HRESULT TranslateAccelerator( [in] MSG *pmsg ); HRESULT EnableModeless( [in] BOOL fEnable ); HRESULT UIActivate( [in] UINT uState );