2 * Copyright 2004, 2005 Martin Fuchs
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.
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.
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
21 #include "ntobjenum.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(ntobjshex
);
26 static struct RootKeyEntry
{
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" }
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
);
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",
50 const LPCWSTR RegistryTypeNames
[] = {
56 L
"REG_DWORD_BIG_ENDIAN",
60 L
"REG_FULL_RESOURCE_DESCRIPTOR",
61 L
"REG_RESOURCE_REQUIREMENTS_LIST ",
65 static DWORD
NtOpenObject(OBJECT_TYPE type
, PHANDLE phandle
, DWORD access
, LPCWSTR path
)
69 RtlInitUnicodeString(&ustr
, path
);
71 OBJECT_ATTRIBUTES open_struct
= { sizeof(OBJECT_ATTRIBUTES
), 0x00, &ustr
, 0x40 };
73 if (type
!= FILE_OBJECT
)
74 access
|= STANDARD_RIGHTS_READ
;
76 IO_STATUS_BLOCK ioStatusBlock
;
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);
92 return ERROR_INVALID_FUNCTION
;
96 OBJECT_TYPE
MapTypeNameToType(LPCWSTR TypeName
, DWORD cbTypeName
)
99 return UNKNOWN_OBJECT_TYPE
;
101 for (UINT i
= 0; i
< _countof(ObjectTypeNames
); i
++)
103 LPCWSTR typeName
= ObjectTypeNames
[i
];
104 if (!StrCmpNW(typeName
, TypeName
, cbTypeName
/ sizeof(WCHAR
)))
106 return (OBJECT_TYPE
) i
;
110 return UNKNOWN_OBJECT_TYPE
;
113 HRESULT
ReadRegistryValue(HKEY root
, PCWSTR path
, PCWSTR valueName
, PVOID
* valueData
, PDWORD valueLength
)
120 res
= RegOpenKeyExW(root
, *path
== '\\' ? path
+ 1 : path
, 0, STANDARD_RIGHTS_READ
| KEY_QUERY_VALUE
, &hkey
);
124 res
= NtOpenObject(KEY_OBJECT
, (PHANDLE
) &hkey
, STANDARD_RIGHTS_READ
| KEY_QUERY_VALUE
, path
);
126 if (!NT_SUCCESS(res
))
128 ERR("RegOpenKeyExW failed for path %S with status=%x\n", path
, res
);
129 return HRESULT_FROM_NT(res
);
132 res
= RegQueryValueExW(hkey
, valueName
, NULL
, NULL
, NULL
, valueLength
);
133 if (!NT_SUCCESS(res
))
135 ERR("RegQueryValueExW failed for path %S with status=%x\n", path
, res
);
136 return HRESULT_FROM_NT(res
);
139 if (*valueLength
> 0)
141 PBYTE data
= (PBYTE
) CoTaskMemAlloc(*valueLength
);;
144 res
= RegQueryValueExW(hkey
, valueName
, NULL
, NULL
, data
, valueLength
);
145 if (!NT_SUCCESS(res
))
152 ERR("RegOpenKeyExW failed for path %S with status=%x\n", path
, res
);
153 return HRESULT_FROM_NT(res
);
166 HRESULT
GetNTObjectSymbolicLinkTarget(LPCWSTR path
, LPCWSTR entryName
, PUNICODE_STRING LinkTarget
)
169 WCHAR buffer
[MAX_PATH
];
170 LPWSTR pend
= buffer
;
172 StringCbCopyExW(buffer
, sizeof(buffer
), path
, &pend
, NULL
, 0);
174 if (pend
[-1] != '\\')
177 StringCbCatW(buffer
, sizeof(buffer
), entryName
);
179 DbgPrint("GetNTObjectSymbolicLinkTarget %d\n", buffer
);
181 LinkTarget
->Length
= 0;
183 DWORD err
= NtOpenObject(SYMBOLICLINK_OBJECT
, &handle
, 0, buffer
);
184 if (!NT_SUCCESS(err
))
185 return HRESULT_FROM_NT(err
);
187 err
= NT_SUCCESS(NtQuerySymbolicLinkObject(handle
, LinkTarget
, NULL
));
188 if (!NT_SUCCESS(err
))
189 return HRESULT_FROM_NT(err
);
197 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
212 HRESULT
EnumerateNext(LPITEMIDLIST
* ppidl
)
214 if (m_idx
>= _countof(RootKeys
))
217 RootKeyEntry
& key
= RootKeys
[m_idx
++];
219 PCWSTR name
= key
.keyName
;
220 DWORD cchName
= wcslen(name
);
222 REG_ENTRY_TYPE otype
= REG_ENTRY_ROOT
;
224 DWORD entryBufferLength
= FIELD_OFFSET(RegPidlEntry
, entryName
) + sizeof(WCHAR
) + cchName
* sizeof(WCHAR
);
226 // allocate space for the terminator
227 entryBufferLength
+= 2;
229 RegPidlEntry
* entry
= (RegPidlEntry
*) CoTaskMemAlloc(entryBufferLength
);
231 return E_OUTOFMEMORY
;
233 memset(entry
, 0, entryBufferLength
);
235 entry
->cb
= FIELD_OFFSET(RegPidlEntry
, entryName
);
236 entry
->magic
= REGISTRY_PIDL_MAGIC
;
237 entry
->entryType
= otype
;
238 entry
->rootKey
= key
.key
;
242 entry
->entryNameLength
= cchName
* sizeof(WCHAR
);
243 StringCbCopyNW(entry
->entryName
, entryBufferLength
, name
, entry
->entryNameLength
);
244 entry
->cb
+= entry
->entryNameLength
+ sizeof(WCHAR
);
248 entry
->entryNameLength
= 0;
249 entry
->entryName
[0] = 0;
250 entry
->cb
+= sizeof(WCHAR
);
254 *ppidl
= (LPITEMIDLIST
) entry
;
258 virtual HRESULT STDMETHODCALLTYPE
Next(ULONG celt
, LPITEMIDLIST
*rgelt
, ULONG
*pceltFetched
)
265 HRESULT hr
= EnumerateNext(rgelt
);
278 virtual HRESULT STDMETHODCALLTYPE
Skip(ULONG celt
)
282 HRESULT hr
= EnumerateNext(NULL
);
292 virtual HRESULT STDMETHODCALLTYPE
Reset()
297 virtual HRESULT STDMETHODCALLTYPE
Clone(IEnumIDList
**ppenum
)
302 DECLARE_NOT_AGGREGATABLE(CEnumRegRoot
)
303 DECLARE_PROTECT_FINAL_CONSTRUCT()
305 BEGIN_COM_MAP(CEnumRegRoot
)
306 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList
, IEnumIDList
)
312 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
322 : m_path(NULL
), m_hkey(NULL
), m_values(FALSE
), m_idx(0)
331 HRESULT
Initialize(PCWSTR path
, HKEY root
)
338 res
= RegOpenKeyExW(root
, *path
== '\\' ? path
+ 1 : path
, 0, STANDARD_RIGHTS_READ
| KEY_QUERY_VALUE
| KEY_ENUMERATE_SUB_KEYS
, &m_hkey
);
342 res
= NtOpenObject(KEY_OBJECT
, (PHANDLE
) &m_hkey
, STANDARD_RIGHTS_READ
| KEY_QUERY_VALUE
| KEY_ENUMERATE_SUB_KEYS
, path
);
344 if (!NT_SUCCESS(res
))
346 ERR("RegOpenKeyExW failed for path %S with status=%x\n", path
, res
);
347 return HRESULT_FROM_NT(res
);
353 HRESULT
NextKey(LPITEMIDLIST
* ppidl
)
355 WCHAR name
[MAX_PATH
];
356 DWORD cchName
= _countof(name
);
358 WCHAR className
[MAX_PATH
];
359 DWORD cchClass
= _countof(className
);
361 if (RegEnumKeyExW(m_hkey
, m_idx
++, name
, &cchName
, 0, className
, &cchClass
, NULL
))
365 className
[cchClass
] = 0;
367 REG_ENTRY_TYPE otype
= REG_ENTRY_KEY
;
369 DWORD entryBufferLength
= FIELD_OFFSET(RegPidlEntry
, entryName
) + sizeof(WCHAR
) + cchName
* sizeof(WCHAR
);
373 entryBufferLength
+= sizeof(WCHAR
) + cchClass
* sizeof(WCHAR
);
376 // allocate space for the terminator
377 entryBufferLength
+= 2;
379 RegPidlEntry
* entry
= (RegPidlEntry
*) CoTaskMemAlloc(entryBufferLength
);
381 return E_OUTOFMEMORY
;
383 memset(entry
, 0, entryBufferLength
);
385 entry
->cb
= FIELD_OFFSET(RegPidlEntry
, entryName
);
386 entry
->magic
= REGISTRY_PIDL_MAGIC
;
387 entry
->entryType
= otype
;
391 entry
->entryNameLength
= cchName
* sizeof(WCHAR
);
392 StringCbCopyNW(entry
->entryName
, entryBufferLength
, name
, entry
->entryNameLength
);
393 entry
->cb
+= entry
->entryNameLength
+ sizeof(WCHAR
);
397 entry
->entryNameLength
= 0;
398 entry
->entryName
[0] = 0;
399 entry
->cb
+= sizeof(WCHAR
);
404 PWSTR contentData
= (PWSTR
) ((PBYTE
) entry
+ entry
->cb
);
405 DWORD remainingSpace
= entryBufferLength
- entry
->cb
;
407 entry
->contentsLength
= cchClass
* sizeof(WCHAR
);
408 StringCbCopyNW(contentData
, remainingSpace
, className
, entry
->contentsLength
);
410 entry
->cb
+= entry
->contentsLength
+ sizeof(WCHAR
);
414 *ppidl
= (LPITEMIDLIST
) entry
;
418 HRESULT
NextValue(LPITEMIDLIST
* ppidl
)
420 WCHAR name
[MAX_PATH
];
421 DWORD cchName
= _countof(name
);
425 if (RegEnumValueW(m_hkey
, m_idx
++, name
, &cchName
, 0, &type
, NULL
, &dataSize
))
428 REG_ENTRY_TYPE otype
= REG_ENTRY_VALUE
;
430 DWORD entryBufferLength
= FIELD_OFFSET(RegPidlEntry
, entryName
) + sizeof(WCHAR
) + cchName
* sizeof(WCHAR
);
432 BOOL copyData
= dataSize
< 32;
435 entryBufferLength
+= dataSize
+ sizeof(WCHAR
);
437 otype
= REG_ENTRY_VALUE_WITH_CONTENT
;
440 RegPidlEntry
* entry
= (RegPidlEntry
*) CoTaskMemAlloc(entryBufferLength
+ 2);
442 return E_OUTOFMEMORY
;
444 memset(entry
, 0, entryBufferLength
);
446 entry
->cb
= FIELD_OFFSET(RegPidlEntry
, entryName
);
447 entry
->magic
= REGISTRY_PIDL_MAGIC
;
448 entry
->entryType
= otype
;
449 entry
->contentType
= type
;
453 entry
->entryNameLength
= cchName
* sizeof(WCHAR
);
454 StringCbCopyNW(entry
->entryName
, entryBufferLength
, name
, entry
->entryNameLength
);
455 entry
->cb
+= entry
->entryNameLength
+ sizeof(WCHAR
);
459 entry
->entryNameLength
= 0;
460 entry
->entryName
[0] = 0;
461 entry
->cb
+= sizeof(WCHAR
);
466 PBYTE contentData
= (PBYTE
) ((PBYTE
) entry
+ entry
->cb
);
468 entry
->contentsLength
= dataSize
;
470 // In case it's an unterminated string, RegGetValue will add the NULL termination
471 dataSize
+= sizeof(WCHAR
);
473 if (!RegQueryValueExW(m_hkey
, name
, NULL
, NULL
, contentData
, &dataSize
))
475 entry
->cb
+= entry
->contentsLength
+ sizeof(WCHAR
);
479 entry
->contentsLength
= 0;
480 entry
->cb
+= sizeof(WCHAR
);
486 *ppidl
= (LPITEMIDLIST
) entry
;
490 HRESULT
EnumerateNext(LPITEMIDLIST
* ppidl
)
494 HRESULT hr
= NextKey(ppidl
);
503 return NextValue(ppidl
);
506 virtual HRESULT STDMETHODCALLTYPE
Next(ULONG celt
, LPITEMIDLIST
*rgelt
, ULONG
*pceltFetched
)
513 HRESULT hr
= EnumerateNext(rgelt
);
526 virtual HRESULT STDMETHODCALLTYPE
Skip(ULONG celt
)
530 HRESULT hr
= EnumerateNext(NULL
);
540 virtual HRESULT STDMETHODCALLTYPE
Reset()
545 virtual HRESULT STDMETHODCALLTYPE
Clone(IEnumIDList
**ppenum
)
550 DECLARE_NOT_AGGREGATABLE(CEnumRegKey
)
551 DECLARE_PROTECT_FINAL_CONSTRUCT()
553 BEGIN_COM_MAP(CEnumRegKey
)
554 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList
, IEnumIDList
)
558 class CEnumNTDirectory
:
559 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
562 WCHAR buffer
[MAX_PATH
];
570 : m_directory(NULL
), m_first(TRUE
), m_enumContext(0), m_pend(NULL
)
576 NtClose(m_directory
);
579 HRESULT
Initialize(PCWSTR path
)
581 StringCbCopyExW(buffer
, sizeof(buffer
), path
, &m_pend
, NULL
, 0);
583 DWORD err
= NtOpenObject(DIRECTORY_OBJECT
, &m_directory
, FILE_LIST_DIRECTORY
, buffer
);
584 if (!NT_SUCCESS(err
))
586 ERR("NtOpenDirectoryObject failed for path %S with status=%x\n", buffer
, err
);
587 return HRESULT_FROM_NT(err
);
590 if (m_pend
[-1] != '\\')
596 HRESULT
EnumerateNext(LPITEMIDLIST
* ppidl
)
598 BYTE dirbuffer
[2048];
599 if (!NT_SUCCESS(NtQueryDirectoryObject(m_directory
, dirbuffer
, 2048, TRUE
, m_first
, &m_enumContext
, NULL
)))
604 // if ppidl is NULL, assume the caller was Skip(),
605 // so we don't care about the info
609 POBJECT_DIRECTORY_INFORMATION info
= (POBJECT_DIRECTORY_INFORMATION
) dirbuffer
;
611 if (info
->Name
.Buffer
)
613 StringCbCopyNW(m_pend
, sizeof(buffer
), info
->Name
.Buffer
, info
->Name
.Length
);
616 OBJECT_TYPE otype
= MapTypeNameToType(info
->TypeName
.Buffer
, info
->TypeName
.Length
);
618 DWORD entryBufferLength
= FIELD_OFFSET(NtPidlEntry
, entryName
) + sizeof(WCHAR
);
619 if (info
->Name
.Buffer
)
620 entryBufferLength
+= info
->Name
.Length
;
624 entryBufferLength
+= FIELD_OFFSET(NtPidlTypeData
, typeName
) + sizeof(WCHAR
);
626 if (info
->TypeName
.Buffer
)
628 entryBufferLength
+= info
->TypeName
.Length
;
632 // allocate space for the terminator
633 entryBufferLength
+= 2;
635 NtPidlEntry
* entry
= (NtPidlEntry
*) CoTaskMemAlloc(entryBufferLength
);
637 return E_OUTOFMEMORY
;
639 memset(entry
, 0, entryBufferLength
);
641 entry
->cb
= FIELD_OFFSET(NtPidlEntry
, entryName
);
642 entry
->magic
= NT_OBJECT_PIDL_MAGIC
;
643 entry
->objectType
= otype
;
645 if (info
->Name
.Buffer
)
647 entry
->entryNameLength
= info
->Name
.Length
;
648 StringCbCopyNW(entry
->entryName
, entryBufferLength
, info
->Name
.Buffer
, info
->Name
.Length
);
649 entry
->cb
+= entry
->entryNameLength
+ sizeof(WCHAR
);
653 entry
->entryNameLength
= 0;
654 entry
->entryName
[0] = 0;
655 entry
->cb
+= sizeof(WCHAR
);
660 NtPidlTypeData
* typedata
= (NtPidlTypeData
*) ((PBYTE
) entry
+ entry
->cb
);
661 DWORD remainingSpace
= entryBufferLength
- ((PBYTE
) (typedata
->typeName
) - (PBYTE
) entry
);
663 if (info
->TypeName
.Buffer
)
665 typedata
->typeNameLength
= info
->TypeName
.Length
;
666 StringCbCopyNW(typedata
->typeName
, remainingSpace
, info
->TypeName
.Buffer
, info
->TypeName
.Length
);
668 entry
->cb
+= typedata
->typeNameLength
+ sizeof(WCHAR
);
672 typedata
->typeNameLength
= 0;
673 typedata
->typeName
[0] = 0;
674 entry
->cb
+= typedata
->typeNameLength
+ sizeof(WCHAR
);
678 *ppidl
= (LPITEMIDLIST
) entry
;
683 virtual HRESULT STDMETHODCALLTYPE
Next(ULONG celt
, LPITEMIDLIST
*rgelt
, ULONG
*pceltFetched
)
690 HRESULT hr
= EnumerateNext(rgelt
);
703 virtual HRESULT STDMETHODCALLTYPE
Skip(ULONG celt
)
707 HRESULT hr
= EnumerateNext(NULL
);
717 virtual HRESULT STDMETHODCALLTYPE
Reset()
722 virtual HRESULT STDMETHODCALLTYPE
Clone(IEnumIDList
**ppenum
)
727 DECLARE_NOT_AGGREGATABLE(CEnumNTDirectory
)
728 DECLARE_PROTECT_FINAL_CONSTRUCT()
730 BEGIN_COM_MAP(CEnumNTDirectory
)
731 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList
, IEnumIDList
)
735 HRESULT
GetEnumRegistryRoot(IEnumIDList
** ppil
)
737 return ShellObjectCreator
<CEnumRegRoot
>(IID_PPV_ARG(IEnumIDList
, ppil
));
740 HRESULT
GetEnumRegistryKey(LPCWSTR path
, HKEY root
, IEnumIDList
** ppil
)
742 return ShellObjectCreatorInit
<CEnumRegKey
>(path
, root
, IID_PPV_ARG(IEnumIDList
, ppil
));
745 HRESULT
GetEnumNTDirectory(LPCWSTR path
, IEnumIDList
** ppil
)
747 return ShellObjectCreatorInit
<CEnumNTDirectory
>(path
, IID_PPV_ARG(IEnumIDList
, ppil
));