[SHELL] IPersistFolder::Initialize takes a PCIDLIST_ABSOLUTE. CORE-16385
[reactos.git] / dll / win32 / shell32 / folders / CControlPanelFolder.cpp
index b78eb65..53bd9cb 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-/*
-TODO:
-1. The selected items list should not be stored in CControlPanelFolder, it should
-    be a result returned by an internal method.
-*/
-
 #include <precomp.h>
 
 WINE_DEFAULT_DEBUG_CHANNEL(shell);
@@ -39,10 +33,9 @@ class CControlPanelEnum :
     public:
         CControlPanelEnum();
         ~CControlPanelEnum();
-        HRESULT WINAPI Initialize(DWORD dwFlags);
-        BOOL RegisterCPanelApp(LPCSTR path);
-        int RegisterRegistryCPanelApps(HKEY hkey_root, LPCSTR szRepPath);
-        int RegisterCPanelFolders(HKEY hkey_root, LPCSTR szRepPath);
+        HRESULT WINAPI Initialize(DWORD dwFlags, IEnumIDList* pRegEnumerator);
+        BOOL RegisterCPanelApp(LPCWSTR path);
+        int RegisterRegistryCPanelApps(HKEY hkey_root, LPCWSTR szRepPath);
         BOOL CreateCPanelEnumList(DWORD dwFlags);
 
         BEGIN_COM_MAP(CControlPanelEnum)
@@ -55,8 +48,8 @@ class CControlPanelEnum :
 */
 
 static const shvheader ControlPanelSFHeader[] = {
-    {IDS_SHV_COLUMN8, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},/*FIXME*/
-    {IDS_SHV_COLUMN9, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 200},/*FIXME*/
+    {IDS_SHV_COLUMN_NAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 20},/*FIXME*/
+    {IDS_SHV_COLUMN_COMMENTS, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 80},/*FIXME*/
 };
 
 #define CONROLPANELSHELLVIEWCOLUMNS 2
@@ -69,14 +62,15 @@ CControlPanelEnum::~CControlPanelEnum()
 {
 }
 
-HRESULT WINAPI CControlPanelEnum::Initialize(DWORD dwFlags)
+HRESULT WINAPI CControlPanelEnum::Initialize(DWORD dwFlags, IEnumIDList* pRegEnumerator)
 {
     if (CreateCPanelEnumList(dwFlags) == FALSE)
         return E_FAIL;
+    AppendItemsFromEnumerator(pRegEnumerator);
     return S_OK;
 }
 
-static LPITEMIDLIST _ILCreateCPanelApplet(LPCSTR pszName, LPCSTR pszDisplayName, LPCSTR pszComment, int iIconIdx)
+static LPITEMIDLIST _ILCreateCPanelApplet(LPCWSTR pszName, LPCWSTR pszDisplayName, LPCWSTR pszComment, int iIconIdx)
 {
     PIDLCPanelStruct *pCP;
     LPITEMIDLIST pidl;
@@ -84,13 +78,13 @@ static LPITEMIDLIST _ILCreateCPanelApplet(LPCSTR pszName, LPCSTR pszDisplayName,
     int cchName, cchDisplayName, cchComment, cbData;
 
     /* Calculate lengths of given strings */
-    cchName = strlen(pszName);
-    cchDisplayName = strlen(pszDisplayName);
-    cchComment = strlen(pszComment);
+    cchName = wcslen(pszName);
+    cchDisplayName = wcslen(pszDisplayName);
+    cchComment = wcslen(pszComment);
 
     /* Allocate PIDL */
     cbData = sizeof(pidl->mkid.cb) + sizeof(pData->type) + sizeof(pData->u.cpanel) - sizeof(pData->u.cpanel.szName)
-             + cchName + cchDisplayName + cchComment + 3;
+             + (cchName + cchDisplayName + cchComment + 3) * sizeof(WCHAR);
     pidl = (LPITEMIDLIST)SHAlloc(cbData + sizeof(WORD));
     if (!pidl)
         return NULL;
@@ -103,11 +97,11 @@ static LPITEMIDLIST _ILCreateCPanelApplet(LPCSTR pszName, LPCSTR pszDisplayName,
     pCP = &pData->u.cpanel;
     pCP->dummy = 0;
     pCP->iconIdx = iIconIdx;
-    strcpy(pCP->szName, pszName);
+    wcscpy(pCP->szName, pszName);
     pCP->offsDispName = cchName + 1;
-    strcpy(pCP->szName + pCP->offsDispName, pszDisplayName);
+    wcscpy(pCP->szName + pCP->offsDispName, pszDisplayName);
     pCP->offsComment = pCP->offsDispName + cchDisplayName + 1;
-    strcpy(pCP->szName + pCP->offsComment, pszComment);
+    wcscpy(pCP->szName + pCP->offsComment, pszComment);
 
     /* Add PIDL NULL terminator */
     *(WORD*)(pCP->szName + pCP->offsComment + cchComment + 1) = 0;
@@ -131,40 +125,40 @@ static PIDLCPanelStruct *_ILGetCPanelPointer(LPCITEMIDLIST pidl)
     return NULL;
 }
 
-BOOL CControlPanelEnum::RegisterCPanelApp(LPCSTR path)
+HRESULT CCPLExtractIcon_CreateInstance(IShellFolder * psf, LPCITEMIDLIST pidl, REFIID riid, LPVOID * ppvOut)
 {
-    LPITEMIDLIST pidl;
-    CPlApplet* applet;
-    CPanel panel;
-    CPLINFO info;
-    unsigned i;
-    int iconIdx;
+    PIDLCPanelStruct *pData = _ILGetCPanelPointer(pidl);
+    if (!pData)
+        return E_FAIL;
 
-    char displayName[MAX_PATH];
-    char comment[MAX_PATH];
+    CComPtr<IDefaultExtractIconInit> initIcon;
+    HRESULT hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit, &initIcon));
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
 
-    WCHAR wpath[MAX_PATH];
+    initIcon->SetNormalIcon(pData->szName, (int)pData->iconIdx != -1 ? pData->iconIdx : 0);
 
-    MultiByteToWideChar(CP_ACP, 0, path, -1, wpath, MAX_PATH);
+    return initIcon->QueryInterface(riid, ppvOut);
+}
 
