2 * Copyright 2003 Martin Fuchs
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 // Martin Fuchs, 23.07.2003
29 #include "../utility/utility.h"
30 #include "../utility/shellclasses.h"
32 #include "../globals.h"
38 bool ShellDirectory::fill_w32fdata_shell(LPCITEMIDLIST pidl, SFGAOF attribs, WIN32_FIND_DATA* pw32fdata, BY_HANDLE_FILE_INFORMATION* pbhfi)
40 bool bhfi_valid = false;
42 if (!( (attribs & SFGAO_FILESYSTEM) && SUCCEEDED(
43 SHGetDataFromIDList(_folder, pidl, SHGDFIL_FINDDATA, pw32fdata, sizeof(WIN32_FIND_DATA))) )) {
44 WIN32_FILE_ATTRIBUTE_DATA fad;
45 IDataObject* pDataObj;
47 STGMEDIUM medium = {0, {0}, 0};
48 FORMATETC fmt = {g_Globals._cfStrFName, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
50 HRESULT hr = _folder->GetUIObjectOf(0, 1, &pidl, IID_IDataObject, 0, (LPVOID*)&pDataObj);
53 hr = pDataObj->GetData(&fmt, &medium);
58 LPCTSTR path = (LPCTSTR)GlobalLock(medium.UNION_MEMBER(hGlobal));
59 UINT sem_org = SetErrorMode(SEM_FAILCRITICALERRORS);
61 if (GetFileAttributesEx(path, GetFileExInfoStandard, &fad)) {
62 pw32fdata->dwFileAttributes = fad.dwFileAttributes;
63 pw32fdata->ftCreationTime = fad.ftCreationTime;
64 pw32fdata->ftLastAccessTime = fad.ftLastAccessTime;
65 pw32fdata->ftLastWriteTime = fad.ftLastWriteTime;
67 if (!(fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
68 pw32fdata->nFileSizeLow = fad.nFileSizeLow;
69 pw32fdata->nFileSizeHigh = fad.nFileSizeHigh;
73 HANDLE hFile = CreateFile(path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
74 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
76 if (hFile != INVALID_HANDLE_VALUE) {
77 if (GetFileInformationByHandle(hFile, pbhfi))
83 SetErrorMode(sem_org);
85 GlobalUnlock(medium.UNION_MEMBER(hGlobal));
86 GlobalFree(medium.UNION_MEMBER(hGlobal));
91 if (!(attribs & SFGAO_FILESYSTEM)) // Archiv files should not be displayed as folders in explorer view.
92 if (attribs & (SFGAO_FOLDER|SFGAO_HASSUBFOLDER))
93 pw32fdata->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
95 if (attribs & SFGAO_READONLY)
96 pw32fdata->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
98 if (attribs & SFGAO_COMPRESSED)
99 pw32fdata->dwFileAttributes |= FILE_ATTRIBUTE_COMPRESSED;
105 LPITEMIDLIST ShellEntry::create_absolute_pidl(HWND hwnd)
107 if (_up/* && _up->_etype==ET_SHELL*/) {
108 ShellDirectory* dir = static_cast<ShellDirectory*>(_up);
110 return _pidl.create_absolute_pidl(dir->_pidl, hwnd);
117 // get full path of a shell entry
118 void ShellEntry::get_path(PTSTR path) const
120 path[0] = TEXT('\0');
122 HRESULT hr = path_from_pidl(get_parent_folder(), &*_pidl, path, MAX_PATH);
126 // get full path of a shell folder
127 void ShellDirectory::get_path(PTSTR path) const
129 path[0] = TEXT('\0');
134 if (!_folder.empty())
135 hr = const_cast<ShellFolder&>(_folder)->GetAttributesOf(1, (LPCITEMIDLIST*)&_pidl, &attribs);
137 if (SUCCEEDED(hr) && (attribs&SFGAO_FILESYSTEM))
138 hr = path_from_pidl(get_parent_folder(), &*_pidl, path, MAX_PATH);
142 BOOL ShellEntry::launch_entry(HWND hwnd, UINT nCmdShow)
146 SHELLEXECUTEINFO shexinfo;
148 shexinfo.cbSize = sizeof(SHELLEXECUTEINFO);
149 shexinfo.fMask = SEE_MASK_INVOKEIDLIST; // SEE_MASK_IDLIST is also possible.
150 shexinfo.hwnd = hwnd;
151 shexinfo.lpVerb = NULL;
152 shexinfo.lpFile = NULL;
153 shexinfo.lpParameters = NULL;
154 shexinfo.lpDirectory = NULL;
155 shexinfo.nShow = nCmdShow;
156 shexinfo.lpIDList = create_absolute_pidl(hwnd);
158 if (!ShellExecuteEx(&shexinfo)) {
159 display_error(hwnd, GetLastError());
163 if (shexinfo.lpIDList != &*_pidl)
164 ShellMalloc()->Free(shexinfo.lpIDList);
170 static HICON extract_icon(IShellFolder* folder, LPCITEMIDLIST pidl)
172 IExtractIcon* pExtract;
174 if (SUCCEEDED(folder->GetUIObjectOf(0, 1, (LPCITEMIDLIST*)&pidl, IID_IExtractIcon, 0, (LPVOID*)&pExtract))) {
175 TCHAR path[_MAX_PATH];
180 if (SUCCEEDED(pExtract->GetIconLocation(GIL_FORSHELL, path, _MAX_PATH, &idx, &flags))) {
181 if (!(flags & GIL_NOTFILENAME)) {
183 idx = 0; // special case for some control panel applications
185 if ((int)ExtractIconEx(path, idx, 0, &hIcon, 1) > 0)
186 flags &= ~GIL_DONTCACHE;
188 HICON hIconLarge = 0;
190 HRESULT hr = pExtract->Extract(path, idx, &hIconLarge, &hIcon, MAKELONG(0/*GetSystemMetrics(SM_CXICON)*/,GetSystemMetrics(SM_CXSMICON)));
193 DestroyIcon(hIconLarge);
204 void ShellDirectory::read_directory()
206 int level = _level + 1;
208 Entry* first_entry = NULL;
211 /*if (_folder.empty())
214 ShellItemEnumerator enumerator(_folder, SHCONTF_FOLDERS|SHCONTF_NONFOLDERS|SHCONTF_INCLUDEHIDDEN|SHCONTF_SHAREABLE|SHCONTF_STORAGE);
216 HRESULT hr_next = S_OK;
219 #define FETCH_ITEM_COUNT 32
220 LPITEMIDLIST pidls[FETCH_ITEM_COUNT];
224 memset(pidls, 0, sizeof(pidls));
226 hr_next = enumerator->Next(FETCH_ITEM_COUNT, pidls, &cnt);
228 /* don't break yet now: Registry Explorer Plugin returns E_FAIL!
229 if (!SUCCEEDED(hr_next))
232 if (hr_next == S_FALSE)
235 for(n=0; n<cnt; ++n) {
236 WIN32_FIND_DATA w32fd;
237 BY_HANDLE_FILE_INFORMATION bhfi;
238 bool bhfi_valid = false;
240 memset(&w32fd, 0, sizeof(WIN32_FIND_DATA));
242 SFGAOF attribs = ~SFGAO_FILESYSTEM; //SFGAO_HASSUBFOLDER|SFGAO_FOLDER; SFGAO_FILESYSTEM sorgt dafür, daß "My Documents" anstatt von "Martin's Documents" angezeigt wird
243 HRESULT hr = _folder->GetAttributesOf(1, (LPCITEMIDLIST*)&pidls[n], &attribs);
246 if (attribs != ~SFGAO_FILESYSTEM)
247 bhfi_valid = fill_w32fdata_shell(pidls[n], attribs, &w32fd, &bhfi);
255 if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
256 entry = new ShellDirectory(this, pidls[n], _hwnd);
258 entry = new ShellEntry(this, pidls[n]);
266 memcpy(&entry->_data, &w32fd, sizeof(WIN32_FIND_DATA));
269 memcpy(&entry->_bhfi, &bhfi, sizeof(BY_HANDLE_FILE_INFORMATION));
271 if (!entry->_data.cFileName[0])
272 /*hr = */name_from_pidl(_folder, pidls[n], entry->_data.cFileName, MAX_PATH, SHGDN_INFOLDER|0x2000/*0x2000=SHGDN_INCLUDE_NONFILESYS*/);
274 // get display icons for files and virtual objects
275 if (!(entry->_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
276 !(attribs & SFGAO_FILESYSTEM)) {
277 entry->_hIcon = extract_icon(_folder, pidls[n]);
280 entry->_hIcon = (HICON)-1; // don't try again later
284 entry->_expanded = false;
285 entry->_scanned = false;
286 entry->_level = level;
287 entry->_shell_attribs = attribs;
288 entry->_bhfi_valid = bhfi_valid;
292 } while(SUCCEEDED(hr_next));
301 const void* ShellDirectory::get_next_path_component(const void* p)
303 LPITEMIDLIST pidl = (LPITEMIDLIST)p;
305 if (!pidl || !pidl->mkid.cb)
308 // go to next element
309 pidl = (LPITEMIDLIST)((LPBYTE)pidl+pidl->mkid.cb);
314 Entry* ShellDirectory::find_entry(const void* p)
316 LPITEMIDLIST pidl = (LPITEMIDLIST) p;
318 for(Entry*entry=_down; entry; entry=entry->_next) {
319 ShellEntry* e = static_cast<ShellEntry*>(entry);
321 if (e->_pidl && e->_pidl->mkid.cb==pidl->mkid.cb && !memcmp(e->_pidl, pidl, e->_pidl->mkid.cb))