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