-    panel.first = NULL;
-    applet = Control_LoadApplet(0, wpath, &panel);
+BOOL CControlPanelEnum::RegisterCPanelApp(LPCWSTR wpath)
+{
+    CPlApplet* applet = Control_LoadApplet(0, wpath, NULL);
+    int iconIdx;
 
     if (applet)
     {
-        for (i = 0; i < applet->count; ++i)
+        for (UINT i = 0; i < applet->count; ++i)
         {
-            WideCharToMultiByte(CP_ACP, 0, applet->info[i].szName, -1, displayName, MAX_PATH, 0, 0);
-            WideCharToMultiByte(CP_ACP, 0, applet->info[i].szInfo, -1, comment, MAX_PATH, 0, 0);
-
-            applet->proc(0, CPL_INQUIRE, i, (LPARAM)&info);
-
-            if (info.idIcon > 0)
-                iconIdx = -info.idIcon; /* negative icon index instead of icon number */
+            if (applet->info[i].idIcon > 0)
+                iconIdx = -applet->info[i].idIcon; /* negative icon index instead of icon number */
             else
                 iconIdx = 0;
 
-            pidl = _ILCreateCPanelApplet(path, displayName, comment, iconIdx);
+            LPITEMIDLIST pidl = _ILCreateCPanelApplet(wpath, 
+                                                      applet->info[i].name, 
+                                                      applet->info[i].info, 
+                                                      iconIdx);
 
             if (pidl)
                 AddToEnumList(pidl);
@@ -174,15 +168,15 @@ BOOL CControlPanelEnum::RegisterCPanelApp(LPCSTR path)
     return TRUE;
 }
 
-int CControlPanelEnum::RegisterRegistryCPanelApps(HKEY hkey_root, LPCSTR szRepPath)
+int CControlPanelEnum::RegisterRegistryCPanelApps(HKEY hkey_root, LPCWSTR szRepPath)
 {
-    char name[MAX_PATH];
-    char value[MAX_PATH];
+    WCHAR name[MAX_PATH];
+    WCHAR value[MAX_PATH];
     HKEY hkey;
 
     int cnt = 0;
 
-    if (RegOpenKeyA(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS)
+    if (RegOpenKeyW(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS)
     {
         int idx = 0;
 
@@ -190,43 +184,19 @@ int CControlPanelEnum::RegisterRegistryCPanelApps(HKEY hkey_root, LPCSTR szRepPa
         {
             DWORD nameLen = MAX_PATH;
             DWORD valueLen = MAX_PATH;
+            WCHAR buffer[MAX_PATH];
 
-            if (RegEnumValueA(hkey, idx, name, &nameLen, NULL, NULL, (LPBYTE)&value, &valueLen) != ERROR_SUCCESS)
+            if (RegEnumValueW(hkey, idx, name, &nameLen, NULL, NULL, (LPBYTE)&value, &valueLen) != ERROR_SUCCESS)
                 break;
 
-            if (RegisterCPanelApp(value))
-                ++cnt;
-        }
-        RegCloseKey(hkey);
-    }
-
-    return cnt;
-}
-
-int CControlPanelEnum::RegisterCPanelFolders(HKEY hkey_root, LPCSTR szRepPath)
-{
-    char name[MAX_PATH];
-    HKEY hkey;
-
-    int cnt = 0;
-
-    if (RegOpenKeyA(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS)
-    {
-        int idx = 0;
-        for (; ; idx++)
-        {
-            if (RegEnumKeyA(hkey, idx, name, MAX_PATH) != ERROR_SUCCESS)
-                break;
-
-            if (*name == '{')
+            if (ExpandEnvironmentStringsW(value, buffer, MAX_PATH))
             {
-                LPITEMIDLIST pidl = _ILCreateGuidFromStrA(name);
-
-                if (pidl && AddToEnumList(pidl))
-                    ++cnt;
+                wcscpy(value, buffer);
             }
-        }
 
+            if (RegisterCPanelApp(value))
+                ++cnt;
+        }
         RegCloseKey(hkey);
     }
 
@@ -238,27 +208,22 @@ int CControlPanelEnum::RegisterCPanelFolders(HKEY hkey_root, LPCSTR szRepPath)
  */
 BOOL CControlPanelEnum::CreateCPanelEnumList(DWORD dwFlags)
 {
-    CHAR szPath[MAX_PATH];
-    WIN32_FIND_DATAA wfd;
+    WCHAR szPath[MAX_PATH];
+    WIN32_FIND_DATAW wfd;
     HANDLE hFile;
 
     TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags);
 
-    /* enumerate control panel folders */
-    if (dwFlags & SHCONTF_FOLDERS)
-        RegisterCPanelFolders(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace");
-
     /* enumerate the control panel applets */
     if (dwFlags & SHCONTF_NONFOLDERS)
     {
-        LPSTR p;
+        LPWSTR p;
 
-        GetSystemDirectoryA(szPath, MAX_PATH);
-        p = PathAddBackslashA(szPath);
-        strcpy(p, "*.cpl");
+        GetSystemDirectoryW(szPath, MAX_PATH);
+        p = PathAddBackslashW(szPath);
+        wcscpy(p, L"*.cpl");
 
-        TRACE("-- (%p)-> enumerate SHCONTF_NONFOLDERS of %s\n", this, debugstr_a(szPath));
-        hFile = FindFirstFileA(szPath, &wfd);
+        hFile = FindFirstFileW(szPath, &wfd);
 
         if (hFile != INVALID_HANDLE_VALUE)
         {
@@ -268,16 +233,16 @@ BOOL CControlPanelEnum::CreateCPanelEnumList(DWORD dwFlags)
                     continue;
 
                 if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
-                    strcpy(p, wfd.cFileName);
-                    if (strcmp(wfd.cFileName, "ncpa.cpl"))
+                    wcscpy(p, wfd.cFileName);
+                    if (wcscmp(wfd.cFileName, L"ncpa.cpl"))
                         RegisterCPanelApp(szPath);
                 }
-            } while(FindNextFileA(hFile, &wfd));
+            } while(FindNextFileW(hFile, &wfd));
             FindClose(hFile);
         }
 
-        RegisterRegistryCPanelApps(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls");
-        RegisterRegistryCPanelApps(HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls");
+        RegisterRegistryCPanelApps(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls");
+        RegisterRegistryCPanelApps(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Control Panel\\Cpls");
     }
     return TRUE;
 }
@@ -285,9 +250,6 @@ BOOL CControlPanelEnum::CreateCPanelEnumList(DWORD dwFlags)
 CControlPanelFolder::CControlPanelFolder()
 {
     pidlRoot = NULL;    /* absolute pidl */
-    dwAttributes = 0;        /* attributes returned by GetAttributesOf FIXME: use it */
-    apidl = NULL;
-    cidl = 0;
 }
 
 CControlPanelFolder::~CControlPanelFolder()
@@ -296,14 +258,6 @@ CControlPanelFolder::~CControlPanelFolder()
     SHFree(pidlRoot);
 }
 
-HRESULT WINAPI CControlPanelFolder::FinalConstruct()
-{
-    pidlRoot = _ILCreateControlPanel();    /* my qualified pidl */
-    if (pidlRoot == NULL)
-        return E_OUTOFMEMORY;
-    return S_OK;
-}
-
 /**************************************************************************
 *    CControlPanelFolder::ParseDisplayName
 */
@@ -315,57 +269,8 @@ HRESULT WINAPI CControlPanelFolder::ParseDisplayName(
     PIDLIST_RELATIVE *ppidl,
     DWORD *pdwAttributes)
 {
-    WCHAR szElement[MAX_PATH];
-    LPCWSTR szNext = NULL;
-    LPITEMIDLIST pidlTemp = NULL;
-    HRESULT hr = S_OK;
-    CLSID clsid;
-
-    TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
-           this, hwndOwner, pbc, lpszDisplayName, debugstr_w(lpszDisplayName),
-           pchEaten, ppidl, pdwAttributes);
-
-    if (!lpszDisplayName || !ppidl)
-        return E_INVALIDARG;
-
-    *ppidl = 0;
-
-    if (pchEaten)
-        *pchEaten = 0;        /* strange but like the original */
-
-    if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
-    {
-        szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
-        TRACE ("-- element: %s\n", debugstr_w (szElement));
-        CLSIDFromString (szElement + 2, &clsid);
-        pidlTemp = _ILCreateGuid (PT_GUID, clsid);
-    }
-    else if( (pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName)) )
-    {
-        *ppidl = pidlTemp;
-        return S_OK;
-    }
-
-    if (SUCCEEDED(hr) && pidlTemp)
-    {
-        if (szNext && *szNext)
-        {
-            hr = SHELL32_ParseNextElement(this, hwndOwner, pbc,
-                                          &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes);
-        }
-        else
-        {
-            if (pdwAttributes && *pdwAttributes)
-                hr = SHELL32_GetItemAttributes(this,
-                                               pidlTemp, pdwAttributes);
-        }
-    }
-
-    *ppidl = pidlTemp;
-
-    TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr);
-
-    return hr;
+    /* We only support parsing guid names */
+    return m_regFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
 }
 
 /**************************************************************************
@@ -373,7 +278,10 @@ HRESULT WINAPI CControlPanelFolder::ParseDisplayName(
 */
 HRESULT WINAPI CControlPanelFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
 {
-    return ShellObjectCreatorInit<CControlPanelEnum>(dwFlags, IID_IEnumIDList, ppEnumIDList);
+    CComPtr<IEnumIDList> pRegEnumerator;
+    m_regFolder->EnumObjects(hwndOwner, dwFlags, &pRegEnumerator);
+
+    return ShellObjectCreatorInit<CControlPanelEnum>(dwFlags, pRegEnumerator, IID_PPV_ARG(IEnumIDList, ppEnumIDList));
 }
 
 /**************************************************************************
@@ -385,9 +293,7 @@ HRESULT WINAPI CControlPanelFolder::BindToObject(
     REFIID riid,
     LPVOID *ppvOut)
 {
-    TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this, pidl, pbcReserved, shdebugstr_guid(&riid), ppvOut);
-
-    return SHELL32_BindToChild(pidlRoot, NULL, pidl, riid, ppvOut);
+    return m_regFolder->BindToObject(pidl, pbcReserved, riid, ppvOut);
 }
 
 /**************************************************************************
@@ -408,15 +314,34 @@ HRESULT WINAPI CControlPanelFolder::BindToStorage(
 /**************************************************************************
 *     CControlPanelFolder::CompareIDs
 */
-
 HRESULT WINAPI CControlPanelFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
 {
-    int nReturn;
+    /* Dont use SHELL32_CompareGuidItems because it would cause guid items to come first */
+    if (_ILIsSpecialFolder(pidl1) || _ILIsSpecialFolder(pidl2))
+    {
+        return SHELL32_CompareDetails(this, lParam, pidl1, pidl2);
+    }
+    PIDLCPanelStruct *pData1 = _ILGetCPanelPointer(pidl1);
+    PIDLCPanelStruct *pData2 = _ILGetCPanelPointer(pidl2);
 
-    TRACE("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", this, lParam, pidl1, pidl2);
-    nReturn = SHELL32_CompareIDs(this, lParam, pidl1, pidl2);
-    TRACE("-- %i\n", nReturn);
-    return nReturn;
+    if (!pData1 || !pData2 || LOWORD(lParam)>= CONROLPANELSHELLVIEWCOLUMNS)
+        return E_INVALIDARG;
+
+    int result;
+    switch(LOWORD(lParam)) 
+    {
+        case 0:        /* name */
+            result = wcsicmp(pData1->szName + pData1->offsDispName, pData2->szName + pData2->offsDispName);
+            break;
+        case 1:        /* comment */
+            result = wcsicmp(pData1->szName + pData1->offsComment, pData2->szName + pData2->offsComment);
+            break;
+        default:
+            ERR("Got wrong lParam!\n");
+            return E_INVALIDARG;
+    }
+
+    return MAKE_COMPARE_HRESULT(result);
 }
 
 /**************************************************************************
@@ -439,10 +364,8 @@ HRESULT WINAPI CControlPanelFolder::CreateViewObject(HWND hwndOwner, REFIID riid
             WARN("IContextMenu not implemented\n");
             hr = E_NOTIMPL;
         } else if (IsEqualIID(riid, IID_IShellView)) {
-            hr = IShellView_Constructor((IShellFolder *)this, &pShellView);
-            if (pShellView) {
-                hr = pShellView->QueryInterface(riid, ppvOut);
-            }
+            SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this};
+            hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut);
         }
     }
     TRACE("--(%p)->(interface=%p)\n", this, ppvOut);
@@ -455,6 +378,8 @@ HRESULT WINAPI CControlPanelFolder::CreateViewObject(HWND hwndOwner, REFIID riid
 HRESULT WINAPI CControlPanelFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD * rgfInOut)
 {
     HRESULT hr = S_OK;
+    static const DWORD dwControlPanelAttributes =
+        SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_CANLINK;
 
     TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
           this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
@@ -467,12 +392,24 @@ HRESULT WINAPI CControlPanelFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_A
     if (*rgfInOut == 0)
         *rgfInOut = ~0;
 
-    while(cidl > 0 && *apidl)
+    if (!cidl)
     {
-        pdump(*apidl);
-        SHELL32_GetItemAttributes(this, *apidl, rgfInOut);
-        apidl++;
-        cidl--;
+        *rgfInOut &= dwControlPanelAttributes;
+    }
+    else
+    {
+        while(cidl > 0 && *apidl)
+        {
+            pdump(*apidl);
+            if (_ILIsCPanelStruct(*apidl))
+                *rgfInOut &= SFGAO_CANLINK;
+            else if (_ILIsSpecialFolder(*apidl))
+                m_regFolder->GetAttributesOf(1, apidl, rgfInOut);
+            else
+                ERR("Got an unkown pidl here!\n");
+            apidl++;
+            cidl--;
+        }
     }
     /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
     *rgfInOut &= ~SFGAO_VALIDATE;
@@ -496,8 +433,7 @@ HRESULT WINAPI CControlPanelFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_A
 HRESULT WINAPI CControlPanelFolder::GetUIObjectOf(HWND hwndOwner,
         UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
 {
-    LPITEMIDLIST pidl;
-    IUnknown *pObj = NULL;
+    LPVOID pObj = NULL;
     HRESULT hr = E_INVALIDARG;
 
     TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
@@ -507,31 +443,28 @@ HRESULT WINAPI CControlPanelFolder::GetUIObjectOf(HWND hwndOwner,
         *ppvOut = NULL;
 
         if (IsEqualIID(riid, IID_IContextMenu) && (cidl >= 1)) {
-            // TODO
-            // create a seperate item struct
-            //
-            pObj = (IContextMenu *)this;
-            this->apidl = apidl;
-            this->cidl = cidl;
-            pObj->AddRef();
-            hr = S_OK;
+            
+            /* HACK: We should use callbacks from CDefaultContextMenu instead of creating one on our own */
+            BOOL bHasCpl = FALSE;
+            for (UINT i = 0; i < cidl; i++)
+            {
+                if(_ILIsCPanelStruct(apidl[i]))
+                {
+                    bHasCpl = TRUE;
+                }
+            }
+
+            if (bHasCpl)
+                hr = ShellObjectCreatorInit<CCPLItemMenu>(cidl, apidl, riid, &pObj);
+            else
+                hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
         } else if (IsEqualIID(riid, IID_IDataObject) && (cidl >= 1)) {
             hr = IDataObject_Constructor(hwndOwner, pidlRoot, apidl, cidl, (IDataObject **)&pObj);
-        } else if (IsEqualIID(riid, IID_IExtractIconA) && (cidl == 1)) {
-            pidl = ILCombine(pidlRoot, apidl[0]);
-            pObj = IExtractIconA_Constructor(pidl);
-            SHFree(pidl);
-            hr = S_OK;
-        } else if (IsEqualIID(riid, IID_IExtractIconW) && (cidl == 1)) {
-            pidl = ILCombine(pidlRoot, apidl[0]);
-            pObj = IExtractIconW_Constructor(pidl);
-            SHFree(pidl);
-            hr = S_OK;
-        } else if ((IsEqualIID(riid, IID_IShellLinkW) || IsEqualIID(riid, IID_IShellLinkA))
-                   && (cidl == 1)) {
-            pidl = ILCombine(pidlRoot, apidl[0]);
-            hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*)&pObj);
-            SHFree(pidl);
+        } else if ((IsEqualIID(riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW)) && (cidl == 1)) {
+            if (_ILGetCPanelPointer(apidl[0]))
+                hr = CCPLExtractIcon_CreateInstance(this, apidl[0], riid, &pObj);
+            else
+                hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
         } else {
             hr = E_NOINTERFACE;
         }
