0d205e4e7d586af6b4bac5beb133359d3019ac3d
[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"WindowStation", 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 IOCOMPLETION_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 {
176 *pend++ = '\\';
177 *pend = 0;
178 }
179
180 StringCbCatW(buffer, sizeof(buffer), entryName);
181
182 DbgPrint("GetNTObjectSymbolicLinkTarget %d\n", buffer);
183
184 LinkTarget->Length = 0;
185
186 DWORD err = NtOpenObject(SYMBOLICLINK_OBJECT, &handle, SYMBOLIC_LINK_QUERY, buffer);
187 if (!NT_SUCCESS(err))
188 return HRESULT_FROM_NT(err);
189
190 err = NtQuerySymbolicLinkObject(handle, LinkTarget, NULL);
191 if (!NT_SUCCESS(err))
192 return HRESULT_FROM_NT(err);
193
194 NtClose(handle);
195
196 return S_OK;
197 }
198
199 class CEnumRegRoot :
200 public CComObjectRootEx<CComMultiThreadModelNoCS>,
201 public IEnumIDList
202 {
203 UINT m_idx;
204
205 public:
206 CEnumRegRoot()
207 : m_idx(0)
208 {
209 }
210
211 ~CEnumRegRoot()
212 {
213 }
214
215 HRESULT EnumerateNext(LPITEMIDLIST* ppidl)
216 {
217 if (m_idx >= _countof(RootKeys))
218 return S_FALSE;
219
220 RootKeyEntry& key = RootKeys[m_idx++];
221
222 PCWSTR name = key.keyName;
223 DWORD cchName = wcslen(name);
224
225 REG_ENTRY_TYPE otype = REG_ENTRY_ROOT;
226
227 DWORD entryBufferLength = FIELD_OFFSET(RegPidlEntry, entryName) + sizeof(WCHAR) + cchName * sizeof(WCHAR);
228
229 // allocate space for the terminator
230 entryBufferLength += 2;
231
232 RegPidlEntry* entry = (RegPidlEntry*) CoTaskMemAlloc(entryBufferLength);
233 if (!entry)
234 return E_OUTOFMEMORY;
235
236 memset(entry, 0, entryBufferLength);
237
238 entry->cb = FIELD_OFFSET(RegPidlEntry, entryName);
239 entry->magic = REGISTRY_PIDL_MAGIC;
240 entry->entryType = otype;
241 entry->rootKey = key.key;
242
243 if (cchName > 0)
244 {
245 entry->entryNameLength = cchName * sizeof(WCHAR);
246 StringCbCopyNW(entry->entryName, entryBufferLength, name, entry->entryNameLength);
247 entry->cb += entry->entryNameLength + sizeof(WCHAR);
248 }
249 else
250 {
251 entry->entryNameLength = 0;
252 entry->entryName[0] = 0;
253 entry->cb += sizeof(WCHAR);
254 }
255
256 if (ppidl)
257 *ppidl = (LPITEMIDLIST) entry;
258 return S_OK;
259 }
260
261 virtual HRESULT STDMETHODCALLTYPE Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched)
262 {
263 if (pceltFetched)
264 *pceltFetched = 0;
265
266 while (celt-- > 0)
267 {
268 HRESULT hr = EnumerateNext(rgelt);
269 if (hr != S_OK)
270 return hr;
271
272 if (pceltFetched)
273 (*pceltFetched)++;
274 if (rgelt)
275 rgelt++;
276 }
277
278 return S_OK;
279 }
280
281 virtual HRESULT STDMETHODCALLTYPE Skip(ULONG celt)
282 {
283 while (celt > 0)
284 {
285 HRESULT hr = EnumerateNext(NULL);
286 if (FAILED(hr))
287 return hr;
288 if (hr != S_OK)
289 break;
290 }
291
292 return S_OK;
293 }
294
295 virtual HRESULT STDMETHODCALLTYPE Reset()
296 {
297 return E_NOTIMPL;
298 }
299
300 virtual HRESULT STDMETHODCALLTYPE Clone(IEnumIDList **ppenum)
301 {
302 return E_NOTIMPL;
303 }
304
305 DECLARE_NOT_AGGREGATABLE(CEnumRegRoot)
306 DECLARE_PROTECT_FINAL_CONSTRUCT()
307
308 BEGIN_COM_MAP(CEnumRegRoot)
309 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
310 END_COM_MAP()
311
312 };
313
314 class CEnumRegKey :
315 public CComObjectRootEx<CComMultiThreadModelNoCS>,
316 public IEnumIDList
317 {
318 PCWSTR m_path;
319 HKEY m_hkey;
320 BOOL m_values;
321 int m_idx;
322
323 public:
324 CEnumRegKey()
325 : m_path(NULL), m_hkey(NULL), m_values(FALSE), m_idx(0)
326 {
327 }
328
329 ~CEnumRegKey()
330 {
331 RegCloseKey(m_hkey);
332 }
333
334 HRESULT Initialize(PCWSTR path, HKEY root)
335 {
336 m_path = path;
337
338 DWORD res;
339 if (root)
340 {
341 res = RegOpenKeyExW(root, *path == '\\' ? path + 1 : path, 0, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &m_hkey);
342 }
343 else
344 {
345 res = NtOpenObject(KEY_OBJECT, (PHANDLE) &m_hkey, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, path);
346 }
347 if (!NT_SUCCESS(res))
348 {
349 ERR("RegOpenKeyExW failed for path %S with status=%x\n", path, res);
350 return HRESULT_FROM_NT(res);
351 }
352
353 return S_OK;
354 }
355
356 HRESULT NextKey(LPITEMIDLIST* ppidl)
357 {
358 WCHAR name[MAX_PATH];
359 DWORD cchName = _countof(name);
360
361 WCHAR className[MAX_PATH];
362 DWORD cchClass = _countof(className);
363
364 if (RegEnumKeyExW(m_hkey, m_idx++, name, &cchName, 0, className, &cchClass, NULL))
365 return S_FALSE;
366
367 name[cchName] = 0;
368 className[cchClass] = 0;
369
370 REG_ENTRY_TYPE otype = REG_ENTRY_KEY;
371
372 DWORD entryBufferLength = FIELD_OFFSET(RegPidlEntry, entryName) + sizeof(WCHAR) + cchName * sizeof(WCHAR);
373
374 if (cchClass > 0)
375 {
376 entryBufferLength += sizeof(WCHAR) + cchClass * sizeof(WCHAR);
377 }
378
379 // allocate space for the terminator
380 entryBufferLength += 2;
381
382 RegPidlEntry* entry = (RegPidlEntry*) CoTaskMemAlloc(entryBufferLength);
383 if (!entry)
384 return E_OUTOFMEMORY;
385
386 memset(entry, 0, entryBufferLength);
387
388 entry->cb = FIELD_OFFSET(RegPidlEntry, entryName);
389 entry->magic = REGISTRY_PIDL_MAGIC;
390 entry->entryType = otype;
391
392 if (cchName > 0)
393 {
394 entry->entryNameLength = cchName * sizeof(WCHAR);
395 StringCbCopyNW(entry->entryName, entryBufferLength, name, entry->entryNameLength);
396 entry->cb += entry->entryNameLength + sizeof(WCHAR);
397 }
398 else
399 {
400 entry->entryNameLength = 0;
401 entry->entryName[0] = 0;
402 entry->cb += sizeof(WCHAR);
403 }
404
405 if (cchClass)
406 {
407 PWSTR contentData = (PWSTR) ((PBYTE) entry + entry->cb);
408 DWORD remainingSpace = entryBufferLength - entry->cb;
409
410 entry->contentsLength = cchClass * sizeof(WCHAR);
411 StringCbCopyNW(contentData, remainingSpace, className, entry->contentsLength);
412
413 entry->cb += entry->contentsLength + sizeof(WCHAR);
414 }
415
416 if (ppidl)
417 *ppidl = (LPITEMIDLIST) entry;
418 return S_OK;
419 }
420
421 HRESULT NextValue(LPITEMIDLIST* ppidl)
422 {
423 WCHAR name[MAX_PATH];
424 DWORD cchName = _countof(name);
425 DWORD type = 0;
426 DWORD dataSize = 0;
427
428 if (RegEnumValueW(m_hkey, m_idx++, name, &cchName, 0, &type, NULL, &dataSize))
429 return S_FALSE;
430
431 REG_ENTRY_TYPE otype = REG_ENTRY_VALUE;
432
433 DWORD entryBufferLength = FIELD_OFFSET(RegPidlEntry, entryName) + sizeof(WCHAR) + cchName * sizeof(WCHAR);
434
435 BOOL copyData = dataSize < 256;
436 if (copyData)
437 {
438 entryBufferLength += dataSize + sizeof(WCHAR);
439
440 otype = REG_ENTRY_VALUE_WITH_CONTENT;
441 }
442
443 // allocate space for the terminator
444 entryBufferLength += 2;
445
446 RegPidlEntry* entry = (RegPidlEntry*) CoTaskMemAlloc(entryBufferLength);
447 if (!entry)
448 return E_OUTOFMEMORY;
449
450 memset(entry, 0, entryBufferLength);
451
452 entry->cb = FIELD_OFFSET(RegPidlEntry, entryName);
453 entry->magic = REGISTRY_PIDL_MAGIC;
454 entry->entryType = otype;
455 entry->contentType = type;
456
457 if (cchName > 0)
458 {
459 entry->entryNameLength = cchName * sizeof(WCHAR);
460 StringCbCopyNW(entry->entryName, entryBufferLength, name, entry->entryNameLength);
461 entry->cb += entry->entryNameLength + sizeof(WCHAR);
462 }
463 else
464 {
465 entry->entryNameLength = 0;
466 entry->entryName[0] = 0;
467 entry->cb += sizeof(WCHAR);
468 }
469
470 if (copyData)
471 {
472 PBYTE contentData = (PBYTE) ((PBYTE) entry + entry->cb);
473
474 entry->contentsLength = dataSize;
475
476 // In case it's an unterminated string, RegGetValue will add the NULL termination
477 dataSize += sizeof(WCHAR);
478
479 if (!RegQueryValueExW(m_hkey, name, NULL, NULL, contentData, &dataSize))
480 {
481 entry->cb += entry->contentsLength + sizeof(WCHAR);
482 }
483 else
484 {
485 entry->contentsLength = 0;
486 entry->cb += sizeof(WCHAR);
487 }
488
489 }
490
491 if (ppidl)
492 *ppidl = (LPITEMIDLIST) entry;
493 return S_OK;
494 }
495
496 HRESULT EnumerateNext(LPITEMIDLIST* ppidl)
497 {
498 if (!m_values)
499 {
500 HRESULT hr = NextKey(ppidl);
501 if (hr != S_FALSE)
502 return hr;
503
504 // switch to values.
505 m_values = TRUE;
506 m_idx = 0;
507 }
508
509 return NextValue(ppidl);
510 }
511
512 virtual HRESULT STDMETHODCALLTYPE Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched)
513 {
514 if (pceltFetched)
515 *pceltFetched = 0;
516
517 while (celt-- > 0)
518 {
519 HRESULT hr = EnumerateNext(rgelt);
520 if (hr != S_OK)
521 return hr;
522
523 if (pceltFetched)
524 (*pceltFetched)++;
525 if (rgelt)
526 rgelt++;
527 }
528
529 return S_OK;
530 }
531
532 virtual HRESULT STDMETHODCALLTYPE Skip(ULONG celt)
533 {
534 while (celt > 0)
535 {
536 HRESULT hr = EnumerateNext(NULL);
537 if (FAILED(hr))
538 return hr;
539 if (hr != S_OK)
540 break;
541 }
542
543 return S_OK;
544 }
545
546 virtual HRESULT STDMETHODCALLTYPE Reset()
547 {
548 return E_NOTIMPL;
549 }
550
551 virtual HRESULT STDMETHODCALLTYPE Clone(IEnumIDList **ppenum)
552 {
553 return E_NOTIMPL;
554 }
555
556 DECLARE_NOT_AGGREGATABLE(CEnumRegKey)
557 DECLARE_PROTECT_FINAL_CONSTRUCT()
558
559 BEGIN_COM_MAP(CEnumRegKey)
560 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
561 END_COM_MAP()
562 };
563
564 class CEnumNTDirectory :
565 public CComObjectRootEx<CComMultiThreadModelNoCS>,
566 public IEnumIDList
567 {
568 WCHAR buffer[MAX_PATH];
569 HANDLE m_directory;
570 BOOL m_first;
571 ULONG m_enumContext;
572 PWSTR m_pend;
573
574 public:
575 CEnumNTDirectory()
576 : m_directory(NULL), m_first(TRUE), m_enumContext(0), m_pend(NULL)
577 {
578 }
579
580 ~CEnumNTDirectory()
581 {
582 NtClose(m_directory);
583 }
584
585 HRESULT Initialize(PCWSTR path)
586 {
587 StringCbCopyExW(buffer, sizeof(buffer), path, &m_pend, NULL, 0);
588
589 DWORD err = NtOpenObject(DIRECTORY_OBJECT, &m_directory, FILE_LIST_DIRECTORY, buffer);
590 if (!NT_SUCCESS(err))
591 {
592 ERR("NtOpenDirectoryObject failed for path %S with status=%x\n", buffer, err);
593 return HRESULT_FROM_NT(err);
594 }
595
596 if (m_pend[-1] != '\\')
597 *m_pend++ = '\\';
598
599 return S_OK;
600 }
601
602 HRESULT EnumerateNext(LPITEMIDLIST* ppidl)
603 {
604 BYTE dirbuffer[2048];
605 if (!NT_SUCCESS(NtQueryDirectoryObject(m_directory, dirbuffer, 2048, TRUE, m_first, &m_enumContext, NULL)))
606 return S_FALSE;
607
608 m_first = FALSE;
609
610 // if ppidl is NULL, assume the caller was Skip(),
611 // so we don't care about the info
612 if (!ppidl)
613 return S_OK;
614
615 POBJECT_DIRECTORY_INFORMATION info = (POBJECT_DIRECTORY_INFORMATION) dirbuffer;
616
617 if (info->Name.Buffer)
618 {
619 StringCbCopyNW(m_pend, sizeof(buffer), info->Name.Buffer, info->Name.Length);
620 }
621
622 OBJECT_TYPE otype = MapTypeNameToType(info->TypeName.Buffer, info->TypeName.Length);
623
624 DWORD entryBufferLength = FIELD_OFFSET(NtPidlEntry, entryName) + sizeof(WCHAR);
625 if (info->Name.Buffer)
626 entryBufferLength += info->Name.Length;
627
628 if (otype < 0)
629 {
630 entryBufferLength += FIELD_OFFSET(NtPidlTypeData, typeName) + sizeof(WCHAR);
631
632 if (info->TypeName.Buffer)
633 {
634 entryBufferLength += info->TypeName.Length;
635 }
636 }
637
638 // allocate space for the terminator
639 entryBufferLength += 2;
640
641 NtPidlEntry* entry = (NtPidlEntry*) CoTaskMemAlloc(entryBufferLength);
642 if (!entry)
643 return E_OUTOFMEMORY;
644
645 memset(entry, 0, entryBufferLength);
646
647 entry->cb = FIELD_OFFSET(NtPidlEntry, entryName);
648 entry->magic = NT_OBJECT_PIDL_MAGIC;
649 entry->objectType = otype;
650
651 if (info->Name.Buffer)
652 {
653 entry->entryNameLength = info->Name.Length;
654 StringCbCopyNW(entry->entryName, entryBufferLength, info->Name.Buffer, info->Name.Length);
655 entry->cb += entry->entryNameLength + sizeof(WCHAR);
656 }
657 else
658 {
659 entry->entryNameLength = 0;
660 entry->entryName[0] = 0;
661 entry->cb += sizeof(WCHAR);
662 }
663
664 if (otype < 0)
665 {
666 NtPidlTypeData * typedata = (NtPidlTypeData*) ((PBYTE) entry + entry->cb);
667 DWORD remainingSpace = entryBufferLength - ((PBYTE) (typedata->typeName) - (PBYTE) entry);
668
669 if (info->TypeName.Buffer)
670 {
671 typedata->typeNameLength = info->TypeName.Length;
672 StringCbCopyNW(typedata->typeName, remainingSpace, info->TypeName.Buffer, info->TypeName.Length);
673
674 entry->cb += typedata->typeNameLength + sizeof(WCHAR);
675 }
676 else
677 {
678 typedata->typeNameLength = 0;
679 typedata->typeName[0] = 0;
680 entry->cb += typedata->typeNameLength + sizeof(WCHAR);
681 }
682 }
683
684 *ppidl = (LPITEMIDLIST) entry;
685
686 return S_OK;
687 }
688
689 virtual HRESULT STDMETHODCALLTYPE Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched)
690 {
691 if (pceltFetched)
692 *pceltFetched = 0;
693
694 while (celt-- > 0)
695 {
696 HRESULT hr = EnumerateNext(rgelt);
697 if (hr != S_OK)
698 return hr;
699
700 if (pceltFetched)
701 (*pceltFetched)++;
702 if (rgelt)
703 rgelt++;
704 }
705
706 return S_OK;
707 }
708
709 virtual HRESULT STDMETHODCALLTYPE Skip(ULONG celt)
710 {
711 while (celt > 0)
712 {
713 HRESULT hr = EnumerateNext(NULL);
714 if (FAILED(hr))
715 return hr;
716 if (hr != S_OK)
717 break;
718 }
719
720 return S_OK;
721 }
722
723 virtual HRESULT STDMETHODCALLTYPE Reset()
724 {
725 return E_NOTIMPL;
726 }
727
728 virtual HRESULT STDMETHODCALLTYPE Clone(IEnumIDList **ppenum)
729 {
730 return E_NOTIMPL;
731 }
732
733 DECLARE_NOT_AGGREGATABLE(CEnumNTDirectory)
734 DECLARE_PROTECT_FINAL_CONSTRUCT()
735
736 BEGIN_COM_MAP(CEnumNTDirectory)
737 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
738 END_COM_MAP()
739 };
740
741 HRESULT GetEnumRegistryRoot(IEnumIDList ** ppil)
742 {
743 return ShellObjectCreator<CEnumRegRoot>(IID_PPV_ARG(IEnumIDList, ppil));
744 }
745
746 HRESULT GetEnumRegistryKey(LPCWSTR path, HKEY root, IEnumIDList ** ppil)
747 {
748 return ShellObjectCreatorInit<CEnumRegKey>(path, root, IID_PPV_ARG(IEnumIDList, ppil));
749 }
750
751 HRESULT GetEnumNTDirectory(LPCWSTR path, IEnumIDList ** ppil)
752 {
753 return ShellObjectCreatorInit<CEnumNTDirectory>(path, IID_PPV_ARG(IEnumIDList, ppil));
754 }