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
);
253 *ppidl
= (LPITEMIDLIST
) entry
;
257 virtual HRESULT STDMETHODCALLTYPE
Next(ULONG celt
, LPITEMIDLIST
*rgelt
, ULONG
*pceltFetched
)
264 HRESULT hr
= EnumerateNext(rgelt
);
277 virtual HRESULT STDMETHODCALLTYPE
Skip(ULONG celt
)
281 HRESULT hr
= EnumerateNext(NULL
);
291 virtual HRESULT STDMETHODCALLTYPE
Reset()
296 virtual HRESULT STDMETHODCALLTYPE
Clone(IEnumIDList
**ppenum
)
301 DECLARE_NOT_AGGREGATABLE(CEnumRegRoot
)
302 DECLARE_PROTECT_FINAL_CONSTRUCT()
304 BEGIN_COM_MAP(CEnumRegRoot
)
305 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList
, IEnumIDList
)
311 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
321 : m_path(NULL
), m_hkey(NULL
), m_values(FALSE
), m_idx(0)
330 HRESULT
Initialize(PCWSTR path
, HKEY root
)
337 res
= RegOpenKeyExW(root
, *path
== '\\' ? path
+ 1 : path
, 0, STANDARD_RIGHTS_READ
| KEY_QUERY_VALUE
| KEY_ENUMERATE_SUB_KEYS
, &m_hkey
);
341 res
= NtOpenObject(KEY_OBJECT
, (PHANDLE
) &m_hkey
, STANDARD_RIGHTS_READ
| KEY_QUERY_VALUE
| KEY_ENUMERATE_SUB_KEYS
, path
);
343 if (!NT_SUCCESS(res
))
345 ERR("RegOpenKeyExW failed for path %S with status=%x\n", path
, res
);
346 return HRESULT_FROM_NT(res
);
352 HRESULT
NextKey(LPITEMIDLIST
* ppidl
)
354 WCHAR name
[MAX_PATH
];
355 DWORD cchName
= _countof(name
);
357 WCHAR className
[MAX_PATH
];
358 DWORD cchClass
= _countof(className
);
360 if (RegEnumKeyExW(m_hkey
, m_idx
++, name
, &cchName
, 0, className
, &cchClass
, NULL
))
364 className
[cchClass
] = 0;
366 REG_ENTRY_TYPE otype
= REG_ENTRY_KEY
;
368 DWORD entryBufferLength
= FIELD_OFFSET(RegPidlEntry
, entryName
) + sizeof(WCHAR
) + cchName
* sizeof(WCHAR
);
372 entryBufferLength
+= sizeof(WCHAR
) + cchClass
* sizeof(WCHAR
);
375 // allocate space for the terminator
376 entryBufferLength
+= 2;
378 RegPidlEntry
* entry
= (RegPidlEntry
*) CoTaskMemAlloc(entryBufferLength
);
380 return E_OUTOFMEMORY
;
382 memset(entry
, 0, entryBufferLength
);
384 entry
->cb
= FIELD_OFFSET(RegPidlEntry
, entryName
);
385 entry
->magic
= REGISTRY_PIDL_MAGIC
;
386 entry
->entryType
= otype
;
390 entry
->entryNameLength
= cchName
* sizeof(WCHAR
);
391 StringCbCopyNW(entry
->entryName
, entryBufferLength
, name
, entry
->entryNameLength
);
392 entry
->cb
+= entry
->entryNameLength
+ sizeof(WCHAR
);
396 entry
->entryNameLength
= 0;
397 entry
->entryName
[0] = 0;
398 entry
->cb
+= sizeof(WCHAR
);
403 PWSTR contentData
= (PWSTR
) ((PBYTE
) entry
+ entry
->cb
);
404 DWORD remainingSpace
= entryBufferLength
- entry
->cb
;
406 entry
->contentsLength
= cchClass
* sizeof(WCHAR
);
407 StringCbCopyNW(contentData
, remainingSpace
, className
, entry
->contentsLength
);
409 entry
->cb
+= entry
->contentsLength
+ sizeof(WCHAR
);
412 *ppidl
= (LPITEMIDLIST
) entry
;
416 HRESULT
NextValue(LPITEMIDLIST
* ppidl
)
418 WCHAR name
[MAX_PATH
];
419 DWORD cchName
= _countof(name
);
423 if (RegEnumValueW(m_hkey
, m_idx
++, name
, &cchName
, 0, &type
, NULL
, &dataSize
))
426 REG_ENTRY_TYPE otype
= REG_ENTRY_VALUE
;
428 DWORD entryBufferLength
= FIELD_OFFSET(RegPidlEntry
, entryName
) + sizeof(WCHAR
) + cchName
* sizeof(WCHAR
);
430 BOOL copyData
= dataSize
< 32;
433 entryBufferLength
+= dataSize
+ sizeof(WCHAR
);
435 otype
= REG_ENTRY_VALUE_WITH_CONTENT
;
438 RegPidlEntry
* entry
= (RegPidlEntry
*) CoTaskMemAlloc(entryBufferLength
+ 2);
440 return E_OUTOFMEMORY
;
442 memset(entry
, 0, entryBufferLength
);
444 entry
->cb
= FIELD_OFFSET(RegPidlEntry
, entryName
);
445 entry
->magic
= REGISTRY_PIDL_MAGIC
;
446 entry
->entryType
= otype
;
447 entry
->contentType
= type
;
451 entry
->entryNameLength
= cchName
* sizeof(WCHAR
);
452 StringCbCopyNW(entry
->entryName
, entryBufferLength
, name
, entry
->entryNameLength
);
453 entry
->cb
+= entry
->entryNameLength
+ sizeof(WCHAR
);
457 entry
->entryNameLength
= 0;
458 entry
->entryName
[0] = 0;
459 entry
->cb
+= sizeof(WCHAR
);
464 PBYTE contentData
= (PBYTE
) ((PBYTE
) entry
+ entry
->cb
);
466 entry
->contentsLength
= dataSize
;
468 // In case it's an unterminated string, RegGetValue will add the NULL termination
469 dataSize
+= sizeof(WCHAR
);
471 if (!RegQueryValueExW(m_hkey
, name
, NULL
, NULL
, contentData
, &dataSize
))
473 entry
->cb
+= entry
->contentsLength
+ sizeof(WCHAR
);
477 entry
->contentsLength
= 0;
478 entry
->cb
+= sizeof(WCHAR
);
483 *ppidl
= (LPITEMIDLIST
) entry
;
487 HRESULT
EnumerateNext(LPITEMIDLIST
* ppidl
)
491 HRESULT hr
= NextKey(ppidl
);
500 return NextValue(ppidl
);
503 virtual HRESULT STDMETHODCALLTYPE
Next(ULONG celt
, LPITEMIDLIST
*rgelt
, ULONG
*pceltFetched
)
510 HRESULT hr
= EnumerateNext(rgelt
);
523 virtual HRESULT STDMETHODCALLTYPE
Skip(ULONG celt
)
527 HRESULT hr
= EnumerateNext(NULL
);
537 virtual HRESULT STDMETHODCALLTYPE
Reset()
542 virtual HRESULT STDMETHODCALLTYPE
Clone(IEnumIDList
**ppenum
)
547 DECLARE_NOT_AGGREGATABLE(CEnumRegKey
)
548 DECLARE_PROTECT_FINAL_CONSTRUCT()
550 BEGIN_COM_MAP(CEnumRegKey
)
551 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList
, IEnumIDList
)
555 class CEnumNTDirectory
:
556 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
559 WCHAR buffer
[MAX_PATH
];
567 : m_directory(NULL
), m_first(TRUE
), m_enumContext(0), m_pend(NULL
)
573 NtClose(m_directory
);
576 HRESULT
Initialize(PCWSTR path
)
578 StringCbCopyExW(buffer
, sizeof(buffer
), path
, &m_pend
, NULL
, 0);
580 DWORD err
= NtOpenObject(DIRECTORY_OBJECT
, &m_directory
, FILE_LIST_DIRECTORY
, buffer
);
581 if (!NT_SUCCESS(err
))
583 ERR("NtOpenDirectoryObject failed for path %S with status=%x\n", buffer
, err
);
584 return HRESULT_FROM_NT(err
);
587 if (m_pend
[-1] != '\\')
593 HRESULT
EnumerateNext(LPITEMIDLIST
* ppidl
)
595 BYTE dirbuffer
[2048];
596 if (!NT_SUCCESS(NtQueryDirectoryObject(m_directory
, dirbuffer
, 2048, TRUE
, m_first
, &m_enumContext
, NULL
)))
599 // if ppidl is NULL, assume the caller was Skip(),
600 // so we don't care about the info
605 POBJECT_DIRECTORY_INFORMATION info
= (POBJECT_DIRECTORY_INFORMATION
) dirbuffer
;
607 if (info
->Name
.Buffer
)
609 StringCbCopyNW(m_pend
, sizeof(buffer
), info
->Name
.Buffer
, info
->Name
.Length
);
612 OBJECT_TYPE otype
= MapTypeNameToType(info
->TypeName
.Buffer
, info
->TypeName
.Length
);
614 DWORD entryBufferLength
= FIELD_OFFSET(NtPidlEntry
, entryName
) + sizeof(WCHAR
);
615 if (info
->Name
.Buffer
)
616 entryBufferLength
+= info
->Name
.Length
;
620 entryBufferLength
+= FIELD_OFFSET(NtPidlTypeData
, typeName
) + sizeof(WCHAR
);
622 if (info
->TypeName
.Buffer
)
624 entryBufferLength
+= info
->TypeName
.Length
;
628 // allocate space for the terminator
629 entryBufferLength
+= 2;
631 NtPidlEntry
* entry
= (NtPidlEntry
*) CoTaskMemAlloc(entryBufferLength
);
633 return E_OUTOFMEMORY
;
635 memset(entry
, 0, entryBufferLength
);
637 entry
->cb
= FIELD_OFFSET(NtPidlEntry
, entryName
);
638 entry
->magic
= NT_OBJECT_PIDL_MAGIC
;
639 entry
->objectType
= otype
;
641 if (info
->Name
.Buffer
)
643 entry
->entryNameLength
= info
->Name
.Length
;
644 StringCbCopyNW(entry
->entryName
, entryBufferLength
, info
->Name
.Buffer
, info
->Name
.Length
);
645 entry
->cb
+= entry
->entryNameLength
+ sizeof(WCHAR
);
649 entry
->entryNameLength
= 0;
650 entry
->entryName
[0] = 0;
651 entry
->cb
+= sizeof(WCHAR
);
656 NtPidlTypeData
* typedata
= (NtPidlTypeData
*) ((PBYTE
) entry
+ entry
->cb
);
657 DWORD remainingSpace
= entryBufferLength
- ((PBYTE
) (typedata
->typeName
) - (PBYTE
) entry
);
659 if (info
->TypeName
.Buffer
)
661 typedata
->typeNameLength
= info
->TypeName
.Length
;
662 StringCbCopyNW(typedata
->typeName
, remainingSpace
, info
->TypeName
.Buffer
, info
->TypeName
.Length
);
664 entry
->cb
+= typedata
->typeNameLength
+ sizeof(WCHAR
);
668 typedata
->typeNameLength
= 0;
669 typedata
->typeName
[0] = 0;
670 entry
->cb
+= typedata
->typeNameLength
+ sizeof(WCHAR
);
674 *ppidl
= (LPITEMIDLIST
) entry
;
679 virtual HRESULT STDMETHODCALLTYPE
Next(ULONG celt
, LPITEMIDLIST
*rgelt
, ULONG
*pceltFetched
)
686 HRESULT hr
= EnumerateNext(rgelt
);
699 virtual HRESULT STDMETHODCALLTYPE
Skip(ULONG celt
)
703 HRESULT hr
= EnumerateNext(NULL
);
713 virtual HRESULT STDMETHODCALLTYPE
Reset()
718 virtual HRESULT STDMETHODCALLTYPE
Clone(IEnumIDList
**ppenum
)
723 DECLARE_NOT_AGGREGATABLE(CEnumNTDirectory
)
724 DECLARE_PROTECT_FINAL_CONSTRUCT()
726 BEGIN_COM_MAP(CEnumNTDirectory
)
727 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList
, IEnumIDList
)
731 HRESULT
GetEnumRegistryRoot(IEnumIDList
** ppil
)
733 return ShellObjectCreator
<CEnumRegRoot
>(IID_PPV_ARG(IEnumIDList
, ppil
));
736 HRESULT
GetEnumRegistryKey(LPCWSTR path
, HKEY root
, IEnumIDList
** ppil
)
738 return ShellObjectCreatorInit
<CEnumRegKey
>(path
, root
, IID_PPV_ARG(IEnumIDList
, ppil
));
741 HRESULT
GetEnumNTDirectory(LPCWSTR path
, IEnumIDList
** ppil
)
743 return ShellObjectCreatorInit
<CEnumNTDirectory
>(path
, IID_PPV_ARG(IEnumIDList
, ppil
));