Author: dquintana Date: Mon Feb 23 17:13:32 2015 New Revision: 66426
URL: http://svn.reactos.org/svn/reactos?rev=66426&view=rev Log: [NTOBJSHEX] * Fix all the size calculations broken by r66425. * Fix subfolder navigation (in windows). * Fix enumeration skipping the last item. * Add the beginning of a registry folder implementation. It doesn't display all data types yet, and it doesn't support editing or searching. CORE-9244
Added: trunk/reactos/dll/shellext/ntobjshex/regfolder.cpp (with props) trunk/reactos/dll/shellext/ntobjshex/regfolder.h (with props) trunk/reactos/dll/shellext/ntobjshex/util.h (with props) Modified: trunk/reactos/dll/shellext/ntobjshex/CMakeLists.txt trunk/reactos/dll/shellext/ntobjshex/ntobjns.cpp trunk/reactos/dll/shellext/ntobjshex/ntobjutil.cpp trunk/reactos/dll/shellext/ntobjshex/ntobjutil.h trunk/reactos/dll/shellext/ntobjshex/precomp.h trunk/reactos/dll/shellext/ntobjshex/resource.h
Modified: trunk/reactos/dll/shellext/ntobjshex/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/shellext/ntobjshex/CMak... ============================================================================== --- trunk/reactos/dll/shellext/ntobjshex/CMakeLists.txt [iso-8859-1] (original) +++ trunk/reactos/dll/shellext/ntobjshex/CMakeLists.txt [iso-8859-1] Mon Feb 23 17:13:32 2015 @@ -19,6 +19,7 @@ ntobjshex.cpp ntobjutil.cpp ntobjshex.rc + regfolder.cpp ${CMAKE_CURRENT_BINARY_DIR}/ntobjshex.def)
list(APPEND atl_rc_deps
Modified: trunk/reactos/dll/shellext/ntobjshex/ntobjns.cpp URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/shellext/ntobjshex/ntob... ============================================================================== --- trunk/reactos/dll/shellext/ntobjshex/ntobjns.cpp [iso-8859-1] (original) +++ trunk/reactos/dll/shellext/ntobjshex/ntobjns.cpp [iso-8859-1] Mon Feb 23 17:13:32 2015 @@ -9,6 +9,7 @@ #include "precomp.h" #include "ntobjutil.h" #include <ntquery.h> +#include "util.h"
#define SHCIDS_ALLFIELDS 0x80000000L #define SHCIDS_CANONICALONLY 0x10000000L @@ -32,45 +33,6 @@ NTOBJECT_COLUMN_LINKTARGET = 3, };
-static HRESULT MakeStrRetFromString(LPCWSTR string, DWORD cbLength, STRRET * str) -{ - str->uType = STRRET_WSTR; - - DWORD blen = cbLength + sizeof(WCHAR); - str->pOleStr = (LPWSTR) CoTaskMemAlloc(blen); - return StringCbCopyNW(str->pOleStr, blen, string, cbLength); -} - -static HRESULT MakeStrRetFromString(LPCWSTR string, STRRET * str) -{ - DWORD stringLength = wcslen(string) * sizeof(WCHAR); - return MakeStrRetFromString(string, stringLength, str); -} - -static HRESULT MakeVariantString(VARIANT * pv, PCWSTR string) -{ - V_VT(pv) = VT_BSTR; - V_BSTR(pv) = SysAllocString(string); - return S_OK; -} - -static HRESULT GetFullName(PCIDLIST_ABSOLUTE pidl, DWORD uFlags, PWSTR strName, DWORD cchName) -{ - CComPtr<IShellFolder> psfDesktop; - STRRET str; - HRESULT hr; - - hr = SHGetDesktopFolder(&psfDesktop); - if (FAILED_UNEXPECTEDLY(hr)) - return hr; - - hr = psfDesktop->GetDisplayNameOf(pidl, uFlags, &str); - if (FAILED_UNEXPECTEDLY(hr)) - return hr; - - return StrRetToBufW(&str, pidl, strName, cchName); -} - class CNtObjectFolderContextMenu : public CComObjectRootEx<CComMultiThreadModelNoCS>, public IContextMenu @@ -113,7 +75,8 @@ const NtPidlEntry * entry = (NtPidlEntry *) m_pcidlChild;
if ((entry->objectType == DIRECTORY_OBJECT) || - (entry->objectType == SYMBOLICLINK_OBJECT)) + (entry->objectType == SYMBOLICLINK_OBJECT) || + (entry->objectType == KEY_OBJECT)) { MENUITEMINFOW mii;
@@ -373,6 +336,13 @@ return E_FAIL; }
+ NtPidlEntry * info = (NtPidlEntry *) pcidl; + if ((info->cb < sizeof(NtPidlEntry)) || (info->magic != NT_OBJECT_PIDL_MAGIC)) + { + ERR("FindPidlInList: Requested pidl is not of the correct type.\n"); + return E_INVALIDARG; + } + TRACE("Searching for pidl { cb=%d } in a list of %d items\n", pcidl->mkid.cb, m_hDpaCount);
for (UINT i = 0; i < m_hDpaCount; i++) @@ -395,7 +365,7 @@ } }
- TRACE("Pidl not found\n"); + ERR("PIDL NOT FOUND: Requested filename: %S\n", info->entryName); return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); }
@@ -537,6 +507,9 @@ if (entry->objectType == SYMBOLICLINK_OBJECT) flags |= SFGAO_LINK | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_BROWSABLE;
+ if (entry->objectType == KEY_OBJECT) + flags |= SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_BROWSABLE; + return flags & mask; }
@@ -605,6 +578,7 @@ { case SYMBOLICLINK_OBJECT: case DIRECTORY_OBJECT: + case KEY_OBJECT: flagsOk = (m_Flags & SHCONTF_FOLDERS) != 0; break; default: @@ -613,7 +587,7 @@ } } while (m_Index < m_Count && !flagsOk);
- if (m_Index < m_Count) + if (flagsOk) { if (rgelt) rgelt[i] = m_Folder->GetManager().CreatePidlFromItem(tinfo); @@ -660,12 +634,6 @@ //----------------------------------------------------------------------------- // CNtObjectFolder
-extern "C" -HRESULT WINAPI CMergedFolder_Constructor(REFIID riid, LPVOID *ppv) -{ - return ShellObjectCreator<CNtObjectFolder>(riid, ppv); -} - CNtObjectFolder::CNtObjectFolder() : m_PidlManager(NULL), m_shellPidl(NULL) @@ -674,6 +642,7 @@
CNtObjectFolder::~CNtObjectFolder() { + TRACE("Destroying CNtObjectFolder %p\n", this); }
// IShellFolder @@ -697,7 +666,7 @@ if (pdwAttributes) *pdwAttributes = 0;
- TRACE("ParseDisplayName name=%S\n", lpszDisplayName); + TRACE("CNtObjectFolder::ParseDisplayName name=%S (ntPath=%S)\n", lpszDisplayName, m_NtPath);
hr = m_PidlManager->FindByName(lpszDisplayName, &info); if (FAILED(hr)) @@ -743,36 +712,64 @@ return E_ACCESSDENIED;
WCHAR path[MAX_PATH]; + StringCbCopyW(path, _countof(path), m_NtPath); + PathAppendW(path, info->entryName); + + LPITEMIDLIST first = ILCloneFirst(pidl); + LPCITEMIDLIST rest = ILGetNext(pidl); + + LPITEMIDLIST fullPidl = ILCombine(m_shellPidl, first);
if (info->objectType == SYMBOLICLINK_OBJECT) { - NtPidlSymlinkData * symlink = (NtPidlSymlinkData*) (((PBYTE) info) + sizeof(NtPidlEntry) + info->entryNameLength + sizeof(WCHAR)); + NtPidlSymlinkData * symlink = (NtPidlSymlinkData*) (((PBYTE) info) + FIELD_OFFSET(NtPidlEntry,entryName) + info->entryNameLength + sizeof(WCHAR));
if (symlink->targetNameLength > 0) { - StringCbCopyW(path, _countof(path), symlink->targetName); + if (symlink->targetName[1] == L':' && isalphaW(symlink->targetName[0])) + { + ERR("TODO: Navigating to WIN32 PATH from NT PATH.\n"); + return E_NOTIMPL; + } + + StringCbCopyW(path, _countof(path), L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\::{845B0FB2-66E0-416B-8F91-314E23F7C12D}"); + PathAppend(path, symlink->targetName); + + CComPtr<IShellFolder> psfDesktop; + hr = SHGetDesktopFolder(&psfDesktop); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + hr = psfDesktop->ParseDisplayName(NULL, NULL, path, NULL, &first, NULL); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; } else { return E_UNEXPECTED; } } + + CComPtr<IShellFolder> psfChild; + + if (info->objectType == KEY_OBJECT) + { + hr = ShellObjectCreatorInit<CRegistryFolder>(fullPidl, path, IID_PPV_ARG(IShellFolder, &psfChild)); + } else { - StringCbCopyW(path, _countof(path), m_NtPath); - - PathAppendW(path, info->entryName); - - DbgPrint("BindToObject for Directory %S\n", path); - } - - LPITEMIDLIST fullPidl = ILCombine(m_shellPidl, pidl); - - hr = ShellObjectCreatorInit<CNtObjectFolder>(fullPidl, path, riid, ppvOut); + hr = ShellObjectCreatorInit<CNtObjectFolder>(fullPidl, path, IID_PPV_ARG(IShellFolder, &psfChild)); + }
ILFree(fullPidl); - - return hr; + ILFree(first); + + if (rest->mkid.cb > 0) + { + return psfChild->BindToObject(rest, pbcReserved, riid, ppvOut); + } + + return psfChild->QueryInterface(riid, ppvOut); }
return E_NOTIMPL; @@ -953,18 +950,70 @@ // IPersistFolder HRESULT STDMETHODCALLTYPE CNtObjectFolder::Initialize(LPCITEMIDLIST pidl) { - return Initialize(pidl, L"\"); + m_shellPidl = ILClone(pidl); + + PCWSTR ntPath = L"\"; + +#if 0 + WCHAR debugTemp[MAX_PATH]; + GetFullName(m_shellPidl, SHGDN_FORPARSING, debugTemp, _countof(debugTemp)); + DbgPrint("INITIALIZE CRegistryFolder PIDL PATH: %S (ntPath: %S)\n", debugTemp, ntPath); + + if (ntPath[wcslen(ntPath)-1] == L'\' && debugTemp[wcslen(debugTemp) - 1] != L'\') + wcscat(debugTemp, L"\"); + + PCWSTR guidTemp = L"::{845B0FB2-66E0-416B-8F91-314E23F7C12D}"; + + PCWSTR findTemp = StrStrW(debugTemp, guidTemp); + PCWSTR nextTemp = findTemp + wcslen(guidTemp); + + if (wcscmp(nextTemp, ntPath)) + { + DbgPrint("WHAT THE F, the NT PATH DOES NOT MATCH\n"); + return E_FAIL; + } +#endif + + if (!m_PidlManager) + { + m_PidlManager = new CNtObjectPidlManager(); + + StringCbCopy(m_NtPath, _countof(m_NtPath), ntPath); + } + + return m_PidlManager->Initialize(m_NtPath); }
// Internal HRESULT STDMETHODCALLTYPE CNtObjectFolder::Initialize(LPCITEMIDLIST pidl, PCWSTR ntPath) { + TRACE("INITIALIZE %p CNtObjectFolder with ntPath %S\n", this, ntPath); + +#if 0 m_shellPidl = ILClone(pidl); - StringCbCopy(m_NtPath, _countof(m_NtPath), ntPath); - + WCHAR debugTemp[MAX_PATH]; + GetFullName(m_shellPidl, SHGDN_FORPARSING, debugTemp, _countof(debugTemp)); + DbgPrint("INITIALIZE CNtObjectFolder PIDL PATH: %S (ntPath: %S)\n", debugTemp, ntPath); + + if (ntPath[wcslen(ntPath) - 1] == L'\' && debugTemp[wcslen(debugTemp) - 1] != L'\') + wcscat(debugTemp, L"\"); + + PCWSTR guidTemp = L"::{845B0FB2-66E0-416B-8F91-314E23F7C12D}"; + + PCWSTR findTemp = StrStrW(debugTemp, guidTemp); + PCWSTR nextTemp = findTemp + wcslen(guidTemp); + + if (wcscmp(nextTemp, ntPath)) + { + DbgPrint("WHAT THE F, the NT PATH DOES NOT MATCH\n"); + return E_FAIL; + } +#endif + if (!m_PidlManager) m_PidlManager = new CNtObjectPidlManager();
+ StringCbCopy(m_NtPath, _countof(m_NtPath), ntPath); return m_PidlManager->Initialize(m_NtPath); }
@@ -1055,7 +1104,7 @@ { if (info->objectType < 0) { - NtPidlTypeData * td = (NtPidlTypeData*) (((PBYTE) info) + sizeof(NtPidlEntry) + info->entryNameLength + sizeof(WCHAR)); + NtPidlTypeData * td = (NtPidlTypeData*) (((PBYTE) info) + FIELD_OFFSET(NtPidlEntry,entryName) + info->entryNameLength + sizeof(WCHAR));
if (td->typeNameLength > 0) { @@ -1089,7 +1138,7 @@ { if (info->objectType == SYMBOLICLINK_OBJECT) { - NtPidlSymlinkData * symlink = (NtPidlSymlinkData*) (((PBYTE) info) + sizeof(NtPidlEntry) + info->entryNameLength + sizeof(WCHAR)); + NtPidlSymlinkData * symlink = (NtPidlSymlinkData*) (((PBYTE) info) + FIELD_OFFSET(NtPidlEntry,entryName) + info->entryNameLength + sizeof(WCHAR));
if (symlink->targetNameLength > 0) { @@ -1134,7 +1183,7 @@
if (info->objectType < 0) { - NtPidlTypeData * td = (NtPidlTypeData*) (((PBYTE) info) + sizeof(NtPidlEntry) + info->entryNameLength + sizeof(WCHAR)); + NtPidlTypeData * td = (NtPidlTypeData*) (((PBYTE) info) + FIELD_OFFSET(NtPidlEntry,entryName) + info->entryNameLength + sizeof(WCHAR));
if (td->typeNameLength > 0) MakeStrRetFromString(td->typeName, td->typeNameLength, &(psd->str)); @@ -1170,7 +1219,7 @@
if (info->objectType == SYMBOLICLINK_OBJECT) { - NtPidlSymlinkData * symlink = (NtPidlSymlinkData*) (((PBYTE) info) + sizeof(NtPidlEntry) + info->entryNameLength + sizeof(WCHAR)); + NtPidlSymlinkData * symlink = (NtPidlSymlinkData*) (((PBYTE) info) + FIELD_OFFSET(NtPidlEntry,entryName) + info->entryNameLength + sizeof(WCHAR));
if (symlink->targetNameLength > 0) {
Modified: trunk/reactos/dll/shellext/ntobjshex/ntobjutil.cpp URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/shellext/ntobjshex/ntob... ============================================================================== --- trunk/reactos/dll/shellext/ntobjshex/ntobjutil.cpp [iso-8859-1] (original) +++ trunk/reactos/dll/shellext/ntobjshex/ntobjutil.cpp [iso-8859-1] Mon Feb 23 17:13:32 2015 @@ -36,7 +36,22 @@ 0 };
-static DWORD NtOpenObject(OBJECT_TYPE type, HANDLE* phandle, DWORD access, LPCWSTR path) +const LPCWSTR RegistryTypeNames[] = { + L"REG_NONE", + L"REG_SZ", + L"REG_EXPAND_SZ", + L"REG_BINARY", + L"REG_DWORD", + L"REG_DWORD_BIG_ENDIAN", + L"REG_LINK", + L"REG_MULTI_SZ", + L"REG_RESOURCE_LIST", + L"REG_FULL_RESOURCE_DESCRIPTOR", + L"REG_RESOURCE_REQUIREMENTS_LIST ", + L"REG_QWORD" +}; + +static DWORD NtOpenObject(OBJECT_TYPE type, PHANDLE phandle, DWORD access, LPCWSTR path) { UNICODE_STRING ustr;
@@ -128,7 +143,7 @@ UNICODE_STRING link; RtlInitEmptyUnicodeString(&link, wbLink, sizeof(wbLink));
- DWORD entryBufferLength = sizeof(NtPidlEntry) + sizeof(WCHAR); + DWORD entryBufferLength = FIELD_OFFSET(NtPidlEntry,entryName) + sizeof(WCHAR); if (info->Name.Buffer) entryBufferLength += info->Name.Length;
@@ -183,7 +198,7 @@
memset(entry, 0, entryBufferLength);
- entry->cb = sizeof(NtPidlEntry); + entry->cb = FIELD_OFFSET(NtPidlEntry,entryName); entry->magic = NT_OBJECT_PIDL_MAGIC; entry->objectType = otype; entry->objectInformation = object; @@ -242,3 +257,161 @@
return S_OK; } + +HRESULT EnumerateRegistryKey(HDPA hdpa, PCWSTR path, HKEY root, UINT * hdpaCount) +{ + *hdpaCount = 0; + + HKEY hkey; + + DWORD res; + if (root) + { + res = RegOpenKeyExW(root, *path == '\' ? path + 1 : path, 0, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hkey); + } + else + { + res = NtOpenObject(KEY_OBJECT, (PHANDLE)&hkey, STANDARD_RIGHTS_READ | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, path); + } + if (!NT_SUCCESS(res)) + { + ERR("RegOpenKeyExW failed for path %S with status=%x\n", path, res); + return HRESULT_FROM_NT(res); + } + + for (int idx = 0;; ++idx) + { + WCHAR name[MAX_PATH]; + DWORD cchName = _countof(name); + + WCHAR className[MAX_PATH]; + DWORD cchClass = _countof(className); + + if (RegEnumKeyExW(hkey, idx, name, &cchName, 0, className, &cchClass, NULL)) + break; + + name[cchName] = 0; + className[cchClass] = 0; + + REG_ENTRY_TYPE otype = REG_ENTRY_KEY; + + DWORD entryBufferLength = FIELD_OFFSET(RegPidlEntry,entryName) + sizeof(WCHAR) + cchName * sizeof(WCHAR); + + if (cchClass > 0) + { + entryBufferLength += sizeof(WCHAR) + cchClass * sizeof(WCHAR); + } + + RegPidlEntry* entry = (RegPidlEntry*) CoTaskMemAlloc(entryBufferLength); + if (!entry) + return E_OUTOFMEMORY; + + memset(entry, 0, entryBufferLength); + + entry->cb = FIELD_OFFSET(NtPidlEntry,entryName); + entry->magic = REGISTRY_PIDL_MAGIC; + entry->entryType = otype; + + if (cchName > 0) + { + entry->entryNameLength = cchName * sizeof(WCHAR); + StringCbCopyNW(entry->entryName, entryBufferLength, name, entry->entryNameLength); + entry->cb += entry->entryNameLength + sizeof(WCHAR); + } + else + { + entry->entryNameLength = 0; + entry->entryName[0] = 0; + entry->cb += sizeof(WCHAR); + } + + if (cchClass) + { + PWSTR contentData = (PWSTR) ((PBYTE) entry + entry->cb); + DWORD remainingSpace = entryBufferLength - entry->cb; + + entry->contentsLength = cchClass * sizeof(WCHAR); + StringCbCopyNW(contentData, remainingSpace, className, entry->contentsLength); + + entry->cb += entry->contentsLength + sizeof(WCHAR); + } + + DPA_AppendPtr(hdpa, entry); + (*hdpaCount)++; + + } + + for (int idx = 0;; ++idx) + { + WCHAR name[MAX_PATH]; + DWORD cchName = _countof(name); + DWORD type; + DWORD dataSize; + + if (RegEnumValueW(hkey, idx, name, &cchName, 0, &type, NULL, &dataSize)) + break; + + REG_ENTRY_TYPE otype = REG_ENTRY_VALUE; + + DWORD entryBufferLength = FIELD_OFFSET(RegPidlEntry,entryName) + sizeof(WCHAR) + cchName * sizeof(WCHAR); + + BOOL copyData = dataSize < 32; + if (copyData) + { + entryBufferLength += dataSize + sizeof(WCHAR); + + otype = REG_ENTRY_VALUE_WITH_CONTENT; + } + + RegPidlEntry* entry = (RegPidlEntry*) CoTaskMemAlloc(entryBufferLength); + if (!entry) + return E_OUTOFMEMORY; + + memset(entry, 0, entryBufferLength); + + entry->cb = FIELD_OFFSET(RegPidlEntry, entryName); + entry->magic = REGISTRY_PIDL_MAGIC; + entry->entryType = otype; + + if (cchName > 0) + { + entry->entryNameLength = cchName * sizeof(WCHAR); + StringCbCopyNW(entry->entryName, entryBufferLength, name, entry->entryNameLength); + entry->cb += entry->entryNameLength + sizeof(WCHAR); + } + else + { + entry->entryNameLength = 0; + entry->entryName[0] = 0; + entry->cb += sizeof(WCHAR); + } + + if (copyData) + { + PBYTE contentData = (PBYTE) ((PBYTE) entry + entry->cb); + + entry->contentsLength = dataSize; + + // In case it's an unterminated string, RegGetValue will add the NULL termination + dataSize += sizeof(WCHAR); + + if (!RegQueryValueExW(hkey, name, NULL, NULL, contentData, &dataSize)) + { + entry->cb += entry->contentsLength + sizeof(WCHAR); + } + else + { + entry->contentsLength = 0; + entry->cb += sizeof(WCHAR); + } + + } + + DPA_AppendPtr(hdpa, entry); + (*hdpaCount)++; + } + + RegCloseKey(hkey); + + return S_OK; +}
Modified: trunk/reactos/dll/shellext/ntobjshex/ntobjutil.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/shellext/ntobjshex/ntob... ============================================================================== --- trunk/reactos/dll/shellext/ntobjshex/ntobjutil.h [iso-8859-1] (original) +++ trunk/reactos/dll/shellext/ntobjshex/ntobjutil.h [iso-8859-1] Mon Feb 23 17:13:32 2015 @@ -37,8 +37,11 @@ extern const LPCWSTR ObjectTypeNames[];
#define NT_OBJECT_PIDL_MAGIC (USHORT)0x9A03 +#define REGISTRY_PIDL_MAGIC (USHORT)0x5364
#include <pshpack1.h> + +// NT OBJECT browsere struct NtPidlEntry { USHORT cb; @@ -65,6 +68,37 @@ USHORT targetNameLength; WCHAR targetName[ANYSIZE_ARRAY]; }; + +// REGISTRY browsere +enum REG_ENTRY_TYPE +{ + REG_ENTRY_KEY, + REG_ENTRY_VALUE, + REG_ENTRY_VALUE_WITH_CONTENT + // any more? +}; +extern const LPCWSTR RegistryTypeNames []; + +struct RegPidlEntry +{ + USHORT cb; + USHORT magic; // 0x5364 ~~~ "REGK" + + REG_ENTRY_TYPE entryType; + + USHORT entryNameLength; + + // For Value entries, this contains the value contents, if it's resonably small. + // For Key entries, this contains the custom class name + DWORD contentType; + USHORT contentsLength; + + WCHAR entryName[0]; + +}; + + #include <poppack.h>
-HRESULT EnumerateNtDirectory(HDPA hdpa, PCWSTR path, UINT * hdpaCount); +HRESULT EnumerateNtDirectory(HDPA hdpa, PCWSTR path, UINT * hdpaCount); +HRESULT EnumerateRegistryKey(HDPA hdpa, PCWSTR path, HKEY root, UINT * hdpaCount);
Modified: trunk/reactos/dll/shellext/ntobjshex/precomp.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/shellext/ntobjshex/prec... ============================================================================== --- trunk/reactos/dll/shellext/ntobjshex/precomp.h [iso-8859-1] (original) +++ trunk/reactos/dll/shellext/ntobjshex/precomp.h [iso-8859-1] Mon Feb 23 17:13:32 2015 @@ -47,3 +47,4 @@ 0x845b0fb2, 0x66e0, 0x416b, 0x8f, 0x91, 0x31, 0x4e, 0x23, 0xf7, 0xc1, 0x2d);
#include "ntobjns.h" +#include "regfolder.h"
Added: trunk/reactos/dll/shellext/ntobjshex/regfolder.cpp URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/shellext/ntobjshex/regf... ============================================================================== --- trunk/reactos/dll/shellext/ntobjshex/regfolder.cpp (added) +++ trunk/reactos/dll/shellext/ntobjshex/regfolder.cpp [iso-8859-1] Mon Feb 23 17:13:32 2015 @@ -0,0 +1,1248 @@ +/* +* PROJECT: ReactOS shell extensions +* LICENSE: GPL - See COPYING in the top level directory +* FILE: dll\shellext\ntobjshex\ntobjns.cpp +* PURPOSE: NT Object Namespace shell extension +* PROGRAMMERS: David Quintana gigaherz@gmail.com +*/ + +#include "precomp.h" +#include "ntobjutil.h" +#include <ntquery.h> +#include "util.h" + +#define SHCIDS_ALLFIELDS 0x80000000L +#define SHCIDS_CANONICALONLY 0x10000000L + +#define GET_SHGDN_FOR(dwFlags) ((DWORD)dwFlags & (DWORD)0x0000FF00) +#define GET_SHGDN_RELATION(dwFlags) ((DWORD)dwFlags & (DWORD)0x000000FF) + +WINE_DEFAULT_DEBUG_CHANNEL(ntobjshex); + +// {1C6D6E08-2332-4A7B-A94D-6432DB2B5AE6} +const GUID CLSID_RegistryFolder = { 0x1c6d6e08, 0x2332, 0x4a7b, { 0xa9, 0x4d, 0x64, 0x32, 0xdb, 0x2b, 0x5a, 0xe6 } }; + +// {18A4B504-F6D8-4D8A-8661-6296514C2CF0} +static const GUID GUID_RegistryColumns = { 0x18a4b504, 0xf6d8, 0x4d8a, { 0x86, 0x61, 0x62, 0x96, 0x51, 0x4c, 0x2c, 0xf0 } }; + +enum RegistryColumns +{ + REGISTRY_COLUMN_NAME = 0, + REGISTRY_COLUMN_TYPE = 1, + REGISTRY_COLUMN_VALUE = 2, +}; + +class CRegistryFolderContextMenu : + public CComObjectRootEx<CComMultiThreadModelNoCS>, + public IContextMenu +{ + PCIDLIST_ABSOLUTE m_pcidlFolder; + PCITEMID_CHILD m_pcidlChild; + UINT m_idFirst; + +public: + CRegistryFolderContextMenu() : + m_pcidlFolder(NULL), + m_pcidlChild(NULL), + m_idFirst(0) + { + + } + + virtual ~CRegistryFolderContextMenu() + { + if (m_pcidlFolder) + ILFree((LPITEMIDLIST) m_pcidlFolder); + if (m_pcidlChild) + ILFree((LPITEMIDLIST) m_pcidlChild); + } + + HRESULT Initialize(PCIDLIST_ABSOLUTE parent, UINT cidl, PCUITEMID_CHILD_ARRAY apidl) + { + m_pcidlFolder = ILClone(parent); + if (cidl != 1) + return E_INVALIDARG; + m_pcidlChild = ILClone(apidl[0]); + return S_OK; + } + + // IContextMenu + virtual HRESULT WINAPI QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) + { + m_idFirst = idCmdFirst; + + const RegPidlEntry * entry = (RegPidlEntry *) m_pcidlChild; + + if (entry->entryType == REG_ENTRY_KEY) + { + MENUITEMINFOW mii; + + WCHAR open [] = L"Open"; + WCHAR opennewwindow [] = L"Open in new window"; + + ZeroMemory(&mii, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU | MIIM_ID; + mii.fType = MFT_STRING; + mii.wID = idCmdFirst++; + mii.dwTypeData = open; + mii.cch = _countof(open); + mii.fState = MFS_ENABLED | MFS_DEFAULT; + mii.hSubMenu = NULL; + InsertMenuItemW(hmenu, idCmdFirst, TRUE, &mii); + + if (!(uFlags & CMF_DEFAULTONLY) && idCmdFirst <= idCmdLast) + { + ZeroMemory(&mii, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU | MIIM_ID; + mii.fType = MFT_STRING; + mii.wID = idCmdFirst++; + mii.dwTypeData = opennewwindow; + mii.cch = _countof(opennewwindow); + mii.fState = MFS_ENABLED; + mii.hSubMenu = NULL; + InsertMenuItemW(hmenu, idCmdFirst, FALSE, &mii); + } + } + + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, idCmdFirst - m_idFirst); + } + + virtual HRESULT WINAPI InvokeCommand(LPCMINVOKECOMMANDINFO lpici) + { + if (LOWORD(lpici->lpVerb) == m_idFirst || !lpici->lpVerb) + { + LPITEMIDLIST fullPidl = ILCombine(m_pcidlFolder, m_pcidlChild); + + SHELLEXECUTEINFO sei = { 0 }; + sei.cbSize = sizeof(sei); + sei.fMask = SEE_MASK_IDLIST | SEE_MASK_CLASSNAME; + sei.lpIDList = fullPidl; + sei.lpClass = L"folder"; + sei.hwnd = lpici->hwnd; + sei.nShow = lpici->nShow; + sei.lpVerb = L"open"; + BOOL bRes = ::ShellExecuteEx(&sei); + + ILFree(fullPidl); + + return bRes ? S_OK : HRESULT_FROM_WIN32(GetLastError()); + } + else if (LOWORD(lpici->lpVerb) == (m_idFirst + 1)) + { + LPITEMIDLIST fullPidl = ILCombine(m_pcidlFolder, m_pcidlChild); + + SHELLEXECUTEINFO sei = { 0 }; + sei.cbSize = sizeof(sei); + sei.fMask = SEE_MASK_IDLIST | SEE_MASK_CLASSNAME; + sei.lpIDList = fullPidl; + sei.lpClass = L"folder"; + sei.hwnd = lpici->hwnd; + sei.nShow = lpici->nShow; + sei.lpVerb = L"opennewwindow"; + BOOL bRes = ::ShellExecuteEx(&sei); + + ILFree(fullPidl); + + return bRes ? S_OK : HRESULT_FROM_WIN32(GetLastError()); + } + return E_NOTIMPL; + } + + virtual HRESULT WINAPI GetCommandString(UINT_PTR idCmd, UINT uType, UINT *pwReserved, LPSTR pszName, UINT cchMax) + { + if (idCmd == m_idFirst) + { + if (uType == GCS_VERBW) + { + return StringCchCopyW((LPWSTR) pszName, cchMax, L"open"); + } + } + else if (idCmd == (m_idFirst + 1)) + { + if (uType == GCS_VERBW) + { + return StringCchCopyW((LPWSTR) pszName, cchMax, L"opennewwindow"); + } + } + return E_NOTIMPL; + } + + DECLARE_NOT_AGGREGATABLE(CRegistryFolderContextMenu) + DECLARE_PROTECT_FINAL_CONSTRUCT() + + BEGIN_COM_MAP(CRegistryFolderContextMenu) + COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu) + END_COM_MAP() + +}; + +class CRegistryFolderExtractIcon : + public CComObjectRootEx<CComMultiThreadModelNoCS>, + public IExtractIconW +{ + PCIDLIST_ABSOLUTE m_pcidlFolder; + PCITEMID_CHILD m_pcidlChild; + +public: + CRegistryFolderExtractIcon() : + m_pcidlFolder(NULL), + m_pcidlChild(NULL) + { + + } + + virtual ~CRegistryFolderExtractIcon() + { + if (m_pcidlFolder) + ILFree((LPITEMIDLIST) m_pcidlFolder); + if (m_pcidlChild) + ILFree((LPITEMIDLIST) m_pcidlChild); + } + + HRESULT Initialize(PCIDLIST_ABSOLUTE parent, UINT cidl, PCUITEMID_CHILD_ARRAY apidl) + { + m_pcidlFolder = ILClone(parent); + if (cidl != 1) + return E_INVALIDARG; + m_pcidlChild = ILClone(apidl[0]); + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE GetIconLocation( + UINT uFlags, + LPWSTR szIconFile, + UINT cchMax, + INT *piIndex, + UINT *pwFlags) + { + const RegPidlEntry * entry = (RegPidlEntry *) m_pcidlChild; + + if ((entry->cb < sizeof(RegPidlEntry)) || (entry->magic != REGISTRY_PIDL_MAGIC)) + return E_INVALIDARG; + + UINT flags = 0; + + switch (entry->entryType) + { + case REG_ENTRY_KEY: + GetModuleFileNameW(g_hInstance, szIconFile, cchMax); + *piIndex = -IDI_REGISTRYKEY; + *pwFlags = flags; + return S_OK; + case REG_ENTRY_VALUE: + GetModuleFileNameW(g_hInstance, szIconFile, cchMax); + *piIndex = -IDI_REGISTRYVALUE; + *pwFlags = flags; + return S_OK; + default: + GetModuleFileNameW(g_hInstance, szIconFile, cchMax); + *piIndex = -IDI_NTOBJECTITEM; + *pwFlags = flags; + return S_OK; + } + } + + virtual HRESULT STDMETHODCALLTYPE Extract( + LPCWSTR pszFile, + UINT nIconIndex, + HICON *phiconLarge, + HICON *phiconSmall, + UINT nIconSize) + { + return SHDefExtractIconW(pszFile, nIconIndex, 0, phiconLarge, phiconSmall, nIconSize); + } + + DECLARE_NOT_AGGREGATABLE(CRegistryFolderExtractIcon) + DECLARE_PROTECT_FINAL_CONSTRUCT() + + BEGIN_COM_MAP(CRegistryFolderExtractIcon) + COM_INTERFACE_ENTRY_IID(IID_IExtractIconW, IExtractIconW) + END_COM_MAP() + +}; + +class CRegistryPidlManager +{ +private: + PWSTR m_ntPath; + + HDPA m_hDpa; + UINT m_hDpaCount; + + int DpaDeleteCallback(RegPidlEntry * info) + { + CoTaskMemFree(info); + return 0; + } + + static int CALLBACK s_DpaDeleteCallback(void *pItem, void *pData) + { + CRegistryPidlManager * mf = (CRegistryPidlManager*) pData; + RegPidlEntry * item = (RegPidlEntry*) pItem; + return mf->DpaDeleteCallback(item); + } + +public: + CRegistryPidlManager() : + m_ntPath(NULL), + m_hDpa(NULL), + m_hDpaCount(0) + { + } + + ~CRegistryPidlManager() + { + DPA_DestroyCallback(m_hDpa, s_DpaDeleteCallback, this); + } + + HRESULT Initialize(PWSTR ntPath) + { + m_ntPath = ntPath; + + m_hDpa = DPA_Create(10); + + if (!m_hDpa) + return E_OUTOFMEMORY; + + HRESULT hr = EnumerateRegistryKey(m_hDpa, m_ntPath, NULL, &m_hDpaCount); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + return S_OK; + } + + HRESULT FindPidlInList(PCUITEMID_CHILD pcidl, RegPidlEntry ** pinfo) + { + HRESULT hr; + + if (!m_hDpa) + { + return E_FAIL; + } + + RegPidlEntry * info = (RegPidlEntry *) pcidl; + if ((info->cb < sizeof(RegPidlEntry)) || (info->magic != REGISTRY_PIDL_MAGIC)) + { + ERR("FindPidlInList: Requested pidl is not of the correct type.\n"); + return E_INVALIDARG; + } + + TRACE("Searching for pidl { cb=%d } in a list of %d items\n", pcidl->mkid.cb, m_hDpaCount); + + for (UINT i = 0; i < m_hDpaCount; i++) + { + RegPidlEntry * pInfo = (RegPidlEntry *) DPA_GetPtr(m_hDpa, i); + ASSERT(pInfo); + + hr = CompareIDs(0, pInfo, pcidl); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + if (hr == S_OK) + { + *pinfo = pInfo; + return S_OK; + } + else + { + TRACE("Comparison returned %d\n", (int) (short) (hr & 0xFFFF)); + } + } + + ERR("PIDL NOT FOUND: Requested filename: %S\n", info->entryName); + return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + } + + HRESULT FindByName(LPCWSTR strParsingName, RegPidlEntry ** pinfo) + { + if (!m_hDpa) + { + return E_FAIL; + } + + TRACE("Searching for '%S' in a list of %d items\n", strParsingName, m_hDpaCount); + + for (int i = 0; i < (int) m_hDpaCount; i++) + { + RegPidlEntry * pInfo = (RegPidlEntry *) DPA_GetPtr(m_hDpa, i); + ASSERT(pInfo); + + int order = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, + pInfo->entryName, wcslen(pInfo->entryName), + strParsingName, wcslen(strParsingName)); + + if (order == CSTR_EQUAL) + { + *pinfo = pInfo; + return S_OK; + } + } + + TRACE("Pidl not found\n"); + return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + } + + HRESULT GetPidl(UINT index, RegPidlEntry ** pEntry) + { + *pEntry = NULL; + + RegPidlEntry * entry = (RegPidlEntry *) DPA_GetPtr(m_hDpa, index); + if (!entry) + { + return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + } + + *pEntry = entry; + return S_OK; + } + + HRESULT GetCount(UINT * count) + { + *count = m_hDpaCount; + return S_OK; + } + + + static LPITEMIDLIST CreatePidlFromItem(RegPidlEntry * entry) + { + LPITEMIDLIST idl = (LPITEMIDLIST) CoTaskMemAlloc(entry->cb + 2); + if (!idl) + return NULL; + memset(idl, 0, entry->cb + 2); + memcpy(idl, entry, entry->cb); + return idl; + } + + HRESULT CompareIDs(LPARAM lParam, RegPidlEntry * first, RegPidlEntry * second) + { + if (LOWORD(lParam) != 0) + return E_INVALIDARG; + + if (second->cb > first->cb) + return MAKE_HRESULT(0, 0, (USHORT) 1); + if (second->cb < first->cb) + return MAKE_HRESULT(0, 0, (USHORT) -1); + + if (second->entryNameLength > first->entryNameLength) + return MAKE_HRESULT(0, 0, (USHORT) 1); + if (second->entryNameLength < first->entryNameLength) + return MAKE_HRESULT(0, 0, (USHORT) -1); + + if (HIWORD(lParam) == SHCIDS_ALLFIELDS) + { + int ord = memcmp(second, first, first->cb); + + if (ord != 0) + return MAKE_HRESULT(0, 0, (USHORT) ord); + } + else if (HIWORD(lParam) == SHCIDS_CANONICALONLY) + { + int ord = StrCmpNW(second->entryName, first->entryName, first->entryNameLength); + + if (ord != 0) + return MAKE_HRESULT(0, 0, (USHORT) ord); + } + else + { + int ord = (int) second->entryType - (int) first->entryType; + + if (ord > 0) + return MAKE_HRESULT(0, 0, (USHORT) 1); + if (ord < 0) + return MAKE_HRESULT(0, 0, (USHORT) -1); + + ord = StrCmpNW(second->entryName, first->entryName, first->entryNameLength/sizeof(WCHAR)); + + if (ord != 0) + return MAKE_HRESULT(0, 0, (USHORT) ord); + } + + return S_OK; + } + + HRESULT CompareIDs(LPARAM lParam, RegPidlEntry * first, LPCITEMIDLIST pcidl) + { + LPCITEMIDLIST p = pcidl; + RegPidlEntry * second = (RegPidlEntry*) &(p->mkid); + if ((second->cb < sizeof(RegPidlEntry)) || (second->magic != REGISTRY_PIDL_MAGIC)) + return E_INVALIDARG; + + return CompareIDs(lParam, first, second); + } + + HRESULT CompareIDs(LPARAM lParam, LPCITEMIDLIST pcidl1, LPCITEMIDLIST pcidl2) + { + LPCITEMIDLIST p = pcidl1; + RegPidlEntry * first = (RegPidlEntry*) &(p->mkid); + if ((first->cb < sizeof(RegPidlEntry)) || (first->magic != REGISTRY_PIDL_MAGIC)) + return E_INVALIDARG; + + return CompareIDs(lParam, first, pcidl2); + } + + ULONG ConvertAttributes(RegPidlEntry * entry, PULONG inMask) + { + ULONG mask = inMask ? *inMask : 0xFFFFFFFF; + ULONG flags = 0; + + if (entry->entryType == REG_ENTRY_KEY) + flags |= SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_BROWSABLE; + + return flags & mask; + } + + HRESULT FormatContentsForDisplay(RegPidlEntry * info, PCWSTR * strContents) + { + PVOID td = (((PBYTE) info) + FIELD_OFFSET(RegPidlEntry,entryName) + info->entryNameLength + sizeof(WCHAR)); + + if (info->contentsLength > 0) + { + if (info->entryType == REG_ENTRY_VALUE_WITH_CONTENT) + { + switch (info->contentType) + { + case REG_SZ: + case REG_EXPAND_SZ: + { + PWSTR strValue = (PWSTR) CoTaskMemAlloc(info->contentsLength + sizeof(WCHAR)); + StringCbCopyNW(strValue, info->contentsLength + sizeof(WCHAR), (LPCWSTR) td, info->contentsLength); + *strContents = strValue; + return S_OK; + } + case REG_DWORD: + { + DWORD bufferLength = 64 * sizeof(WCHAR); + PWSTR strValue = (PWSTR) CoTaskMemAlloc(bufferLength); + StringCbPrintfW(strValue, bufferLength, L"0x%08x (%d)", + *(DWORD*) td, *(DWORD*) td); + *strContents = strValue; + return S_OK; + } + case REG_QWORD: + { + DWORD bufferLength = 64 * sizeof(WCHAR); + PWSTR strValue = (PWSTR) CoTaskMemAlloc(bufferLength); + StringCbPrintfW(strValue, bufferLength, L"0x%016llx (%d)", + *(LARGE_INTEGER*) td, ((LARGE_INTEGER*) td)->QuadPart); + *strContents = strValue; + return S_OK; + } + default: + { + PCWSTR strTodo = L"<TODO: Convert value for display>"; + DWORD bufferLength = (wcslen(strTodo) + 1) * sizeof(WCHAR); + PWSTR strValue = (PWSTR) CoTaskMemAlloc(bufferLength); + StringCbCopyW(strValue, bufferLength, strTodo); + *strContents = strValue; + return S_OK; + } + } + } + else + { + PCWSTR strTodo = L"<TODO: Query non-embedded value>"; + DWORD bufferLength = (wcslen(strTodo) + 1) * sizeof(WCHAR); + PWSTR strValue = (PWSTR) CoTaskMemAlloc(bufferLength); + StringCbCopyW(strValue, bufferLength, strTodo); + *strContents = strValue; + return S_OK; + } + } + else + { + PCWSTR strEmpty = L"(Empty)"; + DWORD bufferLength = (wcslen(strEmpty)+1) * sizeof(WCHAR); + PWSTR strValue = (PWSTR) CoTaskMemAlloc(bufferLength); + StringCbCopyW(strValue, bufferLength, strEmpty); + *strContents = strValue; + return S_OK; + } + + } + +}; + +class CRegistryFolderEnum : + public CComObjectRootEx<CComMultiThreadModelNoCS>, + public IEnumIDList +{ +private: + CComPtr<CRegistryFolder> m_Folder; + + HWND m_HwndOwner; + SHCONTF m_Flags; + + UINT m_Index; + UINT m_Count; + +public: + CRegistryFolderEnum() : + m_HwndOwner(NULL), + m_Flags(0), + m_Index(0), + m_Count(0) + { + } + + virtual ~CRegistryFolderEnum() + { + } + + HRESULT Initialize(CRegistryFolder * folder, HWND hwndOwner, SHCONTF flags) + { + m_Folder = folder; + + m_Folder->GetManager().GetCount(&m_Count); + + m_HwndOwner = hwndOwner; + m_Flags = flags; + + return Reset(); + } + + virtual HRESULT STDMETHODCALLTYPE Next( + ULONG celt, + LPITEMIDLIST *rgelt, + ULONG *pceltFetched) + { + if (pceltFetched) + *pceltFetched = 0; + + if (m_Index >= m_Count) + return S_FALSE; + + for (int i = 0; i < (int) celt;) + { + RegPidlEntry * tinfo; + BOOL flagsOk = FALSE; + + do { + HRESULT hr = m_Folder->GetManager().GetPidl(m_Index++, &tinfo); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + switch (tinfo->entryType) + { + case REG_ENTRY_KEY: + flagsOk = (m_Flags & SHCONTF_FOLDERS) != 0; + break; + default: + flagsOk = (m_Flags & SHCONTF_NONFOLDERS) != 0; + break; + } + } while (m_Index < m_Count && !flagsOk); + + if (flagsOk) + { + if (rgelt) + rgelt[i] = m_Folder->GetManager().CreatePidlFromItem(tinfo); + i++; + } + + if (m_Index == m_Count) + { + if (pceltFetched) + *pceltFetched = i; + return (i == (int) celt) ? S_OK : S_FALSE; + } + } + + if (pceltFetched) *pceltFetched = celt; + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE Skip(ULONG celt) + { + return Next(celt, NULL, NULL); + } + + virtual HRESULT STDMETHODCALLTYPE Reset() + { + m_Index = 0; + return S_OK; + } + + virtual HRESULT STDMETHODCALLTYPE Clone(IEnumIDList **ppenum) + { + return ShellObjectCreatorInit<CRegistryFolderEnum>(m_Folder, m_HwndOwner, m_Flags, IID_PPV_ARG(IEnumIDList, ppenum)); + } + + DECLARE_NOT_AGGREGATABLE(CRegistryFolderEnum) + DECLARE_PROTECT_FINAL_CONSTRUCT() + + BEGIN_COM_MAP(CRegistryFolderEnum) + COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) + END_COM_MAP() + +}; + +//----------------------------------------------------------------------------- +// CRegistryFolder + +CRegistryFolder::CRegistryFolder() : + m_PidlManager(NULL), + m_shellPidl(NULL) +{ +} + +CRegistryFolder::~CRegistryFolder() +{ + TRACE("Destroying CRegistryFolder %p\n", this); +} + +// IShellFolder +HRESULT STDMETHODCALLTYPE CRegistryFolder::ParseDisplayName( + HWND hwndOwner, + LPBC pbcReserved, + LPOLESTR lpszDisplayName, + ULONG *pchEaten, + LPITEMIDLIST *ppidl, + ULONG *pdwAttributes) +{ + HRESULT hr; + RegPidlEntry * info; + + if (!ppidl) + return E_POINTER; + + if (pchEaten) + *pchEaten = 0; + + if (pdwAttributes) + *pdwAttributes = 0; + + TRACE("CRegistryFolder::ParseDisplayName name=%S (ntPath=%S)\n", lpszDisplayName, m_NtPath); + + hr = m_PidlManager->FindByName(lpszDisplayName, &info); + if (FAILED(hr)) + { + return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + } + + *ppidl = m_PidlManager->CreatePidlFromItem(info); + + if (pchEaten) + *pchEaten = wcslen(info->entryName); + + if (pdwAttributes) + *pdwAttributes = m_PidlManager->ConvertAttributes(info, pdwAttributes); + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CRegistryFolder::EnumObjects( + HWND hwndOwner, + SHCONTF grfFlags, + IEnumIDList **ppenumIDList) +{ + return ShellObjectCreatorInit<CRegistryFolderEnum>(this, hwndOwner, grfFlags, IID_PPV_ARG(IEnumIDList, ppenumIDList)); +} + +HRESULT STDMETHODCALLTYPE CRegistryFolder::BindToObject( + LPCITEMIDLIST pidl, + LPBC pbcReserved, + REFIID riid, + void **ppvOut) +{ + RegPidlEntry * info; + HRESULT hr; + + if (IsEqualIID(riid, IID_IShellFolder)) + { + hr = m_PidlManager->FindPidlInList(pidl, &info); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + +#if 0 + if (!(info->objectInformation.GrantedAccess & (STANDARD_RIGHTS_READ | FILE_LIST_DIRECTORY))) + return E_ACCESSDENIED; +#endif + + WCHAR path[MAX_PATH]; + + StringCbCopyW(path, _countof(path), m_NtPath); + + PathAppendW(path, info->entryName); + + LPITEMIDLIST first = ILCloneFirst(pidl); + LPCITEMIDLIST rest = ILGetNext(pidl); + + LPITEMIDLIST fullPidl = ILCombine(m_shellPidl, first); + + CComPtr<IShellFolder> psfChild; + hr = ShellObjectCreatorInit<CRegistryFolder>(fullPidl, path, IID_PPV_ARG(IShellFolder, &psfChild)); + + ILFree(fullPidl); + ILFree(first); + + if (rest->mkid.cb > 0) + { + return psfChild->BindToObject(rest, pbcReserved, riid, ppvOut); + } + + return psfChild->QueryInterface(riid, ppvOut); + } + + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CRegistryFolder::BindToStorage( + LPCITEMIDLIST pidl, + LPBC pbcReserved, + REFIID riid, + void **ppvObj) +{ + UNIMPLEMENTED; + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CRegistryFolder::CompareIDs( + LPARAM lParam, + LPCITEMIDLIST pidl1, + LPCITEMIDLIST pidl2) +{ + TRACE("CompareIDs\n"); + return m_PidlManager->CompareIDs(lParam, pidl1, pidl2); +} + +HRESULT STDMETHODCALLTYPE CRegistryFolder::CreateViewObject( + HWND hwndOwner, + REFIID riid, + void **ppvOut) +{ + if (!IsEqualIID(riid, IID_IShellView)) + return E_NOINTERFACE; + + SFV_CREATE sfv; + sfv.cbSize = sizeof(sfv); + sfv.pshf = this; + sfv.psvOuter = NULL; + sfv.psfvcb = NULL; + + return SHCreateShellFolderView(&sfv, (IShellView**) ppvOut); +} + +HRESULT STDMETHODCALLTYPE CRegistryFolder::GetAttributesOf( + UINT cidl, + PCUITEMID_CHILD_ARRAY apidl, + SFGAOF *rgfInOut) +{ + RegPidlEntry * info; + HRESULT hr; + + TRACE("GetAttributesOf\n"); + + if (cidl == 0) + { + *rgfInOut &= SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_BROWSABLE; + return S_OK; + } + + for (int i = 0; i < (int) cidl; i++) + { + PCUITEMID_CHILD pidl = apidl[i]; + + hr = m_PidlManager->FindPidlInList(pidl, &info); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + // Update attributes. + *rgfInOut = m_PidlManager->ConvertAttributes(info, rgfInOut); + } + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CRegistryFolder::GetUIObjectOf( + HWND hwndOwner, + UINT cidl, + PCUITEMID_CHILD_ARRAY apidl, + REFIID riid, + UINT *prgfInOut, + void **ppvOut) +{ + TRACE("GetUIObjectOf\n"); + + if (IsEqualIID(riid, IID_IContextMenu)) + { + return ShellObjectCreatorInit<CRegistryFolderContextMenu>(m_shellPidl, cidl, apidl, riid, ppvOut); + //return CDefFolderMenu_Create2(m_shellPidl, hwndOwner, cidl, apidl, this, ContextMenuCallback, 0, NULL, (IContextMenu**) ppvOut); + } + + if (IsEqualIID(riid, IID_IExtractIconW)) + { + return ShellObjectCreatorInit<CRegistryFolderExtractIcon>(m_shellPidl, cidl, apidl, riid, ppvOut); + } + + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDisplayNameOf( + LPCITEMIDLIST pidl, + SHGDNF uFlags, + STRRET *lpName) +{ + RegPidlEntry * info; + HRESULT hr; + + TRACE("GetDisplayNameOf %p\n", pidl); + + hr = m_PidlManager->FindPidlInList(pidl, &info); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + if ((GET_SHGDN_RELATION(uFlags) == SHGDN_NORMAL) && + (GET_SHGDN_FOR(uFlags) & SHGDN_FORPARSING)) + { + WCHAR path[MAX_PATH] = { 0 }; + + hr = GetFullName(m_shellPidl, uFlags, path, _countof(path)); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + PathAppendW(path, info->entryName); + + hr = MakeStrRetFromString(path, lpName); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + LPCITEMIDLIST pidlNext = ILGetNext(pidl); + + if (pidlNext && pidlNext->mkid.cb > 0) + { + CComPtr<IShellFolder> psfChild; + hr = BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfChild)); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + WCHAR temp[MAX_PATH]; + STRRET childName; + + hr = psfChild->GetDisplayNameOf(pidlNext, uFlags | SHGDN_INFOLDER, &childName); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + hr = StrRetToBufW(&childName, pidlNext, temp, _countof(temp)); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + PathAppendW(path, temp); + } + } + else + { + MakeStrRetFromString(info->entryName, info->entryNameLength, lpName); + } + + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CRegistryFolder::SetNameOf( + HWND hwnd, + LPCITEMIDLIST pidl, + LPCOLESTR lpszName, + SHGDNF uFlags, + LPITEMIDLIST *ppidlOut) +{ + UNIMPLEMENTED; + return E_NOTIMPL; +} + +// IPersist +HRESULT STDMETHODCALLTYPE CRegistryFolder::GetClassID(CLSID *lpClassId) +{ + if (!lpClassId) + return E_POINTER; + + *lpClassId = CLSID_RegistryFolder; + return S_OK; +} + +// IPersistFolder +HRESULT STDMETHODCALLTYPE CRegistryFolder::Initialize(LPCITEMIDLIST pidl) +{ + m_shellPidl = ILClone(pidl); + + PCWSTR ntPath = L"\REGISTRY"; + +#if 0 + WCHAR debugTemp[MAX_PATH]; + GetFullName(m_shellPidl, SHGDN_FORPARSING, debugTemp, _countof(debugTemp)); + DbgPrint("INITIALIZE CRegistryFolder PIDL PATH: %S (ntPath: %S)\n", debugTemp, ntPath); + + if (ntPath[wcslen(ntPath) - 1] == L'\' && debugTemp[wcslen(debugTemp) - 1] != L'\') + wcscat(debugTemp, L"\"); + + PCWSTR guidTemp = L"::{845B0FB2-66E0-416B-8F91-314E23F7C12D}"; + + PCWSTR findTemp = StrStrW(debugTemp, guidTemp); + PCWSTR nextTemp = findTemp + wcslen(guidTemp); + + if (wcscmp(nextTemp, ntPath)) + { + DbgPrint("WHAT THE F, the NT PATH DOES NOT MATCH\n"); + return E_FAIL; + } +#endif + + if (!m_PidlManager) + { + m_PidlManager = new CRegistryPidlManager(); + + StringCbCopy(m_NtPath, _countof(m_NtPath), ntPath); + } + + return m_PidlManager->Initialize(m_NtPath); +} + +// Internal +HRESULT STDMETHODCALLTYPE CRegistryFolder::Initialize(LPCITEMIDLIST pidl, PCWSTR ntPath) +{ + m_shellPidl = ILClone(pidl); + +#if 0 + WCHAR debugTemp[MAX_PATH]; + GetFullName(m_shellPidl, SHGDN_FORPARSING, debugTemp, _countof(debugTemp)); + DbgPrint("INITIALIZE CRegistryFolder PIDL PATH: %S (ntPath: %S)\n", debugTemp, ntPath); + + if (ntPath[wcslen(ntPath) - 1] == L'\' && debugTemp[wcslen(debugTemp) - 1] != L'\') + wcscat(debugTemp, L"\"); + + PCWSTR guidTemp = L"::{845B0FB2-66E0-416B-8F91-314E23F7C12D}"; + + PCWSTR findTemp = StrStrW(debugTemp, guidTemp); + PCWSTR nextTemp = findTemp + wcslen(guidTemp); + + if (wcscmp(nextTemp, ntPath)) + { + DbgPrint("WHAT THE F, the NT PATH DOES NOT MATCH\n"); + return E_FAIL; + } +#endif + + if (!m_PidlManager) + m_PidlManager = new CRegistryPidlManager(); + + StringCbCopy(m_NtPath, _countof(m_NtPath), ntPath); + return m_PidlManager->Initialize(m_NtPath); +} + +// IPersistFolder2 +HRESULT STDMETHODCALLTYPE CRegistryFolder::GetCurFolder(LPITEMIDLIST * pidl) +{ + if (pidl) + *pidl = ILClone(m_shellPidl); + if (!m_shellPidl) + return S_FALSE; + return S_OK; +} + +// IShellFolder2 +HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDefaultSearchGUID( + GUID *lpguid) +{ + UNIMPLEMENTED; + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CRegistryFolder::EnumSearches( + IEnumExtraSearch **ppenum) +{ + UNIMPLEMENTED; + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDefaultColumn( + DWORD dwReserved, + ULONG *pSort, + ULONG *pDisplay) +{ + if (pSort) + *pSort = 0; + if (pDisplay) + *pDisplay = 0; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDefaultColumnState( + UINT iColumn, + SHCOLSTATEF *pcsFlags) +{ + switch (iColumn) + { + case REGISTRY_COLUMN_NAME: + *pcsFlags = SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT; + return S_OK; + case REGISTRY_COLUMN_TYPE: + *pcsFlags = SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT; + return S_OK; + case REGISTRY_COLUMN_VALUE: + *pcsFlags = SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT | SHCOLSTATE_SLOW; + return S_OK; + } + + return E_INVALIDARG; +} + +HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDetailsEx( + LPCITEMIDLIST pidl, + const SHCOLUMNID *pscid, + VARIANT *pv) +{ + RegPidlEntry * info; + HRESULT hr; + + TRACE("GetDetailsEx\n"); + + if (pidl) + { + hr = m_PidlManager->FindPidlInList(pidl, &info); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + static const GUID storage = PSGUID_STORAGE; + if (IsEqualGUID(pscid->fmtid, storage)) + { + if (pscid->pid == PID_STG_NAME) + { + return MakeVariantString(pv, info->entryName); + } + else if (pscid->pid == PID_STG_STORAGETYPE) + { + return MakeVariantString(pv, RegistryTypeNames[info->entryType]); + } + else if (pscid->pid == PID_STG_CONTENTS) + { + PCWSTR strValueContents; + + hr = m_PidlManager->FormatContentsForDisplay(info, &strValueContents); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + if (hr == S_FALSE) + { + V_VT(pv) = VT_EMPTY; + return S_OK; + } + + hr = MakeVariantString(pv, strValueContents); + + CoTaskMemFree((PVOID)strValueContents); + + return hr; + + } + } + } + + return E_INVALIDARG; +} + +HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDetailsOf( + LPCITEMIDLIST pidl, + UINT iColumn, + SHELLDETAILS *psd) +{ + RegPidlEntry * info; + HRESULT hr; + + TRACE("GetDetailsOf\n"); + + if (pidl) + { + hr = m_PidlManager->FindPidlInList(pidl, &info); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + switch (iColumn) + { + case REGISTRY_COLUMN_NAME: + psd->fmt = LVCFMT_LEFT; + + if (info->entryNameLength > 0) + { + return MakeStrRetFromString(info->entryName, info->entryNameLength, &(psd->str)); + } + return MakeStrRetFromString(L"(Default)", &(psd->str)); + + case REGISTRY_COLUMN_TYPE: + psd->fmt = LVCFMT_LEFT; + + return MakeStrRetFromString(RegistryTypeNames[info->entryType], &(psd->str)); + + case REGISTRY_COLUMN_VALUE: + psd->fmt = LVCFMT_LEFT; + + PCWSTR strValueContents; + + hr = m_PidlManager->FormatContentsForDisplay(info, &strValueContents); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + if (hr == S_FALSE) + { + return MakeStrRetFromString(L"(Empty)", &(psd->str)); + } + + hr = MakeStrRetFromString(strValueContents, &(psd->str)); + + CoTaskMemFree((PVOID) strValueContents); + + return hr; + } + } + else + { + switch (iColumn) + { + case REGISTRY_COLUMN_NAME: + psd->fmt = LVCFMT_LEFT; + psd->cxChar = 30; + + // TODO: Make localizable + MakeStrRetFromString(L"Object Name", &(psd->str)); + return S_OK; + case REGISTRY_COLUMN_TYPE: + psd->fmt = LVCFMT_LEFT; + psd->cxChar = 20; + + // TODO: Make localizable + MakeStrRetFromString(L"Content Type", &(psd->str)); + return S_OK; + case REGISTRY_COLUMN_VALUE: + psd->fmt = LVCFMT_LEFT; + psd->cxChar = 20; + + // TODO: Make localizable + MakeStrRetFromString(L"Value", &(psd->str)); + return S_OK; + } + } + + return E_INVALIDARG; +} + +HRESULT STDMETHODCALLTYPE CRegistryFolder::MapColumnToSCID( + UINT iColumn, + SHCOLUMNID *pscid) +{ + static const GUID storage = PSGUID_STORAGE; + switch (iColumn) + { + case REGISTRY_COLUMN_NAME: + pscid->fmtid = storage; + pscid->pid = PID_STG_NAME; + return S_OK; + case REGISTRY_COLUMN_TYPE: + pscid->fmtid = storage; + pscid->pid = PID_STG_STORAGETYPE; + return S_OK; + case REGISTRY_COLUMN_VALUE: + pscid->fmtid = storage; + pscid->pid = PID_STG_CONTENTS; + return S_OK; + } + return E_INVALIDARG; +}
Propchange: trunk/reactos/dll/shellext/ntobjshex/regfolder.cpp ------------------------------------------------------------------------------ svn:eol-style = native
Added: trunk/reactos/dll/shellext/ntobjshex/regfolder.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/shellext/ntobjshex/regf... ============================================================================== --- trunk/reactos/dll/shellext/ntobjshex/regfolder.h (added) +++ trunk/reactos/dll/shellext/ntobjshex/regfolder.h [iso-8859-1] Mon Feb 23 17:13:32 2015 @@ -0,0 +1,149 @@ +/* + * PROJECT: ReactOS system libraries + * LICENSE: GPL - See COPYING in the top level directory + * FILE: dll\win32\stobject\stobject.cpp + * PURPOSE: Systray shell service object + * PROGRAMMERS: Robert Naumann + David Quintana gigaherz@gmail.com + */ +#pragma once + +extern const GUID CLSID_RegistryFolder; + +class CRegistryPidlManager; + +class CRegistryFolder : + public CComCoClass<CRegistryFolder, &CLSID_RegistryFolder>, + public CComObjectRootEx<CComMultiThreadModelNoCS>, + public IShellFolder2, + public IPersistFolder2 +{ + CRegistryPidlManager * m_PidlManager; + + WCHAR m_NtPath[MAX_PATH]; + + LPITEMIDLIST m_shellPidl; + +public: + + CRegistryFolder(); + virtual ~CRegistryFolder(); + + CRegistryPidlManager& GetManager() { return *m_PidlManager; } + + // IShellFolder + virtual HRESULT STDMETHODCALLTYPE ParseDisplayName( + HWND hwndOwner, + LPBC pbcReserved, + LPOLESTR lpszDisplayName, + ULONG *pchEaten, + LPITEMIDLIST *ppidl, + ULONG *pdwAttributes); + + virtual HRESULT STDMETHODCALLTYPE EnumObjects( + HWND hwndOwner, + SHCONTF grfFlags, + IEnumIDList **ppenumIDList); + + virtual HRESULT STDMETHODCALLTYPE BindToObject( + LPCITEMIDLIST pidl, + LPBC pbcReserved, + REFIID riid, + void **ppvOut); + + virtual HRESULT STDMETHODCALLTYPE BindToStorage( + LPCITEMIDLIST pidl, + LPBC pbcReserved, + REFIID riid, + void **ppvObj); + + virtual HRESULT STDMETHODCALLTYPE CompareIDs( + LPARAM lParam, + LPCITEMIDLIST pidl1, + LPCITEMIDLIST pidl2); + + virtual HRESULT STDMETHODCALLTYPE CreateViewObject( + HWND hwndOwner, + REFIID riid, + void **ppvOut); + + virtual HRESULT STDMETHODCALLTYPE GetAttributesOf( + UINT cidl, + PCUITEMID_CHILD_ARRAY apidl, + SFGAOF *rgfInOut); + + virtual HRESULT STDMETHODCALLTYPE GetUIObjectOf( + HWND hwndOwner, + UINT cidl, + PCUITEMID_CHILD_ARRAY apidl, + REFIID riid, + UINT *prgfInOut, + void **ppvOut); + + virtual HRESULT STDMETHODCALLTYPE GetDisplayNameOf( + LPCITEMIDLIST pidl, + SHGDNF uFlags, + STRRET *lpName); + + virtual HRESULT STDMETHODCALLTYPE SetNameOf( + HWND hwnd, + LPCITEMIDLIST pidl, + LPCOLESTR lpszName, + SHGDNF uFlags, + LPITEMIDLIST *ppidlOut); + + // IShellFolder2 + virtual HRESULT STDMETHODCALLTYPE GetDefaultSearchGUID( + GUID *lpguid); + + virtual HRESULT STDMETHODCALLTYPE EnumSearches( + IEnumExtraSearch **ppenum); + + virtual HRESULT STDMETHODCALLTYPE GetDefaultColumn( + DWORD dwReserved, + ULONG *pSort, + ULONG *pDisplay); + + virtual HRESULT STDMETHODCALLTYPE GetDefaultColumnState( + UINT iColumn, + SHCOLSTATEF *pcsFlags); + + virtual HRESULT STDMETHODCALLTYPE GetDetailsEx( + LPCITEMIDLIST pidl, + const SHCOLUMNID *pscid, + VARIANT *pv); + + virtual HRESULT STDMETHODCALLTYPE GetDetailsOf( + LPCITEMIDLIST pidl, + UINT iColumn, + SHELLDETAILS *psd); + + virtual HRESULT STDMETHODCALLTYPE MapColumnToSCID( + UINT iColumn, + SHCOLUMNID *pscid); + + // IPersist + virtual HRESULT STDMETHODCALLTYPE GetClassID(CLSID *lpClassId); + + // IPersistFolder + virtual HRESULT STDMETHODCALLTYPE Initialize(LPCITEMIDLIST pidl); + + // IPersistFolder2 + virtual HRESULT STDMETHODCALLTYPE GetCurFolder(LPITEMIDLIST * pidl); + + // Internal + HRESULT STDMETHODCALLTYPE Initialize(LPCITEMIDLIST pidl, PCWSTR ntPath); + + DECLARE_REGISTRY_RESOURCEID(IDR_NTOBJECTFOLDER) + DECLARE_NOT_AGGREGATABLE(CRegistryFolder) + DECLARE_PROTECT_FINAL_CONSTRUCT() + + BEGIN_COM_MAP(CRegistryFolder) + COM_INTERFACE_ENTRY_IID(IID_IShellFolder, IShellFolder) + COM_INTERFACE_ENTRY_IID(IID_IShellFolder2, IShellFolder2) + COM_INTERFACE_ENTRY_IID(IID_IPersist, IPersist) + COM_INTERFACE_ENTRY_IID(IID_IPersistFolder, IPersistFolder) + COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2) + END_COM_MAP() + +};
Propchange: trunk/reactos/dll/shellext/ntobjshex/regfolder.h ------------------------------------------------------------------------------ svn:eol-style = native
Modified: trunk/reactos/dll/shellext/ntobjshex/resource.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/shellext/ntobjshex/reso... ============================================================================== --- trunk/reactos/dll/shellext/ntobjshex/resource.h [iso-8859-1] (original) +++ trunk/reactos/dll/shellext/ntobjshex/resource.h [iso-8859-1] Mon Feb 23 17:13:32 2015 @@ -7,6 +7,9 @@ #define IDI_NTOBJECTDEVICE 5 #define IDI_NTOBJECTPORT 6
+#define IDI_REGISTRYKEY 32 +#define IDI_REGISTRYVALUE 33 + #define IDS_NAME 101
#define IDR_NTOBJECTFOLDER 1001
Added: trunk/reactos/dll/shellext/ntobjshex/util.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/shellext/ntobjshex/util... ============================================================================== --- trunk/reactos/dll/shellext/ntobjshex/util.h (added) +++ trunk/reactos/dll/shellext/ntobjshex/util.h [iso-8859-1] Mon Feb 23 17:13:32 2015 @@ -0,0 +1,44 @@ +#pragma once + +#ifndef INLINE +#define INLINE inline +#endif + +HRESULT INLINE MakeStrRetFromString(LPCWSTR string, DWORD cbLength, STRRET * str) +{ + str->uType = STRRET_WSTR; + + DWORD blen = cbLength + sizeof(WCHAR); + str->pOleStr = (LPWSTR) CoTaskMemAlloc(blen); + return StringCbCopyNW(str->pOleStr, blen, string, cbLength); +} + +HRESULT INLINE MakeStrRetFromString(LPCWSTR string, STRRET * str) +{ + DWORD stringLength = wcslen(string) * sizeof(WCHAR); + return MakeStrRetFromString(string, stringLength, str); +} + +HRESULT INLINE MakeVariantString(VARIANT * pv, PCWSTR string) +{ + V_VT(pv) = VT_BSTR; + V_BSTR(pv) = SysAllocString(string); + return S_OK; +} + +HRESULT INLINE GetFullName(PCIDLIST_ABSOLUTE pidl, DWORD uFlags, PWSTR strName, DWORD cchName) +{ + CComPtr<IShellFolder> psfDesktop; + STRRET str; + HRESULT hr; + + hr = SHGetDesktopFolder(&psfDesktop); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + hr = psfDesktop->GetDisplayNameOf(pidl, uFlags, &str); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + return StrRetToBufW(&str, pidl, strName, cchName); +}
Propchange: trunk/reactos/dll/shellext/ntobjshex/util.h ------------------------------------------------------------------------------ svn:eol-style = native