00001 /* 00002 * Winefile 00003 * 00004 * Copyright 2000, 2003, 2004, 2005, 2008 Martin Fuchs 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00019 */ 00020 00021 #include "winefile.h" 00022 00023 00024 #ifdef _SHELL_FOLDERS 00025 00026 /* free shell allocated memory */ 00027 static void free_strret(STRRET* str) 00028 { 00029 if (str->uType == STRRET_WSTR) 00030 IMalloc_Free(Globals.iMalloc, str->UNION_MEMBER(pOleStr)); 00031 } 00032 00033 00034 #ifndef UNICODE 00035 00036 /* copy up to count characters of the ANSI source string including the zero terminator to dest */ 00037 static LPSTR strcpyn(LPSTR dest, LPCSTR source, size_t count) 00038 { 00039 LPCSTR s; 00040 LPSTR d = dest; 00041 00042 for(s=source; count&&(*d++=*s++); ) 00043 count--; 00044 00045 return dest; 00046 } 00047 00048 /* retreive an ANSI string from STRRET */ 00049 static void get_strretA(STRRET* str, const SHITEMID* shiid, LPSTR buffer, int len) 00050 { 00051 switch(str->uType) { 00052 case STRRET_WSTR: 00053 WideCharToMultiByte(CP_ACP, 0, str->UNION_MEMBER(pOleStr), -1, buffer, len, NULL, NULL); 00054 break; 00055 00056 case STRRET_OFFSET: 00057 strcpyn(buffer, (LPCSTR)shiid+str->UNION_MEMBER(uOffset), len); 00058 break; 00059 00060 case STRRET_CSTR: 00061 strcpyn(buffer, str->UNION_MEMBER(cStr), len); 00062 } 00063 } 00064 00065 /* get the full file system path from item id list */ 00066 HRESULT path_from_pidlA(IShellFolder* folder, LPITEMIDLIST pidl, LPSTR buffer, int len) 00067 { 00068 STRRET str; 00069 00070 /* SHGDN_FORPARSING: get full path of id list */ 00071 HRESULT hr = IShellFolder_GetDisplayNameOf(folder, pidl, SHGDN_FORPARSING, &str); 00072 00073 if (SUCCEEDED(hr)) { 00074 get_strretA(&str, &pidl->mkid, buffer, len); 00075 free_strret(&str); 00076 } else 00077 buffer[0] = '\0'; 00078 00079 return hr; 00080 } 00081 00082 #endif 00083 00084 /* copy up to count characters of the wide character source string including the zero terminator to dest */ 00085 static LPWSTR wcscpyn(LPWSTR dest, LPCWSTR source, size_t count) 00086 { 00087 LPCWSTR s; 00088 LPWSTR d = dest; 00089 00090 for(s=source; count&&(*d++=*s++); ) 00091 count--; 00092 00093 return dest; 00094 } 00095 00096 /* retreive an wide character string from STRRET */ 00097 static void get_strretW(STRRET* str, const SHITEMID* shiid, LPWSTR buffer, int len) 00098 { 00099 switch(str->uType) { 00100 case STRRET_WSTR: 00101 wcscpyn(buffer, str->UNION_MEMBER(pOleStr), len); 00102 break; 00103 00104 case STRRET_OFFSET: 00105 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)shiid+str->UNION_MEMBER(uOffset), -1, buffer, len); 00106 break; 00107 00108 case STRRET_CSTR: 00109 MultiByteToWideChar(CP_ACP, 0, str->UNION_MEMBER(cStr), -1, buffer, len); 00110 } 00111 } 00112 00113 00114 /* retrieve name string from an item id list */ 00115 00116 static HRESULT name_from_pidl(IShellFolder* folder, LPITEMIDLIST pidl, LPTSTR buffer, int len, SHGDNF flags) 00117 { 00118 STRRET str; 00119 00120 HRESULT hr = IShellFolder_GetDisplayNameOf(folder, pidl, flags, &str); 00121 00122 if (SUCCEEDED(hr)) { 00123 get_strret(&str, &pidl->mkid, buffer, len); 00124 free_strret(&str); 00125 } else 00126 buffer[0] = '\0'; 00127 00128 return hr; 00129 } 00130 00131 00132 /* retrieve path from an item id list */ 00133 00134 HRESULT path_from_pidlW(IShellFolder* folder, LPITEMIDLIST pidl, LPWSTR buffer, int len) 00135 { 00136 STRRET str; 00137 00138 /* SHGDN_FORPARSING: get full path of id list */ 00139 HRESULT hr = IShellFolder_GetDisplayNameOf(folder, pidl, SHGDN_FORPARSING, &str); 00140 00141 if (SUCCEEDED(hr)) { 00142 get_strretW(&str, &pidl->mkid, buffer, len); 00143 free_strret(&str); 00144 } else 00145 buffer[0] = '\0'; 00146 00147 return hr; 00148 } 00149 00150 00151 /* create an item id list from a file system path */ 00152 00153 LPITEMIDLIST get_path_pidl(LPCTSTR path, HWND hwnd) 00154 { 00155 LPITEMIDLIST pidl; 00156 HRESULT hr; 00157 ULONG len; 00158 00159 #ifdef UNICODE 00160 LPCWSTR buffer = path; 00161 #else 00162 WCHAR buffer[MAX_PATH]; 00163 MultiByteToWideChar(CP_ACP, 0, path, -1, buffer, MAX_PATH); 00164 #endif 00165 00166 hr = IShellFolder_ParseDisplayName(Globals.iDesktop, hwnd, NULL, (LPOLESTR)buffer, &len, &pidl, NULL); 00167 if (FAILED(hr)) 00168 return NULL; 00169 00170 return pidl; 00171 } 00172 00173 00174 /* convert an item id list from relative to absolute (=relative to the desktop) format */ 00175 00176 LPITEMIDLIST get_to_absolute_pidl(Entry* entry, HWND hwnd) 00177 { 00178 if (entry->up && entry->up->etype==ET_SHELL) { 00179 IShellFolder* folder = entry->up->folder; 00180 WCHAR buffer[MAX_PATH]; 00181 00182 HRESULT hr = path_from_pidlW(folder, entry->pidl, buffer, MAX_PATH); 00183 00184 if (SUCCEEDED(hr)) { 00185 LPITEMIDLIST pidl; 00186 ULONG len; 00187 00188 hr = IShellFolder_ParseDisplayName(Globals.iDesktop, hwnd, NULL, buffer, &len, &pidl, NULL); 00189 00190 if (SUCCEEDED(hr)) 00191 return pidl; 00192 } 00193 } else if (entry->etype == ET_WINDOWS) { 00194 TCHAR path[MAX_PATH]; 00195 00196 get_path(entry, path); 00197 00198 return get_path_pidl(path, hwnd); 00199 } else if (entry->pidl) 00200 return ILClone(entry->pidl); 00201 00202 return NULL; 00203 } 00204 00205 00206 /* retrieve display icon from the given item id list */ 00207 00208 static HICON extract_icon(IShellFolder* folder, LPCITEMIDLIST pidl) 00209 { 00210 IExtractIcon* pExtract; 00211 00212 if (SUCCEEDED(IShellFolder_GetUIObjectOf(folder, 0, 1, (LPCITEMIDLIST*)&pidl, &IID_IExtractIcon, 0, (LPVOID*)&pExtract))) { 00213 TCHAR path[_MAX_PATH]; 00214 unsigned flags; 00215 HICON hicon; 00216 int idx; 00217 00218 if (SUCCEEDED((*pExtract->lpVtbl->GetIconLocation)(pExtract, GIL_FORSHELL, path, _MAX_PATH, &idx, &flags))) { 00219 if (!(flags & GIL_NOTFILENAME)) { 00220 if (idx == -1) 00221 idx = 0; /* special case for some control panel applications */ 00222 00223 if ((int)ExtractIconEx(path, idx, 0, &hicon, 1) > 0) 00224 flags &= ~GIL_DONTCACHE; 00225 } else { 00226 HICON hIconLarge = 0; 00227 00228 HRESULT hr = (*pExtract->lpVtbl->Extract)(pExtract, path, idx, &hIconLarge, &hicon, MAKELONG(0/*GetSystemMetrics(SM_CXICON)*/,GetSystemMetrics(SM_CXSMICON))); 00229 00230 if (SUCCEEDED(hr)) 00231 DestroyIcon(hIconLarge); 00232 } 00233 00234 return hicon; 00235 } 00236 } 00237 00238 return 0; 00239 } 00240 00241 00242 /* search a Shell directory entry by item id list */ 00243 static Entry* find_entry_shell(Entry* dir, LPCITEMIDLIST pidl) 00244 { 00245 Entry* entry; 00246 00247 for(entry=dir->down; entry; entry=entry->next) { 00248 if (entry->pidl->mkid.cb == pidl->mkid.cb && 00249 !memcmp(entry->pidl, pidl, entry->pidl->mkid.cb)) 00250 return entry; 00251 } 00252 00253 return 0; 00254 } 00255 00256 /* read a directory tree for the given item id list in the shell namespace */ 00257 Entry* read_tree_shell(Root* root, LPITEMIDLIST pidl, enum SORT_ORDER sortOrder, HWND hwnd) 00258 { 00259 Entry* entry = &root->entry; 00260 Entry* next; 00261 LPITEMIDLIST next_pidl = pidl; 00262 IShellFolder* folder; 00263 IShellFolder* child = NULL; 00264 HRESULT hr; 00265 00266 HCURSOR old_cursor = SetCursor(LoadCursor(0, IDC_WAIT)); 00267 00268 #ifndef _NO_EXTENSIONS 00269 entry->etype = ET_SHELL; 00270 #endif 00271 00272 folder = Globals.iDesktop; 00273 00274 while(entry) { 00275 entry->pidl = next_pidl; 00276 entry->folder = folder; 00277 00278 if (!pidl->mkid.cb) 00279 break; 00280 00281 /* copy first element of item id list */ 00282 next_pidl = IMalloc_Alloc(Globals.iMalloc, pidl->mkid.cb+sizeof(USHORT)); 00283 memcpy(next_pidl, pidl, pidl->mkid.cb); 00284 ((LPITEMIDLIST)((LPBYTE)next_pidl+pidl->mkid.cb))->mkid.cb = 0; 00285 00286 hr = IShellFolder_BindToObject(folder, next_pidl, 0, &IID_IShellFolder, (void**)&child); 00287 if (!SUCCEEDED(hr)) 00288 break; 00289 00290 read_directory(entry, NULL, sortOrder, hwnd); 00291 00292 if (entry->down) 00293 entry->expanded = TRUE; 00294 00295 next = find_entry_shell(entry, next_pidl); 00296 if (!next) 00297 break; 00298 00299 folder = child; 00300 entry = next; 00301 00302 /* go to next element */ 00303 pidl = (LPITEMIDLIST) ((LPBYTE)pidl+pidl->mkid.cb); 00304 } 00305 00306 SetCursor(old_cursor); 00307 00308 return entry; 00309 } 00310 00311 00312 /* fill a WIN32_FIND_DATA structure with information about a shell namespace object */ 00313 00314 static void fill_w32fdata_shell(IShellFolder* folder, LPCITEMIDLIST pidl, SFGAOF attribs, WIN32_FIND_DATA* w32fdata) 00315 { 00316 if (!(attribs & SFGAO_FILESYSTEM) || 00317 FAILED(SHGetDataFromIDList(folder, pidl, SHGDFIL_FINDDATA, w32fdata, sizeof(WIN32_FIND_DATA)))) { 00318 WIN32_FILE_ATTRIBUTE_DATA fad; 00319 IDataObject* pDataObj; 00320 00321 STGMEDIUM medium = {0, {0}, 0}; 00322 FORMATETC fmt = {Globals.cfStrFName, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL}; 00323 00324 HRESULT hr = IShellFolder_GetUIObjectOf(folder, 0, 1, &pidl, &IID_IDataObject, 0, (LPVOID*)&pDataObj); 00325 00326 if (SUCCEEDED(hr)) { 00327 hr = IDataObject_GetData(pDataObj, &fmt, &medium); 00328 00329 IDataObject_Release(pDataObj); 00330 00331 if (SUCCEEDED(hr)) { 00332 LPCTSTR path = (LPCTSTR)GlobalLock(medium.UNION_MEMBER(hGlobal)); 00333 UINT sem_org = SetErrorMode(SEM_FAILCRITICALERRORS); 00334 00335 if (GetFileAttributesEx(path, GetFileExInfoStandard, &fad)) { 00336 w32fdata->dwFileAttributes = fad.dwFileAttributes; 00337 w32fdata->ftCreationTime = fad.ftCreationTime; 00338 w32fdata->ftLastAccessTime = fad.ftLastAccessTime; 00339 w32fdata->ftLastWriteTime = fad.ftLastWriteTime; 00340 00341 if (!(fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { 00342 w32fdata->nFileSizeLow = fad.nFileSizeLow; 00343 w32fdata->nFileSizeHigh = fad.nFileSizeHigh; 00344 } 00345 } 00346 00347 SetErrorMode(sem_org); 00348 00349 GlobalUnlock(medium.UNION_MEMBER(hGlobal)); 00350 GlobalFree(medium.UNION_MEMBER(hGlobal)); 00351 } 00352 } 00353 } 00354 00355 if (attribs & (SFGAO_FOLDER|SFGAO_HASSUBFOLDER)) 00356 w32fdata->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY; 00357 00358 if (attribs & SFGAO_READONLY) 00359 w32fdata->dwFileAttributes |= FILE_ATTRIBUTE_READONLY; 00360 00361 if (attribs & SFGAO_COMPRESSED) 00362 w32fdata->dwFileAttributes |= FILE_ATTRIBUTE_COMPRESSED; 00363 } 00364 00365 00366 /* read a directory entry using the WIN32 file system API */ 00367 00368 void read_directory_shell(Entry* dir, HWND hwnd) 00369 { 00370 IShellFolder* folder = dir->folder; 00371 int level = dir->level + 1; 00372 HRESULT hr; 00373 00374 IShellFolder* child; 00375 IEnumIDList* idlist; 00376 00377 Entry* first_entry = NULL; 00378 Entry* last = NULL; 00379 Entry* entry; 00380 00381 if (!folder) 00382 return; 00383 00384 hr = IShellFolder_EnumObjects(folder, hwnd, SHCONTF_FOLDERS|SHCONTF_NONFOLDERS|SHCONTF_INCLUDEHIDDEN|SHCONTF_SHAREABLE|SHCONTF_STORAGE, &idlist); 00385 00386 if (SUCCEEDED(hr)) { 00387 for(;;) { 00388 #define FETCH_ITEM_COUNT 32 00389 LPITEMIDLIST pidls[FETCH_ITEM_COUNT]; 00390 SFGAOF attribs; 00391 ULONG cnt = 0; 00392 ULONG n; 00393 00394 memset(pidls, 0, sizeof(pidls)); 00395 00396 hr = IEnumIDList_Next(idlist, FETCH_ITEM_COUNT, pidls, &cnt); 00397 if (!SUCCEEDED(hr)) 00398 break; 00399 00400 if (hr == S_FALSE) 00401 break; 00402 00403 for(n=0; n<cnt; ++n) { 00404 entry = alloc_entry(); 00405 00406 if (!first_entry) 00407 first_entry = entry; 00408 00409 if (last) 00410 last->next = entry; 00411 00412 memset(&entry->data, 0, sizeof(WIN32_FIND_DATA)); 00413 entry->bhfi_valid = FALSE; 00414 00415 attribs = ~SFGAO_FILESYSTEM; /*SFGAO_HASSUBFOLDER|SFGAO_FOLDER; SFGAO_FILESYSTEM sorgt dafür, daß "My Documents" anstatt von "Martin's Documents" angezeigt wird */ 00416 00417 hr = IShellFolder_GetAttributesOf(folder, 1, (LPCITEMIDLIST*)&pidls[n], &attribs); 00418 00419 if (SUCCEEDED(hr)) { 00420 if (attribs != (SFGAOF)~SFGAO_FILESYSTEM) { 00421 fill_w32fdata_shell(folder, pidls[n], attribs, &entry->data); 00422 00423 entry->bhfi_valid = TRUE; 00424 } else 00425 attribs = 0; 00426 } else 00427 attribs = 0; 00428 00429 entry->pidl = pidls[n]; 00430 00431 if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { 00432 hr = IShellFolder_BindToObject(folder, pidls[n], 0, &IID_IShellFolder, (void**)&child); 00433 00434 if (SUCCEEDED(hr)) 00435 entry->folder = child; 00436 else 00437 entry->folder = NULL; 00438 } 00439 else 00440 entry->folder = NULL; 00441 00442 if (!entry->data.cFileName[0]) 00443 /*hr = */name_from_pidl(folder, pidls[n], entry->data.cFileName, MAX_PATH, /*SHGDN_INFOLDER*/0x2000/*0x2000=SHGDN_INCLUDE_NONFILESYS*/); 00444 00445 /* get display icons for files and virtual objects */ 00446 if (!(entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) || 00447 !(attribs & SFGAO_FILESYSTEM)) { 00448 entry->hicon = extract_icon(folder, pidls[n]); 00449 00450 if (!entry->hicon) 00451 entry->hicon = (HICON)-1; /* don't try again later */ 00452 } 00453 00454 entry->down = NULL; 00455 entry->up = dir; 00456 entry->expanded = FALSE; 00457 entry->scanned = FALSE; 00458 entry->level = level; 00459 00460 #ifndef _NO_EXTENSIONS 00461 entry->etype = ET_SHELL; 00462 entry->bhfi_valid = FALSE; 00463 #endif 00464 00465 last = entry; 00466 } 00467 } 00468 00469 IEnumIDList_Release(idlist); 00470 } 00471 00472 if (last) 00473 last->next = NULL; 00474 00475 dir->down = first_entry; 00476 dir->scanned = TRUE; 00477 } 00478 00479 #endif /* _SHELL_FOLDERS */
Winefile Source Code Documentation
generated on 15.09.2008 by ![]() |