@@ -550,70 +483,21 @@ HRESULT WINAPI CControlPanelFolder::GetUIObjectOf(HWND hwndOwner,
 */
 HRESULT WINAPI CControlPanelFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
 {
-    CHAR szName[MAX_PATH];
-    WCHAR wszName[MAX_PATH+1]; /* +1 for potential backslash */
-    PIDLCPanelStruct *pCPanel;
-    HRESULT hr;
-
-    *szName = '\0';
-
-    TRACE("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
-    pdump(pidl);
-
     if (!pidl)
         return S_FALSE;
 
-    pCPanel = _ILGetCPanelPointer(pidl);
+    PIDLCPanelStruct *pCPanel = _ILGetCPanelPointer(pidl);
 
     if (pCPanel)
     {
-        /* copy display name from pidl - it was retrived from applet before;
-           SHGDN_FORPARSING does not need special handling */
-        lstrcpyA(szName, pCPanel->szName + pCPanel->offsDispName);
+        return SHSetStrRet(strRet, pCPanel->szName + pCPanel->offsDispName);
     }
-    /* take names of special folders only if it's only this folder */
     else if (_ILIsSpecialFolder(pidl))
     {
-        BOOL bSimplePidl = _ILIsPidlSimple(pidl);
-        SFGAOF Attr = SFGAO_FILESYSTEM;
-
-        SHELL32_GetItemAttributes(this, pidl, &Attr);
-        if (Attr & SFGAO_FILESYSTEM)
-        {
-            hr = SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, wszName, sizeof(wszName));
-            if (FAILED(hr))
-                return hr;
-        }
-        else if (bSimplePidl)
-        {
-            _ILSimpleGetTextW(pidl, wszName, MAX_PATH);    /* append my own path */
-        }
-        else
-        {
-            FIXME("special pidl\n");
-            if (dwFlags & SHGDN_FORPARSING)
-            {
-                /* go deeper if needed */
-                int cchName;
-
-                PathAddBackslashW(wszName);
-                cchName = wcslen(wszName);
-
-                hr = SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, wszName + cchName, MAX_PATH + 1 - cchName);
-                if (FAILED(hr))
-                    return hr;
-            }
-        }
-
-        if (!WideCharToMultiByte(CP_ACP, 0, wszName, -1, szName, MAX_PATH, NULL, NULL))
-            szName[0] = '\0';
+        return m_regFolder->GetDisplayNameOf(pidl, dwFlags, strRet);
     }
 
-    strRet->uType = STRRET_CSTR;
-    lstrcpynA(strRet->cStr, szName, MAX_PATH);
-
-    TRACE("--(%p)->(%s)\n", this, szName);
-    return S_OK;
+    return E_FAIL;
 }
 
 /**************************************************************************
@@ -673,34 +557,36 @@ HRESULT WINAPI CControlPanelFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHC
 
 HRESULT WINAPI CControlPanelFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
 {
-    HRESULT hr;
-
-    TRACE("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
-
     if (!psd || iColumn >= CONROLPANELSHELLVIEWCOLUMNS)
         return E_INVALIDARG;
 
-    if (!pidl) {
+    if (!pidl) 
+    {
         psd->fmt = ControlPanelSFHeader[iColumn].fmt;
         psd->cxChar = ControlPanelSFHeader[iColumn].cxChar;
-        psd->str.uType = STRRET_CSTR;
-        LoadStringA(shell32_hInstance, ControlPanelSFHeader[iColumn].colnameid, psd->str.cStr, MAX_PATH);
-        return S_OK;
-    } else {
-        psd->str.cStr[0] = 0x00;
-        psd->str.uType = STRRET_CSTR;
-        switch(iColumn) {
+        return SHSetStrRet(&psd->str, shell32_hInstance, ControlPanelSFHeader[iColumn].colnameid);
+    }
+    else if (_ILIsSpecialFolder(pidl))
+    {
+        return m_regFolder->GetDetailsOf(pidl, iColumn, psd);
+    }
+    else 
+    {
+        PIDLCPanelStruct *pCPanel = _ILGetCPanelPointer(pidl);
+
+        if (!pCPanel)
+            return E_FAIL;
+
+        switch(iColumn) 
+        {
             case 0:        /* name */
