2016-08-10 18:56:48 +00:00
|
|
|
/*
|
|
|
|
* ReactOS Shell
|
|
|
|
*
|
|
|
|
* Copyright 2016 Giannis Adamopoulos
|
|
|
|
*
|
|
|
|
* 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 Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <precomp.h>
|
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL (shell);
|
|
|
|
|
2016-11-17 14:35:19 +00:00
|
|
|
HRESULT CALLBACK RegFolderContextMenuCallback(IShellFolder *psf,
|
|
|
|
HWND hwnd,
|
|
|
|
IDataObject *pdtobj,
|
|
|
|
UINT uMsg,
|
|
|
|
WPARAM wParam,
|
|
|
|
LPARAM lParam)
|
|
|
|
{
|
|
|
|
if (uMsg != DFM_INVOKECOMMAND || wParam != DFM_CMD_PROPERTIES)
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
|
PIDLIST_ABSOLUTE pidlFolder;
|
|
|
|
PUITEMID_CHILD *apidl;
|
|
|
|
UINT cidl;
|
|
|
|
HRESULT hr = SH_GetApidlFromDataObject(pdtobj, &pidlFolder, &apidl, &cidl);
|
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
|
|
return hr;
|
|
|
|
|
|
|
|
if (_ILIsMyComputer(apidl[0]))
|
|
|
|
{
|
2019-08-15 20:21:21 +00:00
|
|
|
if (32 >= (UINT_PTR)ShellExecuteW(hwnd,
|
|
|
|
L"open",
|
|
|
|
L"rundll32.exe",
|
|
|
|
L"shell32.dll,Control_RunDLL sysdm.cpl",
|
|
|
|
NULL,
|
|
|
|
SW_SHOWNORMAL))
|
|
|
|
{
|
2016-11-17 14:35:19 +00:00
|
|
|
hr = E_FAIL;
|
2019-08-15 20:21:21 +00:00
|
|
|
}
|
2016-11-17 14:35:19 +00:00
|
|
|
}
|
|
|
|
else if (_ILIsDesktop(apidl[0]))
|
|
|
|
{
|
2019-08-15 20:21:21 +00:00
|
|
|
if (32 >= (UINT_PTR)ShellExecuteW(hwnd,
|
|
|
|
L"open",
|
|
|
|
L"rundll32.exe",
|
|
|
|
L"shell32.dll,Control_RunDLL desk.cpl",
|
|
|
|
NULL,
|
|
|
|
SW_SHOWNORMAL))
|
|
|
|
{
|
2016-11-17 14:35:19 +00:00
|
|
|
hr = E_FAIL;
|
2019-08-15 20:21:21 +00:00
|
|
|
}
|
2016-11-17 14:35:19 +00:00
|
|
|
}
|
|
|
|
else if (_ILIsNetHood(apidl[0]))
|
|
|
|
{
|
|
|
|
// FIXME path!
|
2019-08-15 20:21:21 +00:00
|
|
|
if (32 >= (UINT_PTR)ShellExecuteW(NULL,
|
|
|
|
L"open",
|
|
|
|
L"explorer.exe",
|
|
|
|
L"::{7007ACC7-3202-11D1-AAD2-00805FC1270E}",
|
|
|
|
NULL,
|
|
|
|
SW_SHOWDEFAULT))
|
|
|
|
{
|
2016-11-17 14:35:19 +00:00
|
|
|
hr = E_FAIL;
|
2019-08-15 20:21:21 +00:00
|
|
|
}
|
2016-11-17 14:35:19 +00:00
|
|
|
}
|
|
|
|
else if (_ILIsBitBucket(apidl[0]))
|
|
|
|
{
|
|
|
|
/* FIXME: detect the drive path of bitbucket if appropiate */
|
|
|
|
if (!SH_ShowRecycleBinProperties(L'C'))
|
|
|
|
hr = E_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
SHFree(pidlFolder);
|
|
|
|
_ILFreeaPidl(apidl, cidl);
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
2016-11-15 20:14:56 +00:00
|
|
|
HRESULT CGuidItemContextMenu_CreateInstance(PCIDLIST_ABSOLUTE pidlFolder,
|
|
|
|
HWND hwnd,
|
|
|
|
UINT cidl,
|
|
|
|
PCUITEMID_CHILD_ARRAY apidl,
|
|
|
|
IShellFolder *psf,
|
|
|
|
IContextMenu **ppcm)
|
|
|
|
{
|
|
|
|
HKEY hKeys[10];
|
|
|
|
UINT cKeys = 0;
|
|
|
|
|
|
|
|
GUID *pGuid = _ILGetGUIDPointer(apidl[0]);
|
|
|
|
if (pGuid)
|
|
|
|
{
|
|
|
|
LPOLESTR pwszCLSID;
|
|
|
|
WCHAR key[60];
|
|
|
|
|
|
|
|
wcscpy(key, L"CLSID\\");
|
|
|
|
HRESULT hr = StringFromCLSID(*pGuid, &pwszCLSID);
|
|
|
|
if (hr == S_OK)
|
|
|
|
{
|
|
|
|
wcscpy(&key[6], pwszCLSID);
|
|
|
|
AddClassKeyToArray(key, hKeys, &cKeys);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
AddClassKeyToArray(L"Folder", hKeys, &cKeys);
|
|
|
|
|
2016-11-17 14:35:19 +00:00
|
|
|
return CDefFolderMenu_Create2(pidlFolder, hwnd, cidl, apidl, psf, RegFolderContextMenuCallback, cKeys, hKeys, ppcm);
|
2016-11-15 20:14:56 +00:00
|
|
|
}
|
|
|
|
|
2016-08-12 12:21:13 +00:00
|
|
|
HRESULT CGuidItemExtractIcon_CreateInstance(LPCITEMIDLIST pidl, REFIID iid, LPVOID * ppvOut)
|
|
|
|
{
|
|
|
|
CComPtr<IDefaultExtractIconInit> initIcon;
|
|
|
|
HRESULT hr;
|
|
|
|
GUID const * riid;
|
|
|
|
int icon_idx;
|
|
|
|
WCHAR wTemp[MAX_PATH];
|
|
|
|
|
|
|
|
hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit,&initIcon));
|
|
|
|
if (FAILED(hr))
|
|
|
|
return hr;
|
|
|
|
|
|
|
|
if (_ILIsDesktop(pidl))
|
|
|
|
{
|
|
|
|
initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_DESKTOP);
|
|
|
|
return initIcon->QueryInterface(iid, ppvOut);
|
|
|
|
}
|
|
|
|
|
|
|
|
riid = _ILGetGUIDPointer(pidl);
|
|
|
|
if (!riid)
|
|
|
|
return E_FAIL;
|
|
|
|
|
|
|
|
/* my computer and other shell extensions */
|
|
|
|
static const WCHAR fmt[] = { 'C', 'L', 'S', 'I', 'D', '\\',
|
|
|
|
'{', '%', '0', '8', 'l', 'x', '-', '%', '0', '4', 'x', '-', '%', '0', '4', 'x', '-',
|
|
|
|
'%', '0', '2', 'x', '%', '0', '2', 'x', '-', '%', '0', '2', 'x', '%', '0', '2', 'x',
|
|
|
|
'%', '0', '2', 'x', '%', '0', '2', 'x', '%', '0', '2', 'x', '%', '0', '2', 'x', '}', 0
|
|
|
|
};
|
|
|
|
WCHAR xriid[50];
|
|
|
|
|
|
|
|
swprintf(xriid, fmt,
|
|
|
|
riid->Data1, riid->Data2, riid->Data3,
|
|
|
|
riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
|
|
|
|
riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]);
|
|
|
|
|
|
|
|
const WCHAR* iconname = NULL;
|
|
|
|
if (_ILIsBitBucket(pidl))
|
|
|
|
{
|
|
|
|
static const WCHAR szFull[] = {'F','u','l','l',0};
|
|
|
|
static const WCHAR szEmpty[] = {'E','m','p','t','y',0};
|
|
|
|
CComPtr<IEnumIDList> EnumIDList;
|
|
|
|
CoInitialize(NULL);
|
|
|
|
|
|
|
|
CComPtr<IShellFolder2> psfRecycleBin;
|
|
|
|
CComPtr<IShellFolder> psfDesktop;
|
|
|
|
hr = SHGetDesktopFolder(&psfDesktop);
|
|
|
|
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder2, &psfRecycleBin));
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
hr = psfRecycleBin->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &EnumIDList);
|
|
|
|
|
|
|
|
ULONG itemcount;
|
|
|
|
LPITEMIDLIST pidl = NULL;
|
|
|
|
if (SUCCEEDED(hr) && (hr = EnumIDList->Next(1, &pidl, &itemcount)) == S_OK)
|
|
|
|
{
|
|
|
|
CoTaskMemFree(pidl);
|
|
|
|
iconname = szFull;
|
|
|
|
} else {
|
|
|
|
iconname = szEmpty;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (HCR_GetIconW(xriid, wTemp, iconname, MAX_PATH, &icon_idx))
|
|
|
|
{
|
|
|
|
initIcon->SetNormalIcon(wTemp, icon_idx);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (IsEqualGUID(*riid, CLSID_MyComputer))
|
|
|
|
initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_MY_COMPUTER);
|
|
|
|
else if (IsEqualGUID(*riid, CLSID_MyDocuments))
|
|
|
|
initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_MY_DOCUMENTS);
|
|
|
|
else if (IsEqualGUID(*riid, CLSID_NetworkPlaces))
|
|
|
|
initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_MY_NETWORK_PLACES);
|
|
|
|
else
|
|
|
|
initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_FOLDER);
|
|
|
|
}
|
|
|
|
|
|
|
|
return initIcon->QueryInterface(iid, ppvOut);
|
|
|
|
}
|
|
|
|
|
2017-07-16 15:13:02 +00:00
|
|
|
class CRegFolderEnum :
|
|
|
|
public CEnumIDListBase
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
CRegFolderEnum();
|
|
|
|
~CRegFolderEnum();
|
|
|
|
HRESULT Initialize(LPCWSTR lpszEnumKeyName, DWORD dwFlags);
|
|
|
|
HRESULT AddItemsFromKey(HKEY hkey_root, LPCWSTR szRepPath);
|
|
|
|
|
|
|
|
BEGIN_COM_MAP(CRegFolderEnum)
|
|
|
|
COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
|
|
|
|
END_COM_MAP()
|
|
|
|
};
|
|
|
|
|
|
|
|
CRegFolderEnum::CRegFolderEnum()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CRegFolderEnum::~CRegFolderEnum()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT CRegFolderEnum::Initialize(LPCWSTR lpszEnumKeyName, DWORD dwFlags)
|
|
|
|
{
|
|
|
|
WCHAR KeyName[MAX_PATH];
|
|
|
|
static const WCHAR KeyNameFormat[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\%s\\Namespace";
|
|
|
|
|
|
|
|
if (!(dwFlags & SHCONTF_FOLDERS))
|
|
|
|
return S_OK;
|
|
|
|
|
|
|
|
HRESULT hr = StringCchPrintfW(KeyName, MAX_PATH, KeyNameFormat, lpszEnumKeyName);
|
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
|
|
return hr;
|
|
|
|
|
|
|
|
AddItemsFromKey(HKEY_LOCAL_MACHINE, KeyName);
|
|
|
|
AddItemsFromKey(HKEY_CURRENT_USER, KeyName);
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT CRegFolderEnum::AddItemsFromKey(HKEY hkey_root, LPCWSTR szRepPath)
|
|
|
|
{
|
|
|
|
WCHAR name[MAX_PATH];
|
|
|
|
HKEY hkey;
|
|
|
|
|
|
|
|
if (RegOpenKeyW(hkey_root, szRepPath, &hkey) != ERROR_SUCCESS)
|
|
|
|
return S_FALSE;
|
|
|
|
|
|
|
|
for (int idx = 0; ; idx++)
|
|
|
|
{
|
|
|
|
if (RegEnumKeyW(hkey, idx, name, MAX_PATH) != ERROR_SUCCESS)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* If the name of the key is not a guid try to get the default value of the key */
|
|
|
|
if (name[0] != L'{')
|
|
|
|
{
|
|
|
|
DWORD dwSize = sizeof(name);
|
|
|
|
RegGetValueW(hkey, name, NULL, RRF_RT_REG_SZ, NULL, name, &dwSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*name == '{')
|
|
|
|
{
|
|
|
|
LPITEMIDLIST pidl = _ILCreateGuidFromStrW(name);
|
|
|
|
|
|
|
|
if (pidl)
|
|
|
|
AddToEnumList(pidl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RegCloseKey(hkey);
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2016-08-10 18:56:48 +00:00
|
|
|
class CRegFolder :
|
|
|
|
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
|
|
|
public IShellFolder2
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
GUID m_guid;
|
|
|
|
CAtlStringW m_rootPath;
|
2017-07-16 15:13:02 +00:00
|
|
|
CAtlStringW m_enumKeyName;
|
2016-08-10 18:56:48 +00:00
|
|
|
CComHeapPtr<ITEMIDLIST> m_pidlRoot;
|
|
|
|
|
2016-08-12 12:21:13 +00:00
|
|
|
HRESULT GetGuidItemAttributes (LPCITEMIDLIST pidl, LPDWORD pdwAttributes);
|
2016-08-10 18:56:48 +00:00
|
|
|
public:
|
|
|
|
CRegFolder();
|
|
|
|
~CRegFolder();
|
2017-07-16 15:13:02 +00:00
|
|
|
HRESULT WINAPI Initialize(const GUID *pGuid, LPCITEMIDLIST pidlRoot, LPCWSTR lpszPath, LPCWSTR lpszEnumKeyName);
|
2016-08-10 18:56:48 +00:00
|
|
|
|
|
|
|
// IShellFolder
|
|
|
|
virtual HRESULT WINAPI ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName, ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes);
|
|
|
|
virtual HRESULT WINAPI EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList);
|
|
|
|
virtual HRESULT WINAPI BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut);
|
|
|
|
virtual HRESULT WINAPI BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut);
|
|
|
|
virtual HRESULT WINAPI CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2);
|
|
|
|
virtual HRESULT WINAPI CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut);
|
|
|
|
virtual HRESULT WINAPI GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut);
|
|
|
|
virtual HRESULT WINAPI GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut);
|
|
|
|
virtual HRESULT WINAPI GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet);
|
|
|
|
virtual HRESULT WINAPI SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut);
|
|
|
|
|
|
|
|
/* ShellFolder2 */
|
|
|
|
virtual HRESULT WINAPI GetDefaultSearchGUID(GUID *pguid);
|
|
|
|
virtual HRESULT WINAPI EnumSearches(IEnumExtraSearch **ppenum);
|
|
|
|
virtual HRESULT WINAPI GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay);
|
|
|
|
virtual HRESULT WINAPI GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags);
|
|
|
|
virtual HRESULT WINAPI GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv);
|
|
|
|
virtual HRESULT WINAPI GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd);
|
|
|
|
virtual HRESULT WINAPI MapColumnToSCID(UINT column, SHCOLUMNID *pscid);
|
|
|
|
|
|
|
|
DECLARE_NOT_AGGREGATABLE(CRegFolder)
|
|
|
|
|
|
|
|
DECLARE_PROTECT_FINAL_CONSTRUCT()
|
|
|
|
|
|
|
|
BEGIN_COM_MAP(CRegFolder)
|
|
|
|
COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2)
|
|
|
|
COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder)
|
|
|
|
END_COM_MAP()
|
|
|
|
};
|
|
|
|
|
|
|
|
CRegFolder::CRegFolder()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
CRegFolder::~CRegFolder()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-07-16 15:13:02 +00:00
|
|
|
HRESULT WINAPI CRegFolder::Initialize(const GUID *pGuid, LPCITEMIDLIST pidlRoot, LPCWSTR lpszPath, LPCWSTR lpszEnumKeyName)
|
2016-08-10 18:56:48 +00:00
|
|
|
{
|
|
|
|
memcpy(&m_guid, pGuid, sizeof(m_guid));
|
|
|
|
|
|
|
|
m_rootPath = lpszPath;
|
|
|
|
if (!m_rootPath)
|
|
|
|
return E_OUTOFMEMORY;
|
|
|
|
|
2017-07-16 15:13:02 +00:00
|
|
|
m_enumKeyName = lpszEnumKeyName;
|
|
|
|
if (!m_enumKeyName)
|
|
|
|
return E_OUTOFMEMORY;
|
|
|
|
|
2016-08-10 18:56:48 +00:00
|
|
|
m_pidlRoot.Attach(ILClone(pidlRoot));
|
|
|
|
if (!m_pidlRoot)
|
|
|
|
return E_OUTOFMEMORY;
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2016-08-12 12:21:13 +00:00
|
|
|
HRESULT CRegFolder::GetGuidItemAttributes (LPCITEMIDLIST pidl, LPDWORD pdwAttributes)
|
|
|
|
{
|
2016-11-15 20:14:56 +00:00
|
|
|
DWORD dwAttributes = *pdwAttributes;
|
|
|
|
|
2016-08-12 12:21:13 +00:00
|
|
|
/* First try to get them from the registry */
|
2016-11-15 20:14:56 +00:00
|
|
|
if (!HCR_GetFolderAttributes(pidl, pdwAttributes))
|
2016-08-12 12:21:13 +00:00
|
|
|
{
|
2016-11-15 20:14:56 +00:00
|
|
|
/* We couldn't get anything */
|
|
|
|
*pdwAttributes = 0;
|
2016-08-12 12:21:13 +00:00
|
|
|
}
|
|
|
|
|
2016-11-15 20:14:56 +00:00
|
|
|
/* Items have more attributes when on desktop */
|
|
|
|
if (_ILIsDesktop(m_pidlRoot))
|
|
|
|
{
|
|
|
|
*pdwAttributes |= (dwAttributes & (SFGAO_CANLINK|SFGAO_CANDELETE|SFGAO_CANRENAME|SFGAO_HASPROPSHEET));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* In any case, links can be created */
|
|
|
|
if (*pdwAttributes == NULL)
|
|
|
|
{
|
|
|
|
*pdwAttributes |= (dwAttributes & SFGAO_CANLINK);
|
|
|
|
}
|
2016-08-12 12:21:13 +00:00
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
2016-08-10 18:56:48 +00:00
|
|
|
HRESULT WINAPI CRegFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
|
|
|
|
ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, ULONG *pdwAttributes)
|
|
|
|
{
|
2016-08-12 12:21:13 +00:00
|
|
|
LPITEMIDLIST pidl;
|
|
|
|
|
|
|
|
if (!lpszDisplayName || !ppidl)
|
|
|
|
return E_INVALIDARG;
|
|
|
|
|
|
|
|
*ppidl = 0;
|
|
|
|
|
|
|
|
if (pchEaten)
|
|
|
|
*pchEaten = 0;
|
|
|
|
|
|
|
|
UINT cch = wcslen(lpszDisplayName);
|
|
|
|
if (cch < 39 || lpszDisplayName[0] != L':' || lpszDisplayName[1] != L':')
|
|
|
|
return E_FAIL;
|
|
|
|
|
|
|
|
pidl = _ILCreateGuidFromStrW(lpszDisplayName + 2);
|
|
|
|
if (pidl == NULL)
|
|
|
|
return E_FAIL;
|
|
|
|
|
|
|
|
if (cch < 41)
|
|
|
|
{
|
|
|
|
*ppidl = pidl;
|
|
|
|
if (pdwAttributes && *pdwAttributes)
|
|
|
|
{
|
|
|
|
GetGuidItemAttributes(*ppidl, pdwAttributes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
HRESULT hr = SHELL32_ParseNextElement(this, hwndOwner, pbc, &pidl, lpszDisplayName + 41, pchEaten, pdwAttributes);
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
*ppidl = pidl;
|
|
|
|
}
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return S_OK;
|
2016-08-10 18:56:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT WINAPI CRegFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
|
|
|
|
{
|
2017-07-16 15:13:02 +00:00
|
|
|
return ShellObjectCreatorInit<CRegFolderEnum>(m_enumKeyName, dwFlags, IID_PPV_ARG(IEnumIDList, ppEnumIDList));
|
2016-08-10 18:56:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT WINAPI CRegFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
|
|
|
|
{
|
2016-08-12 12:21:13 +00:00
|
|
|
CComPtr<IPersistFolder> pFolder;
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
if (!ppvOut || !pidl || !pidl->mkid.cb)
|
|
|
|
return E_INVALIDARG;
|
|
|
|
|
|
|
|
*ppvOut = NULL;
|
|
|
|
|
|
|
|
GUID *pGUID = _ILGetGUIDPointer(pidl);
|
|
|
|
if (!pGUID)
|
|
|
|
{
|
|
|
|
ERR("CRegFolder::BindToObject called for non guid item!\n");
|
|
|
|
return E_INVALIDARG;
|
|
|
|
}
|
|
|
|
|
2017-07-07 20:34:27 +00:00
|
|
|
hr = SHELL32_BindToSF(m_pidlRoot, NULL, pidl, pGUID, riid, ppvOut);
|
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
2016-08-12 12:21:13 +00:00
|
|
|
return hr;
|
|
|
|
|
2017-07-07 20:34:27 +00:00
|
|
|
return S_OK;
|
2016-08-10 18:56:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT WINAPI CRegFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
|
|
|
|
{
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT WINAPI CRegFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
|
|
|
|
{
|
2016-08-12 12:21:13 +00:00
|
|
|
if (!pidl1 || !pidl2 || pidl1->mkid.cb == 0 || pidl2->mkid.cb == 0)
|
|
|
|
{
|
|
|
|
ERR("Got an empty pidl!\n");
|
|
|
|
return E_INVALIDARG;
|
|
|
|
}
|
|
|
|
|
2016-11-04 23:11:29 +00:00
|
|
|
GUID const *clsid1 = _ILGetGUIDPointer (pidl1);
|
|
|
|
GUID const *clsid2 = _ILGetGUIDPointer (pidl2);
|
2016-08-12 12:21:13 +00:00
|
|
|
|
2016-11-04 23:11:29 +00:00
|
|
|
if (!clsid1 && !clsid2)
|
2016-08-12 12:21:13 +00:00
|
|
|
{
|
|
|
|
ERR("Got no guid pidl!\n");
|
|
|
|
return E_INVALIDARG;
|
|
|
|
}
|
2016-11-04 23:11:29 +00:00
|
|
|
else if (clsid1 && clsid2)
|
2016-08-12 12:21:13 +00:00
|
|
|
{
|
2016-11-04 23:11:29 +00:00
|
|
|
if (memcmp(clsid1, clsid2, sizeof(GUID)) == 0)
|
|
|
|
return SHELL32_CompareChildren(this, lParam, pidl1, pidl2);
|
|
|
|
|
2016-08-12 12:21:13 +00:00
|
|
|
return SHELL32_CompareDetails(this, lParam, pidl1, pidl2);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Guid folders come first compared to everything else */
|
2016-11-04 23:11:29 +00:00
|
|
|
return MAKE_COMPARE_HRESULT(clsid1 ? -1 : 1);
|
2016-08-10 18:56:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT WINAPI CRegFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut)
|
|
|
|
{
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT WINAPI CRegFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut)
|
|
|
|
{
|
|
|
|
if (!rgfInOut || !cidl || !apidl)
|
|
|
|
return E_INVALIDARG;
|
|
|
|
|
|
|
|
if (*rgfInOut == 0)
|
|
|
|
*rgfInOut = ~0;
|
|
|
|
|
|
|
|
while(cidl > 0 && *apidl)
|
|
|
|
{
|
|
|
|
if (_ILIsSpecialFolder(*apidl))
|
2016-08-12 12:21:13 +00:00
|
|
|
GetGuidItemAttributes(*apidl, rgfInOut);
|
2016-08-10 18:56:48 +00:00
|
|
|
else
|
|
|
|
ERR("Got an unkown pidl here!\n");
|
|
|
|
apidl++;
|
|
|
|
cidl--;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
|
|
|
|
*rgfInOut &= ~SFGAO_VALIDATE;
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT WINAPI CRegFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
|
|
|
|
REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
|
|
|
|
{
|
|
|
|
LPVOID pObj = NULL;
|
|
|
|
HRESULT hr = E_INVALIDARG;
|
|
|
|
|
|
|
|
if (!ppvOut)
|
|
|
|
return hr;
|
|
|
|
|
|
|
|
*ppvOut = NULL;
|
|
|
|
|
|
|
|
if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1))
|
|
|
|
{
|
2016-08-12 12:21:13 +00:00
|
|
|
hr = CGuidItemExtractIcon_CreateInstance(apidl[0], riid, &pObj);
|
2016-08-10 18:56:48 +00:00
|
|
|
}
|
2016-11-15 20:14:56 +00:00
|
|
|
else if (IsEqualIID (riid, IID_IContextMenu) && (cidl >= 1))
|
|
|
|
{
|
|
|
|
if (!_ILGetGUIDPointer (apidl[0]))
|
|
|
|
{
|
|
|
|
ERR("Got non guid item!\n");
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
hr = CGuidItemContextMenu_CreateInstance(m_pidlRoot, hwndOwner, cidl, apidl, static_cast<IShellFolder*>(this), (IContextMenu**)&pObj);
|
|
|
|
}
|
2016-11-17 14:35:19 +00:00
|
|
|
else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
|
|
|
|
{
|
|
|
|
hr = IDataObject_Constructor (hwndOwner, m_pidlRoot, apidl, cidl, (IDataObject **)&pObj);
|
|
|
|
}
|
2016-08-10 18:56:48 +00:00
|
|
|
else
|
2016-11-15 20:14:56 +00:00
|
|
|
{
|
2016-08-10 18:56:48 +00:00
|
|
|
hr = E_NOINTERFACE;
|
2016-11-15 20:14:56 +00:00
|
|
|
}
|
2016-08-10 18:56:48 +00:00
|
|
|
|
|
|
|
*ppvOut = pObj;
|
|
|
|
return hr;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT WINAPI CRegFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
|
|
|
|
{
|
2016-11-15 14:25:05 +00:00
|
|
|
if (!strRet || (!_ILIsSpecialFolder(pidl) && pidl != NULL))
|
2016-08-10 18:56:48 +00:00
|
|
|
return E_INVALIDARG;
|
|
|
|
|
2016-11-15 14:25:05 +00:00
|
|
|
if (!pidl || !pidl->mkid.cb)
|
2016-08-10 18:56:48 +00:00
|
|
|
{
|
2016-11-05 19:55:29 +00:00
|
|
|
if ((GET_SHGDN_RELATION(dwFlags) == SHGDN_NORMAL) && (GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING))
|
|
|
|
{
|
|
|
|
LPWSTR pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
|
|
|
|
if (!pszPath)
|
|
|
|
return E_OUTOFMEMORY;
|
2016-08-10 18:56:48 +00:00
|
|
|
|
2016-11-05 19:55:29 +00:00
|
|
|
/* parsing name like ::{...} */
|
|
|
|
pszPath[0] = ':';
|
|
|
|
pszPath[1] = ':';
|
|
|
|
SHELL32_GUIDToStringW(m_guid, &pszPath[2]);
|
2016-08-10 18:56:48 +00:00
|
|
|
|
2016-11-05 19:55:29 +00:00
|
|
|
strRet->uType = STRRET_WSTR;
|
|
|
|
strRet->pOleStr = pszPath;
|
2016-08-10 18:56:48 +00:00
|
|
|
|
2016-11-05 19:55:29 +00:00
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-07-07 20:34:27 +00:00
|
|
|
BOOL bRet;
|
|
|
|
WCHAR wstrName[MAX_PATH+1];
|
|
|
|
bRet = HCR_GetClassNameW(m_guid, wstrName, MAX_PATH);
|
|
|
|
if (!bRet)
|
|
|
|
return E_FAIL;
|
|
|
|
|
|
|
|
return SHSetStrRet(strRet, wstrName);
|
|
|
|
|
2016-11-05 19:55:29 +00:00
|
|
|
}
|
2016-08-10 18:56:48 +00:00
|
|
|
}
|
|
|
|
|
2016-08-12 12:21:13 +00:00
|
|
|
HRESULT hr;
|
|
|
|
GUID const *clsid = _ILGetGUIDPointer (pidl);
|
|
|
|
|
|
|
|
/* First of all check if we need to query the name from the child item */
|
|
|
|
if (GET_SHGDN_FOR (dwFlags) == SHGDN_FORPARSING &&
|
|
|
|
GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL)
|
|
|
|
{
|
|
|
|
int bWantsForParsing = FALSE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We can only get a filesystem path from a shellfolder if the
|
|
|
|
* value WantsFORPARSING in CLSID\\{...}\\shellfolder exists.
|
|
|
|
*
|
|
|
|
* Exception: The MyComputer folder doesn't have this key,
|
|
|
|
* but any other filesystem backed folder it needs it.
|
|
|
|
*/
|
|
|
|
if (IsEqualIID (*clsid, CLSID_MyComputer))
|
|
|
|
{
|
|
|
|
bWantsForParsing = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
HKEY hkeyClass;
|
|
|
|
if (HCR_RegOpenClassIDKey(*clsid, &hkeyClass))
|
|
|
|
{
|
|
|
|
LONG res = SHGetValueW(hkeyClass, L"Shellfolder", L"WantsForParsing", NULL, NULL, NULL);
|
|
|
|
bWantsForParsing = (res == ERROR_SUCCESS);
|
|
|
|
RegCloseKey(hkeyClass);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bWantsForParsing)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* we need the filesystem path to the destination folder.
|
|
|
|
* Only the folder itself can know it
|
|
|
|
*/
|
|
|
|
return SHELL32_GetDisplayNameOfChild (this, pidl, dwFlags, strRet);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate the buffer for the result */
|
|
|
|
LPWSTR pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
|
|
|
|
if (!pszPath)
|
|
|
|
return E_OUTOFMEMORY;
|
|
|
|
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
|
|
if (GET_SHGDN_FOR (dwFlags) == SHGDN_FORPARSING)
|
2016-08-10 18:56:48 +00:00
|
|
|
{
|
2016-08-12 12:21:13 +00:00
|
|
|
wcscpy(pszPath, m_rootPath);
|
|
|
|
PWCHAR pItemName = &pszPath[wcslen(pszPath)];
|
|
|
|
|
|
|
|
/* parsing name like ::{...} */
|
|
|
|
pItemName[0] = ':';
|
|
|
|
pItemName[1] = ':';
|
|
|
|
SHELL32_GUIDToStringW (*clsid, &pItemName[2]);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* user friendly name */
|
|
|
|
if (!HCR_GetClassNameW (*clsid, pszPath, MAX_PATH))
|
|
|
|
hr = E_FAIL;
|
2016-08-10 18:56:48 +00:00
|
|
|
}
|
|
|
|
|
2016-08-12 12:21:13 +00:00
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
strRet->uType = STRRET_WSTR;
|
|
|
|
strRet->pOleStr = pszPath;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CoTaskMemFree(pszPath);
|
|
|
|
}
|
|
|
|
|
|
|
|
return hr;
|
2016-08-10 18:56:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT WINAPI CRegFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, /* simple pidl */
|
|
|
|
LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
|
|
|
|
{
|
2016-08-12 12:21:13 +00:00
|
|
|
GUID const *clsid = _ILGetGUIDPointer (pidl);
|
|
|
|
LPOLESTR pStr;
|
|
|
|
HRESULT hr;
|
|
|
|
WCHAR szName[100];
|
|
|
|
|
|
|
|
if (!clsid)
|
|
|
|
{
|
|
|
|
ERR("Pidl is not reg item!\n");
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
hr = StringFromCLSID(*clsid, &pStr);
|
|
|
|
if (FAILED_UNEXPECTEDLY(hr))
|
|
|
|
return hr;
|
|
|
|
|
|
|
|
swprintf(szName, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\%s", pStr);
|
|
|
|
|
|
|
|
DWORD cbData = (wcslen(lpName) + 1) * sizeof(WCHAR);
|
|
|
|
LONG res = SHSetValueW(HKEY_CURRENT_USER, szName, NULL, RRF_RT_REG_SZ, lpName, cbData);
|
|
|
|
|
|
|
|
CoTaskMemFree(pStr);
|
|
|
|
|
|
|
|
if (res == ERROR_SUCCESS)
|
|
|
|
{
|
|
|
|
*pPidlOut = ILClone(pidl);
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return E_FAIL;
|
2016-08-10 18:56:48 +00:00
|
|
|
}
|
|
|
|
|
2016-08-12 12:21:13 +00:00
|
|
|
|
2016-08-10 18:56:48 +00:00
|
|
|
HRESULT WINAPI CRegFolder::GetDefaultSearchGUID(GUID *pguid)
|
|
|
|
{
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT WINAPI CRegFolder::EnumSearches(IEnumExtraSearch ** ppenum)
|
|
|
|
{
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT WINAPI CRegFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
|
|
|
|
{
|
|
|
|
if (pSort)
|
|
|
|
*pSort = 0;
|
|
|
|
if (pDisplay)
|
|
|
|
*pDisplay = 0;
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT WINAPI CRegFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
|
|
|
|
{
|
|
|
|
if (iColumn >= 2)
|
|
|
|
return E_INVALIDARG;
|
|
|
|
*pcsFlags = SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT WINAPI CRegFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
|
|
|
|
{
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT WINAPI CRegFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
|
|
|
|
{
|
2017-06-12 18:38:26 +00:00
|
|
|
if (!psd)
|
2016-08-10 18:56:48 +00:00
|
|
|
return E_INVALIDARG;
|
|
|
|
|
2016-08-12 12:21:13 +00:00
|
|
|
GUID const *clsid = _ILGetGUIDPointer (pidl);
|
|
|
|
|
|
|
|
if (!clsid)
|
|
|
|
{
|
|
|
|
ERR("Pidl is not reg item!\n");
|
|
|
|
return E_INVALIDARG;
|
|
|
|
}
|
|
|
|
|
2017-06-12 18:38:26 +00:00
|
|
|
if (iColumn >= 3)
|
|
|
|
{
|
|
|
|
/* Return an empty string when we area asked for a column we don't support.
|
|
|
|
Only the regfolder is supposed to do this as it supports less columns compared to other folder
|
|
|
|
and its contents are supposed to be presented alongside items that support more columns. */
|
|
|
|
return SHSetStrRet(&psd->str, "");
|
|
|
|
}
|
|
|
|
|
2016-08-12 12:21:13 +00:00
|
|
|
switch(iColumn)
|
|
|
|
{
|
|
|
|
case 0: /* name */
|
|
|
|
return GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
|
2017-06-12 18:38:26 +00:00
|
|
|
case 1: /* comments */
|
2016-08-12 12:21:13 +00:00
|
|
|
HKEY hKey;
|
2017-06-12 18:38:26 +00:00
|
|
|
if (!HCR_RegOpenClassIDKey(*clsid, &hKey))
|
|
|
|
return SHSetStrRet(&psd->str, "");
|
|
|
|
|
|
|
|
psd->str.cStr[0] = 0x00;
|
|
|
|
psd->str.uType = STRRET_CSTR;
|
|
|
|
RegLoadMUIStringA(hKey, "InfoTip", psd->str.cStr, MAX_PATH, NULL, 0, NULL);
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
return S_OK;
|
|
|
|
case 2: /* type */
|
|
|
|
//return SHSetStrRet(&psd->str, resource_id); /* FIXME: translate */
|
|
|
|
return SHSetStrRet(&psd->str, "System Folder");
|
2016-08-12 12:21:13 +00:00
|
|
|
}
|
|
|
|
return E_FAIL;
|
2016-08-10 18:56:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
HRESULT WINAPI CRegFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
|
|
|
|
{
|
|
|
|
return E_NOTIMPL;
|
|
|
|
}
|
|
|
|
|
2016-08-12 12:21:13 +00:00
|
|
|
/* In latest windows version this is exported but it takes different arguments! */
|
2017-07-16 15:13:02 +00:00
|
|
|
HRESULT CRegFolder_CreateInstance(const GUID *pGuid, LPCITEMIDLIST pidlRoot, LPCWSTR lpszPath, LPCWSTR lpszEnumKeyName, REFIID riid, void **ppv)
|
2016-08-10 18:56:48 +00:00
|
|
|
{
|
2017-07-16 15:13:02 +00:00
|
|
|
return ShellObjectCreatorInit<CRegFolder>(pGuid, pidlRoot, lpszPath, lpszEnumKeyName, riid, ppv);
|
2016-08-10 18:56:48 +00:00
|
|
|
}
|