--- /dev/null
- CComPtr<IDataObject> pDataObj;
+/*
+ * PROJECT: shell32
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: dll/win32/shell32/shv_item_new.c
+ * PURPOSE: provides default context menu implementation
+ * PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org)
+ */
+
+/*
+TODO:
+ The code in NotifyShellViewWindow to deliver commands to the view is broken. It is an excellent
+ example of the wrong way to do it.
+*/
+
+#include "precomp.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(dmenu);
+
+typedef struct _DynamicShellEntry_
+{
+ UINT iIdCmdFirst;
+ UINT NumIds;
+ CLSID ClassID;
+ IContextMenu *pCM;
+ struct _DynamicShellEntry_ *pNext;
+} DynamicShellEntry, *PDynamicShellEntry;
+
+typedef struct _StaticShellEntry_
+{
+ LPWSTR szVerb;
+ LPWSTR szClass;
+ struct _StaticShellEntry_ *pNext;
+} StaticShellEntry, *PStaticShellEntry;
+
+class CDefaultContextMenu :
+ public CComObjectRootEx<CComMultiThreadModelNoCS>,
+ public IContextMenu2
+{
+ private:
+ CComPtr<IShellFolder> m_psf;
+ UINT m_cidl;
+ PCUITEMID_CHILD_ARRAY m_apidl;
+ CComPtr<IDataObject> m_pDataObj;
+ PIDLIST_ABSOLUTE m_pidlFolder;
+ DWORD m_bGroupPolicyActive;
+ PDynamicShellEntry m_pDynamicEntries; /* first dynamic shell extension entry */
+ UINT m_iIdSHEFirst; /* first used id */
+ UINT m_iIdSHELast; /* last used id */
+ PStaticShellEntry m_pStaticEntries; /* first static shell extension entry */
+ UINT m_iIdSCMFirst; /* first static used id */
+ UINT m_iIdSCMLast; /* last static used id */
+
+ void AddStaticEntry(LPCWSTR pwszVerb, LPCWSTR pwszClass);
+ void AddStaticEntryForKey(HKEY hKey, LPCWSTR pwszClass);
+ void AddStaticEntryForFileClass(LPCWSTR pwszExt);
+ BOOL IsShellExtensionAlreadyLoaded(const CLSID *pclsid);
+ HRESULT LoadDynamicContextMenuHandler(HKEY hKey, const CLSID *pclsid);
+ BOOL EnumerateDynamicContextHandlerForKey(HKEY hRootKey);
+ UINT InsertMenuItemsOfDynamicContextMenuExtension(HMENU hMenu, UINT IndexMenu, UINT idCmdFirst, UINT idCmdLast);
+ UINT BuildBackgroundContextMenu(HMENU hMenu, UINT iIdCmdFirst, UINT iIdCmdLast, UINT uFlags);
+ UINT AddStaticContextMenusToMenu(HMENU hMenu, UINT IndexMenu);
+ UINT BuildShellItemContextMenu(HMENU hMenu, UINT iIdCmdFirst, UINT iIdCmdLast, UINT uFlags);
+ HRESULT DoPaste(LPCMINVOKECOMMANDINFO lpcmi, BOOL bLink);
+ HRESULT DoOpenOrExplore(LPCMINVOKECOMMANDINFO lpcmi);
+ HRESULT DoCreateLink(LPCMINVOKECOMMANDINFO lpcmi);
+ HRESULT DoRefresh(LPCMINVOKECOMMANDINFO lpcmi);
+ HRESULT DoDelete(LPCMINVOKECOMMANDINFO lpcmi);
+ HRESULT DoCopyOrCut(LPCMINVOKECOMMANDINFO lpcmi, BOOL bCopy);
+ HRESULT DoRename(LPCMINVOKECOMMANDINFO lpcmi);
+ HRESULT DoProperties(LPCMINVOKECOMMANDINFO lpcmi);
+ HRESULT DoFormat(LPCMINVOKECOMMANDINFO lpcmi);
+ HRESULT DoDynamicShellExtensions(LPCMINVOKECOMMANDINFO lpcmi);
+ HRESULT DoStaticShellExtensions(LPCMINVOKECOMMANDINFO lpcmi);
+ DWORD BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFO lpcmi, PStaticShellEntry pEntry);
+ HRESULT TryToBrowse(LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl, DWORD wFlags);
+ HRESULT InvokePidl(LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl, PStaticShellEntry pEntry);
+
+ public:
+ CDefaultContextMenu();
+ ~CDefaultContextMenu();
+ HRESULT WINAPI Initialize(const DEFCONTEXTMENU *pdcm);
+
+ // IContextMenu
+ virtual HRESULT WINAPI QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
+ virtual HRESULT WINAPI InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi);
+ virtual HRESULT WINAPI GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen);
+
+ // IContextMenu2
+ virtual HRESULT WINAPI HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+ BEGIN_COM_MAP(CDefaultContextMenu)
+ COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
+ COM_INTERFACE_ENTRY_IID(IID_IContextMenu2, IContextMenu2)
+ END_COM_MAP()
+};
+
+CDefaultContextMenu::CDefaultContextMenu() :
+ m_psf(NULL),
+ m_cidl(0),
+ m_apidl(NULL),
+ m_pDataObj(NULL),
+ m_pidlFolder(NULL),
+ m_bGroupPolicyActive(0),
+ m_pDynamicEntries(NULL),
+ m_iIdSHEFirst(0),
+ m_iIdSHELast(0),
+ m_pStaticEntries(NULL),
+ m_iIdSCMFirst(0),
+ m_iIdSCMLast(0)
+{
+}
+
+CDefaultContextMenu::~CDefaultContextMenu()
+{
+ /* Free dynamic shell extension entries */
+ PDynamicShellEntry pDynamicEntry = m_pDynamicEntries, pNextDynamic;
+ while (pDynamicEntry)
+ {
+ pNextDynamic = pDynamicEntry->pNext;
+ pDynamicEntry->pCM->Release();
+ HeapFree(GetProcessHeap(), 0, pDynamicEntry);
+ pDynamicEntry = pNextDynamic;
+ }
+
+ /* Free static shell extension entries */
+ PStaticShellEntry pStaticEntry = m_pStaticEntries, pNextStatic;
+ while (pStaticEntry)
+ {
+ pNextStatic = pStaticEntry->pNext;
+ HeapFree(GetProcessHeap(), 0, pStaticEntry->szClass);
+ HeapFree(GetProcessHeap(), 0, pStaticEntry->szVerb);
+ HeapFree(GetProcessHeap(), 0, pStaticEntry);
+ pStaticEntry = pNextStatic;
+ }
+
+ if (m_pidlFolder)
+ CoTaskMemFree(m_pidlFolder);
+ _ILFreeaPidl(const_cast<PITEMID_CHILD *>(m_apidl), m_cidl);
+}
+
+HRESULT WINAPI CDefaultContextMenu::Initialize(const DEFCONTEXTMENU *pdcm)
+{
+ CComPtr<IDataObject> pDataObj;
+
+ TRACE("cidl %u\n", pdcm->cidl);
+
+ m_cidl = pdcm->cidl;
+ m_apidl = const_cast<PCUITEMID_CHILD_ARRAY>(_ILCopyaPidl(pdcm->apidl, m_cidl));
+ if (m_cidl && !m_apidl)
+ return E_OUTOFMEMORY;
+ m_psf = pdcm->psf;
+
+ if (SUCCEEDED(SHCreateDataObject(pdcm->pidlFolder, pdcm->cidl, pdcm->apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj))))
+ m_pDataObj = pDataObj;
+
+ if (pdcm->pidlFolder)
+ {
+ m_pidlFolder = ILClone(pdcm->pidlFolder);
+ }
+ else
+ {
+ CComPtr<IPersistFolder2> pf = NULL;
+ if (SUCCEEDED(m_psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &pf))))
+ {
+ if (FAILED(pf->GetCurFolder(reinterpret_cast<LPITEMIDLIST*>(&m_pidlFolder))))
+ ERR("GetCurFolder failed\n");
+ }
+ TRACE("pidlFolder %p\n", m_pidlFolder);
+ }
+
+ return S_OK;
+}
+
+void
+CDefaultContextMenu::AddStaticEntry(const WCHAR *szVerb, const WCHAR *szClass)
+{
+ PStaticShellEntry pEntry = m_pStaticEntries, pLastEntry = NULL;
+ while(pEntry)
+ {
+ if (!wcsicmp(pEntry->szVerb, szVerb))
+ {
+ /* entry already exists */
+ return;
+ }
+ pLastEntry = pEntry;
+ pEntry = pEntry->pNext;
+ }
+
+ TRACE("adding verb %s szClass %s\n", debugstr_w(szVerb), debugstr_w(szClass));
+
+ pEntry = (StaticShellEntry *)HeapAlloc(GetProcessHeap(), 0, sizeof(StaticShellEntry));
+ if (pEntry)
+ {
+ pEntry->pNext = NULL;
+ pEntry->szVerb = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(szVerb) + 1) * sizeof(WCHAR));
+ if (pEntry->szVerb)
+ wcscpy(pEntry->szVerb, szVerb);
+ pEntry->szClass = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, (wcslen(szClass) + 1) * sizeof(WCHAR));
+ if (pEntry->szClass)
+ wcscpy(pEntry->szClass, szClass);
+ }
+
+ if (!wcsicmp(szVerb, L"open"))
+ {
+ /* open verb is always inserted in front */
+ pEntry->pNext = m_pStaticEntries;
+ m_pStaticEntries = pEntry;
+ }
+ else if (pLastEntry)
+ pLastEntry->pNext = pEntry;
+ else
+ m_pStaticEntries = pEntry;
+}
+
+void
+CDefaultContextMenu::AddStaticEntryForKey(HKEY hKey, const WCHAR *pwszClass)
+{
+ WCHAR wszName[40];
+ DWORD cchName, dwIndex = 0;
+
+ TRACE("AddStaticEntryForKey %x %ls\n", hKey, pwszClass);
+
+ while(TRUE)
+ {
+ cchName = _countof(wszName);
+ if (RegEnumKeyExW(hKey, dwIndex++, wszName, &cchName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
+ break;
+
+ AddStaticEntry(wszName, pwszClass);
+ }
+}
+
+void
+CDefaultContextMenu::AddStaticEntryForFileClass(const WCHAR * szExt)
+{
+ WCHAR szBuffer[100];
+ HKEY hKey;
+ LONG result;
+ DWORD dwBuffer;
+ UINT Length;
+ static WCHAR szShell[] = L"\\shell";
+ static WCHAR szShellAssoc[] = L"SystemFileAssociations\\";
+
+ TRACE("AddStaticEntryForFileClass entered with %s\n", debugstr_w(szExt));
+
+ Length = wcslen(szExt);
+ if (Length + (sizeof(szShell) / sizeof(WCHAR)) + 1 < sizeof(szBuffer) / sizeof(WCHAR))
+ {
+ wcscpy(szBuffer, szExt);
+ wcscpy(&szBuffer[Length], szShell);
+ result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey);
+ if (result == ERROR_SUCCESS)
+ {
+ szBuffer[Length] = 0;
+ AddStaticEntryForKey(hKey, szExt);
+ RegCloseKey(hKey);
+ }
+ }
+
+ dwBuffer = sizeof(szBuffer);
+ result = RegGetValueW(HKEY_CLASSES_ROOT, szExt, NULL, RRF_RT_REG_SZ, NULL, (LPBYTE)szBuffer, &dwBuffer);
+ if (result == ERROR_SUCCESS)
+ {
+ Length = wcslen(szBuffer);
+ if (Length + (sizeof(szShell) / sizeof(WCHAR)) + 1 < sizeof(szBuffer) / sizeof(WCHAR))
+ {
+ wcscpy(&szBuffer[Length], szShell);
+ TRACE("szBuffer %s\n", debugstr_w(szBuffer));
+
+ result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey);
+ if (result == ERROR_SUCCESS)
+ {
+ szBuffer[Length] = 0;
+ AddStaticEntryForKey(hKey, szBuffer);
+ RegCloseKey(hKey);
+ }
+ }
+ }
+
+ wcscpy(szBuffer, szShellAssoc);
+ dwBuffer = sizeof(szBuffer) - sizeof(szShellAssoc) - sizeof(WCHAR);
+ result = RegGetValueW(HKEY_CLASSES_ROOT, szExt, L"PerceivedType", RRF_RT_REG_SZ, NULL, (LPBYTE)&szBuffer[_countof(szShellAssoc) - 1], &dwBuffer);
+ if (result == ERROR_SUCCESS)
+ {
+ Length = wcslen(&szBuffer[_countof(szShellAssoc)]) + _countof(szShellAssoc);
+ wcscat(szBuffer, L"\\shell");
+ TRACE("szBuffer %s\n", debugstr_w(szBuffer));
+
+ result = RegOpenKeyExW(HKEY_CLASSES_ROOT, szBuffer, 0, KEY_READ | KEY_QUERY_VALUE, &hKey);
+ if (result == ERROR_SUCCESS)
+ {
+ szBuffer[Length] = 0;
+ AddStaticEntryForKey(hKey, szBuffer);
+ RegCloseKey(hKey);
+ }
+ }
+}
+
+static
+BOOL
+HasClipboardData()
+{
+ BOOL bRet = FALSE;
+ CComPtr<IDataObject> pDataObj;
+
+ if(SUCCEEDED(OleGetClipboard(&pDataObj)))
+ {
+ STGMEDIUM medium;
+ FORMATETC formatetc;
+
+ TRACE("pDataObj=%p\n", pDataObj.p);
+
+ /* Set the FORMATETC structure*/
+ InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
+ if(SUCCEEDED(pDataObj->GetData(&formatetc, &medium)))
+ {
+ bRet = TRUE;
+ ReleaseStgMedium(&medium);
+ }
+ }
+
+ return bRet;
+}
+
+static
+VOID
+DisablePasteOptions(HMENU hMenu)
+{
+ MENUITEMINFOW mii;
+
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_STATE;
+ mii.fState = MFS_DISABLED;
+
+ TRACE("result %d\n", SetMenuItemInfoW(hMenu, FCIDM_SHVIEW_INSERT, FALSE, &mii));
+ TRACE("result %d\n", SetMenuItemInfoW(hMenu, FCIDM_SHVIEW_INSERTLINK, FALSE, &mii));
+}
+
+BOOL
+CDefaultContextMenu::IsShellExtensionAlreadyLoaded(const CLSID *pclsid)
+{
+ PDynamicShellEntry pEntry = m_pDynamicEntries;
+
+ while (pEntry)
+ {
+ if (!memcmp(&pEntry->ClassID, pclsid, sizeof(CLSID)))
+ return TRUE;
+ pEntry = pEntry->pNext;
+ }
+
+ return FALSE;
+}
+
+HRESULT
+CDefaultContextMenu::LoadDynamicContextMenuHandler(HKEY hKey, const CLSID *pclsid)
+{
+ HRESULT hr;
+
+ TRACE("LoadDynamicContextMenuHandler entered with This %p hKey %p pclsid %s\n", this, hKey, wine_dbgstr_guid(pclsid));
+
+ if (IsShellExtensionAlreadyLoaded(pclsid))
+ return S_OK;
+
+ CComPtr<IContextMenu> pcm;
+ hr = SHCoCreateInstance(NULL, pclsid, NULL, IID_PPV_ARG(IContextMenu, &pcm));
+ if (hr != S_OK)
+ {
+ ERR("SHCoCreateInstance failed %x\n", GetLastError());
+ return hr;
+ }
+
+ CComPtr<IShellExtInit> pExtInit;
+ hr = pcm->QueryInterface(IID_PPV_ARG(IShellExtInit, &pExtInit));
+ if (hr != S_OK)
+ {
+ ERR("Failed to query for interface IID_IShellExtInit hr %x pclsid %s\n", hr, wine_dbgstr_guid(pclsid));
+ return hr;
+ }
+
+ hr = pExtInit->Initialize(m_pidlFolder, m_pDataObj, hKey);
+ if (hr != S_OK)
+ {
+ TRACE("Failed to initialize shell extension error %x pclsid %s\n", hr, wine_dbgstr_guid(pclsid));
+ return hr;
+ }
+
+ PDynamicShellEntry pEntry = (DynamicShellEntry *)HeapAlloc(GetProcessHeap(), 0, sizeof(DynamicShellEntry));
+ if (!pEntry)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ pEntry->iIdCmdFirst = 0;
+ pEntry->pNext = NULL;
+ pEntry->NumIds = 0;
+ pEntry->pCM = pcm.Detach();
+ memcpy(&pEntry->ClassID, pclsid, sizeof(CLSID));
+
+ if (m_pDynamicEntries)
+ {
+ PDynamicShellEntry pLastEntry = m_pDynamicEntries;
+
+ while (pLastEntry->pNext)
+ pLastEntry = pLastEntry->pNext;
+
+ pLastEntry->pNext = pEntry;
+ }
+ else
+ m_pDynamicEntries = pEntry;
+
+ return S_OK;
+}
+
+BOOL
+CDefaultContextMenu::EnumerateDynamicContextHandlerForKey(HKEY hRootKey)
+{
+
+ WCHAR wszName[MAX_PATH], wszBuf[MAX_PATH], *pwszClsid;
+ DWORD cchName;
+ HRESULT hr;
+ HKEY hKey;
+
+ if (RegOpenKeyExW(hRootKey, L"shellex\\ContextMenuHandlers", 0, KEY_READ, &hKey) != ERROR_SUCCESS)
+ {
+ TRACE("RegOpenKeyExW failed\n");
+ return FALSE;
+ }
+
+ DWORD dwIndex = 0;
+ while (TRUE)
+ {
+ cchName = _countof(wszName);
+ if (RegEnumKeyExW(hKey, dwIndex++, wszName, &cchName, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
+ break;
+
+ /* Key name or key value is CLSID */
+ CLSID clsid;
+ hr = CLSIDFromString(wszName, &clsid);
+ if (hr == S_OK)
+ pwszClsid = wszName;
+ else
+ {
+ DWORD cchBuf = _countof(wszBuf);
+ if (RegGetValueW(hKey, wszName, NULL, RRF_RT_REG_SZ, NULL, wszBuf, &cchBuf) == ERROR_SUCCESS)
+ hr = CLSIDFromString(wszBuf, &clsid);
+ pwszClsid = wszBuf;
+ }
+ if (SUCCEEDED(hr))
+ {
+ if (m_bGroupPolicyActive)
+ {
+ if (RegGetValueW(HKEY_LOCAL_MACHINE,
+ L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
+ pwszClsid,
+ RRF_RT_REG_SZ,
+ NULL,
+ NULL,
+ NULL) == ERROR_SUCCESS)
+ {
+ LoadDynamicContextMenuHandler(hKey, &clsid);
+ }
+ }
+ else
+ LoadDynamicContextMenuHandler(hKey, &clsid);
+ }
+ }
+
+ RegCloseKey(hKey);
+ return TRUE;
+}
+
+UINT
+CDefaultContextMenu::InsertMenuItemsOfDynamicContextMenuExtension(HMENU hMenu, UINT IndexMenu, UINT idCmdFirst, UINT idCmdLast)
+{
+ if (!m_pDynamicEntries)
+ {
+ m_iIdSHEFirst = 0;
+ m_iIdSHELast = 0;
+ return IndexMenu;
+ }
+
+ PDynamicShellEntry pEntry = m_pDynamicEntries;
+ idCmdFirst = 0x5000;
+ idCmdLast = 0x6000;
+ m_iIdSHEFirst = idCmdFirst;
+ do
+ {
+ HRESULT hr = pEntry->pCM->QueryContextMenu(hMenu, IndexMenu++, idCmdFirst, idCmdLast, CMF_NORMAL);
+ if (SUCCEEDED(hr))
+ {
+ pEntry->iIdCmdFirst = idCmdFirst;
+ pEntry->NumIds = LOWORD(hr);
+ IndexMenu += pEntry->NumIds;
+ idCmdFirst += pEntry->NumIds + 0x10;
+ }
+ TRACE("pEntry %p hr %x contextmenu %p cmdfirst %x num ids %x\n", pEntry, hr, pEntry->pCM, pEntry->iIdCmdFirst, pEntry->NumIds);
+ pEntry = pEntry->pNext;
+ } while (pEntry);
+
+ m_iIdSHELast = idCmdFirst;
+ TRACE("SH_LoadContextMenuHandlers first %x last %x\n", m_iIdSHEFirst, m_iIdSHELast);
+ return IndexMenu;
+}
+
+UINT
+CDefaultContextMenu::BuildBackgroundContextMenu(
+ HMENU hMenu,
+ UINT iIdCmdFirst,
+ UINT iIdCmdLast,
+ UINT uFlags)
+{
+ UINT IndexMenu = 0;
+ HMENU hSubMenu;
+
+ TRACE("BuildBackgroundContextMenu entered\n");
+
+ if (!_ILIsDesktop(m_pidlFolder))
+ {
+ WCHAR wszBuf[MAX_PATH];
+
+ /* view option is only available in browsing mode */
+ hSubMenu = LoadMenuW(shell32_hInstance, L"MENU_001");
+ if (hSubMenu && LoadStringW(shell32_hInstance, FCIDM_SHVIEW_VIEW, wszBuf, _countof(wszBuf)))
+ {
+ TRACE("wszBuf %s\n", debugstr_w(wszBuf));
+
+ MENUITEMINFOW mii;
+ ZeroMemory(&mii, sizeof(mii));
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_SUBMENU | MIIM_ID;
+ mii.fType = MFT_STRING;
+ mii.wID = iIdCmdFirst++;
+ mii.dwTypeData = wszBuf;
+ mii.cch = wcslen(mii.dwTypeData);
+ mii.fState = MFS_ENABLED;
+ mii.hSubMenu = hSubMenu;
+ InsertMenuItemW(hMenu, IndexMenu++, TRUE, &mii);
+ DestroyMenu(hSubMenu);
+ }
+ }
+
+ hSubMenu = LoadMenuW(shell32_hInstance, L"MENU_002");
+ if (hSubMenu)
+ {
+ /* merge general background context menu in */
+ iIdCmdFirst = Shell_MergeMenus(hMenu, GetSubMenu(hSubMenu, 0), IndexMenu, 0, 0xFFFF, MM_DONTREMOVESEPS | MM_SUBMENUSHAVEIDS) + 1;
+ DestroyMenu(hSubMenu);
+ }
+
+ if (!HasClipboardData())
+ {
+ TRACE("disabling paste options\n");
+ DisablePasteOptions(hMenu);
+ }
+
+ /* Directory is progid of filesystem folders only */
+ LPITEMIDLIST pidlFolderLast = ILFindLastID(m_pidlFolder);
+ if (_ILIsDesktop(pidlFolderLast) || _ILIsDrive(pidlFolderLast) || _ILIsFolder(pidlFolderLast))
+ {
+ /* Load context menu handlers */
+ TRACE("Add background handlers: %p\n", m_pidlFolder);
+ HKEY hKey;
+ if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Directory\\Background", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
+ {
+ EnumerateDynamicContextHandlerForKey(hKey);
+ RegCloseKey(hKey);
+ }
+
+ if (InsertMenuItemsOfDynamicContextMenuExtension(hMenu, GetMenuItemCount(hMenu) - 1, iIdCmdFirst, iIdCmdLast))
+ {
+ /* seperate dynamic context menu items */
+ _InsertMenuItemW(hMenu, GetMenuItemCount(hMenu) - 1, TRUE, -1, MFT_SEPARATOR, NULL, MFS_ENABLED);
+ }
+ }
+
+ return iIdCmdLast;
+}
+
+UINT
+CDefaultContextMenu::AddStaticContextMenusToMenu(
+ HMENU hMenu,
+ UINT IndexMenu)
+{
+ MENUITEMINFOW mii;
+ UINT idResource;
+ WCHAR wszVerb[40];
+ UINT fState;
+
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_DATA;
+ mii.fType = MFT_STRING;
+ mii.wID = 0x4000;
+ mii.dwTypeData = NULL;
+ m_iIdSCMFirst = mii.wID;
+
+ PStaticShellEntry pEntry = m_pStaticEntries;
+
+ while (pEntry)
+ {
+ fState = MFS_ENABLED;
+ mii.dwTypeData = NULL;
+
+ /* set first entry as default */
+ if (pEntry == m_pStaticEntries)
+ fState |= MFS_DEFAULT;
+
+ if (!wcsicmp(pEntry->szVerb, L"open"))
+ {
+ /* override default when open verb is found */
+ fState |= MFS_DEFAULT;
+ idResource = IDS_OPEN_VERB;
+ }
+ else if (!wcsicmp(pEntry->szVerb, L"explore"))
+ idResource = IDS_EXPLORE_VERB;
+ else if (!wcsicmp(pEntry->szVerb, L"runas"))
+ idResource = IDS_RUNAS_VERB;
+ else if (!wcsicmp(pEntry->szVerb, L"edit"))
+ idResource = IDS_EDIT_VERB;
+ else if (!wcsicmp(pEntry->szVerb, L"find"))
+ idResource = IDS_FIND_VERB;
+ else if (!wcsicmp(pEntry->szVerb, L"print"))
+ idResource = IDS_PRINT_VERB;
+ else if (!wcsicmp(pEntry->szVerb, L"printto"))
+ {
+ pEntry = pEntry->pNext;
+ continue;
+ }
+ else
+ idResource = 0;
+
+ /* By default use verb for menu item name */
+ mii.dwTypeData = pEntry->szVerb;
+
+ if (idResource > 0)
+ {
+ if (LoadStringW(shell32_hInstance, idResource, wszVerb, _countof(wszVerb)))
+ mii.dwTypeData = wszVerb; /* use translated verb */
+ else
+ ERR("Failed to load string\n");
+ }
+ else
+ {
+ WCHAR wszKey[256];
+ HRESULT hr = StringCbPrintfW(wszKey, sizeof(wszKey), L"%s\\shell\\%s", pEntry->szClass, pEntry->szVerb);
+
+ if (SUCCEEDED(hr))
+ {
+ DWORD cbVerb = sizeof(wszVerb);
+
+ if (RegGetValueW(HKEY_CLASSES_ROOT, wszKey, NULL, RRF_RT_REG_SZ, NULL, wszVerb, &cbVerb) == ERROR_SUCCESS)
+ mii.dwTypeData = wszVerb; /* use description for the menu entry */
+ }
+ }
+
+ mii.cch = wcslen(mii.dwTypeData);
+ mii.fState = fState;
+ InsertMenuItemW(hMenu, IndexMenu++, TRUE, &mii);
+
+ mii.wID++;
+ pEntry = pEntry->pNext;
+ }
+
+ m_iIdSCMLast = mii.wID - 1;
+ return IndexMenu;
+}
+
+void WINAPI _InsertMenuItemW(
+ HMENU hMenu,
+ UINT indexMenu,
+ BOOL fByPosition,
+ UINT wID,
+ UINT fType,
+ LPCWSTR dwTypeData,
+ UINT fState)
+{
+ MENUITEMINFOW mii;
+ WCHAR wszText[100];
+
+ ZeroMemory(&mii, sizeof(mii));
+ mii.cbSize = sizeof(mii);
+ if (fType == MFT_SEPARATOR)
+ mii.fMask = MIIM_ID | MIIM_TYPE;
+ else if (fType == MFT_STRING)
+ {
+ mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
+ if ((ULONG_PTR)HIWORD((ULONG_PTR)dwTypeData) == 0)
+ {
+ if (LoadStringW(shell32_hInstance, LOWORD((ULONG_PTR)dwTypeData), wszText, _countof(wszText)))
+ mii.dwTypeData = wszText;
+ else
+ {
+ ERR("failed to load string %p\n", dwTypeData);
+ return;
+ }
+ }
+ else
+ mii.dwTypeData = (LPWSTR)dwTypeData;
+ mii.fState = fState;
+ }
+
+ mii.wID = wID;
+ mii.fType = fType;
+ InsertMenuItemW(hMenu, indexMenu, fByPosition, &mii);
+}
+
+UINT
+CDefaultContextMenu::BuildShellItemContextMenu(
+ HMENU hMenu,
+ UINT iIdCmdFirst,
+ UINT iIdCmdLast,
+ UINT uFlags)
+{
+ HKEY hKey;
+ HRESULT hr;
+
+ TRACE("BuildShellItemContextMenu entered\n");
+ ASSERT(m_cidl >= 1);
+
+ STRRET strFile;
+ hr = m_psf->GetDisplayNameOf(m_apidl[0], SHGDN_FORPARSING, &strFile);
+ if (hr == S_OK)
+ {
+ WCHAR wszPath[MAX_PATH];
+ hr = StrRetToBufW(&strFile, m_apidl[0], wszPath, _countof(wszPath));
+ if (hr == S_OK)
+ {
+ LPCWSTR pwszExt = PathFindExtensionW(wszPath);
+ if (pwszExt[0])
+ {
+ /* enumerate dynamic/static for a given file class */
+ if (RegOpenKeyExW(HKEY_CLASSES_ROOT, pwszExt, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
+ {
+ /* add static verbs */
+ AddStaticEntryForFileClass(pwszExt);
+
+ /* load dynamic extensions from file extension key */
+ EnumerateDynamicContextHandlerForKey(hKey);
+ RegCloseKey(hKey);
+ }
+
+ WCHAR wszTemp[40];
+ DWORD dwSize = sizeof(wszTemp);
+ if (RegGetValueW(HKEY_CLASSES_ROOT, pwszExt, NULL, RRF_RT_REG_SZ, NULL, wszTemp, &dwSize) == ERROR_SUCCESS)
+ {
+ if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszTemp, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
+ {
+ /* add static verbs from progid key */
+ AddStaticEntryForFileClass(wszTemp);
+
+ /* load dynamic extensions from progid key */
+ EnumerateDynamicContextHandlerForKey(hKey);
+ RegCloseKey(hKey);
+ }
+ }
+ }
+
+ if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"*", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
+ {
+ /* load default extensions */
+ EnumerateDynamicContextHandlerForKey(hKey);
+ RegCloseKey(hKey);
+ }
+ }
+ }
+ else
+ ERR("GetDisplayNameOf failed: %x\n", hr);
+
+ GUID *pGuid = _ILGetGUIDPointer(m_apidl[0]);
+ if (pGuid)
+ {
+ LPOLESTR pwszCLSID;
+ WCHAR buffer[60];
+
+ wcscpy(buffer, L"CLSID\\");
+ hr = StringFromCLSID(*pGuid, &pwszCLSID);
+ if (hr == S_OK)
+ {
+ wcscpy(&buffer[6], pwszCLSID);
+ TRACE("buffer %s\n", debugstr_w(buffer));
+ if (RegOpenKeyExW(HKEY_CLASSES_ROOT, buffer, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
+ {
+ EnumerateDynamicContextHandlerForKey(hKey);
+ AddStaticEntryForFileClass(buffer);
+ RegCloseKey(hKey);
+ }
+ CoTaskMemFree(pwszCLSID);
+ }
+ }
+
+ if (_ILIsDrive(m_apidl[0]))
+ {
+ AddStaticEntryForFileClass(L"Drive");
+ if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Drive", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
+ {
+ EnumerateDynamicContextHandlerForKey(hKey);
+ RegCloseKey(hKey);
+ }
+
+ }
+
+ /* add static actions */
+ SFGAOF rfg = SFGAO_BROWSABLE | SFGAO_CANCOPY | SFGAO_CANLINK | SFGAO_CANMOVE | SFGAO_CANDELETE | SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSTEM | SFGAO_FOLDER;
+ hr = m_psf->GetAttributesOf(m_cidl, m_apidl, &rfg);
+ if (FAILED(hr))
+ {
+ ERR("GetAttributesOf failed: %x\n", hr);
+ rfg = 0;
+ }
+
+ if (rfg & SFGAO_FOLDER)
+ {
+ /* add the default verbs open / explore */
+ AddStaticEntryForFileClass(L"Folder");
+ if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Folder", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
+ {
+ EnumerateDynamicContextHandlerForKey(hKey);
+ RegCloseKey(hKey);
+ }
+
+ /* Directory is only loaded for real filesystem directories */
+ if (_ILIsFolder(m_apidl[0]))
+ {
+ AddStaticEntryForFileClass(L"Directory");
+ if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Directory", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
+ {
+ EnumerateDynamicContextHandlerForKey(hKey);
+ RegCloseKey(hKey);
+ }
+ }
+ }
+
+ /* AllFilesystemObjects class is loaded only for files and directories */
+ if (_ILIsFolder(m_apidl[0]) || _ILIsValue(m_apidl[0]))
+ {
+ if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"AllFilesystemObjects", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
+ {
+ /* sendto service is registered here */
+ EnumerateDynamicContextHandlerForKey(hKey);
+ RegCloseKey(hKey);
+ }
+ }
+
+ /* add static context menu handlers */
+ UINT IndexMenu = AddStaticContextMenusToMenu(hMenu, 0);
+
+ /* now process dynamic context menu handlers */
+ BOOL bAddSep = FALSE;
+ IndexMenu = InsertMenuItemsOfDynamicContextMenuExtension(hMenu, IndexMenu, iIdCmdFirst, iIdCmdLast);
+ TRACE("IndexMenu %d\n", IndexMenu);
+
+ if (_ILIsDrive(m_apidl[0]))
+ {
+ /* The 'Format' option must be always available,
+ * thus it is not registered as a static shell extension */
+ _InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
+ _InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0x7ABC, MFT_STRING, MAKEINTRESOURCEW(IDS_FORMATDRIVE), MFS_ENABLED);
+ bAddSep = TRUE;
+ }
+
+ BOOL bClipboardData = (HasClipboardData() && (rfg & SFGAO_FILESYSTEM));
+ if (rfg & (SFGAO_CANCOPY | SFGAO_CANMOVE) || bClipboardData)
+ {
+ _InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
+ if (rfg & SFGAO_CANMOVE)
+ _InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_CUT, MFT_STRING, MAKEINTRESOURCEW(IDS_CUT), MFS_ENABLED);
+ if (rfg & SFGAO_CANCOPY)
+ _InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_COPY, MFT_STRING, MAKEINTRESOURCEW(IDS_COPY), MFS_ENABLED);
+ if (bClipboardData)
+ _InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_INSERT, MFT_STRING, MAKEINTRESOURCEW(IDS_INSERT), MFS_ENABLED);
+
+ bAddSep = TRUE;
+ }
+
+ if (rfg & SFGAO_CANLINK)
+ {
+ bAddSep = FALSE;
+ _InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
+ _InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_CREATELINK, MFT_STRING, MAKEINTRESOURCEW(IDS_CREATELINK), MFS_ENABLED);
+ }
+
+ if (rfg & SFGAO_CANDELETE)
+ {
+ if (bAddSep)
+ {
+ bAddSep = FALSE;
+ _InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
+ }
+ _InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_DELETE, MFT_STRING, MAKEINTRESOURCEW(IDS_DELETE), MFS_ENABLED);
+ }
+
+ if (rfg & SFGAO_CANRENAME)
+ {
+ if (bAddSep)
+ {
+ _InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
+ }
+ _InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_RENAME, MFT_STRING, MAKEINTRESOURCEW(IDS_RENAME), MFS_ENABLED);
+ bAddSep = TRUE;
+ }
+
+ if (rfg & SFGAO_HASPROPSHEET)
+ {
+ _InsertMenuItemW(hMenu, IndexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
+ _InsertMenuItemW(hMenu, IndexMenu++, TRUE, FCIDM_SHVIEW_PROPERTIES, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED);
+ }
+
+ return iIdCmdLast;
+}
+
+HRESULT
+WINAPI
+CDefaultContextMenu::QueryContextMenu(
+ HMENU hMenu,
+ UINT IndexMenu,
+ UINT idCmdFirst,
+ UINT idCmdLast,
+ UINT uFlags)
+{
+ if (m_cidl)
+ idCmdFirst = BuildShellItemContextMenu(hMenu, idCmdFirst, idCmdLast, uFlags);
+ else
+ idCmdFirst = BuildBackgroundContextMenu(hMenu, idCmdFirst, idCmdLast, uFlags);
+
+ return S_OK;
+}
+
+static
+HRESULT
+NotifyShellViewWindow(LPCMINVOKECOMMANDINFO lpcmi, BOOL bRefresh)
+{
+ /* Note: CWM_GETISHELLBROWSER returns not referenced object */
+ LPSHELLBROWSER lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
+ if (!lpSB)
+ return E_FAIL;
+
+ CComPtr<IShellView> lpSV;
+ if (FAILED(lpSB->QueryActiveShellView(&lpSV)))
+ return E_FAIL;
+
+ HWND hwndSV = NULL;
+ if (SUCCEEDED(lpSV->GetWindow(&hwndSV)))
+ SendMessageW(hwndSV, WM_COMMAND, MAKEWPARAM(LOWORD(lpcmi->lpVerb), 0), 0);
+ return S_OK;
+}
+
+HRESULT
+CDefaultContextMenu::DoRefresh(
+ LPCMINVOKECOMMANDINFO lpcmi)
+{
+ CComPtr<IPersistFolder2> ppf2 = NULL;
+ LPITEMIDLIST pidl;
+ HRESULT hr = m_psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
+ if (SUCCEEDED(hr))
+ {
+ hr = ppf2->GetCurFolder(&pidl);
+ if (SUCCEEDED(hr))
+ {
+ SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_IDLIST, pidl, NULL);
+ ILFree(pidl);
+ }
+ }
+ return hr;
+}
+
+HRESULT
+CDefaultContextMenu::DoPaste(
+ LPCMINVOKECOMMANDINFO lpcmi, BOOL bLink)
+{
+ HRESULT hr;
+
+ CComPtr<IDataObject> pda;
+ hr = OleGetClipboard(&pda);
+ if (FAILED(hr))
+ return hr;
+
+ CComPtr<IShellFolder> psfDesktop;
+ CComPtr<IShellFolder> psfTarget = NULL;
+
+ hr = SHGetDesktopFolder(&psfDesktop);
+ if (FAILED(hr))
+ return hr;
+
+ /* Find target folder */
+ if (m_cidl)
+ {
+ hr = m_psf->BindToObject(m_apidl[0], NULL, IID_PPV_ARG(IShellFolder, &psfTarget));
+ }
+ else
+ {
+ CComPtr<IPersistFolder2> ppf2 = NULL;
+ LPITEMIDLIST pidl;
+
+ /* cidl is zero due to explorer view */
+ hr = m_psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
+ if (SUCCEEDED(hr))
+ {
+ hr = ppf2->GetCurFolder(&pidl);
+ if (SUCCEEDED(hr))
+ {
+ if (_ILIsDesktop(pidl))
+ {
+ /* use desktop shellfolder */
+ psfTarget = psfDesktop;
+ }
+ else
+ {
+ /* retrieve target desktop folder */
+ hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfTarget));
+ }
+ TRACE("psfTarget %x %p, Desktop %u\n", hr, psfTarget.p, _ILIsDesktop(pidl));
+ ILFree(pidl);
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ ERR("no IShellFolder\n");
+ return hr;
+ }
+
+ FORMATETC formatetc2;
+ STGMEDIUM medium2;
+ InitFormatEtc(formatetc2, RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECT), TYMED_HGLOBAL);
+
+ DWORD dwKey= 0;
+
+ if (SUCCEEDED(pda->GetData(&formatetc2, &medium2)))
+ {
+ DWORD * pdwFlag = (DWORD*)GlobalLock(medium2.hGlobal);
+ if (pdwFlag)
+ {
+ if (*pdwFlag == DROPEFFECT_COPY)
+ dwKey = MK_CONTROL;
+ else
+ dwKey = MK_SHIFT;
+ }
+ else {
+ ERR("No drop effect obtained");
+ }
+ GlobalUnlock(medium2.hGlobal);
+ }
+
+ if (bLink)
+ {
+ dwKey = MK_CONTROL|MK_SHIFT;
+ }
+
+ CComPtr<IDropTarget> pdrop;
+ hr = psfTarget->QueryInterface(IID_PPV_ARG(IDropTarget, &pdrop));
+ if (FAILED(hr))
+ {
+ ERR("Error getting IDropTarget interface\n");
+ return hr;
+ }
+
+ SHSimulateDrop(pdrop, pda, dwKey, NULL, NULL);
+
+ TRACE("CP result %x\n", hr);
+ return S_OK;
+}
+
+HRESULT
+CDefaultContextMenu::DoOpenOrExplore(
+ LPCMINVOKECOMMANDINFO lpcmi)
+{
+ UNIMPLEMENTED;
+ return E_FAIL;
+}
+
+HRESULT
+CDefaultContextMenu::DoCreateLink(
+ LPCMINVOKECOMMANDINFO lpcmi)
+{
+ CComPtr<IDataObject> pDataObj;
+ CComPtr<IDropTarget> pDT;
+ HRESULT hr;
+ CComPtr<IPersistFolder2> ppf2 = NULL;
+ LPITEMIDLIST pidl;
+ CComPtr<IShellFolder> psfDesktop;
+ CComPtr<IShellFolder> psfTarget = NULL;
+
+ hr = SHGetDesktopFolder(&psfDesktop);
+ if (FAILED(hr))
+ return hr;
+
+ if (SUCCEEDED(hr = SHCreateDataObject(m_pidlFolder, m_cidl, m_apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj))))
+ {
+ hr = m_psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
+ if (SUCCEEDED(hr))
+ {
+ hr = ppf2->GetCurFolder(&pidl);
+ if (SUCCEEDED(hr))
+ {
+ if (_ILIsDesktop(pidl))
+ {
+ /* use desktop shellfolder */
+ psfTarget = psfDesktop;
+ }
+ else
+ {
+ /* retrieve target desktop folder */
+ hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfTarget));
+ }
+ TRACE("psfTarget %x %p, Desktop %u\n", hr, psfTarget.p, _ILIsDesktop(pidl));
+ ILFree(pidl);
+ }
+ }
+
+ }
+
+ if (FAILED(hr))
+ {
+ ERR("no IShellFolder\n");
+ return hr;
+ }
+
+ psfTarget->QueryInterface(IID_PPV_ARG(IDropTarget, &pDT));
+ if (FAILED(hr))
+ {
+ ERR("no IDropTarget Interface\n");
+ return hr;
+ }
+ SHSimulateDrop(pDT, pDataObj, MK_CONTROL|MK_SHIFT, NULL, NULL);
+
+ return S_OK;
+}
+
+HRESULT CDefaultContextMenu::DoDelete(LPCMINVOKECOMMANDINFO lpcmi) {
+ TRACE("(%p) Deleting\n", this);
+
- if (SUCCEEDED(SHCreateDataObject(m_pidlFolder, m_cidl, m_apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj))))
++ CComPtr<IDataObject> pDataObject;
+
- SHCreateThread(DoDeleteThreadProc, pDataObj, NULL, NULL);
++ if (SUCCEEDED(SHCreateDataObject(m_pidlFolder, m_cidl, m_apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObject))))
+ {
-
++ IStream *s;
++ CoMarshalInterThreadInterfaceInStream(IID_IDataObject, pDataObject, &s);
++ SHCreateThread(DoDeleteThreadProc, s, NULL, NULL);
+ }
+ else
+ return E_FAIL;
+ return S_OK;
+}
+
+HRESULT
+CDefaultContextMenu::DoCopyOrCut(
+ LPCMINVOKECOMMANDINFO lpcmi,
+ BOOL bCopy)
+{
+ CComPtr<IDataObject> pDataObj;
+ HRESULT hr;
+
+ if (SUCCEEDED(SHCreateDataObject(m_pidlFolder, m_cidl, m_apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj))))
+ {
+ if (!bCopy)
+ {
+ FORMATETC formatetc;
+ STGMEDIUM medium;
+ InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECT), TYMED_HGLOBAL);
+ pDataObj->GetData(&formatetc, &medium);
+ DWORD * pdwFlag = (DWORD*)GlobalLock(medium.hGlobal);
+ if (pdwFlag)
+ *pdwFlag = DROPEFFECT_MOVE;
+ GlobalUnlock(medium.hGlobal);
+ pDataObj->SetData(&formatetc, &medium, TRUE);
+ }
+
+ hr = OleSetClipboard(pDataObj);
+ return hr;
+ }
+
+ /* Note: CWM_GETISHELLBROWSER returns not referenced object */
+ LPSHELLBROWSER lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
+ if (!lpSB)
+ {
+ ERR("failed to get shellbrowser\n");
+ return E_FAIL;
+ }
+
+ CComPtr<IShellView> lpSV;
+ hr = lpSB->QueryActiveShellView(&lpSV);
+ if (FAILED(hr))
+ {
+ ERR("failed to query the active shellview\n");
+ return hr;
+ }
+
+ hr = lpSV->GetItemObject(SVGIO_SELECTION, IID_PPV_ARG(IDataObject, &pDataObj));
+ if (SUCCEEDED(hr))
+ {
+ hr = OleSetClipboard(pDataObj);
+ if (FAILED(hr))
+ ERR("OleSetClipboard failed");
+ pDataObj->Release();
+ } else
+ ERR("failed to get item object\n");
+
+ return hr;
+}
+
+HRESULT
+CDefaultContextMenu::DoRename(
+ LPCMINVOKECOMMANDINFO lpcmi)
+{
+ /* get the active IShellView. Note: CWM_GETISHELLBROWSER returns not referenced object */
+ LPSHELLBROWSER lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
+ if (!lpSB)
+ {
+ ERR("CWM_GETISHELLBROWSER failed\n");
+ return E_FAIL;
+ }
+
+ /* is the treeview focused */
+ HWND hwnd;
+ if (SUCCEEDED(lpSB->GetControlWindow(FCW_TREE, &hwnd)))
+ {
+ HTREEITEM hItem = TreeView_GetSelection(hwnd);
+ if (hItem)
+ (void)TreeView_EditLabel(hwnd, hItem);
+ }
+
+ CComPtr<IShellView> lpSV;
+ HRESULT hr = lpSB->QueryActiveShellView(&lpSV);
+ if (FAILED(hr))
+ {
+ ERR("CWM_GETISHELLBROWSER failed\n");
+ return hr;
+ }
+
+ SVSIF selFlags = SVSI_DESELECTOTHERS | SVSI_EDIT | SVSI_ENSUREVISIBLE | SVSI_FOCUSED | SVSI_SELECT;
+ lpSV->SelectItem(m_apidl[0], selFlags);
+ return S_OK;
+}
+
+HRESULT
+CDefaultContextMenu::DoProperties(
+ LPCMINVOKECOMMANDINFO lpcmi)
+{
+ HRESULT hr = S_OK;
+ const ITEMIDLIST *pidlParent = m_pidlFolder, *pidlChild;
+
+ if (!pidlParent)
+ {
+ CComPtr<IPersistFolder2> pf;
+
+ /* pidlFolder is optional */
+ if (SUCCEEDED(m_psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &pf))))
+ {
+ pf->GetCurFolder((_ITEMIDLIST**)&pidlParent);
+ }
+ }
+
+ if (m_cidl > 0)
+ pidlChild = m_apidl[0];
+ else
+ {
+ /* Set pidlChild to last pidl of current folder */
+ if (pidlParent == m_pidlFolder)
+ pidlParent = (ITEMIDLIST*)ILClone(pidlParent);
+
+ pidlChild = (ITEMIDLIST*)ILClone(ILFindLastID(pidlParent));
+ ILRemoveLastID((ITEMIDLIST*)pidlParent);
+ }
+
+ if (_ILIsMyComputer(pidlChild))
+ {
+ if (32 >= (UINT)ShellExecuteW(lpcmi->hwnd, L"open", L"rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl", NULL, NULL, SW_SHOWNORMAL))
+ hr = E_FAIL;
+ }
+ else if (_ILIsDesktop(pidlChild))
+ {
+ if (32 >= (UINT)ShellExecuteW(lpcmi->hwnd, L"open", L"rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL, NULL, SW_SHOWNORMAL))
+ hr = E_FAIL;
+ }
+ else if (_ILIsDrive(pidlChild))
+ {
+ WCHAR wszBuf[MAX_PATH];
+ ILGetDisplayName(pidlChild, wszBuf);
+ if (!SH_ShowDriveProperties(wszBuf, pidlParent, &pidlChild))
+ hr = E_FAIL;
+ }
+ else if (_ILIsNetHood(pidlChild))
+ {
+ // FIXME path!
+ if (32 >= (UINT)ShellExecuteW(NULL, L"open", L"explorer.exe",
+ L"::{7007ACC7-3202-11D1-AAD2-00805FC1270E}",
+ NULL, SW_SHOWDEFAULT))
+ hr = E_FAIL;
+ }
+ else if (_ILIsBitBucket(pidlChild))
+ {
+ /* FIXME: detect the drive path of bitbucket if appropiate */
+ if(!SH_ShowRecycleBinProperties(L'C'))
+ hr = E_FAIL;
+ }
+ else
+ {
+ if (m_cidl > 1)
+ WARN("SHMultiFileProperties is not yet implemented\n");
+
+ STRRET strFile;
+ hr = m_psf->GetDisplayNameOf(pidlChild, SHGDN_FORPARSING, &strFile);
+ if (SUCCEEDED(hr))
+ {
+ WCHAR wszBuf[MAX_PATH];
+ hr = StrRetToBufW(&strFile, pidlChild, wszBuf, _countof(wszBuf));
+ if (SUCCEEDED(hr))
+ hr = SH_ShowPropertiesDialog(wszBuf, pidlParent, &pidlChild);
+ else
+ ERR("StrRetToBufW failed\n");
+ }
+ else
+ ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
+ }
+
+ /* Free allocated PIDLs */
+ if (pidlParent != m_pidlFolder)
+ ILFree((ITEMIDLIST*)pidlParent);
+ if (m_cidl < 1 || pidlChild != m_apidl[0])
+ ILFree((ITEMIDLIST*)pidlChild);
+
+ return hr;
+}
+
+HRESULT
+CDefaultContextMenu::DoFormat(
+ LPCMINVOKECOMMANDINFO lpcmi)
+{
+ char szDrive[8] = {0};
+
+ if (!_ILGetDrive(m_apidl[0], szDrive, sizeof(szDrive)))
+ {
+ ERR("pidl is not a drive\n");
+ return E_FAIL;
+ }
+
+ SHFormatDrive(lpcmi->hwnd, szDrive[0] - 'A', SHFMT_ID_DEFAULT, 0);
+ return S_OK;
+}
+
+HRESULT
+CDefaultContextMenu::DoDynamicShellExtensions(
+ LPCMINVOKECOMMANDINFO lpcmi)
+{
+ UINT idCmd = LOWORD(lpcmi->lpVerb);
+ PDynamicShellEntry pEntry = m_pDynamicEntries;
+
+ TRACE("verb %p first %x last %x", lpcmi->lpVerb, m_iIdSHEFirst, m_iIdSHELast);
+
+ while(pEntry && idCmd > pEntry->iIdCmdFirst + pEntry->NumIds)
+ pEntry = pEntry->pNext;
+
+ if (!pEntry)
+ return E_FAIL;
+
+ if (idCmd >= pEntry->iIdCmdFirst && idCmd <= pEntry->iIdCmdFirst + pEntry->NumIds)
+ {
+ /* invoke the dynamic context menu */
+ lpcmi->lpVerb = MAKEINTRESOURCEA(idCmd - pEntry->iIdCmdFirst);
+ return pEntry->pCM->InvokeCommand(lpcmi);
+ }
+
+ return E_FAIL;
+}
+
+DWORD
+CDefaultContextMenu::BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFO lpcmi, PStaticShellEntry pEntry)
+{
+ LPSHELLBROWSER lpSB;
+ HWND hwndTree;
+ LPCWSTR FlagsName;
+ WCHAR wszKey[256];
+ HRESULT hr;
+ DWORD wFlags;
+ DWORD cbVerb;
+
+ /* Get a pointer to the shell browser */
+ lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
+ if (lpSB == NULL)
+ return 0;
+
+ /* See if we are in Explore or Browse mode. If the browser's tree is present, we are in Explore mode.*/
+ if (SUCCEEDED(lpSB->GetControlWindow(FCW_TREE, &hwndTree)) && hwndTree)
+ FlagsName = L"ExplorerFlags";
+ else
+ FlagsName = L"BrowserFlags";
+
+ /* Try to get the flag from the verb */
+ hr = StringCbPrintfW(wszKey, sizeof(wszKey), L"%s\\shell\\%s", pEntry->szClass, pEntry->szVerb);
+ if (!SUCCEEDED(hr))
+ return 0;
+
+ cbVerb = sizeof(wFlags);
+ if (RegGetValueW(HKEY_CLASSES_ROOT, wszKey, FlagsName, RRF_RT_REG_DWORD, NULL, &wFlags, &cbVerb) == ERROR_SUCCESS)
+ {
+ return wFlags;
+ }
+
+ return 0;
+}
+
+HRESULT
+CDefaultContextMenu::TryToBrowse(
+ LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl, DWORD wFlags)
+{
+ LPSHELLBROWSER lpSB = (LPSHELLBROWSER)SendMessageW(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
+ HRESULT hr;
+
+ if (lpSB == NULL)
+ return E_FAIL;
+
+ hr = lpSB->BrowseObject(ILCombine(m_pidlFolder, pidl), wFlags);
+
+ return hr;
+}
+
+HRESULT
+CDefaultContextMenu::InvokePidl(LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl, PStaticShellEntry pEntry)
+{
+ LPITEMIDLIST pidlFull = ILCombine(m_pidlFolder, pidl);
+ if (pidlFull == NULL)
+ {
+ return E_FAIL;
+ }
+
+ WCHAR wszPath[MAX_PATH];
+ BOOL bHasPath = SHGetPathFromIDListW(pidlFull, wszPath);
+
+ WCHAR wszDir[MAX_PATH];
+ if(bHasPath)
+ {
+ wcscpy(wszDir, wszPath);
+ PathRemoveFileSpec(wszDir);
+ }
+ else
+ {
+ SHGetPathFromIDListW(m_pidlFolder, wszDir);
+ }
+
+ HKEY hkeyClass;
+ RegOpenKeyExW(HKEY_CLASSES_ROOT, pEntry->szClass, 0, KEY_READ, &hkeyClass);
+
+ SHELLEXECUTEINFOW sei;
+ ZeroMemory(&sei, sizeof(sei));
+ sei.cbSize = sizeof(sei);
+ sei.hwnd = lpcmi->hwnd;
+ sei.nShow = SW_SHOWNORMAL;
+ sei.lpVerb = pEntry->szVerb;
+ sei.lpDirectory = wszDir;
+ sei.lpIDList = pidlFull;
+ sei.hkeyClass = hkeyClass;
+ sei.fMask = SEE_MASK_CLASSKEY | SEE_MASK_IDLIST;
+ if (bHasPath)
+ {
+ sei.lpFile = wszPath;
+ }
+
+ ShellExecuteExW(&sei);
+
+ RegCloseKey(hkeyClass);
+
+ ILFree(pidlFull);
+
+ return S_OK;
+}
+
+HRESULT
+CDefaultContextMenu::DoStaticShellExtensions(
+ LPCMINVOKECOMMANDINFO lpcmi)
+{
+ PStaticShellEntry pEntry = m_pStaticEntries;
+ INT iCmd = LOWORD(lpcmi->lpVerb) - m_iIdSCMFirst;
+ HRESULT hr;
+ UINT i;
+
+ while (pEntry && (iCmd--) > 0)
+ pEntry = pEntry->pNext;
+
+ if (iCmd > 0)
+ return E_FAIL;
+
+ /* Get the browse flags to see if we need to browse */
+ DWORD wFlags = BrowserFlagsFromVerb(lpcmi, pEntry);
+ BOOL bBrowsed = FALSE;
+
+ for (i=0; i < m_cidl; i++)
+ {
+ /* Check if we need to browse */
+ if (wFlags > 0)
+ {
+ /* In xp if we have browsed, we don't open any more folders .
+ * In win7 we browse to the first folder we find and
+ * open new windows fo for each of the rest of the folders */
+ if (bBrowsed)
+ continue;
+
+ hr = TryToBrowse(lpcmi, m_apidl[i], wFlags);
+ if (SUCCEEDED(hr))
+ {
+ bBrowsed = TRUE;
+ continue;
+ }
+ }
+
+ InvokePidl(lpcmi, m_apidl[i], pEntry);
+ }
+
+ return S_OK;
+}
+
+HRESULT
+WINAPI
+CDefaultContextMenu::InvokeCommand(
+ LPCMINVOKECOMMANDINFO lpcmi)
+{
+ switch(LOWORD(lpcmi->lpVerb))
+ {
+ case FCIDM_SHVIEW_BIGICON:
+ case FCIDM_SHVIEW_SMALLICON:
+ case FCIDM_SHVIEW_LISTVIEW:
+ case FCIDM_SHVIEW_REPORTVIEW:
+ case 0x30: /* FIX IDS in resource files */
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case FCIDM_SHVIEW_AUTOARRANGE:
+ case FCIDM_SHVIEW_SNAPTOGRID:
+ return NotifyShellViewWindow(lpcmi, FALSE);
+ case FCIDM_SHVIEW_REFRESH:
+ return DoRefresh(lpcmi);
+ case FCIDM_SHVIEW_INSERT:
+ return DoPaste(lpcmi, FALSE);
+ case FCIDM_SHVIEW_INSERTLINK:
+ return DoPaste(lpcmi, TRUE);
+ case FCIDM_SHVIEW_OPEN:
+ case FCIDM_SHVIEW_EXPLORE:
+ return DoOpenOrExplore(lpcmi);
+ case FCIDM_SHVIEW_COPY:
+ case FCIDM_SHVIEW_CUT:
+ return DoCopyOrCut(lpcmi, LOWORD(lpcmi->lpVerb) == FCIDM_SHVIEW_COPY);
+ case FCIDM_SHVIEW_CREATELINK:
+ return DoCreateLink(lpcmi);
+ case FCIDM_SHVIEW_DELETE:
+ return DoDelete(lpcmi);
+ case FCIDM_SHVIEW_RENAME:
+ return DoRename(lpcmi);
+ case FCIDM_SHVIEW_PROPERTIES:
+ return DoProperties(lpcmi);
+ case 0x7ABC:
+ return DoFormat(lpcmi);
+ }
+
+ if (m_iIdSHEFirst && m_iIdSHELast)
+ {
+ if (LOWORD(lpcmi->lpVerb) >= m_iIdSHEFirst && LOWORD(lpcmi->lpVerb) <= m_iIdSHELast)
+ return DoDynamicShellExtensions(lpcmi);
+ }
+
+ if (m_iIdSCMFirst && m_iIdSCMLast)
+ {
+ if (LOWORD(lpcmi->lpVerb) >= m_iIdSCMFirst && LOWORD(lpcmi->lpVerb) <= m_iIdSCMLast)
+ return DoStaticShellExtensions(lpcmi);
+ }
+
+ FIXME("Unhandled Verb %xl\n", LOWORD(lpcmi->lpVerb));
+ return E_UNEXPECTED;
+}
+
+HRESULT
+WINAPI
+CDefaultContextMenu::GetCommandString(
+ UINT_PTR idCommand,
+ UINT uFlags,
+ UINT* lpReserved,
+ LPSTR lpszName,
+ UINT uMaxNameLen)
+{
+ return S_OK;
+}
+
+HRESULT
+WINAPI
+CDefaultContextMenu::HandleMenuMsg(
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ return S_OK;
+}
+
+static
+HRESULT
+IDefaultContextMenu_Constructor(
+ const DEFCONTEXTMENU *pdcm,
+ REFIID riid,
+ void **ppv)
+{
+ if (ppv == NULL)
+ return E_POINTER;
+ *ppv = NULL;
+
+ CComObject<CDefaultContextMenu> *pCM;
+ HRESULT hr = CComObject<CDefaultContextMenu>::CreateInstance(&pCM);
+ if (FAILED(hr))
+ return hr;
+ pCM->AddRef(); // CreateInstance returns object with 0 ref count */
+
+ CComPtr<IUnknown> pResult;
+ hr = pCM->QueryInterface(riid, (void **)&pResult);
+ if (FAILED(hr))
+ {
+ pCM->Release();
+ return hr;
+ }
+
+ hr = pCM->Initialize(pdcm);
+ if (FAILED(hr))
+ {
+ pCM->Release();
+ return hr;
+ }
+
+ *ppv = pResult.Detach();
+ pCM->Release();
+ TRACE("This(%p) cidl %u\n", *ppv, pdcm->cidl);
+ return S_OK;
+}
+
+/*************************************************************************
+ * SHCreateDefaultContextMenu [SHELL32.325] Vista API
+ *
+ */
+
+HRESULT
+WINAPI
+SHCreateDefaultContextMenu(
+ const DEFCONTEXTMENU *pdcm,
+ REFIID riid,
+ void **ppv)
+{
+ *ppv = NULL;
+ HRESULT hr = IDefaultContextMenu_Constructor(pdcm, riid, ppv);
+ if (FAILED(hr))
+ ERR("IDefaultContextMenu_Constructor failed: %x\n", hr);
+ TRACE("pcm %p hr %x\n", pdcm, hr);
+ return hr;
+}
+
+/*************************************************************************
+ * CDefFolderMenu_Create2 [SHELL32.701]
+ *
+ */
+
+HRESULT
+WINAPI
+CDefFolderMenu_Create2(
+ LPCITEMIDLIST pidlFolder,
+ HWND hwnd,
+ UINT cidl,
+ LPCITEMIDLIST *apidl,
+ IShellFolder *psf,
+ LPFNDFMCALLBACK lpfn,
+ UINT nKeys,
+ const HKEY *ahkeyClsKeys,
+ IContextMenu **ppcm)
+{
+ DEFCONTEXTMENU pdcm;
+ pdcm.hwnd = hwnd;
+ pdcm.pcmcb = NULL;
+ pdcm.pidlFolder = pidlFolder;
+ pdcm.psf = psf;
+ pdcm.cidl = cidl;
+ pdcm.apidl = apidl;
+ pdcm.punkAssociationInfo = NULL;
+ pdcm.cKeys = nKeys;
+ pdcm.aKeys = ahkeyClsKeys;
+
+ HRESULT hr = SHCreateDefaultContextMenu(&pdcm, IID_PPV_ARG(IContextMenu, ppcm));
+ return hr;
+}
+
--- /dev/null
- DWORD * pchEaten, LPITEMIDLIST * ppidl, DWORD * pdwAttributes)
+/*
+ * Virtual Admin Tools Folder
+ *
+ * Copyright 2008 Johannes Anderwald
+ * Copyright 2009 Andrew Hill
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <precomp.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL (shell);
+
+/*
+This folder should not exist. It is just a file system folder...
+*/
+
+/* List shortcuts of
+ * CSIDL_COMMON_ADMINTOOLS
+ * Note: CSIDL_ADMINTOOLS is ignored, tested with Window XP SP3+
+ */
+
+/***********************************************************************
+ * AdminTools folder implementation
+ */
+
+class CDesktopFolderEnumY :
+ public IEnumIDListImpl
+{
+ private:
+ public:
+ CDesktopFolderEnumY();
+ ~CDesktopFolderEnumY();
+ HRESULT WINAPI Initialize(LPWSTR szTarget, DWORD dwFlags);
+
+ BEGIN_COM_MAP(CDesktopFolderEnumY)
+ COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
+ END_COM_MAP()
+};
+
+static const shvheader AdminToolsSFHeader[] = {
+ {IDS_SHV_COLUMN8, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
+ {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
+ {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
+ {IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 12}
+};
+
+#define COLUMN_NAME 0
+#define COLUMN_SIZE 1
+#define COLUMN_TYPE 2
+#define COLUMN_DATE 3
+
+#define AdminToolsHELLVIEWCOLUMNS (4)
+
+CDesktopFolderEnumY::CDesktopFolderEnumY()
+{
+}
+
+CDesktopFolderEnumY::~CDesktopFolderEnumY()
+{
+}
+
+HRESULT WINAPI CDesktopFolderEnumY::Initialize(LPWSTR szTarget, DWORD dwFlags)
+{
+ TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags);
+ /* enumerate the elements in %windir%\desktop */
+ return CreateFolderEnumList(szTarget, dwFlags);
+}
+
+CAdminToolsFolder::CAdminToolsFolder()
+{
+ pclsid = NULL;
+
+ pidlRoot = NULL; /* absolute pidl */
+ szTarget = NULL;
+
+ dwAttributes = 0; /* attributes returned by GetAttributesOf FIXME: use it */
+}
+
+CAdminToolsFolder::~CAdminToolsFolder()
+{
+ TRACE ("-- destroying IShellFolder(%p)\n", this);
+ if (pidlRoot)
+ SHFree(pidlRoot);
+ HeapFree(GetProcessHeap(), 0, szTarget);
+}
+
+HRESULT WINAPI CAdminToolsFolder::FinalConstruct()
+{
+ szTarget = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
+ if (szTarget == NULL)
+ return E_OUTOFMEMORY;
+ if (!SHGetSpecialFolderPathW(NULL, szTarget, CSIDL_COMMON_ADMINTOOLS, FALSE))
+ return E_FAIL;
+
+ pidlRoot = _ILCreateAdminTools(); /* my qualified pidl */
+ if (pidlRoot == NULL)
+ return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+/**************************************************************************
+ * CAdminToolsFolder::ParseDisplayName
+ *
+ */
+HRESULT WINAPI CAdminToolsFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
- HRESULT WINAPI CAdminToolsFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
++ DWORD *pchEaten, PIDLIST_RELATIVE *ppidl, DWORD *pdwAttributes)
+{
+ TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
+ this, hwndOwner, pbc, lpszDisplayName, debugstr_w(lpszDisplayName),
+ pchEaten, ppidl, pdwAttributes);
+
+ *ppidl = 0;
+ if (pchEaten)
+ *pchEaten = 0;
+
+ MessageBoxW(NULL, lpszDisplayName, L"ParseDisplayName", MB_OK);
+
+ return E_NOTIMPL;
+}
+
+/**************************************************************************
+ * CAdminToolsFolder::EnumObjects
+ */
+HRESULT WINAPI CAdminToolsFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
+{
+ CComObject<CDesktopFolderEnumY> *theEnumerator;
+ CComPtr<IEnumIDList> result;
+ HRESULT hResult;
+
+ TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", this, hwndOwner, dwFlags, ppEnumIDList);
+
+ if (ppEnumIDList == NULL)
+ return E_POINTER;
+ *ppEnumIDList = NULL;
+ ATLTRY (theEnumerator = new CComObject<CDesktopFolderEnumY>);
+ if (theEnumerator == NULL)
+ return E_OUTOFMEMORY;
+ hResult = theEnumerator->QueryInterface(IID_PPV_ARG(IEnumIDList, &result));
+ if (FAILED (hResult))
+ {
+ delete theEnumerator;
+ return hResult;
+ }
+ hResult = theEnumerator->Initialize (szTarget, dwFlags);
+ if (FAILED (hResult))
+ return hResult;
+ *ppEnumIDList = result.Detach ();
+
+ TRACE ("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList);
+
+ return S_OK;
+}
+
+/**************************************************************************
+ * CAdminToolsFolder::BindToObject
+ */
- HRESULT WINAPI CAdminToolsFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
++HRESULT WINAPI CAdminToolsFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, 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);
+}
+
+/**************************************************************************
+ * CAdminToolsFolder::BindToStorage
+ */
- HRESULT WINAPI CAdminToolsFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
++HRESULT WINAPI CAdminToolsFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
+{
+ FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n",
+ this, pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
+
+ *ppvOut = NULL;
+ return E_NOTIMPL;
+}
+
+/**************************************************************************
+ * CAdminToolsFolder::CompareIDs
+ */
- HRESULT WINAPI CAdminToolsFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, DWORD *rgfInOut)
++HRESULT WINAPI CAdminToolsFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
+{
+ int nReturn;
+
+ 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;
+}
+
+/**************************************************************************
+ * CAdminToolsFolder::CreateViewObject
+ */
+HRESULT WINAPI CAdminToolsFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut)
+{
+ CComPtr<IShellView> pShellView;
+ HRESULT hr = E_INVALIDARG;
+
+ TRACE ("(%p)->(hwnd=%p,%s,%p)\n", this,
+ hwndOwner, shdebugstr_guid (&riid), ppvOut);
+
+ if (!ppvOut)
+ return hr;
+
+ *ppvOut = NULL;
+
+ if (IsEqualIID (riid, IID_IDropTarget))
+ {
+ WARN ("IDropTarget 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);
+ }
+ TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
+ return hr;
+}
+
+/**************************************************************************
+ * ISF_AdminTools_fnGetAttributesOf
+ */
- HRESULT WINAPI CAdminToolsFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl,
++HRESULT WINAPI CAdminToolsFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut)
+{
+ HRESULT hr = S_OK;
+ static const DWORD dwAdminToolsAttributes =
+ SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR |
+ SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM;
+
+ TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
+ this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
+
+ if (!rgfInOut)
+ return E_INVALIDARG;
+ if (cidl && !apidl)
+ return E_INVALIDARG;
+
+ if (*rgfInOut == 0)
+ *rgfInOut = ~0;
+
+ if(cidl == 0) {
+ *rgfInOut &= dwAdminToolsAttributes;
+ } else {
+ while (cidl > 0 && *apidl) {
+ pdump (*apidl);
+ if (_ILIsAdminTools(*apidl)) {
+ *rgfInOut &= dwAdminToolsAttributes;
+ } else {
+ SHELL32_GetItemAttributes (this, *apidl, rgfInOut);
+ }
+ apidl++;
+ cidl--;
+ }
+ }
+ /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
+ *rgfInOut &= ~SFGAO_VALIDATE;
+
+ TRACE ("-- result=0x%08x\n", *rgfInOut);
+
+ return hr;
+}
+
+/**************************************************************************
+ * CAdminToolsFolder::GetUIObjectOf
+ *
+ * PARAMETERS
+ * HWND hwndOwner, //[in ] Parent window for any output
+ * UINT cidl, //[in ] array size
+ * LPCITEMIDLIST* apidl, //[in ] simple pidl array
+ * REFIID riid, //[in ] Requested Interface
+ * UINT* prgfInOut, //[ ] reserved
+ * LPVOID* ppvObject) //[out] Resulting Interface
+ *
+ */
- HRESULT WINAPI CAdminToolsFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
++HRESULT WINAPI CAdminToolsFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
+ REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
+{
+ LPITEMIDLIST pidl;
+ CComPtr<IUnknown> pObj;
+ HRESULT hr = E_INVALIDARG;
+
+ TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
+ this, hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
+
+ if (!ppvOut)
+ return hr;
+
+ *ppvOut = NULL;
+
+ if (IsEqualIID (riid, IID_IContextMenu))
+ {
+ IContextMenu * pCm = NULL;
+ hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, static_cast<IShellFolder*>(this), NULL, 0, NULL, &pCm);
+ pObj = pCm;
+ }
+ else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
+ {
+ IDataObject * pDo = NULL;
+ hr = IDataObject_Constructor(hwndOwner, pidlRoot, apidl, cidl, &pDo);
+ pObj = pDo;
+ }
+ 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_IDropTarget) && (cidl >= 1))
+ {
+ IDropTarget * pDt = NULL;
+ hr = this->QueryInterface(IID_PPV_ARG(IDropTarget, &pDt));
+ pObj = pDt;
+ }
+ else if ((IsEqualIID(riid, IID_IShellLinkW) ||
+ IsEqualIID(riid, IID_IShellLinkA)) && (cidl == 1))
+ {
+ pidl = ILCombine (pidlRoot, apidl[0]);
+ hr = IShellLink_ConstructFromFile(NULL, riid, pidl, reinterpret_cast<LPVOID*>(&pObj));
+ SHFree (pidl);
+ }
+ else
+ hr = E_NOINTERFACE;
+
+ if (SUCCEEDED(hr) && !pObj)
+ hr = E_OUTOFMEMORY;
+
+ *ppvOut = pObj.Detach();
+ TRACE ("(%p)->hr=0x%08x\n", this, hr);
+ return hr;
+}
+
+/**************************************************************************
+ * CAdminToolsFolder::GetDisplayNameOf
+ *
+ */
- HRESULT WINAPI CAdminToolsFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, /* simple pidl */
- LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut)
++HRESULT WINAPI CAdminToolsFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
+{
+ HRESULT hr = S_OK;
+ LPWSTR pszPath, pOffset;
+
+ TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
+ pdump (pidl);
+
+ if (!strRet)
+ return E_INVALIDARG;
+
+ pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
+ if (!pszPath)
+ return E_OUTOFMEMORY;
+
+ ZeroMemory(pszPath, (MAX_PATH + 1) * sizeof(WCHAR));
+
+ if (!pidl->mkid.cb)
+ {
+ if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
+ (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING))
+ wcscpy(pszPath, szTarget);
+ else if (!HCR_GetClassNameW(CLSID_AdminFolderShortcut, pszPath, MAX_PATH))
+ hr = E_FAIL;
+ }
+ else if (_ILIsPidlSimple(pidl))
+ {
+ if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
+ (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) &&
+ szTarget)
+ {
+ wcscpy(pszPath, szTarget);
+ pOffset = PathAddBackslashW(pszPath);
+ if (pOffset)
+ {
+ if (!_ILSimpleGetTextW(pidl, pOffset, MAX_PATH + 1 - (pOffset - pszPath)))
+ hr = E_FAIL;
+ }
+ else
+ hr = E_FAIL;
+ }
+ else
+ {
+ if (_ILSimpleGetTextW(pidl, pszPath, MAX_PATH + 1))
+ {
+ if (SHELL_FS_HideExtension(pszPath))
+ PathRemoveExtensionW(pszPath);
+ }
+ else
+ hr = E_FAIL;
+ }
+ }
+ else if (_ILIsSpecialFolder(pidl))
+ {
+ BOOL bSimplePidl = _ILIsPidlSimple(pidl);
+
+ if (bSimplePidl)
+ {
+ if (!_ILSimpleGetTextW(pidl, pszPath, MAX_PATH))
+ hr = E_FAIL;
+ }
+ else if ((dwFlags & SHGDN_FORPARSING) && !bSimplePidl)
+ {
+ int len = 0;
+
+ wcscpy(pszPath, szTarget);
+ PathAddBackslashW(pszPath);
+ len = wcslen(pszPath);
+
+ if (!SUCCEEDED(SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags | SHGDN_INFOLDER, pszPath + len, MAX_PATH + 1 - len)))
+ {
+ CoTaskMemFree(pszPath);
+ return E_OUTOFMEMORY;
+ }
+
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ strRet->uType = STRRET_WSTR;
+ strRet->pOleStr = pszPath;
+ TRACE ("-- (%p)->(%s,0x%08x)\n", this, debugstr_w(strRet->pOleStr), hr);
+ }
+ else
+ CoTaskMemFree(pszPath);
+
+ return hr;
+}
+
+/**************************************************************************
+ * CAdminToolsFolder::SetNameOf
+ * Changes the name of a file object or subfolder, possibly changing its item
+ * identifier in the process.
+ *
+ * PARAMETERS
+ * HWND hwndOwner, //[in ] Owner window for output
+ * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
+ * LPCOLESTR lpszName, //[in ] the items new display name
+ * DWORD dwFlags, //[in ] SHGNO formatting flags
+ * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
+ */
- HRESULT WINAPI CAdminToolsFolder::GetDetailsEx (LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
++HRESULT WINAPI CAdminToolsFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, /* simple pidl */
++ LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
+{
+ FIXME ("(%p)->(%p,pidl=%p,%s,%lu,%p)\n", this, hwndOwner, pidl,
+ debugstr_w (lpName), dwFlags, pPidlOut);
+
+ return E_FAIL;
+}
+
+HRESULT WINAPI CAdminToolsFolder::GetDefaultSearchGUID(GUID *pguid)
+{
+ FIXME ("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CAdminToolsFolder::EnumSearches(IEnumExtraSearch ** ppenum)
+{
+ FIXME ("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CAdminToolsFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
+{
+ if (pSort)
+ *pSort = 0;
+ if (pDisplay)
+ *pDisplay = 0;
+
+ return S_OK;
+}
+HRESULT WINAPI CAdminToolsFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
+{
+ if (!pcsFlags || iColumn >= AdminToolsHELLVIEWCOLUMNS)
+ return E_INVALIDARG;
+ *pcsFlags = AdminToolsSFHeader[iColumn].pcsFlags;
+ return S_OK;
+
+}
+
- HRESULT WINAPI CAdminToolsFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd)
++HRESULT WINAPI CAdminToolsFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
+{
+ FIXME ("(%p): stub\n", this);
+
+ return E_NOTIMPL;
+}
+
++HRESULT WINAPI CAdminToolsFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
+{
+ WCHAR buffer[MAX_PATH] = {0};
+ HRESULT hr = E_FAIL;
+
+ TRACE("(%p)->(%p %i %p): stub\n", this, pidl, iColumn, psd);
+
+ if (iColumn >= AdminToolsHELLVIEWCOLUMNS)
+ return E_FAIL;
+
+ psd->fmt = AdminToolsSFHeader[iColumn].fmt;
+ psd->cxChar = AdminToolsSFHeader[iColumn].cxChar;
+ if (pidl == NULL)
+ {
+ psd->str.uType = STRRET_WSTR;
+ if (LoadStringW(shell32_hInstance, AdminToolsSFHeader[iColumn].colnameid, buffer, MAX_PATH))
+ hr = SHStrDupW(buffer, &psd->str.pOleStr);
+
+ return hr;
+ }
+
+ psd->str.uType = STRRET_CSTR;
+ switch (iColumn)
+ {
+ case COLUMN_NAME:
+ psd->str.uType = STRRET_WSTR;
+ hr = GetDisplayNameOf(pidl,
+ SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
+ break;
+ case COLUMN_SIZE:
+ _ILGetFileSize (pidl, psd->str.cStr, MAX_PATH);
+ break;
+ case COLUMN_TYPE:
+ _ILGetFileType (pidl, psd->str.cStr, MAX_PATH);
+ break;
+ case COLUMN_DATE:
+ _ILGetFileDate (pidl, psd->str.cStr, MAX_PATH);
+ break;
+ }
+
+ return hr;
+}
+
+HRESULT WINAPI CAdminToolsFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
+{
+ FIXME ("(%p): stub\n", this);
+ return E_NOTIMPL;
+}
+
+/************************************************************************
+ * CAdminToolsFolder::GetClassID
+ */
+HRESULT WINAPI CAdminToolsFolder::GetClassID(CLSID *lpClassId)
+{
+ TRACE ("(%p)\n", this);
+
+ memcpy(lpClassId, &CLSID_AdminFolderShortcut, sizeof(CLSID));
+
+ return S_OK;
+}
+
+/************************************************************************
+ * CAdminToolsFolder::Initialize
+ *
+ */
+HRESULT WINAPI CAdminToolsFolder::Initialize(LPCITEMIDLIST pidl)
+{
+ if (pidlRoot)
+ SHFree((LPVOID)pidlRoot);
+
+ pidlRoot = ILClone(pidl);
+ return S_OK;
+}
+
+/**************************************************************************
+ * CAdminToolsFolder::GetCurFolder
+ */
+HRESULT WINAPI CAdminToolsFolder::GetCurFolder(LPITEMIDLIST *pidl)
+{
+ TRACE ("(%p)->(%p)\n", this, pidl);
+
+ *pidl = ILClone (pidlRoot);
+ return S_OK;
+}
--- /dev/null
- LPITEMIDLIST *ppidl,
+/*
+ * Control panel folder
+ *
+ * Copyright 2003 Martin Fuchs
+ * Copyright 2009 Andrew Hill
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * 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);
+
+/***********************************************************************
+* control panel implementation in shell namespace
+*/
+
+class CControlPanelEnum :
+ public IEnumIDListImpl
+{
+ 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);
+ BOOL CreateCPanelEnumList(DWORD dwFlags);
+
+ BEGIN_COM_MAP(CControlPanelEnum)
+ COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
+ END_COM_MAP()
+};
+
+/***********************************************************************
+* IShellFolder [ControlPanel] implementation
+*/
+
+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*/
+};
+
+#define CONROLPANELSHELLVIEWCOLUMNS 2
+
+CControlPanelEnum::CControlPanelEnum()
+{
+}
+
+CControlPanelEnum::~CControlPanelEnum()
+{
+}
+
+HRESULT WINAPI CControlPanelEnum::Initialize(DWORD dwFlags)
+{
+ if (CreateCPanelEnumList(dwFlags) == FALSE)
+ return E_FAIL;
+ return S_OK;
+}
+
+static LPITEMIDLIST _ILCreateCPanelApplet(LPCSTR pszName, LPCSTR pszDisplayName, LPCSTR pszComment, int iIconIdx)
+{
+ PIDLCPanelStruct *pCP;
+ LPITEMIDLIST pidl;
+ LPPIDLDATA pData;
+ int cchName, cchDisplayName, cchComment, cbData;
+
+ /* Calculate lengths of given strings */
+ cchName = strlen(pszName);
+ cchDisplayName = strlen(pszDisplayName);
+ cchComment = strlen(pszComment);
+
+ /* Allocate PIDL */
+ cbData = sizeof(pidl->mkid.cb) + sizeof(pData->type) + sizeof(pData->u.cpanel) - sizeof(pData->u.cpanel.szName)
+ + cchName + cchDisplayName + cchComment + 3;
+ pidl = (LPITEMIDLIST)SHAlloc(cbData + sizeof(WORD));
+ if (!pidl)
+ return NULL;
+
+ /* Copy data to allocated memory */
+ pidl->mkid.cb = cbData;
+ pData = (PIDLDATA *)pidl->mkid.abID;
+ pData->type = PT_CPLAPPLET;
+
+ pCP = &pData->u.cpanel;
+ pCP->dummy = 0;
+ pCP->iconIdx = iIconIdx;
+ strcpy(pCP->szName, pszName);
+ pCP->offsDispName = cchName + 1;
+ strcpy(pCP->szName + pCP->offsDispName, pszDisplayName);
+ pCP->offsComment = pCP->offsDispName + cchDisplayName + 1;
+ strcpy(pCP->szName + pCP->offsComment, pszComment);
+
+ /* Add PIDL NULL terminator */
+ *(WORD*)(pCP->szName + pCP->offsComment + cchComment + 1) = 0;
+
+ pcheck(pidl);
+
+ return pidl;
+}
+
+/**************************************************************************
+ * _ILGetCPanelPointer()
+ * gets a pointer to the control panel struct stored in the pidl
+ */
+static PIDLCPanelStruct *_ILGetCPanelPointer(LPCITEMIDLIST pidl)
+{
+ LPPIDLDATA pdata = _ILGetDataPointer(pidl);
+
+ if (pdata && pdata->type == PT_CPLAPPLET)
+ return (PIDLCPanelStruct *) & (pdata->u.cpanel);
+
+ return NULL;
+}
+
+BOOL CControlPanelEnum::RegisterCPanelApp(LPCSTR path)
+{
+ LPITEMIDLIST pidl;
+ CPlApplet* applet;
+ CPanel panel;
+ CPLINFO info;
+ unsigned i;
+ int iconIdx;
+
+ char displayName[MAX_PATH];
+ char comment[MAX_PATH];
+
+ WCHAR wpath[MAX_PATH];
+
+ MultiByteToWideChar(CP_ACP, 0, path, -1, wpath, MAX_PATH);
+
+ panel.first = NULL;
+ applet = Control_LoadApplet(0, wpath, &panel);
+
+ if (applet)
+ {
+ for (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 */
+ else
+ iconIdx = 0;
+
+ pidl = _ILCreateCPanelApplet(path, displayName, comment, iconIdx);
+
+ if (pidl)
+ AddToEnumList(pidl);
+ }
+ Control_UnloadApplet(applet);
+ }
+ return TRUE;
+}
+
+int CControlPanelEnum::RegisterRegistryCPanelApps(HKEY hkey_root, LPCSTR szRepPath)
+{
+ char name[MAX_PATH];
+ char value[MAX_PATH];
+ HKEY hkey;
+
+ int cnt = 0;
+
+ if (RegOpenKeyA(hkey_root, szRepPath, &hkey) == ERROR_SUCCESS)
+ {
+ int idx = 0;
+
+ for(; ; idx++)
+ {
+ DWORD nameLen = MAX_PATH;
+ DWORD valueLen = MAX_PATH;
+
+ if (RegEnumValueA(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 == '{')
+ {
+ LPITEMIDLIST pidl = _ILCreateGuidFromStrA(name);
+
+ if (pidl && AddToEnumList(pidl))
+ ++cnt;
+ }
+ }
+
+ RegCloseKey(hkey);
+ }
+
+ return cnt;
+}
+
+/**************************************************************************
+ * CControlPanelEnum::CreateCPanelEnumList()
+ */
+BOOL CControlPanelEnum::CreateCPanelEnumList(DWORD dwFlags)
+{
+ CHAR szPath[MAX_PATH];
+ WIN32_FIND_DATAA 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;
+
+ GetSystemDirectoryA(szPath, MAX_PATH);
+ p = PathAddBackslashA(szPath);
+ strcpy(p, "*.cpl");
+
+ TRACE("-- (%p)-> enumerate SHCONTF_NONFOLDERS of %s\n", this, debugstr_a(szPath));
+ hFile = FindFirstFileA(szPath, &wfd);
+
+ if (hFile != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ if (!(dwFlags & SHCONTF_INCLUDEHIDDEN) && (wfd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))
+ continue;
+
+ if (!(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ strcpy(p, wfd.cFileName);
+ if (strcmp(wfd.cFileName, "ncpa.cpl"))
+ RegisterCPanelApp(szPath);
+ }
+ } while(FindNextFileA(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");
+ }
+ return TRUE;
+}
+
+CControlPanelFolder::CControlPanelFolder()
+{
+ pidlRoot = NULL; /* absolute pidl */
+ dwAttributes = 0; /* attributes returned by GetAttributesOf FIXME: use it */
+ apidl = NULL;
+ cidl = 0;
+}
+
+CControlPanelFolder::~CControlPanelFolder()
+{
+ TRACE("-- destroying IShellFolder(%p)\n", this);
+ SHFree(pidlRoot);
+}
+
+HRESULT WINAPI CControlPanelFolder::FinalConstruct()
+{
+ pidlRoot = _ILCreateControlPanel(); /* my qualified pidl */
+ if (pidlRoot == NULL)
+ return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+/**************************************************************************
+* CControlPanelFolder::ParseDisplayName
+*/
+HRESULT WINAPI CControlPanelFolder::ParseDisplayName(
+ HWND hwndOwner,
+ LPBC pbc,
+ LPOLESTR lpszDisplayName,
+ DWORD *pchEaten,
- LPCITEMIDLIST pidl,
++ 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;
+}
+
+/**************************************************************************
+* CControlPanelFolder::EnumObjects
+*/
+HRESULT WINAPI CControlPanelFolder::EnumObjects(
+ HWND hwndOwner,
+ DWORD dwFlags,
+ LPENUMIDLIST *ppEnumIDList)
+{
+ CComObject<CControlPanelEnum> *theEnumerator;
+ CComPtr<IEnumIDList> result;
+ HRESULT hResult;
+
+ TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", this, hwndOwner, dwFlags, ppEnumIDList);
+
+ if (ppEnumIDList == NULL)
+ return E_POINTER;
+ *ppEnumIDList = NULL;
+ ATLTRY (theEnumerator = new CComObject<CControlPanelEnum>);
+ if (theEnumerator == NULL)
+ return E_OUTOFMEMORY;
+ hResult = theEnumerator->QueryInterface(IID_PPV_ARG(IEnumIDList, &result));
+ if (FAILED (hResult))
+ {
+ delete theEnumerator;
+ return hResult;
+ }
+ hResult = theEnumerator->Initialize (dwFlags);
+ if (FAILED (hResult))
+ return hResult;
+ *ppEnumIDList = result.Detach ();
+
+ TRACE ("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList);
+
+ return S_OK;
+}
+
+/**************************************************************************
+* CControlPanelFolder::BindToObject
+*/
+HRESULT WINAPI CControlPanelFolder::BindToObject(
- LPCITEMIDLIST pidl,
++ PCUIDLIST_RELATIVE pidl,
+ LPBC pbcReserved,
+ 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);
+}
+
+/**************************************************************************
+* CControlPanelFolder::BindToStorage
+*/
+HRESULT WINAPI CControlPanelFolder::BindToStorage(
- HRESULT WINAPI CControlPanelFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
++ PCUIDLIST_RELATIVE pidl,
+ LPBC pbcReserved,
+ REFIID riid,
+ LPVOID *ppvOut)
+{
+ FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this, pidl, pbcReserved, shdebugstr_guid(&riid), ppvOut);
+
+ *ppvOut = NULL;
+ return E_NOTIMPL;
+}
+
+/**************************************************************************
+* CControlPanelFolder::CompareIDs
+*/
+
- HRESULT WINAPI CControlPanelFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl, DWORD * rgfInOut)
++HRESULT WINAPI CControlPanelFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
+{
+ int nReturn;
+
+ 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;
+}
+
+/**************************************************************************
+* CControlPanelFolder::CreateViewObject
+*/
+HRESULT WINAPI CControlPanelFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
+{
+ CComPtr<IShellView> pShellView;
+ HRESULT hr = E_INVALIDARG;
+
+ TRACE("(%p)->(hwnd=%p,%s,%p)\n", this, hwndOwner, shdebugstr_guid(&riid), ppvOut);
+
+ if (ppvOut) {
+ *ppvOut = NULL;
+
+ if (IsEqualIID(riid, IID_IDropTarget)) {
+ WARN("IDropTarget not implemented\n");
+ hr = E_NOTIMPL;
+ } else if (IsEqualIID(riid, IID_IContextMenu)) {
+ 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);
+ }
+ }
+ }
+ TRACE("--(%p)->(interface=%p)\n", this, ppvOut);
+ return hr;
+}
+
+/**************************************************************************
+* CControlPanelFolder::GetAttributesOf
+*/
- UINT cidl, LPCITEMIDLIST * apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
++HRESULT WINAPI CControlPanelFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD * rgfInOut)
+{
+ HRESULT hr = S_OK;
+
+ TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
+ this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
+
+ if (!rgfInOut)
+ return E_INVALIDARG;
+ if (cidl && !apidl)
+ return E_INVALIDARG;
+
+ if (*rgfInOut == 0)
+ *rgfInOut = ~0;
+
+ while(cidl > 0 && *apidl)
+ {
+ pdump(*apidl);
+ SHELL32_GetItemAttributes(this, *apidl, rgfInOut);
+ apidl++;
+ cidl--;
+ }
+ /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
+ *rgfInOut &= ~SFGAO_VALIDATE;
+
+ TRACE("-- result=0x%08x\n", *rgfInOut);
+ return hr;
+}
+
+/**************************************************************************
+* CControlPanelFolder::GetUIObjectOf
+*
+* PARAMETERS
+* HWND hwndOwner, //[in ] Parent window for any output
+* UINT cidl, //[in ] array size
+* LPCITEMIDLIST* apidl, //[in ] simple pidl array
+* REFIID riid, //[in ] Requested Interface
+* UINT* prgfInOut, //[ ] reserved
+* LPVOID* ppvObject) //[out] Resulting Interface
+*
+*/
+HRESULT WINAPI CControlPanelFolder::GetUIObjectOf(HWND hwndOwner,
- HRESULT WINAPI CControlPanelFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
++ UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
+{
+ LPITEMIDLIST pidl;
+ IUnknown *pObj = NULL;
+ HRESULT hr = E_INVALIDARG;
+
+ TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
+ this, hwndOwner, cidl, apidl, shdebugstr_guid(&riid), prgfInOut, ppvOut);
+
+ if (ppvOut) {
+ *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;
+ } 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 {
+ hr = E_NOINTERFACE;
+ }
+
+ if (SUCCEEDED(hr) && !pObj)
+ hr = E_OUTOFMEMORY;
+
+ *ppvOut = pObj;
+ }
+ TRACE("(%p)->hr=0x%08x\n", this, hr);
+ return hr;
+}
+
+/**************************************************************************
+* CControlPanelFolder::GetDisplayNameOf
+*/
- HRESULT WINAPI CControlPanelFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, /*simple pidl */
- LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut)
++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);
+
+ 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);
+ }
+ /* 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';
+ }
+
+ strRet->uType = STRRET_CSTR;
+ lstrcpynA(strRet->cStr, szName, MAX_PATH);
+
+ TRACE("--(%p)->(%s)\n", this, szName);
+ return S_OK;
+}
+
+/**************************************************************************
+* CControlPanelFolder::SetNameOf
+* Changes the name of a file object or subfolder, possibly changing its item
+* identifier in the process.
+*
+* PARAMETERS
+* HWND hwndOwner, //[in ] Owner window for output
+* LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
+* LPCOLESTR lpszName, //[in ] the items new display name
+* DWORD dwFlags, //[in ] SHGNO formatting flags
+* LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
+*/
- HRESULT WINAPI CControlPanelFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
++HRESULT WINAPI CControlPanelFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, /*simple pidl */
++ LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
+{
+ FIXME("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl, debugstr_w(lpName), dwFlags, pPidlOut);
+ return E_FAIL;
+}
+
+HRESULT WINAPI CControlPanelFolder::GetDefaultSearchGUID(GUID *pguid)
+{
+ FIXME("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CControlPanelFolder::EnumSearches(IEnumExtraSearch **ppenum)
+{
+ FIXME("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CControlPanelFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
+{
+ TRACE("(%p)\n", this);
+
+ if (pSort) *pSort = 0;
+ if (pDisplay) *pDisplay = 0;
+ return S_OK;
+}
+
+HRESULT WINAPI CControlPanelFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
+{
+ TRACE("(%p)\n", this);
+
+ if (!pcsFlags || iColumn >= CONROLPANELSHELLVIEWCOLUMNS) return E_INVALIDARG;
+ *pcsFlags = ControlPanelSFHeader[iColumn].pcsFlags;
+ return S_OK;
+}
+
- HRESULT WINAPI CControlPanelFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd)
++HRESULT WINAPI CControlPanelFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
+{
+ FIXME("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
++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) {
+ 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) {
+ case 0: /* name */
+ hr = GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
+ break;
+ case 1: /* comment */
+ _ILGetFileType(pidl, psd->str.cStr, MAX_PATH);
+ break;
+ }
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+HRESULT WINAPI CControlPanelFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
+{
+ FIXME("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+/************************************************************************
+ * CControlPanelFolder::GetClassID
+ */
+HRESULT WINAPI CControlPanelFolder::GetClassID(CLSID *lpClassId)
+{
+ TRACE("(%p)\n", this);
+
+ if (!lpClassId)
+ return E_POINTER;
+ *lpClassId = CLSID_ControlPanel;
+
+ return S_OK;
+}
+
+/************************************************************************
+ * CControlPanelFolder::Initialize
+ *
+ * NOTES: it makes no sense to change the pidl
+ */
+HRESULT WINAPI CControlPanelFolder::Initialize(LPCITEMIDLIST pidl)
+{
+ if (pidlRoot)
+ SHFree((LPVOID)pidlRoot);
+
+ pidlRoot = ILClone(pidl);
+ return S_OK;
+}
+
+/**************************************************************************
+ * CControlPanelFolder::GetCurFolder
+ */
+HRESULT WINAPI CControlPanelFolder::GetCurFolder(LPITEMIDLIST * pidl)
+{
+ TRACE("(%p)->(%p)\n", this, pidl);
+
+ if (!pidl)
+ return E_POINTER;
+ *pidl = ILClone(pidlRoot);
+ return S_OK;
+}
+
+HRESULT CPanel_GetIconLocationW(LPCITEMIDLIST pidl, LPWSTR szIconFile, UINT cchMax, int* piIndex)
+{
+ PIDLCPanelStruct* pcpanel = _ILGetCPanelPointer(pidl);
+
+ if (!pcpanel)
+ return E_INVALIDARG;
+
+ MultiByteToWideChar(CP_ACP, 0, pcpanel->szName, -1, szIconFile, cchMax);
+ *piIndex = (int)pcpanel->iconIdx != -1 ? pcpanel->iconIdx : 0;
+
+ return S_OK;
+}
+
+
+/**************************************************************************
+* IShellExecuteHookW Implementation
+*/
+
+static HRESULT
+ExecuteAppletFromCLSID(LPOLESTR pOleStr)
+{
+ WCHAR wszBuf[128], wszCmd[MAX_PATH];
+ DWORD cbCmd = sizeof(wszCmd);
+
+ StringCbPrintfW(wszBuf, sizeof(wszBuf), L"CLSID\\%s\\shell\\open\\command", pOleStr);
+
+ if (RegGetValueW(HKEY_CLASSES_ROOT, wszBuf, NULL, RRF_RT_REG_SZ, NULL, (PVOID)wszCmd, &cbCmd) != ERROR_SUCCESS)
+ {
+ ERR("RegGetValueW(%ls) failed with %u\n", wszBuf, GetLastError());
+ return E_FAIL;
+ }
+
+ if (!ExpandEnvironmentStringsW(wszCmd, wszBuf, _countof(wszBuf)))
+ return E_FAIL;
+
+ PROCESS_INFORMATION pi;
+ STARTUPINFOW si;
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ if (!CreateProcessW(NULL, wszBuf, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
+ return E_FAIL;
+
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ return S_OK;
+}
+
+EXTERN_C void WINAPI Control_RunDLLW(HWND hWnd, HINSTANCE hInst, LPCWSTR cmd, DWORD nCmdShow);
+
+HRESULT WINAPI CControlPanelFolder::ExecuteFromIdList(LPCITEMIDLIST pidl)
+{
+ PIDLCPanelStruct *pCPanel = _ILGetCPanelPointer(ILFindLastID(pidl));
+
+ if (!pCPanel)
+ {
+ /* Is it GUID to control panel applet? */
+ IID *piid = _ILGetGUIDPointer(ILFindLastID(pidl));
+ if (!piid)
+ return E_INVALIDARG;
+
+ /* Start it */
+ LPOLESTR pOleStr;
+ if (StringFromCLSID(*piid, &pOleStr) == S_OK)
+ {
+ HRESULT hr = ExecuteAppletFromCLSID(pOleStr);
+ CoTaskMemFree(pOleStr);
+ return hr;
+ }
+
+ ERR("Cannot open cpanel applet\n");
+ return E_INVALIDARG;
+ }
+
+ /* Build control panel applet cmd
+ Note: we pass the applet name to Control_RunDLL to distinguish between multiple applets in one .cpl file */
+ WCHAR wszCmd[2*MAX_PATH];
+ WCHAR wszAppletName[MAX_PATH];
+
+ if(!MultiByteToWideChar(CP_ACP, 0, pCPanel->szName + pCPanel->offsDispName, -1, wszAppletName, MAX_PATH))
+ return E_FAIL;
+
+ StringCbPrintfW(wszCmd, sizeof(wszCmd), L"rundll32 shell32.dll,Control_RunDLL \"%hs\",\"%ls\"", pCPanel->szName, wszAppletName);
+
+ /* Start the applet */
+ TRACE("Run cpl %ls\n", wszCmd);
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(si);
+ if (!CreateProcessW(NULL, wszCmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
+ return E_FAIL;
+
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ return S_OK;
+}
+
+HRESULT WINAPI CControlPanelFolder::Execute(LPSHELLEXECUTEINFOW psei)
+{
+ TRACE("(%p)->execute(%p)\n", this, psei);
+
+ if (!psei)
+ return E_INVALIDARG;
+
+ if (!(psei->fMask & SEE_MASK_IDLIST))
+ {
+ FIXME("no idlist given!\n");
+ return E_FAIL;
+ }
+
+ return ExecuteFromIdList((LPCITEMIDLIST)psei->lpIDList);
+}
+
+/**************************************************************************
+* IShellExecuteHookA Implementation
+*/
+
+HRESULT WINAPI CControlPanelFolder::Execute(LPSHELLEXECUTEINFOA psei)
+{
+ TRACE("(%p)->execute(%p)\n", this, psei);
+
+ if (!psei)
+ return E_INVALIDARG;
+
+ if (!(psei->fMask & SEE_MASK_IDLIST))
+ {
+ FIXME("no idlist given!\n");
+ return E_FAIL;
+ }
+
+ return ExecuteFromIdList((LPCITEMIDLIST)psei->lpIDList);
+}
+
+/**************************************************************************
+* IContextMenu2 Implementation
+*/
+
+/**************************************************************************
+* ICPanel_IContextMenu_QueryContextMenu()
+*/
+HRESULT WINAPI CControlPanelFolder::QueryContextMenu(
+ HMENU hMenu,
+ UINT indexMenu,
+ UINT idCmdFirst,
+ UINT idCmdLast,
+ UINT uFlags)
+{
+ WCHAR szBuffer[30] = {0};
+ ULONG Count = 1;
+
+ 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);
+}
+
+/**************************************************************************
+* ICPanel_IContextMenu_InvokeCommand()
+*/
+HRESULT WINAPI CControlPanelFolder::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
+{
+ SHELLEXECUTEINFOW sei;
+ WCHAR szPath[MAX_PATH];
+ char szTarget[MAX_PATH];
+ STRRET strret;
+ WCHAR* pszPath;
+ INT Length, cLength;
+ PIDLCPanelStruct *pcpanel;
+ CComPtr<IPersistFile> ppf;
+ CComPtr<IShellLinkA> isl;
+ HRESULT hResult;
+
+ TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n", this, lpcmi, lpcmi->lpVerb, lpcmi->hwnd);
+
+ if (lpcmi->lpVerb == MAKEINTRESOURCEA(IDS_OPEN)) //FIXME
+ {
+ ZeroMemory(&sei, sizeof(sei));
+ sei.cbSize = sizeof(sei);
+ sei.fMask = SEE_MASK_INVOKEIDLIST;
+ sei.lpIDList = ILCombine(pidlRoot, apidl[0]);
+ sei.hwnd = lpcmi->hwnd;
+ sei.nShow = SW_SHOWNORMAL;
+ sei.lpVerb = L"open";
+ERR("here\n");
+ return Execute(&sei);
+ }
+ else if (lpcmi->lpVerb == MAKEINTRESOURCEA(IDS_CREATELINK)) //FIXME
+ {
+ if (!SHGetSpecialFolderPathW(NULL, szPath, CSIDL_DESKTOPDIRECTORY, FALSE))
+ return E_FAIL;
+
+ pszPath = PathAddBackslashW(szPath);
+ if (!pszPath)
+ return E_FAIL;
+
+ if (GetDisplayNameOf(apidl[0], SHGDN_FORPARSING, &strret) != S_OK)
+ return E_FAIL;
+
+ Length = MAX_PATH - (pszPath - szPath);
+ cLength = strlen(strret.cStr);
+ if (Length < cLength + 5)
+ {
+ FIXME("\n");
+ return E_FAIL;
+ }
+
+ if (MultiByteToWideChar(CP_ACP, 0, strret.cStr, cLength + 1, pszPath, Length))
+ {
+ pszPath += cLength;
+ Length -= cLength;
+ }
+
+ 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");
+
+ 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;
+ }
+ return S_OK;
+}
+
+/**************************************************************************
+ * ICPanel_IContextMenu_GetCommandString()
+ *
+ */
+HRESULT WINAPI CControlPanelFolder::GetCommandString(
+ UINT_PTR idCommand,
+ UINT uFlags,
+ UINT* lpReserved,
+ LPSTR lpszName,
+ UINT uMaxNameLen)
+{
+ TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n", this, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
+
+ FIXME("unknown command string\n");
+ return E_FAIL;
+}
+
+/**************************************************************************
+* ICPanel_IContextMenu_HandleMenuMsg()
+*/
+HRESULT WINAPI CControlPanelFolder::HandleMenuMsg(
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ TRACE("ICPanel_IContextMenu_HandleMenuMsg (%p)->(msg=%x wp=%lx lp=%lx)\n", this, uMsg, wParam, lParam);
+
+ return E_NOTIMPL;
+}
--- /dev/null
- LPITEMIDLIST *ppidl,
+/*
+ * Virtual Desktop Folder
+ *
+ * Copyright 1997 Marcus Meissner
+ * Copyright 1998, 1999, 2002 Juergen Schmied
+ * Copyright 2009 Andrew Hill
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <precomp.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL(shell);
+
+/*
+CDesktopFolder should create two file system folders internally, one representing the
+user's desktop folder, and the other representing the common desktop folder. It should
+also create a CRegFolder to represent the virtual items that exist only in the registry.
+The CRegFolder is aggregated by the CDesktopFolder, and queries for the CLSID_IShellFolder,
+CLSID_IShellFolder2, or CLSID_IShellIconOverlay interfaces prefer the CRegFolder
+implementation.
+The CDesktopFolderEnum class should create two enumerators, one for each of the file
+system folders, and enumerate the contents of each folder. Since the CRegFolder
+implementation of IShellFolder::EnumObjects enumerates the virtual items, the
+CDesktopFolderEnum is only responsible for returning the physical items.
+CDesktopFolderEnum is incorrect where it filters My Computer from the enumeration
+if the new start menu is used. The CDesktopViewCallback is responsible for filtering
+it from the view by handling the IncludeObject query to return S_FALSE. The enumerator
+always shows My Computer.
+*/
+
+/* Undocumented functions from shdocvw */
+extern "C" HRESULT WINAPI IEParseDisplayNameWithBCW(DWORD codepage, LPCWSTR lpszDisplayName, LPBC pbc, LPITEMIDLIST *ppidl);
+
+/***********************************************************************
+* Desktopfolder implementation
+*/
+
+class CDesktopFolder;
+
+class CDesktopFolderEnum :
+ public IEnumIDListImpl
+{
+ private:
+// CComPtr fDesktopEnumerator;
+// CComPtr fCommonDesktopEnumerator;
+ public:
+ CDesktopFolderEnum();
+ ~CDesktopFolderEnum();
+ HRESULT WINAPI Initialize(CDesktopFolder *desktopFolder, HWND hwndOwner, DWORD dwFlags);
+
+ BEGIN_COM_MAP(CDesktopFolderEnum)
+ COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
+ END_COM_MAP()
+};
+
+int SHELL_ConfirmMsgBox(HWND hWnd, LPWSTR lpszText, LPWSTR lpszCaption, HICON hIcon, BOOL bYesToAll);
+
+static const shvheader DesktopSFHeader[] = {
+ {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
+ {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
+ {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
+ {IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 12},
+ {IDS_SHV_COLUMN5, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 5}
+};
+
+#define DESKTOPSHELLVIEWCOLUMNS 5
+
+CDesktopFolderEnum::CDesktopFolderEnum()
+{
+}
+
+CDesktopFolderEnum::~CDesktopFolderEnum()
+{
+}
+
+static const WCHAR ClassicStartMenuW[] = L"SOFTWARE\\Microsoft\\Windows\\"
+ L"CurrentVersion\\Explorer\\HideDesktopIcons\\ClassicStartMenu";
+
+static INT
+IsNamespaceExtensionHidden(const WCHAR *iid)
+{
+ DWORD Result, dwResult;
+ dwResult = sizeof(DWORD);
+
+ if (RegGetValueW(HKEY_CURRENT_USER, /* FIXME use NewStartPanel when activated */
+ ClassicStartMenuW,
+ iid,
+ RRF_RT_DWORD,
+ NULL,
+ &Result,
+ &dwResult) != ERROR_SUCCESS)
+ {
+ return -1;
+ }
+
+ return Result;
+}
+
+static VOID
+SetNamespaceExtensionVisibleStatus(const WCHAR * iid, DWORD dwStatus)
+{
+ HKEY hKey;
+
+ if (RegOpenKeyExW(HKEY_CURRENT_USER, ClassicStartMenuW, 0, KEY_WRITE, &hKey) == ERROR_SUCCESS)
+ {
+ RegSetValueExW(hKey, iid, 0, REG_DWORD, (LPBYTE)&dwStatus, sizeof(DWORD));
+ RegCloseKey(hKey);
+ }
+}
+
+/**************************************************************************
+ * CreateDesktopEnumList()
+ */
+
+HRESULT WINAPI CDesktopFolderEnum::Initialize(CDesktopFolder *desktopFolder, HWND hwndOwner, DWORD dwFlags)
+{
+ BOOL ret = TRUE;
+ WCHAR szPath[MAX_PATH];
+
+ static const WCHAR MyDocumentsClassString[] = L"{450D8FBA-AD25-11D0-98A8-0800361B1103}";
+ static const WCHAR Desktop_NameSpaceW[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Desktop\\Namespace";
+
+ TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags);
+
+ /* enumerate the root folders */
+ if (dwFlags & SHCONTF_FOLDERS)
+ {
+ HKEY hkey;
+ UINT i;
+ DWORD dwResult;
+
+ /* create the pidl for This item */
+ if (IsNamespaceExtensionHidden(MyDocumentsClassString) < 1)
+ {
+ ret = AddToEnumList(_ILCreateMyDocuments());
+ }
+ ret = AddToEnumList(_ILCreateMyComputer());
+
+ for (i = 0; i < 2; i++)
+ {
+ if (i == 0)
+ dwResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, Desktop_NameSpaceW, 0, KEY_READ, &hkey);
+ else
+ dwResult = RegOpenKeyExW(HKEY_CURRENT_USER, Desktop_NameSpaceW, 0, KEY_READ, &hkey);
+
+ if (dwResult == ERROR_SUCCESS)
+ {
+ WCHAR iid[50];
+ LPITEMIDLIST pidl;
+ int i = 0;
+
+ while (ret)
+ {
+ DWORD size;
+ LONG r;
+
+ size = sizeof (iid) / sizeof (iid[0]);
+ r = RegEnumKeyExW(hkey, i, iid, &size, 0, NULL, NULL, NULL);
+ if (ERROR_SUCCESS == r)
+ {
+ if (IsNamespaceExtensionHidden(iid) < 1)
+ {
+ pidl = _ILCreateGuidFromStrW(iid);
+ if (pidl != NULL)
+ {
+ if (!HasItemWithCLSID(pidl))
+ {
+ ret = AddToEnumList(pidl);
+ }
+ else
+ {
+ SHFree(pidl);
+ }
+ }
+ }
+ }
+ else if (ERROR_NO_MORE_ITEMS == r)
+ break;
+ else
+ ret = FALSE;
+ i++;
+ }
+ RegCloseKey(hkey);
+ }
+ }
+ for (i = 0; i < 2; i++)
+ {
+ if (i == 0)
+ dwResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, ClassicStartMenuW, 0, KEY_READ, &hkey);
+ else
+ dwResult = RegOpenKeyExW(HKEY_CURRENT_USER, ClassicStartMenuW, 0, KEY_READ, &hkey);
+
+ if (dwResult == ERROR_SUCCESS)
+ {
+ DWORD j = 0, dwVal, Val, dwType, dwIID;
+ LONG r;
+ WCHAR iid[50];
+
+ while(ret)
+ {
+ dwVal = sizeof(Val);
+ dwIID = sizeof(iid) / sizeof(WCHAR);
+
+ r = RegEnumValueW(hkey, j++, iid, &dwIID, NULL, &dwType, (LPBYTE)&Val, &dwVal);
+ if (r == ERROR_SUCCESS)
+ {
+ if (Val == 0 && dwType == REG_DWORD)
+ {
+ LPITEMIDLIST pidl = _ILCreateGuidFromStrW(iid);
+ if (pidl != NULL)
+ {
+ if (!HasItemWithCLSID(pidl))
+ {
+ AddToEnumList(pidl);
+ }
+ else
+ {
+ SHFree(pidl);
+ }
+ }
+ }
+ }
+ else if (ERROR_NO_MORE_ITEMS == r)
+ break;
+ else
+ ret = FALSE;
+ }
+ RegCloseKey(hkey);
+ }
+
+ }
+ }
+
+ /* enumerate the elements in %windir%\desktop */
+ ret = ret && SHGetSpecialFolderPathW(0, szPath, CSIDL_DESKTOPDIRECTORY, FALSE);
+ ret = ret && CreateFolderEnumList(szPath, dwFlags);
+
+ ret = ret && SHGetSpecialFolderPathW(0, szPath, CSIDL_COMMON_DESKTOPDIRECTORY, FALSE);
+ ret = ret && CreateFolderEnumList(szPath, dwFlags);
+
+ return ret ? S_OK : E_FAIL;
+}
+
+void CDesktopFolder::SF_RegisterClipFmt()
+{
+ TRACE ("(%p)\n", this);
+
+ if (!cfShellIDList)
+ cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
+}
+
+CDesktopFolder::CDesktopFolder()
+{
+ pidlRoot = NULL;
+ sPathTarget = NULL;
+ cfShellIDList = 0;
+ SF_RegisterClipFmt();
+ fAcceptFmt = FALSE;
+}
+
+CDesktopFolder::~CDesktopFolder()
+{
+}
+
+HRESULT WINAPI CDesktopFolder::FinalConstruct()
+{
+ WCHAR szMyPath[MAX_PATH];
+
+ if (!SHGetSpecialFolderPathW( 0, szMyPath, CSIDL_DESKTOPDIRECTORY, TRUE ))
+ return E_UNEXPECTED;
+
+ pidlRoot = _ILCreateDesktop(); /* my qualified pidl */
+ sPathTarget = (LPWSTR)SHAlloc((wcslen(szMyPath) + 1) * sizeof(WCHAR));
+ wcscpy(sPathTarget, szMyPath);
+ return S_OK;
+}
+
+/**************************************************************************
+ * CDesktopFolder::ParseDisplayName
+ *
+ * NOTES
+ * "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" and "" binds
+ * to MyComputer
+ */
+HRESULT WINAPI CDesktopFolder::ParseDisplayName(
+ HWND hwndOwner,
+ LPBC pbc,
+ LPOLESTR lpszDisplayName,
+ DWORD *pchEaten,
- LPCITEMIDLIST pidl,
++ PIDLIST_RELATIVE *ppidl,
+ DWORD *pdwAttributes)
+{
+ WCHAR szElement[MAX_PATH];
+ LPCWSTR szNext = NULL;
+ LPITEMIDLIST pidlTemp = NULL;
+ PARSEDURLW urldata;
+ 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 (!ppidl)
+ return E_INVALIDARG;
+
+ if (!lpszDisplayName)
+ {
+ *ppidl = NULL;
+ return E_INVALIDARG;
+ }
+
+ *ppidl = NULL;
+
+ if (pchEaten)
+ *pchEaten = 0; /* strange but like the original */
+
+ urldata.cbSize = sizeof(urldata);
+
+ 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 (PathGetDriveNumberW (lpszDisplayName) >= 0)
+ {
+ /* it's a filesystem path with a drive. Let MyComputer/UnixDosFolder parse it */
+ pidlTemp = _ILCreateMyComputer ();
+ szNext = lpszDisplayName;
+ }
+ else if (PathIsUNCW(lpszDisplayName))
+ {
+ pidlTemp = _ILCreateNetwork();
+ szNext = lpszDisplayName;
+ }
+ else if( (pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, lpszDisplayName)) )
+ {
+ *ppidl = pidlTemp;
+ return S_OK;
+ }
+ else if (SUCCEEDED(ParseURLW(lpszDisplayName, &urldata)))
+ {
+ if (urldata.nScheme == URL_SCHEME_SHELL) /* handle shell: urls */
+ {
+ TRACE ("-- shell url: %s\n", debugstr_w(urldata.pszSuffix));
+ SHCLSIDFromStringW (urldata.pszSuffix + 2, &clsid);
+ pidlTemp = _ILCreateGuid (PT_GUID, clsid);
+ }
+ else
+ return IEParseDisplayNameWithBCW(CP_ACP, lpszDisplayName, pbc, ppidl);
+ }
+ else
+ {
+ /* it's a filesystem path on the desktop. Let a FSFolder parse it */
+
+ if (*lpszDisplayName)
+ {
+ WCHAR szPath[MAX_PATH];
+ LPWSTR pathPtr;
+
+ /* build a complete path to create a simple pidl */
+ lstrcpynW(szPath, sPathTarget, MAX_PATH);
+ pathPtr = PathAddBackslashW(szPath);
+ if (pathPtr)
+ {
+ lstrcpynW(pathPtr, lpszDisplayName, MAX_PATH - (pathPtr - szPath));
+ hr = _ILCreateFromPathW(szPath, &pidlTemp);
+ }
+ else
+ {
+ /* should never reach here, but for completeness */
+ hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
+ }
+ }
+ else
+ pidlTemp = _ILCreateMyComputer();
+
+ szNext = NULL;
+ }
+
+ 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((IShellFolder *)this,
+ pidlTemp, pdwAttributes);
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ *ppidl = pidlTemp;
+ else
+ *ppidl = NULL;
+
+ TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr);
+
+ return hr;
+}
+
+/**************************************************************************
+ * CDesktopFolder::EnumObjects
+ */
+HRESULT WINAPI CDesktopFolder::EnumObjects(
+ HWND hwndOwner,
+ DWORD dwFlags,
+ LPENUMIDLIST *ppEnumIDList)
+{
+ CComObject<CDesktopFolderEnum> *theEnumerator;
+ CComPtr<IEnumIDList> result;
+ HRESULT hResult;
+
+ TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", this, hwndOwner, dwFlags, ppEnumIDList);
+
+ if (ppEnumIDList == NULL)
+ return E_POINTER;
+ *ppEnumIDList = NULL;
+
+ ATLTRY (theEnumerator = new CComObject<CDesktopFolderEnum>);
+
+ if (theEnumerator == NULL)
+ return E_OUTOFMEMORY;
+
+ hResult = theEnumerator->QueryInterface(IID_PPV_ARG(IEnumIDList, &result));
+ if (FAILED (hResult))
+ {
+ delete theEnumerator;
+ return hResult;
+ }
+
+ hResult = theEnumerator->Initialize (this, hwndOwner, dwFlags);
+ if (FAILED (hResult))
+ return hResult;
+ *ppEnumIDList = result.Detach ();
+
+ TRACE ("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList);
+
+ return S_OK;
+}
+
+/**************************************************************************
+ * CDesktopFolder::BindToObject
+ */
+HRESULT WINAPI CDesktopFolder::BindToObject(
- LPCITEMIDLIST pidl,
++ PCUIDLIST_RELATIVE pidl,
+ LPBC pbcReserved,
+ REFIID riid,
+ LPVOID *ppvOut)
+{
+ TRACE ("(%p)->(pidl=%p,%p,%s,%p)\n",
+ this, pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
+
+ return SHELL32_BindToChild( pidlRoot, sPathTarget, pidl, riid, ppvOut );
+}
+
+/**************************************************************************
+ * CDesktopFolder::BindToStorage
+ */
+HRESULT WINAPI CDesktopFolder::BindToStorage(
- HRESULT WINAPI CDesktopFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
++ PCUIDLIST_RELATIVE pidl,
+ LPBC pbcReserved,
+ REFIID riid,
+ LPVOID *ppvOut)
+{
+ FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n",
+ this, pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
+
+ *ppvOut = NULL;
+ return E_NOTIMPL;
+}
+
+/**************************************************************************
+ * CDesktopFolder::CompareIDs
+ */
- LPCITEMIDLIST *apidl,
++HRESULT WINAPI CDesktopFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
+{
+ int nReturn;
+
+ TRACE ("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", this, lParam, pidl1, pidl2);
+ nReturn = SHELL32_CompareIDs ((IShellFolder *)this, lParam, pidl1, pidl2);
+ TRACE ("-- %i\n", nReturn);
+ return nReturn;
+}
+
+/**************************************************************************
+ * CDesktopFolder::CreateViewObject
+ */
+HRESULT WINAPI CDesktopFolder::CreateViewObject(
+ HWND hwndOwner,
+ REFIID riid,
+ LPVOID *ppvOut)
+{
+ CComPtr<IShellView> pShellView;
+ HRESULT hr = E_INVALIDARG;
+
+ TRACE ("(%p)->(hwnd=%p,%s,%p)\n",
+ this, hwndOwner, shdebugstr_guid (&riid), ppvOut);
+
+ if (!ppvOut)
+ return hr;
+
+ *ppvOut = NULL;
+
+ if (IsEqualIID (riid, IID_IDropTarget))
+ {
+ hr = this->QueryInterface (IID_IDropTarget, ppvOut);
+ }
+ else if (IsEqualIID (riid, IID_IContextMenu))
+ {
+ 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);
+ }
+ TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
+ return hr;
+}
+
+/**************************************************************************
+ * CDesktopFolder::GetAttributesOf
+ */
+HRESULT WINAPI CDesktopFolder::GetAttributesOf(
+ UINT cidl,
- LPCITEMIDLIST *apidl,
++ PCUITEMID_CHILD_ARRAY apidl,
+ DWORD *rgfInOut)
+{
+ HRESULT hr = S_OK;
+ static const DWORD dwDesktopAttributes =
+ SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR |
+ SFGAO_STORAGEANCESTOR | SFGAO_HASPROPSHEET | SFGAO_STORAGE | SFGAO_CANLINK;
+ static const DWORD dwMyComputerAttributes =
+ SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
+ SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK;
+ static DWORD dwMyNetPlacesAttributes =
+ SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
+ SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK;
+
+ TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
+ this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
+
+ if (cidl && !apidl)
+ return E_INVALIDARG;
+
+ if (*rgfInOut == 0)
+ *rgfInOut = ~0;
+
+ if(cidl == 0)
+ *rgfInOut &= dwDesktopAttributes;
+ else
+ {
+ /* TODO: always add SFGAO_CANLINK */
+ for (UINT i = 0; i < cidl; ++i)
+ {
+ pdump(*apidl);
+ if (_ILIsDesktop(*apidl))
+ *rgfInOut &= dwDesktopAttributes;
+ else if (_ILIsMyComputer(apidl[i]))
+ *rgfInOut &= dwMyComputerAttributes;
+ else if (_ILIsNetHood(apidl[i]))
+ *rgfInOut &= dwMyNetPlacesAttributes;
+ else
+ SHELL32_GetItemAttributes((IShellFolder *)this, apidl[i], rgfInOut);
+ }
+ }
+ /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
+ *rgfInOut &= ~SFGAO_VALIDATE;
+
+ TRACE("-- result=0x%08x\n", *rgfInOut);
+
+ return hr;
+}
+
+/**************************************************************************
+ * CDesktopFolder::GetUIObjectOf
+ *
+ * PARAMETERS
+ * HWND hwndOwner, //[in ] Parent window for any output
+ * UINT cidl, //[in ] array size
+ * LPCITEMIDLIST* apidl, //[in ] simple pidl array
+ * REFIID riid, //[in ] Requested Interface
+ * UINT* prgfInOut, //[ ] reserved
+ * LPVOID* ppvObject) //[out] Resulting Interface
+ *
+ */
+HRESULT WINAPI CDesktopFolder::GetUIObjectOf(
+ HWND hwndOwner,
+ UINT cidl,
- HRESULT WINAPI CDesktopFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
++ PCUITEMID_CHILD_ARRAY apidl,
+ REFIID riid,
+ UINT *prgfInOut,
+ LPVOID *ppvOut)
+{
+ LPITEMIDLIST pidl;
+ IUnknown *pObj = NULL;
+ HRESULT hr = E_INVALIDARG;
+
+ TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
+ this, hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
+
+ if (!ppvOut)
+ return hr;
+
+ *ppvOut = NULL;
+
+ if (IsEqualIID (riid, IID_IContextMenu))
+ {
+ hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, (IShellFolder *)this, NULL, 0, NULL, (IContextMenu **)&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_IDropTarget))
+ {
+ /* only interested in attempting to bind to shell folders, not files, semicolon intentionate */
+ if (cidl != 1 || FAILED(hr = this->_GetDropTarget(apidl[0], (LPVOID*) &pObj)))
+ {
+ IDropTarget * pDt = NULL;
+ hr = this->QueryInterface(IID_PPV_ARG(IDropTarget, &pDt));
+ pObj = pDt;
+ }
+ }
+ 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
+ hr = E_NOINTERFACE;
+
+ if (SUCCEEDED(hr) && !pObj)
+ hr = E_OUTOFMEMORY;
+
+ *ppvOut = pObj;
+ TRACE ("(%p)->hr=0x%08x\n", this, hr);
+ return hr;
+}
+
+/**************************************************************************
+ * CDesktopFolder::GetDisplayNameOf
+ *
+ * NOTES
+ * special case: pidl = null gives desktop-name back
+ */
- LPCITEMIDLIST pidl, /* simple pidl */
++HRESULT WINAPI CDesktopFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
+{
+ HRESULT hr = S_OK;
+ LPWSTR pszPath;
+
+ TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
+ pdump (pidl);
+
+ if (!strRet)
+ return E_INVALIDARG;
+
+ pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
+ if (!pszPath)
+ return E_OUTOFMEMORY;
+
+ if (_ILIsDesktop (pidl))
+ {
+ if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
+ (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING))
+ wcscpy(pszPath, sPathTarget);
+ else
+ HCR_GetClassNameW(CLSID_ShellDesktop, pszPath, MAX_PATH);
+ }
+ else if (_ILIsPidlSimple (pidl))
+ {
+ GUID const *clsid;
+
+ if ((clsid = _ILGetGUIDPointer (pidl)))
+ {
+ if (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING)
+ {
+ int bWantsForParsing;
+
+ /*
+ * We can only get a filesystem path from a shellfolder if the
+ * value WantsFORPARSING in CLSID\\{...}\\shellfolder exists.
+ *
+ * Exception: The MyComputer folder doesn't have this key,
+ * but any other filesystem backed folder it needs it.
+ */
+ if (IsEqualIID (*clsid, CLSID_MyComputer))
+ {
+ bWantsForParsing = TRUE;
+ }
+ else
+ {
+ /* get the "WantsFORPARSING" flag from the registry */
+ static const WCHAR clsidW[] =
+ { 'C', 'L', 'S', 'I', 'D', '\\', 0 };
+ static const WCHAR shellfolderW[] =
+ { '\\', 's', 'h', 'e', 'l', 'l', 'f', 'o', 'l', 'd', 'e', 'r', 0 };
+ static const WCHAR wantsForParsingW[] =
+ { 'W', 'a', 'n', 't', 's', 'F', 'o', 'r', 'P', 'a', 'r', 's', 'i', 'n',
+ 'g', 0
+ };
+ WCHAR szRegPath[100];
+ LONG r;
+
+ wcscpy (szRegPath, clsidW);
+ SHELL32_GUIDToStringW (*clsid, &szRegPath[6]);
+ wcscat (szRegPath, shellfolderW);
+ r = SHGetValueW(HKEY_CLASSES_ROOT, szRegPath,
+ wantsForParsingW, NULL, NULL, NULL);
+ if (r == ERROR_SUCCESS)
+ bWantsForParsing = TRUE;
+ else
+ bWantsForParsing = FALSE;
+ }
+
+ if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
+ bWantsForParsing)
+ {
+ /*
+ * we need the filesystem path to the destination folder.
+ * Only the folder itself can know it
+ */
+ hr = SHELL32_GetDisplayNameOfChild (this, pidl, dwFlags,
+ pszPath,
+ MAX_PATH);
+ }
+ else
+ {
+ /* parsing name like ::{...} */
+ pszPath[0] = ':';
+ pszPath[1] = ':';
+ SHELL32_GUIDToStringW (*clsid, &pszPath[2]);
+ }
+ }
+ else
+ {
+ /* user friendly name */
+ HCR_GetClassNameW (*clsid, pszPath, MAX_PATH);
+ }
+ }
+ else
+ {
+ int cLen = 0;
+
+ /* file system folder or file rooted at the desktop */
+ if ((GET_SHGDN_FOR(dwFlags) == SHGDN_FORPARSING) &&
+ (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
+ {
+ lstrcpynW(pszPath, sPathTarget, MAX_PATH - 1);
+ PathAddBackslashW(pszPath);
+ cLen = wcslen(pszPath);
+ }
+
+ _ILSimpleGetTextW(pidl, pszPath + cLen, MAX_PATH - cLen);
+ if (!_ILIsFolder(pidl))
+ SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
+
+ if (GetFileAttributes(pszPath) == INVALID_FILE_ATTRIBUTES)
+ {
+ /* file system folder or file rooted at the AllUsers desktop */
+ if ((GET_SHGDN_FOR(dwFlags) == SHGDN_FORPARSING) &&
+ (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
+ {
+ SHGetSpecialFolderPathW(0, pszPath, CSIDL_COMMON_DESKTOPDIRECTORY, FALSE);
+ PathAddBackslashW(pszPath);
+ cLen = wcslen(pszPath);
+ }
+
+ _ILSimpleGetTextW(pidl, pszPath + cLen, MAX_PATH - cLen);
+ if (!_ILIsFolder(pidl))
+ SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
+ }
+ }
+ }
+ else
+ {
+ /* a complex pidl, let the subfolder do the work */
+ hr = SHELL32_GetDisplayNameOfChild (this, pidl, dwFlags,
+ pszPath, MAX_PATH);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ /* Win9x always returns ANSI strings, NT always returns Unicode strings */
+ if (GetVersion() & 0x80000000)
+ {
+ strRet->uType = STRRET_CSTR;
+ if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->cStr, MAX_PATH,
+ NULL, NULL))
+ strRet->cStr[0] = '\0';
+ CoTaskMemFree(pszPath);
+ }
+ else
+ {
+ strRet->uType = STRRET_WSTR;
+ strRet->pOleStr = pszPath;
+ }
+ }
+ else
+ CoTaskMemFree(pszPath);
+
+ TRACE ("-- (%p)->(%s,0x%08x)\n", this,
+ strRet->uType == STRRET_CSTR ? strRet->cStr :
+ debugstr_w(strRet->pOleStr), hr);
+ return hr;
+}
+
+/**************************************************************************
+ * CDesktopFolder::SetNameOf
+ * Changes the name of a file object or subfolder, possibly changing its item
+ * identifier in the process.
+ *
+ * PARAMETERS
+ * HWND hwndOwner, //[in ] Owner window for output
+ * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
+ * LPCOLESTR lpszName, //[in ] the items new display name
+ * DWORD dwFlags, //[in ] SHGNO formatting flags
+ * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
+ */
+HRESULT WINAPI CDesktopFolder::SetNameOf(
+ HWND hwndOwner,
- LPITEMIDLIST *pPidlOut)
++ PCUITEMID_CHILD pidl, /* simple pidl */
+ LPCOLESTR lpName,
+ DWORD dwFlags,
- LPCITEMIDLIST pidl,
++ PITEMID_CHILD *pPidlOut)
+{
+ CComPtr<IShellFolder2> psf;
+ HRESULT hr;
+ WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1];
+ LPWSTR ptr;
+ BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl));
+
+ TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl,
+ debugstr_w (lpName), dwFlags, pPidlOut);
+
+ if (_ILGetGUIDPointer(pidl))
+ {
+ if (SUCCEEDED(BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder2, &psf))))
+ {
+ hr = psf->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut);
+ return hr;
+ }
+ }
+
+ /* build source path */
+ lstrcpynW(szSrc, sPathTarget, MAX_PATH);
+ ptr = PathAddBackslashW (szSrc);
+ if (ptr)
+ _ILSimpleGetTextW (pidl, ptr, MAX_PATH + 1 - (ptr - szSrc));
+
+ /* build destination path */
+ if (dwFlags == SHGDN_NORMAL || dwFlags & SHGDN_INFOLDER) {
+ lstrcpynW(szDest, sPathTarget, MAX_PATH);
+ ptr = PathAddBackslashW (szDest);
+ if (ptr)
+ lstrcpynW(ptr, lpName, MAX_PATH + 1 - (ptr - szDest));
+ } else
+ lstrcpynW(szDest, lpName, MAX_PATH);
+
+ if(!(dwFlags & SHGDN_FORPARSING) && SHELL_FS_HideExtension(szSrc)) {
+ WCHAR *ext = PathFindExtensionW(szSrc);
+ if(*ext != '\0') {
+ INT len = wcslen(szDest);
+ lstrcpynW(szDest + len, ext, MAX_PATH - len);
+ }
+ }
+
+ if (!memcmp(szSrc, szDest, (wcslen(szDest) + 1) * sizeof(WCHAR)))
+ {
+ /* src and destination is the same */
+ hr = S_OK;
+ if (pPidlOut)
+ hr = _ILCreateFromPathW(szDest, pPidlOut);
+
+ return hr;
+ }
+
+ TRACE ("src=%s dest=%s\n", debugstr_w(szSrc), debugstr_w(szDest));
+ if (MoveFileW (szSrc, szDest))
+ {
+ hr = S_OK;
+
+ if (pPidlOut)
+ hr = _ILCreateFromPathW(szDest, pPidlOut);
+
+ SHChangeNotify (bIsFolder ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM,
+ SHCNF_PATHW, szSrc, szDest);
+
+ return hr;
+ }
+ return E_FAIL;
+}
+
+HRESULT WINAPI CDesktopFolder::GetDefaultSearchGUID(GUID *pguid)
+{
+ FIXME ("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CDesktopFolder::EnumSearches(IEnumExtraSearch **ppenum)
+{
+ FIXME ("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CDesktopFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
+{
+ TRACE ("(%p)\n", this);
+
+ if (pSort)
+ *pSort = 0;
+ if (pDisplay)
+ *pDisplay = 0;
+
+ return S_OK;
+}
+
+HRESULT WINAPI CDesktopFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
+{
+ TRACE ("(%p)\n", this);
+
+ if (!pcsFlags || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
+ return E_INVALIDARG;
+
+ *pcsFlags = DesktopSFHeader[iColumn].pcsFlags;
+
+ return S_OK;
+}
+
+HRESULT WINAPI CDesktopFolder::GetDetailsEx(
- LPCITEMIDLIST pidl,
++ PCUITEMID_CHILD pidl,
+ const SHCOLUMNID *pscid,
+ VARIANT *pv)
+{
+ FIXME ("(%p)\n", this);
+
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CDesktopFolder::GetDetailsOf(
++ PCUITEMID_CHILD pidl,
+ UINT iColumn,
+ SHELLDETAILS *psd)
+{
+ HRESULT hr = S_OK;
+
+ TRACE ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
+
+ if (!psd || iColumn >= DESKTOPSHELLVIEWCOLUMNS)
+ return E_INVALIDARG;
+
+ if (!pidl)
+ {
+ psd->fmt = DesktopSFHeader[iColumn].fmt;
+ psd->cxChar = DesktopSFHeader[iColumn].cxChar;
+ psd->str.uType = STRRET_CSTR;
+ LoadStringA (shell32_hInstance, DesktopSFHeader[iColumn].colnameid,
+ psd->str.cStr, MAX_PATH);
+ return S_OK;
+ }
+
+ /* the data from the pidl */
+ psd->str.uType = STRRET_CSTR;
+ switch (iColumn)
+ {
+ case 0: /* name */
+ hr = GetDisplayNameOf(pidl,
+ SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
+ break;
+ case 1: /* size */
+ _ILGetFileSize (pidl, psd->str.cStr, MAX_PATH);
+ break;
+ case 2: /* type */
+ _ILGetFileType (pidl, psd->str.cStr, MAX_PATH);
+ break;
+ case 3: /* date */
+ _ILGetFileDate (pidl, psd->str.cStr, MAX_PATH);
+ break;
+ case 4: /* attributes */
+ _ILGetFileAttributes (pidl, psd->str.cStr, MAX_PATH);
+ break;
+ }
+
+ return hr;
+}
+
+HRESULT WINAPI CDesktopFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
+{
+ FIXME ("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CDesktopFolder::GetClassID(CLSID *lpClassId)
+{
+ TRACE ("(%p)\n", this);
+
+ if (!lpClassId)
+ return E_POINTER;
+
+ *lpClassId = CLSID_ShellDesktop;
+
+ return S_OK;
+}
+
+HRESULT WINAPI CDesktopFolder::Initialize(LPCITEMIDLIST pidl)
+{
+ TRACE ("(%p)->(%p)\n", this, pidl);
+
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CDesktopFolder::GetCurFolder(LPITEMIDLIST * pidl)
+{
+ TRACE ("(%p)->(%p)\n", this, pidl);
+
+ if (!pidl) return E_POINTER;
+ *pidl = ILClone (pidlRoot);
+ return S_OK;
+}
+
+HRESULT WINAPI CDesktopFolder::GetUniqueName(LPWSTR pwszName, UINT uLen)
+{
+ CComPtr<IEnumIDList> penum;
+ HRESULT hr;
+ WCHAR wszText[MAX_PATH];
+ WCHAR wszNewFolder[25];
+ const WCHAR wszFormat[] = {'%', 's', ' ', '%', 'd', 0 };
+
+ LoadStringW(shell32_hInstance, IDS_NEWFOLDER, wszNewFolder, sizeof(wszNewFolder) / sizeof(WCHAR));
+
+ TRACE ("(%p)(%p %u)\n", this, pwszName, uLen);
+
+ if (uLen < sizeof(wszNewFolder) / sizeof(WCHAR) + 3)
+ return E_POINTER;
+
+ lstrcpynW (pwszName, wszNewFolder, uLen);
+
+ hr = EnumObjects(0,
+ SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &penum);
+ if (penum) {
+ LPITEMIDLIST pidl;
+ DWORD dwFetched;
+ int i = 1;
+
+next:
+ penum->Reset ();
+ while (S_OK == penum->Next(1, &pidl, &dwFetched) &&
+ dwFetched) {
+ _ILSimpleGetTextW (pidl, wszText, MAX_PATH);
+ if (0 == lstrcmpiW (wszText, pwszName)) {
+ _snwprintf (pwszName, uLen, wszFormat, wszNewFolder, i++);
+ if (i > 99) {
+ hr = E_FAIL;
+ break;
+ }
+ goto next;
+ }
+ }
+
+ }
+ return hr;
+}
+
+HRESULT WINAPI CDesktopFolder::AddFolder(HWND hwnd, LPCWSTR pwszName, LPITEMIDLIST *ppidlOut)
+{
+ WCHAR wszNewDir[MAX_PATH];
+ DWORD bRes;
+ HRESULT hres = E_FAIL;
+
+ TRACE ("(%p)(%s %p)\n", this, debugstr_w(pwszName), ppidlOut);
+
+ wszNewDir[0] = 0;
+ if (sPathTarget)
+ lstrcpynW(wszNewDir, sPathTarget, MAX_PATH);
+ PathAppendW(wszNewDir, pwszName);
+ bRes = CreateDirectoryW (wszNewDir, NULL);
+ if (bRes)
+ {
+ SHChangeNotify (SHCNE_MKDIR, SHCNF_PATHW, wszNewDir, NULL);
+ hres = S_OK;
+ if (ppidlOut)
+ hres = _ILCreateFromPathW(wszNewDir, ppidlOut);
+ }
+
+ return hres;
+}
+
+HRESULT WINAPI CDesktopFolder::DeleteItems(UINT cidl, LPCITEMIDLIST *apidl)
+{
+ UINT i;
+ SHFILEOPSTRUCTW op;
+ WCHAR wszPath[MAX_PATH];
+ WCHAR wszCaption[50];
+ WCHAR *wszPathsList;
+ HRESULT ret;
+ WCHAR *wszCurrentPath;
+ UINT bRestoreWithDeskCpl = FALSE;
+ int res;
+
+ TRACE ("(%p)(%u %p)\n", this, cidl, apidl);
+ if (cidl == 0) return S_OK;
+
+ for(i = 0; i < cidl; i++)
+ {
+ if (_ILIsMyComputer(apidl[i]))
+ bRestoreWithDeskCpl++;
+ else if (_ILIsNetHood(apidl[i]))
+ bRestoreWithDeskCpl++;
+ else if (_ILIsMyDocuments(apidl[i]))
+ bRestoreWithDeskCpl++;
+ }
+
+ if (bRestoreWithDeskCpl)
+ {
+ /* FIXME use FormatMessage
+ * use a similar message resource as in windows
+ */
+ LoadStringW(shell32_hInstance, IDS_DELETEMULTIPLE_TEXT, wszPath, sizeof(wszPath) / sizeof(WCHAR));
+ wszPath[(sizeof(wszPath)/sizeof(WCHAR))-1] = 0;
+
+ LoadStringW(shell32_hInstance, IDS_DELETEITEM_CAPTION, wszCaption, sizeof(wszCaption) / sizeof(WCHAR));
+ wszCaption[(sizeof(wszCaption)/sizeof(WCHAR))-1] = 0;
+
+ res = SHELL_ConfirmMsgBox(GetActiveWindow(), wszPath, wszCaption, NULL, cidl > 1);
+ if (res == IDC_YESTOALL || res == IDYES)
+ {
+ for(i = 0; i < cidl; i++)
+ {
+ if (_ILIsMyComputer(apidl[i]))
+ SetNamespaceExtensionVisibleStatus(L"{20D04FE0-3AEA-1069-A2D8-08002B30309D}", 0x1);
+ else if (_ILIsNetHood(apidl[i]))
+ SetNamespaceExtensionVisibleStatus(L"{208D2C60-3AEA-1069-A2D7-08002B30309D}", 0x1);
+ else if (_ILIsMyDocuments(apidl[i]))
+ SetNamespaceExtensionVisibleStatus(L"{450D8FBA-AD25-11D0-98A8-0800361B1103}", 0x1);
+ }
+ }
+ }
+ if (sPathTarget)
+ lstrcpynW(wszPath, sPathTarget, MAX_PATH);
+ else
+ wszPath[0] = '\0';
+
+ PathAddBackslashW(wszPath);
+ wszPathsList = BuildPathsList(wszPath, cidl, apidl);
+
+ ZeroMemory(&op, sizeof(op));
+ op.hwnd = GetActiveWindow();
+ op.wFunc = FO_DELETE;
+ op.pFrom = wszPathsList;
+ op.fFlags = FOF_ALLOWUNDO;
+ if (SHFileOperationW(&op))
+ {
+ WARN("SHFileOperation failed\n");
+ ret = E_FAIL;
+ }
+ else
+ ret = S_OK;
+
+ /* we currently need to manually send the notifies */
+ wszCurrentPath = wszPathsList;
+ for (i = 0; i < cidl; i++)
+ {
+ LONG wEventId;
+
+ if (_ILIsFolder(apidl[i]))
+ wEventId = SHCNE_RMDIR;
+ else if (_ILIsValue(apidl[i]))
+ wEventId = SHCNE_DELETE;
+ else
+ continue;
+
+ /* check if file exists */
+ if (GetFileAttributesW(wszCurrentPath) == INVALID_FILE_ATTRIBUTES)
+ {
+ LPITEMIDLIST pidl = ILCombine(pidlRoot, apidl[i]);
+ SHChangeNotify(wEventId, SHCNF_IDLIST, pidl, NULL);
+ SHFree(pidl);
+ }
+
+ wszCurrentPath += wcslen(wszCurrentPath) + 1;
+ }
+ HeapFree(GetProcessHeap(), 0, wszPathsList);
+ return ret;
+}
+
+HRESULT WINAPI CDesktopFolder::CopyItems(IShellFolder *pSFFrom, UINT cidl, LPCITEMIDLIST *apidl, bool bCopy)
+{
+ CComPtr<IPersistFolder2> ppf2;
+ WCHAR szSrcPath[MAX_PATH];
+ WCHAR szTargetPath[MAX_PATH];
+ SHFILEOPSTRUCTW op;
+ LPITEMIDLIST pidl;
+ LPWSTR pszSrc, pszTarget, pszSrcList, pszTargetList, pszFileName;
+ int res, length;
+ STRRET strRet;
+
+ TRACE ("(%p)->(%p,%u,%p)\n", this, pSFFrom, cidl, apidl);
+
+ pSFFrom->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
+ if (ppf2)
+ {
+ if (FAILED(ppf2->GetCurFolder(&pidl)))
+ return E_FAIL;
+
+ if (FAILED(pSFFrom->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strRet)))
+ {
+ SHFree (pidl);
+ return E_FAIL;
+ }
+
+ if (FAILED(StrRetToBufW(&strRet, pidl, szSrcPath, MAX_PATH)))
+ {
+ SHFree (pidl);
+ return E_FAIL;
+ }
+ SHFree (pidl);
+
+ pszSrc = PathAddBackslashW (szSrcPath);
+
+ wcscpy(szTargetPath, sPathTarget);
+ pszTarget = PathAddBackslashW (szTargetPath);
+
+ pszSrcList = BuildPathsList(szSrcPath, cidl, apidl);
+ pszTargetList = BuildPathsList(szTargetPath, cidl, apidl);
+
+ if (!pszSrcList || !pszTargetList)
+ {
+ if (pszSrcList)
+ HeapFree(GetProcessHeap(), 0, pszSrcList);
+
+ if (pszTargetList)
+ HeapFree(GetProcessHeap(), 0, pszTargetList);
+
+ SHFree (pidl);
+ return E_OUTOFMEMORY;
+ }
+ ZeroMemory(&op, sizeof(op));
+ if (!pszSrcList[0])
+ {
+ /* remove trailing backslash */
+ pszSrc--;
+ pszSrc[0] = L'\0';
+ op.pFrom = szSrcPath;
+ }
+ else
+ {
+ op.pFrom = pszSrcList;
+ }
+
+ if (!pszTargetList[0])
+ {
+ /* remove trailing backslash */
+ if (pszTarget - szTargetPath > 3)
+ {
+ pszTarget--;
+ pszTarget[0] = L'\0';
+ }
+ else
+ {
+ pszTarget[1] = L'\0';
+ }
+
+ op.pTo = szTargetPath;
+ op.fFlags = 0;
+ }
+ else
+ {
+ op.pTo = pszTargetList;
+ op.fFlags = FOF_MULTIDESTFILES;
+ }
+ op.hwnd = GetActiveWindow();
+ op.wFunc = bCopy ? FO_COPY : FO_MOVE;
+ op.fFlags |= FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR;
+
+ res = SHFileOperationW(&op);
+
+ if (res == DE_SAMEFILE)
+ {
+ length = wcslen(szTargetPath);
+
+
+ pszFileName = wcsrchr(pszSrcList, '\\');
+ pszFileName++;
+
+ if (LoadStringW(shell32_hInstance, IDS_COPY_OF, pszTarget, MAX_PATH - length))
+ {
+ wcscat(szTargetPath, L" ");
+ }
+
+ wcscat(szTargetPath, pszFileName);
+ op.pTo = szTargetPath;
+
+ res = SHFileOperationW(&op);
+ }
+
+
+ HeapFree(GetProcessHeap(), 0, pszSrcList);
+ HeapFree(GetProcessHeap(), 0, pszTargetList);
+
+ if (res)
+ return E_FAIL;
+ else
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+/****************************************************************************
+ * IDropTarget implementation
+ *
+ * This should allow two somewhat separate things, copying files to the users directory,
+ * as well as allowing icons to be moved anywhere and updating the registry to save.
+ *
+ * The first thing I think is best done using fs.cpp to prevent WET code. So we'll simulate
+ * a drop to the user's home directory. The second will look at the pointer location and
+ * set sensible places for the icons to live.
+ *
+ */
+BOOL CDesktopFolder::QueryDrop(DWORD dwKeyState, LPDWORD pdwEffect)
+{
+ /* TODO Windows does different drop effects if dragging across drives.
+ i.e., it will copy instead of move if the directories are on different disks. */
+
+ DWORD dwEffect = DROPEFFECT_MOVE;
+
+ *pdwEffect = DROPEFFECT_NONE;
+
+ if (fAcceptFmt) { /* Does our interpretation of the keystate ... */
+ *pdwEffect = KeyStateToDropEffect (dwKeyState);
+
+ if (*pdwEffect == DROPEFFECT_NONE)
+ *pdwEffect = dwEffect;
+
+ /* ... matches the desired effect ? */
+ if (dwEffect & *pdwEffect) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+HRESULT WINAPI CDesktopFolder::DragEnter(IDataObject *pDataObject,
+ DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
+{
+ TRACE("(%p)->(DataObject=%p)\n", this, pDataObject);
+ FORMATETC fmt;
+ FORMATETC fmt2;
+ fAcceptFmt = FALSE;
+
+ InitFormatEtc (fmt, cfShellIDList, TYMED_HGLOBAL);
+ InitFormatEtc (fmt2, CF_HDROP, TYMED_HGLOBAL);
+
+ if (SUCCEEDED(pDataObject->QueryGetData(&fmt)))
+ fAcceptFmt = TRUE;
+ else if (SUCCEEDED(pDataObject->QueryGetData(&fmt2)))
+ fAcceptFmt = TRUE;
+
+ QueryDrop(dwKeyState, pdwEffect);
+ return S_OK;
+}
+
+HRESULT WINAPI CDesktopFolder::DragOver(DWORD dwKeyState, POINTL pt,
+ DWORD *pdwEffect)
+{
+ TRACE("(%p)\n", this);
+
+ if (!pdwEffect)
+ return E_INVALIDARG;
+
+ QueryDrop(dwKeyState, pdwEffect);
+
+ return S_OK;
+}
+
+HRESULT WINAPI CDesktopFolder::DragLeave()
+{
+ TRACE("(%p)\n", this);
+ fAcceptFmt = FALSE;
+ return S_OK;
+}
+
+HRESULT WINAPI CDesktopFolder::Drop(IDataObject *pDataObject,
+ DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
+{
+ TRACE("(%p) object dropped desktop\n", this);
+
+ STGMEDIUM medium;
+ bool passthroughtofs = FALSE;
+ FORMATETC formatetc;
+ InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
+
+ HRESULT hr = pDataObject->GetData(&formatetc, &medium);
+ if (SUCCEEDED(hr))
+ {
+ /* lock the handle */
+ LPIDA lpcida = (LPIDA)GlobalLock(medium.hGlobal);
+ if (!lpcida)
+ {
+ ReleaseStgMedium(&medium);
+ return E_FAIL;
+ }
+
+ /* convert the clipboard data into pidl (pointer to id list) */
+ LPITEMIDLIST pidl;
+ LPITEMIDLIST *apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
+ if (!apidl)
+ {
+ ReleaseStgMedium(&medium);
+ return E_FAIL;
+ }
+ passthroughtofs = !_ILIsDesktop(pidl) || (dwKeyState & MK_CONTROL);
+ SHFree(pidl);
+ _ILFreeaPidl(apidl, lpcida->cidl);
+ ReleaseStgMedium(&medium);
+ }
+ else
+ {
+ InitFormatEtc (formatetc, CF_HDROP, TYMED_HGLOBAL);
+ if (SUCCEEDED(pDataObject->QueryGetData(&formatetc)))
+ {
+ passthroughtofs = TRUE;
+ }
+ }
+ /* We only want to really move files around if they don't already
+ come from the desktop, or we're linking or copying */
+ if (passthroughtofs)
+ {
+ LPITEMIDLIST pidl = NULL;
+
+ WCHAR szPath[MAX_PATH];
+ //LPWSTR pathPtr;
+
+ /* build a complete path to create a simple pidl */
+ lstrcpynW(szPath, sPathTarget, MAX_PATH);
+ /*pathPtr = */PathAddBackslashW(szPath);
+ //hr = _ILCreateFromPathW(szPath, &pidl);
+ hr = this->ParseDisplayName(NULL, NULL, szPath, NULL, &pidl, NULL);
+
+ if (SUCCEEDED(hr))
+ {
+ CComPtr<IDropTarget> pDT;
+ hr = this->BindToObject(pidl, NULL, IID_PPV_ARG(IDropTarget, &pDT));
+ CoTaskMemFree(pidl);
+ if (SUCCEEDED(hr))
+ SHSimulateDrop(pDT, pDataObject, dwKeyState, NULL, pdwEffect);
+ else
+ ERR("Error Binding");
+ }
+ else
+ ERR("Error creating from %s\n", debugstr_w(szPath));
+ }
+
+ /* Todo, rewrite the registry such that the icons are well placed.
+ Blocked by no bags implementation. */
+ return hr;
+}
+
+HRESULT WINAPI CDesktopFolder::_GetDropTarget(LPCITEMIDLIST pidl, LPVOID *ppvOut) {
+ HRESULT hr;
+
+ TRACE("CFSFolder::_GetDropTarget entered\n");
+
+ if (_ILGetGUIDPointer (pidl) || _ILIsFolder (pidl))
+ return this->BindToObject(pidl, NULL, IID_IDropTarget, ppvOut);
+
+ LPITEMIDLIST pidlNext = NULL;
+
+ STRRET strFile;
+ hr = this->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strFile);
+ if (SUCCEEDED(hr))
+ {
+ WCHAR wszPath[MAX_PATH];
+ hr = StrRetToBufW(&strFile, pidl, wszPath, _countof(wszPath));
+
+ if (SUCCEEDED(hr))
+ {
+ PathRemoveFileSpecW (wszPath);
+ hr = this->ParseDisplayName(NULL, NULL, wszPath, NULL, &pidlNext, NULL);
+
+ if (SUCCEEDED(hr))
+ {
+ CComPtr<IShellFolder> psf;
+ hr = this->BindToObject(pidlNext, NULL, IID_PPV_ARG(IShellFolder, &psf));
+ CoTaskMemFree(pidlNext);
+ if (SUCCEEDED(hr))
+ {
+ hr = psf->GetUIObjectOf(NULL, 1, &pidl, IID_IDropTarget, NULL, ppvOut);
+ if (FAILED(hr))
+ ERR("FS GetUIObjectOf failed: %x\n", hr);
+ }
+ else
+ ERR("BindToObject failed: %x\n", hr);
+ }
+ else
+ ERR("ParseDisplayName failed: %x\n", hr);
+ }
+ else
+ ERR("StrRetToBufW failed: %x\n", hr);
+ }
+ else
+ ERR("GetDisplayNameOf failed: %x\n", hr);
+
+ return hr;
+}
--- /dev/null
- LPITEMIDLIST *ppidl,
+/*
+ * Fonts folder
+ *
+ * Copyright 2008 Johannes Anderwald <johannes.anderwald@reactos.org>
+ * Copyright 2009 Andrew Hill
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <precomp.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL (shell);
+
+/*
+This folder should not exist. It is just a file system folder... The \windows\fonts
+directory contains a hidden desktop.ini with a UIHandler entry that specifies a class
+that lives in fontext.dll. The UI handler creates a custom view for the folder, which
+is what we normally see. However, the folder is a perfectly normal CFSFolder.
+*/
+
+/***********************************************************************
+* IShellFolder implementation
+*/
+
+class CDesktopFolderEnumZ: public IEnumIDListImpl
+{
+ public:
+ CDesktopFolderEnumZ();
+ ~CDesktopFolderEnumZ();
+ HRESULT WINAPI Initialize(DWORD dwFlags);
+ BOOL CreateFontsEnumList(DWORD dwFlags);
+
+ BEGIN_COM_MAP(CDesktopFolderEnumZ)
+ COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
+ END_COM_MAP()
+};
+
+static shvheader FontsSFHeader[] = {
+ {IDS_SHV_COLUMN8, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
+ {IDS_SHV_COLUMN_FONTTYPE , SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
+ {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
+ {IDS_SHV_COLUMN12, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15}
+};
+
+#define COLUMN_NAME 0
+#define COLUMN_TYPE 1
+#define COLUMN_SIZE 2
+#define COLUMN_FILENAME 3
+
+#define FontsSHELLVIEWCOLUMNS (4)
+
+CDesktopFolderEnumZ::CDesktopFolderEnumZ()
+{
+}
+
+CDesktopFolderEnumZ::~CDesktopFolderEnumZ()
+{
+}
+
+HRESULT WINAPI CDesktopFolderEnumZ::Initialize(DWORD dwFlags)
+{
+ if (CreateFontsEnumList(dwFlags) == FALSE)
+ return E_FAIL;
+ return S_OK;
+}
+
+static LPITEMIDLIST _ILCreateFontItem(LPWSTR pszFont, LPWSTR pszFile)
+{
+ PIDLDATA tmp;
+ LPITEMIDLIST pidl;
+ PIDLFontStruct * p;
+ int size0 = (char*)&tmp.u.cfont.szName - (char*)&tmp.u.cfont;
+ int size = size0;
+
+ tmp.type = 0x00;
+ tmp.u.cfont.dummy = 0xFF;
+ tmp.u.cfont.offsFile = wcslen(pszFont) + 1;
+
+ size += (tmp.u.cfont.offsFile + wcslen(pszFile) + 1) * sizeof(WCHAR);
+
+ pidl = (LPITEMIDLIST)SHAlloc(size + 4);
+ if (!pidl)
+ return pidl;
+
+ pidl->mkid.cb = size + 2;
+ memcpy(pidl->mkid.abID, &tmp, 2 + size0);
+
+ p = &((PIDLDATA*)pidl->mkid.abID)->u.cfont;
+ wcscpy(p->szName, pszFont);
+ wcscpy(p->szName + tmp.u.cfont.offsFile, pszFile);
+
+ *(WORD*)((char*)pidl + (size + 2)) = 0;
+ return pidl;
+}
+
+static PIDLFontStruct * _ILGetFontStruct(LPCITEMIDLIST pidl)
+{
+ LPPIDLDATA pdata = _ILGetDataPointer(pidl);
+
+ if (pdata && pdata->type == 0x00)
+ return (PIDLFontStruct*) & (pdata->u.cfont);
+
+ return NULL;
+}
+
+/**************************************************************************
+ * CDesktopFolderEnumZ::CreateFontsEnumList()
+ */
+BOOL CDesktopFolderEnumZ::CreateFontsEnumList(DWORD dwFlags)
+{
+ WCHAR szPath[MAX_PATH];
+ WCHAR szName[LF_FACESIZE+20];
+ WCHAR szFile[MAX_PATH];
+ LPWSTR pszPath;
+ UINT Length;
+ LONG ret;
+ DWORD dwType, dwName, dwFile, dwIndex;
+ LPITEMIDLIST pidl;
+ HKEY hKey;
+
+ if (dwFlags & SHCONTF_NONFOLDERS)
+ {
+ if (!SHGetSpecialFolderPathW(NULL, szPath, CSIDL_FONTS, FALSE))
+ return FALSE;
+
+ pszPath = PathAddBackslashW(szPath);
+ if (!pszPath)
+ return FALSE;
+ if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Fonts", 0, KEY_READ, &hKey) != ERROR_SUCCESS)
+ return FALSE;
+
+ Length = pszPath - szPath;
+ dwIndex = 0;
+ do
+ {
+ dwName = sizeof(szName) / sizeof(WCHAR);
+ dwFile = sizeof(szFile) / sizeof(WCHAR);
+ ret = RegEnumValueW(hKey, dwIndex++, szName, &dwName, NULL, &dwType, (LPBYTE)szFile, &dwFile);
+ if (ret == ERROR_SUCCESS)
+ {
+ szFile[(sizeof(szFile)/sizeof(WCHAR))-1] = L'\0';
+ if (dwType == REG_SZ && wcslen(szFile) + Length + 1 < (sizeof(szPath) / sizeof(WCHAR)))
+ {
+ wcscpy(&szPath[Length], szFile);
+ pidl = _ILCreateFontItem(szName, szPath);
+ TRACE("pidl %p name %s path %s\n", pidl, debugstr_w(szName), debugstr_w(szPath));
+ if (pidl)
+ {
+ if (!AddToEnumList(pidl))
+ SHFree(pidl);
+ }
+ }
+ }
+ } while(ret != ERROR_NO_MORE_ITEMS);
+ RegCloseKey(hKey);
+
+ }
+ return TRUE;
+}
+
+CFontsFolder::CFontsFolder()
+{
+ pidlRoot = NULL;
+ apidl = NULL;
+}
+
+CFontsFolder::~CFontsFolder()
+{
+ TRACE("-- destroying IShellFolder(%p)\n", this);
+ SHFree(pidlRoot);
+}
+
+HRESULT WINAPI CFontsFolder::FinalConstruct()
+{
+ pidlRoot = _ILCreateFont(); /* my qualified pidl */
+ if (pidlRoot == NULL)
+ return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+/**************************************************************************
+* CFontsFolder::ParseDisplayName
+*/
+HRESULT WINAPI CFontsFolder::ParseDisplayName(
+ HWND hwndOwner,
+ LPBC pbcReserved,
+ LPOLESTR lpszDisplayName,
+ DWORD *pchEaten,
- HRESULT WINAPI CFontsFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
++ PIDLIST_RELATIVE *ppidl,
+ DWORD * pdwAttributes)
+{
+ HRESULT hr = E_UNEXPECTED;
+
+ TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", this,
+ hwndOwner, pbcReserved, lpszDisplayName, debugstr_w (lpszDisplayName),
+ pchEaten, ppidl, pdwAttributes);
+
+ *ppidl = 0;
+ if (pchEaten)
+ *pchEaten = 0; /* strange but like the original */
+
+ TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr);
+
+ return hr;
+}
+
+/**************************************************************************
+* CFontsFolder::EnumObjects
+*/
+HRESULT WINAPI CFontsFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
+{
+ CComObject<CDesktopFolderEnumZ> *theEnumerator;
+ CComPtr<IEnumIDList> result;
+ HRESULT hResult;
+
+ TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", this, hwndOwner, dwFlags, ppEnumIDList);
+
+ if (ppEnumIDList == NULL)
+ return E_POINTER;
+ *ppEnumIDList = NULL;
+ ATLTRY (theEnumerator = new CComObject<CDesktopFolderEnumZ>);
+ if (theEnumerator == NULL)
+ return E_OUTOFMEMORY;
+ hResult = theEnumerator->QueryInterface(IID_PPV_ARG(IEnumIDList, &result));
+ if (FAILED (hResult))
+ {
+ delete theEnumerator;
+ return hResult;
+ }
+ hResult = theEnumerator->Initialize (dwFlags);
+ if (FAILED (hResult))
+ return hResult;
+ *ppEnumIDList = result.Detach ();
+
+ TRACE ("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList);
+
+ return S_OK;
+}
+
+/**************************************************************************
+* CFontsFolder::BindToObject
+*/
- HRESULT WINAPI CFontsFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
++HRESULT WINAPI CFontsFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, 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);
+}
+
+/**************************************************************************
+* CFontsFolder::BindToStorage
+*/
- HRESULT WINAPI CFontsFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
++HRESULT WINAPI CFontsFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
+{
+ FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n", this,
+ pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
+
+ *ppvOut = NULL;
+ return E_NOTIMPL;
+}
+
+/**************************************************************************
+* CFontsFolder::CompareIDs
+*/
+
- HRESULT WINAPI CFontsFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, DWORD *rgfInOut)
++HRESULT WINAPI CFontsFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
+{
+ int nReturn;
+
+ 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;
+}
+
+/**************************************************************************
+* CFontsFolder::CreateViewObject
+*/
+HRESULT WINAPI CFontsFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut)
+{
+ CComPtr<IShellView> pShellView;
+ HRESULT hr = E_INVALIDARG;
+
+ TRACE ("(%p)->(hwnd=%p,%s,%p)\n", this,
+ hwndOwner, shdebugstr_guid (&riid), ppvOut);
+
+ if (!ppvOut)
+ return hr;
+
+ *ppvOut = NULL;
+
+ if (IsEqualIID (riid, IID_IDropTarget))
+ {
+ WARN ("IDropTarget not implemented\n");
+ hr = E_NOTIMPL;
+ }
+ else if (IsEqualIID (riid, IID_IContextMenu))
+ {
+ WARN ("IContextMenu not implemented\n");
+ hr = E_NOTIMPL;
+ }
+ else if (IsEqualIID (riid, IID_IShellView))
+ {
+ hr = IShellView_Constructor (this, &pShellView);
+ if (pShellView)
+ hr = pShellView->QueryInterface(riid, ppvOut);
+ }
+ TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
+ return hr;
+}
+
+/**************************************************************************
+* CFontsFolder::GetAttributesOf
+*/
- UINT cidl, LPCITEMIDLIST *apidl,
++HRESULT WINAPI CFontsFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut)
+{
+ HRESULT hr = S_OK;
+
+ TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n", this,
+ cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
+
+ if (!rgfInOut)
+ return E_INVALIDARG;
+ if (cidl && !apidl)
+ return E_INVALIDARG;
+
+ if (*rgfInOut == 0)
+ *rgfInOut = ~0;
+
+ if (cidl == 0)
+ {
+ CComPtr<IShellFolder> psfParent;
+ LPCITEMIDLIST rpidl = NULL;
+
+ hr = SHBindToParent(pidlRoot, IID_PPV_ARG(IShellFolder, &psfParent), (LPCITEMIDLIST *)&rpidl);
+ if (SUCCEEDED(hr))
+ SHELL32_GetItemAttributes (psfParent, rpidl, rgfInOut);
+ }
+ else
+ {
+ while (cidl > 0 && *apidl)
+ {
+ pdump (*apidl);
+ SHELL32_GetItemAttributes (this, *apidl, rgfInOut);
+ apidl++;
+ cidl--;
+ }
+ }
+
+ /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
+ *rgfInOut &= ~SFGAO_VALIDATE;
+
+ TRACE ("-- result=0x%08x\n", *rgfInOut);
+ return hr;
+}
+
+/**************************************************************************
+* CFontsFolder::GetUIObjectOf
+*
+* PARAMETERS
+* hwndOwner [in] Parent window for any output
+* cidl [in] array size
+* apidl [in] simple pidl array
+* riid [in] Requested Interface
+* prgfInOut [ ] reserved
+* ppvObject [out] Resulting Interface
+*
+*/
+HRESULT WINAPI CFontsFolder::GetUIObjectOf(
+ HWND hwndOwner,
- HRESULT WINAPI CFontsFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
++ UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
+ REFIID riid, UINT *prgfInOut, LPVOID *ppvOut)
+{
+ LPITEMIDLIST pidl;
+ CComPtr<IUnknown> pObj;
+ HRESULT hr = E_INVALIDARG;
+
+ TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", this,
+ hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
+
+ if (!ppvOut)
+ return hr;
+
+ *ppvOut = NULL;
+
+ if (IsEqualIID (riid, IID_IContextMenu) && (cidl >= 1))
+ {
+ pObj = (IContextMenu *)this;
+ this->apidl = apidl[0];
+ hr = S_OK;
+ }
+ 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_IDropTarget) && (cidl >= 1))
+ {
+ IDropTarget * pDt = NULL;
+ hr = this->QueryInterface(IID_PPV_ARG(IDropTarget, &pDt));
+ pObj = pDt;
+ }
+ else
+ hr = E_NOINTERFACE;
+
+ if (SUCCEEDED(hr) && !pObj)
+ hr = E_OUTOFMEMORY;
+
+ *ppvOut = pObj.Detach();
+ TRACE ("(%p)->hr=0x%08x\n", this, hr);
+ return hr;
+}
+
+/**************************************************************************
+* CFontsFolder::GetDisplayNameOf
+*
+*/
- HRESULT WINAPI CFontsFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, /*simple pidl */
- LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut)
++HRESULT WINAPI CFontsFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
+{
+ PIDLFontStruct *pFont;
+
+ TRACE("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
+ pdump (pidl);
+
+ if (!strRet)
+ return E_INVALIDARG;
+
+ pFont = _ILGetFontStruct(pidl);
+ if (pFont)
+ {
+ strRet->pOleStr = (LPWSTR)CoTaskMemAlloc((wcslen(pFont->szName) + 1) * sizeof(WCHAR));
+ if (!strRet->pOleStr)
+ return E_OUTOFMEMORY;
+
+ wcscpy(strRet->pOleStr, pFont->szName);
+ strRet->uType = STRRET_WSTR;
+ }
+ else if (!pidl->mkid.cb)
+ {
+ WCHAR wszPath[MAX_PATH];
+
+ if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
+ (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING))
+ {
+ if (!SHGetSpecialFolderPathW(NULL, wszPath, CSIDL_FONTS, FALSE))
+ return E_FAIL;
+ }
+ else if (!HCR_GetClassNameW(CLSID_FontsFolderShortcut, wszPath, MAX_PATH))
+ return E_FAIL;
+
+ strRet->pOleStr = (LPWSTR)CoTaskMemAlloc((wcslen(wszPath) + 1) * sizeof(WCHAR));
+ if (!strRet->pOleStr)
+ return E_OUTOFMEMORY;
+
+ wcscpy(strRet->pOleStr, wszPath);
+ strRet->uType = STRRET_WSTR;
+ }
+ else
+ return E_INVALIDARG;
+
+ return S_OK;
+}
+
+/**************************************************************************
+* CFontsFolder::SetNameOf
+* Changes the name of a file object or subfolder, possibly changing its item
+* identifier in the process.
+*
+* PARAMETERS
+* hwndOwner [in] Owner window for output
+* pidl [in] simple pidl of item to change
+* lpszName [in] the items new display name
+* dwFlags [in] SHGNO formatting flags
+* ppidlOut [out] simple pidl returned
+*/
- HRESULT WINAPI CFontsFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
++HRESULT WINAPI CFontsFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, /*simple pidl */
++ LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
+{
+ FIXME ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this,
+ hwndOwner, pidl, debugstr_w (lpName), dwFlags, pPidlOut);
+ return E_FAIL;
+}
+
+HRESULT WINAPI CFontsFolder::GetDefaultSearchGUID(GUID *pguid)
+{
+ FIXME ("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CFontsFolder::EnumSearches(IEnumExtraSearch **ppenum)
+{
+ FIXME ("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CFontsFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
+{
+ TRACE ("(%p)\n", this);
+
+ if (pSort)
+ *pSort = 0;
+ if (pDisplay)
+ *pDisplay = 0;
+
+ return S_OK;
+}
+
+HRESULT WINAPI CFontsFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
+{
+ TRACE ("(%p)\n", this);
+
+ if (!pcsFlags || iColumn >= FontsSHELLVIEWCOLUMNS)
+ return E_INVALIDARG;
+ *pcsFlags = FontsSFHeader[iColumn].pcsFlags;
+ return S_OK;
+}
+
- HRESULT WINAPI CFontsFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd)
++HRESULT WINAPI CFontsFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
+{
+ FIXME ("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
++HRESULT WINAPI CFontsFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
+{
+ WCHAR buffer[MAX_PATH] = {0};
+ HRESULT hr = E_FAIL;
+ PIDLFontStruct * pfont;
+ HANDLE hFile;
+ LARGE_INTEGER FileSize;
+ SHFILEINFOW fi;
+
+ TRACE("(%p, %p, %d, %p)\n", this, pidl, iColumn, psd);
+
+ if (iColumn >= FontsSHELLVIEWCOLUMNS)
+ return E_FAIL;
+
+ psd->fmt = FontsSFHeader[iColumn].fmt;
+ psd->cxChar = FontsSFHeader[iColumn].cxChar;
+ if (pidl == NULL)
+ {
+ psd->str.uType = STRRET_WSTR;
+ if (LoadStringW(shell32_hInstance, FontsSFHeader[iColumn].colnameid, buffer, MAX_PATH))
+ hr = SHStrDupW(buffer, &psd->str.pOleStr);
+
+ return hr;
+ }
+
+ if (iColumn == COLUMN_NAME)
+ {
+ psd->str.uType = STRRET_WSTR;
+ return GetDisplayNameOf(pidl, SHGDN_NORMAL, &psd->str);
+ }
+
+ psd->str.uType = STRRET_CSTR;
+ psd->str.cStr[0] = '\0';
+
+ switch(iColumn)
+ {
+ case COLUMN_TYPE:
+ pfont = _ILGetFontStruct(pidl);
+ if (pfont)
+ {
+ if (SHGetFileInfoW(pfont->szName + pfont->offsFile, 0, &fi, sizeof(fi), SHGFI_TYPENAME))
+ {
+ psd->str.pOleStr = (LPWSTR)CoTaskMemAlloc((wcslen(fi.szTypeName) + 1) * sizeof(WCHAR));
+ if (!psd->str.pOleStr)
+ return E_OUTOFMEMORY;
+ wcscpy(psd->str.pOleStr, fi.szTypeName);
+ psd->str.uType = STRRET_WSTR;
+ return S_OK;
+ }
+ }
+ break;
+ case COLUMN_SIZE:
+ pfont = _ILGetFontStruct(pidl);
+ if (pfont)
+ {
+ hFile = CreateFileW(pfont->szName + pfont->offsFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hFile != INVALID_HANDLE_VALUE)
+ {
+ if (GetFileSizeEx(hFile, &FileSize))
+ {
+ if (StrFormatByteSizeW(FileSize.QuadPart, buffer, sizeof(buffer) / sizeof(WCHAR)))
+ {
+ psd->str.pOleStr = (LPWSTR)CoTaskMemAlloc(wcslen(buffer) + 1);
+ if (!psd->str.pOleStr)
+ {
+ CloseHandle(hFile);
+ return E_OUTOFMEMORY;
+ }
+ wcscpy(psd->str.pOleStr, buffer);
+ psd->str.uType = STRRET_WSTR;
+ CloseHandle(hFile);
+ return S_OK;
+ }
+ }
+ CloseHandle(hFile);
+ }
+ }
+ break;
+ case COLUMN_FILENAME:
+ pfont = _ILGetFontStruct(pidl);
+ if (pfont)
+ {
+ psd->str.pOleStr = (LPWSTR)CoTaskMemAlloc((wcslen(pfont->szName + pfont->offsFile) + 1) * sizeof(WCHAR));
+ if (psd->str.pOleStr)
+ {
+ psd->str.uType = STRRET_WSTR;
+ wcscpy(psd->str.pOleStr, pfont->szName + pfont->offsFile);
+ return S_OK;
+ }
+ else
+ return E_OUTOFMEMORY;
+ }
+ break;
+ }
+
+ return E_FAIL;
+}
+
+HRESULT WINAPI CFontsFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
+{
+ FIXME ("(%p)\n", this);
+
+ return E_NOTIMPL;
+}
+
+/************************************************************************
+ * CFontsFolder::GetClassID
+ */
+HRESULT WINAPI CFontsFolder::GetClassID(CLSID *lpClassId)
+{
+ TRACE ("(%p)\n", this);
+
+ if (!lpClassId)
+ return E_POINTER;
+
+ *lpClassId = CLSID_FontsFolderShortcut;
+
+ return S_OK;
+}
+
+/************************************************************************
+ * CFontsFolder::Initialize
+ *
+ * NOTES: it makes no sense to change the pidl
+ */
+HRESULT WINAPI CFontsFolder::Initialize(LPCITEMIDLIST pidl)
+{
+ TRACE ("(%p)->(%p)\n", this, pidl);
+
+ return E_NOTIMPL;
+}
+
+/**************************************************************************
+ * CFontsFolder::GetCurFolder
+ */
+HRESULT WINAPI CFontsFolder::GetCurFolder(LPITEMIDLIST *pidl)
+{
+ TRACE ("(%p)->(%p)\n", this, pidl);
+
+ if (!pidl)
+ return E_POINTER;
+
+ *pidl = ILClone(pidlRoot);
+
+ return S_OK;
+}
+
+/**************************************************************************
+* IContextMenu2 Implementation
+*/
+
+/**************************************************************************
+* CFontsFolder::QueryContextMenu()
+*/
+HRESULT WINAPI CFontsFolder::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
+{
+ WCHAR szBuffer[30] = {0};
+ ULONG Count = 1;
+
+ 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, idCmdFirst + Count, MFT_STRING, szBuffer, MFS_DEFAULT);
+ Count++;
+ }
+
+ if (LoadStringW(shell32_hInstance, IDS_PRINT_VERB, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
+ {
+ szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
+ _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_STRING, szBuffer, MFS_ENABLED);
+ }
+
+ if (LoadStringW(shell32_hInstance, IDS_COPY, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
+ {
+ szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
+ _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED);
+ _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_STRING, szBuffer, MFS_ENABLED);
+ }
+
+ if (LoadStringW(shell32_hInstance, IDS_DELETE, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
+ {
+ szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
+ _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED);
+ _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count, MFT_STRING, szBuffer, MFS_ENABLED);
+ }
+
+ if (LoadStringW(shell32_hInstance, IDS_PROPERTIES, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
+ {
+ szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
+ _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED);
+ _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count, MFT_STRING, szBuffer, MFS_ENABLED);
+ }
+
+ return MAKE_HRESULT(SEVERITY_SUCCESS, 0, Count);
+}
+
+/**************************************************************************
+* CFontsFolder::InvokeCommand()
+*/
+HRESULT WINAPI CFontsFolder::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
+{
+ SHELLEXECUTEINFOW sei;
+ PIDLFontStruct * pfont;
+ SHFILEOPSTRUCTW op;
+
+ TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n", this, lpcmi, lpcmi->lpVerb, lpcmi->hwnd);
+
+ if (lpcmi->lpVerb == MAKEINTRESOURCEA(1) || lpcmi->lpVerb == MAKEINTRESOURCEA(2) || lpcmi->lpVerb == MAKEINTRESOURCEA(7))
+ {
+ ZeroMemory(&sei, sizeof(sei));
+ sei.cbSize = sizeof(sei);
+ sei.hwnd = lpcmi->hwnd;
+ sei.nShow = SW_SHOWNORMAL;
+ if (lpcmi->lpVerb == MAKEINTRESOURCEA(1))
+ sei.lpVerb = L"open";
+ else if (lpcmi->lpVerb == MAKEINTRESOURCEA(2))
+ sei.lpVerb = L"print";
+ else if (lpcmi->lpVerb == MAKEINTRESOURCEA(7))
+ sei.lpVerb = L"properties";
+
+ pfont = _ILGetFontStruct(apidl);
+ sei.lpFile = pfont->szName + pfont->offsFile;
+
+ if (ShellExecuteExW(&sei) == FALSE)
+ return E_FAIL;
+ }
+ else if (lpcmi->lpVerb == MAKEINTRESOURCEA(4))
+ {
+ FIXME("implement font copying\n");
+ return E_NOTIMPL;
+ }
+ else if (lpcmi->lpVerb == MAKEINTRESOURCEA(6))
+ {
+ ZeroMemory(&op, sizeof(op));
+ op.hwnd = lpcmi->hwnd;
+ op.wFunc = FO_DELETE;
+ op.fFlags = FOF_ALLOWUNDO;
+ pfont = _ILGetFontStruct(apidl);
+ op.pFrom = pfont->szName + pfont->offsFile;
+ SHFileOperationW(&op);
+ }
+
+ return S_OK;
+}
+
+/**************************************************************************
+ * CFontsFolder::GetCommandString()
+ *
+ */
+HRESULT WINAPI CFontsFolder::GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen)
+{
+ TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n", this, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
+
+ return E_FAIL;
+}
+
+/**************************************************************************
+* CFontsFolder::HandleMenuMsg()
+*/
+HRESULT WINAPI CFontsFolder::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ TRACE("(%p)->(msg=%x wp=%lx lp=%lx)\n", this, uMsg, wParam, lParam);
+
+ return E_NOTIMPL;
+}
--- /dev/null
- DWORD *pchEaten, LPITEMIDLIST *ppidl,
+
+/*
+ * file system folder
+ *
+ * Copyright 1997 Marcus Meissner
+ * Copyright 1998, 1999, 2002 Juergen Schmied
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <precomp.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL (shell);
+
+/*
+CFileSysEnum should do an initial FindFirstFile and do a FindNextFile as each file is
+returned by Next. When the enumerator is created, it can do numerous additional operations
+including formatting a drive, reconnecting a network share drive, and requesting a disk
+be inserted in a removable drive.
+*/
+
+/***********************************************************************
+* IShellFolder implementation
+*/
+
+class CFileSysEnum :
+ public IEnumIDListImpl
+{
+ private:
+ public:
+ CFileSysEnum();
+ ~CFileSysEnum();
+ HRESULT WINAPI Initialize(LPWSTR sPathTarget, DWORD dwFlags);
+
+ BEGIN_COM_MAP(CFileSysEnum)
+ COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
+ END_COM_MAP()
+};
+
+CFileSysEnum::CFileSysEnum()
+{
+}
+
+CFileSysEnum::~CFileSysEnum()
+{
+}
+
+HRESULT WINAPI CFileSysEnum::Initialize(LPWSTR sPathTarget, DWORD dwFlags)
+{
+ return CreateFolderEnumList(sPathTarget, dwFlags);
+}
+
+/**************************************************************************
+* registers clipboardformat once
+*/
+void CFSFolder::SF_RegisterClipFmt()
+{
+ TRACE ("(%p)\n", this);
+
+ if (!cfShellIDList)
+ cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
+}
+
+CFSFolder::CFSFolder()
+{
+ pclsid = (CLSID *)&CLSID_ShellFSFolder;
+ sPathTarget = NULL;
+ pidlRoot = NULL;
+ cfShellIDList = 0;
+ SF_RegisterClipFmt();
+ fAcceptFmt = FALSE;
+ m_bGroupPolicyActive = 0;
+}
+
+CFSFolder::~CFSFolder()
+{
+ TRACE("-- destroying IShellFolder(%p)\n", this);
+
+ SHFree(pidlRoot);
+ SHFree(sPathTarget);
+}
+
+
+static const shvheader GenericSFHeader[] = {
+ {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
+ {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
+ {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
+ {IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 12},
+ {IDS_SHV_COLUMN5, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 5}
+};
+
+#define GENERICSHELLVIEWCOLUMNS 5
+
+/**************************************************************************
+ * SHELL32_CreatePidlFromBindCtx [internal]
+ *
+ * If the caller bound File System Bind Data, assume it is the
+ * find data for the path.
+ * This allows binding of paths that don't exist.
+ */
+LPITEMIDLIST SHELL32_CreatePidlFromBindCtx(IBindCtx *pbc, LPCWSTR path)
+{
+ IFileSystemBindData *fsbd = NULL;
+ LPITEMIDLIST pidl = NULL;
+ IUnknown *param = NULL;
+ WIN32_FIND_DATAW wfd;
+ HRESULT r;
+
+ TRACE("%p %s\n", pbc, debugstr_w(path));
+
+ if (!pbc)
+ return NULL;
+
+ /* see if the caller bound File System Bind Data */
+ r = pbc->GetObjectParam((LPOLESTR)STR_FILE_SYS_BIND_DATA, ¶m);
+ if (FAILED(r))
+ return NULL;
+
+ r = param->QueryInterface(IID_PPV_ARG(IFileSystemBindData,&fsbd));
+ if (SUCCEEDED(r))
+ {
+ r = fsbd->GetFindData(&wfd);
+ if (SUCCEEDED(r))
+ {
+ lstrcpynW(&wfd.cFileName[0], path, MAX_PATH);
+ pidl = _ILCreateFromFindDataW(&wfd);
+ }
+ fsbd->Release();
+ }
+
+ return pidl;
+}
+
+/**************************************************************************
+* CFSFolder::ParseDisplayName {SHELL32}
+*
+* Parse a display name.
+*
+* PARAMS
+* hwndOwner [in] Parent window for any message's
+* pbc [in] optional FileSystemBindData context
+* lpszDisplayName [in] Unicode displayname.
+* pchEaten [out] (unicode) characters processed
+* ppidl [out] complex pidl to item
+* pdwAttributes [out] items attributes
+*
+* NOTES
+* Every folder tries to parse only its own (the leftmost) pidl and creates a
+* subfolder to evaluate the remaining parts.
+* Now we can parse into namespaces implemented by shell extensions
+*
+* Behaviour on win98: lpszDisplayName=NULL -> crash
+* lpszDisplayName="" -> returns mycoputer-pidl
+*
+* FIXME
+* pdwAttributes is not set
+* pchEaten is not set like in windows
+*/
+HRESULT WINAPI CFSFolder::ParseDisplayName(HWND hwndOwner,
+ LPBC pbc,
+ LPOLESTR lpszDisplayName,
- LPCITEMIDLIST pidl,
++ DWORD *pchEaten, PIDLIST_RELATIVE *ppidl,
+ DWORD *pdwAttributes)
+{
+ HRESULT hr = E_INVALIDARG;
+ LPCWSTR szNext = NULL;
+ WCHAR szElement[MAX_PATH];
+ WCHAR szPath[MAX_PATH];
+ LPITEMIDLIST pidlTemp = NULL;
+ DWORD len;
+
+ TRACE ("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
+ this, hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName),
+ pchEaten, ppidl, pdwAttributes);
+
+ if (!ppidl)
+ return E_INVALIDARG;
+
+ if (!lpszDisplayName)
+ {
+ *ppidl = NULL;
+ return E_INVALIDARG;
+ }
+
+ *ppidl = NULL;
+
+ if (pchEaten)
+ *pchEaten = 0; /* strange but like the original */
+
+ if (*lpszDisplayName)
+ {
+ /* get the next element */
+ szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
+
+ pidlTemp = SHELL32_CreatePidlFromBindCtx(pbc, szElement);
+ if (pidlTemp != NULL)
+ {
+ hr = S_OK;
+ }
+ else
+ {
+ /* build the full pathname to the element */
+ lstrcpynW(szPath, sPathTarget, MAX_PATH - 1);
+ PathAddBackslashW(szPath);
+ len = wcslen(szPath);
+ lstrcpynW(szPath + len, szElement, MAX_PATH - len);
+
+ /* get the pidl */
+ hr = _ILCreateFromPathW(szPath, &pidlTemp);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (szNext && *szNext)
+ {
+ /* try to analyse the next element */
+ hr = SHELL32_ParseNextElement(this, hwndOwner, pbc,
+ &pidlTemp, (LPOLESTR) szNext, pchEaten, pdwAttributes);
+ }
+ else
+ {
+ /* it's the last element */
+ if (pdwAttributes && *pdwAttributes)
+ hr = SHELL32_GetItemAttributes(this, pidlTemp, pdwAttributes);
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ *ppidl = pidlTemp;
+ else
+ *ppidl = NULL;
+
+ TRACE("(%p)->(-- pidl=%p ret=0x%08x)\n", this, ppidl ? *ppidl : 0, hr);
+
+ return hr;
+}
+
+/**************************************************************************
+* CFSFolder::EnumObjects
+* PARAMETERS
+* HWND hwndOwner, //[in ] Parent Window
+* DWORD grfFlags, //[in ] SHCONTF enumeration mask
+* LPENUMIDLIST* ppenumIDList //[out] IEnumIDList interface
+*/
+HRESULT WINAPI CFSFolder::EnumObjects(
+ HWND hwndOwner,
+ DWORD dwFlags,
+ LPENUMIDLIST *ppEnumIDList)
+{
+ CComObject<CFileSysEnum> *theEnumerator;
+ CComPtr<IEnumIDList> result;
+ HRESULT hResult;
+
+ TRACE("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", this, hwndOwner, dwFlags, ppEnumIDList);
+
+ if (ppEnumIDList == NULL)
+ return E_POINTER;
+ *ppEnumIDList = NULL;
+ ATLTRY (theEnumerator = new CComObject<CFileSysEnum>);
+ if (theEnumerator == NULL)
+ return E_OUTOFMEMORY;
+ hResult = theEnumerator->QueryInterface(IID_PPV_ARG(IEnumIDList, &result));
+ if (FAILED(hResult))
+ {
+ delete theEnumerator;
+ return hResult;
+ }
+ hResult = theEnumerator->Initialize (sPathTarget, dwFlags);
+ if (FAILED (hResult))
+ return hResult;
+ *ppEnumIDList = result.Detach();
+
+ TRACE("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList);
+
+ return S_OK;
+}
+
+/**************************************************************************
+* CFSFolder::BindToObject
+* PARAMETERS
+* LPCITEMIDLIST pidl, //[in ] relative pidl to open
+* LPBC pbc, //[in ] optional FileSystemBindData context
+* REFIID riid, //[in ] Initial Interface
+* LPVOID* ppvObject //[out] Interface*
+*/
+HRESULT WINAPI CFSFolder::BindToObject(
- LPCITEMIDLIST pidl,
++ PCUIDLIST_RELATIVE pidl,
+ LPBC pbc,
+ REFIID riid,
+ LPVOID * ppvOut)
+{
+ TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this, pidl, pbc,
+ shdebugstr_guid(&riid), ppvOut);
+
+ return SHELL32_BindToChild(pidlRoot, sPathTarget, pidl, riid, ppvOut);
+}
+
+/**************************************************************************
+* CFSFolder::BindToStorage
+* PARAMETERS
+* LPCITEMIDLIST pidl, //[in ] complex pidl to store
+* LPBC pbc, //[in ] reserved
+* REFIID riid, //[in ] Initial storage interface
+* LPVOID* ppvObject //[out] Interface* returned
+*/
+HRESULT WINAPI CFSFolder::BindToStorage(
- LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
++ PCUIDLIST_RELATIVE pidl,
+ LPBC pbcReserved,
+ REFIID riid,
+ LPVOID *ppvOut)
+{
+ FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this, pidl, pbcReserved,
+ shdebugstr_guid (&riid), ppvOut);
+
+ *ppvOut = NULL;
+ return E_NOTIMPL;
+}
+
+/**************************************************************************
+* CFSFolder::CompareIDs
+*/
+
+HRESULT WINAPI CFSFolder::CompareIDs(LPARAM lParam,
- LPCITEMIDLIST * apidl, DWORD * rgfInOut)
++ PCUIDLIST_RELATIVE pidl1,
++ PCUIDLIST_RELATIVE pidl2)
+{
+ int nReturn;
+
+ 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;
+}
+
+/**************************************************************************
+* CFSFolder::CreateViewObject
+*/
+HRESULT WINAPI CFSFolder::CreateViewObject(HWND hwndOwner,
+ REFIID riid, LPVOID * ppvOut)
+{
+ CComPtr<IShellView> pShellView;
+ HRESULT hr = E_INVALIDARG;
+
+ TRACE ("(%p)->(hwnd=%p,%s,%p)\n", this, hwndOwner, shdebugstr_guid (&riid),
+ ppvOut);
+
+ if (ppvOut)
+ {
+ *ppvOut = NULL;
+
+ if (IsEqualIID (riid, IID_IDropTarget))
+ hr = this->QueryInterface (IID_IDropTarget, ppvOut);
+ else if (IsEqualIID (riid, IID_IContextMenu))
+ {
+ FIXME ("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);
+ }
+ }
+ }
+ TRACE("-- (%p)->(interface=%p)\n", this, ppvOut);
+ return hr;
+}
+
+/**************************************************************************
+* CFSFolder::GetAttributesOf
+*
+* PARAMETERS
+* UINT cidl, //[in ] num elements in pidl array
+* LPCITEMIDLIST* apidl, //[in ] simple pidl array
+* ULONG* rgfInOut) //[out] result array
+*
+*/
+HRESULT WINAPI CFSFolder::GetAttributesOf(UINT cidl,
- UINT cidl, LPCITEMIDLIST * apidl, REFIID riid,
- UINT * prgfInOut, LPVOID * ppvOut)
++ PCUITEMID_CHILD_ARRAY apidl, DWORD * rgfInOut)
+{
+ HRESULT hr = S_OK;
+
+ TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n", this, cidl, apidl,
+ rgfInOut, rgfInOut ? *rgfInOut : 0);
+
+ if (!rgfInOut)
+ return E_INVALIDARG;
+ if (cidl && !apidl)
+ return E_INVALIDARG;
+
+ if (*rgfInOut == 0)
+ *rgfInOut = ~0;
+
+ if(cidl == 0)
+ {
+ IShellFolder *psfParent = NULL;
+ LPCITEMIDLIST rpidl = NULL;
+
+ hr = SHBindToParent(pidlRoot, IID_PPV_ARG(IShellFolder, &psfParent), &rpidl);
+ if(SUCCEEDED(hr))
+ {
+ SHELL32_GetItemAttributes (psfParent, rpidl, rgfInOut);
+ psfParent->Release();
+ }
+ }
+ else
+ {
+ while (cidl > 0 && *apidl)
+ {
+ pdump(*apidl);
+ SHELL32_GetItemAttributes(this, *apidl, rgfInOut);
+ apidl++;
+ cidl--;
+ }
+ }
+ /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
+ *rgfInOut &= ~SFGAO_VALIDATE;
+
+ TRACE("-- result=0x%08x\n", *rgfInOut);
+
+ return hr;
+}
+
+/**************************************************************************
+* CFSFolder::GetUIObjectOf
+*
+* PARAMETERS
+* HWND hwndOwner, //[in ] Parent window for any output
+* UINT cidl, //[in ] array size
+* LPCITEMIDLIST* apidl, //[in ] simple pidl array
+* REFIID riid, //[in ] Requested Interface
+* UINT* prgfInOut, //[ ] reserved
+* LPVOID* ppvObject) //[out] Resulting Interface
+*
+* NOTES
+* This function gets asked to return "view objects" for one or more (multiple
+* select) items:
+* The viewobject typically is an COM object with one of the following
+* interfaces:
+* IExtractIcon,IDataObject,IContextMenu
+* In order to support icon positions in the default Listview your DataObject
+* must implement the SetData method (in addition to GetData :) - the shell
+* passes a barely documented "Icon positions" structure to SetData when the
+* drag starts, and GetData's it if the drop is in another explorer window that
+* needs the positions.
+*/
+HRESULT WINAPI CFSFolder::GetUIObjectOf(HWND hwndOwner,
- HRESULT WINAPI CFSFolder::GetDisplayNameOf(LPCITEMIDLIST pidl,
++ UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
++ REFIID riid, UINT * prgfInOut,
++ LPVOID * ppvOut)
+{
+ LPITEMIDLIST pidl;
+ IUnknown *pObj = NULL;
+ HRESULT hr = E_INVALIDARG;
+
+ TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
+ this, hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
+
+ if (ppvOut)
+ {
+ *ppvOut = NULL;
+
+ if (IsEqualIID(riid, IID_IContextMenu) && (cidl >= 1))
+ {
+ IContextMenu * pCm = NULL;
+ hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, static_cast<IShellFolder*>(this), NULL, 0, NULL, &pCm);
+ pObj = pCm;
+ }
+ else if (IsEqualIID (riid, IID_IDataObject))
+ {
+ if (cidl >= 1)
+ {
+ hr = IDataObject_Constructor (hwndOwner, pidlRoot, apidl, cidl, (IDataObject **)&pObj);
+ }
+ else
+ {
+ hr = IDataObject_Constructor (hwndOwner, pidlRoot, (LPCITEMIDLIST*)&pidlRoot, 1, (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_IDropTarget))
+ {
+ /* only interested in attempting to bind to shell folders, not files (except exe), so if we fail, rebind to root */
+ if (cidl != 1 || FAILED(hr = this->_GetDropTarget(apidl[0], (LPVOID*) &pObj)))
+ {
+ IDropTarget * pDt = NULL;
+ hr = this->QueryInterface(IID_PPV_ARG(IDropTarget, &pDt));
+ pObj = pDt;
+ }
+ }
+ 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
+ hr = E_NOINTERFACE;
+
+ if (SUCCEEDED(hr) && !pObj)
+ hr = E_OUTOFMEMORY;
+
+ *ppvOut = pObj;
+ }
+ TRACE("(%p)->hr=0x%08x\n", this, hr);
+ return hr;
+}
+
+static const WCHAR AdvancedW[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced";
+static const WCHAR HideFileExtW[] = L"HideFileExt";
+static const WCHAR NeverShowExtW[] = L"NeverShowExt";
+
+/******************************************************************************
+ * SHELL_FS_HideExtension [Internal]
+ *
+ * Query the registry if the filename extension of a given path should be
+ * hidden.
+ *
+ * PARAMS
+ * szPath [I] Relative or absolute path of a file
+ *
+ * RETURNS
+ * TRUE, if the filename's extension should be hidden
+ * FALSE, otherwise.
+ */
+BOOL SHELL_FS_HideExtension(LPWSTR szPath)
+{
+ HKEY hKey;
+ DWORD dwData;
+ DWORD dwDataSize = sizeof (DWORD);
+ BOOL doHide = FALSE; /* The default value is FALSE (win98 at least) */
+
+ if (!RegCreateKeyExW(HKEY_CURRENT_USER, AdvancedW, 0, 0, 0, KEY_ALL_ACCESS, 0, &hKey, 0)) {
+ if (!RegQueryValueExW(hKey, HideFileExtW, 0, 0, (LPBYTE) &dwData, &dwDataSize))
+ doHide = dwData;
+ RegCloseKey (hKey);
+ }
+
+ if (!doHide) {
+ LPWSTR ext = PathFindExtensionW(szPath);
+
+ if (*ext != '\0') {
+ WCHAR classname[MAX_PATH];
+ LONG classlen = sizeof(classname);
+
+ if (!RegQueryValueW(HKEY_CLASSES_ROOT, ext, classname, &classlen))
+ if (!RegOpenKeyW(HKEY_CLASSES_ROOT, classname, &hKey)) {
+ if (!RegQueryValueExW(hKey, NeverShowExtW, 0, NULL, NULL, NULL))
+ doHide = TRUE;
+ RegCloseKey(hKey);
+ }
+ }
+ }
+ return doHide;
+}
+
+void SHELL_FS_ProcessDisplayFilename(LPWSTR szPath, DWORD dwFlags)
+{
+ /*FIXME: MSDN also mentions SHGDN_FOREDITING which is not yet handled. */
+ if (!(dwFlags & SHGDN_FORPARSING) &&
+ ((dwFlags & SHGDN_INFOLDER) || (dwFlags == SHGDN_NORMAL))) {
+ if (SHELL_FS_HideExtension(szPath) && szPath[0] != '.')
+ PathRemoveExtensionW(szPath);
+ }
+}
+
+/**************************************************************************
+* CFSFolder::GetDisplayNameOf
+* Retrieves the display name for the specified file object or subfolder
+*
+* PARAMETERS
+* LPCITEMIDLIST pidl, //[in ] complex pidl to item
+* DWORD dwFlags, //[in ] SHGNO formatting flags
+* LPSTRRET lpName) //[out] Returned display name
+*
+* FIXME
+* if the name is in the pidl the ret value should be a STRRET_OFFSET
+*/
+
- LPCITEMIDLIST pidl,
++HRESULT WINAPI CFSFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl,
+ DWORD dwFlags, LPSTRRET strRet)
+{
+ LPWSTR pszPath;
+
+ HRESULT hr = S_OK;
+ int len = 0;
+
+ TRACE("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
+ pdump(pidl);
+
+ if (!pidl || !strRet)
+ return E_INVALIDARG;
+
+ pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
+ if (!pszPath)
+ return E_OUTOFMEMORY;
+
+ if (_ILIsDesktop(pidl)) /* empty pidl */
+ {
+ if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
+ (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
+ {
+ if (sPathTarget)
+ lstrcpynW(pszPath, sPathTarget, MAX_PATH);
+ }
+ else
+ hr = E_INVALIDARG; /* pidl has to contain exactly one non null SHITEMID */
+ }
+ else if (_ILIsPidlSimple(pidl))
+ {
+ if ((GET_SHGDN_FOR(dwFlags) & SHGDN_FORPARSING) &&
+ (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER) &&
+ sPathTarget)
+ {
+ lstrcpynW(pszPath, sPathTarget, MAX_PATH);
+ PathAddBackslashW(pszPath);
+ len = wcslen(pszPath);
+ }
+ _ILSimpleGetTextW(pidl, pszPath + len, MAX_PATH + 1 - len);
+ if (!_ILIsFolder(pidl)) SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
+ } else
+ hr = SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, pszPath, MAX_PATH);
+
+ if (SUCCEEDED(hr)) {
+ /* Win9x always returns ANSI strings, NT always returns Unicode strings */
+ if (GetVersion() & 0x80000000)
+ {
+ strRet->uType = STRRET_CSTR;
+ if (!WideCharToMultiByte(CP_ACP, 0, pszPath, -1, strRet->cStr, MAX_PATH,
+ NULL, NULL))
+ strRet->cStr[0] = '\0';
+ CoTaskMemFree(pszPath);
+ }
+ else
+ {
+ strRet->uType = STRRET_WSTR;
+ strRet->pOleStr = pszPath;
+ }
+ } else
+ CoTaskMemFree(pszPath);
+
+ TRACE ("-- (%p)->(%s)\n", this, strRet->uType == STRRET_CSTR ? strRet->cStr : debugstr_w(strRet->pOleStr));
+ return hr;
+}
+
+/**************************************************************************
+* CFSFolder::SetNameOf
+* Changes the name of a file object or subfolder, possibly changing its item
+* identifier in the process.
+*
+* PARAMETERS
+* HWND hwndOwner, //[in ] Owner window for output
+* LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
+* LPCOLESTR lpszName, //[in ] the items new display name
+* DWORD dwFlags, //[in ] SHGNO formatting flags
+* LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
+*/
+HRESULT WINAPI CFSFolder::SetNameOf(
+ HWND hwndOwner,
- LPITEMIDLIST * pPidlOut)
++ PCUITEMID_CHILD pidl,
+ LPCOLESTR lpName,
+ DWORD dwFlags,
- HRESULT WINAPI CFSFolder::GetDetailsEx(LPCITEMIDLIST pidl,
++ PITEMID_CHILD *pPidlOut)
+{
+ WCHAR szSrc[MAX_PATH + 1], szDest[MAX_PATH + 1];
+ LPWSTR ptr;
+ BOOL bIsFolder = _ILIsFolder (ILFindLastID (pidl));
+
+ TRACE ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl,
+ debugstr_w (lpName), dwFlags, pPidlOut);
+
+ /* build source path */
+ lstrcpynW(szSrc, sPathTarget, MAX_PATH);
+ ptr = PathAddBackslashW (szSrc);
+ if (ptr)
+ _ILSimpleGetTextW (pidl, ptr, MAX_PATH + 1 - (ptr - szSrc));
+
+ /* build destination path */
+ if (dwFlags == SHGDN_NORMAL || dwFlags & SHGDN_INFOLDER) {
+ lstrcpynW(szDest, sPathTarget, MAX_PATH);
+ ptr = PathAddBackslashW (szDest);
+ if (ptr)
+ lstrcpynW(ptr, lpName, MAX_PATH + 1 - (ptr - szDest));
+ } else
+ lstrcpynW(szDest, lpName, MAX_PATH);
+
+ if(!(dwFlags & SHGDN_FORPARSING) && SHELL_FS_HideExtension(szSrc)) {
+ WCHAR *ext = PathFindExtensionW(szSrc);
+ if(*ext != '\0') {
+ INT len = wcslen(szDest);
+ lstrcpynW(szDest + len, ext, MAX_PATH - len);
+ }
+ }
+
+ TRACE ("src=%s dest=%s\n", debugstr_w(szSrc), debugstr_w(szDest));
+ if (!memcmp(szSrc, szDest, (wcslen(szDest) + 1) * sizeof(WCHAR)))
+ {
+ /* src and destination is the same */
+ HRESULT hr = S_OK;
+ if (pPidlOut)
+ hr = _ILCreateFromPathW(szDest, pPidlOut);
+
+ return hr;
+ }
+
+
+ if (MoveFileW (szSrc, szDest))
+ {
+ HRESULT hr = S_OK;
+
+ if (pPidlOut)
+ hr = _ILCreateFromPathW(szDest, pPidlOut);
+
+ SHChangeNotify (bIsFolder ? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM,
+ SHCNF_PATHW, szSrc, szDest);
+
+ return hr;
+ }
+
+ return E_FAIL;
+}
+
+HRESULT WINAPI CFSFolder::GetDefaultSearchGUID(GUID * pguid)
+{
+ FIXME ("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CFSFolder::EnumSearches(IEnumExtraSearch ** ppenum)
+{
+ FIXME ("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CFSFolder::GetDefaultColumn(DWORD dwRes,
+ ULONG * pSort, ULONG * pDisplay)
+{
+ TRACE ("(%p)\n", this);
+
+ if (pSort)
+ *pSort = 0;
+ if (pDisplay)
+ *pDisplay = 0;
+
+ return S_OK;
+}
+
+HRESULT WINAPI CFSFolder::GetDefaultColumnState(UINT iColumn,
+ DWORD * pcsFlags)
+{
+ TRACE ("(%p)\n", this);
+
+ if (!pcsFlags || iColumn >= GENERICSHELLVIEWCOLUMNS)
+ return E_INVALIDARG;
+
+ *pcsFlags = GenericSFHeader[iColumn].pcsFlags;
+
+ return S_OK;
+}
+
- HRESULT WINAPI CFSFolder::GetDetailsOf(LPCITEMIDLIST pidl,
++HRESULT WINAPI CFSFolder::GetDetailsEx(PCUITEMID_CHILD pidl,
+ const SHCOLUMNID * pscid, VARIANT * pv)
+{
+ FIXME ("(%p)\n", this);
+
+ return E_NOTIMPL;
+}
+
++HRESULT WINAPI CFSFolder::GetDetailsOf(PCUITEMID_CHILD pidl,
+ UINT iColumn, SHELLDETAILS * psd)
+{
+ HRESULT hr = E_FAIL;
+
+ TRACE ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
+
+ if (!psd || iColumn >= GENERICSHELLVIEWCOLUMNS)
+ return E_INVALIDARG;
+
+ if (!pidl)
+ {
+ /* the header titles */
+ psd->fmt = GenericSFHeader[iColumn].fmt;
+ psd->cxChar = GenericSFHeader[iColumn].cxChar;
+ psd->str.uType = STRRET_CSTR;
+ LoadStringA(shell32_hInstance, GenericSFHeader[iColumn].colnameid,
+ psd->str.cStr, MAX_PATH);
+ return S_OK;
+ }
+ else
+ {
+ hr = S_OK;
+ psd->str.uType = STRRET_CSTR;
+ /* the data from the pidl */
+ switch (iColumn)
+ {
+ case 0: /* name */
+ hr = GetDisplayNameOf (pidl,
+ SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
+ break;
+ case 1: /* size */
+ _ILGetFileSize(pidl, psd->str.cStr, MAX_PATH);
+ break;
+ case 2: /* type */
+ _ILGetFileType(pidl, psd->str.cStr, MAX_PATH);
+ break;
+ case 3: /* date */
+ _ILGetFileDate(pidl, psd->str.cStr, MAX_PATH);
+ break;
+ case 4: /* attributes */
+ _ILGetFileAttributes(pidl, psd->str.cStr, MAX_PATH);
+ break;
+ }
+ }
+
+ return hr;
+}
+
+HRESULT WINAPI CFSFolder::MapColumnToSCID (UINT column,
+ SHCOLUMNID * pscid)
+{
+ FIXME ("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+/****************************************************************************
+ * ISFHelper for IShellFolder implementation
+ */
+
+/****************************************************************************
+ * CFSFolder::GetUniqueName
+ *
+ * creates a unique folder name
+ */
+
+HRESULT WINAPI CFSFolder::GetUniqueName(LPWSTR pwszName, UINT uLen)
+{
+ CComPtr<IEnumIDList> penum;
+ HRESULT hr;
+ WCHAR wszText[MAX_PATH];
+ WCHAR wszNewFolder[25];
+ const WCHAR wszFormat[] = L"%s %d";
+
+ LoadStringW(shell32_hInstance, IDS_NEWFOLDER, wszNewFolder, _countof(wszNewFolder));
+
+ TRACE ("(%p)(%p %u)\n", this, pwszName, uLen);
+
+ if (uLen < _countof(wszNewFolder) + 3)
+ return E_POINTER;
+
+ lstrcpynW (pwszName, wszNewFolder, uLen);
+
+ hr = EnumObjects(0, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &penum);
+ if (penum)
+ {
+ LPITEMIDLIST pidl;
+ DWORD dwFetched;
+ int i = 1;
+
+next:
+ penum->Reset ();
+ while (S_OK == penum->Next(1, &pidl, &dwFetched) && dwFetched)
+ {
+ _ILSimpleGetTextW(pidl, wszText, MAX_PATH);
+ if (0 == lstrcmpiW(wszText, pwszName))
+ {
+ _snwprintf(pwszName, uLen, wszFormat, wszNewFolder, i++);
+ if (i > 99)
+ {
+ hr = E_FAIL;
+ break;
+ }
+ goto next;
+ }
+ }
+ }
+ return hr;
+}
+
+/****************************************************************************
+ * CFSFolder::AddFolder
+ *
+ * adds a new folder.
+ */
+
+HRESULT WINAPI CFSFolder::AddFolder(HWND hwnd, LPCWSTR pwszName,
+ LPITEMIDLIST * ppidlOut)
+{
+ WCHAR wszNewDir[MAX_PATH];
+ DWORD bRes;
+ HRESULT hres = E_FAIL;
+
+ TRACE ("(%p)(%s %p)\n", this, debugstr_w(pwszName), ppidlOut);
+
+ wszNewDir[0] = 0;
+ if (sPathTarget)
+ lstrcpynW(wszNewDir, sPathTarget, MAX_PATH);
+ PathAppendW(wszNewDir, pwszName);
+
+ bRes = CreateDirectoryW(wszNewDir, NULL);
+ if (bRes)
+ {
+ SHChangeNotify(SHCNE_MKDIR, SHCNF_PATHW, wszNewDir, NULL);
+
+ hres = S_OK;
+
+ if (ppidlOut)
+ hres = _ILCreateFromPathW(wszNewDir, ppidlOut);
+ }
+ else
+ {
+ WCHAR wszText[128 + MAX_PATH];
+ WCHAR wszTempText[128];
+ WCHAR wszCaption[256];
+
+ /* Cannot Create folder because of permissions */
+ LoadStringW(shell32_hInstance, IDS_CREATEFOLDER_DENIED, wszTempText,
+ _countof(wszTempText));
+ LoadStringW(shell32_hInstance, IDS_CREATEFOLDER_CAPTION, wszCaption,
+ _countof(wszCaption));
+ swprintf(wszText, wszTempText, wszNewDir);
+ MessageBoxW(hwnd, wszText, wszCaption, MB_OK | MB_ICONEXCLAMATION);
+ }
+
+ return hres;
+}
+
+/****************************************************************************
+ * BuildPathsList
+ *
+ * Builds a list of paths like the one used in SHFileOperation from a table of
+ * PIDLs relative to the given base folder
+ */
+WCHAR *
+BuildPathsList(LPCWSTR wszBasePath, int cidl, LPCITEMIDLIST *pidls)
+{
+ WCHAR *pwszPathsList;
+ WCHAR *pwszListPos;
+ int iPathLen, i;
+
+ iPathLen = wcslen(wszBasePath);
+ pwszPathsList = (WCHAR *)HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR) * cidl + 1);
+ pwszListPos = pwszPathsList;
+
+ for (i = 0; i < cidl; i++)
+ {
+ if (!_ILIsFolder(pidls[i]) && !_ILIsValue(pidls[i]))
+ continue;
+
+ wcscpy(pwszListPos, wszBasePath);
+ pwszListPos += iPathLen;
+ /* FIXME: abort if path too long */
+ _ILSimpleGetTextW(pidls[i], pwszListPos, MAX_PATH - iPathLen);
+ pwszListPos += wcslen(pwszListPos) + 1;
+ }
+ *pwszListPos = 0;
+ return pwszPathsList;
+}
+
+/****************************************************************************
+ * CFSFolder::DeleteItems
+ *
+ * deletes items in folder
+ */
+HRESULT WINAPI CFSFolder::DeleteItems(UINT cidl, LPCITEMIDLIST *apidl)
+{
+ UINT i;
+ SHFILEOPSTRUCTW op;
+ WCHAR wszPath[MAX_PATH];
+ WCHAR *wszPathsList;
+ HRESULT ret;
+ WCHAR *wszCurrentPath;
+
+ TRACE ("(%p)(%u %p)\n", this, cidl, apidl);
+ if (cidl == 0) return S_OK;
+
+ if (sPathTarget)
+ lstrcpynW(wszPath, sPathTarget, MAX_PATH);
+ else
+ wszPath[0] = '\0';
+ PathAddBackslashW(wszPath);
+ wszPathsList = BuildPathsList(wszPath, cidl, apidl);
+
+ ZeroMemory(&op, sizeof(op));
+ op.hwnd = GetActiveWindow();
+ op.wFunc = FO_DELETE;
+ op.pFrom = wszPathsList;
+ op.fFlags = FOF_ALLOWUNDO;
+ if (SHFileOperationW(&op))
+ {
+ WARN("SHFileOperation failed\n");
+ ret = E_FAIL;
+ }
+ else
+ ret = S_OK;
+
+ /* we currently need to manually send the notifies */
+ wszCurrentPath = wszPathsList;
+ for (i = 0; i < cidl; i++)
+ {
+ LONG wEventId;
+
+ if (_ILIsFolder(apidl[i]))
+ wEventId = SHCNE_RMDIR;
+ else if (_ILIsValue(apidl[i]))
+ wEventId = SHCNE_DELETE;
+ else
+ continue;
+
+ /* check if file exists */
+ if (GetFileAttributesW(wszCurrentPath) == INVALID_FILE_ATTRIBUTES)
+ {
+ LPITEMIDLIST pidl = ILCombine(pidlRoot, apidl[i]);
+ SHChangeNotify(wEventId, SHCNF_IDLIST, pidl, NULL);
+ SHFree(pidl);
+ }
+
+ wszCurrentPath += wcslen(wszCurrentPath) + 1;
+ }
+ HeapFree(GetProcessHeap(), 0, wszPathsList);
+ return ret;
+}
+
+/****************************************************************************
+ * CFSFolder::CopyItems
+ *
+ * copies items to this folder
+ */
+HRESULT WINAPI CFSFolder::CopyItems(IShellFolder * pSFFrom, UINT cidl,
+ LPCITEMIDLIST * apidl, bool bCopy)
+{
+ CComPtr<IPersistFolder2> ppf2 = NULL;
+ WCHAR szSrcPath[MAX_PATH];
+ WCHAR szTargetPath[MAX_PATH];
+ SHFILEOPSTRUCTW op;
+ LPITEMIDLIST pidl;
+ LPWSTR pszSrc, pszTarget, pszSrcList, pszTargetList, pszFileName;
+ int res, length;
+ HRESULT hr;
+ STRRET strRet;
+
+ TRACE ("(%p)->(%p,%u,%p)\n", this, pSFFrom, cidl, apidl);
+
+ hr = pSFFrom->QueryInterface (IID_PPV_ARG(IPersistFolder2, &ppf2));
+ if (SUCCEEDED(hr))
+ {
+ hr = ppf2->GetCurFolder(&pidl);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ hr = pSFFrom->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strRet);
+ if (FAILED(hr))
+ {
+ SHFree(pidl);
+ return hr;
+ }
+
+ hr = StrRetToBufW(&strRet, pidl, szSrcPath, MAX_PATH);
+ if (FAILED(hr))
+ {
+ SHFree(pidl);
+ return hr;
+ }
+ SHFree(pidl);
+
+ pszSrc = PathAddBackslashW(szSrcPath);
+
+ wcscpy(szTargetPath, sPathTarget);
+ pszTarget = PathAddBackslashW(szTargetPath);
+
+ pszSrcList = BuildPathsList(szSrcPath, cidl, apidl);
+ pszTargetList = BuildPathsList(szTargetPath, cidl, apidl);
+
+ if (!pszSrcList || !pszTargetList)
+ {
+ if (pszSrcList)
+ HeapFree(GetProcessHeap(), 0, pszSrcList);
+
+ if (pszTargetList)
+ HeapFree(GetProcessHeap(), 0, pszTargetList);
+
+ SHFree(pidl);
+ return E_OUTOFMEMORY;
+ }
+
+ ZeroMemory(&op, sizeof(op));
+ if (!pszSrcList[0])
+ {
+ /* remove trailing backslash */
+ pszSrc--;
+ pszSrc[0] = L'\0';
+ op.pFrom = szSrcPath;
+ }
+ else
+ {
+ op.pFrom = pszSrcList;
+ }
+
+ if (!pszTargetList[0])
+ {
+ /* remove trailing backslash */
+ if (pszTarget - szTargetPath > 3)
+ {
+ pszTarget--;
+ pszTarget[0] = L'\0';
+ }
+ else
+ {
+ pszTarget[1] = L'\0';
+ }
+
+ op.pTo = szTargetPath;
+ op.fFlags = 0;
+ }
+ else
+ {
+ op.pTo = pszTargetList;
+ op.fFlags = FOF_MULTIDESTFILES;
+ }
+ op.hwnd = GetActiveWindow();
+ op.wFunc = bCopy ? FO_COPY : FO_MOVE;
+ op.fFlags |= FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR;
+
+ res = SHFileOperationW(&op);
+
+ if (res == DE_SAMEFILE)
+ {
+ length = wcslen(szTargetPath);
+
+ pszFileName = wcsrchr(pszSrcList, '\\');
+ pszFileName++;
+
+ if (LoadStringW(shell32_hInstance, IDS_COPY_OF, pszTarget, MAX_PATH - length))
+ {
+ wcscat(szTargetPath, L" ");
+ }
+
+ wcscat(szTargetPath, pszFileName);
+ op.pTo = szTargetPath;
+
+ res = SHFileOperationW(&op);
+ }
+
+ HeapFree(GetProcessHeap(), 0, pszSrcList);
+ HeapFree(GetProcessHeap(), 0, pszTargetList);
+
+ if (res)
+ return E_FAIL;
+ else
+ return S_OK;
+ }
+ return E_FAIL;
+}
+
+/************************************************************************
+ * CFSFolder::GetClassID
+ */
+HRESULT WINAPI CFSFolder::GetClassID(CLSID * lpClassId)
+{
+ TRACE ("(%p)\n", this);
+
+ if (!lpClassId)
+ return E_POINTER;
+
+ *lpClassId = *pclsid;
+
+ return S_OK;
+}
+
+/************************************************************************
+ * CFSFolder::Initialize
+ *
+ * NOTES
+ * sPathTarget is not set. Don't know how to handle in a non rooted environment.
+ */
+HRESULT WINAPI CFSFolder::Initialize(LPCITEMIDLIST pidl)
+{
+ WCHAR wszTemp[MAX_PATH];
+
+ TRACE ("(%p)->(%p)\n", this, pidl);
+
+ SHFree (pidlRoot); /* free the old pidl */
+ pidlRoot = ILClone (pidl); /* set my pidl */
+
+ SHFree (sPathTarget);
+ sPathTarget = NULL;
+
+ /* set my path */
+ if (SHGetPathFromIDListW (pidl, wszTemp))
+ {
+ int len = wcslen(wszTemp);
+ sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR));
+ if (!sPathTarget)
+ return E_OUTOFMEMORY;
+ memcpy(sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
+ }
+
+ TRACE ("--(%p)->(%s)\n", this, debugstr_w(sPathTarget));
+ return S_OK;
+}
+
+/**************************************************************************
+ * CFSFolder::GetCurFolder
+ */
+HRESULT WINAPI CFSFolder::GetCurFolder(LPITEMIDLIST * pidl)
+{
+ TRACE ("(%p)->(%p)\n", this, pidl);
+
+ if (!pidl)
+ return E_POINTER;
+
+ *pidl = ILClone(pidlRoot);
+ return S_OK;
+}
+
+/**************************************************************************
+ * CFSFolder::InitializeEx
+ *
+ * FIXME: error handling
+ */
+HRESULT WINAPI CFSFolder::InitializeEx(IBindCtx * pbc, LPCITEMIDLIST pidlRootx,
+ const PERSIST_FOLDER_TARGET_INFO * ppfti)
+{
+ WCHAR wszTemp[MAX_PATH];
+
+ TRACE("(%p)->(%p,%p,%p)\n", this, pbc, pidlRootx, ppfti);
+ if (ppfti)
+ TRACE("--%p %s %s 0x%08x 0x%08x\n",
+ ppfti->pidlTargetFolder, debugstr_w (ppfti->szTargetParsingName),
+ debugstr_w (ppfti->szNetworkProvider), ppfti->dwAttributes,
+ ppfti->csidl);
+
+ pdump (pidlRootx);
+ if (ppfti && ppfti->pidlTargetFolder)
+ pdump(ppfti->pidlTargetFolder);
+
+ if (pidlRoot)
+ __SHFreeAndNil(&pidlRoot); /* free the old */
+ if (sPathTarget)
+ __SHFreeAndNil(&sPathTarget);
+
+ /*
+ * Root path and pidl
+ */
+ pidlRoot = ILClone(pidlRootx);
+
+ /*
+ * the target folder is spezified in csidl OR pidlTargetFolder OR
+ * szTargetParsingName
+ */
+ if (ppfti)
+ {
+ if (ppfti->csidl != -1)
+ {
+ if (SHGetSpecialFolderPathW(0, wszTemp, ppfti->csidl,
+ ppfti->csidl & CSIDL_FLAG_CREATE)) {
+ int len = wcslen(wszTemp);
+ sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR));
+ if (!sPathTarget)
+ return E_OUTOFMEMORY;
+ memcpy(sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
+ }
+ }
+ else if (ppfti->szTargetParsingName[0])
+ {
+ int len = wcslen(ppfti->szTargetParsingName);
+ sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR));
+ if (!sPathTarget)
+ return E_OUTOFMEMORY;
+ memcpy(sPathTarget, ppfti->szTargetParsingName,
+ (len + 1) * sizeof(WCHAR));
+ }
+ else if (ppfti->pidlTargetFolder)
+ {
+ if (SHGetPathFromIDListW(ppfti->pidlTargetFolder, wszTemp))
+ {
+ int len = wcslen(wszTemp);
+ sPathTarget = (WCHAR *)SHAlloc((len + 1) * sizeof(WCHAR));
+ if (!sPathTarget)
+ return E_OUTOFMEMORY;
+ memcpy(sPathTarget, wszTemp, (len + 1) * sizeof(WCHAR));
+ }
+ }
+ }
+
+ TRACE("--(%p)->(target=%s)\n", this, debugstr_w(sPathTarget));
+ pdump(pidlRoot);
+ return (sPathTarget) ? S_OK : E_FAIL;
+}
+
+HRESULT WINAPI CFSFolder::GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO * ppfti)
+{
+ FIXME("(%p)->(%p)\n", this, ppfti);
+ ZeroMemory(ppfti, sizeof (*ppfti));
+ return E_NOTIMPL;
+}
+
+BOOL
+CFSFolder::GetUniqueFileName(LPWSTR pwszBasePath, LPCWSTR pwszExt, LPWSTR pwszTarget, BOOL bShortcut)
+{
+ WCHAR wszLink[40];
+
+ if (!bShortcut)
+ {
+ if (!LoadStringW(shell32_hInstance, IDS_LNK_FILE, wszLink, _countof(wszLink)))
+ wszLink[0] = L'\0';
+ }
+
+ if (!bShortcut)
+ swprintf(pwszTarget, L"%s%s%s", wszLink, pwszBasePath, pwszExt);
+ else
+ swprintf(pwszTarget, L"%s%s", pwszBasePath, pwszExt);
+
+ for (UINT i = 2; PathFileExistsW(pwszTarget); ++i)
+ {
+ if (!bShortcut)
+ swprintf(pwszTarget, L"%s%s (%u)%s", wszLink, pwszBasePath, i, pwszExt);
+ else
+ swprintf(pwszTarget, L"%s (%u)%s", pwszBasePath, i, pwszExt);
+ }
+
+ return TRUE;
+}
+
+/****************************************************************************
+ * IDropTarget implementation
+ */
+BOOL CFSFolder::QueryDrop(DWORD dwKeyState, LPDWORD pdwEffect)
+{
+ /* TODO Windows does different drop effects if dragging across drives.
+ i.e., it will copy instead of move if the directories are on different disks. */
+
+ DWORD dwEffect = DROPEFFECT_MOVE;
+
+ *pdwEffect = DROPEFFECT_NONE;
+
+ if (fAcceptFmt) { /* Does our interpretation of the keystate ... */
+ *pdwEffect = KeyStateToDropEffect (dwKeyState);
+
+ if (*pdwEffect == DROPEFFECT_NONE)
+ *pdwEffect = dwEffect;
+
+ /* ... matches the desired effect ? */
+ if (dwEffect & *pdwEffect) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+HRESULT WINAPI CFSFolder::DragEnter(IDataObject *pDataObject,
+ DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
+{
+ TRACE("(%p)->(DataObject=%p)\n", this, pDataObject);
+ FORMATETC fmt;
+ FORMATETC fmt2;
+ fAcceptFmt = FALSE;
+
+ InitFormatEtc (fmt, cfShellIDList, TYMED_HGLOBAL);
+ InitFormatEtc (fmt2, CF_HDROP, TYMED_HGLOBAL);
+
+ if (SUCCEEDED(pDataObject->QueryGetData(&fmt)))
+ fAcceptFmt = TRUE;
+ else if (SUCCEEDED(pDataObject->QueryGetData(&fmt2)))
+ fAcceptFmt = TRUE;
+
+ QueryDrop(dwKeyState, pdwEffect);
+ return S_OK;
+}
+
+HRESULT WINAPI CFSFolder::DragOver(DWORD dwKeyState, POINTL pt,
+ DWORD *pdwEffect)
+{
+ TRACE("(%p)\n", this);
+
+ if (!pdwEffect)
+ return E_INVALIDARG;
+
+ QueryDrop(dwKeyState, pdwEffect);
+
+ return S_OK;
+}
+
+HRESULT WINAPI CFSFolder::DragLeave()
+{
+ TRACE("(%p)\n", this);
+
+ fAcceptFmt = FALSE;
+
+ return S_OK;
+}
+
+HRESULT WINAPI CFSFolder::Drop(IDataObject *pDataObject,
+ DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
+{
+ TRACE("(%p) object dropped, effect %u\n", this, *pdwEffect);
+
+ BOOL fIsOpAsync = FALSE;
+ CComPtr<IAsyncOperation> pAsyncOperation;
+
+ if (SUCCEEDED(pDataObject->QueryInterface(IID_PPV_ARG(IAsyncOperation, &pAsyncOperation))))
+ {
+ if (SUCCEEDED(pAsyncOperation->GetAsyncMode(&fIsOpAsync)) && fIsOpAsync)
+ {
+ _DoDropData *data = static_cast<_DoDropData*>(HeapAlloc(GetProcessHeap(), 0, sizeof(_DoDropData)));
+ data->This = this;
+ // Need to maintain this class in case the window is closed or the class exists temporarily (when dropping onto a folder).
+ pDataObject->AddRef();
+ pAsyncOperation->StartOperation(NULL);
+ CoMarshalInterThreadInterfaceInStream(IID_IDataObject, pDataObject, &data->pStream);
+ this->AddRef();
+ data->dwKeyState = dwKeyState;
+ data->pt = pt;
+ // Need to dereference as pdweffect gets freed.
+ data->pdwEffect = *pdwEffect;
+ SHCreateThread(CFSFolder::_DoDropThreadProc, data, NULL, NULL);
+ return S_OK;
+ }
+ }
+ return this->_DoDrop(pDataObject, dwKeyState, pt, pdwEffect);
+}
+
+HRESULT WINAPI CFSFolder::_DoDrop(IDataObject *pDataObject,
+ DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
+{
+ TRACE("(%p) performing drop, effect %u\n", this, *pdwEffect);
+ FORMATETC fmt;
+ FORMATETC fmt2;
+ STGMEDIUM medium;
+
+ InitFormatEtc (fmt, cfShellIDList, TYMED_HGLOBAL);
+ InitFormatEtc (fmt2, CF_HDROP, TYMED_HGLOBAL);
+
+ HRESULT hr;
+ bool bCopy = TRUE;
+ bool bLinking = FALSE;
+
+ /* Figure out what drop operation we're doing */
+ if (pdwEffect)
+ {
+ TRACE("Current drop effect flag %i\n", *pdwEffect);
+ if ((*pdwEffect & DROPEFFECT_MOVE) == DROPEFFECT_MOVE)
+ bCopy = FALSE;
+ if ((*pdwEffect & DROPEFFECT_LINK) == DROPEFFECT_LINK)
+ bLinking = TRUE;
+ }
+
+ if (SUCCEEDED(pDataObject->QueryGetData(&fmt)))
+ {
+ hr = pDataObject->GetData(&fmt, &medium);
+ TRACE("CFSTR_SHELLIDLIST.\n");
+
+ /* lock the handle */
+ LPIDA lpcida = (LPIDA)GlobalLock(medium.hGlobal);
+ if (!lpcida)
+ {
+ ReleaseStgMedium(&medium);
+ return E_FAIL;
+ }
+
+ /* convert the data into pidl */
+ LPITEMIDLIST pidl;
+ LPITEMIDLIST *apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
+ if (!apidl)
+ {
+ ReleaseStgMedium(&medium);
+ return E_FAIL;
+ }
+
+ CComPtr<IShellFolder> psfDesktop;
+ CComPtr<IShellFolder> psfFrom = NULL;
+ CComPtr<IShellFolder> psfTarget = NULL;
+
+ hr = this->QueryInterface(IID_PPV_ARG(IShellFolder, &psfTarget));
+ if (FAILED(hr))
+ {
+ ERR("psfTarget setting failed\n");
+ SHFree(pidl);
+ _ILFreeaPidl(apidl, lpcida->cidl);
+ ReleaseStgMedium(&medium);
+ return E_FAIL;
+ }
+
+ /* Grab the desktop shell folder */
+ hr = SHGetDesktopFolder(&psfDesktop);
+ if (FAILED(hr))
+ {
+ ERR("SHGetDesktopFolder failed\n");
+ SHFree(pidl);
+ _ILFreeaPidl(apidl, lpcida->cidl);
+ ReleaseStgMedium(&medium);
+ return E_FAIL;
+ }
+
+ /* Find source folder, this is where the clipboard data was copied from */
+ if (_ILIsDesktop(pidl))
+ {
+ /* use desktop shell folder */
+ psfFrom = psfDesktop;
+ }
+ else
+ {
+ hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfFrom));
+ if (FAILED(hr))
+ {
+ ERR("no IShellFolder\n");
+ SHFree(pidl);
+ _ILFreeaPidl(apidl, lpcida->cidl);
+ ReleaseStgMedium(&medium);
+ return E_FAIL;
+ }
+ }
+
+ if (bLinking)
+ {
+ CComPtr<IPersistFolder2> ppf2 = NULL;
+ STRRET strFile;
+ WCHAR wszTargetPath[MAX_PATH];
+ LPITEMIDLIST targetpidl;
+ WCHAR wszPath[MAX_PATH];
+ WCHAR wszTarget[MAX_PATH];
+
+ hr = this->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
+ if (SUCCEEDED(hr))
+ {
+ hr = ppf2->GetCurFolder(&targetpidl);
+ if (SUCCEEDED(hr))
+ {
+ hr = psfDesktop->GetDisplayNameOf(targetpidl, SHGDN_FORPARSING, &strFile);
+ ILFree(targetpidl);
+ if (SUCCEEDED(hr))
+ {
+ hr = StrRetToBufW(&strFile, NULL, wszTargetPath, _countof(wszTargetPath));
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ ERR("Error obtaining target path");
+ }
+
+ TRACE("target path = %s", debugstr_w(wszTargetPath));
+
+ /* We need to create a link for each pidl in the copied items, so step through the pidls from the clipboard */
+ for (UINT i = 0; i < lpcida->cidl; i++)
+ {
+ //Find out which file we're copying
+ STRRET strFile;
+ hr = psfFrom->GetDisplayNameOf(apidl[i], SHGDN_FORPARSING, &strFile);
+ if (FAILED(hr))
+ {
+ ERR("Error source obtaining path");
+ break;
+ }
+
+ hr = StrRetToBufW(&strFile, apidl[i], wszPath, _countof(wszPath));
+ if (FAILED(hr))
+ {
+ ERR("Error putting source path into buffer");
+ break;
+ }
+ TRACE("source path = %s", debugstr_w(wszPath));
+
+ // Creating a buffer to hold the combined path
+ WCHAR buffer_1[MAX_PATH] = L"";
+ WCHAR *lpStr1;
+ lpStr1 = buffer_1;
+
+ LPWSTR pwszFileName = PathFindFileNameW(wszPath);
+ LPWSTR pwszExt = PathFindExtensionW(wszPath);
+ LPWSTR placementPath = PathCombineW(lpStr1, wszTargetPath, pwszFileName);
+ CComPtr<IPersistFile> ppf;
+
+ //Check to see if it's already a link.
+ if (!wcsicmp(pwszExt, L".lnk"))
+ {
+ //It's a link so, we create a new one which copies the old.
+ if(!GetUniqueFileName(placementPath, pwszExt, wszTarget, TRUE))
+ {
+ ERR("Error getting unique file name");
+ hr = E_FAIL;
+ break;
+ }
+ hr = IShellLink_ConstructFromFile(NULL, IID_IPersistFile, ILCombine(pidl, apidl[i]), (LPVOID*)&ppf);
+ if (FAILED(hr)) {
+ ERR("Error constructing link from file");
+ break;
+ }
+
+ hr = ppf->Save(wszTarget, FALSE);
+ if (FAILED(hr))
+ break;
+ SHChangeNotify(SHCNE_CREATE, SHCNF_PATHW, wszTarget, NULL);
+ }
+ else
+ {
+ //It's not a link, so build a new link using the creator class and fill it in.
+ //Create a file name for the link
+ if (!GetUniqueFileName(placementPath, L".lnk", wszTarget, TRUE))
+ {
+ ERR("Error creating unique file name");
+ hr = E_FAIL;
+ break;
+ }
+
+ CComPtr<IShellLinkW> pLink;
+ hr = CShellLink::_CreatorClass::CreateInstance(NULL, IID_PPV_ARG(IShellLinkW, &pLink));
+ if (FAILED(hr)) {
+ ERR("Error instantiating IShellLinkW");
+ break;
+ }
+
+ WCHAR szDirPath[MAX_PATH], *pwszFile;
+ GetFullPathName(wszPath, MAX_PATH, szDirPath, &pwszFile);
+ if (pwszFile) pwszFile[0] = 0;
+
+ hr = pLink->SetPath(wszPath);
+ if(FAILED(hr))
+ break;
+
+ hr = pLink->SetWorkingDirectory(szDirPath);
+ if(FAILED(hr))
+ break;
+
+ hr = pLink->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
+ if(FAILED(hr))
+ break;
+
+ hr = ppf->Save(wszTarget, TRUE);
+ if (FAILED(hr))
+ break;
+ SHChangeNotify(SHCNE_CREATE, SHCNF_PATHW, wszTarget, NULL);
+ }
+ }
+ }
+ else
+ {
+ hr = this->CopyItems(psfFrom, lpcida->cidl, (LPCITEMIDLIST*)apidl, bCopy);
+ }
+
+ SHFree(pidl);
+ _ILFreeaPidl(apidl, lpcida->cidl);
+ ReleaseStgMedium(&medium);
+ }
+ else if (SUCCEEDED(pDataObject->QueryGetData(&fmt2)))
+ {
+ FORMATETC fmt2;
+ InitFormatEtc (fmt2, CF_HDROP, TYMED_HGLOBAL);
+ if (SUCCEEDED(pDataObject->GetData(&fmt2, &medium)) /* && SUCCEEDED(pDataObject->GetData(&fmt2, &medium))*/)
+ {
+ CComPtr<IPersistFolder2> ppf2 = NULL;
+ STRRET strFile;
+ WCHAR wszTargetPath[MAX_PATH + 1];
+ LPWSTR pszSrcList;
+ LPITEMIDLIST targetpidl;
+ CComPtr<IShellFolder> psfDesktop = NULL;
+ hr = SHGetDesktopFolder(&psfDesktop);
+ if (FAILED(hr))
+ {
+ ERR("SHGetDesktopFolder failed\n");
+ return E_FAIL;
+ }
+
+ hr = this->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
+ if (SUCCEEDED(hr))
+ {
+ hr = ppf2->GetCurFolder(&targetpidl);
+ if (SUCCEEDED(hr))
+ {
+ hr = psfDesktop->GetDisplayNameOf(targetpidl, SHGDN_FORPARSING, &strFile);
+ ILFree(targetpidl);
+ if (SUCCEEDED(hr))
+ {
+ hr = StrRetToBufW(&strFile, NULL, wszTargetPath, _countof(wszTargetPath));
+ //Double NULL terminate.
+ wszTargetPath[wcslen(wszTargetPath) + 1] = '\0';
+ }
+ }
+ }
+ if (FAILED(hr))
+ {
+ ERR("Error obtaining target path");
+ return E_FAIL;
+ }
+
+ LPDROPFILES lpdf = (LPDROPFILES) GlobalLock(medium.hGlobal);
+ if (!lpdf)
+ {
+ ERR("Error locking global\n");
+ return E_FAIL;
+ }
+ pszSrcList = (LPWSTR) (((byte*) lpdf) + lpdf->pFiles);
+ TRACE("Source file (just the first) = %s\n", debugstr_w(pszSrcList));
+ TRACE("Target path = %s\n", debugstr_w(wszTargetPath));
+
+ SHFILEOPSTRUCTW op;
+ ZeroMemory(&op, sizeof(op));
+ op.pFrom = pszSrcList;
+ op.pTo = wszTargetPath;
+ op.hwnd = GetActiveWindow();
+ op.wFunc = bCopy ? FO_COPY : FO_MOVE;
+ op.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMMKDIR;
+ hr = SHFileOperationW(&op);
+ return hr;
+ }
+ ERR("Error calling GetData\n");
+ hr = E_FAIL;
+ }
+ else
+ {
+ ERR("No viable drop format.\n");
+ hr = E_FAIL;
+ }
+ return hr;
+}
+
+DWORD WINAPI CFSFolder::_DoDropThreadProc(LPVOID lpParameter) {
+ CoInitialize(NULL);
+ _DoDropData *data = static_cast<_DoDropData*>(lpParameter);
+ CComPtr<IDataObject> pDataObject;
+ HRESULT hr = CoGetInterfaceAndReleaseStream (data->pStream, IID_PPV_ARG(IDataObject, &pDataObject));
+
+ if (SUCCEEDED(hr))
+ {
+ CComPtr<IAsyncOperation> pAsyncOperation;
+ hr = data->This->_DoDrop(pDataObject, data->dwKeyState, data->pt, &data->pdwEffect);
+ if (SUCCEEDED(pDataObject->QueryInterface(IID_PPV_ARG(IAsyncOperation, &pAsyncOperation))))
+ {
+ pAsyncOperation->EndOperation(hr, NULL, data->pdwEffect);
+ }
+ }
+ //Release the CFSFolder and data object holds in the copying thread.
+ data->This->Release();
+ //Release the parameter from the heap.
+ HeapFree(GetProcessHeap(), 0, data);
++ CoUninitialize();
+ return 0;
+}
+
+HRESULT WINAPI CFSFolder::_GetDropTarget(LPCITEMIDLIST pidl, LPVOID *ppvOut) {
+ HKEY hKey;
+ HRESULT hr;
+
+ TRACE("CFSFolder::_GetDropTarget entered\n");
+
+ if (_ILGetGUIDPointer (pidl) || _ILIsFolder (pidl))
+ return this->BindToObject(pidl, NULL, IID_IDropTarget, ppvOut);
+
+ STRRET strFile;
+ hr = this->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strFile);
+ if (hr == S_OK)
+ {
+ WCHAR wszPath[MAX_PATH];
+ hr = StrRetToBufW(&strFile, pidl, wszPath, _countof(wszPath));
+
+ if (hr == S_OK)
+ {
+ LPCWSTR pwszExt = PathFindExtensionW(wszPath);
+ if (pwszExt[0])
+ {
+ /* enumerate dynamic/static for a given file class */
+ if (RegOpenKeyExW(HKEY_CLASSES_ROOT, pwszExt, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
+ {
+ /* load dynamic extensions from file extension key, for example .jpg */
+ _LoadDynamicDropTargetHandlerForKey(hKey, wszPath, ppvOut);
+ RegCloseKey(hKey);
+ }
+
+ WCHAR wszTemp[40];
+ DWORD dwSize = sizeof(wszTemp);
+ if (RegGetValueW(HKEY_CLASSES_ROOT, pwszExt, NULL, RRF_RT_REG_SZ, NULL, wszTemp, &dwSize) == ERROR_SUCCESS)
+ {
+ if (RegOpenKeyExW(HKEY_CLASSES_ROOT, wszTemp, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
+ {
+ /* load dynamic extensions from progid key, for example jpegfile */
+ _LoadDynamicDropTargetHandlerForKey(hKey, wszPath, ppvOut);
+ RegCloseKey(hKey);
+ }
+ }
+ }
+ }
+ }
+ else
+ ERR("GetDisplayNameOf failed: %x\n", hr);
+
+ return hr;
+}
+
+HRESULT WINAPI CFSFolder::_LoadDynamicDropTargetHandlerForKey(HKEY hRootKey, LPCWSTR pwcsname, LPVOID *ppvOut)
+{
+ TRACE("CFSFolder::_LoadDynamicDropTargetHandlerForKey entered\n");
+
+ WCHAR wszName[MAX_PATH], *pwszClsid;
+ DWORD dwSize = sizeof(wszName);
+ HRESULT hr;
+
+ if (RegGetValueW(hRootKey, L"shellex\\DropHandler", NULL, RRF_RT_REG_SZ, NULL, wszName, &dwSize) == ERROR_SUCCESS)
+ {
+ CLSID clsid;
+ hr = CLSIDFromString(wszName, &clsid);
+ if (hr == S_OK)
+ pwszClsid = wszName;
+
+ if (m_bGroupPolicyActive)
+ {
+ if (RegGetValueW(HKEY_LOCAL_MACHINE,
+ L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
+ pwszClsid,
+ RRF_RT_REG_SZ,
+ NULL,
+ NULL,
+ NULL) == ERROR_SUCCESS)
+ {
+ hr = _LoadDynamicDropTargetHandler(&clsid, pwcsname, ppvOut);
+ }
+ }
+ else
+ {
+ hr = _LoadDynamicDropTargetHandler(&clsid, pwcsname, ppvOut);
+ }
+ }
+ else
+ return E_FAIL;
+ return hr;
+}
+
+HRESULT WINAPI CFSFolder::_LoadDynamicDropTargetHandler(const CLSID *pclsid, LPCWSTR pwcsname, LPVOID *ppvOut)
+{
+ TRACE("CFSFolder::_LoadDynamicDropTargetHandler entered\n");
+ HRESULT hr;
+
+ CComPtr<IPersistFile> pp;
+ hr = SHCoCreateInstance(NULL, pclsid, NULL, IID_PPV_ARG(IPersistFile, &pp));
+ if (hr != S_OK)
+ {
+ ERR("SHCoCreateInstance failed %x\n", GetLastError());
+ }
+ pp->Load(pwcsname, 0);
+
+ hr = pp->QueryInterface(IID_PPV_ARG(IDropTarget, (IDropTarget**) ppvOut));
+ if (hr != S_OK)
+ {
+ ERR("Failed to query for interface IID_IShellExtInit hr %x pclsid %s\n", hr, wine_dbgstr_guid(pclsid));
+ return hr;
+ }
+ return hr;
+}
--- /dev/null
- DWORD * pchEaten, LPITEMIDLIST * ppidl, DWORD * pdwAttributes)
+/*
+ * Virtual Workplace folder
+ *
+ * Copyright 1997 Marcus Meissner
+ * Copyright 1998, 1999, 2002 Juergen Schmied
+ * Copyright 2009 Andrew Hill
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <precomp.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL (shell);
+
+/*
+CDrivesFolder should create a CRegFolder to represent the virtual items that exist only in
+the registry. The CRegFolder is aggregated by the CDrivesFolder.
+The CDrivesFolderEnum class should enumerate only drives on the system. Since the CRegFolder
+implementation of IShellFolder::EnumObjects enumerates the virtual items, the
+CDrivesFolderEnum is only responsible for returning the physical items.
+
+2. At least on my XP system, the drive pidls returned are of type PT_DRIVE1, not PT_DRIVE
+3. The parsing name returned for my computer is incorrect. It should be "My Computer"
+*/
+
+/***********************************************************************
+* IShellFolder implementation
+*/
+
+class CDrivesFolderEnum :
+ public IEnumIDListImpl
+{
+ public:
+ CDrivesFolderEnum();
+ ~CDrivesFolderEnum();
+ HRESULT WINAPI Initialize(HWND hwndOwner, DWORD dwFlags);
+ BOOL CreateMyCompEnumList(DWORD dwFlags);
+
+ BEGIN_COM_MAP(CDrivesFolderEnum)
+ COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
+ END_COM_MAP()
+};
+
+/***********************************************************************
+* IShellFolder [MyComputer] implementation
+*/
+
+static const shvheader MyComputerSFHeader[] = {
+ {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
+ {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
+ {IDS_SHV_COLUMN6, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
+ {IDS_SHV_COLUMN7, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
+};
+
+#define MYCOMPUTERSHELLVIEWCOLUMNS 4
+
+CDrivesFolderEnum::CDrivesFolderEnum()
+{
+}
+
+CDrivesFolderEnum::~CDrivesFolderEnum()
+{
+}
+
+HRESULT WINAPI CDrivesFolderEnum::Initialize(HWND hwndOwner, DWORD dwFlags)
+{
+ if (CreateMyCompEnumList(dwFlags) == FALSE)
+ return E_FAIL;
+
+ return S_OK;
+}
+
+/**************************************************************************
+ * CDrivesFolderEnum::CreateMyCompEnumList()
+ */
+
+BOOL CDrivesFolderEnum::CreateMyCompEnumList(DWORD dwFlags)
+{
+ BOOL bRet = TRUE;
+ static const WCHAR MyComputer_NameSpaceW[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\Namespace";
+
+ TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags);
+
+ /* enumerate the folders */
+ if (dwFlags & SHCONTF_FOLDERS)
+ {
+ WCHAR wszDriveName[] = {'A', ':', '\\', '\0'};
+ DWORD dwDrivemap = GetLogicalDrives();
+ HKEY hKey;
+ UINT i;
+
+ while (bRet && wszDriveName[0] <= 'Z')
+ {
+ if(dwDrivemap & 0x00000001L)
+ bRet = AddToEnumList(_ILCreateDrive(wszDriveName));
+ wszDriveName[0]++;
+ dwDrivemap = dwDrivemap >> 1;
+ }
+
+ TRACE("-- (%p)-> enumerate (mycomputer shell extensions)\n", this);
+ for (i = 0; i < 2; i++)
+ {
+ if (bRet && ERROR_SUCCESS == RegOpenKeyExW(i == 0 ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
+ MyComputer_NameSpaceW, 0, KEY_READ, &hKey))
+ {
+ WCHAR wszBuf[50];
+ DWORD dwSize, j = 0;
+ LONG ErrorCode;
+ LPITEMIDLIST pidl;
+
+ while (bRet)
+ {
+ dwSize = sizeof(wszBuf) / sizeof(wszBuf[0]);
+ ErrorCode = RegEnumKeyExW(hKey, j, wszBuf, &dwSize, 0, NULL, NULL, NULL);
+ if (ERROR_SUCCESS == ErrorCode)
+ {
+ if (wszBuf[0] != L'{')
+ {
+ dwSize = sizeof(wszBuf);
+ RegGetValueW(hKey, wszBuf, NULL, RRF_RT_REG_SZ, NULL, wszBuf, &dwSize);
+ }
+
+ /* FIXME: shell extensions - the type should be PT_SHELLEXT (tested) */
+ pidl = _ILCreateGuidFromStrW(wszBuf);
+ if (pidl != NULL)
+ bRet = AddToEnumList(pidl);
+ else
+ ERR("Invalid MyComputer namespace extesion: %s\n", wszBuf);
+ j++;
+ }
+ else if (ERROR_NO_MORE_ITEMS == ErrorCode)
+ break;
+ else
+ bRet = FALSE;
+ }
+ RegCloseKey(hKey);
+ }
+ }
+ }
+ return bRet;
+}
+
+CDrivesFolder::CDrivesFolder()
+{
+ pidlRoot = NULL;
+ sName = NULL;
+}
+
+CDrivesFolder::~CDrivesFolder()
+{
+ TRACE ("-- destroying IShellFolder(%p)\n", this);
+ SHFree(pidlRoot);
+}
+
+HRESULT WINAPI CDrivesFolder::FinalConstruct()
+{
+ DWORD dwSize;
+ WCHAR szName[MAX_PATH];
+ WCHAR wszMyCompKey[256];
+ INT i;
+
+ pidlRoot = _ILCreateMyComputer(); /* my qualified pidl */
+ if (pidlRoot == NULL)
+ return E_OUTOFMEMORY;
+
+ i = swprintf(wszMyCompKey, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\");
+ StringFromGUID2(CLSID_MyComputer, wszMyCompKey + i, sizeof(wszMyCompKey) / sizeof(wszMyCompKey[0]) - i);
+ dwSize = sizeof(szName);
+ if (RegGetValueW(HKEY_CURRENT_USER, wszMyCompKey,
+ NULL, RRF_RT_REG_SZ, NULL, szName, &dwSize) == ERROR_SUCCESS)
+ {
+ sName = (LPWSTR)SHAlloc((wcslen(szName) + 1) * sizeof(WCHAR));
+ if (sName)
+ wcscpy(sName, szName);
+ TRACE("sName %s\n", debugstr_w(sName));
+ }
+ return S_OK;
+}
+
+/**************************************************************************
+* CDrivesFolder::ParseDisplayName
+*/
+HRESULT WINAPI CDrivesFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
- HRESULT WINAPI CDrivesFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
++ DWORD * pchEaten, PIDLIST_RELATIVE * ppidl, DWORD * pdwAttributes)
+{
+ HRESULT hr = E_INVALIDARG;
+ LPCWSTR szNext = NULL;
+ WCHAR szElement[MAX_PATH];
+ LPITEMIDLIST pidlTemp = NULL;
+ CLSID clsid;
+
+ TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", this,
+ hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName),
+ pchEaten, ppidl, pdwAttributes);
+
+ *ppidl = 0;
+ if (pchEaten)
+ *pchEaten = 0; /* strange but like the original */
+
+ /* handle CLSID paths */
+ 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);
+ }
+ /* do we have an absolute path name ? */
+ else if (PathGetDriveNumberW (lpszDisplayName) >= 0 &&
+ lpszDisplayName[2] == (WCHAR) '\\')
+ {
+ szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
+ /* make drive letter uppercase to enable PIDL comparison */
+ szElement[0] = toupper(szElement[0]);
+ pidlTemp = _ILCreateDrive (szElement);
+ }
+
+ if (szNext && *szNext)
+ {
+ hr = SHELL32_ParseNextElement (this, hwndOwner, pbc, &pidlTemp,
+ (LPOLESTR) szNext, pchEaten, pdwAttributes);
+ }
+ else
+ {
+ if (pdwAttributes && *pdwAttributes)
+ SHELL32_GetItemAttributes (this,
+ pidlTemp, pdwAttributes);
+ hr = S_OK;
+ }
+
+ *ppidl = pidlTemp;
+
+ TRACE ("(%p)->(-- ret=0x%08x)\n", this, hr);
+
+ return hr;
+}
+
+/**************************************************************************
+* CDrivesFolder::EnumObjects
+*/
+HRESULT WINAPI CDrivesFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
+{
+ CComObject<CDrivesFolderEnum> *theEnumerator;
+ CComPtr<IEnumIDList> result;
+ HRESULT hResult;
+
+ TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", this, hwndOwner, dwFlags, ppEnumIDList);
+
+ if (ppEnumIDList == NULL)
+ return E_POINTER;
+
+ *ppEnumIDList = NULL;
+ ATLTRY(theEnumerator = new CComObject<CDrivesFolderEnum>);
+
+ if (theEnumerator == NULL)
+ return E_OUTOFMEMORY;
+
+ hResult = theEnumerator->QueryInterface(IID_IEnumIDList, (void **)&result);
+ if (FAILED(hResult))
+ {
+ delete theEnumerator;
+ return hResult;
+ }
+
+ hResult = theEnumerator->Initialize(hwndOwner, dwFlags);
+ if (FAILED(hResult))
+ return hResult;
+ *ppEnumIDList = result.Detach();
+
+ TRACE("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList);
+
+ return S_OK;
+}
+
+/**************************************************************************
+* CDrivesFolder::BindToObject
+*/
- HRESULT WINAPI CDrivesFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
++HRESULT WINAPI CDrivesFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, 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);
+}
+
+/**************************************************************************
+* CDrivesFolder::BindToStorage
+*/
- HRESULT WINAPI CDrivesFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
++HRESULT WINAPI CDrivesFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
+{
+ FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this,
+ pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
+
+ *ppvOut = NULL;
+ return E_NOTIMPL;
+}
+
+/**************************************************************************
+* CDrivesFolder::CompareIDs
+*/
+
- HRESULT WINAPI CDrivesFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl, DWORD * rgfInOut)
++HRESULT WINAPI CDrivesFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
+{
+ int nReturn;
+
+ 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;
+}
+
+/**************************************************************************
+* CDrivesFolder::CreateViewObject
+*/
+HRESULT WINAPI CDrivesFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
+{
+ CComPtr<IShellView> pShellView;
+ HRESULT hr = E_INVALIDARG;
+
+ TRACE("(%p)->(hwnd=%p,%s,%p)\n", this,
+ hwndOwner, shdebugstr_guid (&riid), ppvOut);
+
+ if (!ppvOut)
+ return hr;
+
+ *ppvOut = NULL;
+
+ if (IsEqualIID(riid, IID_IDropTarget))
+ {
+ WARN("IDropTarget not implemented\n");
+ hr = E_NOTIMPL;
+ }
+ else if (IsEqualIID(riid, IID_IContextMenu))
+ {
+ 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);
+ }
+ }
+ TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
+ return hr;
+}
+
+/**************************************************************************
+* CDrivesFolder::GetAttributesOf
+*/
- UINT cidl, LPCITEMIDLIST *apidl,
++HRESULT WINAPI CDrivesFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD * rgfInOut)
+{
+ static const DWORD dwComputerAttributes =
+ SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
+ SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK;
+ static const DWORD dwControlPanelAttributes =
+ SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_CANLINK;
+ static const DWORD dwDriveAttributes =
+ SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR |
+ SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANRENAME | SFGAO_CANLINK;
+
+ TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
+ this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
+
+ if (cidl && !apidl)
+ return E_INVALIDARG;
+
+ if (*rgfInOut == 0)
+ *rgfInOut = ~0;
+
+ /* FIXME: always add SFGAO_CANLINK */
+ if(cidl == 0)
+ *rgfInOut &= dwComputerAttributes;
+ else
+ {
+ for (UINT i = 0; i < cidl; ++i)
+ {
+ if (_ILIsDrive(apidl[i]))
+ *rgfInOut &= dwDriveAttributes;
+ else if (_ILIsControlPanel(apidl[i]))
+ *rgfInOut &= dwControlPanelAttributes;
+ else
+ {
+ pdump(apidl[i]);
+ SHELL32_GetItemAttributes(this, apidl[i], rgfInOut);
+ }
+ }
+ }
+
+ /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
+ *rgfInOut &= ~SFGAO_VALIDATE;
+
+ TRACE ("-- result=0x%08x\n", *rgfInOut);
+ return S_OK;
+}
+
+/**************************************************************************
+* CDrivesFolder::GetUIObjectOf
+*
+* PARAMETERS
+* hwndOwner [in] Parent window for any output
+* cidl [in] array size
+* apidl [in] simple pidl array
+* riid [in] Requested Interface
+* prgfInOut [ ] reserved
+* ppvObject [out] Resulting Interface
+*
+*/
+HRESULT WINAPI CDrivesFolder::GetUIObjectOf(HWND hwndOwner,
- HRESULT WINAPI CDrivesFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
++ UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
+ REFIID riid, UINT *prgfInOut, LPVOID *ppvOut)
+{
+ LPITEMIDLIST pidl;
+ IUnknown *pObj = NULL;
+ HRESULT hr = E_INVALIDARG;
+
+ TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", this,
+ hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
+
+ if (!ppvOut)
+ return hr;
+
+ *ppvOut = NULL;
+
+ if (IsEqualIID (riid, IID_IContextMenu) && (cidl >= 1))
+ {
+ hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, (IShellFolder*)this, NULL, 0, NULL, (IContextMenu**)&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_IDropTarget) && (cidl >= 1))
+ {
+ IDropTarget * pDt = NULL;
+ hr = this->QueryInterface(IID_PPV_ARG(IDropTarget, &pDt));
+ pObj = pDt;
+ }
+ 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
+ hr = E_NOINTERFACE;
+
+ if (SUCCEEDED(hr) && !pObj)
+ hr = E_OUTOFMEMORY;
+
+ *ppvOut = pObj;
+ TRACE ("(%p)->hr=0x%08x\n", this, hr);
+ return hr;
+}
+
+/**************************************************************************
+* CDrivesFolder::GetDisplayNameOf
+*/
- HRESULT WINAPI CDrivesFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl,
- LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST *pPidlOut)
++HRESULT WINAPI CDrivesFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
+{
+ LPWSTR pszPath;
+ HRESULT hr = S_OK;
+
+ TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
+ pdump (pidl);
+
+ if (!strRet)
+ return E_INVALIDARG;
+
+ pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
+ if (!pszPath)
+ return E_OUTOFMEMORY;
+
+ pszPath[0] = 0;
+
+ if (!pidl->mkid.cb)
+ {
+ /* parsing name like ::{...} */
+ pszPath[0] = ':';
+ pszPath[1] = ':';
+ SHELL32_GUIDToStringW(CLSID_MyComputer, &pszPath[2]);
+ }
+ else if (_ILIsPidlSimple(pidl))
+ {
+ /* take names of special folders only if its only this folder */
+ if (_ILIsSpecialFolder(pidl))
+ {
+ GUID const *clsid;
+
+ clsid = _ILGetGUIDPointer (pidl);
+ if (clsid)
+ {
+ if (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING)
+ {
+ static const WCHAR clsidW[] = L"CLSID\\";
+ static const WCHAR shellfolderW[] = L"\\shellfolder";
+ static const WCHAR wantsForParsingW[] = L"WantsForParsing";
+ BOOL bWantsForParsing = FALSE;
+ WCHAR szRegPath[100];
+ LONG r;
+
+ /*
+ * We can only get a filesystem path from a shellfolder
+ * if the value WantsFORPARSING exists in
+ * CLSID\\{...}\\shellfolder
+ * exception: the MyComputer folder has this keys not
+ * but like any filesystem backed
+ * folder it needs these behaviour
+ *
+ * Get the "WantsFORPARSING" flag from the registry
+ */
+
+ wcscpy(szRegPath, clsidW);
+ SHELL32_GUIDToStringW(*clsid, &szRegPath[6]);
+ wcscat(szRegPath, shellfolderW);
+ r = SHGetValueW(HKEY_CLASSES_ROOT, szRegPath,
+ wantsForParsingW, NULL, NULL, NULL);
+ if (r == ERROR_SUCCESS)
+ bWantsForParsing = TRUE;
+
+ if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
+ bWantsForParsing)
+ {
+ /*
+ * We need the filesystem path to the destination folder
+ * Only the folder itself can know it
+ */
+ hr = SHELL32_GetDisplayNameOfChild (this, pidl,
+ dwFlags, pszPath, MAX_PATH);
+ }
+ else
+ {
+ LPWSTR p = pszPath;
+
+ /* parsing name like ::{...} */
+ p[0] = ':';
+ p[1] = ':';
+ p += 2;
+ p += SHELL32_GUIDToStringW(CLSID_MyComputer, p);
+
+ /* \:: */
+ p[0] = '\\';
+ p[1] = ':';
+ p[2] = ':';
+ p += 3;
+ SHELL32_GUIDToStringW(*clsid, p);
+ }
+ }
+ else
+ {
+ /* user friendly name */
+
+ if (_ILIsMyComputer(pidl) && sName)
+ wcscpy(pszPath, sName);
+ else
+ HCR_GetClassNameW (*clsid, pszPath, MAX_PATH);
+
+ TRACE("pszPath %s\n", debugstr_w(pszPath));
+ }
+ }
+ else
+ {
+ /* append my own path */
+ _ILSimpleGetTextW(pidl, pszPath, MAX_PATH);
+ }
+ }
+ else if (_ILIsDrive(pidl))
+ {
+
+ _ILSimpleGetTextW(pidl, pszPath, MAX_PATH); /* append my own path */
+ /* long view "lw_name (C:)" */
+ if (!(dwFlags & SHGDN_FORPARSING))
+ {
+ WCHAR wszDrive[18] = {0};
+ DWORD dwVolumeSerialNumber, dwMaximumComponentLength, dwFileSystemFlags;
+ static const WCHAR wszOpenBracket[] = {' ', '(', 0};
+ static const WCHAR wszCloseBracket[] = {')', 0};
+
+ lstrcpynW(wszDrive, pszPath, 4);
+ pszPath[0] = L'\0';
+ GetVolumeInformationW(wszDrive, pszPath,
+ MAX_PATH - 7,
+ &dwVolumeSerialNumber,
+ &dwMaximumComponentLength, &dwFileSystemFlags, NULL, 0);
+ pszPath[MAX_PATH-1] = L'\0';
+ if (!wcslen(pszPath))
+ {
+ UINT DriveType, ResourceId;
+ DriveType = GetDriveTypeW(wszDrive);
+ switch(DriveType)
+ {
+ case DRIVE_FIXED:
+ ResourceId = IDS_DRIVE_FIXED;
+ break;
+ case DRIVE_REMOTE:
+ ResourceId = IDS_DRIVE_NETWORK;
+ break;
+ case DRIVE_CDROM:
+ ResourceId = IDS_DRIVE_CDROM;
+ break;
+ default:
+ ResourceId = 0;
+ }
+ if (ResourceId)
+ {
+ dwFileSystemFlags = LoadStringW(shell32_hInstance, ResourceId, pszPath, MAX_PATH);
+ if (dwFileSystemFlags > MAX_PATH - 7)
+ pszPath[MAX_PATH-7] = L'\0';
+ }
+ }
+ wcscat (pszPath, wszOpenBracket);
+ wszDrive[2] = L'\0';
+ wcscat (pszPath, wszDrive);
+ wcscat (pszPath, wszCloseBracket);
+ }
+ }
+ else
+ {
+ /* Neither a shell namespace extension nor a drive letter. */
+ ERR("Wrong pidl type\n");
+ CoTaskMemFree(pszPath);
+ return E_INVALIDARG;
+ }
+ }
+ else
+ {
+ /* Complex pidl. Let the child folder do the work */
+ hr = SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, pszPath, MAX_PATH);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ strRet->uType = STRRET_WSTR;
+ strRet->pOleStr = pszPath;
+ }
+ else
+ CoTaskMemFree(pszPath);
+
+ TRACE("-- (%p)->(%s)\n", this, strRet->uType == STRRET_CSTR ? strRet->cStr : debugstr_w(strRet->pOleStr));
+ return hr;
+}
+
+/**************************************************************************
+* CDrivesFolder::SetNameOf
+* Changes the name of a file object or subfolder, possibly changing its item
+* identifier in the process.
+*
+* PARAMETERS
+* hwndOwner [in] Owner window for output
+* pidl [in] simple pidl of item to change
+* lpszName [in] the items new display name
+* dwFlags [in] SHGNO formatting flags
+* ppidlOut [out] simple pidl returned
+*/
- HRESULT WINAPI CDrivesFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID * pscid, VARIANT * pv)
++HRESULT WINAPI CDrivesFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl,
++ LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
+{
+ LPWSTR sName;
+ HKEY hKey;
+ UINT length;
+ WCHAR szName[30];
+
+ TRACE("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this,
+ hwndOwner, pidl, debugstr_w (lpName), dwFlags, pPidlOut);
+
+ if (_ILIsDrive(pidl))
+ {
+ if (_ILSimpleGetTextW(pidl, szName, _countof(szName)))
+ SetVolumeLabelW(szName, lpName);
+ if (pPidlOut)
+ *pPidlOut = _ILCreateDrive(szName);
+ return S_OK;
+ }
+
+
+ if (pPidlOut != NULL)
+ *pPidlOut = _ILCreateMyComputer();
+
+ length = (wcslen(lpName) + 1) * sizeof(WCHAR);
+ sName = (LPWSTR)SHAlloc(length);
+
+ if (!sName)
+ return E_OUTOFMEMORY;
+
+ if (RegOpenKeyExW(HKEY_CURRENT_USER,
+ L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\{20D04FE0-3AEA-1069-A2D8-08002B30309D}",
+ 0,
+ KEY_WRITE,
+ &hKey) != ERROR_SUCCESS)
+ {
+ WARN("Error: failed to open registry key\n");
+ }
+ else
+ {
+ RegSetValueExW(hKey, NULL, 0, REG_SZ, (const LPBYTE)lpName, length);
+ RegCloseKey(hKey);
+ }
+
+ wcscpy(sName, lpName);
+ SHFree(this->sName);
+ this->sName = sName;
+ TRACE("result %s\n", debugstr_w(sName));
+ return S_OK;
+}
+
+HRESULT WINAPI CDrivesFolder::GetDefaultSearchGUID(GUID * pguid)
+{
+ FIXME ("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CDrivesFolder::EnumSearches(IEnumExtraSearch ** ppenum)
+{
+ FIXME ("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CDrivesFolder::GetDefaultColumn (DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
+{
+ TRACE ("(%p)\n", this);
+
+ if (pSort)
+ *pSort = 0;
+ if (pDisplay)
+ *pDisplay = 0;
+ return S_OK;
+}
+
+HRESULT WINAPI CDrivesFolder::GetDefaultColumnState(UINT iColumn, DWORD * pcsFlags)
+{
+ TRACE ("(%p)\n", this);
+
+ if (!pcsFlags || iColumn >= MYCOMPUTERSHELLVIEWCOLUMNS)
+ return E_INVALIDARG;
+ *pcsFlags = MyComputerSFHeader[iColumn].pcsFlags;
+ return S_OK;
+}
+
- HRESULT WINAPI CDrivesFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd)
++HRESULT WINAPI CDrivesFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID * pscid, VARIANT * pv)
+{
+ FIXME ("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+/* FIXME: drive size >4GB is rolling over */
++HRESULT WINAPI CDrivesFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
+{
+ HRESULT hr;
+
+ TRACE ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
+
+ if (!psd || iColumn >= MYCOMPUTERSHELLVIEWCOLUMNS)
+ return E_INVALIDARG;
+
+ if (!pidl)
+ {
+ psd->fmt = MyComputerSFHeader[iColumn].fmt;
+ psd->cxChar = MyComputerSFHeader[iColumn].cxChar;
+ psd->str.uType = STRRET_CSTR;
+ LoadStringA(shell32_hInstance, MyComputerSFHeader[iColumn].colnameid,
+ psd->str.cStr, MAX_PATH);
+ return S_OK;
+ }
+ else
+ {
+ char szPath[MAX_PATH];
+ ULARGE_INTEGER ulBytes;
+
+ psd->str.cStr[0] = 0x00;
+ psd->str.uType = STRRET_CSTR;
+ switch (iColumn)
+ {
+ case 0: /* name */
+ hr = GetDisplayNameOf(pidl,
+ SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
+ break;
+ case 1: /* type */
+ _ILGetFileType(pidl, psd->str.cStr, MAX_PATH);
+ break;
+ case 2: /* total size */
+ if (_ILIsDrive(pidl))
+ {
+ _ILSimpleGetText (pidl, szPath, MAX_PATH);
+ GetDiskFreeSpaceExA (szPath, NULL, &ulBytes, NULL);
+ StrFormatByteSizeA (ulBytes.LowPart, psd->str.cStr, MAX_PATH);
+ }
+ break;
+ case 3: /* free size */
+ if (_ILIsDrive(pidl))
+ {
+ _ILSimpleGetText (pidl, szPath, MAX_PATH);
+ GetDiskFreeSpaceExA (szPath, &ulBytes, NULL, NULL);
+ StrFormatByteSizeA (ulBytes.LowPart, psd->str.cStr, MAX_PATH);
+ }
+ break;
+ }
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+HRESULT WINAPI CDrivesFolder::MapColumnToSCID(UINT column, SHCOLUMNID * pscid)
+{
+ FIXME("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+/************************************************************************
+ * CDrivesFolder::GetClassID
+ */
+HRESULT WINAPI CDrivesFolder::GetClassID(CLSID *lpClassId)
+{
+ TRACE ("(%p)\n", this);
+
+ if (!lpClassId)
+ return E_POINTER;
+
+ *lpClassId = CLSID_MyComputer;
+ return S_OK;
+}
+
+/************************************************************************
+ * CDrivesFolder::Initialize
+ *
+ * NOTES: it makes no sense to change the pidl
+ */
+HRESULT WINAPI CDrivesFolder::Initialize(LPCITEMIDLIST pidl)
+{
+ TRACE ("(%p)->(%p)\n", this, pidl);
+
+ if (pidlRoot)
+ SHFree((LPVOID)pidlRoot);
+
+ pidlRoot = ILClone(pidl);
+ return S_OK;
+}
+
+/**************************************************************************
+ * CDrivesFolder::GetCurFolder
+ */
+HRESULT WINAPI CDrivesFolder::GetCurFolder(LPITEMIDLIST *pidl)
+{
+ TRACE("(%p)->(%p)\n", this, pidl);
+
+ if (!pidl)
+ return E_POINTER;
+
+ *pidl = ILClone(pidlRoot);
+ return S_OK;
+}
--- /dev/null
- HRESULT WINAPI CMyDocsFolder::ParseDisplayName (HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
- DWORD * pchEaten, LPITEMIDLIST * ppidl, DWORD * pdwAttributes)
+/*
+ * Virtual MyDocuments Folder
+ *
+ * Copyright 2007 Johannes Anderwald
+ * Copyright 2009 Andrew Hill
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <precomp.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL (mydocs);
+
+/*
+CFileSysEnumX should not exist. CMyDocsFolder should aggregate a CFSFolder which always
+maps the contents of CSIDL_PERSONAL. Therefore, CMyDocsFolder::EnumObjects simply calls
+CFSFolder::EnumObjects.
+*/
+
+/***********************************************************************
+* MyDocumentsfolder implementation
+*/
+
+class CFileSysEnumX :
+ public IEnumIDListImpl
+{
+ private:
+ public:
+ CFileSysEnumX();
+ ~CFileSysEnumX();
+ HRESULT WINAPI Initialize(DWORD dwFlags);
+
+ BEGIN_COM_MAP(CFileSysEnumX)
+ COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
+ END_COM_MAP()
+};
+
+static const shvheader MyDocumentsSFHeader[] = {
+ {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
+ {IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
+ {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
+ {IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 12},
+ {IDS_SHV_COLUMN5, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 5}
+};
+
+#define MYDOCUMENTSSHELLVIEWCOLUMNS 5
+
+CFileSysEnumX::CFileSysEnumX()
+{
+}
+
+CFileSysEnumX::~CFileSysEnumX()
+{
+}
+
+HRESULT WINAPI CFileSysEnumX::Initialize(DWORD dwFlags)
+{
+ WCHAR szPath[MAX_PATH];
+
+ if (SHGetSpecialFolderPathW(0, szPath, CSIDL_PERSONAL, FALSE) == FALSE)
+ return E_FAIL;
+ return CreateFolderEnumList(szPath, dwFlags);
+}
+
+CMyDocsFolder::CMyDocsFolder()
+{
+ pidlRoot = NULL;
+ sPathTarget = NULL;
+ mFSDropTarget = NULL;
+}
+
+CMyDocsFolder::~CMyDocsFolder()
+{
+ TRACE ("-- destroying IShellFolder(%p)\n", this);
+ SHFree(pidlRoot);
+ HeapFree(GetProcessHeap(), 0, sPathTarget);
+ mFSDropTarget->Release();
+}
+
+HRESULT WINAPI CMyDocsFolder::FinalConstruct()
+{
+ WCHAR szMyPath[MAX_PATH];
+
+ if (!SHGetSpecialFolderPathW(0, szMyPath, CSIDL_PERSONAL, TRUE))
+ return E_UNEXPECTED;
+
+ pidlRoot = _ILCreateMyDocuments(); /* my qualified pidl */
+ sPathTarget = (LPWSTR)SHAlloc((wcslen(szMyPath) + 1) * sizeof(WCHAR));
+ wcscpy(sPathTarget, szMyPath);
+
+ LPITEMIDLIST pidl = NULL;
+
+ WCHAR szPath[MAX_PATH];
+ lstrcpynW(szPath, sPathTarget, MAX_PATH);
+ PathAddBackslashW(szPath);
+ CComPtr<IShellFolder> psfDesktop = NULL;
+
+ HRESULT hr = SHGetDesktopFolder(&psfDesktop);
+ if (SUCCEEDED(hr))
+ hr = psfDesktop->ParseDisplayName(NULL, NULL, szPath, NULL, &pidl, NULL);
+ else
+ ERR("Error getting desktop folder\n");
+
+ if (SUCCEEDED(hr))
+ {
+ hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IDropTarget, &mFSDropTarget));
+ CoTaskMemFree(pidl);
+ if (FAILED(hr))
+ ERR("Error Binding");
+ }
+ else
+ ERR("Error creating from %s\n", debugstr_w(szPath));
+
+ return S_OK;
+}
+
- HRESULT WINAPI CMyDocsFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
++HRESULT WINAPI CMyDocsFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
++ DWORD *pchEaten, 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;
+ }
+ else
+ {
+ /* it's a filesystem path on the desktop. Let a FSFolder parse it */
+
+ if (*lpszDisplayName)
+ {
+ WCHAR szPath[MAX_PATH];
+ LPWSTR pathPtr;
+
+ /* build a complete path to create a simple pidl */
+ lstrcpynW(szPath, sPathTarget, MAX_PATH);
+ pathPtr = PathAddBackslashW(szPath);
+ if (pathPtr)
+ {
+ lstrcpynW(pathPtr, lpszDisplayName, MAX_PATH - (pathPtr - szPath));
+ hr = _ILCreateFromPathW(szPath, &pidlTemp);
+ }
+ else
+ {
+ /* should never reach here, but for completeness */
+ hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
+ }
+ }
+ else
+ pidlTemp = _ILCreateMyDocuments();
+
+ szNext = NULL;
+ }
+
+ 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;
+}
+
+/**************************************************************************
+ * ISF_MyDocuments_fnEnumObjects
+ */
+HRESULT WINAPI CMyDocsFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
+{
+ CComObject<CFileSysEnumX> *theEnumerator;
+ CComPtr<IEnumIDList> result;
+ HRESULT hResult;
+
+ TRACE("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", this, hwndOwner, dwFlags, ppEnumIDList);
+
+ if (ppEnumIDList == NULL)
+ return E_POINTER;
+ *ppEnumIDList = NULL;
+ ATLTRY (theEnumerator = new CComObject<CFileSysEnumX>);
+ if (theEnumerator == NULL)
+ return E_OUTOFMEMORY;
+ hResult = theEnumerator->QueryInterface(IID_IEnumIDList, (void **)&result);
+ if (FAILED (hResult))
+ {
+ delete theEnumerator;
+ return hResult;
+ }
+ hResult = theEnumerator->Initialize(dwFlags);
+ if (FAILED (hResult))
+ return hResult;
+ *ppEnumIDList = result.Detach();
+
+ TRACE("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList);
+
+ return S_OK;
+}
+
+/**************************************************************************
+ * CMyDocsFolder::BindToObject
+ */
- HRESULT WINAPI CMyDocsFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
++HRESULT WINAPI CMyDocsFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
+{
+ TRACE("(%p)->(pidl=%p,%p,%s,%p)\n",
+ this, pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
+
+ return SHELL32_BindToChild( pidlRoot, sPathTarget, pidl, riid, ppvOut );
+}
+
+/**************************************************************************
+ * CMyDocsFolder::BindToStorage
+ */
- HRESULT WINAPI CMyDocsFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
++HRESULT WINAPI CMyDocsFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
+{
+ FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n",
+ this, pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
+
+ *ppvOut = NULL;
+ return E_NOTIMPL;
+}
+
+/**************************************************************************
+ * CMyDocsFolder::CompareIDs
+ */
- HRESULT WINAPI CMyDocsFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, DWORD *rgfInOut)
++HRESULT WINAPI CMyDocsFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
+{
+ int nReturn;
+
+ 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;
+}
+
+/**************************************************************************
+ * CMyDocsFolder::CreateViewObject
+ */
+HRESULT WINAPI CMyDocsFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut)
+{
+ CComPtr<IShellView> pShellView;
+ HRESULT hr = E_INVALIDARG;
+
+ TRACE ("(%p)->(hwnd=%p,%s,%p)\n",
+ this, hwndOwner, shdebugstr_guid (&riid), ppvOut);
+
+ if (!ppvOut)
+ return hr;
+
+ *ppvOut = NULL;
+
+ if (IsEqualIID (riid, IID_IDropTarget))
+ {
+ hr = this->QueryInterface (IID_IDropTarget, ppvOut);
+ }
+ else if (IsEqualIID (riid, IID_IContextMenu))
+ {
+ 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);
+ }
+ }
+ TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
+ return hr;
+}
+
+/**************************************************************************
+ * CMyDocsFolder::GetAttributesOf
+ */
- HRESULT WINAPI CMyDocsFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl,
++HRESULT WINAPI CMyDocsFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut)
+{
+ HRESULT hr = S_OK;
+ static const DWORD dwMyDocumentsAttributes =
+ SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_CANCOPY |
+ SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER | SFGAO_CANRENAME | SFGAO_CANDELETE;
+
+ TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
+ this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
+
+ if (!rgfInOut)
+ return E_INVALIDARG;
+ if (cidl && !apidl)
+ return E_INVALIDARG;
+
+ if (*rgfInOut == 0)
+ *rgfInOut = ~0;
+
+ if(cidl == 0) {
+ *rgfInOut &= dwMyDocumentsAttributes;
+ } else {
+ while (cidl > 0 && *apidl) {
+ pdump (*apidl);
+ if (_ILIsMyDocuments(*apidl)) {
+ *rgfInOut &= dwMyDocumentsAttributes;
+ } else {
+ SHELL32_GetItemAttributes (this, *apidl, rgfInOut);
+ }
+ apidl++;
+ cidl--;
+ }
+ }
+ /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
+ *rgfInOut &= ~SFGAO_VALIDATE;
+
+ TRACE ("-- result=0x%08x\n", *rgfInOut);
+
+ return hr;
+}
+
+/**************************************************************************
+ * CMyDocsFolder::GetUIObjectOf
+ *
+ * PARAMETERS
+ * HWND hwndOwner, //[in ] Parent window for any output
+ * UINT cidl, //[in ] array size
+ * LPCITEMIDLIST* apidl, //[in ] simple pidl array
+ * REFIID riid, //[in ] Requested Interface
+ * UINT* prgfInOut, //[ ] reserved
+ * LPVOID* ppvObject) //[out] Resulting Interface
+ *
+ */
- HRESULT WINAPI CMyDocsFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
++HRESULT WINAPI CMyDocsFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
+ REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
+{
+ LPITEMIDLIST pidl;
+ IUnknown *pObj = NULL;
+ HRESULT hr = E_INVALIDARG;
+
+ TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
+ this, hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
+
+ if (!ppvOut)
+ return hr;
+
+ *ppvOut = NULL;
+
+ if (IsEqualIID (riid, IID_IContextMenu))
+ {
+ IContextMenu * pCm = NULL;
+ hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, static_cast<IShellFolder*>(this), NULL, 0, NULL, &pCm);
+ pObj = pCm;
+ }
+ else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
+ {
+ IDataObject * pDo = NULL;
+ hr = IDataObject_Constructor(hwndOwner, pidlRoot, apidl, cidl, &pDo);
+ pObj = pDo;
+ }
+ 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_IDropTarget) && (cidl >= 1))
+ {
+ IDropTarget * pDt = NULL;
+ hr = this->QueryInterface(IID_PPV_ARG(IDropTarget, &pDt));
+ pObj = pDt;
+ }
+ 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
+ hr = E_NOINTERFACE;
+
+ if (SUCCEEDED(hr) && !pObj)
+ hr = E_OUTOFMEMORY;
+
+ *ppvOut = pObj;
+ TRACE ("(%p)->hr=0x%08x\n", this, hr);
+ return hr;
+}
+
- HRESULT WINAPI CMyDocsFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, /* simple pidl */
- LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut)
++HRESULT WINAPI CMyDocsFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
+{
+ HRESULT hr = S_OK;
+ LPWSTR pszPath;
+
+ TRACE ("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
+ pdump (pidl);
+
+ if (!strRet)
+ return E_INVALIDARG;
+
+ pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
+ if (!pszPath)
+ return E_OUTOFMEMORY;
+
+ ZeroMemory(pszPath, (MAX_PATH + 1) * sizeof(WCHAR));
+
+ if (_ILIsMyDocuments (pidl))
+ {
+ if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
+ (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING))
+ wcscpy(pszPath, sPathTarget);
+ else
+ HCR_GetClassNameW(CLSID_MyDocuments, pszPath, MAX_PATH);
+ TRACE("CP\n");
+ }
+ else if (_ILIsPidlSimple (pidl))
+ {
+ GUID const *clsid;
+
+ if ((clsid = _ILGetGUIDPointer (pidl)))
+ {
+ if (GET_SHGDN_FOR (dwFlags) & SHGDN_FORPARSING)
+ {
+ int bWantsForParsing;
+
+ /*
+ * We can only get a filesystem path from a shellfolder if the
+ * value WantsFORPARSING in CLSID\\{...}\\shellfolder exists.
+ *
+ * Exception: The MyComputer folder doesn't have this key,
+ * but any other filesystem backed folder it needs it.
+ */
+ if (IsEqualIID (*clsid, CLSID_MyDocuments))
+ {
+ bWantsForParsing = TRUE;
+ }
+ else
+ {
+ /* get the "WantsFORPARSING" flag from the registry */
+ static const WCHAR clsidW[] = L"CLSID\\";
+ static const WCHAR shellfolderW[] = L"shellfolder";
+ static const WCHAR wantsForParsingW[] = L"WantsForParsing";
+ WCHAR szRegPath[100];
+ LONG r;
+
+ wcscpy (szRegPath, clsidW);
+ SHELL32_GUIDToStringW (*clsid, &szRegPath[6]);
+ wcscat (szRegPath, shellfolderW);
+ r = SHGetValueW(HKEY_CLASSES_ROOT, szRegPath,
+ wantsForParsingW, NULL, NULL, NULL);
+ if (r == ERROR_SUCCESS)
+ bWantsForParsing = TRUE;
+ else
+ bWantsForParsing = FALSE;
+ }
+
+ if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
+ bWantsForParsing)
+ {
+ /*
+ * we need the filesystem path to the destination folder.
+ * Only the folder itself can know it
+ */
+ hr = SHELL32_GetDisplayNameOfChild (this, pidl, dwFlags,
+ pszPath,
+ MAX_PATH);
+ TRACE("CP\n");
+ }
+ else
+ {
+ /* parsing name like ::{...} */
+ pszPath[0] = ':';
+ pszPath[1] = ':';
+ SHELL32_GUIDToStringW (*clsid, &pszPath[2]);
+ TRACE("CP\n");
+ }
+ }
+ else
+ {
+ /* user friendly name */
+ HCR_GetClassNameW (*clsid, pszPath, MAX_PATH);
+ TRACE("CP\n");
+ }
+ }
+ else
+ {
+ int cLen = 0;
+
+ /* file system folder or file rooted at the desktop */
+ if ((GET_SHGDN_FOR(dwFlags) == SHGDN_FORPARSING) &&
+ (GET_SHGDN_RELATION(dwFlags) != SHGDN_INFOLDER))
+ {
+ lstrcpynW(pszPath, sPathTarget, MAX_PATH - 1);
+ TRACE("CP %s\n", debugstr_w(pszPath));
+ }
+
+ if (!_ILIsDesktop(pidl))
+ {
+ PathAddBackslashW(pszPath);
+ cLen = wcslen(pszPath);
+ _ILSimpleGetTextW(pidl, pszPath + cLen, MAX_PATH - cLen);
+ if (!_ILIsFolder(pidl))
+ {
+ SHELL_FS_ProcessDisplayFilename(pszPath, dwFlags);
+ TRACE("CP\n");
+ }
+ }
+ }
+ }
+ else
+ {
+ /* a complex pidl, let the subfolder do the work */
+ hr = SHELL32_GetDisplayNameOfChild (this, pidl, dwFlags,
+ pszPath, MAX_PATH);
+ TRACE("CP\n");
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ strRet->uType = STRRET_WSTR;
+ strRet->pOleStr = pszPath;
+ }
+ else
+ CoTaskMemFree(pszPath);
+
+ TRACE ("-- (%p)->(%s,0x%08x)\n", this, debugstr_w(strRet->pOleStr), hr);
+ return hr;
+}
+
- HRESULT WINAPI CMyDocsFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
++HRESULT WINAPI CMyDocsFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, /* simple pidl */
++ LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
+{
+ FIXME ("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this, hwndOwner, pidl,
+ debugstr_w (lpName), dwFlags, pPidlOut);
+
+ return E_FAIL;
+}
+
+HRESULT WINAPI CMyDocsFolder::GetDefaultSearchGUID(GUID *pguid)
+{
+ FIXME ("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CMyDocsFolder::EnumSearches(IEnumExtraSearch **ppenum)
+{
+ FIXME ("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CMyDocsFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
+{
+ TRACE ("(%p)\n", this);
+
+ if (pSort)
+ *pSort = 0;
+ if (pDisplay)
+ *pDisplay = 0;
+
+ return S_OK;
+}
+
+HRESULT WINAPI CMyDocsFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
+{
+ TRACE ("(%p)\n", this);
+
+ if (!pcsFlags || iColumn >= MYDOCUMENTSSHELLVIEWCOLUMNS)
+ return E_INVALIDARG;
+
+ *pcsFlags = MyDocumentsSFHeader[iColumn].pcsFlags;
+
+ return S_OK;
+}
+
- HRESULT WINAPI CMyDocsFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd)
++HRESULT WINAPI CMyDocsFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
+{
+ FIXME ("(%p)\n", this);
+
+ return E_NOTIMPL;
+}
+
++HRESULT WINAPI CMyDocsFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
+{
+ HRESULT hr = S_OK;
+
+ TRACE ("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
+
+ if (!psd || iColumn >= MYDOCUMENTSSHELLVIEWCOLUMNS)
+ return E_INVALIDARG;
+
+ if (!pidl)
+ {
+ psd->fmt = MyDocumentsSFHeader[iColumn].fmt;
+ psd->cxChar = MyDocumentsSFHeader[iColumn].cxChar;
+ psd->str.uType = STRRET_CSTR;
+ LoadStringA (shell32_hInstance, MyDocumentsSFHeader[iColumn].colnameid,
+ psd->str.cStr, MAX_PATH);
+ return S_OK;
+ }
+
+ /* the data from the pidl */
+ psd->str.uType = STRRET_CSTR;
+ switch (iColumn)
+ {
+ case 0: /* name */
+ hr = GetDisplayNameOf(pidl,
+ SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
+ break;
+ case 1: /* size */
+ _ILGetFileSize (pidl, psd->str.cStr, MAX_PATH);
+ break;
+ case 2: /* type */
+ _ILGetFileType (pidl, psd->str.cStr, MAX_PATH);
+ break;
+ case 3: /* date */
+ _ILGetFileDate (pidl, psd->str.cStr, MAX_PATH);
+ break;
+ case 4: /* attributes */
+ _ILGetFileAttributes (pidl, psd->str.cStr, MAX_PATH);
+ break;
+ }
+
+ return hr;
+}
+
+HRESULT WINAPI CMyDocsFolder::MapColumnToSCID (UINT column, SHCOLUMNID *pscid)
+{
+ FIXME ("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CMyDocsFolder::GetClassID(CLSID *lpClassId)
+{
+ static GUID const CLSID_MyDocuments =
+ { 0x450d8fba, 0xad25, 0x11d0, {0x98, 0xa8, 0x08, 0x00, 0x36, 0x1b, 0x11, 0x03} };
+
+ TRACE ("(%p)\n", this);
+
+ if (!lpClassId)
+ return E_POINTER;
+
+ memcpy(lpClassId, &CLSID_MyDocuments, sizeof(GUID));
+
+ return S_OK;
+}
+
+HRESULT WINAPI CMyDocsFolder::Initialize(LPCITEMIDLIST pidl)
+{
+ TRACE ("(%p)->(%p)\n", this, pidl);
+
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CMyDocsFolder::GetCurFolder(LPITEMIDLIST *pidl)
+{
+ TRACE ("(%p)->(%p)\n", this, pidl);
+
+ if (!pidl) return E_POINTER;
+ *pidl = ILClone (pidlRoot);
+ return S_OK;
+}
+
+HRESULT WINAPI CMyDocsFolder::DragEnter(IDataObject *pDataObject,
+ DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
+{
+ return mFSDropTarget->DragEnter(pDataObject, dwKeyState, pt, pdwEffect);
+}
+
+HRESULT WINAPI CMyDocsFolder::DragOver(DWORD dwKeyState, POINTL pt,
+ DWORD *pdwEffect)
+{
+ return mFSDropTarget->DragOver(dwKeyState, pt, pdwEffect);
+}
+
+HRESULT WINAPI CMyDocsFolder::DragLeave()
+{
+ return mFSDropTarget->DragLeave();
+}
+
+HRESULT WINAPI CMyDocsFolder::Drop(IDataObject *pDataObject,
+ DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
+{
+ return mFSDropTarget->Drop(pDataObject, dwKeyState, pt, pdwEffect);
+}
--- /dev/null
- DWORD *pchEaten, LPITEMIDLIST *ppidl, DWORD *pdwAttributes)
+/*
+ * Network Places (Neighbourhood) folder
+ *
+ * Copyright 1997 Marcus Meissner
+ * Copyright 1998, 1999, 2002 Juergen Schmied
+ * Copyright 2003 Mike McCormack for Codeweavers
+ * Copyright 2009 Andrew Hill
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <precomp.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL (shell);
+
+/***********************************************************************
+* IShellFolder implementation
+*/
+
+static shvheader NetworkPlacesSFHeader[] = {
+ {IDS_SHV_COLUMN8, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
+ {IDS_SHV_COLUMN13, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
+ {IDS_SHV_COLUMN_WORKGROUP, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
+ {IDS_SHV_NETWORKLOCATION, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15}
+};
+
+#define COLUMN_NAME 0
+#define COLUMN_CATEGORY 1
+#define COLUMN_WORKGROUP 2
+#define COLUMN_NETLOCATION 3
+
+#define NETWORKPLACESSHELLVIEWCOLUMNS 4
+
+CNetFolder::CNetFolder()
+{
+ pidlRoot = NULL;
+}
+
+CNetFolder::~CNetFolder()
+{
+ TRACE("-- destroying IShellFolder(%p)\n", this);
+ SHFree(pidlRoot);
+}
+
+HRESULT WINAPI CNetFolder::FinalConstruct()
+{
+ pidlRoot = _ILCreateNetHood(); /* my qualified pidl */
+ if (pidlRoot == NULL)
+ return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+/**************************************************************************
+* CNetFolder::ParseDisplayName
+*/
+HRESULT WINAPI CNetFolder::ParseDisplayName(HWND hwndOwner, LPBC pbcReserved, LPOLESTR lpszDisplayName,
- HRESULT WINAPI CNetFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
++ DWORD *pchEaten, PIDLIST_RELATIVE *ppidl, DWORD *pdwAttributes)
+{
+ HRESULT hr = E_UNEXPECTED;
+
+ TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", this,
+ hwndOwner, pbcReserved, lpszDisplayName, debugstr_w (lpszDisplayName),
+ pchEaten, ppidl, pdwAttributes);
+
+ *ppidl = 0;
+ if (pchEaten)
+ *pchEaten = 0; /* strange but like the original */
+
+ TRACE("(%p)->(-- ret=0x%08x)\n", this, hr);
+
+ return hr;
+}
+
+/**************************************************************************
+* CNetFolder::EnumObjects
+*/
+HRESULT WINAPI CNetFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
+{
+ TRACE("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", this,
+ hwndOwner, dwFlags, ppEnumIDList);
+
+ *ppEnumIDList = NULL; //IEnumIDList_Constructor();
+
+ TRACE("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList);
+ return S_FALSE;
+ // return (*ppEnumIDList) ? S_OK : E_OUTOFMEMORY;
+}
+
+/**************************************************************************
+* CNetFolder::BindToObject
+*/
- HRESULT WINAPI CNetFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
++HRESULT WINAPI CNetFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, 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);
+}
+
+/**************************************************************************
+* CNetFolder::BindToStorage
+*/
- HRESULT WINAPI CNetFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
++HRESULT WINAPI CNetFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID *ppvOut)
+{
+ FIXME("(%p)->(pidl=%p,%p,%s,%p) stub\n", this,
+ pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
+
+ *ppvOut = NULL;
+ return E_NOTIMPL;
+}
+
+/**************************************************************************
+* CNetFolder::CompareIDs
+*/
+
- HRESULT WINAPI CNetFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, DWORD *rgfInOut)
++HRESULT WINAPI CNetFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
+{
+ int nReturn;
+
+ 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;
+}
+
+/**************************************************************************
+* CNetFolder::CreateViewObject
+*/
+HRESULT WINAPI CNetFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID *ppvOut)
+{
+ CComPtr<IShellView> pShellView;
+ HRESULT hr = E_INVALIDARG;
+
+ TRACE("(%p)->(hwnd=%p,%s,%p)\n", this,
+ hwndOwner, shdebugstr_guid (&riid), ppvOut);
+
+ if (!ppvOut)
+ return hr;
+
+ *ppvOut = NULL;
+
+ if (IsEqualIID(riid, IID_IDropTarget))
+ {
+ WARN("IDropTarget not implemented\n");
+ hr = E_NOTIMPL;
+ }
+ else if (IsEqualIID(riid, IID_IContextMenu))
+ {
+ 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);
+ }
+ }
+ TRACE("-- (%p)->(interface=%p)\n", this, ppvOut);
+ return hr;
+}
+
+/**************************************************************************
+* CNetFolder::GetAttributesOf
+*/
- HRESULT WINAPI CNetFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl, REFIID riid,
++HRESULT WINAPI CNetFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut)
+{
+ static const DWORD dwNethoodAttributes =
+ SFGAO_STORAGE | SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR |
+ SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER | SFGAO_CANRENAME | SFGAO_CANDELETE;
+ HRESULT hr = S_OK;
+
+ TRACE("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n", this,
+ cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
+
+ if (!rgfInOut)
+ return E_INVALIDARG;
+ if (cidl && !apidl)
+ return E_INVALIDARG;
+
+ if (*rgfInOut == 0)
+ *rgfInOut = ~0;
+
+ if(cidl == 0)
+ *rgfInOut = dwNethoodAttributes;
+ else
+ {
+ while (cidl > 0 && *apidl)
+ {
+ pdump(*apidl);
+ SHELL32_GetItemAttributes(this, *apidl, rgfInOut);
+ apidl++;
+ cidl--;
+ }
+ }
+
+ /* make sure SFGAO_VALIDATE is cleared, some apps depend on that */
+ *rgfInOut &= ~SFGAO_VALIDATE;
+
+ TRACE("-- result=0x%08x\n", *rgfInOut);
+ return hr;
+}
+
+/**************************************************************************
+* CNetFolder::GetUIObjectOf
+*
+* PARAMETERS
+* hwndOwner [in] Parent window for any output
+* cidl [in] array size
+* apidl [in] simple pidl array
+* riid [in] Requested Interface
+* prgfInOut [ ] reserved
+* ppvObject [out] Resulting Interface
+*
+*/
- HRESULT WINAPI CNetFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
++HRESULT WINAPI CNetFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, REFIID riid,
+ UINT * prgfInOut, LPVOID * ppvOut)
+{
+ LPITEMIDLIST pidl;
+ IUnknown *pObj = NULL;
+ HRESULT hr = E_INVALIDARG;
+
+ TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", this,
+ hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
+
+ if (!ppvOut)
+ return hr;
+
+ *ppvOut = NULL;
+
+ if (IsEqualIID(riid, IID_IContextMenu) && (cidl >= 1))
+ {
+ IContextMenu * pCm = NULL;
+ hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, static_cast<IShellFolder*>(this), NULL, 0, NULL, &pCm);
+ pObj = pCm;
+ }
+ else if (IsEqualIID(riid, IID_IDataObject) && (cidl >= 1))
+ {
+ IDataObject * pDo = NULL;
+ hr = IDataObject_Constructor (hwndOwner, pidlRoot, apidl, cidl, &pDo);
+ pObj = pDo;
+ }
+ 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_IDropTarget) && (cidl >= 1))
+ {
+ IDropTarget * pDt = NULL;
+ hr = this->QueryInterface(IID_PPV_ARG(IDropTarget, &pDt));
+ pObj = pDt;
+ }
+ else
+ hr = E_NOINTERFACE;
+
+ if (SUCCEEDED(hr) && !pObj)
+ hr = E_OUTOFMEMORY;
+
+ *ppvOut = pObj;
+ TRACE("(%p)->hr=0x%08x\n", this, hr);
+ return hr;
+}
+
+/**************************************************************************
+* CNetFolder::GetDisplayNameOf
+*
+*/
- HRESULT WINAPI CNetFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, /*simple pidl */
- LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut)
++HRESULT WINAPI CNetFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
+{
+ FIXME("(%p)->(pidl=%p,0x%08x,%p)\n", this, pidl, dwFlags, strRet);
+ pdump(pidl);
+
+ if (!strRet)
+ return E_INVALIDARG;
+
+ return E_NOTIMPL;
+}
+
+/**************************************************************************
+* CNetFolder::SetNameOf
+* Changes the name of a file object or subfolder, possibly changing its item
+* identifier in the process.
+*
+* PARAMETERS
+* hwndOwner [in] Owner window for output
+* pidl [in] simple pidl of item to change
+* lpszName [in] the items new display name
+* dwFlags [in] SHGNO formatting flags
+* ppidlOut [out] simple pidl returned
+*/
- HRESULT WINAPI CNetFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
++HRESULT WINAPI CNetFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, /*simple pidl */
++ LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
+{
+ FIXME("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this,
+ hwndOwner, pidl, debugstr_w (lpName), dwFlags, pPidlOut);
+ return E_FAIL;
+}
+
+HRESULT WINAPI CNetFolder::GetDefaultSearchGUID(GUID *pguid)
+{
+ FIXME("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CNetFolder::EnumSearches(IEnumExtraSearch ** ppenum)
+{
+ FIXME("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CNetFolder::GetDefaultColumn (DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
+{
+ TRACE("(%p)\n", this);
+
+ if (pSort)
+ *pSort = 0;
+ if (pDisplay)
+ *pDisplay = 0;
+
+ return S_OK;
+}
+
+HRESULT WINAPI CNetFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
+{
+ TRACE("(%p)\n", this);
+
+ if (!pcsFlags || iColumn >= NETWORKPLACESSHELLVIEWCOLUMNS)
+ return E_INVALIDARG;
+ *pcsFlags = NetworkPlacesSFHeader[iColumn].pcsFlags;
+ return S_OK;
+}
+
- HRESULT WINAPI CNetFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd)
++HRESULT WINAPI CNetFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
+{
+ FIXME("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
++HRESULT WINAPI CNetFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
+{
+ WCHAR buffer[MAX_PATH] = {0};
+ HRESULT hr = E_FAIL;
+
+ if (iColumn >= NETWORKPLACESSHELLVIEWCOLUMNS)
+ return E_FAIL;
+
+ psd->fmt = NetworkPlacesSFHeader[iColumn].fmt;
+ psd->cxChar = NetworkPlacesSFHeader[iColumn].cxChar;
+ if (pidl == NULL)
+ {
+ psd->str.uType = STRRET_WSTR;
+ if (LoadStringW(shell32_hInstance, NetworkPlacesSFHeader[iColumn].colnameid, buffer, _countof(buffer)))
+ hr = SHStrDupW(buffer, &psd->str.pOleStr);
+
+ return hr;
+ }
+
+ if (iColumn == COLUMN_NAME)
+ return GetDisplayNameOf(pidl, SHGDN_NORMAL, &psd->str);
+
+ FIXME("(%p)->(%p %i %p)\n", this, pidl, iColumn, psd);
+
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CNetFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
+{
+ FIXME("(%p)\n", this);
+
+ return E_NOTIMPL;
+}
+
+/************************************************************************
+ * CNetFolder::GetClassID
+ */
+HRESULT WINAPI CNetFolder::GetClassID(CLSID *lpClassId)
+{
+ TRACE("(%p)\n", this);
+
+ if (!lpClassId)
+ return E_POINTER;
+
+ *lpClassId = CLSID_NetworkPlaces;
+
+ return S_OK;
+}
+
+/************************************************************************
+ * CNetFolder::Initialize
+ *
+ * NOTES: it makes no sense to change the pidl
+ */
+HRESULT WINAPI CNetFolder::Initialize(LPCITEMIDLIST pidl)
+{
+ TRACE("(%p)->(%p)\n", this, pidl);
+
+ return E_NOTIMPL;
+}
+
+/**************************************************************************
+ * CNetFolder::GetCurFolder
+ */
+HRESULT WINAPI CNetFolder::GetCurFolder(LPITEMIDLIST *pidl)
+{
+ TRACE("(%p)->(%p)\n", this, pidl);
+
+ if (!pidl)
+ return E_POINTER;
+
+ *pidl = ILClone(pidlRoot);
+
+ return S_OK;
+}
--- /dev/null
- DWORD * pchEaten, LPITEMIDLIST * ppidl, DWORD * pdwAttributes)
+/*
+ * Virtual Printers Folder
+ *
+ * Copyright 1997 Marcus Meissner
+ * Copyright 1998, 1999, 2002 Juergen Schmied
+ * Copyright 2005 Huw Davies
+ * Copyright 2009 Andrew Hill
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <precomp.h>
+
+#include <winspool.h>
+
+WINE_DEFAULT_DEBUG_CHANNEL (shell);
+
+/***********************************************************************
+ * Printers_IExtractIconW implementation
+ */
+class CPrintersExtractIconW :
+ public CComObjectRootEx<CComMultiThreadModelNoCS>,
+ public IExtractIconW,
+ public IExtractIconA
+{
+ private:
+ LPITEMIDLIST pidl;
+ public:
+ CPrintersExtractIconW();
+ ~CPrintersExtractIconW();
+ HRESULT WINAPI Initialize(LPCITEMIDLIST pidl);
+
+ // IExtractIconW
+ virtual HRESULT STDMETHODCALLTYPE GetIconLocation(UINT uFlags, LPWSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags);
+ virtual HRESULT STDMETHODCALLTYPE Extract(LPCWSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize);
+
+ // IExtractIconA
+ virtual HRESULT STDMETHODCALLTYPE GetIconLocation(UINT uFlags, LPSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags);
+ virtual HRESULT STDMETHODCALLTYPE Extract(LPCSTR pszFile, UINT nIconIndex, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize);
+
+ BEGIN_COM_MAP(CPrintersExtractIconW)
+ COM_INTERFACE_ENTRY_IID(IID_IExtractIconW, IExtractIconW)
+ COM_INTERFACE_ENTRY_IID(IID_IExtractIconA, IExtractIconA)
+ END_COM_MAP()
+};
+
+static shvheader PrinterSFHeader[] = {
+ {IDS_SHV_COLUMN8, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
+ {IDS_SHV_COLUMN_DOCUMENTS , SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
+ {IDS_SHV_COLUMN_STATUS, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
+ {IDS_SHV_COLUMN_COMMENTS, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
+ {IDS_SHV_COLUMN_LOCATION, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
+ {IDS_SHV_COLUMN_MODEL, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15}
+};
+
+#define COLUMN_NAME 0
+#define COLUMN_DOCUMENTS 1
+#define COLUMN_STATUS 2
+#define COLUMN_COMMENTS 3
+#define COLUMN_LOCATION 4
+#define COLUMN_MODEL 5
+
+
+#define PrinterSHELLVIEWCOLUMNS (6)
+
+CPrintersExtractIconW::CPrintersExtractIconW()
+{
+ pidl = NULL;
+}
+
+CPrintersExtractIconW::~CPrintersExtractIconW()
+{
+ TRACE(" destroying IExtractIcon(%p)\n", this);
+ SHFree(pidl);
+}
+
+HRESULT WINAPI CPrintersExtractIconW::Initialize(LPCITEMIDLIST pidl)
+{
+ pidl = ILClone(pidl);
+
+ pdump(pidl);
+ return S_OK;
+}
+
+/**************************************************************************
+ * CPrintersExtractIconW::GetIconLocation
+ *
+ * mapping filetype to icon
+ */
+HRESULT WINAPI CPrintersExtractIconW::GetIconLocation(UINT uFlags, /* GIL_ flags */
+ LPWSTR szIconFile,
+ UINT cchMax,
+ int *piIndex,
+ UINT *pwFlags) /* returned GIL_ flags */
+{
+ TRACE("(%p) (flags=%u %p %u %p %p)\n", this, uFlags, szIconFile, cchMax, piIndex, pwFlags);
+
+ if (pwFlags)
+ *pwFlags = 0;
+
+ lstrcpynW(szIconFile, swShell32Name, cchMax);
+ *piIndex = -IDI_SHELL_PRINTERS_FOLDER; /* FIXME: other icons for default, network, print to file */
+
+ TRACE("-- %s %x\n", debugstr_w(szIconFile), *piIndex);
+ return S_OK;
+}
+
+/**************************************************************************
+ * CPrintersExtractIconW::Extract
+ */
+HRESULT WINAPI CPrintersExtractIconW::Extract(LPCWSTR pszFile,
+ UINT nIconIndex, HICON *phiconLarge,
+ HICON *phiconSmall, UINT nIconSize)
+{
+ int index;
+
+ FIXME("(%p) (file=%p index=%d %p %p size=%x) semi-stub\n", this, debugstr_w(pszFile),
+ (signed)nIconIndex, phiconLarge, phiconSmall, nIconSize);
+
+ index = SIC_GetIconIndex(pszFile, nIconIndex, 0);
+
+ if (phiconLarge)
+ *phiconLarge = ImageList_GetIcon(ShellBigIconList, index, ILD_TRANSPARENT);
+
+ if (phiconSmall)
+ *phiconSmall = ImageList_GetIcon(ShellSmallIconList, index, ILD_TRANSPARENT);
+
+ return S_OK;
+}
+
+/**************************************************************************
+ * CPrintersExtractIconW::GetIconLocation
+ */
+HRESULT WINAPI CPrintersExtractIconW::GetIconLocation(UINT uFlags,
+ LPSTR szIconFile,
+ UINT cchMax,
+ int * piIndex,
+ UINT * pwFlags)
+{
+ HRESULT ret;
+ LPWSTR lpwstrFile = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, cchMax * sizeof(WCHAR));
+
+ TRACE("(%p) (flags=%u %p %u %p %p)\n", this, uFlags, szIconFile, cchMax, piIndex, pwFlags);
+
+ ret = GetIconLocation(uFlags, lpwstrFile, cchMax, piIndex, pwFlags);
+ WideCharToMultiByte(CP_ACP, 0, lpwstrFile, -1, szIconFile, cchMax, NULL, NULL);
+ HeapFree(GetProcessHeap(), 0, lpwstrFile);
+
+ TRACE("-- %s %x\n", szIconFile, *piIndex);
+ return ret;
+}
+/**************************************************************************
+ * CPrintersExtractIconW::Extract
+ */
+HRESULT WINAPI CPrintersExtractIconW::Extract(LPCSTR pszFile,
+ UINT nIconIndex, HICON *phiconLarge,
+ HICON *phiconSmall, UINT nIconSize)
+{
+ HRESULT ret;
+ INT len = MultiByteToWideChar(CP_ACP, 0, pszFile, -1, NULL, 0);
+ LPWSTR lpwstrFile = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+
+ TRACE("(%p) (file=%p index=%u %p %p size=%u)\n", this, pszFile, nIconIndex, phiconLarge, phiconSmall, nIconSize);
+
+ MultiByteToWideChar(CP_ACP, 0, pszFile, -1, lpwstrFile, len);
+ ret = Extract(lpwstrFile, nIconIndex, phiconLarge, phiconSmall, nIconSize);
+ HeapFree(GetProcessHeap(), 0, lpwstrFile);
+ return ret;
+}
+
+/**************************************************************************
+ * IExtractIcon_Constructor
+ */
+static HRESULT WINAPI IEI_Printers_Constructor(LPCITEMIDLIST pidl, REFIID riid, IUnknown **ppv)
+{
+ CComObject<CPrintersExtractIconW> *theExtractor;
+ CComPtr<IUnknown> result;
+ HRESULT hResult;
+
+ if (ppv == NULL)
+ return E_POINTER;
+ *ppv = NULL;
+ ATLTRY (theExtractor = new CComObject<CPrintersExtractIconW>);
+ if (theExtractor == NULL)
+ return E_OUTOFMEMORY;
+ hResult = theExtractor->QueryInterface(riid, (void **)&result);
+ if (FAILED (hResult))
+ {
+ delete theExtractor;
+ return hResult;
+ }
+ hResult = theExtractor->Initialize(pidl);
+ if (FAILED (hResult))
+ return hResult;
+ *ppv = result.Detach();
+ return S_OK;
+}
+
+/***********************************************************************
+ * Printers folder implementation
+ */
+
+class CPrintersEnum: public IEnumIDListImpl
+{
+ public:
+ CPrintersEnum();
+ ~CPrintersEnum();
+ HRESULT WINAPI Initialize(HWND hwndOwner, DWORD dwFlags);
+ BOOL CreatePrintersEnumList(DWORD dwFlags);
+
+ BEGIN_COM_MAP(CPrintersEnum)
+ COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
+ END_COM_MAP()
+};
+
+CPrintersEnum::CPrintersEnum()
+{
+}
+
+CPrintersEnum::~CPrintersEnum()
+{
+}
+
+HRESULT WINAPI CPrintersEnum::Initialize(HWND hwndOwner, DWORD dwFlags)
+{
+ if (CreatePrintersEnumList(dwFlags) == FALSE)
+ return E_FAIL;
+ return S_OK;
+}
+
+static LPITEMIDLIST _ILCreatePrinterItem(PRINTER_INFO_4W *pi)
+{
+ PIDLDATA tmp;
+ LPITEMIDLIST pidl;
+ PIDLPrinterStruct * p;
+ int size0 = (char*)&tmp.u.cprinter.szName - (char*)&tmp.u.cprinter;
+ int size = size0;
+
+ tmp.type = 0x00;
+ tmp.u.cprinter.dummy = 0xFF;
+ if (pi->pPrinterName)
+ tmp.u.cprinter.offsServer = wcslen(pi->pPrinterName) + 1;
+ else
+ tmp.u.cprinter.offsServer = 1;
+
+ size += tmp.u.cprinter.offsServer * sizeof(WCHAR);
+ if (pi->pServerName)
+ size += (wcslen(pi->pServerName) + 1) * sizeof(WCHAR);
+ else
+ size += sizeof(WCHAR);
+
+ pidl = (LPITEMIDLIST)SHAlloc(size + 4);
+ if (!pidl)
+ return pidl;
+
+ pidl->mkid.cb = size + 2;
+ memcpy(pidl->mkid.abID, &tmp, 2 + size0);
+
+ p = &((PIDLDATA*)pidl->mkid.abID)->u.cprinter;
+
+ p->Attributes = pi->Attributes;
+ if (pi->pPrinterName)
+ wcscpy(p->szName, pi->pPrinterName);
+ else
+ p->szName[0] = L'\0';
+
+ if (pi->pServerName)
+ wcscpy(p->szName + p->offsServer, pi->pServerName);
+ else
+ p->szName[p->offsServer] = L'\0';
+
+ *(WORD*)((char*)pidl + (size + 2)) = 0;
+ return pidl;
+}
+
+/**************************************************************************
+ * CPrintersEnum::CreatePrintersEnumList()
+ */
+BOOL CPrintersEnum::CreatePrintersEnumList(DWORD dwFlags)
+{
+ BOOL ret = TRUE;
+
+ TRACE("(%p)->(flags=0x%08lx) \n", this, dwFlags);
+
+ /* enumerate the folders */
+ if (dwFlags & SHCONTF_NONFOLDERS)
+ {
+ DWORD needed = 0, num = 0, i;
+ PRINTER_INFO_4W *pi;
+
+ EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 4, NULL, 0, &needed, &num);
+ if (!needed)
+ return ret;
+
+ pi = (PRINTER_INFO_4W *)HeapAlloc(GetProcessHeap(), 0, needed);
+ if(!EnumPrintersW(PRINTER_ENUM_LOCAL, NULL, 4, (LPBYTE)pi, needed, &needed, &num)) {
+ HeapFree(GetProcessHeap(), 0, pi);
+ return FALSE;
+ }
+
+ for(i = 0; i < num; i++) {
+ LPITEMIDLIST pidl = _ILCreatePrinterItem(&pi[i]);
+ if (pidl)
+ {
+ if (!AddToEnumList(pidl))
+ SHFree(pidl);
+ }
+ }
+ HeapFree(GetProcessHeap(), 0, pi);
+ }
+ return ret;
+}
+
+CPrinterFolder::CPrinterFolder()
+{
+ pidlRoot = NULL;
+ dwAttributes = 0;
+ pclsid = NULL;
+}
+
+CPrinterFolder::~CPrinterFolder()
+{
+ TRACE("-- destroying IShellFolder(%p)\n", this);
+ if (pidlRoot)
+ SHFree(pidlRoot);
+}
+
+HRESULT WINAPI CPrinterFolder::FinalConstruct()
+{
+ pidlRoot = _ILCreatePrinters(); /* my qualified pidl */
+ if (pidlRoot == NULL)
+ return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+/**************************************************************************
+ * CPrinterFolder::ParseDisplayName
+ *
+ * This is E_NOTIMPL in Windows too.
+ */
+HRESULT WINAPI CPrinterFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
- HRESULT WINAPI CPrinterFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
++ DWORD *pchEaten, PIDLIST_RELATIVE *ppidl, DWORD *pdwAttributes)
+{
+ TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n",
+ this, hwndOwner, pbc, lpszDisplayName, debugstr_w(lpszDisplayName),
+ pchEaten, ppidl, pdwAttributes);
+
+ *ppidl = 0;
+ if (pchEaten)
+ *pchEaten = 0;
+
+ return E_NOTIMPL;
+}
+
+static PIDLPrinterStruct * _ILGetPrinterStruct(LPCITEMIDLIST pidl)
+{
+ LPPIDLDATA pdata = _ILGetDataPointer(pidl);
+
+ if (pdata && pdata->type == 0x00)
+ return (PIDLPrinterStruct*) & (pdata->u.cfont);
+
+ return NULL;
+}
+
+/**************************************************************************
+ * CPrinterFolder::EnumObjects
+ */
+HRESULT WINAPI CPrinterFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST * ppEnumIDList)
+{
+ CComObject<CPrintersEnum> *theEnumerator;
+ CComPtr<IEnumIDList> result;
+ HRESULT hResult;
+
+ TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", this, hwndOwner, dwFlags, ppEnumIDList);
+
+ if (ppEnumIDList == NULL)
+ return E_POINTER;
+ *ppEnumIDList = NULL;
+ ATLTRY (theEnumerator = new CComObject<CPrintersEnum>);
+ if (theEnumerator == NULL)
+ return E_OUTOFMEMORY;
+ hResult = theEnumerator->QueryInterface(IID_PPV_ARG(IEnumIDList, &result));
+ if (FAILED (hResult))
+ {
+ delete theEnumerator;
+ return hResult;
+ }
+ hResult = theEnumerator->Initialize(hwndOwner, dwFlags);
+ if (FAILED (hResult))
+ return hResult;
+ *ppEnumIDList = result.Detach();
+
+ TRACE ("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList);
+
+ return S_OK;
+}
+
+/**************************************************************************
+ * CPrinterFolder::BindToObject
+ */
- HRESULT WINAPI CPrinterFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
++HRESULT WINAPI CPrinterFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, 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);
+}
+
+/**************************************************************************
+ * ISF_Printers_fnBindToStorage
+ */
- HRESULT WINAPI CPrinterFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
++HRESULT WINAPI CPrinterFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcReserved, REFIID riid, LPVOID * ppvOut)
+{
+ FIXME ("(%p)->(pidl=%p,%p,%s,%p) stub\n",
+ this, pidl, pbcReserved, shdebugstr_guid (&riid), ppvOut);
+
+ *ppvOut = NULL;
+ return E_NOTIMPL;
+}
+
+/**************************************************************************
+ * CPrinterFolder::CompareIDs
+ */
- HRESULT WINAPI CPrinterFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, DWORD *rgfInOut)
++HRESULT WINAPI CPrinterFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
+{
+ int nReturn;
+
+ 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;
+}
+
+/**************************************************************************
+ * CPrinterFolder::CreateViewObject
+ */
+HRESULT WINAPI CPrinterFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
+{
+ CComPtr<IShellView> pShellView;
+ HRESULT hr = E_INVALIDARG;
+
+ TRACE("(%p)->(hwnd=%p,%s,%p)\n", this,
+ hwndOwner, shdebugstr_guid (&riid), ppvOut);
+
+ if (!ppvOut)
+ return hr;
+
+ *ppvOut = NULL;
+
+ if (IsEqualIID(riid, IID_IDropTarget))
+ {
+ WARN("IDropTarget not implemented\n");
+ hr = E_NOTIMPL;
+ }
+ else if(IsEqualIID(riid, IID_IContextMenu))
+ {
+ 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);
+ pShellView->Release();
+ }
+ }
+ TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
+ return hr;
+}
+
+/**************************************************************************
+ * CPrinterFolder::GetAttributesOf
+ */
- HRESULT WINAPI CPrinterFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl,
++HRESULT WINAPI CPrinterFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD *rgfInOut)
+{
+ static const DWORD dwPrintersAttributes =
+ SFGAO_HASPROPSHEET | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_CANRENAME | SFGAO_CANDELETE;
+ HRESULT hr = S_OK;
+
+ FIXME ("(%p)->(cidl=%d apidl=%p mask=0x%08lx): stub\n",
+ this, cidl, apidl, *rgfInOut);
+
+ *rgfInOut &= dwPrintersAttributes;
+
+ *rgfInOut &= ~SFGAO_VALIDATE;
+
+ TRACE ("-- result=0x%08x\n", *rgfInOut);
+ return hr;
+}
+
+/**************************************************************************
+ * CPrinterFolder::GetUIObjectOf
+ *
+ * PARAMETERS
+ * HWND hwndOwner, //[in ] Parent window for any output
+ * UINT cidl, //[in ] array size
+ * LPCITEMIDLIST* apidl, //[in ] simple pidl array
+ * REFIID riid, //[in ] Requested Interface
+ * UINT* prgfInOut, //[ ] reserved
+ * LPVOID* ppvObject) //[out] Resulting Interface
+ *
+ */
- HRESULT WINAPI CPrinterFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, LPSTRRET strRet)
++HRESULT WINAPI CPrinterFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
+ REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
+{
+ IUnknown *pObj = NULL;
+ HRESULT hr = E_INVALIDARG;
+
+ TRACE ("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n",
+ this, hwndOwner, cidl, apidl, shdebugstr_guid (&riid), prgfInOut, ppvOut);
+
+ if (!ppvOut)
+ return hr;
+
+ *ppvOut = NULL;
+
+ if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW)) && cidl == 1)
+ hr = IEI_Printers_Constructor(apidl[0], riid, &pObj);
+ else
+ hr = E_NOINTERFACE;
+
+ if (SUCCEEDED(hr) && !pObj)
+ hr = E_OUTOFMEMORY;
+
+ *ppvOut = pObj;
+ TRACE ("(%p)->hr=0x%08lx\n", this, hr);
+ return hr;
+}
+
+/**************************************************************************
+ * CPrinterFolder::GetDisplayNameOf
+ *
+ */
- HRESULT WINAPI CPrinterFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, /* simple pidl */
- LPCOLESTR lpName, DWORD dwFlags, LPITEMIDLIST * pPidlOut)
++HRESULT WINAPI CPrinterFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFlags, LPSTRRET strRet)
+{
+ LPWSTR pszName;
+ PIDLPrinterStruct * p;
+
+ TRACE ("(%p)->(pidl=%p,0x%08lx,%p)\n", this, pidl, dwFlags, strRet);
+ pdump (pidl);
+
+ if (!strRet)
+ {
+ WARN("no strRet\n");
+ return E_INVALIDARG;
+ }
+
+ if (!pidl->mkid.cb)
+ {
+ pszName = (LPWSTR)CoTaskMemAlloc(MAX_PATH * sizeof(WCHAR));
+ if (!pszName)
+ return E_OUTOFMEMORY;
+
+ if (LoadStringW(shell32_hInstance, IDS_PRINTERS, pszName, MAX_PATH))
+ {
+ pszName[MAX_PATH-1] = L'\0';
+ strRet->uType = STRRET_WSTR;
+ strRet->pOleStr = pszName;
+ return S_OK;
+ }
+ CoTaskMemFree(pszName);
+ return E_FAIL;
+ }
+
+ p = _ILGetPrinterStruct(pidl);
+ if (!p)
+ {
+ WARN("no printer struct\n");
+ return E_INVALIDARG;
+ }
+ strRet->pOleStr = (LPWSTR)SHAlloc(p->offsServer * sizeof(WCHAR));
+ if (!strRet->pOleStr)
+ return E_OUTOFMEMORY;
+
+ memcpy((LPVOID)strRet->pOleStr, (LPVOID)p->szName, p->offsServer * sizeof(WCHAR));
+ TRACE("ret %s\n", debugstr_w(strRet->pOleStr));
+
+ return S_OK;
+}
+
+/**************************************************************************
+ * CPrinterFolder::SetNameOf
+ * Changes the name of a file object or subfolder, possibly changing its item
+ * identifier in the process.
+ *
+ * PARAMETERS
+ * HWND hwndOwner, //[in ] Owner window for output
+ * LPCITEMIDLIST pidl, //[in ] simple pidl of item to change
+ * LPCOLESTR lpszName, //[in ] the items new display name
+ * DWORD dwFlags, //[in ] SHGNO formatting flags
+ * LPITEMIDLIST* ppidlOut) //[out] simple pidl returned
+ */
- HRESULT WINAPI CPrinterFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
++HRESULT WINAPI CPrinterFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl, /* simple pidl */
++ LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
+{
+ FIXME("(%p)->(%p,pidl=%p,%s,%lu,%p)\n", this, hwndOwner, pidl,
+ debugstr_w (lpName), dwFlags, pPidlOut);
+
+ return E_FAIL;
+}
+
+HRESULT WINAPI CPrinterFolder::GetDefaultSearchGUID(GUID *pguid)
+{
+ FIXME("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CPrinterFolder::EnumSearches(IEnumExtraSearch **ppenum)
+{
+ FIXME("(%p)\n", this);
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CPrinterFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
+{
+ if (pSort)
+ *pSort = 0;
+ if (pDisplay)
+ *pDisplay = 0;
+
+ return S_OK;
+}
+
+HRESULT WINAPI CPrinterFolder::GetDefaultColumnState(UINT iColumn, DWORD *pcsFlags)
+{
+ if (!pcsFlags || iColumn >= PrinterSHELLVIEWCOLUMNS)
+ return E_INVALIDARG;
+ *pcsFlags = PrinterSFHeader[iColumn].pcsFlags;
+ return S_OK;
+
+}
+
- HRESULT WINAPI CPrinterFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *psd)
++HRESULT WINAPI CPrinterFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
+{
+ FIXME("(%p): stub\n", this);
+
+ return E_NOTIMPL;
+}
+
++HRESULT WINAPI CPrinterFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
+{
+ WCHAR buffer[MAX_PATH] = {0};
+ HRESULT hr = E_FAIL;
+
+ TRACE("(%p)->(%p %i %p): stub\n", this, pidl, iColumn, psd);
+
+ if (iColumn >= PrinterSHELLVIEWCOLUMNS)
+ return E_FAIL;
+
+ psd->fmt = PrinterSFHeader[iColumn].fmt;
+ psd->cxChar = PrinterSFHeader[iColumn].cxChar;
+ if (pidl == NULL)
+ {
+ psd->str.uType = STRRET_WSTR;
+ if (LoadStringW(shell32_hInstance, PrinterSFHeader[iColumn].colnameid, buffer, MAX_PATH))
+ hr = SHStrDupW(buffer, &psd->str.pOleStr);
+
+ return hr;
+ }
+
+ if (iColumn == COLUMN_NAME)
+ {
+ psd->str.uType = STRRET_WSTR;
+ return GetDisplayNameOf(pidl, SHGDN_NORMAL, &psd->str);
+ }
+
+ psd->str.uType = STRRET_CSTR;
+ psd->str.cStr[0] = '\0';
+
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CPrinterFolder::MapColumnToSCID(UINT column, SHCOLUMNID *pscid)
+{
+ FIXME ("(%p): stub\n", this);
+ return E_NOTIMPL;
+}
+
+/************************************************************************
+ * CPrinterFolder::GetClassID
+ */
+HRESULT WINAPI CPrinterFolder::GetClassID(CLSID *lpClassId)
+{
+ TRACE ("(%p)\n", this);
+
+ *lpClassId = CLSID_Printers;
+
+ return S_OK;
+}
+
+/************************************************************************
+ * CPrinterFolder::Initialize
+ */
+HRESULT WINAPI CPrinterFolder::Initialize(LPCITEMIDLIST pidl)
+{
+ if (pidlRoot)
+ SHFree((LPVOID)pidlRoot);
+
+ pidlRoot = ILClone(pidl);
+ return S_OK;
+}
+
+/**************************************************************************
+ * CPrinterFolder::GetCurFolder
+ */
+HRESULT WINAPI CPrinterFolder::GetCurFolder(LPITEMIDLIST * pidl)
+{
+ TRACE ("(%p)->(%p)\n", this, pidl);
+
+ *pidl = ILClone (pidlRoot);
+ return S_OK;
+}
--- /dev/null
- LPOLESTR pszDisplayName, ULONG *pchEaten, LPITEMIDLIST *ppidl,
+/*
+ * Trash virtual folder support. The trashing engine is implemented in trash.c
+ *
+ * Copyright (C) 2006 Mikolaj Zalewski
+ * Copyright (C) 2009 Andrew Hill
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <precomp.h>
+
+#include <ntquery.h>
+
+#define MAX_PROPERTY_SHEET_PAGE 32
+
+WINE_DEFAULT_DEBUG_CHANNEL(CRecycleBin);
+
+typedef struct
+{
+ int column_name_id;
+ const GUID *fmtId;
+ DWORD pid;
+ int pcsFlags;
+ int fmt;
+ int cxChars;
+} columninfo;
+
+static const columninfo RecycleBinColumns[] =
+{
+ {IDS_SHV_COLUMN1, &FMTID_Storage, PID_STG_NAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 30},
+ {IDS_SHV_COLUMN_DELFROM, &FMTID_Displaced, PID_DISPLACED_FROM, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 30},
+ {IDS_SHV_COLUMN_DELDATE, &FMTID_Displaced, PID_DISPLACED_DATE, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 20},
+ {IDS_SHV_COLUMN2, &FMTID_Storage, PID_STG_SIZE, SHCOLSTATE_TYPE_INT | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 20},
+ {IDS_SHV_COLUMN3, &FMTID_Storage, PID_STG_STORAGETYPE, SHCOLSTATE_TYPE_INT | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 20},
+ {IDS_SHV_COLUMN4, &FMTID_Storage, PID_STG_WRITETIME, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 20},
+ /* {"creation time", &FMTID_Storage, PID_STG_CREATETIME, SHCOLSTATE_TYPE_DATE, LVCFMT_LEFT, 20}, */
+ /* {"attribs", &FMTID_Storage, PID_STG_ATTRIBUTES, SHCOLSTATE_TYPE_STR, LVCFMT_LEFT, 20}, */
+};
+
+#define COLUMN_NAME 0
+#define COLUMN_DELFROM 1
+#define COLUMN_DATEDEL 2
+#define COLUMN_SIZE 3
+#define COLUMN_TYPE 4
+#define COLUMN_MTIME 5
+
+#define COLUMNS_COUNT 6
+
+/*
+ * Recycle Bin folder
+ */
+
+class CRecycleBinEnum :
+ public IEnumIDListImpl
+{
+ private:
+ public:
+ CRecycleBinEnum();
+ ~CRecycleBinEnum();
+ HRESULT WINAPI Initialize(DWORD dwFlags);
+ static BOOL WINAPI CBEnumRecycleBin(IN PVOID Context, IN HANDLE hDeletedFile);
+ BOOL WINAPI CBEnumRecycleBin(IN HANDLE hDeletedFile);
+
+ BEGIN_COM_MAP(CRecycleBinEnum)
+ COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
+ END_COM_MAP()
+};
+
+class CRecycleBinItemContextMenu :
+ public CComObjectRootEx<CComMultiThreadModelNoCS>,
+ public IContextMenu2
+{
+ private:
+ LPITEMIDLIST apidl;
+ public:
+ CRecycleBinItemContextMenu();
+ ~CRecycleBinItemContextMenu();
+ HRESULT WINAPI Initialize(LPCITEMIDLIST pidl);
+
+ // IContextMenu
+ virtual HRESULT WINAPI QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
+ virtual HRESULT WINAPI InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi);
+ virtual HRESULT WINAPI GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen);
+
+ // IContextMenu2
+ virtual HRESULT WINAPI HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+ BEGIN_COM_MAP(CRecycleBinItemContextMenu)
+ COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
+ COM_INTERFACE_ENTRY_IID(IID_IContextMenu2, IContextMenu2)
+ END_COM_MAP()
+};
+
+typedef struct
+{
+ PIDLRecycleStruct *pFileDetails;
+ HANDLE hDeletedFile;
+ BOOL bFound;
+} SEARCH_CONTEXT, *PSEARCH_CONTEXT;
+
+typedef struct
+{
+ DWORD dwNukeOnDelete;
+ DWORD dwSerial;
+ DWORD dwMaxCapacity;
+} DRIVE_ITEM_CONTEXT, *PDRIVE_ITEM_CONTEXT;
+
+BOOL WINAPI CBSearchRecycleBin(IN PVOID Context, IN HANDLE hDeletedFile)
+{
+ PSEARCH_CONTEXT pContext = (PSEARCH_CONTEXT)Context;
+
+ PDELETED_FILE_DETAILS_W pFileDetails;
+ DWORD dwSize;
+ BOOL ret;
+
+ if (!GetDeletedFileDetailsW(hDeletedFile,
+ 0,
+ NULL,
+ &dwSize) &&
+ GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ {
+ ERR("GetDeletedFileDetailsW failed\n");
+ return FALSE;
+ }
+
+ pFileDetails = (DELETED_FILE_DETAILS_W *)SHAlloc(dwSize);
+ if (!pFileDetails)
+ {
+ ERR("No memory\n");
+ return FALSE;
+ }
+
+ if (!GetDeletedFileDetailsW(hDeletedFile,
+ dwSize,
+ pFileDetails,
+ NULL))
+ {
+ ERR("GetDeletedFileDetailsW failed\n");
+ SHFree(pFileDetails);
+ return FALSE;
+ }
+
+ ret = memcmp(pFileDetails, pContext->pFileDetails, dwSize);
+ if (!ret)
+ {
+ pContext->hDeletedFile = hDeletedFile;
+ pContext->bFound = TRUE;
+ }
+ else
+ CloseRecycleBinHandle(hDeletedFile);
+
+ SHFree(pFileDetails);
+ return ret;
+}
+
+static PIDLRecycleStruct * _ILGetRecycleStruct(LPCITEMIDLIST pidl)
+{
+ LPPIDLDATA pdata = _ILGetDataPointer(pidl);
+
+ if (pdata && pdata->type == 0x00)
+ return (PIDLRecycleStruct*) & (pdata->u.crecycle);
+
+ return NULL;
+}
+
+CRecycleBinEnum::CRecycleBinEnum()
+{
+}
+
+CRecycleBinEnum::~CRecycleBinEnum()
+{
+}
+
+HRESULT WINAPI CRecycleBinEnum::Initialize(DWORD dwFlags)
+{
+ static LPCWSTR szDrive = L"C:\\";
+
+ if (dwFlags & SHCONTF_NONFOLDERS)
+ {
+ TRACE("Starting Enumeration\n");
+
+ if (!EnumerateRecycleBinW(szDrive /* FIXME */ , CBEnumRecycleBin, (PVOID)this))
+ {
+ WARN("Error: EnumerateCRecycleBinW failed\n");
+ return E_FAIL;
+ }
+ }
+ else
+ {
+ // do nothing
+ }
+ return S_OK;
+}
+
+static LPITEMIDLIST _ILCreateRecycleItem(PDELETED_FILE_DETAILS_W pFileDetails)
+{
+ PIDLDATA tmp;
+ LPITEMIDLIST pidl;
+ PIDLRecycleStruct * p;
+ int size0 = (char*)&tmp.u.crecycle.szName - (char*)&tmp.u.crecycle;
+ int size = size0;
+
+ tmp.type = 0x00;
+ size += (wcslen(pFileDetails->FileName) + 1) * sizeof(WCHAR);
+
+ pidl = (LPITEMIDLIST)SHAlloc(size + 4);
+ if (!pidl)
+ return pidl;
+
+ pidl->mkid.cb = size + 2;
+ memcpy(pidl->mkid.abID, &tmp, 2 + size0);
+
+ p = &((PIDLDATA*)pidl->mkid.abID)->u.crecycle;
+ RtlCopyMemory(p, pFileDetails, sizeof(DELETED_FILE_DETAILS_W));
+ wcscpy(p->szName, pFileDetails->FileName);
+ *(WORD*)((char*)pidl + (size + 2)) = 0;
+ return pidl;
+}
+
+BOOL WINAPI CRecycleBinEnum::CBEnumRecycleBin(IN PVOID Context, IN HANDLE hDeletedFile)
+{
+ return static_cast<CRecycleBinEnum *>(Context)->CBEnumRecycleBin(hDeletedFile);
+}
+
+BOOL WINAPI CRecycleBinEnum::CBEnumRecycleBin(IN HANDLE hDeletedFile)
+{
+ PDELETED_FILE_DETAILS_W pFileDetails;
+ DWORD dwSize;
+ LPITEMIDLIST pidl = NULL;
+ BOOL ret;
+
+ if (!GetDeletedFileDetailsW(hDeletedFile,
+ 0,
+ NULL,
+ &dwSize) &&
+ GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ {
+ ERR("GetDeletedFileDetailsW failed\n");
+ return FALSE;
+ }
+
+ pFileDetails = (DELETED_FILE_DETAILS_W *)SHAlloc(dwSize);
+ if (!pFileDetails)
+ {
+ ERR("No memory\n");
+ return FALSE;
+ }
+
+ if (!GetDeletedFileDetailsW(hDeletedFile,
+ dwSize,
+ pFileDetails,
+ NULL))
+ {
+ ERR("GetDeletedFileDetailsW failed\n");
+ SHFree(pFileDetails);
+ return FALSE;
+ }
+
+ pidl = _ILCreateRecycleItem(pFileDetails);
+ if (!pidl)
+ {
+ SHFree(pFileDetails);
+ return FALSE;
+ }
+
+ ret = AddToEnumList(pidl);
+
+ if (!ret)
+ SHFree(pidl);
+ SHFree(pFileDetails);
+ TRACE("Returning %d\n", ret);
+ CloseRecycleBinHandle(hDeletedFile);
+ return ret;
+}
+
+/**************************************************************************
+* IContextMenu2 Bitbucket Item Implementation
+*/
+
+CRecycleBinItemContextMenu::CRecycleBinItemContextMenu()
+{
+ apidl = NULL;
+}
+
+CRecycleBinItemContextMenu::~CRecycleBinItemContextMenu()
+{
+ ILFree(apidl);
+}
+
+HRESULT WINAPI CRecycleBinItemContextMenu::Initialize(LPCITEMIDLIST pidl)
+{
+ apidl = ILClone(pidl);
+ if (apidl == NULL)
+ return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+HRESULT WINAPI CRecycleBinItemContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
+{
+ WCHAR szBuffer[30] = {0};
+ ULONG Count = 1;
+
+ TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n", this, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
+
+ if (LoadStringW(shell32_hInstance, IDS_RESTORE, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
+ {
+ szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
+ _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count, MFT_STRING, szBuffer, MFS_ENABLED);
+ Count++;
+ }
+
+ if (LoadStringW(shell32_hInstance, IDS_CUT, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
+ {
+ _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED);
+ szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
+ _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_STRING, szBuffer, MFS_ENABLED);
+ }
+
+ if (LoadStringW(shell32_hInstance, IDS_DELETE, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
+ {
+ szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
+ _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED);
+ _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_STRING, szBuffer, MFS_ENABLED);
+ }
+
+ if (LoadStringW(shell32_hInstance, IDS_PROPERTIES, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
+ {
+ szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
+ _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED);
+ _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count, MFT_STRING, szBuffer, MFS_DEFAULT);
+ }
+
+ return MAKE_HRESULT(SEVERITY_SUCCESS, 0, Count);
+}
+
+HRESULT WINAPI CRecycleBinItemContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
+{
+ SEARCH_CONTEXT Context;
+ static LPCWSTR szDrive = L"C:\\";
+
+ TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n", this, lpcmi, lpcmi->lpVerb, lpcmi->hwnd);
+
+ if (lpcmi->lpVerb == MAKEINTRESOURCEA(1) || lpcmi->lpVerb == MAKEINTRESOURCEA(5))
+ {
+ Context.pFileDetails = _ILGetRecycleStruct(apidl);
+ Context.bFound = FALSE;
+
+ EnumerateRecycleBinW(szDrive, CBSearchRecycleBin, (PVOID)&Context);
+ if (!Context.bFound)
+ return E_FAIL;
+
+ if (lpcmi->lpVerb == MAKEINTRESOURCEA(1))
+ {
+ /* restore file */
+ if (RestoreFile(Context.hDeletedFile))
+ return S_OK;
+ else
+ return E_FAIL;
+ }
+ else
+ {
+ DeleteFileHandleToRecycleBin(Context.hDeletedFile);
+ return E_NOTIMPL;
+ }
+ }
+ else if (lpcmi->lpVerb == MAKEINTRESOURCEA(3))
+ {
+ FIXME("implement cut\n");
+ return E_NOTIMPL;
+ }
+ else if (lpcmi->lpVerb == MAKEINTRESOURCEA(7))
+ {
+ FIXME("implement properties\n");
+ return E_NOTIMPL;
+ }
+
+ return S_OK;
+}
+
+HRESULT WINAPI CRecycleBinItemContextMenu::GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen)
+{
+ TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n", this, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
+
+ return E_FAIL;
+}
+
+HRESULT WINAPI CRecycleBinItemContextMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ TRACE("CRecycleBin_IContextMenu2Item_HandleMenuMsg (%p)->(msg=%x wp=%lx lp=%lx)\n", this, uMsg, wParam, lParam);
+
+ return E_NOTIMPL;
+}
+
+static HRESULT WINAPI CRecycleBinItemContextMenuConstructor(REFIID riid, LPCITEMIDLIST pidl, LPVOID *ppv)
+{
+ CComObject<CRecycleBinItemContextMenu> *theMenu;
+ CComPtr<IUnknown> result;
+ HRESULT hResult;
+
+ TRACE("%s\n", shdebugstr_guid(&riid));
+
+ if (ppv == NULL)
+ return E_POINTER;
+ *ppv = NULL;
+ ATLTRY(theMenu = new CComObject<CRecycleBinItemContextMenu>);
+ if (theMenu == NULL)
+ return E_OUTOFMEMORY;
+ hResult = theMenu->QueryInterface(riid, (void **)&result);
+ if (FAILED(hResult))
+ {
+ delete theMenu;
+ return hResult;
+ }
+ hResult = theMenu->Initialize(pidl);
+ if (FAILED(hResult))
+ return hResult;
+ *ppv = result.Detach();
+ TRACE ("--(%p)\n", *ppv);
+ return S_OK;
+}
+
+/**************************************************************************
+* registers clipboardformat once
+*/
+void CRecycleBin::SF_RegisterClipFmt()
+{
+ TRACE ("(%p)\n", this);
+
+ if (!cfShellIDList)
+ cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
+}
+
+CRecycleBin::CRecycleBin()
+{
+ pidl = NULL;
+ iIdEmpty = 0;
+ cfShellIDList = 0;
+ SF_RegisterClipFmt();
+ fAcceptFmt = FALSE;
+}
+
+CRecycleBin::~CRecycleBin()
+{
+ /* InterlockedDecrement(&objCount);*/
+ SHFree(pidl);
+}
+
+/*************************************************************************
+ * RecycleBin IPersistFolder2 interface
+ */
+
+HRESULT WINAPI CRecycleBin::GetClassID(CLSID *pClassID)
+{
+ TRACE("(%p, %p)\n", this, pClassID);
+ if (pClassID == NULL)
+ return E_INVALIDARG;
+ memcpy(pClassID, &CLSID_RecycleBin, sizeof(CLSID));
+ return S_OK;
+}
+
+HRESULT WINAPI CRecycleBin::Initialize(LPCITEMIDLIST pidl)
+{
+ TRACE("(%p, %p)\n", this, pidl);
+
+ SHFree((LPVOID)this->pidl);
+ this->pidl = ILClone(pidl);
+ if (this->pidl == NULL)
+ return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+HRESULT WINAPI CRecycleBin::GetCurFolder(LPITEMIDLIST *ppidl)
+{
+ TRACE("\n");
+ *ppidl = ILClone(pidl);
+ return S_OK;
+}
+
+/*************************************************************************
+ * RecycleBin IShellFolder2 interface
+ */
+
+HRESULT WINAPI CRecycleBin::ParseDisplayName(HWND hwnd, LPBC pbc,
- HRESULT WINAPI CRecycleBin::BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
++ LPOLESTR pszDisplayName, ULONG *pchEaten, PIDLIST_RELATIVE *ppidl,
+ ULONG *pdwAttributes)
+{
+ FIXME("stub\n");
+ return E_NOTIMPL;
+}
+
+
+PDELETED_FILE_DETAILS_W
+UnpackDetailsFromPidl(LPCITEMIDLIST pidl)
+{
+ return (PDELETED_FILE_DETAILS_W)&pidl->mkid.abID;
+}
+
+HRESULT WINAPI CRecycleBin::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
+{
+ CComObject<CRecycleBinEnum> *theEnumerator;
+ CComPtr<IEnumIDList> result;
+ HRESULT hResult;
+
+ TRACE ("(%p)->(HWND=%p flags=0x%08x pplist=%p)\n", this, hwndOwner, dwFlags, ppEnumIDList);
+
+ if (ppEnumIDList == NULL)
+ return E_POINTER;
+ *ppEnumIDList = NULL;
+ ATLTRY (theEnumerator = new CComObject<CRecycleBinEnum>);
+ if (theEnumerator == NULL)
+ return E_OUTOFMEMORY;
+ hResult = theEnumerator->QueryInterface(IID_PPV_ARG(IEnumIDList, &result));
+ if (FAILED (hResult))
+ {
+ delete theEnumerator;
+ return hResult;
+ }
+ hResult = theEnumerator->Initialize(dwFlags);
+ if (FAILED (hResult))
+ return hResult;
+ *ppEnumIDList = result.Detach();
+
+ TRACE ("-- (%p)->(new ID List: %p)\n", this, *ppEnumIDList);
+
+ return S_OK;
+}
+
- HRESULT WINAPI CRecycleBin::BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
++HRESULT WINAPI CRecycleBin::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbc, REFIID riid, void **ppv)
+{
+ FIXME("(%p, %p, %p, %s, %p) - stub\n", this, pidl, pbc, debugstr_guid(&riid), ppv);
+ return E_NOTIMPL;
+}
+
- HRESULT WINAPI CRecycleBin::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
++HRESULT WINAPI CRecycleBin::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbc, REFIID riid, void **ppv)
+{
+ FIXME("(%p, %p, %p, %s, %p) - stub\n", this, pidl, pbc, debugstr_guid(&riid), ppv);
+ return E_NOTIMPL;
+}
+
- HRESULT WINAPI CRecycleBin::GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl,
++HRESULT WINAPI CRecycleBin::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
+{
+ /* TODO */
+ TRACE("(%p, %p, %p, %p)\n", this, (void *)lParam, pidl1, pidl2);
+ if (pidl1->mkid.cb != pidl2->mkid.cb)
+ return MAKE_HRESULT(SEVERITY_SUCCESS, 0, pidl1->mkid.cb - pidl2->mkid.cb);
+ return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (unsigned short)memcmp(pidl1->mkid.abID, pidl2->mkid.abID, pidl1->mkid.cb));
+}
+
+HRESULT WINAPI CRecycleBin::CreateViewObject(HWND hwndOwner, REFIID riid, void **ppv)
+{
+ CComPtr<IShellView> pShellView;
+ HRESULT hr = E_NOINTERFACE;
+
+ TRACE("(%p, %p, %s, %p)\n", this, hwndOwner, debugstr_guid(&riid), ppv);
+
+ if (!ppv)
+ return hr;
+
+ *ppv = NULL;
+
+ if (IsEqualIID (riid, IID_IDropTarget))
+ {
+ hr = this->QueryInterface (IID_IDropTarget, ppv);
+ }
+ else if (IsEqualIID (riid, IID_IContextMenu) || IsEqualIID (riid, IID_IContextMenu2))
+ {
+ hr = this->QueryInterface(riid, ppv);
+ }
+ else if (IsEqualIID (riid, IID_IShellView))
+ {
+ hr = IShellView_Constructor ((IShellFolder *)this, &pShellView);
+ if (pShellView)
+ {
+ hr = pShellView->QueryInterface(riid, ppv);
+ }
+ }
+ else
+ return hr;
+ TRACE ("-- (%p)->(interface=%p)\n", this, ppv);
+ return hr;
+
+}
+
- HRESULT WINAPI CRecycleBin::GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl,
++HRESULT WINAPI CRecycleBin::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
+ SFGAOF *rgfInOut)
+{
+ TRACE("(%p, %d, {%p, ...}, {%x})\n", this, cidl, apidl ? apidl[0] : NULL, (unsigned int)*rgfInOut);
+ *rgfInOut &= SFGAO_FOLDER|SFGAO_DROPTARGET|SFGAO_HASPROPSHEET|SFGAO_CANLINK;
+ return S_OK;
+}
+
- HRESULT WINAPI CRecycleBin::GetDisplayNameOf(LPCITEMIDLIST pidl, SHGDNF uFlags, STRRET *pName)
++HRESULT WINAPI CRecycleBin::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
+ REFIID riid, UINT *prgfInOut, void **ppv)
+{
+ IUnknown *pObj = NULL;
+ HRESULT hr = E_INVALIDARG;
+
+ TRACE ("(%p)->(%p,%u,apidl=%p, %p %p)\n", this,
+ hwndOwner, cidl, apidl, prgfInOut, ppv);
+
+ if (!ppv)
+ return hr;
+
+ *ppv = NULL;
+
+ if ((IsEqualIID (riid, IID_IContextMenu) || IsEqualIID(riid, IID_IContextMenu2)) && (cidl >= 1))
+ {
+ hr = CRecycleBinItemContextMenuConstructor(riid, apidl[0], (void **)&pObj);
+ }
+ else if (IsEqualIID (riid, IID_IDropTarget) && (cidl == 1))
+ {
+ IDropTarget * pDt = NULL;
+ hr = this->QueryInterface(IID_PPV_ARG(IDropTarget, &pDt));
+ pObj = pDt;
+ }
+ else
+ hr = E_NOINTERFACE;
+
+ if (SUCCEEDED(hr) && !pObj)
+ hr = E_OUTOFMEMORY;
+
+ *ppv = pObj;
+ TRACE ("(%p)->hr=0x%08x\n", this, hr);
+ return hr;
+}
+
- HRESULT WINAPI CRecycleBin::SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR pszName,
- SHGDNF uFlags, LPITEMIDLIST *ppidlOut)
++HRESULT WINAPI CRecycleBin::GetDisplayNameOf(PCUITEMID_CHILD pidl, SHGDNF uFlags, STRRET *pName)
+{
+ PIDLRecycleStruct *pFileDetails;
+ LPWSTR pFileName;
+
+ TRACE("(%p, %p, %x, %p)\n", this, pidl, (unsigned int)uFlags, pName);
+
+
+ if (_ILIsBitBucket (pidl))
+ {
+ WCHAR pszPath[100];
+
+ if (HCR_GetClassNameW(CLSID_RecycleBin, pszPath, MAX_PATH))
+ {
+ pName->uType = STRRET_WSTR;
+ pName->pOleStr = StrDupW(pszPath);
+ return S_OK;
+ }
+ }
+
+ pFileDetails = _ILGetRecycleStruct(pidl);
+ if (!pFileDetails)
+ {
+ pName->cStr[0] = 0;
+ pName->uType = STRRET_CSTR;
+ return E_INVALIDARG;
+ }
+
+ pFileName = wcsrchr(pFileDetails->szName, L'\\');
+ if (!pFileName)
+ {
+ pName->cStr[0] = 0;
+ pName->uType = STRRET_CSTR;
+ return E_UNEXPECTED;
+ }
+
+ pName->pOleStr = StrDupW(pFileName + 1);
+ if (pName->pOleStr == NULL)
+ return E_OUTOFMEMORY;
+
+ pName->uType = STRRET_WSTR;
+ return S_OK;
+}
+
- HRESULT WINAPI CRecycleBin::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
++HRESULT WINAPI CRecycleBin::SetNameOf(HWND hwnd, PCUITEMID_CHILD pidl, LPCOLESTR pszName,
++ SHGDNF uFlags, PITEMID_CHILD *ppidlOut)
+{
+ TRACE("\n");
+ return E_FAIL; /* not supported */
+}
+
+HRESULT WINAPI CRecycleBin::GetDefaultSearchGUID(GUID *pguid)
+{
+ FIXME("stub\n");
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CRecycleBin::EnumSearches(IEnumExtraSearch **ppEnum)
+{
+ FIXME("stub\n");
+ *ppEnum = NULL;
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CRecycleBin::GetDefaultColumn(DWORD dwReserved, ULONG *pSort, ULONG *pDisplay)
+{
+ TRACE("(%p, %x, %p, %p)\n", this, (unsigned int)dwReserved, pSort, pDisplay);
+ *pSort = 0;
+ *pDisplay = 0;
+ return S_OK;
+}
+
+HRESULT WINAPI CRecycleBin::GetDefaultColumnState(UINT iColumn, SHCOLSTATEF *pcsFlags)
+{
+ TRACE("(%p, %d, %p)\n", this, iColumn, pcsFlags);
+ if (iColumn >= COLUMNS_COUNT)
+ return E_INVALIDARG;
+ *pcsFlags = RecycleBinColumns[iColumn].pcsFlags;
+ return S_OK;
+}
+
- HRESULT WINAPI CRecycleBin::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, LPSHELLDETAILS pDetails)
++HRESULT WINAPI CRecycleBin::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv)
+{
+ FIXME("stub\n");
+ return E_NOTIMPL;
+}
+
+static HRESULT FormatDateTime(LPWSTR buffer, int size, FILETIME * ft)
+{
+ FILETIME lft;
+ SYSTEMTIME time;
+ int ret;
+
+ FileTimeToLocalFileTime(ft, &lft);
+ FileTimeToSystemTime(&lft, &time);
+
+ ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &time, NULL, buffer, size);
+ if (ret > 0 && ret < size)
+ {
+ /* Append space + time without seconds */
+ buffer[ret-1] = ' ';
+ GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &time, NULL, &buffer[ret], size - ret);
+ }
+
+ return (ret != 0 ? E_FAIL : S_OK);
+}
+
- pDataObject->AddRef();
- SHCreateThread(DoDeleteThreadProc, pDataObject, NULL, NULL);
++HRESULT WINAPI CRecycleBin::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, LPSHELLDETAILS pDetails)
+{
+ PIDLRecycleStruct * pFileDetails;
+ WCHAR buffer[MAX_PATH];
+ WCHAR szTypeName[100];
+ LPWSTR pszBackslash;
+ UINT Length;
+
+ TRACE("(%p, %p, %d, %p)\n", this, pidl, iColumn, pDetails);
+ if (iColumn >= COLUMNS_COUNT)
+ return E_FAIL;
+ pDetails->fmt = RecycleBinColumns[iColumn].fmt;
+ pDetails->cxChar = RecycleBinColumns[iColumn].cxChars;
+ if (pidl == NULL)
+ {
+ pDetails->str.uType = STRRET_WSTR;
+ LoadStringW(shell32_hInstance, RecycleBinColumns[iColumn].column_name_id, buffer, MAX_PATH);
+ return SHStrDupW(buffer, &pDetails->str.pOleStr);
+ }
+
+ if (iColumn == COLUMN_NAME)
+ return GetDisplayNameOf(pidl, SHGDN_NORMAL, &pDetails->str);
+
+ pFileDetails = _ILGetRecycleStruct(pidl);
+ switch (iColumn)
+ {
+ case COLUMN_DATEDEL:
+ FormatDateTime(buffer, MAX_PATH, &pFileDetails->DeletionTime);
+ break;
+ case COLUMN_DELFROM:
+ pszBackslash = wcsrchr(pFileDetails->szName, L'\\');
+ Length = (pszBackslash - pFileDetails->szName);
+ memcpy((LPVOID)buffer, pFileDetails->szName, Length * sizeof(WCHAR));
+ buffer[Length] = L'\0';
+ break;
+ case COLUMN_SIZE:
+ StrFormatKBSizeW(pFileDetails->FileSize.QuadPart, buffer, MAX_PATH);
+ break;
+ case COLUMN_MTIME:
+ FormatDateTime(buffer, MAX_PATH, &pFileDetails->LastModification);
+ break;
+ case COLUMN_TYPE:
+ szTypeName[0] = L'\0';
+ wcscpy(buffer, PathFindExtensionW(pFileDetails->szName));
+ if (!( HCR_MapTypeToValueW(buffer, buffer, sizeof(buffer) / sizeof(WCHAR), TRUE) &&
+ HCR_MapTypeToValueW(buffer, szTypeName, sizeof(szTypeName) / sizeof(WCHAR), FALSE )))
+ {
+ wcscpy (szTypeName, PathFindExtensionW(pFileDetails->szName));
+ wcscat(szTypeName, L"-");
+ Length = wcslen(szTypeName);
+ if (LoadStringW(shell32_hInstance, IDS_SHV_COLUMN1, &szTypeName[Length], (sizeof(szTypeName) / sizeof(WCHAR)) - Length))
+ szTypeName[(sizeof(szTypeName)/sizeof(WCHAR))-1] = L'\0';
+ }
+ pDetails->str.uType = STRRET_WSTR;
+ return SHStrDupW(szTypeName, &pDetails->str.pOleStr);
+ break;
+ default:
+ return E_FAIL;
+ }
+
+ pDetails->str.uType = STRRET_WSTR;
+ return SHStrDupW(buffer, &pDetails->str.pOleStr);
+}
+
+HRESULT WINAPI CRecycleBin::MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid)
+{
+ TRACE("(%p, %d, %p)\n", this, iColumn, pscid);
+ if (iColumn >= COLUMNS_COUNT)
+ return E_INVALIDARG;
+ pscid->fmtid = *RecycleBinColumns[iColumn].fmtId;
+ pscid->pid = RecycleBinColumns[iColumn].pid;
+ return S_OK;
+}
+
+/*************************************************************************
+ * RecycleBin IContextMenu interface
+ */
+
+HRESULT WINAPI CRecycleBin::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
+{
+ WCHAR szBuffer[100];
+ MENUITEMINFOW mii;
+ int id = 1;
+
+ TRACE("QueryContextMenu %p %p %u %u %u %u\n", this, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags );
+
+ if (!hMenu)
+ return E_INVALIDARG;
+
+ memset(&mii, 0, sizeof(mii));
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
+ mii.fState = MFS_ENABLED;
+ szBuffer[0] = L'\0';
+ LoadStringW(shell32_hInstance, IDS_EMPTY_BITBUCKET, szBuffer, sizeof(szBuffer) / sizeof(WCHAR));
+ mii.dwTypeData = szBuffer;
+ mii.cch = wcslen(mii.dwTypeData);
+ mii.wID = idCmdFirst + id++;
+ mii.fType = MFT_STRING;
+ iIdEmpty = 1;
+
+ if (!InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
+ return E_FAIL;
+
+ return MAKE_HRESULT(SEVERITY_SUCCESS, 0, id);
+}
+
+HRESULT WINAPI CRecycleBin::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
+{
+ HRESULT hr;
+ LPSHELLBROWSER lpSB;
+ IShellView * lpSV = NULL;
+
+ TRACE("%p %p verb %p\n", this, lpcmi, lpcmi->lpVerb);
+
+ if (LOWORD(lpcmi->lpVerb) == iIdEmpty)
+ {
+ // FIXME
+ // path & flags
+ hr = SHEmptyRecycleBinW(lpcmi->hwnd, L"C:\\", 0);
+ TRACE("result %x\n", hr);
+ if (hr != S_OK)
+ return hr;
+
+ lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0);
+ if (lpSB && SUCCEEDED(lpSB->QueryActiveShellView(&lpSV)))
+ lpSV->Refresh();
+ }
+ return S_OK;
+}
+
+HRESULT WINAPI CRecycleBin::GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen)
+{
+ FIXME("%p %lu %u %p %p %u\n", this, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
+
+ return E_NOTIMPL;
+}
+
+/*************************************************************************
+ * RecycleBin IShellPropSheetExt interface
+ */
+
+HRESULT WINAPI CRecycleBin::AddPages(LPFNSVADDPROPSHEETPAGE pfnAddPage, LPARAM lParam)
+{
+ FIXME("%p %p %lu\n", this, pfnAddPage, lParam);
+
+ return E_NOTIMPL;
+}
+
+HRESULT WINAPI CRecycleBin::ReplacePage(EXPPS uPageID, LPFNSVADDPROPSHEETPAGE pfnReplaceWith, LPARAM lParam)
+{
+ FIXME("%p %lu %p %lu\n", this, uPageID, pfnReplaceWith, lParam);
+
+ return E_NOTIMPL;
+}
+
+/*************************************************************************
+ * RecycleBin IShellExtInit interface
+ */
+
+HRESULT WINAPI CRecycleBin::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID)
+{
+ TRACE("%p %p %p %p\n", this, pidlFolder, pdtobj, hkeyProgID );
+ return S_OK;
+}
+
+void toggleNukeOnDeleteOption(HWND hwndDlg, BOOL bEnable)
+{
+ if (bEnable)
+ {
+ SendDlgItemMessage(hwndDlg, 14001, BM_SETCHECK, BST_UNCHECKED, 0);
+ EnableWindow(GetDlgItem(hwndDlg, 14002), FALSE);
+ SendDlgItemMessage(hwndDlg, 14003, BM_SETCHECK, BST_CHECKED, 0);
+ }
+ else
+ {
+ SendDlgItemMessage(hwndDlg, 14001, BM_SETCHECK, BST_CHECKED, 0);
+ EnableWindow(GetDlgItem(hwndDlg, 14002), TRUE);
+ SendDlgItemMessage(hwndDlg, 14003, BM_SETCHECK, BST_UNCHECKED, 0);
+ }
+}
+
+
+static VOID
+InitializeRecycleBinDlg(HWND hwndDlg, WCHAR DefaultDrive)
+{
+ WCHAR CurDrive = L'A';
+ WCHAR szDrive[] = L"A:\\";
+ DWORD dwDrives;
+ WCHAR szName[100];
+ WCHAR szVolume[100];
+ DWORD MaxComponent, Flags;
+ DWORD dwSerial;
+ LVCOLUMNW lc;
+ HWND hDlgCtrl;
+ LVITEMW li;
+ INT itemCount;
+ ULARGE_INTEGER TotalNumberOfFreeBytes, TotalNumberOfBytes, FreeBytesAvailable;
+ RECT rect;
+ int columnSize;
+ int defIndex = 0;
+ DWORD dwSize;
+ PDRIVE_ITEM_CONTEXT pItem = NULL, pDefault = NULL, pFirst = NULL;
+
+ hDlgCtrl = GetDlgItem(hwndDlg, 14000);
+
+ if (!LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_LOCATION, szVolume, sizeof(szVolume) / sizeof(WCHAR)))
+ szVolume[0] = 0;
+
+ GetClientRect(hDlgCtrl, &rect);
+
+ memset(&lc, 0, sizeof(LV_COLUMN) );
+ lc.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT;
+
+ columnSize = 140; //FIXME
+ lc.iSubItem = 0;
+ lc.fmt = LVCFMT_FIXED_WIDTH;
+ lc.cx = columnSize;
+ lc.cchTextMax = wcslen(szVolume);
+ lc.pszText = szVolume;
+ (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 0, (LPARAM)&lc);
+
+ if (!LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_DISKSPACE, szVolume, sizeof(szVolume) / sizeof(WCHAR)))
+ szVolume[0] = 0;
+
+ lc.iSubItem = 1;
+ lc.cx = rect.right - rect.left - columnSize;
+ lc.cchTextMax = wcslen(szVolume);
+ lc.pszText = szVolume;
+ (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 1, (LPARAM)&lc);
+
+ dwDrives = GetLogicalDrives();
+ itemCount = 0;
+ do
+ {
+ if ((dwDrives & 0x1))
+ {
+ UINT Type = GetDriveTypeW(szDrive);
+ if (Type == DRIVE_FIXED) //FIXME
+ {
+ if (!GetVolumeInformationW(szDrive, szName, sizeof(szName) / sizeof(WCHAR), &dwSerial, &MaxComponent, &Flags, NULL, 0))
+ {
+ szName[0] = 0;
+ dwSerial = -1;
+ }
+
+ swprintf(szVolume, L"%s (%c)", szName, szDrive[0]);
+ memset(&li, 0x0, sizeof(LVITEMW));
+ li.mask = LVIF_TEXT | LVIF_PARAM;
+ li.iSubItem = 0;
+ li.pszText = szVolume;
+ li.iItem = itemCount;
+ SendMessageW(hDlgCtrl, LVM_INSERTITEMW, 0, (LPARAM)&li);
+ if (GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailable , &TotalNumberOfBytes, &TotalNumberOfFreeBytes))
+ {
+ if (StrFormatByteSizeW(TotalNumberOfFreeBytes.QuadPart, szVolume, sizeof(szVolume) / sizeof(WCHAR)))
+ {
+
+ pItem = (DRIVE_ITEM_CONTEXT *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DRIVE_ITEM_CONTEXT));
+ if (pItem)
+ {
+ swprintf(szName, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Bitbucket\\Volume\\%04X-%04X", LOWORD(dwSerial), HIWORD(dwSerial));
+ dwSize = sizeof(DWORD);
+ RegGetValueW(HKEY_CURRENT_USER, szName, L"MaxCapacity", RRF_RT_DWORD, NULL, &pItem->dwMaxCapacity, &dwSize);
+ dwSize = sizeof(DWORD);
+ RegGetValueW(HKEY_CURRENT_USER, szName, L"NukeOnDelete", RRF_RT_DWORD, NULL, &pItem->dwNukeOnDelete, &dwSize);
+ pItem->dwSerial = dwSerial;
+ li.mask = LVIF_PARAM;
+ li.lParam = (LPARAM)pItem;
+ (void)SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
+ if (CurDrive == DefaultDrive)
+ {
+ defIndex = itemCount;
+ pDefault = pItem;
+ }
+ }
+ if (!pFirst)
+ pFirst = pItem;
+
+ li.mask = LVIF_TEXT;
+ li.iSubItem = 1;
+ li.pszText = szVolume;
+ li.iItem = itemCount;
+ (void)SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
+ }
+ }
+ itemCount++;
+ }
+ }
+ CurDrive++;
+ szDrive[0] = CurDrive;
+ dwDrives = (dwDrives >> 1);
+ } while(dwDrives);
+
+ if (!pDefault)
+ pDefault = pFirst;
+ if (pDefault)
+ {
+ toggleNukeOnDeleteOption(hwndDlg, pDefault->dwNukeOnDelete);
+ SetDlgItemInt(hwndDlg, 14002, pDefault->dwMaxCapacity, FALSE);
+ }
+ ZeroMemory(&li, sizeof(li));
+ li.mask = LVIF_STATE;
+ li.stateMask = (UINT) - 1;
+ li.state = LVIS_FOCUSED | LVIS_SELECTED;
+ li.iItem = defIndex;
+ (void)SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
+
+}
+
+static BOOL StoreDriveSettings(HWND hwndDlg)
+{
+ int iCount, iIndex;
+ HWND hDlgCtrl = GetDlgItem(hwndDlg, 14000);
+ LVITEMW li;
+ PDRIVE_ITEM_CONTEXT pItem;
+ HKEY hKey, hSubKey;
+ WCHAR szSerial[20];
+ DWORD dwSize;
+
+
+ if (RegCreateKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Bitbucket\\Volume", 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS)
+ return FALSE;
+
+ iCount = ListView_GetItemCount(hDlgCtrl);
+
+ ZeroMemory(&li, sizeof(li));
+ li.mask = LVIF_PARAM;
+
+ for(iIndex = 0; iIndex < iCount; iIndex++)
+ {
+ li.iItem = iIndex;
+ if (SendMessageW(hDlgCtrl, LVM_GETITEMW, 0, (LPARAM)&li))
+ {
+ pItem = (PDRIVE_ITEM_CONTEXT)li.lParam;
+ swprintf(szSerial, L"%04X-%04X", LOWORD(pItem->dwSerial), HIWORD(pItem->dwSerial));
+ if (RegCreateKeyExW(hKey, szSerial, 0, NULL, 0, KEY_WRITE, NULL, &hSubKey, NULL) == ERROR_SUCCESS)
+ {
+ dwSize = sizeof(DWORD);
+ RegSetValueExW(hSubKey, L"NukeOnDelete", 0, REG_DWORD, (LPBYTE)&pItem->dwNukeOnDelete, dwSize);
+ dwSize = sizeof(DWORD);
+ RegSetValueExW(hSubKey, L"MaxCapacity", 0, REG_DWORD, (LPBYTE)&pItem->dwMaxCapacity, dwSize);
+ RegCloseKey(hSubKey);
+ }
+ }
+ }
+ RegCloseKey(hKey);
+ return TRUE;
+
+}
+
+static VOID FreeDriveItemContext(HWND hwndDlg)
+{
+ int iCount, iIndex;
+ HWND hDlgCtrl = GetDlgItem(hwndDlg, 14000);
+ LVITEMW li;
+
+ iCount = ListView_GetItemCount(hDlgCtrl);
+
+ ZeroMemory(&li, sizeof(li));
+ li.mask = LVIF_PARAM;
+
+ for(iIndex = 0; iIndex < iCount; iIndex++)
+ {
+ li.iItem = iIndex;
+ if (SendMessageW(hDlgCtrl, LVM_GETITEMW, 0, (LPARAM)&li))
+ {
+ HeapFree(GetProcessHeap(), 0, (LPVOID)li.lParam);
+ }
+ }
+}
+
+static INT
+GetDefaultItem(HWND hwndDlg, LVITEMW * li)
+{
+ HWND hDlgCtrl;
+ UINT iItemCount, iIndex;
+
+ hDlgCtrl = GetDlgItem(hwndDlg, 14000);
+ if (!hDlgCtrl)
+ return -1;
+
+ iItemCount = ListView_GetItemCount(hDlgCtrl);
+ if (!iItemCount)
+ return -1;
+
+ ZeroMemory(li, sizeof(LVITEMW));
+ li->mask = LVIF_PARAM | LVIF_STATE;
+ li->stateMask = (UINT) - 1;
+ for (iIndex = 0; iIndex < iItemCount; iIndex++)
+ {
+ li->iItem = iIndex;
+ if (SendMessageW(hDlgCtrl, LVM_GETITEMW, 0, (LPARAM)li))
+ {
+ if (li->state & LVIS_SELECTED)
+ return iIndex;
+ }
+ }
+ return -1;
+
+}
+
+static INT_PTR CALLBACK
+RecycleBinDlg(
+ HWND hwndDlg,
+ UINT uMsg,
+ WPARAM wParam,
+ LPARAM lParam
+)
+{
+ LPPSHNOTIFY lppsn;
+ LPNMLISTVIEW lppl;
+ LVITEMW li;
+ PDRIVE_ITEM_CONTEXT pItem;
+ BOOL bSuccess;
+ UINT uResult;
+ PROPSHEETPAGE * page;
+ DWORD dwStyle;
+
+ switch(uMsg)
+ {
+ case WM_INITDIALOG:
+ page = (PROPSHEETPAGE*)lParam;
+ InitializeRecycleBinDlg(hwndDlg, (WCHAR)page->lParam);
+ dwStyle = (DWORD) SendDlgItemMessage(hwndDlg, 14000, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
+ dwStyle = dwStyle | LVS_EX_FULLROWSELECT;
+ SendDlgItemMessage(hwndDlg, 14000, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle);
+ if (GetDlgCtrlID((HWND)wParam) != 14000)
+ {
+ SetFocus(GetDlgItem(hwndDlg, 14000));
+ return FALSE;
+ }
+ return TRUE;
+ case WM_COMMAND:
+ switch(LOWORD(wParam))
+ {
+ case 14001:
+ toggleNukeOnDeleteOption(hwndDlg, FALSE);
+ PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
+ break;
+ case 14003:
+ toggleNukeOnDeleteOption(hwndDlg, TRUE);
+ PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
+ break;
+ case 14004:
+ PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
+ break;
+ }
+ break;
+ case WM_NOTIFY:
+ lppsn = (LPPSHNOTIFY) lParam;
+ lppl = (LPNMLISTVIEW) lParam;
+ if (lppsn->hdr.code == PSN_APPLY)
+ {
+ if (GetDefaultItem(hwndDlg, &li) > -1)
+ {
+ pItem = (PDRIVE_ITEM_CONTEXT)li.lParam;
+ if (pItem)
+ {
+ uResult = GetDlgItemInt(hwndDlg, 14002, &bSuccess, FALSE);
+ if (bSuccess)
+ pItem->dwMaxCapacity = uResult;
+ if (SendDlgItemMessageW(hwndDlg, 14003, BM_GETCHECK, 0, 0) == BST_CHECKED)
+ pItem->dwNukeOnDelete = TRUE;
+ else
+ pItem->dwNukeOnDelete = FALSE;
+ }
+ }
+ if (StoreDriveSettings(hwndDlg))
+ {
+ SetWindowLongPtr( hwndDlg, DWL_MSGRESULT, PSNRET_NOERROR );
+ return TRUE;
+ }
+ }
+ else if (lppl->hdr.code == LVN_ITEMCHANGING)
+ {
+ ZeroMemory(&li, sizeof(li));
+ li.mask = LVIF_PARAM;
+ li.iItem = lppl->iItem;
+ if (!SendMessageW(lppl->hdr.hwndFrom, LVM_GETITEMW, 0, (LPARAM)&li))
+ return TRUE;
+
+ pItem = (PDRIVE_ITEM_CONTEXT)li.lParam;
+ if (!pItem)
+ return TRUE;
+
+ if (!(lppl->uOldState & LVIS_FOCUSED) && (lppl->uNewState & LVIS_FOCUSED))
+ {
+ /* new focused item */
+ toggleNukeOnDeleteOption(lppl->hdr.hwndFrom, pItem->dwNukeOnDelete);
+ SetDlgItemInt(hwndDlg, 14002, pItem->dwMaxCapacity, FALSE);
+ }
+ else if ((lppl->uOldState & LVIS_FOCUSED) && !(lppl->uNewState & LVIS_FOCUSED))
+ {
+ /* kill focus */
+ uResult = GetDlgItemInt(hwndDlg, 14002, &bSuccess, FALSE);
+ if (bSuccess)
+ pItem->dwMaxCapacity = uResult;
+ if (SendDlgItemMessageW(hwndDlg, 14003, BM_GETCHECK, 0, 0) == BST_CHECKED)
+ pItem->dwNukeOnDelete = TRUE;
+ else
+ pItem->dwNukeOnDelete = FALSE;
+ }
+ return TRUE;
+
+ }
+ break;
+ case WM_DESTROY:
+ FreeDriveItemContext(hwndDlg);
+ break;
+ }
+ return FALSE;
+}
+
+BOOL SH_ShowRecycleBinProperties(WCHAR sDrive)
+{
+ HPROPSHEETPAGE hpsp[1];
+ PROPSHEETHEADERW psh;
+ HPROPSHEETPAGE hprop;
+
+ BOOL ret;
+
+
+ ZeroMemory(&psh, sizeof(PROPSHEETHEADERW));
+ psh.dwSize = sizeof(PROPSHEETHEADERW);
+ psh.dwFlags = PSP_DEFAULT | PSH_PROPTITLE;
+ psh.pszCaption = MAKEINTRESOURCEW(IDS_RECYCLEBIN_FOLDER_NAME);
+ psh.hwndParent = NULL;
+ psh.phpage = hpsp;
+ psh.hInstance = shell32_hInstance;
+
+ hprop = SH_CreatePropertySheetPage(IDD_RECYCLE_BIN_PROPERTIES, RecycleBinDlg, (LPARAM)sDrive, NULL);
+ if (!hprop)
+ {
+ ERR("Failed to create property sheet\n");
+ return FALSE;
+ }
+ hpsp[psh.nPages] = hprop;
+ psh.nPages++;
+
+
+ ret = PropertySheetW(&psh);
+ if (ret < 0)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+BOOL
+TRASH_CanTrashFile(LPCWSTR wszPath)
+{
+ LONG ret;
+ DWORD dwNukeOnDelete, dwType, VolSerialNumber, MaxComponentLength;
+ DWORD FileSystemFlags, dwSize, dwDisposition;
+ HKEY hKey;
+ WCHAR szBuffer[10];
+ WCHAR szKey[150] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Bitbucket\\Volume\\";
+
+ if (wszPath[1] != L':')
+ {
+ /* path is UNC */
+ return FALSE;
+ }
+
+ if (GetDriveTypeW(wszPath) != DRIVE_FIXED)
+ {
+ /* no bitbucket on removable media */
+ return FALSE;
+ }
+
+ if (!GetVolumeInformationW(wszPath, NULL, 0, &VolSerialNumber, &MaxComponentLength, &FileSystemFlags, NULL, 0))
+ {
+ ERR("GetVolumeInformationW failed with %u\n", GetLastError());
+ return FALSE;
+ }
+
+ swprintf(szBuffer, L"%04X-%04X", LOWORD(VolSerialNumber), HIWORD(VolSerialNumber));
+ wcscat(szKey, szBuffer);
+
+ if (RegCreateKeyExW(HKEY_CURRENT_USER, szKey, 0, NULL, 0, KEY_WRITE, NULL, &hKey, &dwDisposition) != ERROR_SUCCESS)
+ {
+ ERR("RegCreateKeyExW failed\n");
+ return FALSE;
+ }
+
+ if (dwDisposition & REG_CREATED_NEW_KEY)
+ {
+ /* per default move to bitbucket */
+ dwNukeOnDelete = 0;
+ RegSetValueExW(hKey, L"NukeOnDelete", 0, REG_DWORD, (LPBYTE)&dwNukeOnDelete, sizeof(DWORD));
+ /* per default unlimited size */
+ dwSize = -1;
+ RegSetValueExW(hKey, L"MaxCapacity", 0, REG_DWORD, (LPBYTE)&dwSize, sizeof(DWORD));
+ RegCloseKey(hKey);
+ return TRUE;
+ }
+ else
+ {
+ dwSize = sizeof(dwNukeOnDelete);
+ ret = RegQueryValueExW(hKey, L"NukeOnDelete", NULL, &dwType, (LPBYTE)&dwNukeOnDelete, &dwSize);
+ if (ret != ERROR_SUCCESS)
+ {
+ if (ret == ERROR_FILE_NOT_FOUND)
+ {
+ /* restore key and enable bitbucket */
+ dwNukeOnDelete = 0;
+ RegSetValueExW(hKey, L"NukeOnDelete", 0, REG_DWORD, (LPBYTE)&dwNukeOnDelete, sizeof(DWORD));
+ }
+ RegCloseKey(hKey);
+ return TRUE;
+ }
+ else if (dwNukeOnDelete)
+ {
+ /* do not delete to bitbucket */
+ RegCloseKey(hKey);
+ return FALSE;
+ }
+ /* FIXME
+ * check if bitbucket is full
+ */
+ RegCloseKey(hKey);
+ return TRUE;
+ }
+}
+
+BOOL
+TRASH_TrashFile(LPCWSTR wszPath)
+{
+ TRACE("(%s)\n", debugstr_w(wszPath));
+ return DeleteFileToRecycleBin(wszPath);
+}
+
+/*************************************************************************
+ * SHUpdateCRecycleBinIcon [SHELL32.@]
+ *
+ * Undocumented
+ */
+EXTERN_C HRESULT WINAPI SHUpdateRecycleBinIcon(void)
+{
+ FIXME("stub\n");
+
+
+
+ return S_OK;
+}
+
+/****************************************************************************
+ * IDropTarget implementation
+ */
+BOOL CRecycleBin::QueryDrop(DWORD dwKeyState, LPDWORD pdwEffect)
+{
+ /* TODO on shift we should delete, we should update the cursor manager to show this. */
+
+ DWORD dwEffect = DROPEFFECT_COPY;
+
+ *pdwEffect = DROPEFFECT_NONE;
+
+ if (fAcceptFmt) { /* Does our interpretation of the keystate ... */
+ *pdwEffect = KeyStateToDropEffect (dwKeyState);
+
+ if (*pdwEffect == DROPEFFECT_NONE)
+ *pdwEffect = dwEffect;
+
+ /* ... matches the desired effect ? */
+ if (dwEffect & *pdwEffect) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+HRESULT WINAPI CRecycleBin::DragEnter(IDataObject *pDataObject,
+ DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
+{
+ TRACE("Recycle bin drag over (%p)\n", this);
+ /* The recycle bin accepts pretty much everything, and sets a CSIDL flag. */
+ fAcceptFmt = TRUE;
+
+ QueryDrop(dwKeyState, pdwEffect);
+ return S_OK;
+}
+
+HRESULT WINAPI CRecycleBin::DragOver(DWORD dwKeyState, POINTL pt,
+ DWORD *pdwEffect)
+{
+ TRACE("(%p)\n", this);
+
+ if (!pdwEffect)
+ return E_INVALIDARG;
+
+ QueryDrop(dwKeyState, pdwEffect);
+
+ return S_OK;
+}
+
+HRESULT WINAPI CRecycleBin::DragLeave()
+{
+ TRACE("(%p)\n", this);
+
+ fAcceptFmt = FALSE;
+
+ return S_OK;
+}
+
+HRESULT WINAPI CRecycleBin::Drop(IDataObject *pDataObject,
+ DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
+{
+ TRACE("(%p) object dropped on recycle bin, effect %u\n", this, *pdwEffect);
+
+ /* TODO: pdwEffect should be read and make the drop object be permanently deleted in the move case (shift held) */
+
+ FORMATETC fmt;
+ TRACE("(%p)->(DataObject=%p)\n", this, pDataObject);
+ InitFormatEtc (fmt, cfShellIDList, TYMED_HGLOBAL);
+
+ /* Handle cfShellIDList Drop objects here, otherwise send the approriate message to other software */
+ if (SUCCEEDED(pDataObject->QueryGetData(&fmt))) {
- IDataObject *pda = (IDataObject*) lpParameter;
- DoDeleteDataObject(pda);
- //Release the data object
- pda->Release();
++ IStream *s;
++ CoMarshalInterThreadInterfaceInStream(IID_IDataObject, pDataObject, &s);
++ SHCreateThread(DoDeleteThreadProc, s, NULL, NULL);
+ }
+ else
+ {
+ /*
+ * TODO call SetData on the data object with format CFSTR_TARGETCLSID
+ * set to the Recycle Bin's class identifier CLSID_RecycleBin.
+ */
+ }
+ return S_OK;
+}
+
+DWORD WINAPI DoDeleteThreadProc(LPVOID lpParameter)
+{
++ CoInitialize(NULL);
++ CComPtr<IDataObject> pDataObject;
++ HRESULT hr = CoGetInterfaceAndReleaseStream (static_cast<IStream*>(lpParameter), IID_PPV_ARG(IDataObject, &pDataObject));
++ if (SUCCEEDED(hr))
++ {
++ DoDeleteDataObject(pDataObject);
++ }
++ CoUninitialize();
+ return 0;
+}
+
+HRESULT WINAPI DoDeleteDataObject(IDataObject *pda)
+{
+ TRACE("performing delete");
+ HRESULT hr;
+
+ STGMEDIUM medium;
+ FORMATETC formatetc;
+ InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
+ hr = pda->GetData(&formatetc, &medium);
+ if (FAILED(hr))
+ return hr;
+
+ /* lock the handle */
+ LPIDA lpcida = (LPIDA)GlobalLock(medium.hGlobal);
+ if (!lpcida)
+ {
+ ReleaseStgMedium(&medium);
+ return E_FAIL;
+ }
+
+ /* convert the data into pidl */
+ LPITEMIDLIST pidl;
+ LPITEMIDLIST *apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
+ if (!apidl)
+ {
+ ReleaseStgMedium(&medium);
+ return E_FAIL;
+ }
+
+ CComPtr<IShellFolder> psfDesktop;
+ CComPtr<IShellFolder> psfFrom = NULL;
+
+ /* Grab the desktop shell folder */
+ hr = SHGetDesktopFolder(&psfDesktop);
+ if (FAILED(hr))
+ {
+ ERR("SHGetDesktopFolder failed\n");
+ SHFree(pidl);
+ _ILFreeaPidl(apidl, lpcida->cidl);
+ ReleaseStgMedium(&medium);
+ return E_FAIL;
+ }
+
+ /* Find source folder, this is where the clipboard data was copied from */
+ if (_ILIsDesktop(pidl))
+ {
+ psfFrom = psfDesktop;
+ }
+ else
+ {
+ hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfFrom));
+ if (FAILED(hr))
+ {
+ ERR("no IShellFolder\n");
+ SHFree(pidl);
+ _ILFreeaPidl(apidl, lpcida->cidl);
+ ReleaseStgMedium(&medium);
+ return E_FAIL;
+ }
+ }
+
+ STRRET strTemp;
+ hr = psfFrom->GetDisplayNameOf(apidl[0], SHGDN_FORPARSING, &strTemp);
+ if (FAILED(hr))
+ {
+ ERR("IShellFolder_GetDisplayNameOf failed with %x\n", hr);
+ SHFree(pidl);
+ _ILFreeaPidl(apidl, lpcida->cidl);
+ ReleaseStgMedium(&medium);
+ return hr;
+ }
+
+ WCHAR wszPath[MAX_PATH];
+ hr = StrRetToBufW(&strTemp, apidl[0], wszPath, _countof(wszPath));
+ if (FAILED(hr))
+ {
+ ERR("StrRetToBufW failed with %x\n", hr);
+ SHFree(pidl);
+ _ILFreeaPidl(apidl, lpcida->cidl);
+ ReleaseStgMedium(&medium);
+ return hr;
+ }
+
+ /* Only keep the base path */
+ LPWSTR pwszFilename = PathFindFileNameW(wszPath);
+ *pwszFilename = L'\0';
+
+ /* Build paths list */
+ LPWSTR pwszPaths = BuildPathsList(wszPath, lpcida->cidl, (LPCITEMIDLIST*) apidl);
+ if (!pwszPaths)
+ {
+ SHFree(pidl);
+ _ILFreeaPidl(apidl, lpcida->cidl);
+ ReleaseStgMedium(&medium);
+ return E_FAIL;
+ }
+
+ /* Delete them */
+ SHFILEOPSTRUCTW FileOp;
+ ZeroMemory(&FileOp, sizeof(FileOp));
+ FileOp.wFunc = FO_DELETE;
+ FileOp.pFrom = pwszPaths;
+ FileOp.fFlags = FOF_ALLOWUNDO;
+
+ if (SHFileOperationW(&FileOp) != 0)
+ {
+ ERR("SHFileOperation failed with 0x%x for %s\n", GetLastError(), debugstr_w(pwszPaths));
+ hr = E_FAIL;
+ }
+
+ HeapFree(GetProcessHeap(), 0, pwszPaths);
+ SHFree(pidl);
+ _ILFreeaPidl(apidl, lpcida->cidl);
+ ReleaseStgMedium(&medium);
+
+ return hr;
+}