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