-                hr = GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
-                break;
+                return SHSetStrRet(&psd->str, pCPanel->szName + pCPanel->offsDispName);
             case 1:        /* comment */
-                _ILGetFileType(pidl, psd->str.cStr, MAX_PATH);
-                break;
+                return SHSetStrRet(&psd->str, pCPanel->szName + pCPanel->offsComment);
         }
-        hr = S_OK;
     }
 
-    return hr;
+    return S_OK;
 }
 
 HRESULT WINAPI CControlPanelFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
@@ -728,19 +614,31 @@ HRESULT WINAPI CControlPanelFolder::GetClassID(CLSID *lpClassId)
  *
  * NOTES: it makes no sense to change the pidl
  */
-HRESULT WINAPI CControlPanelFolder::Initialize(LPCITEMIDLIST pidl)
+HRESULT WINAPI CControlPanelFolder::Initialize(PCIDLIST_ABSOLUTE pidl)
 {
     if (pidlRoot)
         SHFree((LPVOID)pidlRoot);
 
     pidlRoot = ILClone(pidl);
+
+    /* Create the inner reg folder */
+    HRESULT hr;
+    static const WCHAR* pszCPanelPath = L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\\::{21EC2020-3AEA-1069-A2DD-08002B30309D}";
+    hr = CRegFolder_CreateInstance(&CLSID_ControlPanel,
+                                   pidlRoot,
+                                   pszCPanelPath, 
+                                   L"ControlPanel",
+                                   IID_PPV_ARG(IShellFolder2, &m_regFolder));
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
+
     return S_OK;
 }
 
 /**************************************************************************
  *    CControlPanelFolder::GetCurFolder
  */
