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