Index: dll/win32/shell32/defcontextmenu.cpp =================================================================== --- dll/win32/shell32/defcontextmenu.cpp (revision 60765) +++ dll/win32/shell32/defcontextmenu.cpp (working copy) @@ -59,6 +59,7 @@ UINT AddStaticContextMenusToMenu(HMENU hMenu, UINT IndexMenu); UINT BuildShellItemContextMenu(HMENU hMenu, UINT iIdCmdFirst, UINT iIdCmdLast, UINT uFlags); HRESULT DoPaste(LPCMINVOKECOMMANDINFO lpcmi); + HRESULT DoPasteLink(LPCMINVOKECOMMANDINFO lpcmi); HRESULT DoOpenOrExplore(LPCMINVOKECOMMANDINFO lpcmi); HRESULT DoCreateLink(LPCMINVOKECOMMANDINFO lpcmi); HRESULT DoDelete(LPCMINVOKECOMMANDINFO lpcmi); @@ -1105,17 +1106,10 @@ ReleaseStgMedium(&medium); pda->Release(); TRACE("CP result %x\n", hr); + NotifyShellViewWindow(lpcmi, TRUE); return S_OK; } -HRESULT -CDefaultContextMenu::DoOpenOrExplore( - LPCMINVOKECOMMANDINFO lpcmi) -{ - UNIMPLEMENTED; - return E_FAIL; -} - BOOL GetUniqueFileName(LPWSTR pwszBasePath, LPCWSTR pwszExt, LPWSTR pwszTarget, BOOL bShortcut) { @@ -1144,7 +1138,215 @@ } + HRESULT +CDefaultContextMenu::DoPasteLink( + LPCMINVOKECOMMANDINFO lpcmi) +{ + HRESULT hr; + WCHAR wszPath[MAX_PATH]; + WCHAR wszTarget[MAX_PATH]; + IPersistFile *ppf; + + IDataObject *pda; + if (OleGetClipboard(&pda) != S_OK) + return E_FAIL; + + STGMEDIUM medium; + FORMATETC formatetc; + InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL); + hr = pda->GetData(&formatetc, &medium); + + if (FAILED(hr)) + { + pda->Release(); + return E_FAIL; + } + + /* lock the handle */ + LPIDA lpcida = (LPIDA)GlobalLock(medium.hGlobal); + if (!lpcida) + { + ReleaseStgMedium(&medium); + pda->Release(); + return E_FAIL; + } + + /* convert the clipboard data into pidl (pointer to id list) */ + LPITEMIDLIST pidl; + LPITEMIDLIST *apidl = _ILCopyCidaToaPidl(&pidl, lpcida); + if (!apidl) + return E_FAIL; + + /* Grab the desktop shell folder */ + IShellFolder *psfDesktop; + if (FAILED(SHGetDesktopFolder(&psfDesktop))) + { + SHFree(pidl); + _ILFreeaPidl(apidl, lpcida->cidl); + ReleaseStgMedium(&medium); + pda->Release(); + return E_FAIL; + } + + /* Find source folder, this is where the clipboard data was copied from */ + IShellFolder *psfFrom = NULL; + if (_ILIsDesktop(pidl)) + { + /* use desktop shellfolder */ + psfFrom = psfDesktop; + } + else if (FAILED(psfDesktop->BindToObject(pidl, NULL, IID_IShellFolder, (LPVOID*)&psfFrom))) + { + ERR("no IShellFolder\n"); + + psfDesktop->Release(); + SHFree(pidl); + _ILFreeaPidl(apidl, lpcida->cidl); + ReleaseStgMedium(&medium); + pda->Release(); + + return E_FAIL; + } + + /* Find the target path, where we will be saving the new links (where the user right clicked) */ + STRRET strFile; + WCHAR wszTargetPath[MAX_PATH]; + { + IPersistFolder2 *ppf2 = NULL; + LPITEMIDLIST targetpidl; + + hr = m_Dcm.psf->QueryInterface(IID_IPersistFolder2, (LPVOID *) &ppf2); + if (SUCCEEDED(hr)) + { + hr = ppf2->GetCurFolder(&targetpidl); + ppf2->Release(); + if (SUCCEEDED(hr)) + { + hr = psfDesktop->GetDisplayNameOf(targetpidl, SHGDN_FORPARSING, &strFile); + ILFree(targetpidl); + if (SUCCEEDED(hr)) + { + hr = StrRetToBufW(&strFile, NULL, wszTargetPath, _countof(wszTargetPath)); + } + } + } + } + + if (hr != S_OK) { + ERR("Error obtaining target path"); + psfFrom->Release(); + if (!_ILIsDesktop(pidl)) + psfDesktop->Release(); + SHFree(pidl); + _ILFreeaPidl(apidl, lpcida->cidl); + ReleaseStgMedium(&medium); + pda->Release(); + return hr; + } + 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 (hr != S_OK) { + ERR("Error source obtaining path"); + break; + } + + hr = StrRetToBufW(&strFile, apidl[i], wszPath, _countof(wszPath)); + if (hr != S_OK) { + 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); + + //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 uniue file name"); + break; + } + hr = IShellLink_ConstructFromFile(NULL, IID_IPersistFile, ILCombine(pidl, apidl[i]), (LPVOID*)&ppf); + if (hr != S_OK) { + ERR("Error constucting link from file"); + break; + } + + hr = ppf->Save(wszTarget, FALSE); + ppf->Release(); + } + 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; + } + + IShellLinkW *pLink; + hr = CShellLink::_CreatorClass::CreateInstance(NULL, IID_IShellLinkW, (void**)&pLink); + if (hr != S_OK) { + ERR("Error creating shell link"); + break; + } + + WCHAR szDirPath[MAX_PATH], *pwszFile; + GetFullPathName(wszPath, MAX_PATH, szDirPath, &pwszFile); + if (pwszFile) pwszFile[0] = 0; + + if (SUCCEEDED(pLink->SetPath(wszPath)) && + SUCCEEDED(pLink->SetWorkingDirectory(szDirPath)) && + SUCCEEDED(pLink->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf))) + { + hr = ppf->Save(wszTarget, TRUE); + ppf->Release(); + + } else { + ERR("Error setting path and working directory"); + hr = E_FAIL; + pLink->Release(); + break; + } + pLink->Release(); + } + } + psfFrom->Release(); + if (!_ILIsDesktop(pidl)) + psfDesktop->Release(); + pda->Release(); + SHFree(pidl); + _ILFreeaPidl(apidl, lpcida->cidl); + ReleaseStgMedium(&medium); + NotifyShellViewWindow(lpcmi, TRUE); + return hr; +} + +HRESULT +CDefaultContextMenu::DoOpenOrExplore( + LPCMINVOKECOMMANDINFO lpcmi) +{ + UNIMPLEMENTED; + return E_FAIL; +} + +HRESULT CDefaultContextMenu::DoCreateLink( LPCMINVOKECOMMANDINFO lpcmi) { @@ -1169,8 +1371,16 @@ { if (!GetUniqueFileName(wszPath, pwszExt, wszTarget, TRUE)) return E_FAIL; - - hr = IShellLink_ConstructFromFile(NULL, IID_IPersistFile, m_Dcm.apidl[0], (LPVOID*)&ppf); + IPersistFolder2 *ppf2 = NULL; + LPITEMIDLIST pidl; + hr = m_Dcm.psf->QueryInterface(IID_IPersistFolder2, (LPVOID *) &ppf2); + if (SUCCEEDED(hr)) + { + hr = ppf2->GetCurFolder(&pidl); + ppf2->Release(); + if (SUCCEEDED(hr)) + hr = IShellLink_ConstructFromFile(NULL, IID_IPersistFile, ILCombine(pidl, m_Dcm.apidl[0]), (LPVOID*)&ppf); + } if (hr != S_OK) return hr; @@ -1282,6 +1492,7 @@ if (SUCCEEDED(SHCreateDataObject(m_Dcm.pidlFolder, m_Dcm.cidl, m_Dcm.apidl, NULL, IID_IDataObject, (void**)&pDataObj))) { + //TODO, modify pDataObj to indicate cut or copy. hr = OleSetClipboard(pDataObj); pDataObj->Release(); return hr; @@ -1634,8 +1845,9 @@ case FCIDM_SHVIEW_REFRESH: return NotifyShellViewWindow(lpcmi, FALSE); case FCIDM_SHVIEW_INSERT: + return DoPaste(lpcmi); case FCIDM_SHVIEW_INSERTLINK: - return DoPaste(lpcmi); + return DoPasteLink(lpcmi); case FCIDM_SHVIEW_OPEN: case FCIDM_SHVIEW_EXPLORE: return DoOpenOrExplore(lpcmi);