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
"WindowStation", 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 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);
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] != '\\')
180 StringCbCatW(buffer
, sizeof(buffer
), entryName
);
182 DbgPrint("GetNTObjectSymbolicLinkTarget %d\n", buffer
);
184 LinkTarget
->Length
= 0;
186 DWORD err
= NtOpenObject(SYMBOLICLINK_OBJECT
, &handle
, SYMBOLIC_LINK_QUERY
, buffer
);
187 if (!NT_SUCCESS(err
))
188 return HRESULT_FROM_NT(err
);
190 err
= NtQuerySymbolicLinkObject(handle
, LinkTarget
, NULL
);
191 if (!NT_SUCCESS(err
))
192 return HRESULT_FROM_NT(err
);
200 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
215 HRESULT
EnumerateNext(LPITEMIDLIST
* ppidl
)
217 if (m_idx
>= _countof(RootKeys
))
220 RootKeyEntry
& key
= RootKeys
[m_idx
++];
222 PCWSTR name
= key
.keyName
;
223 DWORD cchName
= wcslen(name
);
225 REG_ENTRY_TYPE otype
= REG_ENTRY_ROOT
;
227 DWORD entryBufferLength
= FIELD_OFFSET(RegPidlEntry
, entryName
) + sizeof(WCHAR
) + cchName
* sizeof(WCHAR
);
229 // allocate space for the terminator
230 entryBufferLength
+= 2;
232 RegPidlEntry
* entry
= (RegPidlEntry
*) CoTaskMemAlloc(entryBufferLength
);
234 return E_OUTOFMEMORY
;
236 memset(entry
, 0, entryBufferLength
);
238 entry
->cb
= FIELD_OFFSET(RegPidlEntry
, entryName
);
239 entry
->magic
= REGISTRY_PIDL_MAGIC
;
240 entry
->entryType
= otype
;
241 entry
->rootKey
= key
.key
;
245 entry
->entryNameLength
= cchName
* sizeof(WCHAR
);
246 StringCbCopyNW(entry
->entryName
, entryBufferLength
, name
, entry
->entryNameLength
);
247 entry
->cb
+= entry
->entryNameLength
+ sizeof(WCHAR
);
251 entry
->entryNameLength
= 0;
252 entry
->entryName
[0] = 0;
253 entry
->cb
+= sizeof(WCHAR
);
257 *ppidl
= (LPITEMIDLIST
) entry
;
261 virtual HRESULT STDMETHODCALLTYPE
Next(ULONG celt
, LPITEMIDLIST
*rgelt
, ULONG
*pceltFetched
)
268 HRESULT hr
= EnumerateNext(rgelt
);
281 virtual HRESULT STDMETHODCALLTYPE
Skip(ULONG celt
)
285 HRESULT hr
= EnumerateNext(NULL
);
295 virtual HRESULT STDMETHODCALLTYPE
Reset()
300 virtual HRESULT STDMETHODCALLTYPE
Clone(IEnumIDList
**ppenum
)
305 DECLARE_NOT_AGGREGATABLE(CEnumRegRoot
)
306 DECLARE_PROTECT_FINAL_CONSTRUCT()
308 BEGIN_COM_MAP(CEnumRegRoot
)
309 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList
, IEnumIDList
)
315 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
325 : m_path(NULL
), m_hkey(NULL
), m_values(FALSE
), m_idx(0)
334 HRESULT
Initialize(PCWSTR path
, HKEY root
)
341 res
= RegOpenKeyExW(root
, *path
== '\\' ? path
+ 1 : path
, 0, STANDARD_RIGHTS_READ
| KEY_QUERY_VALUE
| KEY_ENUMERATE_SUB_KEYS
, &m_hkey
);
345 res
= NtOpenObject(KEY_OBJECT
, (PHANDLE
) &m_hkey
, STANDARD_RIGHTS_READ
| KEY_QUERY_VALUE
| KEY_ENUMERATE_SUB_KEYS
, path
);
347 if (!NT_SUCCESS(res
))
349 ERR("RegOpenKeyExW failed for path %S with status=%x\n", path
, res
);
350 return HRESULT_FROM_NT(res
);
356 HRESULT
NextKey(LPITEMIDLIST
* ppidl
)
358 WCHAR name
[MAX_PATH
];
359 DWORD cchName
= _countof(name
);
361 WCHAR className
[MAX_PATH
];
362 DWORD cchClass
= _countof(className
);
364 if (RegEnumKeyExW(m_hkey
, m_idx
++, name
, &cchName
, 0, className
, &cchClass
, NULL
))
368 className
[cchClass
] = 0;
370 REG_ENTRY_TYPE otype
= REG_ENTRY_KEY
;
372 DWORD entryBufferLength
= FIELD_OFFSET(RegPidlEntry
, entryName
) + sizeof(WCHAR
) + cchName
* sizeof(WCHAR
);
376 entryBufferLength
+= sizeof(WCHAR
) + cchClass
* sizeof(WCHAR
);
379 // allocate space for the terminator
380 entryBufferLength
+= 2;
382 RegPidlEntry
* entry
= (RegPidlEntry
*) CoTaskMemAlloc(entryBufferLength
);
384 return E_OUTOFMEMORY
;
386 memset(entry
, 0, entryBufferLength
);
388 entry
->cb
= FIELD_OFFSET(RegPidlEntry
, entryName
);
389 entry
->magic
= REGISTRY_PIDL_MAGIC
;
390 entry
->entryType
= otype
;
394 entry
->entryNameLength
= cchName
* sizeof(WCHAR
);
395 StringCbCopyNW(entry
->entryName
, entryBufferLength
, name
, entry
->entryNameLength
);
396 entry
->cb
+= entry
->entryNameLength
+ sizeof(WCHAR
);
400 entry
->entryNameLength
= 0;
401 entry
->entryName
[0] = 0;
402 entry
->cb
+= sizeof(WCHAR
);
407 PWSTR contentData
= (PWSTR
) ((PBYTE
) entry
+ entry
->cb
);
408 DWORD remainingSpace
= entryBufferLength
- entry
->cb
;
410 entry
->contentsLength
= cchClass
* sizeof(WCHAR
);
411 StringCbCopyNW(contentData
, remainingSpace
, className
, entry
->contentsLength
);
413 entry
->cb
+= entry
->contentsLength
+ sizeof(WCHAR
);
417 *ppidl
= (LPITEMIDLIST
) entry
;
421 HRESULT
NextValue(LPITEMIDLIST
* ppidl
)
423 WCHAR name
[MAX_PATH
];
424 DWORD cchName
= _countof(name
);
428 if (RegEnumValueW(m_hkey
, m_idx
++, name
, &cchName
, 0, &type
, NULL
, &dataSize
))
431 REG_ENTRY_TYPE otype
= REG_ENTRY_VALUE
;
433 DWORD entryBufferLength
= FIELD_OFFSET(RegPidlEntry
, entryName
) + sizeof(WCHAR
) + cchName
* sizeof(WCHAR
);
435 BOOL copyData
= dataSize
< 256;
438 entryBufferLength
+= dataSize
+ sizeof(WCHAR
);
440 otype
= REG_ENTRY_VALUE_WITH_CONTENT
;
443 // allocate space for the terminator
444 entryBufferLength
+= 2;
446 RegPidlEntry
* entry
= (RegPidlEntry
*) CoTaskMemAlloc(entryBufferLength
);
448 return E_OUTOFMEMORY
;
450 memset(entry
, 0, entryBufferLength
);
452 entry
->cb
= FIELD_OFFSET(RegPidlEntry
, entryName
);
453 entry
->magic
= REGISTRY_PIDL_MAGIC
;
454 entry
->entryType
= otype
;
455 entry
->contentType
= type
;
459 entry
->entryNameLength
= cchName
* sizeof(WCHAR
);
460 StringCbCopyNW(entry
->entryName
, entryBufferLength
, name
, entry
->entryNameLength
);
461 entry
->cb
+= entry
->entryNameLength
+ sizeof(WCHAR
);
465 entry
->entryNameLength
= 0;
466 entry
->entryName
[0] = 0;
467 entry
->cb
+= sizeof(WCHAR
);
472 PBYTE contentData
= (PBYTE
) ((PBYTE
) entry
+ entry
->cb
);
474 entry
->contentsLength
= dataSize
;
476 // In case it's an unterminated string, RegGetValue will add the NULL termination
477 dataSize
+= sizeof(WCHAR
);
479 if (!RegQueryValueExW(m_hkey
, name
, NULL
, NULL
, contentData
, &dataSize
))
481 entry
->cb
+= entry
->contentsLength
+ sizeof(WCHAR
);
485 entry
->contentsLength
= 0;
486 entry
->cb
+= sizeof(WCHAR
);
492 *ppidl
= (LPITEMIDLIST
) entry
;
496 HRESULT
EnumerateNext(LPITEMIDLIST
* ppidl
)
500 HRESULT hr
= NextKey(ppidl
);
509 return NextValue(ppidl
);
512 virtual HRESULT STDMETHODCALLTYPE
Next(ULONG celt
, LPITEMIDLIST
*rgelt
, ULONG
*pceltFetched
)
519 HRESULT hr
= EnumerateNext(rgelt
);
532 virtual HRESULT STDMETHODCALLTYPE
Skip(ULONG celt
)
536 HRESULT hr
= EnumerateNext(NULL
);
546 virtual HRESULT STDMETHODCALLTYPE
Reset()
551 virtual HRESULT STDMETHODCALLTYPE
Clone(IEnumIDList
**ppenum
)
556 DECLARE_NOT_AGGREGATABLE(CEnumRegKey
)
557 DECLARE_PROTECT_FINAL_CONSTRUCT()
559 BEGIN_COM_MAP(CEnumRegKey
)
560 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList
, IEnumIDList
)
564 class CEnumNTDirectory
:
565 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
568 WCHAR buffer
[MAX_PATH
];
576 : m_directory(NULL
), m_first(TRUE
), m_enumContext(0), m_pend(NULL
)
582 NtClose(m_directory
);
585 HRESULT
Initialize(PCWSTR path
)
587 StringCbCopyExW(buffer
, sizeof(buffer
), path
, &m_pend
, NULL
, 0);
589 DWORD err
= NtOpenObject(DIRECTORY_OBJECT
, &m_directory
, FILE_LIST_DIRECTORY
, buffer
);
590 if (!NT_SUCCESS(err
))
592 ERR("NtOpenDirectoryObject failed for path %S with status=%x\n", buffer
, err
);
593 return HRESULT_FROM_NT(err
);
596 if (m_pend
[-1] != '\\')
602 HRESULT
EnumerateNext(LPITEMIDLIST
* ppidl
)
604 BYTE dirbuffer
[2048];
605 if (!NT_SUCCESS(NtQueryDirectoryObject(m_directory
, dirbuffer
, 2048, TRUE
, m_first
, &m_enumContext
, NULL
)))
610 // if ppidl is NULL, assume the caller was Skip(),
611 // so we don't care about the info
615 POBJECT_DIRECTORY_INFORMATION info
= (POBJECT_DIRECTORY_INFORMATION
) dirbuffer
;
617 if (info
->Name
.Buffer
)
619 StringCbCopyNW(m_pend
, sizeof(buffer
), info
->Name
.Buffer
, info
->Name
.Length
);
622 OBJECT_TYPE otype
= MapTypeNameToType(info
->TypeName
.Buffer
, info
->TypeName
.Length
);
624 DWORD entryBufferLength
= FIELD_OFFSET(NtPidlEntry
, entryName
) + sizeof(WCHAR
);
625 if (info
->Name
.Buffer
)
626 entryBufferLength
+= info
->Name
.Length
;
630 entryBufferLength
+= FIELD_OFFSET(NtPidlTypeData
, typeName
) + sizeof(WCHAR
);
632 if (info
->TypeName
.Buffer
)
634 entryBufferLength
+= info
->TypeName
.Length
;
638 // allocate space for the terminator
639 entryBufferLength
+= 2;
641 NtPidlEntry
* entry
= (NtPidlEntry
*) CoTaskMemAlloc(entryBufferLength
);
643 return E_OUTOFMEMORY
;
645 memset(entry
, 0, entryBufferLength
);
647 entry
->cb
= FIELD_OFFSET(NtPidlEntry
, entryName
);
648 entry
->magic
= NT_OBJECT_PIDL_MAGIC
;
649 entry
->objectType
= otype
;
651 if (info
->Name
.Buffer
)
653 entry
->entryNameLength
= info
->Name
.Length
;
654 StringCbCopyNW(entry
->entryName
, entryBufferLength
, info
->Name
.Buffer
, info
->Name
.Length
);
655 entry
->cb
+= entry
->entryNameLength
+ sizeof(WCHAR
);
659 entry
->entryNameLength
= 0;
660 entry
->entryName
[0] = 0;
661 entry
->cb
+= sizeof(WCHAR
);
666 NtPidlTypeData
* typedata
= (NtPidlTypeData
*) ((PBYTE
) entry
+ entry
->cb
);
667 DWORD remainingSpace
= entryBufferLength
- ((PBYTE
) (typedata
->typeName
) - (PBYTE
) entry
);
669 if (info
->TypeName
.Buffer
)
671 typedata
->typeNameLength
= info
->TypeName
.Length
;
672 StringCbCopyNW(typedata
->typeName
, remainingSpace
, info
->TypeName
.Buffer
, info
->TypeName
.Length
);
674 entry
->cb
+= typedata
->typeNameLength
+ sizeof(WCHAR
);
678 typedata
->typeNameLength
= 0;
679 typedata
->typeName
[0] = 0;
680 entry
->cb
+= typedata
->typeNameLength
+ sizeof(WCHAR
);
684 *ppidl
= (LPITEMIDLIST
) entry
;
689 virtual HRESULT STDMETHODCALLTYPE
Next(ULONG celt
, LPITEMIDLIST
*rgelt
, ULONG
*pceltFetched
)
696 HRESULT hr
= EnumerateNext(rgelt
);
709 virtual HRESULT STDMETHODCALLTYPE
Skip(ULONG celt
)
713 HRESULT hr
= EnumerateNext(NULL
);
723 virtual HRESULT STDMETHODCALLTYPE
Reset()
728 virtual HRESULT STDMETHODCALLTYPE
Clone(IEnumIDList
**ppenum
)
733 DECLARE_NOT_AGGREGATABLE(CEnumNTDirectory
)
734 DECLARE_PROTECT_FINAL_CONSTRUCT()
736 BEGIN_COM_MAP(CEnumNTDirectory
)
737 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList
, IEnumIDList
)
741 HRESULT
GetEnumRegistryRoot(IEnumIDList
** ppil
)
743 return ShellObjectCreator
<CEnumRegRoot
>(IID_PPV_ARG(IEnumIDList
, ppil
));
746 HRESULT
GetEnumRegistryKey(LPCWSTR path
, HKEY root
, IEnumIDList
** ppil
)
748 return ShellObjectCreatorInit
<CEnumRegKey
>(path
, root
, IID_PPV_ARG(IEnumIDList
, ppil
));
751 HRESULT
GetEnumNTDirectory(LPCWSTR path
, IEnumIDList
** ppil
)
753 return ShellObjectCreatorInit
<CEnumNTDirectory
>(path
, IID_PPV_ARG(IEnumIDList
, ppil
));