[NTOBJSHEX]

* Implement loading the hardcoded list of root keys.
* Add support for root keys to the registry PIDL structure.
* Add support for root-key PIDLs in the registry folder.
* Implement loading root keys when no path is specified.
* Expose the registry folder as a namespace extension to My Computer.
* Make the namespace extension folder names load from resources.
* Add icons for registry keys and values.
CORE-9244 #resolve #comment Basic registry browsing should now be functional. Any other issues (including editing capability), would go in followup issues.

svn path=/trunk/; revision=66719
This commit is contained in:
David Quintana 2015-03-15 00:00:13 +00:00
parent 42d0a9c883
commit 477fb78355
14 changed files with 219 additions and 40 deletions

View file

@ -2,5 +2,6 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
STRINGTABLE STRINGTABLE
BEGIN BEGIN
IDS_NAME "NT Object Namespace" IDS_NTOBJFLD_NAME "NT Object Namespace"
IDS_REGISTRY_NAME "System Registry"
END END

View file

@ -3,5 +3,6 @@ LANGUAGE LANG_ROMANIAN, SUBLANG_NEUTRAL
STRINGTABLE STRINGTABLE
BEGIN BEGIN
IDS_NAME "Spațiu de nume Obiect NT" IDS_NTOBJFLD_NAME "Spațiu de nume Obiect NT"
IDS_REGISTRY_NAME "System Registry"
END END

View file

