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 "ntobjutil.h"
24 WINE_DEFAULT_DEBUG_CHANNEL(ntobjshex
);
26 typedef NTSTATUS(__stdcall
* pfnNtGenericOpen
)(PHANDLE
, ACCESS_MASK
, POBJECT_ATTRIBUTES
);
27 typedef NTSTATUS(__stdcall
* pfnNtOpenFile
)(PHANDLE
, ACCESS_MASK
, POBJECT_ATTRIBUTES
, PIO_STATUS_BLOCK
, ULONG
, ULONG
);
29 const LPCWSTR ObjectTypeNames
[] = {
30 L
"Directory", L
"SymbolicLink",
31 L
"Mutant", L
"Section", L
"Event", L
"Semaphore",
32 L
"Timer", L
"Key", L
"EventPair", L
"IoCompletion",
33 L
"Device", L
"File", L
"Controller", L
"Profile",
34 L
"Type", L
"Desktop", L
"WindowStatiom", L
"Driver",
35 L
"Token", L
"Process", L
"Thread", L
"Adapter", L
"Port",
39 const LPCWSTR RegistryTypeNames
[] = {
45 L
"REG_DWORD_BIG_ENDIAN",
49 L
"REG_FULL_RESOURCE_DESCRIPTOR",
50 L
"REG_RESOURCE_REQUIREMENTS_LIST ",
54 static DWORD
NtOpenObject(OBJECT_TYPE type
, PHANDLE phandle
, DWORD access
, LPCWSTR path
)
58 RtlInitUnicodeString(&ustr
, path
);
60 OBJECT_ATTRIBUTES open_struct
= { sizeof(OBJECT_ATTRIBUTES
), 0x00, &ustr
, 0x40 };
62 if (type
!= FILE_OBJECT
)
63 access
|= STANDARD_RIGHTS_READ
;
65 IO_STATUS_BLOCK ioStatusBlock
;
69 case DIRECTORY_OBJECT
: return NtOpenDirectoryObject(phandle
, access
, &open_struct
);
70 case SYMBOLICLINK_OBJECT
: return NtOpenSymbolicLinkObject(phandle
, access
, &open_struct
);
71 case MUTANT_OBJECT
: return NtOpenMutant(phandle
, access
, &open_struct
);
72 case SECTION_OBJECT
: return NtOpenSection(phandle
, access
, &open_struct
);
73 case EVENT_OBJECT
: return NtOpenEvent(phandle
, access
, &open_struct
);
74 case SEMAPHORE_OBJECT
: return NtOpenSemaphore(phandle
, access
, &open_struct
);
75 case TIMER_OBJECT
: return NtOpenTimer(phandle
, access
, &open_struct
);
76 case KEY_OBJECT
: return NtOpenKey(phandle
, access
, &open_struct
);
77 case EVENTPAIR_OBJECT
: return NtOpenEventPair(phandle
, access
, &open_struct
);
78 case IOCOMPLETITION_OBJECT
: return NtOpenIoCompletion(phandle
, access
, &open_struct
);
79 case FILE_OBJECT
: return NtOpenFile(phandle
, access
, &open_struct
, &ioStatusBlock
, FILE_SHARE_READ
| FILE_SHARE_WRITE
| FILE_SHARE_DELETE
, 0);
81 return ERROR_INVALID_FUNCTION
;
85 OBJECT_TYPE
MapTypeNameToType(LPCWSTR TypeName
, DWORD cbTypeName
)
88 return UNKNOWN_OBJECT_TYPE
;
90 for (UINT i
= 0; i
< _countof(ObjectTypeNames
); i
++)
92 LPCWSTR typeName
= ObjectTypeNames
[i
];
93 if (!StrCmpNW(typeName
, TypeName
, cbTypeName
/ sizeof(WCHAR
)))
95 return (OBJECT_TYPE
) i
;
99 return UNKNOWN_OBJECT_TYPE
;
102 HRESULT
EnumerateNtDirectory(HDPA hdpa
, PCWSTR path
, UINT
* hdpaCount
)
104 WCHAR buffer
[MAX_PATH
];
109 StringCbCopyExW(buffer
, sizeof(buffer
), path
, &pend
, NULL
, 0);
111 ULONG enumContext
= 0;
112 HANDLE directory
= NULL
;
114 DWORD err
= NtOpenObject(DIRECTORY_OBJECT
, &directory
, FILE_LIST_DIRECTORY
, buffer
);
115 if (!NT_SUCCESS(err
))
117 ERR("NtOpenDirectoryObject failed for path %S with status=%x\n", buffer
, err
);
118 return HRESULT_FROM_NT(err
);
121 if (pend
[-1] != '\\')
125 BYTE dirbuffer
[2048];
128 while (NtQueryDirectoryObject(directory
, dirbuffer
, 2048, TRUE
, first
, &enumContext
, NULL
) == STATUS_SUCCESS
)
131 POBJECT_DIRECTORY_INFORMATION info
= (POBJECT_DIRECTORY_INFORMATION
) dirbuffer
;
132 //for (; info->Name.Buffer != NULL; info++)
134 if (info
->Name
.Buffer
)
136 StringCbCopyNW(pend
, sizeof(buffer
), info
->Name
.Buffer
, info
->Name
.Length
);
139 OBJECT_TYPE otype
= MapTypeNameToType(info
->TypeName
.Buffer
, info
->TypeName
.Length
);
140 OBJECT_BASIC_INFORMATION object
= { 0 };
142 WCHAR wbLink
[_MAX_PATH
] = { 0 };
144 RtlInitEmptyUnicodeString(&link
, wbLink
, sizeof(wbLink
));
146 DWORD entryBufferLength
= FIELD_OFFSET(NtPidlEntry
,entryName
) + sizeof(WCHAR
);
147 if (info
->Name
.Buffer
)
148 entryBufferLength
+= info
->Name
.Length
;
152 entryBufferLength
+= FIELD_OFFSET(NtPidlTypeData
,typeName
) + sizeof(WCHAR
);
154 if (info
->TypeName
.Buffer
)
156 entryBufferLength
+= info
->TypeName
.Length
;
160 if (otype
== SYMBOLICLINK_OBJECT
)
162 entryBufferLength
+= FIELD_OFFSET(NtPidlSymlinkData
,targetName
) + sizeof(WCHAR
);
165 DWORD access
= STANDARD_RIGHTS_READ
;
166 if ((otype
== DIRECTORY_OBJECT
) ||
167 (otype
== SYMBOLICLINK_OBJECT
))
168 access
|= FILE_LIST_DIRECTORY
;
171 if (!NtOpenObject(otype
, &handle
, access
, buffer
))
175 if (!NT_SUCCESS(NtQueryObject(handle
, ObjectBasicInformation
, &object
, sizeof(OBJECT_BASIC_INFORMATION
), &read
)))
177 ZeroMemory(&object
, sizeof(OBJECT_BASIC_INFORMATION
));
180 if (otype
== SYMBOLICLINK_OBJECT
)
182 if (NtQuerySymbolicLinkObject(handle
, &link
, NULL
) == STATUS_SUCCESS
)
184 entryBufferLength
+= link
.Length
;
195 NtPidlEntry
* entry
= (NtPidlEntry
*) CoTaskMemAlloc(entryBufferLength
);
197 return E_OUTOFMEMORY
;
199 memset(entry
, 0, entryBufferLength
);
201 entry
->cb
= FIELD_OFFSET(NtPidlEntry
,entryName
);
202 entry
->magic
= NT_OBJECT_PIDL_MAGIC
;
203 entry
->objectType
= otype
;
204 entry
->objectInformation
= object
;
205 memset(entry
->objectInformation
.Reserved
, 0, sizeof(entry
->objectInformation
.Reserved
));
207 if (info
->Name
.Buffer
)
209 entry
->entryNameLength
= info
->Name
.Length
;
210 StringCbCopyNW(entry
->entryName
, entryBufferLength
, info
->Name
.Buffer
, info
->Name
.Length
);
211 entry
->cb
+= entry
->entryNameLength
+ sizeof(WCHAR
);
215 entry
->entryNameLength
= 0;
216 entry
->entryName
[0] = 0;
217 entry
->cb
+= sizeof(WCHAR
);
222 NtPidlTypeData
* typedata
= (NtPidlTypeData
*) ((PBYTE
) entry
+ entry
->cb
);
223 DWORD remainingSpace
= entryBufferLength
- ((PBYTE
) (typedata
->typeName
) - (PBYTE
) entry
);
225 if (info
->TypeName
.Buffer
)
227 typedata
->typeNameLength
= info
->TypeName
.Length
;
228 StringCbCopyNW(typedata
->typeName
, remainingSpace
, info
->TypeName
.Buffer
, info
->TypeName
.Length
);
230 entry
->cb
+= typedata
->typeNameLength
+ sizeof(WCHAR
);
234 typedata
->typeNameLength
= 0;
235 typedata
->typeName
[0] = 0;
236 entry
->cb
+= typedata
->typeNameLength
+ sizeof(WCHAR
);
240 if (otype
== SYMBOLICLINK_OBJECT
)
242 NtPidlSymlinkData
* symlink
= (NtPidlSymlinkData
*) ((PBYTE
) entry
+ entry
->cb
);
243 DWORD remainingSpace
= entryBufferLength
- ((PBYTE
) (symlink
->targetName
) - (PBYTE
) entry
);
245 symlink
->targetNameLength
= link
.Length
;
246 StringCbCopyNW(symlink
->targetName
, remainingSpace
, link
.Buffer
, link
.Length
);
248 entry
->cb
+= symlink
->targetNameLength
+ sizeof(WCHAR
);
251 DPA_AppendPtr(hdpa
, entry
);
261 HRESULT
EnumerateRegistryKey(HDPA hdpa
, PCWSTR path
, HKEY root
, UINT
* hdpaCount
)
270 res
= RegOpenKeyExW(root
, *path
== '\\' ? path
+ 1 : path
, 0, STANDARD_RIGHTS_READ
| KEY_QUERY_VALUE
| KEY_ENUMERATE_SUB_KEYS
, &hkey
);
274 res
= NtOpenObject(KEY_OBJECT
, (PHANDLE
)&hkey
, STANDARD_RIGHTS_READ
| KEY_QUERY_VALUE
| KEY_ENUMERATE_SUB_KEYS
, path
);
276 if (!NT_SUCCESS(res
))
278 ERR("RegOpenKeyExW failed for path %S with status=%x\n", path
, res
);
279 return HRESULT_FROM_NT(res
);
282 for (int idx
= 0;; ++idx
)
284 WCHAR name
[MAX_PATH
];
285 DWORD cchName
= _countof(name
);
287 WCHAR className
[MAX_PATH
];
288 DWORD cchClass
= _countof(className
);
290 if (RegEnumKeyExW(hkey
, idx
, name
, &cchName
, 0, className
, &cchClass
, NULL
))
294 className
[cchClass
] = 0;
296 REG_ENTRY_TYPE otype
= REG_ENTRY_KEY
;
298 DWORD entryBufferLength
= FIELD_OFFSET(RegPidlEntry
,entryName
) + sizeof(WCHAR
) + cchName
* sizeof(WCHAR
);
302 entryBufferLength
+= sizeof(WCHAR
) + cchClass
* sizeof(WCHAR
);
305 RegPidlEntry
* entry
= (RegPidlEntry
*) CoTaskMemAlloc(entryBufferLength
);
307 return E_OUTOFMEMORY
;
309 memset(entry
, 0, entryBufferLength
);
311 entry
->cb
= FIELD_OFFSET(NtPidlEntry
,entryName
);
312 entry
->magic
= REGISTRY_PIDL_MAGIC
;
313 entry
->entryType
= otype
;
317 entry
->entryNameLength
= cchName
* sizeof(WCHAR
);
318 StringCbCopyNW(entry
->entryName
, entryBufferLength
, name
, entry
->entryNameLength
);
319 entry
->cb
+= entry
->entryNameLength
+ sizeof(WCHAR
);
323 entry
->entryNameLength
= 0;
324 entry
->entryName
[0] = 0;
325 entry
->cb
+= sizeof(WCHAR
);
330 PWSTR contentData
= (PWSTR
) ((PBYTE
) entry
+ entry
->cb
);
331 DWORD remainingSpace
= entryBufferLength
- entry
->cb
;
333 entry
->contentsLength
= cchClass
* sizeof(WCHAR
);
334 StringCbCopyNW(contentData
, remainingSpace
, className
, entry
->contentsLength
);
336 entry
->cb
+= entry
->contentsLength
+ sizeof(WCHAR
);
339 DPA_AppendPtr(hdpa
, entry
);
344 for (int idx
= 0;; ++idx
)
346 WCHAR name
[MAX_PATH
];
347 DWORD cchName
= _countof(name
);
351 if (RegEnumValueW(hkey
, idx
, name
, &cchName
, 0, &type
, NULL
, &dataSize
))
354 REG_ENTRY_TYPE otype
= REG_ENTRY_VALUE
;
356 DWORD entryBufferLength
= FIELD_OFFSET(RegPidlEntry
,entryName
) + sizeof(WCHAR
) + cchName
* sizeof(WCHAR
);
358 BOOL copyData
= dataSize
< 32;
361 entryBufferLength
+= dataSize
+ sizeof(WCHAR
);
363 otype
= REG_ENTRY_VALUE_WITH_CONTENT
;
366 RegPidlEntry
* entry
= (RegPidlEntry
*) CoTaskMemAlloc(entryBufferLength
);
368 return E_OUTOFMEMORY
;
370 memset(entry
, 0, entryBufferLength
);
372 entry
->cb
= FIELD_OFFSET(RegPidlEntry
, entryName
);
373 entry
->magic
= REGISTRY_PIDL_MAGIC
;
374 entry
->entryType
= otype
;
378 entry
->entryNameLength
= cchName
* sizeof(WCHAR
);
379 StringCbCopyNW(entry
->entryName
, entryBufferLength
, name
, entry
->entryNameLength
);
380 entry
->cb
+= entry
->entryNameLength
+ sizeof(WCHAR
);
384 entry
->entryNameLength
= 0;
385 entry
->entryName
[0] = 0;
386 entry
->cb
+= sizeof(WCHAR
);
391 PBYTE contentData
= (PBYTE
) ((PBYTE
) entry
+ entry
->cb
);
393 entry
->contentsLength
= dataSize
;
395 // In case it's an unterminated string, RegGetValue will add the NULL termination
396 dataSize
+= sizeof(WCHAR
);
398 if (!RegQueryValueExW(hkey
, name
, NULL
, NULL
, contentData
, &dataSize
))
400 entry
->cb
+= entry
->contentsLength
+ sizeof(WCHAR
);
404 entry
->contentsLength
= 0;
405 entry
->cb
+= sizeof(WCHAR
);
410 DPA_AppendPtr(hdpa
, entry
);