/** * Install a shortcut for the virtual folder in the Windows Start Menu. * This method knows when we're installing under WOW64 so creating a shortcut will allow * the user to access the virtual folder, even when using a 32bit DLL under 64bit Windows. */ HRESULT UpdateStartMenuLink(LPCWSTR pstrDisplayName, LPCWSTR pstrDescription, KNOWNFOLDERID FolderId, BOOL bRegister) { HRESULT Hr = S_OK; // Get folder for installation... CPidl pidlFolderPath; CCoTaskString strFolderPath; HR( pidlFolderPath.CreateFromKnownFolder(FolderId) ); HR( pidlFolderPath.GetName(SIGDN_DESKTOPABSOLUTEPARSING, &strFolderPath) ); // Create shortcut link... CComPtr<IShellLink> spLink; HR( spLink.CoCreateInstance(CLSID_ShellLink) ); BOOL bIsWOW64 = FALSE; ::IsWow64Process(::GetCurrentProcess(), &bIsWOW64); CComBSTR bstrPath = bIsWOW64 ? L"%windir%\\syswow64\\explorer.exe" : L"%windir%\\explorer.exe"; CComBSTR bstrIcon = bIsWOW64 ? L"%windir%\\syswow64\\shell32.dll" : L"%SystemRoot%\\system32\\shell32.dll"; int iIconIndex = _ShellModule.GetConfigBool(VFS_HAVE_VIRTUAL_FILES) ? SIID_DRIVEFIXED : SIID_FOLDER; WCHAR wszArgs[MAX_PATH + 80] = { 0 }; ::wnsprintf(wszArgs, lengthof(wszArgs) - 1, L"/separate,%s%s%s::%s", bIsWOW64 ? L"/select," : L"", static_cast<LPCWSTR>(strFolderPath), strFolderPath.IsEmpty() ? L"" : L"\\", static_cast<LPCWSTR>(CComBSTR(CLSID_ShellFolder))); spLink->SetPath(bstrPath); spLink->SetArguments(wszArgs); spLink->SetIconLocation(bstrIcon, iIconIndex); spLink->SetDescription(pstrDescription); // Write the link file to the Windows Start Menu... CComQIPtr<IPersistFile> spPersist = spLink; if( spPersist == NULL ) return E_UNEXPECTED; CCoTaskString strLinkPath; HR( ::SHGetKnownFolderPath(FOLDERID_StartMenu, 0, NULL, &strLinkPath) ); WCHAR wszLinkFilename[MAX_PATH] = { 0 }; ::wnsprintf(wszLinkFilename, lengthof(wszLinkFilename) - 1, L"%s\\%s.lnk", static_cast<LPCWSTR>(strLinkPath), pstrDisplayName); if( bRegister ) Hr = spPersist->Save(wszLinkFilename, TRUE); else ::DeleteFileW(wszLinkFilename); return Hr; }
void OnItemExpanding(EShellTreeItem& tItem) { //LPNMTREEVIEW pnmtv = (LPNMTREEVIEW) pnmh; #ifdef __ATLCTRLX_H__ CWaitCursor cursor; #endif // 展开过就去掉“没展开”属性 tItem.remove_attribute("not-expand-ever"); // 删掉占位的那个项目 EShellTreeItem tiFake = tItem.find_first("option"); if (tiFake.is_valid()) { tiFake.destroy(); } // 遍历目录下的子文件夹 PSHELLITEMINFO pFolderItem = reinterpret_cast<PSHELLITEMINFO>(tItem.GetData()); CComPtr<IShellFolder> spFolder; if( pFolderItem->pidlNode != NULL ) { if( FAILED(pFolderItem->spFolder->BindToObject(pFolderItem->pidlNode, NULL, IID_IShellFolder, (LPVOID*)&spFolder)) ) return ; } else { spFolder = pFolderItem->spFolder; } // Add children CComPtr<IEnumIDList> spEnum; DWORD dwEnumFlags = SHCONTF_FOLDERS; if( (m_dwShellStyle & SCT_EX_SHOWHIDDEN) != 0 ) dwEnumFlags |= SHCONTF_INCLUDEHIDDEN; if( SUCCEEDED(spFolder->EnumObjects(NULL, dwEnumFlags, &spEnum)) ) { CPidl pidl; DWORD dwFetched; while( (spEnum->Next(1, &pidl, &dwFetched) == S_OK) && (dwFetched > 0) ) { // Get attributes and filter some items DWORD dwAttribs = SFGAO_DISPLAYATTRMASK | SFGAO_HASSUBFOLDER; if( !_FilterItem(spFolder, pidl, dwAttribs) ) { _InsertItem(spFolder, pFolderItem->pidlFull, pidl, dwAttribs, tItem); } pidl.Delete(); } } }
/** * Serialize data to a SHITEMID item. * This is a helper function designed to ease the process of serializing internal * item structures to a Simple PIDL structure. */ PCITEMID_CHILD CNseBaseItem::GenerateITEMID(LPVOID pData, SIZE_T cbData) { // NOTE: This method assumes that pData points to a structure // which derives (or has same layout) as the SHITEMID // structure (= a basic PIDL). // TODO: Type-safety? ATLASSERT(pData); ATLASSERT(cbData>=sizeof(SHITEMID)); LPSHITEMID pSHID = reinterpret_cast<LPSHITEMID>(pData); pSHID->cb = (USHORT) cbData; CPidl pidl; pidl.Create(pSHID); return (PCITEMID_CHILD) pidl.Detach(); }
/** * Show file properties. * Launches the default File Properties window for the selected item. * This method can only handle 1 item and will only show properties * for the first item in the passed selection. */ HRESULT CNseBaseItem::_DoShowProperties(VFS_MENUCOMMAND& Cmd) { // Get first item or view from selection CComPtr<IShellItem> spItem; if( Cmd.pShellItems != NULL ) Cmd.pShellItems->GetItemAt(0, &spItem); else ::SHCreateItemFromIDList(m_pFolder->m_pidlMonitor, IID_PPV_ARGS(&spItem)); if( spItem == NULL ) return E_FAIL; CPidl pidl; HR( pidl.CreateFromObject(spItem) ); // Show properties for this item SHELLEXECUTEINFO sei = { 0 }; sei.cbSize = sizeof(sei); sei.hwnd = Cmd.hWnd; sei.fMask = SEE_MASK_INVOKEIDLIST; sei.lpVerb = _T("properties"); sei.lpIDList = pidl; sei.nShow = SW_SHOW; ::ShellExecuteEx(&sei); // We handled this operation successfully for all items in selection return NSE_S_ALL_DONE; }
inline BOOL AtlGetShellPidl(LPCITEMIDLIST pidl, IShellFolder** ppFolder, LPITEMIDLIST* pidlRel) { ATLASSERT(pidl); ATLASSERT(ppFolder); ATLASSERT(pidlRel); *ppFolder = NULL; *pidlRel = NULL; // Get the desktop folder as a starting point CComPtr<IShellFolder> spFolder; if( FAILED( ::SHGetDesktopFolder(&spFolder) ) ) return FALSE; CPidl pidlMain; pidlMain.Copy(pidl); // Traverse each PIDL item and create a new IShellFolder for each of // them. Eventually we get to the last IShellFolder object and is left // with a simple (as opposed to complex) PIDL. int nCount = pidlMain.GetCount(); while( --nCount > 0 ) { // Get the next PIDL entry CPidl pidlNext; pidlNext.Attach( pidlMain.CopyFirstItem() ); if( pidlNext.IsEmpty() ) return FALSE; // Bind to the folder specified in the new item ID list. CComPtr<IShellFolder> spNextFolder; if( FAILED( spFolder->BindToObject(pidlNext, NULL, IID_IShellFolder, (LPVOID*) &spNextFolder)) ) return FALSE; spFolder = spNextFolder; // Strip first PIDL entry and copy remaining CPidl temp; temp.Copy( pidlMain.GetNextItem() ); pidlMain.Attach(temp.Detach()); } *ppFolder = spFolder.Detach(); *pidlRel = pidlMain.Detach(); return TRUE; };
HRESULT CDataObject::_CollectFiles(IShellFolder* pShellFolder, PCIDLIST_RELATIVE pidlFolder, LPCWSTR pstrFolder, CPidl& pidls) { ATLASSERT(pShellFolder); UINT nCount = pidls.GetItemCount(); for( UINT i = 0; i < nCount; i++ ) { CPidl pidlItem = pidls.GetItem(i); WIN32_FIND_DATA wfd = { 0 }; HRESULT Hr = ::SHGetDataFromIDList(pShellFolder, pidlItem.GetItem(0), SHGDFIL_FINDDATA, &wfd, sizeof(wfd)); if( FAILED(Hr) ) return Hr; FILEDESCRIPTOR fd = { 0 }; fd.dwFlags = (DWORD)(FD_FILESIZE | FD_ATTRIBUTES | FD_UNICODE); if( _ShellModule.GetConfigBool(VFS_CAN_PROGRESSUI) ) fd.dwFlags |= FD_PROGRESSUI; wcscpy_s(fd.cFileName, lengthof(fd.cFileName), pstrFolder); wcscat_s(fd.cFileName, lengthof(fd.cFileName), wfd.cFileName); fd.nFileSizeLow = wfd.nFileSizeLow; if( IsFileTimeValid(wfd.ftCreationTime) ) fd.ftCreationTime = wfd.ftCreationTime, fd.dwFlags |= FD_CREATETIME; if( IsFileTimeValid(wfd.ftLastWriteTime) ) fd.ftLastWriteTime = wfd.ftLastWriteTime, fd.dwFlags |= FD_WRITESTIME; if( IsFileTimeValid(wfd.ftLastAccessTime) ) fd.ftLastAccessTime = wfd.ftLastAccessTime, fd.dwFlags |= FD_ACCESSTIME; fd.dwFileAttributes = wfd.dwFileAttributes; // Setup item info into <sizel> NSEFILEPIDLDATA * pNseInfo = (NSEFILEPIDLDATA *)pidlItem.GetItem(0); if (pNseInfo && pNseInfo->magic == TARFILE_MAGIC_ID && pNseInfo->cb == sizeof(NSEFILEPIDLDATA)){ fd.sizel.cx = pNseInfo->wfd.dwId.category; fd.sizel.cy = pNseInfo->wfd.dwId.id; } // Setup parent info into <pointl> if (m_spFolder && m_spFolder->m_spFolderItem){ VFS_FIND_DATA vfd = m_spFolder->m_spFolderItem->GetFindData(); fd.pointl.x = vfd.dwId.category; fd.pointl.y = vfd.dwId.id; } if( !m_aFiles.Add(fd) ) return E_OUTOFMEMORY; // Recurse into sub-folders... // HarryWu, 2014.7.21 // it is high-cost and terrible, and not need for non-http mode. if( FALSE && IsBitSet(wfd.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY) ) { CComPtr<IShellFolder> spSubFolder; HR( pShellFolder->BindToObject(pidlItem, NULL, IID_PPV_ARGS(&spSubFolder)) ); CComPtr<IEnumIDList> spEnum; HR( spSubFolder->EnumObjects(m_hwndOwner, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_STORAGE, &spEnum) ); ULONG uFetched = 0; CPidl pidlSubItems; PITEMID_CHILD pidlChild = NULL; while( spEnum->Next(1, &pidlChild, &uFetched), uFetched > 0 ) { pidlSubItems.Append(pidlChild); ::CoTaskMemFree(pidlChild); uFetched = 0; } WCHAR wszSubFolder[MAX_PATH] = { 0 }; ::wnsprintf(wszSubFolder, lengthof(wszSubFolder) - 1, L"%s%s\\", pstrFolder, wfd.cFileName); CPidl pidlSubFolder = pidlFolder + pidlItem; HR( _CollectFiles(spSubFolder, pidlSubFolder, wszSubFolder, pidlSubItems) ); } } return S_OK; }