-HRESULT WINAPI CControlPanelFolder::GetCurFolder(LPITEMIDLIST * pidl)
+HRESULT WINAPI CControlPanelFolder::GetCurFolder(PIDLIST_ABSOLUTE * pidl)
 {
     TRACE("(%p)->(%p)\n", this, pidl);
 
@@ -750,153 +648,93 @@ HRESULT WINAPI CControlPanelFolder::GetCurFolder(LPITEMIDLIST * pidl)
     return S_OK;
 }
 
-HRESULT CPanel_GetIconLocationW(LPCITEMIDLIST pidl, LPWSTR szIconFile, UINT cchMax, int* piIndex)
+CCPLItemMenu::CCPLItemMenu()
 {
-    PIDLCPanelStruct* pcpanel = _ILGetCPanelPointer(pidl);
-
-    if (!pcpanel)
-        return E_INVALIDARG;
+    m_apidl = NULL;
+    m_cidl = 0;
+}
 
-    MultiByteToWideChar(CP_ACP, 0, pcpanel->szName, -1, szIconFile, cchMax);
-    *piIndex = (int)pcpanel->iconIdx != -1 ? pcpanel->iconIdx : 0;
+HRESULT WINAPI CCPLItemMenu::Initialize(UINT cidl, PCUITEMID_CHILD_ARRAY apidl)
+{
+    m_cidl = cidl;
+    m_apidl = _ILCopyaPidl(apidl, m_cidl);
+    if (m_cidl && !m_apidl)
+        return E_OUTOFMEMORY;
 
     return S_OK;
 }
 
