1c2c66affSColin Finck /*
2ba03ffd6SStanislav Motylkov * PROJECT: NT Object Namespace shell extension
3ba03ffd6SStanislav Motylkov * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4ba03ffd6SStanislav Motylkov * PURPOSE: NT Object Namespace enumeration functions
5ba03ffd6SStanislav Motylkov * COPYRIGHT: Copyright 2004-2005 Martin Fuchs <martin-fuchs@gmx.net>
6c2c66affSColin Finck */
7c2c66affSColin Finck
8c2c66affSColin Finck #include "precomp.h"
9c2c66affSColin Finck #include <strsafe.h>
10c2c66affSColin Finck
11c2c66affSColin Finck static struct RootKeyEntry {
12c2c66affSColin Finck HKEY key;
13c2c66affSColin Finck PCWSTR keyName;
14c2c66affSColin Finck } RootKeys [] = {
15c2c66affSColin Finck { HKEY_CLASSES_ROOT, L"HKEY_CLASSES_ROOT" },
16c2c66affSColin Finck { HKEY_CURRENT_USER, L"HKEY_CURRENT_USER" },
17c2c66affSColin Finck { HKEY_LOCAL_MACHINE, L"HKEY_LOCAL_MACHINE" },
18c2c66affSColin Finck { HKEY_USERS, L"HKEY_USERS" },
19c2c66affSColin Finck { HKEY_CURRENT_CONFIG, L"HKEY_CURRENT_CONFIG" }
20c2c66affSColin Finck };
21c2c66affSColin Finck
22c2c66affSColin Finck typedef NTSTATUS(__stdcall* pfnNtGenericOpen)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
23c2c66affSColin Finck typedef NTSTATUS(__stdcall* pfnNtOpenFile)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PIO_STATUS_BLOCK, ULONG, ULONG);
24c2c66affSColin Finck
25c2c66affSColin Finck const LPCWSTR ObjectTypeNames [] = {
26c2c66affSColin Finck L"Directory", L"SymbolicLink",
27c2c66affSColin Finck L"Mutant", L"Section", L"Event", L"Semaphore",
28c2c66affSColin Finck L"Timer", L"Key", L"EventPair", L"IoCompletion",
29c2c66affSColin Finck L"Device", L"File", L"Controller", L"Profile",
30c2c66affSColin Finck L"Type", L"Desktop", L"WindowStation", L"Driver",
31c2c66affSColin Finck L"Token", L"Process", L"Thread", L"Adapter", L"Port",
32c2c66affSColin Finck 0
33c2c66affSColin Finck };
34c2c66affSColin Finck
35c2c66affSColin Finck const LPCWSTR RegistryTypeNames [] = {
36c2c66affSColin Finck L"REG_NONE",
37c2c66affSColin Finck L"REG_SZ",
38c2c66affSColin Finck L"REG_EXPAND_SZ",
39c2c66affSColin Finck L"REG_BINARY",
40c2c66affSColin Finck L"REG_DWORD",
41c2c66affSColin Finck L"REG_DWORD_BIG_ENDIAN",
42c2c66affSColin Finck L"REG_LINK",
43c2c66affSColin Finck L"REG_MULTI_SZ",
44c2c66affSColin Finck L"REG_RESOURCE_LIST",
45c2c66affSColin Finck L"REG_FULL_RESOURCE_DESCRIPTOR",
46c2c66affSColin Finck L"REG_RESOURCE_REQUIREMENTS_LIST",
47c2c66affSColin Finck L"REG_QWORD"
48c2c66affSColin Finck };
49c2c66affSColin Finck
NtOpenObject(OBJECT_TYPE type,PHANDLE phandle,DWORD access,LPCWSTR path)50c2c66affSColin Finck static DWORD NtOpenObject(OBJECT_TYPE type, PHANDLE phandle, DWORD access, LPCWSTR path)
51c2c66affSColin Finck {
52c2c66affSColin Finck UNICODE_STRING ustr;
53c2c66affSColin Finck
54c2c66affSColin Finck RtlInitUnicodeString(&ustr, path);
55c2c66affSColin Finck
56c2c66affSColin Finck OBJECT_ATTRIBUTES open_struct = { sizeof(OBJECT_ATTRIBUTES), 0x00, &ustr, 0x40 };
57c2c66affSColin Finck
58c2c66affSColin Finck if (type != FILE_OBJECT)
59c2c66affSColin Finck access |= STANDARD_RIGHTS_READ;
60c2c66affSColin Finck
61c2c66affSColin Finck IO_STATUS_BLOCK ioStatusBlock;
62c2c66affSColin Finck
63c2c66affSColin Finck switch (type)
64c2c66affSColin Finck {
65c2c66affSColin Finck case DIRECTORY_OBJECT: return NtOpenDirectoryObject(phandle, access, &open_struct);
66c2c66affSColin Finck case SYMBOLICLINK_OBJECT: return NtOpenSymbolicLinkObject(phandle, access, &open_struct);
67c2c66affSColin Finck case MUTANT_OBJECT: return NtOpenMutant(phandle, access, &open_struct);
68c2c66affSColin Finck case SECTION_OBJECT: return NtOpenSection(phandle, access, &open_struct);
69c2c66affSColin Finck case EVENT_OBJECT: return NtOpenEvent(phandle, access, &open_struct);
70c2c66affSColin Finck case SEMAPHORE_OBJECT: return NtOpenSemaphore(phandle, access, &open_struct);
71c2c66affSColin Finck case TIMER_OBJECT: return NtOpenTimer(phandle, access, &open_struct);
72c2c66affSColin Finck case KEY_OBJECT: return NtOpenKey(phandle, access, &open_struct);
73c2c66affSColin Finck case EVENTPAIR_OBJECT: return NtOpenEventPair(phandle, access, &open_struct);
74c2c66affSColin Finck case IOCOMPLETION_OBJECT: return NtOpenIoCompletion(phandle, access, &open_struct);
75c2c66affSColin Finck case FILE_OBJECT: return NtOpenFile(phandle, access, &open_struct, &ioStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0);
76c2c66affSColin Finck default:
77c2c66affSColin Finck return ERROR_INVALID_FUNCTION;
78c2c66affSColin Finck }
79c2c66affSColin Finck }
80c2c66affSColin Finck
MapTypeNameToType(LPCWSTR TypeName,DWORD cbTypeName)81c2c66affSColin Finck OBJECT_TYPE MapTypeNameToType(LPCWSTR TypeName, DWORD cbTypeName)
82c2c66affSColin Finck {
83c2c66affSColin Finck if (!TypeName)
84c2c66affSColin Finck return UNKNOWN_OBJECT_TYPE;
85c2c66affSColin Finck
86c2c66affSColin Finck for (UINT i = 0; i < _countof(ObjectTypeNames); i++)
87c2c66affSColin Finck {
88c2c66affSColin Finck LPCWSTR typeName = ObjectTypeNames[i];
89c2c66affSColin Finck if (!StrCmpNW(typeName, TypeName, cbTypeName / sizeof(WCHAR)))
90c2c66affSColin Finck {
91c2c66affSColin Finck return (OBJECT_TYPE) i;
92c2c66affSColin Finck }
93c2c66affSColin Finck }
94c2c66affSColin Finck
95c2c66affSColin Finck return UNKNOWN_OBJECT_TYPE;
96c2c66affSColin Finck }
97c2c66affSColin Finck
ReadRegistryValue(HKEY root,PCWSTR path,PCWSTR valueName,PVOID * valueData,PDWORD valueLength)98c2c66affSColin Finck HRESULT ReadRegistryValue(HKEY root, PCWSTR path, PCWSTR valueName, PVOID * valueData, PDWORD valueLength)
99c2c66affSColin Finck {
100c2c66affSColin Finck HKEY hkey;
101c2c66affSColin Finck
102c2c66affSColin Finck DWORD res;
103c2c66affSColin Finck if (root)
104c2c66affSColin Finck {
105c2c66affSColin Finck res = RegOpenKeyExW(root, *path == '\\' ? path + 1 : path, 0, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE, &hkey);
106c2c66affSColin Finck }
107c2c66affSColin Finck else
108c2c66affSColin Finck {
109c2c66affSColin Finck res = NtOpenObject(KEY_OBJECT, (PHANDLE) &hkey, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE, path);
110c2c66affSColin Finck }
111c2c66affSColin Finck if (!NT_SUCCESS(res))
112c2c66affSColin Finck {
113c2c66affSColin Finck ERR("RegOpenKeyExW failed for path %S with status=%x\n", path, res);
114c2c66affSColin Finck return HRESULT_FROM_NT(res);
115c2c66affSColin Finck }
116c2c66affSColin Finck
117c2c66affSColin Finck res = RegQueryValueExW(hkey, valueName, NULL, NULL, NULL, valueLength);
118c2c66affSColin Finck if (!NT_SUCCESS(res))
119c2c66affSColin Finck {
120c2c66affSColin Finck ERR("RegQueryValueExW failed for path %S with status=%x\n", path, res);
121c2c66affSColin Finck return HRESULT_FROM_NT(res);
122c2c66affSColin Finck }
123c2c66affSColin Finck
124c2c66affSColin Finck if (*valueLength > 0)
125c2c66affSColin Finck {
126c2c66affSColin Finck PBYTE data = (PBYTE) CoTaskMemAlloc(*valueLength);
127c2c66affSColin Finck *valueData = data;
128c2c66affSColin Finck
129c2c66affSColin Finck res = RegQueryValueExW(hkey, valueName, NULL, NULL, data, valueLength);
130c2c66affSColin Finck if (!NT_SUCCESS(res))
131c2c66affSColin Finck {
132c2c66affSColin Finck CoTaskMemFree(data);
133c2c66affSColin Finck *valueData = NULL;
134c2c66affSColin Finck
135c2c66affSColin Finck RegCloseKey(hkey);
136c2c66affSColin Finck
137c2c66affSColin Finck ERR("RegOpenKeyExW failed for path %S with status=%x\n", path, res);
138c2c66affSColin Finck return HRESULT_FROM_NT(res);
139c2c66affSColin Finck }
140c2c66affSColin Finck }
141c2c66affSColin Finck else
142c2c66affSColin Finck {
143c2c66affSColin Finck *valueData = NULL;
144c2c66affSColin Finck }
145c2c66affSColin Finck
146c2c66affSColin Finck RegCloseKey(hkey);
147c2c66affSColin Finck
148c2c66affSColin Finck return S_OK;
149c2c66affSColin Finck }
150c2c66affSColin Finck
GetNTObjectSymbolicLinkTarget(LPCWSTR path,LPCWSTR entryName,PUNICODE_STRING LinkTarget)151c2c66affSColin Finck HRESULT GetNTObjectSymbolicLinkTarget(LPCWSTR path, LPCWSTR entryName, PUNICODE_STRING LinkTarget)
152c2c66affSColin Finck {
153c2c66affSColin Finck HANDLE handle;
154c2c66affSColin Finck WCHAR buffer[MAX_PATH];
155c2c66affSColin Finck LPWSTR pend = buffer;
156c2c66affSColin Finck
157c2c66affSColin Finck StringCbCopyExW(buffer, sizeof(buffer), path, &pend, NULL, 0);
158c2c66affSColin Finck
159c2c66affSColin Finck if (pend[-1] != '\\')
160c2c66affSColin Finck {
161c2c66affSColin Finck *pend++ = '\\';
162c2c66affSColin Finck *pend = 0;
163c2c66affSColin Finck }
164c2c66affSColin Finck
165c2c66affSColin Finck StringCbCatW(buffer, sizeof(buffer), entryName);
166c2c66affSColin Finck
167c2c66affSColin Finck DbgPrint("GetNTObjectSymbolicLinkTarget %d\n", buffer);
168c2c66affSColin Finck
169c2c66affSColin Finck LinkTarget->Length = 0;
170c2c66affSColin Finck
171c2c66affSColin Finck DWORD err = NtOpenObject(SYMBOLICLINK_OBJECT, &handle, SYMBOLIC_LINK_QUERY, buffer);
172c2c66affSColin Finck if (!NT_SUCCESS(err))
173c2c66affSColin Finck return HRESULT_FROM_NT(err);
174c2c66affSColin Finck
175c2c66affSColin Finck err = NtQuerySymbolicLinkObject(handle, LinkTarget, NULL);
176c2c66affSColin Finck if (!NT_SUCCESS(err))
177c2c66affSColin Finck return HRESULT_FROM_NT(err);
178c2c66affSColin Finck
179c2c66affSColin Finck NtClose(handle);
180c2c66affSColin Finck
181c2c66affSColin Finck return S_OK;
182c2c66affSColin Finck }
183c2c66affSColin Finck
184c2c66affSColin Finck class CEnumRegRoot :
185c2c66affSColin Finck public CComObjectRootEx<CComMultiThreadModelNoCS>,
186c2c66affSColin Finck public IEnumIDList
187c2c66affSColin Finck {
188c2c66affSColin Finck UINT m_idx;
189c2c66affSColin Finck
190c2c66affSColin Finck public:
CEnumRegRoot()191c2c66affSColin Finck CEnumRegRoot()
192c2c66affSColin Finck : m_idx(0)
193c2c66affSColin Finck {
194c2c66affSColin Finck }
195c2c66affSColin Finck
~CEnumRegRoot()196c2c66affSColin Finck ~CEnumRegRoot()
197c2c66affSColin Finck {
198c2c66affSColin Finck }
199c2c66affSColin Finck
EnumerateNext(LPITEMIDLIST * ppidl)200c2c66affSColin Finck HRESULT EnumerateNext(LPITEMIDLIST* ppidl)
201c2c66affSColin Finck {
202c2c66affSColin Finck if (m_idx >= _countof(RootKeys))
203c2c66affSColin Finck return S_FALSE;
204c2c66affSColin Finck
205c2c66affSColin Finck RootKeyEntry& key = RootKeys[m_idx++];
206c2c66affSColin Finck
207c2c66affSColin Finck PCWSTR name = key.keyName;
208c2c66affSColin Finck DWORD cchName = wcslen(name);
209c2c66affSColin Finck
210c2c66affSColin Finck REG_ENTRY_TYPE otype = REG_ENTRY_ROOT;
211c2c66affSColin Finck
212c2c66affSColin Finck DWORD entryBufferLength = FIELD_OFFSET(RegPidlEntry, entryName) + sizeof(WCHAR) + cchName * sizeof(WCHAR);
213c2c66affSColin Finck
214c2c66affSColin Finck // allocate space for the terminator
215c2c66affSColin Finck entryBufferLength += FIELD_OFFSET(SHITEMID, abID);
216c2c66affSColin Finck
217c2c66affSColin Finck RegPidlEntry* entry = (RegPidlEntry*) CoTaskMemAlloc(entryBufferLength);
218c2c66affSColin Finck if (!entry)
219c2c66affSColin Finck return E_OUTOFMEMORY;
220c2c66affSColin Finck
221c2c66affSColin Finck memset(entry, 0, entryBufferLength);
222c2c66affSColin Finck
223c2c66affSColin Finck entry->cb = FIELD_OFFSET(RegPidlEntry, entryName);
224c2c66affSColin Finck entry->magic = REGISTRY_PIDL_MAGIC;
225c2c66affSColin Finck entry->entryType = otype;
226c2c66affSColin Finck entry->rootKey = key.key;
227c2c66affSColin Finck
228c2c66affSColin Finck if (cchName > 0)
229c2c66affSColin Finck {
230c2c66affSColin Finck entry->entryNameLength = cchName * sizeof(WCHAR);
231c2c66affSColin Finck StringCbCopyNW(entry->entryName, entryBufferLength, name, entry->entryNameLength);
232c2c66affSColin Finck entry->cb += entry->entryNameLength + sizeof(WCHAR);
233c2c66affSColin Finck }
234c2c66affSColin Finck else
235c2c66affSColin Finck {
236c2c66affSColin Finck entry->entryNameLength = 0;
237c2c66affSColin Finck entry->entryName[0] = 0;
238c2c66affSColin Finck entry->cb += sizeof(WCHAR);
239c2c66affSColin Finck }
240c2c66affSColin Finck
241c2c66affSColin Finck if (ppidl)
242c2c66affSColin Finck *ppidl = (LPITEMIDLIST) entry;
243c2c66affSColin Finck return S_OK;
244c2c66affSColin Finck }
245c2c66affSColin Finck
Next(ULONG celt,LPITEMIDLIST * rgelt,ULONG * pceltFetched)246*de8e1553SKatayama Hirofumi MZ STDMETHODIMP Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched) override
247c2c66affSColin Finck {
248c2c66affSColin Finck if (pceltFetched)
249c2c66affSColin Finck *pceltFetched = 0;
250c2c66affSColin Finck
251c2c66affSColin Finck while (celt-- > 0)
252c2c66affSColin Finck {
253c2c66affSColin Finck HRESULT hr = EnumerateNext(rgelt);
254c2c66affSColin Finck if (hr != S_OK)
255c2c66affSColin Finck return hr;
256c2c66affSColin Finck
257c2c66affSColin Finck if (pceltFetched)
258c2c66affSColin Finck (*pceltFetched)++;
259c2c66affSColin Finck if (rgelt)
260c2c66affSColin Finck rgelt++;
261c2c66affSColin Finck }
262c2c66affSColin Finck
263c2c66affSColin Finck return S_OK;
264c2c66affSColin Finck }
265c2c66affSColin Finck
Skip(ULONG celt)266*de8e1553SKatayama Hirofumi MZ STDMETHODIMP Skip(ULONG celt) override
267c2c66affSColin Finck {
268c2c66affSColin Finck while (celt > 0)
269c2c66affSColin Finck {
270c2c66affSColin Finck HRESULT hr = EnumerateNext(NULL);
271c2c66affSColin Finck if (FAILED(hr))
272c2c66affSColin Finck return hr;
273c2c66affSColin Finck if (hr != S_OK)
274c2c66affSColin Finck break;
275c2c66affSColin Finck }
276c2c66affSColin Finck
277c2c66affSColin Finck return S_OK;
278c2c66affSColin Finck }
279c2c66affSColin Finck
Reset()280*de8e1553SKatayama Hirofumi MZ STDMETHODIMP Reset() override
281c2c66affSColin Finck {
282c2c66affSColin Finck return E_NOTIMPL;
283c2c66affSColin Finck }
284c2c66affSColin Finck
Clone(IEnumIDList ** ppenum)285*de8e1553SKatayama Hirofumi MZ STDMETHODIMP Clone(IEnumIDList **ppenum) override
286c2c66affSColin Finck {
287c2c66affSColin Finck return E_NOTIMPL;
288c2c66affSColin Finck }
289c2c66affSColin Finck
290c2c66affSColin Finck DECLARE_NOT_AGGREGATABLE(CEnumRegRoot)
291c2c66affSColin Finck DECLARE_PROTECT_FINAL_CONSTRUCT()
292c2c66affSColin Finck
293c2c66affSColin Finck BEGIN_COM_MAP(CEnumRegRoot)
294c2c66affSColin Finck COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
295c2c66affSColin Finck END_COM_MAP()
296c2c66affSColin Finck
297c2c66affSColin Finck };
298c2c66affSColin Finck
299c2c66affSColin Finck class CEnumRegKey :
300c2c66affSColin Finck public CComObjectRootEx<CComMultiThreadModelNoCS>,
301c2c66affSColin Finck public IEnumIDList
302c2c66affSColin Finck {
303c2c66affSColin Finck PCWSTR m_path;
304c2c66affSColin Finck HKEY m_hkey;
305c2c66affSColin Finck BOOL m_values;
306c2c66affSColin Finck int m_idx;
307c2c66affSColin Finck
308c2c66affSColin Finck public:
CEnumRegKey()309c2c66affSColin Finck CEnumRegKey()
310c2c66affSColin Finck : m_path(NULL), m_hkey(NULL), m_values(FALSE), m_idx(0)
311c2c66affSColin Finck {
312c2c66affSColin Finck }
313c2c66affSColin Finck
~CEnumRegKey()314c2c66affSColin Finck ~CEnumRegKey()
315c2c66affSColin Finck {
316c2c66affSColin Finck RegCloseKey(m_hkey);
317c2c66affSColin Finck }
318c2c66affSColin Finck
Initialize(PCWSTR path,HKEY root)319c2c66affSColin Finck HRESULT Initialize(PCWSTR path, HKEY root)
320c2c66affSColin Finck {
321c2c66affSColin Finck m_path = path;
322c2c66affSColin Finck
323c2c66affSColin Finck DWORD res;
324c2c66affSColin Finck if (root)
325c2c66affSColin Finck {
326c2c66affSColin Finck res = RegOpenKeyExW(root, *path == '\\' ? path + 1 : path, 0, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &m_hkey);
327c2c66affSColin Finck }
328c2c66affSColin Finck else
329c2c66affSColin Finck {
330c2c66affSColin Finck res = NtOpenObject(KEY_OBJECT, (PHANDLE) &m_hkey, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, path);
331c2c66affSColin Finck }
332c2c66affSColin Finck if (!NT_SUCCESS(res))
333c2c66affSColin Finck {
334c2c66affSColin Finck ERR("RegOpenKeyExW failed for path %S with status=%x\n", path, res);
335c2c66affSColin Finck return HRESULT_FROM_NT(res);
336c2c66affSColin Finck }
337c2c66affSColin Finck
338c2c66affSColin Finck return S_OK;
339c2c66affSColin Finck }
340c2c66affSColin Finck
NextKey(LPITEMIDLIST * ppidl)341c2c66affSColin Finck HRESULT NextKey(LPITEMIDLIST* ppidl)
342c2c66affSColin Finck {
343c2c66affSColin Finck WCHAR name[MAX_PATH];
344c2c66affSColin Finck DWORD cchName = _countof(name);
345c2c66affSColin Finck
346c2c66affSColin Finck WCHAR className[MAX_PATH];
347c2c66affSColin Finck DWORD cchClass = _countof(className);
348c2c66affSColin Finck
349c2c66affSColin Finck if (RegEnumKeyExW(m_hkey, m_idx++, name, &cchName, 0, className, &cchClass, NULL))
350c2c66affSColin Finck return S_FALSE;
351c2c66affSColin Finck
352c2c66affSColin Finck name[cchName] = 0;
353c2c66affSColin Finck className[cchClass] = 0;
354c2c66affSColin Finck
355c2c66affSColin Finck REG_ENTRY_TYPE otype = REG_ENTRY_KEY;
356c2c66affSColin Finck
357c2c66affSColin Finck DWORD entryBufferLength = FIELD_OFFSET(RegPidlEntry, entryName) + sizeof(WCHAR) + cchName * sizeof(WCHAR);
358c2c66affSColin Finck
359c2c66affSColin Finck if (cchClass > 0)
360c2c66affSColin Finck {
361c2c66affSColin Finck entryBufferLength += sizeof(WCHAR) + cchClass * sizeof(WCHAR);
362c2c66affSColin Finck }
363c2c66affSColin Finck
364c2c66affSColin Finck // allocate space for the terminator
365c2c66affSColin Finck entryBufferLength += FIELD_OFFSET(SHITEMID, abID);
366c2c66affSColin Finck
367c2c66affSColin Finck RegPidlEntry* entry = (RegPidlEntry*) CoTaskMemAlloc(entryBufferLength);
368c2c66affSColin Finck if (!entry)
369c2c66affSColin Finck return E_OUTOFMEMORY;
370c2c66affSColin Finck
371c2c66affSColin Finck memset(entry, 0, entryBufferLength);
372c2c66affSColin Finck
373c2c66affSColin Finck entry->cb = FIELD_OFFSET(RegPidlEntry, entryName);
374c2c66affSColin Finck entry->magic = REGISTRY_PIDL_MAGIC;
375c2c66affSColin Finck entry->entryType = otype;
376c2c66affSColin Finck
377c2c66affSColin Finck if (cchName > 0)
378c2c66affSColin Finck {
379c2c66affSColin Finck entry->entryNameLength = cchName * sizeof(WCHAR);
380c2c66affSColin Finck StringCbCopyNW(entry->entryName, entryBufferLength, name, entry->entryNameLength);
381c2c66affSColin Finck entry->cb += entry->entryNameLength + sizeof(WCHAR);
382c2c66affSColin Finck }
383c2c66affSColin Finck else
384c2c66affSColin Finck {
385c2c66affSColin Finck entry->entryNameLength = 0;
386c2c66affSColin Finck entry->entryName[0] = 0;
387c2c66affSColin Finck entry->cb += sizeof(WCHAR);
388c2c66affSColin Finck }
389c2c66affSColin Finck
390c2c66affSColin Finck if (cchClass)
391c2c66affSColin Finck {
392c2c66affSColin Finck PWSTR contentData = (PWSTR) ((PBYTE) entry + entry->cb);
393c2c66affSColin Finck DWORD remainingSpace = entryBufferLength - entry->cb;
394c2c66affSColin Finck
395c2c66affSColin Finck entry->contentsLength = cchClass * sizeof(WCHAR);
396c2c66affSColin Finck StringCbCopyNW(contentData, remainingSpace, className, entry->contentsLength);
397c2c66affSColin Finck
398c2c66affSColin Finck entry->cb += entry->contentsLength + sizeof(WCHAR);
399c2c66affSColin Finck }
400c2c66affSColin Finck
401c2c66affSColin Finck if (ppidl)
402c2c66affSColin Finck *ppidl = (LPITEMIDLIST) entry;
403c2c66affSColin Finck return S_OK;
404c2c66affSColin Finck }
405c2c66affSColin Finck
NextValue(LPITEMIDLIST * ppidl)406c2c66affSColin Finck HRESULT NextValue(LPITEMIDLIST* ppidl)
407c2c66affSColin Finck {
408c2c66affSColin Finck WCHAR name[MAX_PATH];
409c2c66affSColin Finck DWORD cchName = _countof(name);
410c2c66affSColin Finck DWORD type = 0;
411c2c66affSColin Finck DWORD dataSize = 0;
412c2c66affSColin Finck
413c2c66affSColin Finck if (RegEnumValueW(m_hkey, m_idx++, name, &cchName, 0, &type, NULL, &dataSize))
414c2c66affSColin Finck return S_FALSE;
415c2c66affSColin Finck
416c2c66affSColin Finck REG_ENTRY_TYPE otype = REG_ENTRY_VALUE;
417c2c66affSColin Finck
418c2c66affSColin Finck DWORD entryBufferLength = FIELD_OFFSET(RegPidlEntry, entryName) + sizeof(WCHAR) + cchName * sizeof(WCHAR);
419c2c66affSColin Finck
420c2c66affSColin Finck #define MAX_EMBEDDED_DATA 32
421c2c66affSColin Finck BOOL copyData = dataSize <= MAX_EMBEDDED_DATA;
422c2c66affSColin Finck if (copyData)
423c2c66affSColin Finck {
424c2c66affSColin Finck entryBufferLength += dataSize + sizeof(WCHAR);
425c2c66affSColin Finck
426c2c66affSColin Finck otype = REG_ENTRY_VALUE_WITH_CONTENT;
427c2c66affSColin Finck }
428c2c66affSColin Finck
429c2c66affSColin Finck // allocate space for the terminator
430c2c66affSColin Finck entryBufferLength += FIELD_OFFSET(SHITEMID, abID);
431c2c66affSColin Finck
432c2c66affSColin Finck RegPidlEntry* entry = (RegPidlEntry*) CoTaskMemAlloc(entryBufferLength);
433c2c66affSColin Finck if (!entry)
434c2c66affSColin Finck return E_OUTOFMEMORY;
435c2c66affSColin Finck
436c2c66affSColin Finck memset(entry, 0, entryBufferLength);
437c2c66affSColin Finck
438c2c66affSColin Finck entry->cb = FIELD_OFFSET(RegPidlEntry, entryName);
439c2c66affSColin Finck entry->magic = REGISTRY_PIDL_MAGIC;
440c2c66affSColin Finck entry->entryType = otype;
441c2c66affSColin Finck entry->contentType = type;
442c2c66affSColin Finck
443c2c66affSColin Finck if (cchName > 0)
444c2c66affSColin Finck {
445c2c66affSColin Finck entry->entryNameLength = cchName * sizeof(WCHAR);
446c2c66affSColin Finck StringCbCopyNW(entry->entryName, entryBufferLength, name, entry->entryNameLength);
447c2c66affSColin Finck entry->cb += entry->entryNameLength + sizeof(WCHAR);
448c2c66affSColin Finck }
449c2c66affSColin Finck else
450c2c66affSColin Finck {
451c2c66affSColin Finck entry->entryNameLength = 0;
452c2c66affSColin Finck entry->entryName[0] = 0;
453c2c66affSColin Finck entry->cb += sizeof(WCHAR);
454c2c66affSColin Finck }
455c2c66affSColin Finck
456c2c66affSColin Finck if (copyData)
457c2c66affSColin Finck {
458c2c66affSColin Finck PBYTE contentData = (PBYTE) ((PBYTE) entry + entry->cb);
459c2c66affSColin Finck
460c2c66affSColin Finck entry->contentsLength = dataSize;
461c2c66affSColin Finck
462c2c66affSColin Finck // In case it's an unterminated string, RegGetValue will add the NULL termination
463c2c66affSColin Finck dataSize += sizeof(WCHAR);
464c2c66affSColin Finck
465c2c66affSColin Finck if (!RegQueryValueExW(m_hkey, name, NULL, NULL, contentData, &dataSize))
466c2c66affSColin Finck {
467c2c66affSColin Finck entry->cb += entry->contentsLength + sizeof(WCHAR);
468c2c66affSColin Finck }
469c2c66affSColin Finck else
470c2c66affSColin Finck {
471c2c66affSColin Finck entry->contentsLength = 0;
472c2c66affSColin Finck entry->cb += sizeof(WCHAR);
473c2c66affSColin Finck }
474c2c66affSColin Finck
475c2c66affSColin Finck }
476c2c66affSColin Finck
477c2c66affSColin Finck if (ppidl)
478c2c66affSColin Finck *ppidl = (LPITEMIDLIST) entry;
479c2c66affSColin Finck return S_OK;
480c2c66affSColin Finck }
481c2c66affSColin Finck
EnumerateNext(LPITEMIDLIST * ppidl)482c2c66affSColin Finck HRESULT EnumerateNext(LPITEMIDLIST* ppidl)
483c2c66affSColin Finck {
484c2c66affSColin Finck if (!m_values)
485c2c66affSColin Finck {
486c2c66affSColin Finck HRESULT hr = NextKey(ppidl);
487c2c66affSColin Finck if (hr != S_FALSE)
488c2c66affSColin Finck return hr;
489c2c66affSColin Finck
490c2c66affSColin Finck // switch to values.
491c2c66affSColin Finck m_values = TRUE;
492c2c66affSColin Finck m_idx = 0;
493c2c66affSColin Finck }
494c2c66affSColin Finck
495c2c66affSColin Finck return NextValue(ppidl);
496c2c66affSColin Finck }
497c2c66affSColin Finck
Next(ULONG celt,LPITEMIDLIST * rgelt,ULONG * pceltFetched)498*de8e1553SKatayama Hirofumi MZ STDMETHODIMP Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched) override
499c2c66affSColin Finck {
500c2c66affSColin Finck if (pceltFetched)
501c2c66affSColin Finck *pceltFetched = 0;
502c2c66affSColin Finck
503c2c66affSColin Finck while (celt-- > 0)
504c2c66affSColin Finck {
505c2c66affSColin Finck HRESULT hr = EnumerateNext(rgelt);
506c2c66affSColin Finck if (hr != S_OK)
507c2c66affSColin Finck return hr;
508c2c66affSColin Finck
509c2c66affSColin Finck if (pceltFetched)
510c2c66affSColin Finck (*pceltFetched)++;
511c2c66affSColin Finck if (rgelt)
512c2c66affSColin Finck rgelt++;
513c2c66affSColin Finck }
514c2c66affSColin Finck
515c2c66affSColin Finck return S_OK;
516c2c66affSColin Finck }
517c2c66affSColin Finck
Skip(ULONG celt)518*de8e1553SKatayama Hirofumi MZ STDMETHODIMP Skip(ULONG celt) override
519c2c66affSColin Finck {
520c2c66affSColin Finck while (celt > 0)
521c2c66affSColin Finck {
522c2c66affSColin Finck HRESULT hr = EnumerateNext(NULL);
523c2c66affSColin Finck if (FAILED(hr))
524c2c66affSColin Finck return hr;
525c2c66affSColin Finck if (hr != S_OK)
526c2c66affSColin Finck break;
527c2c66affSColin Finck }
528c2c66affSColin Finck
529c2c66affSColin Finck return S_OK;
530c2c66affSColin Finck }
531c2c66affSColin Finck
Reset()532*de8e1553SKatayama Hirofumi MZ STDMETHODIMP Reset() override
533c2c66affSColin Finck {
534c2c66affSColin Finck return E_NOTIMPL;
535c2c66affSColin Finck }
536c2c66affSColin Finck
Clone(IEnumIDList ** ppenum)537*de8e1553SKatayama Hirofumi MZ STDMETHODIMP Clone(IEnumIDList **ppenum) override
538c2c66affSColin Finck {
539c2c66affSColin Finck return E_NOTIMPL;
540c2c66affSColin Finck }
541c2c66affSColin Finck
542c2c66affSColin Finck DECLARE_NOT_AGGREGATABLE(CEnumRegKey)
543c2c66affSColin Finck DECLARE_PROTECT_FINAL_CONSTRUCT()
544c2c66affSColin Finck
545c2c66affSColin Finck BEGIN_COM_MAP(CEnumRegKey)
546c2c66affSColin Finck COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
547c2c66affSColin Finck END_COM_MAP()
548c2c66affSColin Finck };
549c2c66affSColin Finck
550c2c66affSColin Finck class CEnumNTDirectory :
551c2c66affSColin Finck public CComObjectRootEx<CComMultiThreadModelNoCS>,
552c2c66affSColin Finck public IEnumIDList
553c2c66affSColin Finck {
554c2c66affSColin Finck WCHAR buffer[MAX_PATH];
555c2c66affSColin Finck HANDLE m_directory;
556c2c66affSColin Finck BOOL m_first;
557c2c66affSColin Finck ULONG m_enumContext;
558c2c66affSColin Finck PWSTR m_pend;
559c2c66affSColin Finck
560c2c66affSColin Finck public:
CEnumNTDirectory()561c2c66affSColin Finck CEnumNTDirectory()
562c2c66affSColin Finck : m_directory(NULL), m_first(TRUE), m_enumContext(0), m_pend(NULL)
563c2c66affSColin Finck {
564c2c66affSColin Finck }
565c2c66affSColin Finck
~CEnumNTDirectory()566c2c66affSColin Finck ~CEnumNTDirectory()
567c2c66affSColin Finck {
568c2c66affSColin Finck NtClose(m_directory);
569c2c66affSColin Finck }
570c2c66affSColin Finck
Initialize(PCWSTR path)571c2c66affSColin Finck HRESULT Initialize(PCWSTR path)
572c2c66affSColin Finck {
573c2c66affSColin Finck StringCbCopyExW(buffer, sizeof(buffer), path, &m_pend, NULL, 0);
574c2c66affSColin Finck
575c2c66affSColin Finck DWORD err = NtOpenObject(DIRECTORY_OBJECT, &m_directory, FILE_LIST_DIRECTORY, buffer);
576c2c66affSColin Finck if (!NT_SUCCESS(err))
577c2c66affSColin Finck {
578c2c66affSColin Finck ERR("NtOpenDirectoryObject failed for path %S with status=%x\n", buffer, err);
579c2c66affSColin Finck return HRESULT_FROM_NT(err);
580c2c66affSColin Finck }
581c2c66affSColin Finck
582c2c66affSColin Finck if (m_pend[-1] != '\\')
583c2c66affSColin Finck *m_pend++ = '\\';
584c2c66affSColin Finck
585c2c66affSColin Finck return S_OK;
586c2c66affSColin Finck }
587c2c66affSColin Finck
EnumerateNext(LPITEMIDLIST * ppidl)588c2c66affSColin Finck HRESULT EnumerateNext(LPITEMIDLIST* ppidl)
589c2c66affSColin Finck {
590c2c66affSColin Finck BYTE dirbuffer[2048];
591c2c66affSColin Finck if (!NT_SUCCESS(NtQueryDirectoryObject(m_directory, dirbuffer, 2048, TRUE, m_first, &m_enumContext, NULL)))
592c2c66affSColin Finck return S_FALSE;
593c2c66affSColin Finck
594c2c66affSColin Finck m_first = FALSE;
595c2c66affSColin Finck
596c2c66affSColin Finck // if ppidl is NULL, assume the caller was Skip(),
597c2c66affSColin Finck // so we don't care about the info
598c2c66affSColin Finck if (!ppidl)
599c2c66affSColin Finck return S_OK;
600c2c66affSColin Finck
601c2c66affSColin Finck POBJECT_DIRECTORY_INFORMATION info = (POBJECT_DIRECTORY_INFORMATION) dirbuffer;
602c2c66affSColin Finck
603c2c66affSColin Finck if (info->Name.Buffer)
604c2c66affSColin Finck {
605c2c66affSColin Finck StringCbCopyNW(m_pend, sizeof(buffer), info->Name.Buffer, info->Name.Length);
606c2c66affSColin Finck }
607c2c66affSColin Finck
608c2c66affSColin Finck OBJECT_TYPE otype = MapTypeNameToType(info->TypeName.Buffer, info->TypeName.Length);
609c2c66affSColin Finck
610c2c66affSColin Finck DWORD entryBufferLength = FIELD_OFFSET(NtPidlEntry, entryName) + sizeof(WCHAR);
611c2c66affSColin Finck if (info->Name.Buffer)
612c2c66affSColin Finck entryBufferLength += info->Name.Length;
613c2c66affSColin Finck
614c2c66affSColin Finck if (otype < 0)
615c2c66affSColin Finck {
616c2c66affSColin Finck entryBufferLength += FIELD_OFFSET(NtPidlTypeData, typeName) + sizeof(WCHAR);
617c2c66affSColin Finck
618c2c66affSColin Finck if (info->TypeName.Buffer)
619c2c66affSColin Finck {
620c2c66affSColin Finck entryBufferLength += info->TypeName.Length;
621c2c66affSColin Finck }
622c2c66affSColin Finck }
623c2c66affSColin Finck
624c2c66affSColin Finck // allocate space for the terminator
625c2c66affSColin Finck entryBufferLength += FIELD_OFFSET(SHITEMID, abID);
626c2c66affSColin Finck
627c2c66affSColin Finck NtPidlEntry* entry = (NtPidlEntry*) CoTaskMemAlloc(entryBufferLength);
628c2c66affSColin Finck if (!entry)
629c2c66affSColin Finck return E_OUTOFMEMORY;
630c2c66affSColin Finck
631c2c66affSColin Finck memset(entry, 0, entryBufferLength);
632c2c66affSColin Finck
633c2c66affSColin Finck entry->cb = FIELD_OFFSET(NtPidlEntry, entryName);
634c2c66affSColin Finck entry->magic = NT_OBJECT_PIDL_MAGIC;
635c2c66affSColin Finck entry->objectType = otype;
636c2c66affSColin Finck
637c2c66affSColin Finck if (info->Name.Buffer)
638c2c66affSColin Finck {
639c2c66affSColin Finck entry->entryNameLength = info->Name.Length;
640c2c66affSColin Finck StringCbCopyNW(entry->entryName, entryBufferLength, info->Name.Buffer, info->Name.Length);
641c2c66affSColin Finck entry->cb += entry->entryNameLength + sizeof(WCHAR);
642c2c66affSColin Finck }
643c2c66affSColin Finck else
644c2c66affSColin Finck {
645c2c66affSColin Finck entry->entryNameLength = 0;
646c2c66affSColin Finck entry->entryName[0] = 0;
647c2c66affSColin Finck entry->cb += sizeof(WCHAR);
648c2c66affSColin Finck }
649c2c66affSColin Finck
650c2c66affSColin Finck if (otype < 0)
651c2c66affSColin Finck {
652c2c66affSColin Finck NtPidlTypeData * typedata = (NtPidlTypeData*) ((PBYTE) entry + entry->cb);
653c2c66affSColin Finck DWORD remainingSpace = entryBufferLength - ((PBYTE) (typedata->typeName) - (PBYTE) entry);
654c2c66affSColin Finck
655c2c66affSColin Finck if (info->TypeName.Buffer)
656c2c66affSColin Finck {
657c2c66affSColin Finck typedata->typeNameLength = info->TypeName.Length;
658c2c66affSColin Finck StringCbCopyNW(typedata->typeName, remainingSpace, info->TypeName.Buffer, info->TypeName.Length);
659c2c66affSColin Finck
660c2c66affSColin Finck entry->cb += typedata->typeNameLength + sizeof(WCHAR);
661c2c66affSColin Finck }
662c2c66affSColin Finck else
663c2c66affSColin Finck {
664c2c66affSColin Finck typedata->typeNameLength = 0;
665c2c66affSColin Finck typedata->typeName[0] = 0;
666c2c66affSColin Finck entry->cb += typedata->typeNameLength + sizeof(WCHAR);
667c2c66affSColin Finck }
668c2c66affSColin Finck }
669c2c66affSColin Finck
670c2c66affSColin Finck *ppidl = (LPITEMIDLIST) entry;
671c2c66affSColin Finck
672c2c66affSColin Finck return S_OK;
673c2c66affSColin Finck }
674c2c66affSColin Finck
Next(ULONG celt,LPITEMIDLIST * rgelt,ULONG * pceltFetched)675*de8e1553SKatayama Hirofumi MZ STDMETHODIMP Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched) override
676c2c66affSColin Finck {
677c2c66affSColin Finck if (pceltFetched)
678c2c66affSColin Finck *pceltFetched = 0;
679c2c66affSColin Finck
680c2c66affSColin Finck while (celt-- > 0)
681c2c66affSColin Finck {
682c2c66affSColin Finck HRESULT hr = EnumerateNext(rgelt);
683c2c66affSColin Finck if (hr != S_OK)
684c2c66affSColin Finck return hr;
685c2c66affSColin Finck
686c2c66affSColin Finck if (pceltFetched)
687c2c66affSColin Finck (*pceltFetched)++;
688c2c66affSColin Finck if (rgelt)
689c2c66affSColin Finck rgelt++;
690c2c66affSColin Finck }
691c2c66affSColin Finck
692c2c66affSColin Finck return S_OK;
693c2c66affSColin Finck }
694c2c66affSColin Finck
Skip(ULONG celt)695*de8e1553SKatayama Hirofumi MZ STDMETHODIMP Skip(ULONG celt) override
696c2c66affSColin Finck {
697c2c66affSColin Finck while (celt > 0)
698c2c66affSColin Finck {
699c2c66affSColin Finck HRESULT hr = EnumerateNext(NULL);
700c2c66affSColin Finck if (FAILED(hr))
701c2c66affSColin Finck return hr;
702c2c66affSColin Finck if (hr != S_OK)
703c2c66affSColin Finck break;
704c2c66affSColin Finck }
705c2c66affSColin Finck
706c2c66affSColin Finck return S_OK;
707c2c66affSColin Finck }
708c2c66affSColin Finck
Reset()709*de8e1553SKatayama Hirofumi MZ STDMETHODIMP Reset() override
710c2c66affSColin Finck {
711c2c66affSColin Finck return E_NOTIMPL;
712c2c66affSColin Finck }
713c2c66affSColin Finck
Clone(IEnumIDList ** ppenum)714*de8e1553SKatayama Hirofumi MZ STDMETHODIMP Clone(IEnumIDList **ppenum) override
715c2c66affSColin Finck {
716c2c66affSColin Finck return E_NOTIMPL;
717c2c66affSColin Finck }
718c2c66affSColin Finck
719c2c66affSColin Finck DECLARE_NOT_AGGREGATABLE(CEnumNTDirectory)
720c2c66affSColin Finck DECLARE_PROTECT_FINAL_CONSTRUCT()
721c2c66affSColin Finck
722c2c66affSColin Finck BEGIN_COM_MAP(CEnumNTDirectory)
723c2c66affSColin Finck COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
724c2c66affSColin Finck END_COM_MAP()
725c2c66affSColin Finck };
726c2c66affSColin Finck
GetEnumRegistryRoot(IEnumIDList ** ppil)727c2c66affSColin Finck HRESULT GetEnumRegistryRoot(IEnumIDList ** ppil)
728c2c66affSColin Finck {
729c2c66affSColin Finck return ShellObjectCreator<CEnumRegRoot>(IID_PPV_ARG(IEnumIDList, ppil));
730c2c66affSColin Finck }
731c2c66affSColin Finck
GetEnumRegistryKey(LPCWSTR path,HKEY root,IEnumIDList ** ppil)732c2c66affSColin Finck HRESULT GetEnumRegistryKey(LPCWSTR path, HKEY root, IEnumIDList ** ppil)
733c2c66affSColin Finck {
734c2c66affSColin Finck return ShellObjectCreatorInit<CEnumRegKey>(path, root, IID_PPV_ARG(IEnumIDList, ppil));
735c2c66affSColin Finck }
736c2c66affSColin Finck
GetEnumNTDirectory(LPCWSTR path,IEnumIDList ** ppil)737c2c66affSColin Finck HRESULT GetEnumNTDirectory(LPCWSTR path, IEnumIDList ** ppil)
738c2c66affSColin Finck {
739c2c66affSColin Finck return ShellObjectCreatorInit<CEnumNTDirectory>(path, IID_PPV_ARG(IEnumIDList, ppil));
740c2c66affSColin Finck }
741