[NTOBJSHEX]

* Replace the custom context menu classes with the default implementation from shell32. As a side-effect, navigation now works in ReactOS.
* Make use of the default implementations of IDataObject and IQueryAssociations from shell32 (required by the IContextMenu implementation of Win2003).
* Fix initialization of the NT Object Folder's pidl.
* Make CompareIDs recursive.
* Fix the recursivity in GetDisplayNameOf, when called with FORPARSING.
NOTE: There is still some issue with GetDisplayNameOf, where the address shown in the addressbar seems to skip path components.

svn path=/trunk/; revision=66674
This commit is contained in:
David Quintana 2015-03-14 03:15:36 +00:00
parent d2d2431614
commit 6928fadeff
6 changed files with 257 additions and 338 deletions

View file

@ -11,6 +11,11 @@
#include <ntquery.h> #include <ntquery.h>
#include "util.h" #include "util.h"
#define DFM_MERGECONTEXTMENU 1 // uFlags LPQCMINFO
#define DFM_INVOKECOMMAND 2 // idCmd pszArgs
#define DFM_INVOKECOMMANDEX 12 // idCmd PDFMICS
#define DFM_GETDEFSTATICID 14 // idCmd * 0
#define SHCIDS_ALLFIELDS 0x80000000L #define SHCIDS_ALLFIELDS 0x80000000L
#define SHCIDS_CANONICALONLY 0x10000000L #define SHCIDS_CANONICALONLY 0x10000000L
@ -33,158 +38,6 @@ enum NtObjectColumns
NTOBJECT_COLUMN_LINKTARGET = 3, NTOBJECT_COLUMN_LINKTARGET = 3,
}; };
class CNtObjectFolderContextMenu :
public CComObjectRootEx<CComMultiThreadModelNoCS>,
public IContextMenu
{
PCIDLIST_ABSOLUTE m_pcidlFolder;
PCITEMID_CHILD m_pcidlChild;
UINT m_idFirst;
enum ItemOffsets
{
ITEM_Open = 0,
ITEM_OpenNewWindow
};
public:
CNtObjectFolderContextMenu() :
m_pcidlFolder(NULL),
m_pcidlChild(NULL),
m_idFirst(0)
{
}
virtual ~CNtObjectFolderContextMenu()
{
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)
{
MENUITEMINFOW mii;
m_idFirst = idCmdFirst;
const NtPidlEntry * entry = (NtPidlEntry *) m_pcidlChild;
static WCHAR open [] = L"Open";
static WCHAR opennewwindow [] = L"Open in new window";
if ((entry->objectType == DIRECTORY_OBJECT) ||
(entry->objectType == SYMBOLICLINK_OBJECT) ||
(entry->objectType == KEY_OBJECT))
{
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 = m_idFirst + ITEM_Open);
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 = m_idFirst + ITEM_OpenNewWindow);
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)
{
LPITEMIDLIST fullPidl = ILCombine(m_pcidlFolder, m_pcidlChild);
if (LOWORD(lpici->lpVerb) == (m_idFirst + ITEM_Open) || !lpici->lpVerb)
{
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 + ITEM_OpenNewWindow))
{
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(CNtObjectFolderContextMenu)
DECLARE_PROTECT_FINAL_CONSTRUCT()
BEGIN_COM_MAP(CNtObjectFolderContextMenu)
COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
END_COM_MAP()
};
class CNtObjectFolderExtractIcon : class CNtObjectFolderExtractIcon :
public CComObjectRootEx<CComMultiThreadModelNoCS>, public CComObjectRootEx<CComMultiThreadModelNoCS>,
public IExtractIconW public IExtractIconW
@ -517,6 +370,17 @@ public:
return flags & mask; return flags & mask;
} }
BOOL IsFolder(LPCITEMIDLIST pcidl)
{
NtPidlEntry * entry;
HRESULT hr = FindPidlInList(pcidl, &entry);
if (FAILED_UNEXPECTEDLY(hr))
return FALSE;
return (entry->objectType == DIRECTORY_OBJECT) ||
(entry->objectType == SYMBOLICLINK_OBJECT) ||
(entry->objectType == KEY_OBJECT);
}
}; };
class CNtObjectFolderEnum : class CNtObjectFolderEnum :
@ -716,7 +580,9 @@ HRESULT STDMETHODCALLTYPE CNtObjectFolder::BindToObject(
return E_ACCESSDENIED; return E_ACCESSDENIED;
WCHAR path[MAX_PATH]; WCHAR path[MAX_PATH];
StringCbCopyW(path, _countof(path), m_NtPath); StringCbCopyW(path, _countof(path), m_NtPath);
PathAppendW(path, info->entryName); PathAppendW(path, info->entryName);
LPITEMIDLIST first = ILCloneFirst(pidl); LPITEMIDLIST first = ILCloneFirst(pidl);
@ -795,7 +661,36 @@ HRESULT STDMETHODCALLTYPE CNtObjectFolder::CompareIDs(
LPCITEMIDLIST pidl2) LPCITEMIDLIST pidl2)
{ {
TRACE("CompareIDs\n"); TRACE("CompareIDs\n");
return m_PidlManager->CompareIDs(lParam, pidl1, pidl2);
HRESULT hr = m_PidlManager->CompareIDs(lParam, pidl1, pidl2);
if (hr != S_OK)
return hr;
LPCITEMIDLIST rest1 = ILGetNext(pidl1);
LPCITEMIDLIST rest2 = ILGetNext(pidl2);
bool hasNext1 = (rest1->mkid.cb > 0);
bool hasNext2 = (rest2->mkid.cb > 0);
if (hasNext1 || hasNext2)
{
if (hasNext1 && !hasNext2)
return MAKE_HRESULT(0, 0, (USHORT) -1);
if (hasNext2 && !hasNext1)
return MAKE_HRESULT(0, 0, (USHORT) 1);
LPCITEMIDLIST first1 = ILCloneFirst(pidl1);
CComPtr<IShellFolder> psfNext;
hr = BindToObject(first1, NULL, IID_PPV_ARG(IShellFolder, &psfNext));
if (FAILED_UNEXPECTEDLY(hr))
return hr;
return psfNext->CompareIDs(lParam, rest1, rest2);
}
return S_OK;
} }
HRESULT STDMETHODCALLTYPE CNtObjectFolder::CreateViewObject( HRESULT STDMETHODCALLTYPE CNtObjectFolder::CreateViewObject(
@ -856,10 +751,29 @@ HRESULT STDMETHODCALLTYPE CNtObjectFolder::GetUIObjectOf(
{ {
TRACE("GetUIObjectOf\n"); TRACE("GetUIObjectOf\n");
if (IsEqualIID(riid, IID_IContextMenu)) if (IsEqualIID(riid, IID_IContextMenu) ||
IsEqualIID(riid, IID_IContextMenu2) ||
IsEqualIID(riid, IID_IContextMenu3))
{ {
return ShellObjectCreatorInit<CNtObjectFolderContextMenu>(m_shellPidl, cidl, apidl, riid, ppvOut); CComPtr<IContextMenu> pcm;
//return CDefFolderMenu_Create2(m_shellPidl, hwndOwner, cidl, apidl, this, ContextMenuCallback, 0, NULL, (IContextMenu**) ppvOut);
HKEY keys [1];
int nkeys = _countof(keys);
if (cidl == 1 && m_PidlManager->IsFolder(apidl[0]))
{
RegOpenKey(HKEY_CLASSES_ROOT, L"Folder", keys + 0);
}
else
{
nkeys = 0;
}
HRESULT hr = CDefFolderMenu_Create2(m_shellPidl, hwndOwner, cidl, apidl, this, DefCtxMenuCallback, nkeys, keys, &pcm);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
return pcm->QueryInterface(riid, ppvOut);
} }
if (IsEqualIID(riid, IID_IExtractIconW)) if (IsEqualIID(riid, IID_IExtractIconW))
@ -867,6 +781,28 @@ HRESULT STDMETHODCALLTYPE CNtObjectFolder::GetUIObjectOf(
return ShellObjectCreatorInit<CNtObjectFolderExtractIcon>(m_shellPidl, cidl, apidl, riid, ppvOut); return ShellObjectCreatorInit<CNtObjectFolderExtractIcon>(m_shellPidl, cidl, apidl, riid, ppvOut);
} }
if (IsEqualIID(riid, IID_IDataObject))
{
return CIDLData_CreateFromIDArray(m_shellPidl, cidl, apidl, (IDataObject**)ppvOut);
}
if (IsEqualIID(riid, IID_IQueryAssociations))
{
if (cidl == 1 && m_PidlManager->IsFolder(apidl[0]))
{
CComPtr<IQueryAssociations> pqa;
HRESULT hr = AssocCreate(CLSID_QueryAssociations, IID_PPV_ARG(IQueryAssociations, &pqa));
if (FAILED_UNEXPECTEDLY(hr))
return hr;
hr = pqa->Init(ASSOCF_INIT_DEFAULTTOFOLDER, L"NTObjShEx.NTDirectory", NULL, hwndOwner);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
return pqa->QueryInterface(riid, ppvOut);
}
}
return E_NOTIMPL; return E_NOTIMPL;
} }
@ -899,12 +835,13 @@ HRESULT STDMETHODCALLTYPE CNtObjectFolder::GetDisplayNameOf(
if (FAILED_UNEXPECTEDLY(hr)) if (FAILED_UNEXPECTEDLY(hr))
return hr; return hr;
LPCITEMIDLIST pidlFirst = ILCloneFirst(pidl);
LPCITEMIDLIST pidlNext = ILGetNext(pidl); LPCITEMIDLIST pidlNext = ILGetNext(pidl);
if (pidlNext && pidlNext->mkid.cb > 0) if (pidlNext && pidlNext->mkid.cb > 0)
{ {
CComPtr<IShellFolder> psfChild; CComPtr<IShellFolder> psfChild;
hr = BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfChild)); hr = BindToObject(pidlFirst, NULL, IID_PPV_ARG(IShellFolder, &psfChild));
if (FAILED_UNEXPECTEDLY(hr)) if (FAILED_UNEXPECTEDLY(hr))
return hr; return hr;
@ -921,6 +858,8 @@ HRESULT STDMETHODCALLTYPE CNtObjectFolder::GetDisplayNameOf(
PathAppendW(path, temp); PathAppendW(path, temp);
} }
ILFree((LPITEMIDLIST)pidlFirst);
} }
else else
{ {
@ -971,7 +910,7 @@ HRESULT STDMETHODCALLTYPE CNtObjectFolder::Initialize(LPCITEMIDLIST pidl)
// Internal // Internal
HRESULT STDMETHODCALLTYPE CNtObjectFolder::Initialize(LPCITEMIDLIST pidl, PCWSTR ntPath) HRESULT STDMETHODCALLTYPE CNtObjectFolder::Initialize(LPCITEMIDLIST pidl, PCWSTR ntPath)
{ {
TRACE("INITIALIZE %p CNtObjectFolder with ntPath %S\n", this, ntPath); m_shellPidl = ILClone(pidl);
if (!m_PidlManager) if (!m_PidlManager)
m_PidlManager = new CNtObjectPidlManager(); m_PidlManager = new CNtObjectPidlManager();
@ -1273,3 +1212,17 @@ HRESULT STDMETHODCALLTYPE CNtObjectFolder::MessageSFVCB(UINT uMsg, WPARAM wParam
} }
return E_NOTIMPL; return E_NOTIMPL;
} }
HRESULT CNtObjectFolder::DefCtxMenuCallback(IShellFolder * /*psf*/, HWND /*hwnd*/, IDataObject * /*pdtobj*/, UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/)
{
switch (uMsg)
{
case DFM_MERGECONTEXTMENU:
return S_OK;
case DFM_INVOKECOMMAND:
case DFM_INVOKECOMMANDEX:
case DFM_GETDEFSTATICID: // Required for Windows 7 to pick a default
return S_FALSE;
}
return E_NOTIMPL;
}

View file

@ -137,6 +137,8 @@ public:
// Internal // Internal
HRESULT STDMETHODCALLTYPE Initialize(LPCITEMIDLIST pidl, PCWSTR ntPath); HRESULT STDMETHODCALLTYPE Initialize(LPCITEMIDLIST pidl, PCWSTR ntPath);
static HRESULT CALLBACK DefCtxMenuCallback(IShellFolder *, HWND, IDataObject *, UINT, WPARAM, LPARAM);
DECLARE_REGISTRY_RESOURCEID(IDR_NTOBJECTFOLDER) DECLARE_REGISTRY_RESOURCEID(IDR_NTOBJECTFOLDER)
DECLARE_NOT_AGGREGATABLE(CNtObjectFolder) DECLARE_NOT_AGGREGATABLE(CNtObjectFolder)
DECLARE_PROTECT_FINAL_CONSTRUCT() DECLARE_PROTECT_FINAL_CONSTRUCT()

View file

@ -93,7 +93,7 @@ struct RegPidlEntry
DWORD contentType; DWORD contentType;
USHORT contentsLength; USHORT contentsLength;
WCHAR entryName[0]; WCHAR entryName[ANYSIZE_ARRAY];
}; };

