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