Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741/* * PROJECT: NT Object Namespace shell extension * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) * PURPOSE: NT Object Namespace enumeration functions * COPYRIGHT: Copyright 2004-2005 Martin Fuchs <martin-fuchs@gmx.net> */
#include "precomp.h"#include <strsafe.h>
static struct RootKeyEntry { HKEY key; PCWSTR keyName;} RootKeys [] = { { HKEY_CLASSES_ROOT, L"HKEY_CLASSES_ROOT" }, { HKEY_CURRENT_USER, L"HKEY_CURRENT_USER" }, { HKEY_LOCAL_MACHINE, L"HKEY_LOCAL_MACHINE" }, { HKEY_USERS, L"HKEY_USERS" }, { HKEY_CURRENT_CONFIG, L"HKEY_CURRENT_CONFIG" }};
typedef NTSTATUS(__stdcall* pfnNtGenericOpen)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);typedef NTSTATUS(__stdcall* pfnNtOpenFile)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, ULONG, ULONG);
const LPCWSTR ObjectTypeNames [] = { L"Directory", L"SymbolicLink", L"Mutant", L"Section", L"Event", L"Semaphore", L"Timer", L"Key", L"EventPair", L"IoCompletion", L"Device", L"File", L"Controller", L"Profile", L"Type", L"Desktop", L"WindowStation", L"Driver", L"Token", L"Process", L"Thread", L"Adapter", L"Port", 0};
const LPCWSTR RegistryTypeNames [] = { L"REG_NONE", L"REG_SZ", L"REG_EXPAND_SZ", L"REG_BINARY", L"REG_DWORD", L"REG_DWORD_BIG_ENDIAN", L"REG_LINK", L"REG_MULTI_SZ", L"REG_RESOURCE_LIST", L"REG_FULL_RESOURCE_DESCRIPTOR", L"REG_RESOURCE_REQUIREMENTS_LIST", L"REG_QWORD"};
static DWORD NtOpenObject(OBJECT_TYPE type, PHANDLE phandle, DWORD access, LPCWSTR path){ UNICODE_STRING ustr;
RtlInitUnicodeString(&ustr, path);
OBJECT_ATTRIBUTES open_struct = { sizeof(OBJECT_ATTRIBUTES), 0x00, &ustr, 0x40 };
if (type != FILE_OBJECT) access |= STANDARD_RIGHTS_READ;
IO_STATUS_BLOCK ioStatusBlock;
switch (type) { case DIRECTORY_OBJECT: return NtOpenDirectoryObject(phandle, access, &open_struct); case SYMBOLICLINK_OBJECT: return NtOpenSymbolicLinkObject(phandle, access, &open_struct); case MUTANT_OBJECT: return NtOpenMutant(phandle, access, &open_struct); case SECTION_OBJECT: return NtOpenSection(phandle, access, &open_struct); case EVENT_OBJECT: return NtOpenEvent(phandle, access, &open_struct); case SEMAPHORE_OBJECT: return NtOpenSemaphore(phandle, access, &open_struct); case TIMER_OBJECT: return NtOpenTimer(phandle, access, &open_struct); case KEY_OBJECT: return NtOpenKey(phandle, access, &open_struct); case EVENTPAIR_OBJECT: return NtOpenEventPair(phandle, access, &open_struct); case IOCOMPLETION_OBJECT: return NtOpenIoCompletion(phandle, access, &open_struct); case FILE_OBJECT: return NtOpenFile(phandle, access, &open_struct, &ioStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0); default: return ERROR_INVALID_FUNCTION; }}
OBJECT_TYPE MapTypeNameToType(LPCWSTR TypeName, DWORD cbTypeName){ if (!TypeName) return UNKNOWN_OBJECT_TYPE;
for (UINT i = 0; i < _countof(ObjectTypeNames); i++) { LPCWSTR typeName = ObjectTypeNames[i]; if (!StrCmpNW(typeName, TypeName, cbTypeName / sizeof(WCHAR))) { return (OBJECT_TYPE) i; } }
return UNKNOWN_OBJECT_TYPE;}
HRESULT ReadRegistryValue(HKEY root, PCWSTR path, PCWSTR valueName, PVOID * valueData, PDWORD valueLength){ HKEY hkey;
DWORD res; if (root) { res = RegOpenKeyExW(root, *path == '\\' ? path + 1 : path, 0, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE, &hkey); } else { res = NtOpenObject(KEY_OBJECT, (PHANDLE) &hkey, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE, path); } if (!NT_SUCCESS(res)) { ERR("RegOpenKeyExW failed for path %S with status=%x\n", path, res); return HRESULT_FROM_NT(res); }
res = RegQueryValueExW(hkey, valueName, NULL, NULL, NULL, valueLength); if (!NT_SUCCESS(res)) { ERR("RegQueryValueExW failed for path %S with status=%x\n", path, res); return HRESULT_FROM_NT(res); }
if (*valueLength > 0) { PBYTE data = (PBYTE) CoTaskMemAlloc(*valueLength); *valueData = data;
res = RegQueryValueExW(hkey, valueName, NULL, NULL, data, valueLength); if (!NT_SUCCESS(res)) { CoTaskMemFree(data); *valueData = NULL;
RegCloseKey(hkey);
ERR("RegOpenKeyExW failed for path %S with status=%x\n", path, res); return HRESULT_FROM_NT(res); } } else { *valueData = NULL; }
RegCloseKey(hkey);
return S_OK;}
HRESULT GetNTObjectSymbolicLinkTarget(LPCWSTR path, LPCWSTR entryName, PUNICODE_STRING LinkTarget){ HANDLE handle; WCHAR buffer[MAX_PATH]; LPWSTR pend = buffer;
StringCbCopyExW(buffer, sizeof(buffer), path, &pend, NULL, 0);
if (pend[-1] != '\\') { *pend++ = '\\'; *pend = 0; }
StringCbCatW(buffer, sizeof(buffer), entryName);
DbgPrint("GetNTObjectSymbolicLinkTarget %d\n", buffer);
LinkTarget->Length = 0;
DWORD err = NtOpenObject(SYMBOLICLINK_OBJECT, &handle, SYMBOLIC_LINK_QUERY, buffer); if (!NT_SUCCESS(err)) return HRESULT_FROM_NT(err);
err = NtQuerySymbolicLinkObject(handle, LinkTarget, NULL); if (!NT_SUCCESS(err)) return HRESULT_FROM_NT(err);
NtClose(handle);
return S_OK;}
class CEnumRegRoot : public CComObjectRootEx<CComMultiThreadModelNoCS>, public IEnumIDList{ UINT m_idx;
public: CEnumRegRoot() : m_idx(0) { }
~CEnumRegRoot() { }
HRESULT EnumerateNext(LPITEMIDLIST* ppidl) { if (m_idx >= _countof(RootKeys)) return S_FALSE;
RootKeyEntry& key = RootKeys[m_idx++];
PCWSTR name = key.keyName; DWORD cchName = wcslen(name);
REG_ENTRY_TYPE otype = REG_ENTRY_ROOT;
DWORD entryBufferLength = FIELD_OFFSET(RegPidlEntry, entryName) + sizeof(WCHAR) + cchName * sizeof(WCHAR);
// allocate space for the terminator entryBufferLength += FIELD_OFFSET(SHITEMID, abID);
RegPidlEntry* entry = (RegPidlEntry*) CoTaskMemAlloc(entryBufferLength); if (!entry) return E_OUTOFMEMORY;
memset(entry, 0, entryBufferLength);
entry->cb = FIELD_OFFSET(RegPidlEntry, entryName); entry->magic = REGISTRY_PIDL_MAGIC; entry->entryType = otype; entry->rootKey = key.key;
if (cchName > 0) { entry->entryNameLength = cchName * sizeof(WCHAR); StringCbCopyNW(entry->entryName, entryBufferLength, name, entry->entryNameLength); entry->cb += entry->entryNameLength + sizeof(WCHAR); } else { entry->entryNameLength = 0; entry->entryName[0] = 0; entry->cb += sizeof(WCHAR); }
if (ppidl) *ppidl = (LPITEMIDLIST) entry; return S_OK; }
STDMETHODIMP Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched) override { if (pceltFetched) *pceltFetched = 0;
while (celt-- > 0) { HRESULT hr = EnumerateNext(rgelt); if (hr != S_OK) return hr;
if (pceltFetched) (*pceltFetched)++; if (rgelt) rgelt++; }
return S_OK; }
STDMETHODIMP Skip(ULONG celt) override { while (celt > 0) { HRESULT hr = EnumerateNext(NULL); if (FAILED(hr)) return hr; if (hr != S_OK) break; }
return S_OK; }
STDMETHODIMP Reset() override { return E_NOTIMPL; }
STDMETHODIMP Clone(IEnumIDList **ppenum) override { return E_NOTIMPL; }
DECLARE_NOT_AGGREGATABLE(CEnumRegRoot) DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CEnumRegRoot) COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) END_COM_MAP()
};
class CEnumRegKey : public CComObjectRootEx<CComMultiThreadModelNoCS>, public IEnumIDList{ PCWSTR m_path; HKEY m_hkey; BOOL m_values; int m_idx;
public: CEnumRegKey() : m_path(NULL), m_hkey(NULL), m_values(FALSE), m_idx(0) { }
~CEnumRegKey() { RegCloseKey(m_hkey); }
HRESULT Initialize(PCWSTR path, HKEY root) { m_path = path;
DWORD res; if (root) { res = RegOpenKeyExW(root, *path == '\\' ? path + 1 : path, 0, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &m_hkey); } else { res = NtOpenObject(KEY_OBJECT, (PHANDLE) &m_hkey, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, path); } if (!NT_SUCCESS(res)) { ERR("RegOpenKeyExW failed for path %S with status=%x\n", path, res); return HRESULT_FROM_NT(res); }
return S_OK; }
HRESULT NextKey(LPITEMIDLIST* ppidl) { WCHAR name[MAX_PATH]; DWORD cchName = _countof(name);
WCHAR className[MAX_PATH]; DWORD cchClass = _countof(className);
if (RegEnumKeyExW(m_hkey, m_idx++, name, &cchName, 0, className, &cchClass, NULL)) return S_FALSE;
name[cchName] = 0; className[cchClass] = 0;
REG_ENTRY_TYPE otype = REG_ENTRY_KEY;
DWORD entryBufferLength = FIELD_OFFSET(RegPidlEntry, entryName) + sizeof(WCHAR) + cchName * sizeof(WCHAR);
if (cchClass > 0) { entryBufferLength += sizeof(WCHAR) + cchClass * sizeof(WCHAR); }
// allocate space for the terminator entryBufferLength += FIELD_OFFSET(SHITEMID, abID);
RegPidlEntry* entry = (RegPidlEntry*) CoTaskMemAlloc(entryBufferLength); if (!entry) return E_OUTOFMEMORY;
memset(entry, 0, entryBufferLength);
entry->cb = FIELD_OFFSET(RegPidlEntry, entryName); entry->magic = REGISTRY_PIDL_MAGIC; entry->entryType = otype;
if (cchName > 0) { entry->entryNameLength = cchName * sizeof(WCHAR); StringCbCopyNW(entry->entryName, entryBufferLength, name, entry->entryNameLength); entry->cb += entry->entryNameLength + sizeof(WCHAR); } else { entry->entryNameLength = 0; entry->entryName[0] = 0; entry->cb += sizeof(WCHAR); }
if (cchClass) { PWSTR contentData = (PWSTR) ((PBYTE) entry + entry->cb); DWORD remainingSpace = entryBufferLength - entry->cb;
entry->contentsLength = cchClass * sizeof(WCHAR); StringCbCopyNW(contentData, remainingSpace, className, entry->contentsLength);
entry->cb += entry->contentsLength + sizeof(WCHAR); }
if (ppidl) *ppidl = (LPITEMIDLIST) entry; return S_OK; }
HRESULT NextValue(LPITEMIDLIST* ppidl) { WCHAR name[MAX_PATH]; DWORD cchName = _countof(name); DWORD type = 0; DWORD dataSize = 0;
if (RegEnumValueW(m_hkey, m_idx++, name, &cchName, 0, &type, NULL, &dataSize)) return S_FALSE;
REG_ENTRY_TYPE otype = REG_ENTRY_VALUE;
DWORD entryBufferLength = FIELD_OFFSET(RegPidlEntry, entryName) + sizeof(WCHAR) + cchName * sizeof(WCHAR);
#define MAX_EMBEDDED_DATA 32 BOOL copyData = dataSize <= MAX_EMBEDDED_DATA; if (copyData) { entryBufferLength += dataSize + sizeof(WCHAR);
otype = REG_ENTRY_VALUE_WITH_CONTENT; }
// allocate space for the terminator entryBufferLength += FIELD_OFFSET(SHITEMID, abID);
RegPidlEntry* entry = (RegPidlEntry*) CoTaskMemAlloc(entryBufferLength); if (!entry) return E_OUTOFMEMORY;
memset(entry, 0, entryBufferLength);
entry->cb = FIELD_OFFSET(RegPidlEntry, entryName); entry->magic = REGISTRY_PIDL_MAGIC; entry->entryType = otype; entry->contentType = type;
if (cchName > 0) { entry->entryNameLength = cchName * sizeof(WCHAR); StringCbCopyNW(entry->entryName, entryBufferLength, name, entry->entryNameLength); entry->cb += entry->entryNameLength + sizeof(WCHAR); } else { entry->entryNameLength = 0; entry->entryName[0] = 0; entry->cb += sizeof(WCHAR); }
if (copyData) { PBYTE contentData = (PBYTE) ((PBYTE) entry + entry->cb);
entry->contentsLength = dataSize;
// In case it's an unterminated string, RegGetValue will add the NULL termination dataSize += sizeof(WCHAR);
if (!RegQueryValueExW(m_hkey, name, NULL, NULL, contentData, &dataSize)) { entry->cb += entry->contentsLength + sizeof(WCHAR); } else { entry->contentsLength = 0; entry->cb += sizeof(WCHAR); }
}
if (ppidl) *ppidl = (LPITEMIDLIST) entry; return S_OK; }
HRESULT EnumerateNext(LPITEMIDLIST* ppidl) { if (!m_values) { HRESULT hr = NextKey(ppidl); if (hr != S_FALSE) return hr;
// switch to values. m_values = TRUE; m_idx = 0; }
return NextValue(ppidl); }
STDMETHODIMP Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched) override { if (pceltFetched) *pceltFetched = 0;
while (celt-- > 0) { HRESULT hr = EnumerateNext(rgelt); if (hr != S_OK) return hr;
if (pceltFetched) (*pceltFetched)++; if (rgelt) rgelt++; }
return S_OK; }
STDMETHODIMP Skip(ULONG celt) override { while (celt > 0) { HRESULT hr = EnumerateNext(NULL); if (FAILED(hr)) return hr; if (hr != S_OK) break; }
return S_OK; }
STDMETHODIMP Reset() override { return E_NOTIMPL; }
STDMETHODIMP Clone(IEnumIDList **ppenum) override { return E_NOTIMPL; }
DECLARE_NOT_AGGREGATABLE(CEnumRegKey) DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CEnumRegKey) COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) END_COM_MAP()};
class CEnumNTDirectory : public CComObjectRootEx<CComMultiThreadModelNoCS>, public IEnumIDList{ WCHAR buffer[MAX_PATH]; HANDLE m_directory; BOOL m_first; ULONG m_enumContext; PWSTR m_pend;
public: CEnumNTDirectory() : m_directory(NULL), m_first(TRUE), m_enumContext(0), m_pend(NULL) { }
~CEnumNTDirectory() { NtClose(m_directory); }
HRESULT Initialize(PCWSTR path) { StringCbCopyExW(buffer, sizeof(buffer), path, &m_pend, NULL, 0);
DWORD err = NtOpenObject(DIRECTORY_OBJECT, &m_directory, FILE_LIST_DIRECTORY, buffer); if (!NT_SUCCESS(err)) { ERR("NtOpenDirectoryObject failed for path %S with status=%x\n", buffer, err); return HRESULT_FROM_NT(err); }
if (m_pend[-1] != '\\') *m_pend++ = '\\';
return S_OK; }
HRESULT EnumerateNext(LPITEMIDLIST* ppidl) { BYTE dirbuffer[2048]; if (!NT_SUCCESS(NtQueryDirectoryObject(m_directory, dirbuffer, 2048, TRUE, m_first, &m_enumContext, NULL))) return S_FALSE;
m_first = FALSE;
// if ppidl is NULL, assume the caller was Skip(), // so we don't care about the info if (!ppidl) return S_OK;
POBJECT_DIRECTORY_INFORMATION info = (POBJECT_DIRECTORY_INFORMATION) dirbuffer;
if (info->Name.Buffer) { StringCbCopyNW(m_pend, sizeof(buffer), info->Name.Buffer, info->Name.Length); }
OBJECT_TYPE otype = MapTypeNameToType(info->TypeName.Buffer, info->TypeName.Length);
DWORD entryBufferLength = FIELD_OFFSET(NtPidlEntry, entryName) + sizeof(WCHAR); if (info->Name.Buffer) entryBufferLength += info->Name.Length;
if (otype < 0) { entryBufferLength += FIELD_OFFSET(NtPidlTypeData, typeName) + sizeof(WCHAR);
if (info->TypeName.Buffer) { entryBufferLength += info->TypeName.Length; } }
// allocate space for the terminator entryBufferLength += FIELD_OFFSET(SHITEMID, abID);
NtPidlEntry* entry = (NtPidlEntry*) CoTaskMemAlloc(entryBufferLength); if (!entry) return E_OUTOFMEMORY;
memset(entry, 0, entryBufferLength);
entry->cb = FIELD_OFFSET(NtPidlEntry, entryName); entry->magic = NT_OBJECT_PIDL_MAGIC; entry->objectType = otype;
if (info->Name.Buffer) { entry->entryNameLength = info->Name.Length; StringCbCopyNW(entry->entryName, entryBufferLength, info->Name.Buffer, info->Name.Length); entry->cb += entry->entryNameLength + sizeof(WCHAR); } else { entry->entryNameLength = 0; entry->entryName[0] = 0; entry->cb += sizeof(WCHAR); }
if (otype < 0) { NtPidlTypeData * typedata = (NtPidlTypeData*) ((PBYTE) entry + entry->cb); DWORD remainingSpace = entryBufferLength - ((PBYTE) (typedata->typeName) - (PBYTE) entry);
if (info->TypeName.Buffer) { typedata->typeNameLength = info->TypeName.Length; StringCbCopyNW(typedata->typeName, remainingSpace, info->TypeName.Buffer, info->TypeName.Length);
entry->cb += typedata->typeNameLength + sizeof(WCHAR); } else { typedata->typeNameLength = 0; typedata->typeName[0] = 0; entry->cb += typedata->typeNameLength + sizeof(WCHAR); } }
*ppidl = (LPITEMIDLIST) entry;
return S_OK; }
STDMETHODIMP Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched) override { if (pceltFetched) *pceltFetched = 0;
while (celt-- > 0) { HRESULT hr = EnumerateNext(rgelt); if (hr != S_OK) return hr;
if (pceltFetched) (*pceltFetched)++; if (rgelt) rgelt++; }
return S_OK; }
STDMETHODIMP Skip(ULONG celt) override { while (celt > 0) { HRESULT hr = EnumerateNext(NULL); if (FAILED(hr)) return hr; if (hr != S_OK) break; }
return S_OK; }
STDMETHODIMP Reset() override { return E_NOTIMPL; }
STDMETHODIMP Clone(IEnumIDList **ppenum) override { return E_NOTIMPL; }
DECLARE_NOT_AGGREGATABLE(CEnumNTDirectory) DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CEnumNTDirectory) COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) END_COM_MAP()};
HRESULT GetEnumRegistryRoot(IEnumIDList ** ppil){ return ShellObjectCreator<CEnumRegRoot>(IID_PPV_ARG(IEnumIDList, ppil));}
HRESULT GetEnumRegistryKey(LPCWSTR path, HKEY root, IEnumIDList ** ppil){ return ShellObjectCreatorInit<CEnumRegKey>(path, root, IID_PPV_ARG(IEnumIDList, ppil));}
HRESULT GetEnumNTDirectory(LPCWSTR path, IEnumIDList ** ppil){ return ShellObjectCreatorInit<CEnumNTDirectory>(path, IID_PPV_ARG(IEnumIDList, ppil));}