View file

@ -1,16 +1,21 @@
/* /*
* PROJECT: ReactOS shell extensions * PROJECT: ReactOS shell extensions
* LICENSE: GPL - See COPYING in the top level directory * LICENSE: GPL - See COPYING in the top level directory
* FILE: dll\shellext\ntobjshex\ntobjns.cpp * FILE: dll\shellext\ntobjshex\ntobjns.cpp
* PURPOSE: NT Object Namespace shell extension * PURPOSE: NT Object Namespace shell extension
* PROGRAMMERS: David Quintana <gigaherz@gmail.com> * PROGRAMMERS: David Quintana <gigaherz@gmail.com>
*/ */
#include "precomp.h" #include "precomp.h"
#include "ntobjutil.h" #include "ntobjutil.h"
#include <ntquery.h> #include <ntquery.h>
#include "util.h" #include "util.h"
#define DFM_MERGECONTEXTMENU 1 // uFlags LPQCMINFO
#define DFM_INVOKECOMMAND 2 // idCmd pszArgs
#define DFM_INVOKECOMMANDEX 12 // idCmd PDFMICS
#define DFM_GETDEFSTATICID 14 // idCmd * 0
#define SHCIDS_ALLFIELDS 0x80000000L #define SHCIDS_ALLFIELDS 0x80000000L
#define SHCIDS_CANONICALONLY 0x10000000L #define SHCIDS_CANONICALONLY 0x10000000L
@ -32,156 +37,6 @@ enum RegistryColumns
REGISTRY_COLUMN_VALUE = 2, REGISTRY_COLUMN_VALUE = 2,
}; };
class CRegistryFolderContextMenu :
public CComObjectRootEx<CComMultiThreadModelNoCS>,
public IContextMenu
{
PCIDLIST_ABSOLUTE m_pcidlFolder;
PCITEMID_CHILD m_pcidlChild;
UINT m_idFirst;
enum ItemOffsets
{
ITEM_Open = 0,
ITEM_OpenNewWindow
};
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)
{
MENUITEMINFOW mii;
m_idFirst = idCmdFirst;
const RegPidlEntry * entry = (RegPidlEntry *) m_pcidlChild;
static WCHAR open [] = L"Open";
static WCHAR opennewwindow [] = L"Open in new window";
if (entry->entryType == REG_ENTRY_KEY)
{
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 = m_idFirst + ITEM_Open);
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 = m_idFirst + ITEM_OpenNewWindow);
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)
{
LPITEMIDLIST fullPidl = ILCombine(m_pcidlFolder, m_pcidlChild);
if (LOWORD(lpici->lpVerb) == (m_idFirst + ITEM_Open) || !lpici->lpVerb)
{
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 + ITEM_OpenNewWindow))
{
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 : class CRegistryFolderExtractIcon :
public CComObjectRootEx<CComMultiThreadModelNoCS>, public CComObjectRootEx<CComMultiThreadModelNoCS>,
public IExtractIconW public IExtractIconW
@ -497,6 +352,16 @@ public:
return flags & mask; return flags & mask;
} }
BOOL IsFolder(LPCITEMIDLIST pcidl)
{
RegPidlEntry * entry;
HRESULT hr = FindPidlInList(pcidl, &entry);
if (FAILED_UNEXPECTEDLY(hr))
return FALSE;
return (entry->entryType == REG_ENTRY_KEY);
}
HRESULT FormatContentsForDisplay(RegPidlEntry * info, PCWSTR * strContents) HRESULT FormatContentsForDisplay(RegPidlEntry * info, PCWSTR * strContents)
{ {
PVOID td = (((PBYTE) info) + FIELD_OFFSET(RegPidlEntry, entryName) + info->entryNameLength + sizeof(WCHAR)); PVOID td = (((PBYTE) info) + FIELD_OFFSET(RegPidlEntry, entryName) + info->entryNameLength + sizeof(WCHAR));
@ -565,7 +430,6 @@ public:
} }
} }
}; };
class CRegistryFolderEnum : class CRegistryFolderEnum :
@ -803,7 +667,36 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::CompareIDs(
LPCITEMIDLIST pidl2) LPCITEMIDLIST pidl2)
{ {
TRACE("CompareIDs\n"); TRACE("CompareIDs\n");
return m_PidlManager->CompareIDs(lParam, pidl1, pidl2);
HRESULT hr = m_PidlManager->CompareIDs(lParam, pidl1, pidl2);
if (hr != S_OK)
return hr;
LPCITEMIDLIST rest1 = ILGetNext(pidl1);
LPCITEMIDLIST rest2 = ILGetNext(pidl2);
bool hasNext1 = (rest1->mkid.cb > 0);
bool hasNext2 = (rest2->mkid.cb > 0);
if (hasNext1 || hasNext2)
{
if (hasNext1 && !hasNext2)
return MAKE_HRESULT(0, 0, (USHORT) -1);
if (hasNext2 && !hasNext1)
return MAKE_HRESULT(0, 0, (USHORT) 1);
LPCITEMIDLIST first1 = ILCloneFirst(pidl1);
CComPtr<IShellFolder> psfNext;
hr = BindToObject(first1, NULL, IID_PPV_ARG(IShellFolder, &psfNext));
if (FAILED_UNEXPECTEDLY(hr))
return hr;
return psfNext->CompareIDs(lParam, rest1, rest2);
}
return S_OK;
} }
HRESULT STDMETHODCALLTYPE CRegistryFolder::CreateViewObject( HRESULT STDMETHODCALLTYPE CRegistryFolder::CreateViewObject(
@ -864,10 +757,29 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::GetUIObjectOf(
{ {
TRACE("GetUIObjectOf\n"); TRACE("GetUIObjectOf\n");
if (IsEqualIID(riid, IID_IContextMenu)) if (IsEqualIID(riid, IID_IContextMenu) ||
IsEqualIID(riid, IID_IContextMenu2) ||
IsEqualIID(riid, IID_IContextMenu3))
{ {
return ShellObjectCreatorInit<CRegistryFolderContextMenu>(m_shellPidl, cidl, apidl, riid, ppvOut); CComPtr<IContextMenu> pcm;
//return CDefFolderMenu_Create2(m_shellPidl, hwndOwner, cidl, apidl, this, ContextMenuCallback, 0, NULL, (IContextMenu**) ppvOut);
HKEY keys [1];
int nkeys = _countof(keys);
if (cidl == 1 && m_PidlManager->IsFolder(apidl[0]))
{
RegOpenKey(HKEY_CLASSES_ROOT, L"Folder", keys + 0);
}
else
{
nkeys = 0;
}
HRESULT hr = CDefFolderMenu_Create2(m_shellPidl, hwndOwner, cidl, apidl, this, DefCtxMenuCallback, nkeys, keys, &pcm);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
return pcm->QueryInterface(riid, ppvOut);
} }
if (IsEqualIID(riid, IID_IExtractIconW)) if (IsEqualIID(riid, IID_IExtractIconW))
@ -875,6 +787,28 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::GetUIObjectOf(
return ShellObjectCreatorInit<CRegistryFolderExtractIcon>(m_shellPidl, cidl, apidl, riid, ppvOut); return ShellObjectCreatorInit<CRegistryFolderExtractIcon>(m_shellPidl, cidl, apidl, riid, ppvOut);
} }
if (IsEqualIID(riid, IID_IDataObject))
{
return CIDLData_CreateFromIDArray(m_shellPidl, cidl, apidl, (IDataObject**) ppvOut);
}
if (IsEqualIID(riid, IID_IQueryAssociations))
{
if (cidl == 1 && m_PidlManager->IsFolder(apidl[0]))
{
CComPtr<IQueryAssociations> pqa;
HRESULT hr = AssocCreate(CLSID_QueryAssociations, IID_PPV_ARG(IQueryAssociations, &pqa));
if (FAILED_UNEXPECTEDLY(hr))
return hr;
hr = pqa->Init(ASSOCF_INIT_DEFAULTTOFOLDER, L"NTObjShEx.RegFolder", NULL, hwndOwner);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
return pqa->QueryInterface(riid, ppvOut);
}
}
return E_NOTIMPL; return E_NOTIMPL;
} }
@ -907,12 +841,13 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDisplayNameOf(
if (FAILED_UNEXPECTEDLY(hr)) if (FAILED_UNEXPECTEDLY(hr))
return hr; return hr;
LPCITEMIDLIST pidlFirst = ILCloneFirst(pidl);
LPCITEMIDLIST pidlNext = ILGetNext(pidl); LPCITEMIDLIST pidlNext = ILGetNext(pidl);
if (pidlNext && pidlNext->mkid.cb > 0) if (pidlNext && pidlNext->mkid.cb > 0)
{ {
CComPtr<IShellFolder> psfChild; CComPtr<IShellFolder> psfChild;
hr = BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfChild)); hr = BindToObject(pidlFirst, NULL, IID_PPV_ARG(IShellFolder, &psfChild));
if (FAILED_UNEXPECTEDLY(hr)) if (FAILED_UNEXPECTEDLY(hr))
return hr; return hr;
@ -929,6 +864,8 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::GetDisplayNameOf(
PathAppendW(path, temp); PathAppendW(path, temp);
} }
ILFree((LPITEMIDLIST) pidlFirst);
} }
else else
{ {
@ -1219,3 +1156,17 @@ HRESULT STDMETHODCALLTYPE CRegistryFolder::MessageSFVCB(UINT uMsg, WPARAM wParam
} }
return E_NOTIMPL; return E_NOTIMPL;
} }
HRESULT CRegistryFolder::DefCtxMenuCallback(IShellFolder * /*psf*/, HWND /*hwnd*/, IDataObject * /*pdtobj*/, UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/)
{
switch (uMsg)
{
case DFM_MERGECONTEXTMENU:
return S_OK;
case DFM_INVOKECOMMAND:
case DFM_INVOKECOMMANDEX:
case DFM_GETDEFSTATICID: // Required for Windows 7 to pick a default
return S_FALSE;
}
return E_NOTIMPL;
}

