Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653/* * PROJECT: NT Object Namespace shell extension * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: System Registry folder class implementation * COPYRIGHT: Copyright 2015-2017 David Quintana <gigaherz@gmail.com> */
#include "precomp.h"
// {1C6D6E08-2332-4A7B-A94D-6432DB2B5AE6}const GUID CLSID_RegistryFolder = { 0x1c6d6e08, 0x2332, 0x4a7b, { 0xa9, 0x4d, 0x64, 0x32, 0xdb, 0x2b, 0x5a, 0xe6 } };
// {18A4B504-F6D8-4D8A-8661-6296514C2CF0}//static const GUID GUID_RegistryColumns = { 0x18a4b504, 0xf6d8, 0x4d8a, { 0x86, 0x61, 0x62, 0x96, 0x51, 0x4c, 0x2c, 0xf0 } };
enum RegistryColumns{ REGISTRY_COLUMN_NAME = 0, REGISTRY_COLUMN_TYPE, REGISTRY_COLUMN_VALUE, REGISTRY_COLUMN_END};
// -------------------------------// CRegistryFolderExtractIconCRegistryFolderExtractIcon::CRegistryFolderExtractIcon() : m_pcidlFolder(NULL), m_pcidlChild(NULL){
}
CRegistryFolderExtractIcon::~CRegistryFolderExtractIcon(){ if (m_pcidlFolder) ILFree((LPITEMIDLIST)m_pcidlFolder); if (m_pcidlChild) ILFree((LPITEMIDLIST)m_pcidlChild);}
HRESULT CRegistryFolderExtractIcon::Initialize(LPCWSTR ntPath, PCIDLIST_ABSOLUTE parent, UINT cidl, PCUITEMID_CHILD_ARRAY apidl){ m_pcidlFolder = ILClone(parent); if (cidl != 1) return E_INVALIDARG; m_pcidlChild = ILClone(apidl[0]); return S_OK;}
HRESULT STDMETHODCALLTYPE CRegistryFolderExtractIcon::GetIconLocation( UINT uFlags, LPWSTR szIconFile, UINT cchMax, INT *piIndex, UINT *pwFlags){ const RegPidlEntry * entry = (RegPidlEntry *)m_pcidlChild;
if ((entry->cb < sizeof(RegPidlEntry)) || (entry->magic != REGISTRY_PIDL_MAGIC)) return E_INVALIDARG;
UINT flags = 0;
switch (entry->entryType) { case REG_ENTRY_KEY: case REG_ENTRY_ROOT: GetModuleFileNameW(g_hInstance, szIconFile, cchMax); *piIndex = -IDI_REGISTRYKEY; *pwFlags = flags; return S_OK;
case REG_ENTRY_VALUE: case REG_ENTRY_VALUE_WITH_CONTENT: GetModuleFileNameW(g_hInstance, szIconFile, cchMax); *piIndex = -IDI_REGISTRYVALUE; *pwFlags = flags; return S_OK;
default: GetModuleFileNameW(g_hInstance, szIconFile, cchMax); *piIndex = -IDI_NTOBJECTITEM; *pwFlags = flags; return S_OK; }}
HRESULT STDMETHODCALLTYPE CRegistryFolderExtractIcon::Extract( LPCWSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize){ return SHDefExtractIconW(pszFile, nIconIndex, 0, phiconLarge, phiconSmall, nIconSize);}
// CRegistryFolder
CRegistryFolder::CRegistryFolder(){}
CRegistryFolder::~CRegistryFolder(){}
// IShellFolderHRESULT STDMETHODCALLTYPE CRegistryFolder::EnumObjects( HWND hwndOwner, SHCONTF grfFlags, IEnumIDList **ppenumIDList){ if (m_NtPath[0] == 0 && m_hRoot == NULL) { return GetEnumRegistryRoot(ppenumIDList); } else { return GetEnumRegistryKey(m_NtPath, m_hRoot, ppenumIDList); }}
HRESULT STDMETHODCALLTYPE CRegistryFolder::InternalBindToObject( PWSTR path, const RegPidlEntry * info, LPITEMIDLIST first, LPCITEMIDLIST rest, LPITEMIDLIST fullPidl, LPBC pbcReserved, IShellFolder** ppsfChild){ if (wcslen(m_NtPath) == 0 && m_hRoot == NULL) { return ShellObjectCreatorInit<CRegistryFolder>(fullPidl, L"", info->rootKey, IID_PPV_ARG(IShellFolder, ppsfChild)); }
return ShellObjectCreatorInit<CRegistryFolder>(fullPidl, path, m_hRoot, IID_PPV_ARG(IShellFolder, ppsfChild));}
HRESULT STDMETHODCALLTYPE CRegistryFolder::Initialize(PCIDLIST_ABSOLUTE pidl){ m_shellPidl = ILClone(pidl); m_hRoot = NULL;
StringCbCopyW(m_NtPath, sizeof(m_NtPath), L""); return S_OK;}
HRESULT STDMETHODCALLTYPE CRegistryFolder::Initialize(PCIDLIST_ABSOLUTE pidl, PCWSTR ntPath, HKEY hRoot){ m_shellPidl = ILClone(pidl); m_hRoot = hRoot;
StringCbCopyW(m_NtPath, sizeof(m_NtPath), ntPath); return S_OK;}
HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDefaultColumnState( UINT iColumn, SHCOLSTATEF *pcsFlags){ switch (iColumn) { case REGISTRY_COLUMN_NAME: *pcsFlags = SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT; return S_OK;
case REGISTRY_COLUMN_TYPE: *pcsFlags = SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT; return S_OK;
case REGISTRY_COLUMN_VALUE: *pcsFlags = SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT | SHCOLSTATE_SLOW; return S_OK; }
return E_INVALIDARG;}
HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDetailsEx( LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv){ const RegPidlEntry * info;
TRACE("GetDetailsEx\n");
if (pidl) { HRESULT hr = GetInfoFromPidl(pidl, &info); if (FAILED_UNEXPECTEDLY(hr)) return hr;
static const GUID storage = PSGUID_STORAGE; if (IsEqualGUID(pscid->fmtid, storage)) { if (pscid->pid == PID_STG_NAME) { if (info->entryNameLength > 0) { return MakeVariantString(pv, info->entryName); } return MakeVariantString(pv, L"(Default)"); } else if (pscid->pid == PID_STG_STORAGETYPE) { if (info->entryType == REG_ENTRY_ROOT) { return MakeVariantString(pv, L"Key"); }
if (info->entryType == REG_ENTRY_KEY) { if (info->contentsLength > 0) { PWSTR td = (PWSTR)(((PBYTE)info) + FIELD_OFFSET(RegPidlEntry, entryName) + info->entryNameLength + sizeof(WCHAR));
return MakeVariantString(pv, td); } return MakeVariantString(pv, L"Key"); }
return MakeVariantString(pv, RegistryTypeNames[info->contentType]); } else if (pscid->pid == PID_STG_CONTENTS) { PCWSTR strValueContents;
hr = FormatContentsForDisplay(info, m_hRoot, m_NtPath, &strValueContents); if (FAILED_UNEXPECTEDLY(hr)) return hr;
if (hr == S_FALSE) { V_VT(pv) = VT_EMPTY; return S_OK; }
hr = MakeVariantString(pv, strValueContents);
CoTaskMemFree((PVOID)strValueContents);
return hr;
} } }
return E_INVALIDARG;}
HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDetailsOf( LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd){ const RegPidlEntry * info;
TRACE("GetDetailsOf\n");
if (pidl) { HRESULT hr = GetInfoFromPidl(pidl, &info); if (FAILED_UNEXPECTEDLY(hr)) return hr;
switch (iColumn) { case REGISTRY_COLUMN_NAME: { psd->fmt = LVCFMT_LEFT;
if (info->entryNameLength > 0) { return MakeStrRetFromString(info->entryName, info->entryNameLength, &(psd->str)); } return MakeStrRetFromString(L"(Default)", &(psd->str)); }
case REGISTRY_COLUMN_TYPE: { psd->fmt = LVCFMT_LEFT;
if (info->entryType == REG_ENTRY_ROOT) { return MakeStrRetFromString(L"Key", &(psd->str)); }
if (info->entryType == REG_ENTRY_KEY) { if (info->contentsLength > 0) { PWSTR td = (PWSTR)(((PBYTE)info) + FIELD_OFFSET(RegPidlEntry, entryName) + info->entryNameLength + sizeof(WCHAR));
return MakeStrRetFromString(td, info->contentsLength, &(psd->str)); }
return MakeStrRetFromString(L"Key", &(psd->str)); }
return MakeStrRetFromString(RegistryTypeNames[info->contentType], &(psd->str)); }
case REGISTRY_COLUMN_VALUE: { psd->fmt = LVCFMT_LEFT;
PCWSTR strValueContents;
hr = FormatContentsForDisplay(info, m_hRoot, m_NtPath, &strValueContents); if (FAILED_UNEXPECTEDLY(hr)) return hr;
if (hr == S_FALSE) { return MakeStrRetFromString(L"(Empty)", &(psd->str)); }
hr = MakeStrRetFromString(strValueContents, &(psd->str));
CoTaskMemFree((PVOID)strValueContents);
return hr; } } } else { switch (iColumn) { case REGISTRY_COLUMN_NAME: psd->fmt = LVCFMT_LEFT; psd->cxChar = 30;
// TODO: Make localizable MakeStrRetFromString(L"Object Name", &(psd->str)); return S_OK;
case REGISTRY_COLUMN_TYPE: psd->fmt = LVCFMT_LEFT; psd->cxChar = 20;
// TODO: Make localizable MakeStrRetFromString(L"Content Type", &(psd->str)); return S_OK;
case REGISTRY_COLUMN_VALUE: psd->fmt = LVCFMT_LEFT; psd->cxChar = 20;
// TODO: Make localizable MakeStrRetFromString(L"Value", &(psd->str)); return S_OK; } }
return E_INVALIDARG;}
HRESULT STDMETHODCALLTYPE CRegistryFolder::MapColumnToSCID( UINT iColumn, SHCOLUMNID *pscid){ static const GUID storage = PSGUID_STORAGE; switch (iColumn) { case REGISTRY_COLUMN_NAME: pscid->fmtid = storage; pscid->pid = PID_STG_NAME; return S_OK;
case REGISTRY_COLUMN_TYPE: pscid->fmtid = storage; pscid->pid = PID_STG_STORAGETYPE; return S_OK;
case REGISTRY_COLUMN_VALUE: pscid->fmtid = storage; pscid->pid = PID_STG_CONTENTS; return S_OK; } return E_INVALIDARG;}
HRESULT CRegistryFolder::CompareIDs(LPARAM lParam, const RegPidlEntry * first, const RegPidlEntry * second){ HRESULT hr;
DWORD sortMode = lParam & 0xFFFF0000; DWORD column = lParam & 0x0000FFFF;
if (sortMode == SHCIDS_ALLFIELDS) { if (column != 0) return E_INVALIDARG;
int minsize = min(first->cb, second->cb); hr = MAKE_COMPARE_HRESULT(memcmp(second, first, minsize)); if (hr != S_EQUAL) return hr;
return MAKE_COMPARE_HRESULT(second->cb - first->cb); }
switch (column) { case REGISTRY_COLUMN_NAME: return CompareName(lParam, first, second);
case REGISTRY_COLUMN_TYPE: { if (first->entryType != second->entryType) return MAKE_COMPARE_HRESULT(second->entryType - first->entryType);
if (first->entryType == REG_ENTRY_KEY) { if (first->contentsLength == 0 || second->contentsLength == 0) return (first->contentsLength == 0) ? S_GREATERTHAN : S_LESSTHAN;
PWSTR firstKey = (PWSTR)(((PBYTE)first) + FIELD_OFFSET(RegPidlEntry, entryName) + first->entryNameLength + sizeof(WCHAR)); PWSTR secondKey = (PWSTR)(((PBYTE)second) + FIELD_OFFSET(RegPidlEntry, entryName) + second->entryNameLength + sizeof(WCHAR)); return MAKE_COMPARE_HRESULT(lstrcmpW(firstKey, secondKey)); }
return CompareName(lParam, first, second); }
case REGISTRY_COLUMN_VALUE: { PCWSTR firstContent, secondContent;
if (FAILED_UNEXPECTEDLY(FormatContentsForDisplay(first, m_hRoot, m_NtPath, &firstContent))) return E_INVALIDARG;
if (FAILED_UNEXPECTEDLY(FormatContentsForDisplay(second, m_hRoot, m_NtPath, &secondContent))) return E_INVALIDARG;
hr = MAKE_COMPARE_HRESULT(lstrcmpW(firstContent, secondContent));
CoTaskMemFree((LPVOID)firstContent); CoTaskMemFree((LPVOID)secondContent);
return hr; } }
DbgPrint("Unsupported sorting mode.\n"); return E_INVALIDARG;}
ULONG CRegistryFolder::ConvertAttributes(const RegPidlEntry * entry, PULONG inMask){ ULONG mask = inMask ? *inMask : 0xFFFFFFFF; ULONG flags = 0;
if ((entry->entryType == REG_ENTRY_KEY) || (entry->entryType == REG_ENTRY_ROOT)) flags |= SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_BROWSABLE;
return flags & mask;}
BOOL CRegistryFolder::IsFolder(const RegPidlEntry * info){ return (info->entryType == REG_ENTRY_KEY) ||(info->entryType == REG_ENTRY_ROOT);}
HRESULT CRegistryFolder::GetInfoFromPidl(LPCITEMIDLIST pcidl, const RegPidlEntry ** pentry){ if (!pcidl) { DbgPrint("PCIDL is NULL\n"); return E_INVALIDARG; }
RegPidlEntry * entry = (RegPidlEntry*) &(pcidl->mkid); if (entry->cb < sizeof(RegPidlEntry)) { DbgPrint("PCIDL too small %l (required %l)\n", entry->cb, sizeof(RegPidlEntry)); return E_INVALIDARG; }
if (entry->magic != REGISTRY_PIDL_MAGIC) { DbgPrint("PCIDL magic mismatch %04x (expected %04x)\n", entry->magic, REGISTRY_PIDL_MAGIC); return E_INVALIDARG; }
*pentry = entry; return S_OK;}
HRESULT CRegistryFolder::FormatValueData(DWORD contentType, PVOID td, DWORD contentsLength, PCWSTR * strContents){ switch (contentType) { case REG_NONE: { PCWSTR strTodo = L""; DWORD bufferLength = (wcslen(strTodo) + 1) * sizeof(WCHAR); PWSTR strValue = (PWSTR)CoTaskMemAlloc(bufferLength); StringCbCopyW(strValue, bufferLength, strTodo); *strContents = strValue; return S_OK; }
case REG_SZ: case REG_EXPAND_SZ: { PWSTR strValue = (PWSTR)CoTaskMemAlloc(contentsLength + sizeof(WCHAR)); StringCbCopyNW(strValue, contentsLength + sizeof(WCHAR), (LPCWSTR)td, contentsLength); *strContents = strValue; return S_OK; }
case REG_MULTI_SZ: { PCWSTR separator = L" "; // To match regedit size_t sepChars = wcslen(separator); int strings = 0; int stringChars = 0;
PCWSTR strData = (PCWSTR)td; while (*strData) { size_t len = wcslen(strData); stringChars += len; strData += len + 1; // Skips null-terminator strings++; }
int cch = stringChars + (strings - 1) * sepChars + 1;
PWSTR strValue = (PWSTR)CoTaskMemAlloc(cch * sizeof(WCHAR));
strValue[0] = 0;
strData = (PCWSTR)td; while (*strData) { StrCatW(strValue, strData); strData += wcslen(strData) + 1; if (*strData) StrCatW(strValue, separator); }
*strContents = strValue; return S_OK; }
case REG_DWORD: { DWORD bufferLength = 64 * sizeof(WCHAR); PWSTR strValue = (PWSTR)CoTaskMemAlloc(bufferLength); StringCbPrintfW(strValue, bufferLength, L"0x%08x (%d)", *(DWORD*)td, *(DWORD*)td); *strContents = strValue; return S_OK; }
case REG_QWORD: { DWORD bufferLength = 64 * sizeof(WCHAR); PWSTR strValue = (PWSTR)CoTaskMemAlloc(bufferLength); StringCbPrintfW(strValue, bufferLength, L"0x%016llx (%lld)", *(LARGE_INTEGER*)td, ((LARGE_INTEGER*)td)->QuadPart); *strContents = strValue; return S_OK; }
case REG_BINARY: { DWORD bufferLength = (contentsLength * 3 + 1) * sizeof(WCHAR); PWSTR strValue = (PWSTR)CoTaskMemAlloc(bufferLength); PWSTR strTemp = strValue; PBYTE data = (PBYTE)td; for (DWORD i = 0; i < contentsLength; i++) { StringCbPrintfW(strTemp, bufferLength, L"%02x ", data[i]); strTemp += 3; bufferLength -= 3; } *strContents = strValue; return S_OK; }
default: { PCWSTR strFormat = L"<Unimplemented value type %d>"; DWORD bufferLength = (wcslen(strFormat) + 15) * sizeof(WCHAR); PWSTR strValue = (PWSTR)CoTaskMemAlloc(bufferLength); StringCbPrintfW(strValue, bufferLength, strFormat, contentType); *strContents = strValue; return S_OK; } }}
HRESULT CRegistryFolder::FormatContentsForDisplay(const RegPidlEntry * info, HKEY rootKey, LPCWSTR ntPath, PCWSTR * strContents){ PVOID td = (((PBYTE)info) + FIELD_OFFSET(RegPidlEntry, entryName) + info->entryNameLength + sizeof(WCHAR));
if (info->entryType == REG_ENTRY_VALUE_WITH_CONTENT) { if (info->contentsLength > 0) { return FormatValueData(info->contentType, td, info->contentsLength, strContents); } } else if (info->entryType == REG_ENTRY_VALUE) { PVOID valueData; DWORD valueLength; HRESULT hr = ReadRegistryValue(rootKey, ntPath, info->entryName, &valueData, &valueLength); if (FAILED_UNEXPECTEDLY(hr)) { PCWSTR strEmpty = L"(Error reading value)"; DWORD bufferLength = (wcslen(strEmpty) + 1) * sizeof(WCHAR); PWSTR strValue = (PWSTR)CoTaskMemAlloc(bufferLength); StringCbCopyW(strValue, bufferLength, strEmpty); *strContents = strValue; return S_OK; }
if (valueLength > 0) { hr = FormatValueData(info->contentType, valueData, valueLength, strContents);
CoTaskMemFree(valueData);
return hr; } } else { PCWSTR strEmpty = L""; DWORD bufferLength = (wcslen(strEmpty) + 1) * sizeof(WCHAR); PWSTR strValue = (PWSTR)CoTaskMemAlloc(bufferLength); StringCbCopyW(strValue, bufferLength, strEmpty); *strContents = strValue; return S_OK; }
PCWSTR strEmpty = L"(Empty)"; DWORD bufferLength = (wcslen(strEmpty) + 1) * sizeof(WCHAR); PWSTR strValue = (PWSTR)CoTaskMemAlloc(bufferLength); StringCbCopyW(strValue, bufferLength, strEmpty); *strContents = strValue; return S_OK;}