@ -107,6 +107,11 @@ public:
*piIndex = -IDI_NTOBJECTPORT; *piIndex = -IDI_NTOBJECTPORT;
*pwFlags = flags; *pwFlags = flags;
return S_OK; return S_OK;
case KEY_OBJECT:
GetModuleFileNameW(g_hInstance, szIconFile, cchMax);
*piIndex = -IDI_REGISTRYKEY;
*pwFlags = flags;
return S_OK;
default: default:
GetModuleFileNameW(g_hInstance, szIconFile, cchMax); GetModuleFileNameW(g_hInstance, szIconFile, cchMax);
*piIndex = -IDI_NTOBJECTITEM; *piIndex = -IDI_NTOBJECTITEM;
@ -624,7 +629,7 @@ HRESULT STDMETHODCALLTYPE CNtObjectFolder::BindToObject(
if (info->objectType == KEY_OBJECT) if (info->objectType == KEY_OBJECT)
{ {
hr = ShellObjectCreatorInit<CRegistryFolder>(fullPidl, path, IID_PPV_ARG(IShellFolder, &psfChild)); hr = ShellObjectCreatorInit<CRegistryFolder>(fullPidl, path, (HKEY)NULL, IID_PPV_ARG(IShellFolder, &psfChild));
} }
else else
{ {

View file

@ -14,6 +14,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(ntobjshex);
BEGIN_OBJECT_MAP(ObjectMap) BEGIN_OBJECT_MAP(ObjectMap)
OBJECT_ENTRY(CLSID_NtObjectFolder, CNtObjectFolder) OBJECT_ENTRY(CLSID_NtObjectFolder, CNtObjectFolder)
OBJECT_ENTRY(CLSID_RegistryFolder, CRegistryFolder)
END_OBJECT_MAP() END_OBJECT_MAP()
HINSTANCE g_hInstance; HINSTANCE g_hInstance;

View file

@ -12,8 +12,11 @@ IDI_NTOBJECTDIROPEN ICON "resources/3.ico"
IDI_NTOBJECTITEM ICON "resources/4.ico" IDI_NTOBJECTITEM ICON "resources/4.ico"
IDI_NTOBJECTDEVICE ICON "resources/5.ico" IDI_NTOBJECTDEVICE ICON "resources/5.ico"
IDI_NTOBJECTPORT ICON "resources/6.ico" IDI_NTOBJECTPORT ICON "resources/6.ico"
IDI_REGISTRYKEY ICON "resources/7.ico"
IDI_REGISTRYVALUE ICON "resources/8.ico"
IDR_NTOBJECTFOLDER REGISTRY "resources/rgs/ntobjectfolder.rgs" IDR_NTOBJECTFOLDER REGISTRY "resources/rgs/ntobjectfolder.rgs"
IDR_REGISTRYFOLDER REGISTRY "resources/rgs/regfolder.rgs"
/* UTF-8 */ /* UTF-8 */
#pragma code_page(65001) #pragma code_page(65001)

View file

@ -417,6 +417,62 @@ HRESULT EnumerateRegistryKey(HDPA hdpa, PCWSTR path, HKEY root, UINT * hdpaCount
return S_OK; return S_OK;
} }
HRESULT EnumerateRootKeys(HDPA hdpa, UINT * hdpaCount)
{
*hdpaCount = 0;
static struct {
HKEY key;
PCWSTR keyName;
} rootKeys [] = {
{ HKEY_CLASSES_ROOT, L"HKEY_CLASSES_ROOT" },
{ HKEY_CURRENT_USER, L"HKEY_CURRENT_USER" },
{ HKEY_LOCAL_MACHINE, L"HKEY_LOCAL_MACHINE" },
{ HKEY_USERS, L"HKEY_USERS" },
{ HKEY_CURRENT_CONFIG, L"HKEY_CURRENT_CONFIG" }
};
for (UINT i = 0; i < _countof(rootKeys); i++)
{
PCWSTR name = rootKeys[i].keyName;
DWORD cchName = wcslen(rootKeys[i].keyName);
REG_ENTRY_TYPE otype = REG_ENTRY_ROOT;
DWORD entryBufferLength = FIELD_OFFSET(RegPidlEntry, entryName) + sizeof(WCHAR) + cchName * 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;
entry->rootKey = rootKeys[i].key;
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);
}
DPA_AppendPtr(hdpa, entry);
(*hdpaCount)++;
}
return S_OK;
}
HRESULT ReadRegistryValue(HKEY root, PCWSTR path, PCWSTR valueName, PVOID * valueData, PDWORD valueLength) HRESULT ReadRegistryValue(HKEY root, PCWSTR path, PCWSTR valueName, PVOID * valueData, PDWORD valueLength)
{ {
HKEY hkey; HKEY hkey;

View file

@ -72,6 +72,7 @@ struct NtPidlSymlinkData
// REGISTRY browser // REGISTRY browser
enum REG_ENTRY_TYPE enum REG_ENTRY_TYPE
{ {
REG_ENTRY_ROOT,
REG_ENTRY_KEY, REG_ENTRY_KEY,
REG_ENTRY_VALUE, REG_ENTRY_VALUE,
REG_ENTRY_VALUE_WITH_CONTENT REG_ENTRY_VALUE_WITH_CONTENT
@ -88,10 +89,16 @@ struct RegPidlEntry
USHORT entryNameLength; USHORT entryNameLength;
union {
struct {
// For Value entries, this contains the value contents, if it's resonably small. // For Value entries, this contains the value contents, if it's resonably small.
// For Key entries, this contains the custom class name // For Key entries, this contains the custom class name
DWORD contentType; DWORD contentType;
USHORT contentsLength; USHORT contentsLength;
};
HKEY rootKey;
};
WCHAR entryName[ANYSIZE_ARRAY]; WCHAR entryName[ANYSIZE_ARRAY];
@ -102,5 +109,6 @@ struct RegPidlEntry
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); HRESULT EnumerateRegistryKey(HDPA hdpa, PCWSTR path, HKEY root, UINT * hdpaCount);
HRESULT EnumerateRootKeys(HDPA hdpa, UINT * hdpaCount);
HRESULT ReadRegistryValue(HKEY root, PCWSTR path, PCWSTR valueName, PVOID * valueData, PDWORD valueLength); HRESULT ReadRegistryValue(HKEY root, PCWSTR path, PCWSTR valueName, PVOID * valueData, PDWORD valueLength);

View file

@ -86,6 +86,7 @@ public:
switch (entry->entryType) switch (entry->entryType)
{ {
case REG_ENTRY_KEY: case REG_ENTRY_KEY:
case REG_ENTRY_ROOT:
GetModuleFileNameW(g_hInstance, szIconFile, cchMax); GetModuleFileNameW(g_hInstance, szIconFile, cchMax);
*piIndex = -IDI_REGISTRYKEY; *piIndex = -IDI_REGISTRYKEY;
*pwFlags = flags; *pwFlags = flags;
@ -126,6 +127,7 @@ class CRegistryPidlManager
{ {
private: private:
PWSTR m_ntPath; PWSTR m_ntPath;
HKEY m_hRoot;
HDPA m_hDpa; HDPA m_hDpa;
UINT m_hDpaCount; UINT m_hDpaCount;
@ -146,6 +148,7 @@ private:
public: public:
CRegistryPidlManager() : CRegistryPidlManager() :
m_ntPath(NULL), m_ntPath(NULL),
m_hRoot(NULL),
m_hDpa(NULL), m_hDpa(NULL),
m_hDpaCount(0) m_hDpaCount(0)
{ {
@ -156,18 +159,28 @@ public:
DPA_DestroyCallback(m_hDpa, s_DpaDeleteCallback, this); DPA_DestroyCallback(m_hDpa, s_DpaDeleteCallback, this);
} }
HRESULT Initialize(PWSTR ntPath) HRESULT Initialize(PWSTR ntPath, HKEY hRoot)
{ {
m_ntPath = ntPath; m_ntPath = ntPath;
m_hRoot = hRoot;
m_hDpa = DPA_Create(10); m_hDpa = DPA_Create(10);
if (!m_hDpa) if (!m_hDpa)
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
HRESULT hr = EnumerateRegistryKey(m_hDpa, m_ntPath, NULL, &m_hDpaCount); if (wcslen(m_ntPath) == 0 && m_hRoot == NULL)
{
HRESULT hr = EnumerateRootKeys(m_hDpa, &m_hDpaCount);
if (FAILED_UNEXPECTEDLY(hr)) if (FAILED_UNEXPECTEDLY(hr))
return hr; return hr;
}
else
{
HRESULT hr = EnumerateRegistryKey(m_hDpa, m_ntPath, m_hRoot, &m_hDpaCount);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
}
return S_OK; return S_OK;
} }
@ -346,7 +359,8 @@ public:
ULONG mask = inMask ? *inMask : 0xFFFFFFFF; ULONG mask = inMask ? *inMask : 0xFFFFFFFF;
ULONG flags = 0; ULONG flags = 0;
if (entry->entryType == REG_ENTRY_KEY) if ((entry->entryType == REG_ENTRY_KEY) ||
(entry->entryType == REG_ENTRY_ROOT))
flags |= SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_BROWSABLE; flags |= SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_BROWSABLE;
return flags & mask; return flags & mask;
@ -359,7 +373,8 @@ public:
if (FAILED_UNEXPECTEDLY(hr)) if (FAILED_UNEXPECTEDLY(hr))
return FALSE; return FALSE;
return (entry->entryType == REG_ENTRY_KEY); return (entry->entryType == REG_ENTRY_KEY) ||
(entry->entryType == REG_ENTRY_ROOT);
} }
HRESULT FormatValueData(DWORD contentType, PVOID td, DWORD contentsLength, PCWSTR * strContents) HRESULT FormatValueData(DWORD contentType, PVOID td, DWORD contentsLength, PCWSTR * strContents)
@ -430,7 +445,14 @@ public:
DWORD valueLength; DWORD valueLength;
HRESULT hr = ReadRegistryValue(NULL, m_ntPath, info->entryName, &valueData, &valueLength); HRESULT hr = ReadRegistryValue(NULL, m_ntPath, info->entryName, &valueData, &valueLength);
if (FAILED_UNEXPECTEDLY(hr)) if (FAILED_UNEXPECTEDLY(hr))
return hr; {
PCWSTR strEmpty = L"(Error reading value)";
DWORD bufferLength = (wcslen(strEmpty) + 1) * sizeof(WCHAR);
PWSTR strValue = (PWSTR) CoTaskMemAlloc(bufferLength);
StringCbCopyW(strValue, bufferLength, strEmpty);
*strContents = strValue;
return S_OK;
}
if (valueLength > 0) if (valueLength > 0)
{ {
@ -522,6 +544,7 @@ public:
switch (tinfo->entryType) switch (tinfo->entryType)
{ {
case REG_ENTRY_KEY: case REG_ENTRY_KEY:
case REG_ENTRY_ROOT:
flagsOk = (m_Flags & SHCONTF_FOLDERS) != 0; flagsOk = (m_Flags & SHCONTF_FOLDERS) != 0;
break; break;
default: default:
@ -651,19 +674,26 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::BindToObject(
if (FAILED_UNEXPECTEDLY(hr)) if (FAILED_UNEXPECTEDLY(hr))
return hr; return hr;
WCHAR path[MAX_PATH];
StringCbCopyW(path, _countof(path), m_NtPath);
PathAppendW(path, info->entryName);
LPITEMIDLIST first = ILCloneFirst(pidl); LPITEMIDLIST first = ILCloneFirst(pidl);
LPCITEMIDLIST rest = ILGetNext(pidl); LPCITEMIDLIST rest = ILGetNext(pidl);
LPITEMIDLIST fullPidl = ILCombine(m_shellPidl, first); LPITEMIDLIST fullPidl = ILCombine(m_shellPidl, first);
CComPtr<IShellFolder> psfChild; CComPtr<IShellFolder> psfChild;
hr = ShellObjectCreatorInit<CRegistryFolder>(fullPidl, path, IID_PPV_ARG(IShellFolder, &psfChild)); if (wcslen(m_NtPath) == 0 && m_hRoot == NULL)
{
hr = ShellObjectCreatorInit<CRegistryFolder>(fullPidl, L"", info->rootKey, IID_PPV_ARG(IShellFolder, &psfChild));
}
else
{
WCHAR path[MAX_PATH];
StringCbCopyW(path, _countof(path), m_NtPath);
PathAppendW(path, info->entryName);
hr = ShellObjectCreatorInit<CRegistryFolder>(fullPidl, path, m_hRoot, IID_PPV_ARG(IShellFolder, &psfChild));
}
ILFree(fullPidl); ILFree(fullPidl);
ILFree(first); ILFree(first);
@ -928,8 +958,9 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::GetClassID(CLSID *lpClassId)
HRESULT STDMETHODCALLTYPE CRegistryFolder::Initialize(LPCITEMIDLIST pidl) HRESULT STDMETHODCALLTYPE CRegistryFolder::Initialize(LPCITEMIDLIST pidl)
{ {
m_shellPidl = ILClone(pidl); m_shellPidl = ILClone(pidl);
m_hRoot = NULL;
PCWSTR ntPath = L"\\REGISTRY"; PCWSTR ntPath = L"";
if (!m_PidlManager) if (!m_PidlManager)
{ {
@ -938,19 +969,20 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::Initialize(LPCITEMIDLIST pidl)
StringCbCopy(m_NtPath, _countof(m_NtPath), ntPath); StringCbCopy(m_NtPath, _countof(m_NtPath), ntPath);
} }
return m_PidlManager->Initialize(m_NtPath); return m_PidlManager->Initialize(m_NtPath, m_hRoot);
} }
// Internal // Internal
HRESULT STDMETHODCALLTYPE CRegistryFolder::Initialize(LPCITEMIDLIST pidl, PCWSTR ntPath) HRESULT STDMETHODCALLTYPE CRegistryFolder::Initialize(LPCITEMIDLIST pidl, PCWSTR ntPath, HKEY hRoot)
{ {
m_shellPidl = ILClone(pidl); m_shellPidl = ILClone(pidl);
m_hRoot = hRoot;
if (!m_PidlManager) if (!m_PidlManager)
m_PidlManager = new CRegistryPidlManager(); m_PidlManager = new CRegistryPidlManager();
StringCbCopy(m_NtPath, _countof(m_NtPath), ntPath); StringCbCopy(m_NtPath, _countof(m_NtPath), ntPath);
return m_PidlManager->Initialize(m_NtPath); return m_PidlManager->Initialize(m_NtPath, m_hRoot);
} }
// IPersistFolder2 // IPersistFolder2
@ -1039,6 +1071,11 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDetailsEx(
} }
else if (pscid->pid == PID_STG_STORAGETYPE) else if (pscid->pid == PID_STG_STORAGETYPE)
{ {
if (info->entryType == REG_ENTRY_ROOT)
{
return MakeVariantString(pv, L"Key");
}
if (info->entryType == REG_ENTRY_KEY) if (info->entryType == REG_ENTRY_KEY)
{ {
if (info->contentsLength > 0) if (info->contentsLength > 0)
@ -1109,6 +1146,11 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDetailsOf(
case REGISTRY_COLUMN_TYPE: case REGISTRY_COLUMN_TYPE:
psd->fmt = LVCFMT_LEFT; psd->fmt = LVCFMT_LEFT;
if (info->entryType == REG_ENTRY_ROOT)
{
return MakeStrRetFromString(L"Key", &(psd->str));
}
if (info->entryType == REG_ENTRY_KEY) if (info->entryType == REG_ENTRY_KEY)
{ {
if (info->contentsLength > 0) if (info->contentsLength > 0)

View file

@ -21,6 +21,7 @@ class CRegistryFolder :
{ {
CRegistryPidlManager * m_PidlManager; CRegistryPidlManager * m_PidlManager;
HKEY m_hRoot;
WCHAR m_NtPath[MAX_PATH]; WCHAR m_NtPath[MAX_PATH];
LPITEMIDLIST m_shellPidl; LPITEMIDLIST m_shellPidl;
@ -136,11 +137,11 @@ public:
virtual HRESULT STDMETHODCALLTYPE MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam); virtual HRESULT STDMETHODCALLTYPE MessageSFVCB(UINT uMsg, WPARAM wParam, LPARAM lParam);
// Internal // Internal
HRESULT STDMETHODCALLTYPE Initialize(LPCITEMIDLIST pidl, PCWSTR ntPath); HRESULT STDMETHODCALLTYPE Initialize(LPCITEMIDLIST pidl, PCWSTR ntPath, HKEY hRoot);
static HRESULT CALLBACK DefCtxMenuCallback(IShellFolder *, HWND, IDataObject *, UINT, WPARAM, LPARAM); static HRESULT CALLBACK DefCtxMenuCallback(IShellFolder *, HWND, IDataObject *, UINT, WPARAM, LPARAM);
DECLARE_REGISTRY_RESOURCEID(IDR_NTOBJECTFOLDER) DECLARE_REGISTRY_RESOURCEID(IDR_REGISTRYFOLDER)
DECLARE_NOT_AGGREGATABLE(CRegistryFolder) DECLARE_NOT_AGGREGATABLE(CRegistryFolder)
DECLARE_PROTECT_FINAL_CONSTRUCT() DECLARE_PROTECT_FINAL_CONSTRUCT()

View file

@ -6,10 +6,11 @@
#define IDI_NTOBJECTITEM 4 #define IDI_NTOBJECTITEM 4
#define IDI_NTOBJECTDEVICE 5 #define IDI_NTOBJECTDEVICE 5
#define IDI_NTOBJECTPORT 6 #define IDI_NTOBJECTPORT 6
#define IDI_REGISTRYKEY 7
#define IDI_REGISTRYVALUE 8
#define IDI_REGISTRYKEY 32 #define IDS_NTOBJFLD_NAME 101
#define IDI_REGISTRYVALUE 33 #define IDS_REGISTRY_NAME 102
#define IDS_NAME 101
#define IDR_NTOBJECTFOLDER 1001 #define IDR_NTOBJECTFOLDER 1001
#define IDR_REGISTRYFOLDER 1002

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View file

@ -7,7 +7,7 @@ HKCR
NTObjShEx.NTDirectory = s 'NT Namespace Directory Class' NTObjShEx.NTDirectory = s 'NT Namespace Directory Class'
{ {
CLSID = s '{845B0FB2-66E0-416B-8F91-314E23F7C12D}' CLSID = s '{845B0FB2-66E0-416B-8F91-314E23F7C12D}'
CurVer = s 'WMIFldr.CWMIFldr.1' CurVer = s 'NTObjShEx.NTDirectory.1'
} }
NoRemove CLSID NoRemove CLSID
{ {
@ -20,6 +20,7 @@ HKCR
val ThreadingModel = s 'Both' val ThreadingModel = s 'Both'
} }
val InfoTip = s 'Allows browsing of the NT Object Namespace' val InfoTip = s 'Allows browsing of the NT Object Namespace'
val LocalizedString = s '@%MODULE%,-101'
DefaultIcon = s '%MODULE%,0' DefaultIcon = s '%MODULE%,0'
ShellFolder ShellFolder
{ {
@ -45,7 +46,7 @@ HKLM
{ {
NoRemove NameSpace NoRemove NameSpace
{ {
ForceRemove {845B0FB2-66E0-416B-8F91-314E23F7C12D} = s 'NT Object Namespace Extension' ForceRemove {845B0FB2-66E0-416B-8F91-314E23F7C12D} = s 'NT Object Namespace'
{ {
} }
} }

View file

@ -0,0 +1,59 @@
HKCR
{
NTObjShEx.RegFolder.1 = s 'Registry Folder Class'
{
CLSID = s '{1C6D6E08-2332-4A7B-A94D-6432DB2B5AE6}'
}
NTObjShEx.RegFolder = s 'Registry Folder Class'
{
CLSID = s '{1C6D6E08-2332-4A7B-A94D-6432DB2B5AE6}'
CurVer = s 'NTObjShEx.RegFolder.1'
}
NoRemove CLSID
{
ForceRemove {1C6D6E08-2332-4A7B-A94D-6432DB2B5AE6} = s 'System Registry Namespace Extension'
{
ProgID = s 'NTObjShEx.RegFolder.1'
VersionIndependentProgID = s 'NTObjShEx.RegFolder'
InprocServer32 = s '%MODULE%'
{
val ThreadingModel = s 'Both'
}
val InfoTip = s 'Allows browsing of the System Registry'
val LocalizedString = s '@%MODULE%,-102'
DefaultIcon = s '%MODULE%,-7'
ShellFolder
{
val Attributes = d '0xA8000000'
val BrowserFlags = d '0x22'
}
}
}
}
HKLM
{
NoRemove Software
{
NoRemove Microsoft
{
NoRemove Windows
{
NoRemove CurrentVersion
{
NoRemove Explorer
{
NoRemove MyComputer
{
NoRemove NameSpace
{
ForceRemove {1C6D6E08-2332-4A7B-A94D-6432DB2B5AE6} = s 'System Registry'
{
}
}
}
}
}
}
}
}
}