[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"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 *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 // allocate space for the terminator
441 entryBufferLength += 2;
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 += 2;
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 }