View file

@ -138,6 +138,8 @@ public:
// Internal // Internal
HRESULT STDMETHODCALLTYPE Initialize(LPCITEMIDLIST pidl, PCWSTR ntPath); HRESULT STDMETHODCALLTYPE Initialize(LPCITEMIDLIST pidl, PCWSTR ntPath);
static HRESULT CALLBACK DefCtxMenuCallback(IShellFolder *, HWND, IDataObject *, UINT, WPARAM, LPARAM);
DECLARE_REGISTRY_RESOURCEID(IDR_NTOBJECTFOLDER) DECLARE_REGISTRY_RESOURCEID(IDR_NTOBJECTFOLDER)
DECLARE_NOT_AGGREGATABLE(CRegistryFolder) DECLARE_NOT_AGGREGATABLE(CRegistryFolder)
DECLARE_PROTECT_FINAL_CONSTRUCT() DECLARE_PROTECT_FINAL_CONSTRUCT()

View file

@ -1,22 +1,33 @@
HKCR HKCR
{ {
NoRemove CLSID NTObjShEx.NTDirectory.1 = s 'NT Namespace Directory Class'
{ {
ForceRemove {845B0FB2-66E0-416B-8F91-314E23F7C12D} = s 'NT Object Namespace Extension' CLSID = s '{845B0FB2-66E0-416B-8F91-314E23F7C12D}'
{ }
InprocServer32 = s '%MODULE%' NTObjShEx.NTDirectory = s 'NT Namespace Directory Class'
{ {
val ThreadingModel = s 'Both' CLSID = s '{845B0FB2-66E0-416B-8F91-314E23F7C12D}'
} CurVer = s 'WMIFldr.CWMIFldr.1'
val InfoTip = s 'Allows browsing of the NT Object Namespace' }
DefaultIcon = s '%MODULE%,0' NoRemove CLSID
ShellFolder {
{ ForceRemove {845B0FB2-66E0-416B-8F91-314E23F7C12D} = s 'NT Object Namespace Extension'
val Attributes = d '0xA8000000' {
val BrowserFlags = d '0x22' ProgID = s 'NTObjShEx.NTDirectory.1'
} VersionIndependentProgID = s 'NTObjShEx.NTDirectory'
} InprocServer32 = s '%MODULE%'
} {
val ThreadingModel = s 'Both'
}
val InfoTip = s 'Allows browsing of the NT Object Namespace'
DefaultIcon = s '%MODULE%,0'
ShellFolder
{
val Attributes = d '0xA8000000'
val BrowserFlags = d '0x22'
}
}
}
} }
HKLM HKLM
{ {