-/**************************************************************************
-* IContextMenu2 Implementation
-*/
+CCPLItemMenu::~CCPLItemMenu()
+{
+    _ILFreeaPidl(m_apidl, m_cidl);
+}
 
-/**************************************************************************
-* ICPanel_IContextMenu_QueryContextMenu()
-*/
-HRESULT WINAPI CControlPanelFolder::QueryContextMenu(
+HRESULT WINAPI CCPLItemMenu::QueryContextMenu(
     HMENU hMenu,
     UINT indexMenu,
     UINT idCmdFirst,
     UINT idCmdLast,
     UINT uFlags)
 {
-    WCHAR szBuffer[30] = {0};
-    ULONG Count = 1;
+    _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_OPEN, MFT_STRING, MAKEINTRESOURCEW(IDS_OPEN), MFS_DEFAULT);
+    _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + 1, MFT_SEPARATOR, NULL, MFS_ENABLED);
+    _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_CREATELINK, MFT_STRING, MAKEINTRESOURCEW(IDS_CREATELINK), MFS_ENABLED);
 
-    TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n",
-          this, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
-
-    if (LoadStringW(shell32_hInstance, IDS_OPEN, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
-    {
-        szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
-        _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_OPEN, MFT_STRING, szBuffer, MFS_DEFAULT); //FIXME identifier
-        Count++;
-    }
-
-    if (LoadStringW(shell32_hInstance, IDS_CREATELINK, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
-    {
-        if (Count)
-        {
-            _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count, MFT_SEPARATOR, NULL, MFS_ENABLED);
-        }
-        szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
-
-        _InsertMenuItemW(hMenu, indexMenu++, TRUE, IDS_CREATELINK, MFT_STRING, szBuffer, MFS_ENABLED); //FIXME identifier
-        Count++;
-    }
-    return MAKE_HRESULT(SEVERITY_SUCCESS, 0, Count);
+    return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 2);
 }
 
