Author: dquintana
Date: Mon Dec 1 04:23:44 2014
New Revision: 65537
URL:
http://svn.reactos.org/svn/reactos?rev=65537&view=rev
Log:
[RSHELL]
* Partially rewrite CMergedFolder to fix the invalid assumption that the results of
enumerating a folder are ordered.
Fixes the folder merging on certain languages not working as expected, and also some other
weaknesses of the previous implementation.
CORE-8835 #resolve #comment Should be fixed in r65537. Thanks for reporting.
Modified:
trunk/reactos/base/shell/rshell/CMergedFolder.cpp
trunk/reactos/base/shell/rshell/CMergedFolder.h
trunk/reactos/base/shell/rshell/CStartMenu.cpp
Modified: trunk/reactos/base/shell/rshell/CMergedFolder.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/rshell/CMergedF…
==============================================================================
--- trunk/reactos/base/shell/rshell/CMergedFolder.cpp [iso-8859-1] (original)
+++ trunk/reactos/base/shell/rshell/CMergedFolder.cpp [iso-8859-1] Mon Dec 1 04:23:44
2014
@@ -30,6 +30,8 @@
BOOL shared;
IShellFolder * parent;
LPITEMIDLIST pidl;
+ LPITEMIDLIST pidl2;
+ LPCWSTR parseName;
};
class CEnumMergedFolder :
@@ -66,6 +68,7 @@
HRESULT SetSources(IShellFolder * userLocal, IShellFolder * allUSers);
HRESULT Begin(HWND hwndOwner, SHCONTF flags);
HRESULT FindPidlInList(HWND hwndOwner, LPCITEMIDLIST pcidl, LocalPidlInfo * pinfo);
+ HRESULT FindByName(HWND hwndOwner, LPCWSTR strParsingName, LocalPidlInfo * pinfo);
virtual HRESULT STDMETHODCALLTYPE Next(
ULONG celt,
@@ -96,6 +99,9 @@
int CEnumMergedFolder::DsaDeleteCallback(LocalPidlInfo * info)
{
ILFree(info->pidl);
+ if (info->pidl2)
+ ILFree(info->pidl2);
+ CoTaskMemFree((LPVOID)info->parseName);
return 0;
}
@@ -118,7 +124,8 @@
HRESULT CEnumMergedFolder::Begin(HWND hwndOwner, SHCONTF flags)
{
HRESULT hr;
-
+ LPITEMIDLIST pidl = NULL;
+
if (m_hDsa && m_HwndOwner == hwndOwner && m_Flags == flags)
{
return Reset();
@@ -127,16 +134,14 @@
TRACE("Search conditions changed, recreating list...\n");
CComPtr<IEnumIDList> userLocal;
- CComPtr<IEnumIDList> allUSers;
+ CComPtr<IEnumIDList> allUsers;
+
hr = m_UserLocalFolder->EnumObjects(hwndOwner, flags, &userLocal);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
- hr = m_AllUSersFolder->EnumObjects(hwndOwner, flags, &allUSers);
- if (FAILED_UNEXPECTEDLY(hr))
- {
- userLocal = NULL;
- return hr;
- }
+ hr = m_AllUSersFolder->EnumObjects(hwndOwner, flags, &allUsers);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
if (!m_hDsa)
{
@@ -147,143 +152,131 @@
DSA_DeleteAllItems(m_hDsa);
m_hDsaCount = 0;
- HRESULT hr1 = S_OK;
- HRESULT hr2 = S_OK;
- LPITEMIDLIST pidl1 = NULL;
- LPITEMIDLIST pidl2 = NULL;
- int order = 0;
- do
- {
- if (order <= 0)
+ TRACE("Loading Local entries...\n");
+ for (;;)
+ {
+ hr = userLocal->Next(1, &pidl, NULL);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ if (hr == S_FALSE)
+ break;
+
+ LPWSTR name;
+ STRRET str = { STRRET_WSTR };
+ hr = m_UserLocalFolder->GetDisplayNameOf(pidl, SHGDN_FORPARSING |
SHGDN_INFOLDER, &str);
+ if (FAILED(hr))
+ return hr;
+ StrRetToStrW(&str, pidl, &name);
+
+ LocalPidlInfo info = {
+ FALSE,
+ m_UserLocalFolder,
+ ILClone(pidl),
+ NULL,
+ name
+ };
+
+ ILFree(pidl);
+
+ TRACE("Inserting item %d with name %S\n", m_hDsaCount, name);
+ int idx = DSA_InsertItem(m_hDsa, DSA_APPEND, &info);
+ TRACE("New index: %d\n", idx);
+
+ m_hDsaCount++;
+ }
+
+ TRACE("Loading Common entries...\n");
+ for (;;)
+ {
+ hr = allUsers->Next(1, &pidl, NULL);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ if (hr == S_FALSE)
+ break;
+
+ LPWSTR name;
+ STRRET str = { STRRET_WSTR };
+ hr = m_AllUSersFolder->GetDisplayNameOf(pidl, SHGDN_FORPARSING |
SHGDN_INFOLDER, &str);
+ if (FAILED(hr))
+ return hr;
+ StrRetToStrW(&str, pidl, &name);
+
+ LocalPidlInfo info = {
+ FALSE,
+ m_AllUSersFolder,
+ ILClone(pidl),
+ NULL,
+ name
+ };
+
+ ILFree(pidl);
+
+ BOOL bShared = FALSE;
+ for (int i = 0; i < (int)m_hDsaCount; i++)
{
- if (hr1 == S_OK)
+ LocalPidlInfo *pInfo = (LocalPidlInfo *) DSA_GetItemPtr(m_hDsa, i);
+
+ int order = CompareStringW(GetThreadLocale(), NORM_IGNORECASE,
+ pInfo->parseName, lstrlenW(pInfo->parseName),
+ info.parseName, lstrlenW(info.parseName));
+ switch (order)
{
- hr1 = userLocal->Next(1, &pidl1, NULL);
- if (FAILED_UNEXPECTEDLY(hr1))
- return hr1;
- }
- else
- {
- pidl1 = NULL;
+ case CSTR_EQUAL:
+ TRACE("Item name already exists! Marking '%S' as shared
...\n", name);
+ bShared = TRUE;
+ pInfo->shared = TRUE;
+ pInfo->pidl2 = info.pidl;
+ CoTaskMemFree(name);
+ break;
+ default:
+ continue;
}
}
- if (order >= 0)
+
+ if (!bShared)
{
- if (hr2 == S_OK)
- {
- hr2 = allUSers->Next(1, &pidl2, NULL);
- if (FAILED_UNEXPECTEDLY(hr2))
- return hr2;
- }
- else
- {
- pidl2 = NULL;
- }
+ TRACE("Inserting item %d with name %S\n", m_hDsaCount, name);
+ int idx = DSA_InsertItem(m_hDsa, DSA_APPEND, &info);
+ TRACE("New index: %d\n", idx);
+
+ m_hDsaCount++;
}
-
- if (hr1 == S_OK && hr2 == S_OK)
- {
- LPWSTR name1;
- LPWSTR name2;
- STRRET str1 = { STRRET_WSTR };
- STRRET str2 = { STRRET_WSTR };
- hr = m_UserLocalFolder->GetDisplayNameOf(pidl1, SHGDN_FORPARSING |
SHGDN_INFOLDER, &str1);
- if (FAILED(hr))
- return hr;
- hr = m_AllUSersFolder->GetDisplayNameOf(pidl2, SHGDN_FORPARSING |
SHGDN_INFOLDER, &str2);
- if (FAILED(hr))
- return hr;
- StrRetToStrW(&str1, pidl1, &name1);
- StrRetToStrW(&str2, pidl2, &name2);
- order = StrCmpW(name1, name2);
-
- TRACE("Both sources are S_OK, comparison between %S and %S returns
%d\n", name1, name2, order);
-
- CoTaskMemFree(name1);
- CoTaskMemFree(name2);
- }
- else if (hr1 == S_OK)
- {
- order = -1;
-
- TRACE("Both sources are S_OK, forcing %d\n", order);
- }
- else if (hr2 == S_OK)
- {
- order = 1;
-
- TRACE("Both sources are S_OK, forcing %d\n", order);
- }
- else
- {
- TRACE("None of the sources\n");
- break;
- }
-
- LocalPidlInfo info = { FALSE };
- if (order < 0)
- {
- info.parent = m_UserLocalFolder;
- info.pidl = ILClone(pidl1);
- ILFree(pidl1);
- }
- else if (order > 0)
- {
- info.parent = m_AllUSersFolder;
- info.pidl = ILClone(pidl2);
- ILFree(pidl2);
- }
- else // if (order == 0)
- {
- info.shared = TRUE;
- info.parent = m_UserLocalFolder;
- info.pidl = ILClone(pidl1);
- ILFree(pidl1);
- ILFree(pidl2);
- }
-
- TRACE("Inserting item %d with parent %p and pidl { cb=%d }\n",
m_hDsaCount, info.parent, info.pidl->mkid.cb);
- int idx = DSA_InsertItem(m_hDsa, DSA_APPEND, &info);
- TRACE("New index: %d\n", idx);
-
- m_hDsaCount++;
-
- } while (hr1 == S_OK || hr2 == S_OK);
+ }
m_HwndOwner = hwndOwner;
m_Flags = flags;
+
+ return Reset();
+}
+
+HRESULT CEnumMergedFolder::FindPidlInList(HWND hwndOwner, LPCITEMIDLIST pcidl,
LocalPidlInfo * pinfo)
+{
+ HRESULT hr;
+
+ if (!m_hDsa)
+ {
+ Begin(hwndOwner, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS);
+ }
+
+ TRACE("Searching for pidl { cb=%d } in a list of %d items\n",
pcidl->mkid.cb, m_hDsaCount);
+
+ for (int i = 0; i < (int)m_hDsaCount; i++)
+ {
+ LocalPidlInfo * pInfo = (LocalPidlInfo *) DSA_GetItemPtr(m_hDsa, i);
+ if (!pInfo)
+ return E_FAIL;
- return Reset();
-}
-
-HRESULT CEnumMergedFolder::FindPidlInList(HWND hwndOwner, LPCITEMIDLIST pcidl,
LocalPidlInfo * pinfo)
-{
- HRESULT hr;
-
- if (!m_hDsa)
- {
- Begin(hwndOwner, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS);
- }
-
- TRACE("Searching for pidl { cb=%d } in a list of %d items\n",
pcidl->mkid.cb, m_hDsaCount);
-
- for (int i = 0; i < (int)m_hDsaCount; i++)
- {
- LocalPidlInfo * tinfo = (LocalPidlInfo *)DSA_GetItemPtr(m_hDsa, i);
- if (!tinfo)
- return E_FAIL;
-
- LocalPidlInfo info = *tinfo;
-
- TRACE("Comparing with item at %d with parent %p and pidl { cb=%d }\n",
i, info.parent, info.pidl->mkid.cb);
-
- hr = info.parent->CompareIDs(0, info.pidl, pcidl);
+ TRACE("Comparing with item at %d with parent %p and pidl { cb=%d }\n",
i, pInfo->parent, pInfo->pidl->mkid.cb);
+
+ hr = pInfo->parent->CompareIDs(0, pInfo->pidl, pcidl);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
if (hr == S_OK)
{
- *pinfo = info;
+ *pinfo = *pInfo;
return S_OK;
}
else
@@ -296,12 +289,45 @@
return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
}
+HRESULT CEnumMergedFolder::FindByName(HWND hwndOwner, LPCWSTR strParsingName,
LocalPidlInfo * pinfo)
+{
+ if (!m_hDsa)
+ {
+ Begin(hwndOwner, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS);
+ }
+
+ TRACE("Searching for '%S' in a list of %d items\n", strParsingName,
m_hDsaCount);
+
+ for (int i = 0; i < (int) m_hDsaCount; i++)
+ {
+ LocalPidlInfo * pInfo = (LocalPidlInfo *) DSA_GetItemPtr(m_hDsa, i);
+ if (!pInfo)
+ return E_FAIL;
+
+ int order = CompareStringW(GetThreadLocale(), NORM_IGNORECASE,
+ pInfo->parseName, lstrlenW(pInfo->parseName),
+ strParsingName, lstrlenW(strParsingName));
+ switch (order)
+ {
+ case CSTR_EQUAL:
+ *pinfo = *pInfo;
+ return S_OK;
+ default:
+ continue;
+ }
+ }
+
+ TRACE("Pidl not found\n");
+ return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+}
+
HRESULT STDMETHODCALLTYPE CEnumMergedFolder::Next(
ULONG celt,
LPITEMIDLIST *rgelt,
ULONG *pceltFetched)
{
- if (pceltFetched) *pceltFetched = 0;
+ if (pceltFetched)
+ *pceltFetched = 0;
if (m_hDsaIndex == m_hDsaCount)
return S_FALSE;
@@ -323,7 +349,8 @@
m_hDsaIndex++;
if (m_hDsaIndex == m_hDsaCount)
{
- if (pceltFetched) *pceltFetched = i;
+ if (pceltFetched)
+ *pceltFetched = i;
return (i == (int)celt) ? S_OK : S_FALSE;
}
}
@@ -361,7 +388,7 @@
CMergedFolder::CMergedFolder() :
m_UserLocal(NULL),
- m_AllUSers(NULL),
+ m_AllUsers(NULL),
m_EnumSource(NULL),
m_UserLocalPidl(NULL),
m_AllUsersPidl(NULL),
@@ -384,7 +411,7 @@
return E_NOTIMPL;
}
- TRACE("AddNameSpace %p %p\n", m_UserLocal.p, m_AllUSers.p);
+ TRACE("AddNameSpace %p %p\n", m_UserLocal.p, m_AllUsers.p);
// FIXME: Use a DSA to store the list of merged namespaces, together with their
related info (psf, pidl, ...)
// For now, assume only 2 will ever be used, and ignore all the other data.
@@ -395,14 +422,14 @@
return S_OK;
}
- if (m_AllUSers)
+ if (m_AllUsers)
return E_FAIL;
- m_AllUSers = psf;
+ m_AllUsers = psf;
m_AllUsersPidl = ILClone(pcidl);
m_EnumSource = new CComObject<CEnumMergedFolder>();
- return m_EnumSource->SetSources(m_UserLocal, m_AllUSers);
+ return m_EnumSource->SetSources(m_UserLocal, m_AllUsers);
}
HRESULT STDMETHODCALLTYPE CMergedFolder::GetNameSpaceID(LPCITEMIDLIST pcidl, LPGUID
lpGuid)
@@ -440,45 +467,33 @@
{
HRESULT hr;
LocalPidlInfo info;
- LPITEMIDLIST pidl;
-
- if (!ppidl) return E_FAIL;
-
- if (pchEaten) *pchEaten = 0;
- if (pdwAttributes) *pdwAttributes = 0;
+
+ if (!ppidl)
+ return E_FAIL;
+
+ if (pchEaten)
+ *pchEaten = 0;
+
+ if (pdwAttributes)
+ *pdwAttributes = 0;
TRACE("ParseDisplayName name=%S\n", lpszDisplayName);
- hr = m_UserLocal->ParseDisplayName(hwndOwner, pbcReserved, lpszDisplayName,
pchEaten, &pidl, pdwAttributes);
- if (SUCCEEDED(hr))
- {
- TRACE("ParseDisplayName result local\n");
- hr = m_EnumSource->FindPidlInList(hwndOwner, pidl, &info);
- if (SUCCEEDED(hr))
- {
- ILFree(pidl);
- *ppidl = ILClone(info.pidl);
- return hr;
- }
- }
-
- hr = m_AllUSers->ParseDisplayName(hwndOwner, pbcReserved, lpszDisplayName,
pchEaten, &pidl, pdwAttributes);
- if (SUCCEEDED(hr))
- {
- TRACE("ParseDisplayName result common\n");
- hr = m_EnumSource->FindPidlInList(hwndOwner, pidl, &info);
- if (SUCCEEDED(hr))
- {
- ILFree(pidl);
- *ppidl = ILClone(info.pidl);
- return hr;
- }
- }
-
- if (ppidl) *ppidl = NULL;
- if (pchEaten) *pchEaten = 0;
- if (pdwAttributes) *pdwAttributes = 0;
- return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+ hr = m_EnumSource->FindByName(hwndOwner, lpszDisplayName, &info);
+ if (FAILED(hr))
+ {
+ return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+ }
+
+ *ppidl = ILClone(info.pidl);
+
+ if (pchEaten)
+ *pchEaten = lstrlenW(info.parseName);
+
+ if (pdwAttributes)
+ *pdwAttributes = info.parent->GetAttributesOf(1, (LPCITEMIDLIST*)ppidl,
pdwAttributes);
+
+ return S_OK;
}
HRESULT STDMETHODCALLTYPE CMergedFolder::EnumObjects(
@@ -514,14 +529,16 @@
if (riid != IID_IShellFolder)
return E_FAIL;
+ // Construct a child MergedFolder and return it
CComPtr<IShellFolder> fld1;
CComPtr<IShellFolder> fld2;
+ // In shared folders, the user one takes precedence over the common one, so it will
always be on pidl1
hr = m_UserLocal->BindToObject(info.pidl, pbcReserved, IID_PPV_ARG(IShellFolder,
&fld1));
if (FAILED_UNEXPECTEDLY(hr))
return hr;
- hr = m_AllUSers->BindToObject(info.pidl, pbcReserved, IID_PPV_ARG(IShellFolder,
&fld2));
+ hr = m_AllUsers->BindToObject(info.pidl2, pbcReserved, IID_PPV_ARG(IShellFolder,
&fld2));
if (FAILED_UNEXPECTEDLY(hr))
return hr;
@@ -538,7 +555,7 @@
if (FAILED_UNEXPECTEDLY(hr))
return hr;
- hr = pasf->AddNameSpace(NULL, fld2, info.pidl, 0x0000);
+ hr = pasf->AddNameSpace(NULL, fld2, info.pidl2, 0x0000);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
@@ -786,4 +803,11 @@
{
UNIMPLEMENTED;
return E_NOTIMPL;
+}
+
+// IAugmentedShellFolder3
+HRESULT STDMETHODCALLTYPE CMergedFolder::QueryNameSpace2(ULONG, QUERYNAMESPACEINFO *)
+{
+ UNIMPLEMENTED;
+ return E_NOTIMPL;
}
Modified: trunk/reactos/base/shell/rshell/CMergedFolder.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/rshell/CMergedF…
==============================================================================
--- trunk/reactos/base/shell/rshell/CMergedFolder.h [iso-8859-1] (original)
+++ trunk/reactos/base/shell/rshell/CMergedFolder.h [iso-8859-1] Mon Dec 1 04:23:44 2014
@@ -21,6 +21,7 @@
extern IID IID_IAugmentedShellFolder;
extern IID IID_IAugmentedShellFolder2;
+extern IID IID_IAugmentedShellFolder3;
extern CLSID CLSID_MergedFolder;
interface IAugmentedShellFolder : public IShellFolder
@@ -36,33 +37,35 @@
virtual HRESULT STDMETHODCALLTYPE UnWrapIDList(LPCITEMIDLIST, LONG, IShellFolder **,
LPITEMIDLIST *, LPITEMIDLIST *, LONG *) = 0;
};
-/* No idea what QUERYNAMESPACEINFO struct contains -- the prototype comes from the PDB
info
+/* No idea what QUERYNAMESPACEINFO struct contains, yet */
+struct QUERYNAMESPACEINFO
+{
+ BYTE unknown[1];
+};
+
interface IAugmentedShellFolder3 : public IAugmentedShellFolder2
{
virtual HRESULT STDMETHODCALLTYPE QueryNameSpace2(ULONG, QUERYNAMESPACEINFO *) = 0;
};
-*/
class CEnumMergedFolder;
class CMergedFolder :
public CComObjectRootEx<CComMultiThreadModelNoCS>,
public IShellFolder2,
- //public IStorage,
- public IAugmentedShellFolder2, // -- undocumented
- //public IAugmentedShellFolder3, // -- undocumented
+ public IPersistFolder2,
+ public IAugmentedShellFolder3 // -- undocumented
//public IShellService, // -- undocumented
//public ITranslateShellChangeNotify,// -- undocumented
- public IPersistFolder2
+ //public IStorage,
//public IPersistPropertyBag,
//public IShellIconOverlay, // -- undocumented
//public ICompositeFolder, // -- undocumented
//public IItemNameLimits, // -- undocumented
-
{
private:
CComPtr<IShellFolder> m_UserLocal;
- CComPtr<IShellFolder> m_AllUSers;
+ CComPtr<IShellFolder> m_AllUsers;
CComPtr<CEnumMergedFolder> m_EnumSource;
LPITEMIDLIST m_UserLocalPidl;
@@ -86,7 +89,7 @@
COM_INTERFACE_ENTRY_IID(IID_IPersistFolder2, IPersistFolder2)
COM_INTERFACE_ENTRY_IID(IID_IAugmentedShellFolder, IAugmentedShellFolder)
COM_INTERFACE_ENTRY_IID(IID_IAugmentedShellFolder2, IAugmentedShellFolder2)
- //COM_INTERFACE_ENTRY_IID(IID_IAugmentedShellFolder3,
IAugmentedShellFolder3)
+ COM_INTERFACE_ENTRY_IID(IID_IAugmentedShellFolder3, IAugmentedShellFolder3)
//COM_INTERFACE_ENTRY_IID(IID_IStorage, IStorage)
//COM_INTERFACE_ENTRY_IID(IID_IShellService, IShellService)
//COM_INTERFACE_ENTRY_IID(IID_ITranslateShellChangeNotify,ITranslateShellChangeNotify)
@@ -202,4 +205,7 @@
virtual HRESULT STDMETHODCALLTYPE QueryNameSpace(ULONG dwUnknown, LPGUID lpGuid,
IShellFolder ** ppsf);
virtual HRESULT STDMETHODCALLTYPE EnumNameSpace(ULONG dwUnknown, PULONG lpUnknown);
virtual HRESULT STDMETHODCALLTYPE UnWrapIDList(LPCITEMIDLIST pcidl, LONG lUnknown,
IShellFolder ** ppsf, LPITEMIDLIST * ppidl1, LPITEMIDLIST *ppidl2, LONG * lpUnknown);
-};
+
+ // IAugmentedShellFolder3
+ virtual HRESULT STDMETHODCALLTYPE QueryNameSpace2(ULONG, QUERYNAMESPACEINFO *);
+};
Modified: trunk/reactos/base/shell/rshell/CStartMenu.cpp
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/base/shell/rshell/CStartMe…
==============================================================================
--- trunk/reactos/base/shell/rshell/CStartMenu.cpp [iso-8859-1] (original)
+++ trunk/reactos/base/shell/rshell/CStartMenu.cpp [iso-8859-1] Mon Dec 1 04:23:44 2014
@@ -24,8 +24,9 @@
WINE_DEFAULT_DEBUG_CHANNEL(CStartMenu);
// TODO: declare these GUIDs and interfaces in the right place (whatever that may be)
-IID IID_IAugmentedShellFolder = { 0x91EA3F8C, 0xC99B, 0x11D0, { 0x98, 0x15, 0x00, 0xC0,
0x4F, 0xD9, 0x19, 0x72 } };
+IID IID_IAugmentedShellFolder = { 0x91EA3F8C, 0xC99B, 0x11D0, { 0x98, 0x15, 0x00, 0xC0,
0x4F, 0xD9, 0x19, 0x72 } };
IID IID_IAugmentedShellFolder2 = { 0x8DB3B3F4, 0x6CFE, 0x11D1, { 0x8A, 0xE9, 0x00, 0xC0,
0x4F, 0xD9, 0x18, 0xD0 } };
+IID IID_IAugmentedShellFolder3 = { 0x4F755EA8, 0x247D, 0x479B, { 0x91, 0x81, 0x22, 0x7D,
0x09, 0xC2, 0xE0, 0x01 } };
CLSID CLSID_MergedFolder = { 0x26FDC864, 0xBE88, 0x46E7, { 0x92, 0x35, 0x03, 0x2D, 0x8E,
0xA5, 0x16, 0x2E } };
//#define TEST_TRACKPOPUPMENU_SUBMENUS