094a24217cf8f84d5f43d38ce97e4f4db604ec92
[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 *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 += 2;
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 *ppidl = (LPITEMIDLIST) entry;
413 return S_OK;
414 }
415
416 HRESULT NextValue(LPITEMIDLIST* ppidl)
417 {
418 WCHAR name[MAX_PATH];
419 DWORD cchName = _countof(name);
420 DWORD type = 0;
421 DWORD dataSize = 0;
422
423 if (RegEnumValueW(m_hkey, m_idx++, name, &cchName, 0, &type, NULL, &dataSize))
424 return S_FALSE;
425
426 REG_ENTRY_TYPE otype = REG_ENTRY_VALUE;
427
428 DWORD entryBufferLength = FIELD_OFFSET(RegPidlEntry, entryName) + sizeof(WCHAR) + cchName * sizeof(WCHAR);
429
430 BOOL copyData = dataSize < 32;
431 if (copyData)
432 {
433 entryBufferLength += dataSize + sizeof(WCHAR);
434
435 otype = REG_ENTRY_VALUE_WITH_CONTENT;
436 }
437
438 RegPidlEntry* entry = (RegPidlEntry*) CoTaskMemAlloc(entryBufferLength + 2);
439 if (!entry)
440 return E_OUTOFMEMORY;
441
442 memset(entry, 0, entryBufferLength);
443
444 entry->cb = FIELD_OFFSET(RegPidlEntry, entryName);
445 entry->magic = REGISTRY_PIDL_MAGIC;
446 entry->entryType = otype;
447 entry->contentType = type;
448
449 if (cchName > 0)
450 {
451 entry->entryNameLength = cchName * sizeof(WCHAR);
452 StringCbCopyNW(entry->entryName, entryBufferLength, name, entry->entryNameLength);
453 entry->cb += entry->entryNameLength + sizeof(WCHAR);
454 }
455 else
456 {
457 entry->entryNameLength = 0;
458 entry->entryName[0] = 0;
459 entry->cb += sizeof(WCHAR);
460 }
461
462 if (copyData)
463 {
464 PBYTE contentData = (PBYTE) ((PBYTE) entry + entry->cb);
465
466 entry->contentsLength = dataSize;
467
468 // In case it's an unterminated string, RegGetValue will add the NULL termination
469 dataSize += sizeof(WCHAR);
470
471 if (!RegQueryValueExW(m_hkey, name, NULL, NULL, contentData, &dataSize))
472 {
473 entry->cb += entry->contentsLength + sizeof(WCHAR);
474 }
475 else
476 {
477 entry->contentsLength = 0;
478 entry->cb += sizeof(WCHAR);
479 }
480
481 }
482
483 *ppidl = (LPITEMIDLIST) entry;
484 return S_OK;
485 }
486
487 HRESULT EnumerateNext(LPITEMIDLIST* ppidl)
488 {
489 if (!m_values)
490 {
491 HRESULT hr = NextKey(ppidl);
492 if (hr != S_FALSE)
493 return hr;
494
495 // switch to values.
496 m_values = TRUE;
497 m_idx = 0;
498 }
499
500 return NextValue(ppidl);
501 }
502
503 virtual HRESULT STDMETHODCALLTYPE Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched)
504 {
505 if (pceltFetched)
506 *pceltFetched = 0;
507
508 while (celt-- > 0)
509 {
510 HRESULT hr = EnumerateNext(rgelt);
511 if (hr != S_OK)
512 return hr;
513
514 if (pceltFetched)
515 (*pceltFetched)++;
516 if (rgelt)
517 rgelt++;
518 }
519
520 return S_OK;
521 }
522
523 virtual HRESULT STDMETHODCALLTYPE Skip(ULONG celt)
524 {
525 while (celt > 0)
526 {
527 HRESULT hr = EnumerateNext(NULL);
528 if (FAILED(hr))
529 return hr;
530 if (hr != S_OK)
531 break;
532 }
533
534 return S_OK;
535 }
536
537 virtual HRESULT STDMETHODCALLTYPE Reset()
538 {
539 return E_NOTIMPL;
540 }
541
542 virtual HRESULT STDMETHODCALLTYPE Clone(IEnumIDList **ppenum)
543 {
544 return E_NOTIMPL;
545 }
546
547 DECLARE_NOT_AGGREGATABLE(CEnumRegKey)
548 DECLARE_PROTECT_FINAL_CONSTRUCT()
549
550 BEGIN_COM_MAP(CEnumRegKey)
551 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
552 END_COM_MAP()
553 };
554
555 class CEnumNTDirectory :
556 public CComObjectRootEx<CComMultiThreadModelNoCS>,
557 public IEnumIDList
558 {
559 WCHAR buffer[MAX_PATH];
560 HANDLE m_directory;
561 BOOL m_first;
562 ULONG m_enumContext;
563 PWSTR m_pend;
564
565 public:
566 CEnumNTDirectory()
567 : m_directory(NULL), m_first(TRUE), m_enumContext(0), m_pend(NULL)
568 {
569 }
570
571 ~CEnumNTDirectory()
572 {
573 NtClose(m_directory);
574 }
575
576 HRESULT Initialize(PCWSTR path)
577 {
578 StringCbCopyExW(buffer, sizeof(buffer), path, &m_pend, NULL, 0);
579
580 DWORD err = NtOpenObject(DIRECTORY_OBJECT, &m_directory, FILE_LIST_DIRECTORY, buffer);
581 if (!NT_SUCCESS(err))
582 {
583 ERR("NtOpenDirectoryObject failed for path %S with status=%x\n", buffer, err);
584 return HRESULT_FROM_NT(err);
585 }
586
587 if (m_pend[-1] != '\\')
588 *m_pend++ = '\\';
589
590 return S_OK;
591 }
592
593 HRESULT EnumerateNext(LPITEMIDLIST* ppidl)
594 {
595 BYTE dirbuffer[2048];
596 if (!NT_SUCCESS(NtQueryDirectoryObject(m_directory, dirbuffer, 2048, TRUE, m_first, &m_enumContext, NULL)))
597 return S_FALSE;
598
599 // if ppidl is NULL, assume the caller was Skip(),
600 // so we don't care about the info
601 if (!ppidl)
602 return S_OK;
603
604 m_first = FALSE;
605 POBJECT_DIRECTORY_INFORMATION info = (POBJECT_DIRECTORY_INFORMATION) dirbuffer;
606
607 if (info->Name.Buffer)
608 {
609 StringCbCopyNW(m_pend, sizeof(buffer), info->Name.Buffer, info->Name.Length);
610 }
611
612 OBJECT_TYPE otype = MapTypeNameToType(info->TypeName.Buffer, info->TypeName.Length);
613
614 DWORD entryBufferLength = FIELD_OFFSET(NtPidlEntry, entryName) + sizeof(WCHAR);
615 if (info->Name.Buffer)
616 entryBufferLength += info->Name.Length;
617
618 if (otype < 0)
619 {
620 entryBufferLength += FIELD_OFFSET(NtPidlTypeData, typeName) + sizeof(WCHAR);
621
622 if (info->TypeName.Buffer)
623 {
624 entryBufferLength += info->TypeName.Length;
625 }
626 }
627
628 // allocate space for the terminator
629 entryBufferLength += 2;
630
631 NtPidlEntry* entry = (NtPidlEntry*) CoTaskMemAlloc(entryBufferLength);
632 if (!entry)
633 return E_OUTOFMEMORY;
634
635 memset(entry, 0, entryBufferLength);
636
637 entry->cb = FIELD_OFFSET(NtPidlEntry, entryName);
638 entry->magic = NT_OBJECT_PIDL_MAGIC;
639 entry->objectType = otype;
640
641 if (info->Name.Buffer)
642 {
643 entry->entryNameLength = info->Name.Length;
644 StringCbCopyNW(entry->entryName, entryBufferLength, info->Name.Buffer, info->Name.Length);
645 entry->cb += entry->entryNameLength + sizeof(WCHAR);
646 }
647 else
648 {
649 entry->entryNameLength = 0;
650 entry->entryName[0] = 0;
651 entry->cb += sizeof(WCHAR);
652 }
653
654 if (otype < 0)
655 {
656 NtPidlTypeData * typedata = (NtPidlTypeData*) ((PBYTE) entry + entry->cb);
657 DWORD remainingSpace = entryBufferLength - ((PBYTE) (typedata->typeName) - (PBYTE) entry);
658
659 if (info->TypeName.Buffer)
660 {
661 typedata->typeNameLength = info->TypeName.Length;
662 StringCbCopyNW(typedata->typeName, remainingSpace, info->TypeName.Buffer, info->TypeName.Length);
663
664 entry->cb += typedata->typeNameLength + sizeof(WCHAR);
665 }
666 else
667 {
668 typedata->typeNameLength = 0;
669 typedata->typeName[0] = 0;
670 entry->cb += typedata->typeNameLength + sizeof(WCHAR);
671 }
672 }
673
674 *ppidl = (LPITEMIDLIST) entry;
675
676 return S_OK;
677 }
678
679 virtual HRESULT STDMETHODCALLTYPE Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched)
680 {
681 if (pceltFetched)
682 *pceltFetched = 0;
683
684 while (celt-- > 0)
685 {
686 HRESULT hr = EnumerateNext(rgelt);
687 if (hr != S_OK)
688 return hr;
689
690 if (pceltFetched)
691 (*pceltFetched)++;
692 if (rgelt)
693 rgelt++;
694 }
695
696 return S_OK;
697 }
698
699 virtual HRESULT STDMETHODCALLTYPE Skip(ULONG celt)
700 {
701 while (celt > 0)
702 {
703 HRESULT hr = EnumerateNext(NULL);
704 if (FAILED(hr))
705 return hr;
706 if (hr != S_OK)
707 break;
708 }
709
710 return S_OK;
711 }
712
713 virtual HRESULT STDMETHODCALLTYPE Reset()
714 {
715 return E_NOTIMPL;
716 }
717
718 virtual HRESULT STDMETHODCALLTYPE Clone(IEnumIDList **ppenum)
719 {
720 return E_NOTIMPL;
721 }
722
723 DECLARE_NOT_AGGREGATABLE(CEnumNTDirectory)
724 DECLARE_PROTECT_FINAL_CONSTRUCT()
725
726 BEGIN_COM_MAP(CEnumNTDirectory)
727 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
728 END_COM_MAP()
729 };
730
731 HRESULT GetEnumRegistryRoot(IEnumIDList ** ppil)
732 {
733 return ShellObjectCreator<CEnumRegRoot>(IID_PPV_ARG(IEnumIDList, ppil));
734 }
735
736 HRESULT GetEnumRegistryKey(LPCWSTR path, HKEY root, IEnumIDList ** ppil)
737 {
738 return ShellObjectCreatorInit<CEnumRegKey>(path, root, IID_PPV_ARG(IEnumIDList, ppil));
739 }
740
741 HRESULT GetEnumNTDirectory(LPCWSTR path, IEnumIDList ** ppil)
742 {
743 return ShellObjectCreatorInit<CEnumNTDirectory>(path, IID_PPV_ARG(IEnumIDList, ppil));
744 }