+EXTERN_C
+void WINAPI Control_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow);
+
 /**************************************************************************
 * ICPanel_IContextMenu_InvokeCommand()
 */
-HRESULT WINAPI CControlPanelFolder::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
+HRESULT WINAPI CCPLItemMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
 {
-    WCHAR szPath[MAX_PATH];
-    char szTarget[MAX_PATH];
-    STRRET strret;
-    WCHAR* pszPath;
-    INT Length, cLength;
-    CComPtr<IPersistFile>                ppf;
-    CComPtr<IShellLinkA>                isl;
     HRESULT hResult;
 
-    PIDLCPanelStruct *pcpanel = _ILGetCPanelPointer(apidl[0]);
+    PIDLCPanelStruct *pCPanel = _ILGetCPanelPointer(m_apidl[0]);
+    if(!pCPanel)
+        return E_FAIL;
 
     TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n", this, lpcmi, lpcmi->lpVerb, lpcmi->hwnd);
 
     if (lpcmi->lpVerb == MAKEINTRESOURCEA(IDS_OPEN)) //FIXME
     {
-        LPITEMIDLIST lpIDList = ILCombine(pidlRoot, apidl[0]);
+        /* Hardcode the command here; Executing a cpl file would be fine but we also need to run things like console.dll */
+        WCHAR wszParams[MAX_PATH];
+        PCWSTR wszFile = L"rundll32.exe";
+        PCWSTR wszFormat = L"shell32.dll,Control_RunDLL %s,%s";
 
-        if (!pcpanel)
-        {
-            /* UGLY HACK! */
-            LPSHELLBROWSER lpSB = (LPSHELLBROWSER)SendMessageW(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
-            HRESULT hr;
-
-            if (lpSB == NULL)
-                return E_FAIL;
-
-            hr = lpSB->BrowseObject(lpIDList, 0);
-            return hr;
-        }
+        wsprintfW(wszParams, wszFormat, pCPanel->szName, pCPanel->szName + pCPanel->offsDispName);
 
         /* Note: we pass the applet name to Control_RunDLL to distinguish between multiple applets in one .cpl file */
-        ShellExecuteA(NULL, "cplopen", pcpanel->szName, pcpanel->szName + pcpanel->offsDispName, NULL, 0);
+        ShellExecuteW(NULL, NULL, wszFile, wszParams, NULL, 0);
     }
     else if (lpcmi->lpVerb == MAKEINTRESOURCEA(IDS_CREATELINK)) //FIXME
     {
-        if (!SHGetSpecialFolderPathW(NULL, szPath, CSIDL_DESKTOPDIRECTORY, FALSE))
-            return E_FAIL;
+        CComPtr<IDataObject> pDataObj;
+        LPITEMIDLIST pidl = _ILCreateControlPanel();
 
-        pszPath = PathAddBackslashW(szPath);
-        if (!pszPath)
-            return E_FAIL;
+        hResult = SHCreateDataObject(pidl, m_cidl, m_apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj));
+        if (FAILED(hResult))
+            return hResult;
 
-        if (GetDisplayNameOf(apidl[0], SHGDN_FORPARSING, &strret) != S_OK)
-            return E_FAIL;
+        SHFree(pidl);
 
-        Length =  MAX_PATH - (pszPath - szPath);
-        cLength = strlen(strret.cStr);
-        if (Length < cLength + 5)
-        {
-            FIXME("\n");
-            return E_FAIL;
-        }
+        //FIXME: Use SHCreateLinks
+        CComPtr<IShellFolder> psf;
+        CComPtr<IDropTarget> pDT;
 
-        if (MultiByteToWideChar(CP_ACP, 0, strret.cStr, cLength + 1, pszPath, Length))
-        {
-            pszPath += cLength;
-            Length -= cLength;
-        }
+        hResult = SHGetDesktopFolder(&psf);
+        if (FAILED(hResult))
+            return hResult;
 
-        if (Length > 10)
-        {
-            wcscpy(pszPath, L" - ");
-            cLength = LoadStringW(shell32_hInstance, IDS_LNK_FILE, &pszPath[3], Length - 4) + 3;
-            if (cLength + 5 > Length)
-                cLength = Length - 5;
-            Length -= cLength;
-            pszPath += cLength;
-        }
-        wcscpy(pszPath, L".lnk");
+        hResult = psf->CreateViewObject(NULL, IID_PPV_ARG(IDropTarget, &pDT));
+        if (FAILED(hResult))
+            return hResult;
 
-        pcpanel = _ILGetCPanelPointer(ILFindLastID(apidl[0]));
-        if (pcpanel)
-        {
-            strncpy(szTarget, pcpanel->szName, MAX_PATH);
-        }
-        else
-        {
-            FIXME("Couldn't retrieve pointer to cpl structure\n");
-            return E_FAIL;
-        }
-        hResult = CShellLink::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellLinkA, &isl));
-        if (SUCCEEDED(hResult))
-        {
-            isl->SetPath(szTarget);
-            if (SUCCEEDED(isl->QueryInterface(IID_PPV_ARG(IPersistFile,&ppf))))
-                ppf->Save(szPath, TRUE);
-        }
-        return NOERROR;
+        SHSimulateDrop(pDT, pDataObj, MK_CONTROL|MK_SHIFT, NULL, NULL);
     }
     return S_OK;
 }
@@ -905,7 +743,7 @@ HRESULT WINAPI CControlPanelFolder::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
  *  ICPanel_IContextMenu_GetCommandString()
  *
  */
-HRESULT WINAPI CControlPanelFolder::GetCommandString(
+HRESULT WINAPI CCPLItemMenu::GetCommandString(
     UINT_PTR idCommand,
     UINT uFlags,
     UINT* lpReserved,
@@ -921,7 +759,7 @@ HRESULT WINAPI CControlPanelFolder::GetCommandString(
 /**************************************************************************
 * ICPanel_IContextMenu_HandleMenuMsg()
 */
-HRESULT WINAPI CControlPanelFolder::HandleMenuMsg(
+HRESULT WINAPI CCPLItemMenu::HandleMenuMsg(
     UINT uMsg,
     WPARAM wParam,
     LPARAM lParam)