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
22 static struct RootKeyEntry
{
26 { HKEY_CLASSES_ROOT
, L
"HKEY_CLASSES_ROOT" },
27 { HKEY_CURRENT_USER
, L
"HKEY_CURRENT_USER" },
28 { HKEY_LOCAL_MACHINE
, L
"HKEY_LOCAL_MACHINE" },
29 { HKEY_USERS
, L
"HKEY_USERS" },
30 { HKEY_CURRENT_CONFIG
, L
"HKEY_CURRENT_CONFIG" }
33 typedef NTSTATUS(__stdcall
* pfnNtGenericOpen
)(PHANDLE
, ACCESS_MASK
, POBJECT_ATTRIBUTES
);
34 typedef NTSTATUS(__stdcall
* pfnNtOpenFile
)(PHANDLE
, ACCESS_MASK
, POBJECT_ATTRIBUTES
, PIO_STATUS_BLOCK
, ULONG
, ULONG
);
36 const LPCWSTR ObjectTypeNames
[] = {
37 L
"Directory", L
"SymbolicLink",
38 L
"Mutant", L
"Section", L
"Event", L
"Semaphore",
39 L
"Timer", L
"Key", L
"EventPair", L
"IoCompletion",
40 L
"Device", L
"File", L
"Controller", L
"Profile",
41 L
"Type", L
"Desktop", L
"WindowStation", L
"Driver",
42 L
"Token", L
"Process", L
"Thread", L
"Adapter", L
"Port",
46 const LPCWSTR RegistryTypeNames
[] = {
52 L
"REG_DWORD_BIG_ENDIAN",
56 L
"REG_FULL_RESOURCE_DESCRIPTOR",
57 L
"REG_RESOURCE_REQUIREMENTS_LIST ",
61 static DWORD
NtOpenObject(OBJECT_TYPE type
, PHANDLE phandle
, DWORD access
, LPCWSTR path
)
65 RtlInitUnicodeString(&ustr
, path
);
67 OBJECT_ATTRIBUTES open_struct
= { sizeof(OBJECT_ATTRIBUTES
), 0x00, &ustr
, 0x40 };
69 if (type
!= FILE_OBJECT
)
70 access
|= STANDARD_RIGHTS_READ
;
72 IO_STATUS_BLOCK ioStatusBlock
;
76 case DIRECTORY_OBJECT
: return NtOpenDirectoryObject(phandle
, access
, &open_struct
);
77 case SYMBOLICLINK_OBJECT
: return NtOpenSymbolicLinkObject(phandle
, access
, &open_struct
);
78 case MUTANT_OBJECT
: return NtOpenMutant(phandle
, access
, &open_struct
);
79 case SECTION_OBJECT
: return NtOpenSection(phandle
, access
, &open_struct
);
80 case EVENT_OBJECT
: return NtOpenEvent(phandle
, access
, &open_struct
);
81 case SEMAPHORE_OBJECT
: return NtOpenSemaphore(phandle
, access
, &open_struct
);
82 case TIMER_OBJECT
: return NtOpenTimer(phandle
, access
, &open_struct
);
83 case KEY_OBJECT
: return NtOpenKey(phandle
, access
, &open_struct
);
84 case EVENTPAIR_OBJECT
: return NtOpenEventPair(phandle
, access
, &open_struct
);
85 case IOCOMPLETION_OBJECT
: return NtOpenIoCompletion(phandle
, access
, &open_struct
);
86 case FILE_OBJECT
: return NtOpenFile(phandle
, access
, &open_struct
, &ioStatusBlock
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, 0);
88 return ERROR_INVALID_FUNCTION
;
92 OBJECT_TYPE
MapTypeNameToType(LPCWSTR TypeName
, DWORD cbTypeName
)
95 return UNKNOWN_OBJECT_TYPE
;
97 for (UINT i
= 0; i
< _countof(ObjectTypeNames
); i
++)
99 LPCWSTR typeName
= ObjectTypeNames
[i
];
100 if (!StrCmpNW(typeName
, TypeName
, cbTypeName
/ sizeof(WCHAR
)))
102 return (OBJECT_TYPE
) i
;
106 return UNKNOWN_OBJECT_TYPE
;
109 HRESULT
ReadRegistryValue(HKEY root
, PCWSTR path
, PCWSTR valueName
, PVOID
* valueData
, PDWORD valueLength
)
116 res
= RegOpenKeyExW(root
, *path
== '\\' ? path
+ 1 : path
, 0, STANDARD_RIGHTS_READ
| KEY_QUERY_VALUE
, &hkey
);
120 res
= NtOpenObject(KEY_OBJECT
, (PHANDLE
) &hkey
, STANDARD_RIGHTS_READ
| KEY_QUERY_VALUE
, path
);
122 if (!NT_SUCCESS(res
))
124 ERR("RegOpenKeyExW failed for path %S with status=%x\n", path
, res
);
125 return HRESULT_FROM_NT(res
);
128 res
= RegQueryValueExW(hkey
, valueName
, NULL
, NULL
, NULL
, valueLength
);
129 if (!NT_SUCCESS(res
))
131 ERR("RegQueryValueExW failed for path %S with status=%x\n", path
, res
);
132 return HRESULT_FROM_NT(res
);
135 if (*valueLength
> 0)
137 PBYTE data
= (PBYTE
) CoTaskMemAlloc(*valueLength
);
140 res
= RegQueryValueExW(hkey
, valueName
, NULL
, NULL
, data
, valueLength
);
141 if (!NT_SUCCESS(res
))
148 ERR("RegOpenKeyExW failed for path %S with status=%x\n", path
, res
);
149 return HRESULT_FROM_NT(res
);
162 HRESULT
GetNTObjectSymbolicLinkTarget(LPCWSTR path
, LPCWSTR entryName
, PUNICODE_STRING LinkTarget
)
165 WCHAR buffer
[MAX_PATH
];
166 LPWSTR pend
= buffer
;
168 StringCbCopyExW(buffer
, sizeof(buffer
), path
, &pend
, NULL
, 0);
170 if (pend
[-1] != '\\')
176 StringCbCatW(buffer
, sizeof(buffer
), entryName
);
178 DbgPrint("GetNTObjectSymbolicLinkTarget %d\n", buffer
);
180 LinkTarget
->Length
= 0;
182 DWORD err
= NtOpenObject(SYMBOLICLINK_OBJECT
, &handle
, SYMBOLIC_LINK_QUERY
, buffer
);
183 if (!NT_SUCCESS(err
))
184 return HRESULT_FROM_NT(err
);
186 err
= NtQuerySymbolicLinkObject(handle
, LinkTarget
, NULL
);
187 if (!NT_SUCCESS(err
))
188 return HRESULT_FROM_NT(err
);
196 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
211 HRESULT
EnumerateNext(LPITEMIDLIST
* ppidl
)
213 if (m_idx
>= _countof(RootKeys
))
216 RootKeyEntry
& key
= RootKeys
[m_idx
++];
218 PCWSTR name
= key
.keyName
;
219 DWORD cchName
= wcslen(name
);
221 REG_ENTRY_TYPE otype
= REG_ENTRY_ROOT
;
223 DWORD entryBufferLength
= FIELD_OFFSET(RegPidlEntry
, entryName
) + sizeof(WCHAR
) + cchName
* sizeof(WCHAR
);
225 // allocate space for the terminator
226 entryBufferLength
+= FIELD_OFFSET(SHITEMID
, abID
);
228 RegPidlEntry
* entry
= (RegPidlEntry
*) CoTaskMemAlloc(entryBufferLength
);
230 return E_OUTOFMEMORY
;
232 memset(entry
, 0, entryBufferLength
);
234 entry
->cb
= FIELD_OFFSET(RegPidlEntry
, entryName
);
235 entry
->magic
= REGISTRY_PIDL_MAGIC
;
236 entry
->entryType
= otype
;
237 entry
->rootKey
= key
.key
;
241 entry
->entryNameLength
= cchName
* sizeof(WCHAR
);
242 StringCbCopyNW(entry
->entryName
, entryBufferLength
, name
, entry
->entryNameLength
);
243 entry
->cb
+= entry
->entryNameLength
+ sizeof(WCHAR
);
247 entry
->entryNameLength
= 0;
248 entry
->entryName
[0] = 0;
249 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
+= FIELD_OFFSET(SHITEMID
, abID
);
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
);
413 *ppidl
= (LPITEMIDLIST
) entry
;
417 HRESULT
NextValue(LPITEMIDLIST
* ppidl
)
419 WCHAR name
[MAX_PATH
];
420 DWORD cchName
= _countof(name
);
424 if (RegEnumValueW(m_hkey
, m_idx
++, name
, &cchName
, 0, &type
, NULL
, &dataSize
))
427 REG_ENTRY_TYPE otype
= REG_ENTRY_VALUE
;
429 DWORD entryBufferLength
= FIELD_OFFSET(RegPidlEntry
, entryName
) + sizeof(WCHAR
) + cchName
* sizeof(WCHAR
);
431 #define MAX_EMBEDDED_DATA 32
432 BOOL copyData
= dataSize
<= MAX_EMBEDDED_DATA
;
435 entryBufferLength
+= dataSize
+ sizeof(WCHAR
);
437 otype
= REG_ENTRY_VALUE_WITH_CONTENT
;
440 // allocate space for the terminator
441 entryBufferLength
+= FIELD_OFFSET(SHITEMID
, abID
);
443 RegPidlEntry
* entry
= (RegPidlEntry
*) CoTaskMemAlloc(entryBufferLength
);
445 return E_OUTOFMEMORY
;
447 memset(entry
, 0, entryBufferLength
);
449 entry
->cb
= FIELD_OFFSET(RegPidlEntry
, entryName
);
450 entry
->magic
= REGISTRY_PIDL_MAGIC
;
451 entry
->entryType
= otype
;
452 entry
->contentType
= type
;
456 entry
->entryNameLength
= cchName
* sizeof(WCHAR
);
457 StringCbCopyNW(entry
->entryName
, entryBufferLength
, name
, entry
->entryNameLength
);
458 entry
->cb
+= entry
->entryNameLength
+ sizeof(WCHAR
);
462 entry
->entryNameLength
= 0;
463 entry
->entryName
[0] = 0;
464 entry
->cb
+= sizeof(WCHAR
);
469 PBYTE contentData
= (PBYTE
) ((PBYTE
) entry
+ entry
->cb
);
471 entry
->contentsLength
= dataSize
;
473 // In case it's an unterminated string, RegGetValue will add the NULL termination
474 dataSize
+= sizeof(WCHAR
);
476 if (!RegQueryValueExW(m_hkey
, name
, NULL
, NULL
, contentData
, &dataSize
))
478 entry
->cb
+= entry
->contentsLength
+ sizeof(WCHAR
);
482 entry
->contentsLength
= 0;
483 entry
->cb
+= sizeof(WCHAR
);
489 *ppidl
= (LPITEMIDLIST
) entry
;
493 HRESULT
EnumerateNext(LPITEMIDLIST
* ppidl
)
497 HRESULT hr
= NextKey(ppidl
);
506 return NextValue(ppidl
);
509 virtual HRESULT STDMETHODCALLTYPE
Next(ULONG celt
, LPITEMIDLIST
*rgelt
, ULONG
*pceltFetched
)
516 HRESULT hr
= EnumerateNext(rgelt
);
529 virtual HRESULT STDMETHODCALLTYPE
Skip(ULONG celt
)
533 HRESULT hr
= EnumerateNext(NULL
);
543 virtual HRESULT STDMETHODCALLTYPE
Reset()
548 virtual HRESULT STDMETHODCALLTYPE
Clone(IEnumIDList
**ppenum
)
553 DECLARE_NOT_AGGREGATABLE(CEnumRegKey
)
554 DECLARE_PROTECT_FINAL_CONSTRUCT()
556 BEGIN_COM_MAP(CEnumRegKey
)
557 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList
, IEnumIDList
)
561 class CEnumNTDirectory
:
562 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
565 WCHAR buffer
[MAX_PATH
];
573 : m_directory(NULL
), m_first(TRUE
), m_enumContext(0), m_pend(NULL
)
579 NtClose(m_directory
);
582 HRESULT
Initialize(PCWSTR path
)
584 StringCbCopyExW(buffer
, sizeof(buffer
), path
, &m_pend
, NULL
, 0);
586 DWORD err
= NtOpenObject(DIRECTORY_OBJECT
, &m_directory
, FILE_LIST_DIRECTORY
, buffer
);
587 if (!NT_SUCCESS(err
))
589 ERR("NtOpenDirectoryObject failed for path %S with status=%x\n", buffer
, err
);
590 return HRESULT_FROM_NT(err
);
593 if (m_pend
[-1] != '\\')
599 HRESULT
EnumerateNext(LPITEMIDLIST
* ppidl
)
601 BYTE dirbuffer
[2048];
602 if (!NT_SUCCESS(NtQueryDirectoryObject(m_directory
, dirbuffer
, 2048, TRUE
, m_first
, &m_enumContext
, NULL
)))
607 // if ppidl is NULL, assume the caller was Skip(),
608 // so we don't care about the info
612 POBJECT_DIRECTORY_INFORMATION info
= (POBJECT_DIRECTORY_INFORMATION
) dirbuffer
;
614 if (info
->Name
.Buffer
)
616 StringCbCopyNW(m_pend
, sizeof(buffer
), info
->Name
.Buffer
, info
->Name
.Length
);
619 OBJECT_TYPE otype
= MapTypeNameToType(info
->TypeName
.Buffer
, info
->TypeName
.Length
);
621 DWORD entryBufferLength
= FIELD_OFFSET(NtPidlEntry
, entryName
) + sizeof(WCHAR
);
622 if (info
->Name
.Buffer
)
623 entryBufferLength
+= info
->Name
.Length
;
627 entryBufferLength
+= FIELD_OFFSET(NtPidlTypeData
, typeName
) + sizeof(WCHAR
);
629 if (info
->TypeName
.Buffer
)
631 entryBufferLength
+= info
->TypeName
.Length
;
635 // allocate space for the terminator
636 entryBufferLength
+= FIELD_OFFSET(SHITEMID
, abID
);
638 NtPidlEntry
* entry
= (NtPidlEntry
*) CoTaskMemAlloc(entryBufferLength
);
640 return E_OUTOFMEMORY
;
642 memset(entry
, 0, entryBufferLength
);
644 entry
->cb
= FIELD_OFFSET(NtPidlEntry
, entryName
);
645 entry
->magic
= NT_OBJECT_PIDL_MAGIC
;
646 entry
->objectType
= otype
;
648 if (info
->Name
.Buffer
)
650 entry
->entryNameLength
= info
->Name
.Length
;
651 StringCbCopyNW(entry
->entryName
, entryBufferLength
, info
->Name
.Buffer
, info
->Name
.Length
);
652 entry
->cb
+= entry
->entryNameLength
+ sizeof(WCHAR
);
656 entry
->entryNameLength
= 0;
657 entry
->entryName
[0] = 0;
658 entry
->cb
+= sizeof(WCHAR
);
663 NtPidlTypeData
* typedata
= (NtPidlTypeData
*) ((PBYTE
) entry
+ entry
->cb
);
664 DWORD remainingSpace
= entryBufferLength
- ((PBYTE
) (typedata
->typeName
) - (PBYTE
) entry
);
666 if (info
->TypeName
.Buffer
)
668 typedata
->typeNameLength
= info
->TypeName
.Length
;
669 StringCbCopyNW(typedata
->typeName
, remainingSpace
, info
->TypeName
.Buffer
, info
->TypeName
.Length
);
671 entry
->cb
+= typedata
->typeNameLength
+ sizeof(WCHAR
);
675 typedata
->typeNameLength
= 0;
676 typedata
->typeName
[0] = 0;
677 entry
->cb
+= typedata
->typeNameLength
+ sizeof(WCHAR
);
681 *ppidl
= (LPITEMIDLIST
) entry
;
686 virtual HRESULT STDMETHODCALLTYPE
Next(ULONG celt
, LPITEMIDLIST
*rgelt
, ULONG
*pceltFetched
)
693 HRESULT hr
= EnumerateNext(rgelt
);
706 virtual HRESULT STDMETHODCALLTYPE
Skip(ULONG celt
)
710 HRESULT hr
= EnumerateNext(NULL
);
720 virtual HRESULT STDMETHODCALLTYPE
Reset()
725 virtual HRESULT STDMETHODCALLTYPE
Clone(IEnumIDList
**ppenum
)
730 DECLARE_NOT_AGGREGATABLE(CEnumNTDirectory
)
731 DECLARE_PROTECT_FINAL_CONSTRUCT()
733 BEGIN_COM_MAP(CEnumNTDirectory
)
734 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList
, IEnumIDList
)
738 HRESULT
GetEnumRegistryRoot(IEnumIDList
** ppil
)
740 return ShellObjectCreator
<CEnumRegRoot
>(IID_PPV_ARG(IEnumIDList
, ppil
));
743 HRESULT
GetEnumRegistryKey(LPCWSTR path
, HKEY root
, IEnumIDList
** ppil
)
745 return ShellObjectCreatorInit
<CEnumRegKey
>(path
, root
, IID_PPV_ARG(IEnumIDList
, ppil
));
748 HRESULT
GetEnumNTDirectory(LPCWSTR path
, IEnumIDList
** ppil
)
750 return ShellObjectCreatorInit
<CEnumNTDirectory
>(path
, IID_PPV_ARG(IEnumIDList
, ppil
));