00001 /* 00002 * Copyright 2003, 2004, 2005, 2006, 2010 Martin Fuchs 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation; either 00007 * version 2.1 of the License, or (at your option) any later version. 00008 * 00009 * This library is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Lesser General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Lesser General Public 00015 * License along with this library; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 */ 00018 00019 00020 // 00021 // Explorer clone 00022 // 00023 // explorer.cpp 00024 // 00025 // Martin Fuchs, 23.07.2003 00026 // 00027 // Credits: Thanks to Leon Finker for his explorer cabinet window example 00028 // 00029 00030 00031 #include <precomp.h> // <precomp.h> instead of "precomp.h" because the ROS build system needs this to find the precompiled header file (*.gch) in the output directory tree 00032 00033 #include "resource.h" 00034 00035 #include <locale.h> // for setlocale() 00036 00037 #ifndef __WINE__ 00038 #include <io.h> // for dup2() 00039 #include <fcntl.h> // for _O_RDONLY 00040 #endif 00041 00042 #include "dialogs/settings.h" // for MdiSdiDlg 00043 00044 #include "services/shellservices.h" 00045 00046 00047 extern "C" int initialize_gdb_stub(); // start up GDB stub 00048 00049 00050 DynamicLoadLibFct<void(__stdcall*)(BOOL)> g_SHDOCVW_ShellDDEInit(TEXT("SHDOCVW"), 118); 00051 00052 00053 ExplorerGlobals g_Globals; 00054 00055 00056 ExplorerGlobals::ExplorerGlobals() 00057 { 00058 _hInstance = 0; 00059 _cfStrFName = 0; 00060 00061 #ifndef ROSSHELL 00062 _hframeClass = 0; 00063 _hMainWnd = 0; 00064 _desktop_mode = false; 00065 _prescan_nodes = false; 00066 #endif 00067 00068 _log = NULL; 00069 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003) 00070 _SHRestricted = 0; 00071 #endif 00072 _hwndDesktopBar = 0; 00073 _hwndShellView = 0; 00074 _hwndDesktop = 0; 00075 } 00076 00077 00078 void ExplorerGlobals::init(HINSTANCE hInstance) 00079 { 00080 _hInstance = hInstance; 00081 00082 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003) 00083 _SHRestricted = (DWORD(STDAPICALLTYPE*)(RESTRICTIONS)) GetProcAddress(GetModuleHandle(TEXT("SHELL32")), "SHRestricted"); 00084 #endif 00085 00086 _icon_cache.init(); 00087 } 00088 00089 00090 void ExplorerGlobals::read_persistent() 00091 { 00092 // read configuration file 00093 _cfg_dir.printf(TEXT("%s\\ReactOS"), (LPCTSTR)SpecialFolderFSPath(CSIDL_APPDATA,0)); 00094 _cfg_path.printf(TEXT("%s\\ros-explorer-cfg.xml"), _cfg_dir.c_str()); 00095 00096 if (!_cfg.read_file(_cfg_path)) { 00097 if (!_cfg._errors.empty()) 00098 MessageBox(_hwndDesktop, _cfg._errors.str(), 00099 TEXT("ROS Explorer - reading user settings"), MB_OK); 00100 00101 _cfg.read_file(TEXT("explorer-cfg-template.xml")); 00102 } 00103 00104 // read bookmarks 00105 _favorites_path.printf(TEXT("%s\\ros-explorer-bookmarks.xml"), _cfg_dir.c_str()); 00106 00107 if (!_favorites.read(_favorites_path)) { 00108 _favorites.import_IE_favorites(0); 00109 _favorites.write(_favorites_path); 00110 } 00111 } 00112 00113 void ExplorerGlobals::write_persistent() 00114 { 00115 // write configuration file 00116 RecursiveCreateDirectory(_cfg_dir); 00117 00118 _cfg.write_file(_cfg_path); 00119 _favorites.write(_favorites_path); 00120 } 00121 00122 00123 XMLPos ExplorerGlobals::get_cfg() 00124 { 00125 XMLPos cfg_pos(&_cfg); 00126 00127 cfg_pos.smart_create("explorer-cfg"); 00128 00129 return cfg_pos; 00130 } 00131 00132 XMLPos ExplorerGlobals::get_cfg(const char* path) 00133 { 00134 XMLPos cfg_pos(&_cfg); 00135 00136 cfg_pos.smart_create("explorer-cfg"); 00137 cfg_pos.create_relative(path); 00138 00139 return cfg_pos; 00140 } 00141 00142 00143 void _log_(LPCTSTR txt) 00144 { 00145 FmtString msg(TEXT("%s\n"), txt); 00146 00147 if (g_Globals._log) 00148 _fputts(msg, g_Globals._log); 00149 00150 OutputDebugString(msg); 00151 } 00152 00153 00154 bool FileTypeManager::is_exe_file(LPCTSTR ext) 00155 { 00156 static const LPCTSTR s_executable_extensions[] = { 00157 TEXT("COM"), 00158 TEXT("EXE"), 00159 TEXT("BAT"), 00160 TEXT("CMD"), 00161 TEXT("CMM"), 00162 TEXT("BTM"), 00163 TEXT("AWK"), 00164 0 00165 }; 00166 00167 TCHAR ext_buffer[_MAX_EXT]; 00168 const LPCTSTR* p; 00169 LPCTSTR s; 00170 LPTSTR d; 00171 00172 for(s=ext+1,d=ext_buffer; (*d=toupper(*s)); s++) 00173 ++d; 00174 00175 for(p=s_executable_extensions; *p; p++) 00176 if (!lstrcmp(ext_buffer, *p)) 00177 return true; 00178 00179 return false; 00180 } 00181 00182 00183 const FileTypeInfo& FileTypeManager::operator[](String ext) 00184 { 00185 ext.toLower(); 00186 00187 iterator found = find(ext); 00188 if (found != end()) 00189 return found->second; 00190 00191 FileTypeInfo& ftype = super::operator[](ext); 00192 00193 ftype._neverShowExt = false; 00194 00195 HKEY hkey; 00196 TCHAR value[MAX_PATH], display_name[MAX_PATH]; 00197 LONG valuelen = sizeof(value); 00198 00199 if (!RegQueryValue(HKEY_CLASSES_ROOT, ext, value, &valuelen)) { 00200 ftype._classname = value; 00201 00202 valuelen = sizeof(display_name); 00203 if (!RegQueryValue(HKEY_CLASSES_ROOT, ftype._classname, display_name, &valuelen)) 00204 ftype._displayname = display_name; 00205 00206 if (!RegOpenKey(HKEY_CLASSES_ROOT, ftype._classname, &hkey)) { 00207 if (!RegQueryValueEx(hkey, TEXT("NeverShowExt"), 0, NULL, NULL, NULL)) 00208 ftype._neverShowExt = true; 00209 00210 RegCloseKey(hkey); 00211 } 00212 } 00213 00214 return ftype; 00215 } 00216 00217 LPCTSTR FileTypeManager::set_type(Entry* entry, bool dont_hide_ext) 00218 { 00219 LPCTSTR ext = _tcsrchr(entry->_data.cFileName, TEXT('.')); 00220 00221 if (ext) { 00222 const FileTypeInfo& type = (*this)[ext]; 00223 00224 if (!type._displayname.empty()) 00225 entry->_type_name = _tcsdup(type._displayname); 00226 00227 // hide some file extensions 00228 if (type._neverShowExt && !dont_hide_ext) { 00229 int len = ext - entry->_data.cFileName; 00230 00231 if (entry->_display_name != entry->_data.cFileName) 00232 free(entry->_display_name); 00233 00234 entry->_display_name = (LPTSTR) malloc((len+1)*sizeof(TCHAR)); 00235 lstrcpyn(entry->_display_name, entry->_data.cFileName, len + 1); 00236 } 00237 00238 if (is_exe_file(ext)) 00239 entry->_data.dwFileAttributes |= ATTRIBUTE_EXECUTABLE; 00240 } 00241 00242 return ext; 00243 } 00244 00245 00246 Icon::Icon() 00247 : _id(ICID_UNKNOWN), 00248 _itype(IT_STATIC), 00249 _hicon(0) 00250 { 00251 } 00252 00253 Icon::Icon(ICON_ID id, UINT nid) //, int cx, int cy 00254 : _id(id), 00255 _itype(IT_STATIC), 00256 _hicon(ResIcon(nid)) // ResIconEx(nid, cx, cy) 00257 { 00258 } 00259 00260 Icon::Icon(ICON_ID id, UINT nid, int icon_size) 00261 : _id(id), 00262 _itype(IT_STATIC), 00263 _hicon(ResIconEx(nid, icon_size, icon_size)) 00264 { 00265 } 00266 00267 Icon::Icon(ICON_TYPE itype, int id, HICON hIcon) 00268 : _id((ICON_ID)id), 00269 _itype(itype), 00270 _hicon(hIcon) 00271 { 00272 } 00273 00274 Icon::Icon(ICON_TYPE itype, int id, int sys_idx) 00275 : _id((ICON_ID)id), 00276 _itype(itype), 00277 _sys_idx(sys_idx) 00278 { 00279 } 00280 00281 void Icon::draw(HDC hdc, int x, int y, int cx, int cy, COLORREF bk_color, HBRUSH bk_brush) const 00282 { 00283 if (_itype == IT_SYSCACHE) 00284 ImageList_DrawEx(g_Globals._icon_cache.get_sys_imagelist(), _sys_idx, hdc, x, y, cx, cy, bk_color, CLR_DEFAULT, ILD_NORMAL); 00285 else 00286 DrawIconEx(hdc, x, y, _hicon, cx, cy, 0, bk_brush, DI_NORMAL); 00287 } 00288 00289 HBITMAP Icon::create_bitmap(COLORREF bk_color, HBRUSH hbrBkgnd, HDC hdc_wnd) const 00290 { 00291 if (_itype == IT_SYSCACHE) { 00292 HIMAGELIST himl = g_Globals._icon_cache.get_sys_imagelist(); 00293 00294 int cx, cy; 00295 ImageList_GetIconSize(himl, &cx, &cy); 00296 00297 HBITMAP hbmp = CreateCompatibleBitmap(hdc_wnd, cx, cy); 00298 HDC hdc = CreateCompatibleDC(hdc_wnd); 00299 HBITMAP hbmp_old = SelectBitmap(hdc, hbmp); 00300 ImageList_DrawEx(himl, _sys_idx, hdc, 0, 0, cx, cy, bk_color, CLR_DEFAULT, ILD_NORMAL); 00301 SelectBitmap(hdc, hbmp_old); 00302 DeleteDC(hdc); 00303 00304 return hbmp; 00305 } else 00306 return create_bitmap_from_icon(_hicon, hbrBkgnd, hdc_wnd); 00307 } 00308 00309 00310 int Icon::add_to_imagelist(HIMAGELIST himl, HDC hdc_wnd, COLORREF bk_color, HBRUSH bk_brush) const 00311 { 00312 int ret; 00313 00314 if (_itype == IT_SYSCACHE) { 00315 HIMAGELIST himl = g_Globals._icon_cache.get_sys_imagelist(); 00316 00317 int cx, cy; 00318 ImageList_GetIconSize(himl, &cx, &cy); 00319 00320 HBITMAP hbmp = CreateCompatibleBitmap(hdc_wnd, cx, cy); 00321 HDC hdc = CreateCompatibleDC(hdc_wnd); 00322 HBITMAP hbmp_old = SelectBitmap(hdc, hbmp); 00323 ImageList_DrawEx(himl, _sys_idx, hdc, 0, 0, cx, cy, bk_color, CLR_DEFAULT, ILD_NORMAL); 00324 SelectBitmap(hdc, hbmp_old); 00325 DeleteDC(hdc); 00326 00327 ret = ImageList_Add(himl, hbmp, 0); 00328 00329 DeleteObject(hbmp); 00330 } else 00331 ret = ImageList_AddAlphaIcon(himl, _hicon, bk_brush, hdc_wnd); 00332 00333 return ret; 00334 } 00335 00336 HBITMAP create_bitmap_from_icon(HICON hIcon, HBRUSH hbrush_bkgnd, HDC hdc_wnd/*, int icon_size*/) 00337 { 00338 int cx = ICON_SIZE_SMALL; 00339 int cy = ICON_SIZE_SMALL; 00340 HBITMAP hbmp = CreateCompatibleBitmap(hdc_wnd, cx, cy); 00341 00342 MemCanvas canvas; 00343 BitmapSelection sel(canvas, hbmp); 00344 00345 RECT rect = {0, 0, cx, cy}; 00346 FillRect(canvas, &rect, hbrush_bkgnd); 00347 00348 DrawIconEx(canvas, 0, 0, hIcon, cx, cy, 0, hbrush_bkgnd, DI_NORMAL); 00349 00350 return hbmp; 00351 } 00352 00353 HBITMAP create_small_bitmap_from_icon(HICON hIcon, HBRUSH hbrush_bkgnd, HDC hdc_wnd) 00354 { 00355 int cx = GetSystemMetrics(SM_CXSMICON); 00356 int cy = GetSystemMetrics(SM_CYSMICON); 00357 HBITMAP hbmp = CreateCompatibleBitmap(hdc_wnd, cx, cy); 00358 00359 MemCanvas canvas; 00360 BitmapSelection sel(canvas, hbmp); 00361 00362 RECT rect = {0, 0, cx, cy}; 00363 FillRect(canvas, &rect, hbrush_bkgnd); 00364 00365 DrawIconEx(canvas, 0, 0, hIcon, cx, cy, 0, hbrush_bkgnd, DI_NORMAL); 00366 00367 return hbmp; 00368 } 00369 00370 int ImageList_AddAlphaIcon(HIMAGELIST himl, HICON hIcon, HBRUSH hbrush_bkgnd, HDC hdc_wnd) 00371 { 00372 HBITMAP hbmp = create_bitmap_from_icon(hIcon, hbrush_bkgnd, hdc_wnd); 00373 00374 int ret = ImageList_Add(himl, hbmp, 0); 00375 00376 DeleteObject(hbmp); 00377 00378 return ret; 00379 } 00380 00381 00382 int IconCache::s_next_id = ICID_DYNAMIC; 00383 00384 00385 void IconCache::init() 00386 { 00387 int icon_size = STARTMENUROOT_ICON_SIZE; 00388 00389 _icons[ICID_NONE] = Icon(IT_STATIC, ICID_NONE, (HICON)0); 00390 00391 _icons[ICID_FOLDER] = Icon(ICID_FOLDER, IDI_FOLDER); 00392 //_icons[ICID_DOCUMENT] = Icon(ICID_DOCUMENT, IDI_DOCUMENT); 00393 _icons[ICID_EXPLORER] = Icon(ICID_EXPLORER, IDI_EXPLORER); 00394 // _icons[ICID_APP] = Icon(ICID_APP, IDI_APPICON); 00395 00396 _icons[ICID_CONFIG] = Icon(ICID_CONFIG, IDI_CONFIG, icon_size); 00397 _icons[ICID_DOCUMENTS] = Icon(ICID_DOCUMENTS, IDI_DOCUMENTS, icon_size); 00398 _icons[ICID_FAVORITES] = Icon(ICID_FAVORITES, IDI_FAVORITES, icon_size); 00399 _icons[ICID_INFO] = Icon(ICID_INFO, IDI_INFO, icon_size); 00400 _icons[ICID_APPS] = Icon(ICID_APPS, IDI_APPS, icon_size); 00401 _icons[ICID_SEARCH] = Icon(ICID_SEARCH, IDI_SEARCH, icon_size); 00402 _icons[ICID_ACTION] = Icon(ICID_ACTION, IDI_ACTION, icon_size); 00403 _icons[ICID_SEARCH_DOC] = Icon(ICID_SEARCH_DOC, IDI_SEARCH_DOC, icon_size); 00404 _icons[ICID_PRINTER] = Icon(ICID_PRINTER, IDI_PRINTER, icon_size); 00405 _icons[ICID_NETWORK] = Icon(ICID_NETWORK, IDI_NETWORK, icon_size); 00406 _icons[ICID_COMPUTER] = Icon(ICID_COMPUTER, IDI_COMPUTER, icon_size); 00407 _icons[ICID_LOGOFF] = Icon(ICID_LOGOFF, IDI_LOGOFF, icon_size); 00408 _icons[ICID_SHUTDOWN] = Icon(ICID_SHUTDOWN, IDI_SHUTDOWN, icon_size); 00409 _icons[ICID_RESTART] = Icon(ICID_RESTART, IDI_RESTART, icon_size); 00410 _icons[ICID_BOOKMARK] = Icon(ICID_BOOKMARK, IDI_DOT_TRANS, icon_size); 00411 _icons[ICID_MINIMIZE] = Icon(ICID_MINIMIZE, IDI_MINIMIZE, icon_size); 00412 _icons[ICID_CONTROLPAN] = Icon(ICID_CONTROLPAN, IDI_CONTROLPAN, icon_size); 00413 _icons[ICID_DESKSETTING]= Icon(ICID_DESKSETTING,IDI_DESKSETTING,icon_size); 00414 _icons[ICID_NETCONNS] = Icon(ICID_NETCONNS, IDI_NETCONNS, icon_size); 00415 _icons[ICID_ADMIN] = Icon(ICID_ADMIN, IDI_ADMIN, icon_size); 00416 _icons[ICID_RECENT] = Icon(ICID_RECENT, IDI_RECENT, icon_size); 00417 } 00418 00419 00420 const Icon& IconCache::extract(LPCTSTR path, ICONCACHE_FLAGS flags) 00421 { 00422 // search for matching icon with unchanged flags in the cache 00423 CacheKey mapkey(path, flags); 00424 PathCacheMap::iterator found = _pathCache.find(mapkey); 00425 00426 if (found != _pathCache.end()) 00427 return _icons[found->second]; 00428 00429 // search for matching icon with handle 00430 CacheKey mapkey_hicon(path, flags|ICF_HICON); 00431 if (flags != mapkey_hicon.second) { 00432 found = _pathCache.find(mapkey_hicon); 00433 00434 if (found != _pathCache.end()) 00435 return _icons[found->second]; 00436 } 00437 00438 // search for matching icon in the system image list cache 00439 CacheKey mapkey_syscache(path, flags|ICF_SYSCACHE); 00440 if (flags != mapkey_syscache.second) { 00441 found = _pathCache.find(mapkey_syscache); 00442 00443 if (found != _pathCache.end()) 00444 return _icons[found->second]; 00445 } 00446 00447 SHFILEINFO sfi; 00448 00449 int shgfi_flags = 0; 00450 00451 if (flags & ICF_OPEN) 00452 shgfi_flags |= SHGFI_OPENICON; 00453 00454 if ((flags&(ICF_LARGE|ICF_MIDDLE|ICF_OVERLAYS|ICF_HICON)) && !(flags&ICF_SYSCACHE)) { 00455 shgfi_flags |= SHGFI_ICON; 00456 00457 if (!(flags & (ICF_LARGE|ICF_MIDDLE))) 00458 shgfi_flags |= SHGFI_SMALLICON; 00459 00460 if (flags & ICF_OVERLAYS) 00461 shgfi_flags |= SHGFI_ADDOVERLAYS; 00462 00463 // get small/big icons with/without overlays 00464 if (SHGetFileInfo(path, 0, &sfi, sizeof(sfi), shgfi_flags)) { 00465 const Icon& icon = add(sfi.hIcon, IT_CACHED); 00466 00467 ///@todo limit cache size 00468 _pathCache[mapkey_hicon] = icon; 00469 00470 return icon; 00471 } 00472 } else { 00473 assert(!(flags&ICF_OVERLAYS)); 00474 00475 shgfi_flags |= SHGFI_SYSICONINDEX|SHGFI_SMALLICON; 00476 00477 // use system image list - the "search program dialog" needs it 00478 HIMAGELIST himlSys_small = (HIMAGELIST) SHGetFileInfo(path, 0, &sfi, sizeof(sfi), shgfi_flags); 00479 00480 if (himlSys_small) { 00481 _himlSys_small = himlSys_small; 00482 00483 const Icon& icon = add(sfi.iIcon/*, IT_SYSCACHE*/); 00484 00485 ///@todo limit cache size 00486 _pathCache[mapkey_syscache] = icon; 00487 00488 return icon; 00489 } 00490 } 00491 00492 return _icons[ICID_NONE]; 00493 } 00494 00495 const Icon& IconCache::extract(LPCTSTR path, int icon_idx, ICONCACHE_FLAGS flags) 00496 { 00497 IdxCacheKey key(path, make_pair(icon_idx, (flags|ICF_HICON)&~ICF_SYSCACHE)); 00498 00499 key.first.toLower(); 00500 00501 IdxCacheMap::iterator found = _idxCache.find(key); 00502 00503 if (found != _idxCache.end()) 00504 return _icons[found->second]; 00505 00506 HICON hIcon; 00507 00508 if ((int)ExtractIconEx(path, icon_idx, NULL, &hIcon, 1) > 0) { 00509 const Icon& icon = add(hIcon, IT_CACHED); 00510 00511 _idxCache[key] = icon; 00512 00513 return icon; 00514 } else { 00515 00516 ///@todo retreive "http://.../favicon.ico" format icons 00517 00518 return _icons[ICID_NONE]; 00519 } 00520 } 00521 00522 const Icon& IconCache::extract(IExtractIcon* pExtract, LPCTSTR path, int icon_idx, ICONCACHE_FLAGS flags) 00523 { 00524 HICON hIconLarge = 0; 00525 HICON hIcon; 00526 00527 int icon_size = ICON_SIZE_FROM_ICF(flags); 00528 HRESULT hr = pExtract->Extract(path, icon_idx, &hIconLarge, &hIcon, MAKELONG(GetSystemMetrics(SM_CXICON), icon_size)); 00529 00530 if (hr == NOERROR) { //@@ oder SUCCEEDED(hr) ? 00531 if (icon_size > ICON_SIZE_SMALL) { //@@ OK? 00532 if (hIcon) 00533 DestroyIcon(hIcon); 00534 00535 hIcon = hIconLarge; 00536 } else { 00537 if (hIconLarge) 00538 DestroyIcon(hIconLarge); 00539 } 00540 00541 if (hIcon) 00542 return add(hIcon); //@@ When do we want not to free this icons? 00543 } 00544 00545 return _icons[ICID_NONE]; 00546 } 00547 00548 const Icon& IconCache::extract(LPCITEMIDLIST pidl, ICONCACHE_FLAGS flags) 00549 { 00550 // search for matching icon with unchanged flags in the cache 00551 PidlCacheKey mapkey(pidl, flags); 00552 PidlCacheMap::iterator found = _pidlcache.find(mapkey); 00553 00554 if (found != _pidlcache.end()) 00555 return _icons[found->second]; 00556 00557 // search for matching icon with handle 00558 PidlCacheKey mapkey_hicon(pidl, flags|ICF_HICON); 00559 if (flags != mapkey_hicon.second) { 00560 found = _pidlcache.find(mapkey_hicon); 00561 00562 if (found != _pidlcache.end()) 00563 return _icons[found->second]; 00564 } 00565 00566 // search for matching icon in the system image list cache 00567 PidlCacheKey mapkey_syscache(pidl, flags|ICF_SYSCACHE); 00568 if (flags != mapkey_syscache.second) { 00569 found = _pidlcache.find(mapkey_syscache); 00570 00571 if (found != _pidlcache.end()) 00572 return _icons[found->second]; 00573 } 00574 00575 SHFILEINFO sfi; 00576 00577 int shgfi_flags = SHGFI_PIDL; 00578 00579 if (!(flags & (ICF_LARGE|ICF_MIDDLE))) 00580 shgfi_flags |= SHGFI_SMALLICON; 00581 00582 if (flags & ICF_OPEN) 00583 shgfi_flags |= SHGFI_OPENICON; 00584 00585 if (flags & ICF_SYSCACHE) { 00586 assert(!(flags&ICF_OVERLAYS)); 00587 00588 HIMAGELIST himlSys = (HIMAGELIST) SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX|shgfi_flags); 00589 if (himlSys) { 00590 const Icon& icon = add(sfi.iIcon/*, IT_SYSCACHE*/); 00591 00592 ///@todo limit cache size 00593 _pidlcache[mapkey_syscache] = icon; 00594 00595 return icon; 00596 } 00597 } else { 00598 if (flags & ICF_OVERLAYS) 00599 shgfi_flags |= SHGFI_ADDOVERLAYS; 00600 00601 if (SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi), SHGFI_ICON|shgfi_flags)) { 00602 const Icon& icon = add(sfi.hIcon, IT_CACHED); 00603 00604 ///@todo limit cache size 00605 _pidlcache[mapkey_hicon] = icon; 00606 00607 return icon; 00608 } 00609 } 00610 00611 return _icons[ICID_NONE]; 00612 } 00613 00614 00615 const Icon& IconCache::add(HICON hIcon, ICON_TYPE type) 00616 { 00617 int id = ++s_next_id; 00618 00619 return _icons[id] = Icon(type, id, hIcon); 00620 } 00621 00622 const Icon& IconCache::add(int sys_idx/*, ICON_TYPE type=IT_SYSCACHE*/) 00623 { 00624 int id = ++s_next_id; 00625 00626 return _icons[id] = SysCacheIcon(id, sys_idx); 00627 } 00628 00629 const Icon& IconCache::get_icon(int id) 00630 { 00631 return _icons[id]; 00632 } 00633 00634 IconCache::~IconCache() 00635 { 00636 /* We don't need to free cached resources - they are automatically freed at process termination 00637 for (int index = s_next_id; index >= 0; index--) { 00638 IconMap::iterator found = _icons.find(index); 00639 00640 if (found != _icons.end()) { 00641 Icon& icon = found->second; 00642 00643 if ((icon.get_icontype() == IT_DYNAMIC) || 00644 (icon.get_icontype() == IT_CACHED)) 00645 { 00646 DestroyIcon(icon.get_hicon()); 00647 _icons.erase(found); 00648 } 00649 } 00650 } 00651 */ 00652 } 00653 00654 void IconCache::free_icon(int icon_id) 00655 { 00656 IconMap::iterator found = _icons.find(icon_id); 00657 00658 if (found != _icons.end()) { 00659 Icon& icon = found->second; 00660 00661 if (icon.destroy()) 00662 _icons.erase(found); 00663 } 00664 } 00665 00666 00667 ResString::ResString(UINT nid) 00668 { 00669 TCHAR buffer[BUFFER_LEN]; 00670 00671 int len = LoadString(g_Globals._hInstance, nid, buffer, sizeof(buffer)/sizeof(TCHAR)); 00672 00673 super::assign(buffer, len); 00674 } 00675 00676 00677 ResIcon::ResIcon(UINT nid) 00678 { 00679 _hicon = LoadIcon(g_Globals._hInstance, MAKEINTRESOURCE(nid)); 00680 } 00681 00682 SmallIcon::SmallIcon(UINT nid) 00683 { 00684 _hicon = (HICON)LoadImage(g_Globals._hInstance, MAKEINTRESOURCE(nid), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED); 00685 } 00686 00687 ResIconEx::ResIconEx(UINT nid, int w, int h) 00688 { 00689 _hicon = (HICON)LoadImage(g_Globals._hInstance, MAKEINTRESOURCE(nid), IMAGE_ICON, w, h, LR_SHARED); 00690 } 00691 00692 00693 void SetWindowIcon(HWND hwnd, UINT nid) 00694 { 00695 HICON hIcon = ResIcon(nid); 00696 (void)Window_SetIcon(hwnd, ICON_BIG, hIcon); 00697 00698 HICON hIconSmall = SmallIcon(nid); 00699 (void)Window_SetIcon(hwnd, ICON_SMALL, hIconSmall); 00700 } 00701 00702 00703 ResBitmap::ResBitmap(UINT nid) 00704 { 00705 _hBmp = LoadBitmap(g_Globals._hInstance, MAKEINTRESOURCE(nid)); 00706 } 00707 00708 00709 #ifndef ROSSHELL 00710 00711 void explorer_show_frame(int cmdShow, LPTSTR lpCmdLine) 00712 { 00713 ExplorerCmd cmd; 00714 00715 if (g_Globals._hMainWnd) { 00716 if (IsIconic(g_Globals._hMainWnd)) 00717 ShowWindow(g_Globals._hMainWnd, SW_RESTORE); 00718 else 00719 SetForegroundWindow(g_Globals._hMainWnd); 00720 00721 return; 00722 } 00723 00724 g_Globals._prescan_nodes = false; 00725 00726 XMLPos explorer_options = g_Globals.get_cfg("general/explorer"); 00727 XS_String mdiStr = XMLString(explorer_options, "mdi"); 00728 00729 // If there isn't yet the "mdi" setting in the configuration, display the MDI/SDI dialog. 00730 if (mdiStr.empty()) 00731 Dialog::DoModal(IDD_MDI_SDI, WINDOW_CREATOR(MdiSdiDlg), g_Globals._hwndDesktop); 00732 00733 // Now read the MDI attribute again and interpret it as boolean value. 00734 cmd._mdi = XMLBool(explorer_options, "mdi", true); 00735 00736 cmd._cmdShow = cmdShow; 00737 00738 // parse command line options, which may overwrite the MDI flag 00739 if (lpCmdLine) 00740 cmd.ParseCmdLine(lpCmdLine); 00741 00742 // create main window 00743 MainFrameBase::Create(cmd); 00744 } 00745 00746 bool ExplorerCmd::ParseCmdLine(LPCTSTR lpCmdLine) 00747 { 00748 bool ok = true; 00749 00750 LPCTSTR b = lpCmdLine; 00751 LPCTSTR p = b; 00752 00753 while(*b) { 00754 // remove leading space 00755 while(_istspace((unsigned)*b)) 00756 ++b; 00757 00758 p = b; 00759 00760 bool quote = false; 00761 00762 // options are separated by ',' 00763 for(; *p; ++p) { 00764 if (*p == '"') // Quote characters may appear at any position in the command line. 00765 quote = !quote; 00766 else if (*p==',' && !quote) 00767 break; 00768 } 00769 00770 if (p > b) { 00771 int l = p - b; 00772 00773 // remove trailing space 00774 while(l>0 && _istspace((unsigned)b[l-1])) 00775 --l; 00776 00777 if (!EvaluateOption(String(b, l))) 00778 ok = false; 00779 00780 if (*p) 00781 ++p; 00782 00783 b = p; 00784 } 00785 } 00786 00787 return ok; 00788 } 00789 00790 bool ExplorerCmd::EvaluateOption(LPCTSTR option) 00791 { 00792 String opt_str; 00793 00794 // Remove quote characters, as they are evaluated at this point. 00795 for(; *option; ++option) 00796 if (*option != '"') 00797 opt_str += *option; 00798 00799 option = opt_str; 00800 00801 if (option[0] == '/') { 00802 ++option; 00803 00804 // option /e for windows in explorer mode 00805 if (!_tcsicmp(option, TEXT("e"))) 00806 _flags |= OWM_EXPLORE; 00807 // option /root for rooted explorer windows 00808 else if (!_tcsicmp(option, TEXT("root"))) 00809 _flags |= OWM_ROOTED; 00810 // non-standard options: /mdi, /sdi 00811 else if (!_tcsicmp(option, TEXT("mdi"))) 00812 _mdi = true; 00813 else if (!_tcsicmp(option, TEXT("sdi"))) 00814 _mdi = false; 00815 else 00816 return false; 00817 } else { 00818 if (!_path.empty()) 00819 return false; 00820 00821 _path = opt_str; 00822 } 00823 00824 return true; 00825 } 00826 00827 bool ExplorerCmd::IsValidPath() const 00828 { 00829 if (!_path.empty()) { 00830 DWORD attribs = GetFileAttributes(_path); 00831 00832 if (attribs!=INVALID_FILE_ATTRIBUTES && (attribs&FILE_ATTRIBUTE_DIRECTORY)) 00833 return true; // file system path 00834 else if (*_path==':' && _path.at(1)==':') 00835 return true; // text encoded IDL 00836 } 00837 00838 return false; 00839 } 00840 00841 #else 00842 00843 void explorer_show_frame(int cmdShow, LPTSTR lpCmdLine) 00844 { 00845 if (!lpCmdLine) 00846 lpCmdLine = TEXT("explorer.exe"); 00847 00848 launch_file(GetDesktopWindow(), lpCmdLine, cmdShow); 00849 } 00850 00851 #endif 00852 00853 00854 PopupMenu::PopupMenu(UINT nid) 00855 { 00856 HMENU hMenu = LoadMenu(g_Globals._hInstance, MAKEINTRESOURCE(nid)); 00857 _hmenu = GetSubMenu(hMenu, 0); 00858 RemoveMenu(hMenu, 0, MF_BYPOSITION); 00859 DestroyMenu(hMenu); 00860 } 00861 00862 00863 /// "About Explorer" Dialog 00864 struct ExplorerAboutDlg : public 00865 CtlColorParent< 00866 OwnerDrawParent<Dialog> 00867 > 00868 { 00869 typedef CtlColorParent< 00870 OwnerDrawParent<Dialog> 00871 > super; 00872 00873 ExplorerAboutDlg(HWND hwnd) 00874 : super(hwnd) 00875 { 00876 SetWindowIcon(hwnd, IDI_REACTOS); 00877 00878 new FlatButton(hwnd, IDOK); 00879 00880 _hfont = CreateFont(20, 0, 0, 0, FW_BOLD, TRUE, 0, 0, 0, 0, 0, 0, 0, TEXT("Sans Serif")); 00881 new ColorStatic(hwnd, IDC_ROS_EXPLORER, RGB(32,32,128), 0, _hfont); 00882 00883 new HyperlinkCtrl(hwnd, IDC_WWW); 00884 00885 FmtString ver_txt(ResString(IDS_EXPLORER_VERSION_STR), (LPCTSTR)ResString(IDS_VERSION_STR)); 00886 SetWindowText(GetDlgItem(hwnd, IDC_VERSION_TXT), ver_txt); 00887 00888 HWND hwnd_winver = GetDlgItem(hwnd, IDC_WIN_VERSION); 00889 SetWindowText(hwnd_winver, get_windows_version_str()); 00890 SetWindowFont(hwnd_winver, GetStockFont(DEFAULT_GUI_FONT), FALSE); 00891 00892 CenterWindow(hwnd); 00893 } 00894 00895 ~ExplorerAboutDlg() 00896 { 00897 DeleteObject(_hfont); 00898 } 00899 00900 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) 00901 { 00902 switch(nmsg) { 00903 case WM_PAINT: 00904 Paint(); 00905 break; 00906 00907 default: 00908 return super::WndProc(nmsg, wparam, lparam); 00909 } 00910 00911 return 0; 00912 } 00913 00914 void Paint() 00915 { 00916 PaintCanvas canvas(_hwnd); 00917 00918 HICON hicon = (HICON) LoadImage(g_Globals._hInstance, MAKEINTRESOURCE(IDI_REACTOS_BIG), IMAGE_ICON, 0, 0, LR_SHARED); 00919 00920 DrawIconEx(canvas, 20, 10, hicon, 0, 0, 0, 0, DI_NORMAL); 00921 } 00922 00923 protected: 00924 HFONT _hfont; 00925 }; 00926 00927 void explorer_about(HWND hwndParent) 00928 { 00929 Dialog::DoModal(IDD_ABOUT_EXPLORER, WINDOW_CREATOR(ExplorerAboutDlg), hwndParent); 00930 } 00931 00932 00933 static void InitInstance(HINSTANCE hInstance) 00934 { 00935 CONTEXT("InitInstance"); 00936 00937 setlocale(LC_COLLATE, ""); // set collating rules to local settings for compareName 00938 00939 #ifndef ROSSHELL 00940 // register frame window class 00941 g_Globals._hframeClass = IconWindowClass(CLASSNAME_FRAME,IDI_EXPLORER); 00942 00943 // register child window class 00944 WindowClass(CLASSNAME_CHILDWND, CS_CLASSDC|CS_DBLCLKS|CS_VREDRAW).Register(); 00945 00946 // register tree window class 00947 WindowClass(CLASSNAME_WINEFILETREE, CS_CLASSDC|CS_DBLCLKS|CS_VREDRAW).Register(); 00948 #endif 00949 00950 g_Globals._cfStrFName = RegisterClipboardFormat(CFSTR_FILENAME); 00951 } 00952 00953 00954 int explorer_main(HINSTANCE hInstance, LPTSTR lpCmdLine, int cmdShow) 00955 { 00956 CONTEXT("explorer_main"); 00957 00958 // initialize Common Controls library 00959 CommonControlInit usingCmnCtrl; 00960 00961 try { 00962 InitInstance(hInstance); 00963 } catch(COMException& e) { 00964 HandleException(e, GetDesktopWindow()); 00965 return -1; 00966 } 00967 00968 #ifndef ROSSHELL 00969 if (cmdShow != SW_HIDE) { 00970 /* // don't maximize if being called from the ROS desktop 00971 if (cmdShow == SW_SHOWNORMAL) 00972 ///@todo read window placement from registry 00973 cmdShow = SW_MAXIMIZE; 00974 */ 00975 00976 explorer_show_frame(cmdShow, lpCmdLine); 00977 } 00978 #endif 00979 00980 return Window::MessageLoop(); 00981 } 00982 00983 00984 // MinGW does not provide a Unicode startup routine, so we have to implement an own. 00985 #if defined(__MINGW32__) && defined(UNICODE) 00986 00987 #define _tWinMain wWinMain 00988 int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int); 00989 00990 int main(int argc, char* argv[]) 00991 { 00992 CONTEXT("main"); 00993 00994 STARTUPINFO startupinfo; 00995 int nShowCmd = SW_SHOWNORMAL; 00996 00997 GetStartupInfo(&startupinfo); 00998 00999 if (startupinfo.dwFlags & STARTF_USESHOWWINDOW) 01000 nShowCmd = startupinfo.wShowWindow; 01001 01002 LPWSTR cmdline = GetCommandLineW(); 01003 01004 while(*cmdline && !_istspace((unsigned)*cmdline)) 01005 ++cmdline; 01006 01007 while(_istspace((unsigned)*cmdline)) 01008 ++cmdline; 01009 01010 return wWinMain(GetModuleHandle(NULL), 0, cmdline, nShowCmd); 01011 } 01012 01013 #endif // __MINGW && UNICODE 01014 01015 01016 static bool SetShellReadyEvent(LPCTSTR evtName) 01017 { 01018 HANDLE hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, evtName); 01019 if (!hEvent) 01020 return false; 01021 01022 SetEvent(hEvent); 01023 CloseHandle(hEvent); 01024 01025 return true; 01026 } 01027 01028 01029 int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd) 01030 { 01031 CONTEXT("WinMain()"); 01032 01033 BOOL any_desktop_running = IsAnyDesktopRunning(); 01034 01035 BOOL startup_desktop; 01036 01037 // strip extended options from the front of the command line 01038 String ext_options; 01039 01040 while(*lpCmdLine == '-') { 01041 while(*lpCmdLine && !_istspace((unsigned)*lpCmdLine)) 01042 ext_options += *lpCmdLine++; 01043 01044 while(_istspace((unsigned)*lpCmdLine)) 01045 ++lpCmdLine; 01046 } 01047 01048 // command line option "-install" to replace previous shell application with ROS Explorer 01049 if (_tcsstr(ext_options,TEXT("-install"))) { 01050 // install ROS Explorer into the registry 01051 TCHAR path[MAX_PATH]; 01052 01053 int l = GetModuleFileName(0, path, COUNTOF(path)); 01054 if (l) { 01055 HKEY hkey; 01056 01057 if (!RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"), &hkey)) { 01058 01059 ///@todo save previous shell application in config file 01060 01061 RegSetValueEx(hkey, TEXT("Shell"), 0, REG_SZ, (LPBYTE)path, l*sizeof(TCHAR)); 01062 RegCloseKey(hkey); 01063 } 01064 01065 if (!RegOpenKey(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"), &hkey)) { 01066 01067 ///@todo save previous shell application in config file 01068 01069 RegSetValueEx(hkey, TEXT("Shell"), 0, REG_SZ, (LPBYTE)TEXT(""), l*sizeof(TCHAR)); 01070 RegCloseKey(hkey); 01071 } 01072 } 01073 01074 HWND shellWindow = GetShellWindow(); 01075 01076 if (shellWindow) { 01077 DWORD pid; 01078 01079 // terminate shell process for NT like systems 01080 GetWindowThreadProcessId(shellWindow, &pid); 01081 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); 01082 01083 // On Win 9x it's sufficient to destroy the shell window. 01084 DestroyWindow(shellWindow); 01085 01086 if (TerminateProcess(hProcess, 0)) 01087 WaitForSingleObject(hProcess, INFINITE); 01088 01089 CloseHandle(hProcess); 01090 } 01091 01092 startup_desktop = TRUE; 01093 } else { 01094 // create desktop window and task bar only, if there is no other shell and we are 01095 // the first explorer instance 01096 // MS Explorer looks additionally into the registry entry HKCU\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\shell, 01097 // to decide wether it is currently configured as shell application. 01098 startup_desktop = !any_desktop_running; 01099 } 01100 01101 01102 bool autostart = !any_desktop_running; 01103 01104 // disable autostart if the SHIFT key is pressed 01105 if (GetAsyncKeyState(VK_SHIFT) < 0) 01106 autostart = false; 01107 01108 #ifdef _DEBUG //MF: disabled for debugging 01109 autostart = false; 01110 #endif 01111 01112 // If there is given the command line option "-desktop", create desktop window anyways 01113 if (_tcsstr(ext_options,TEXT("-desktop"))) 01114 startup_desktop = TRUE; 01115 #ifndef ROSSHELL 01116 else if (_tcsstr(ext_options,TEXT("-nodesktop"))) 01117 startup_desktop = FALSE; 01118 01119 // Don't display cabinet window in desktop mode 01120 if (startup_desktop && !_tcsstr(ext_options,TEXT("-explorer"))) 01121 nShowCmd = SW_HIDE; 01122 #endif 01123 01124 if (_tcsstr(ext_options,TEXT("-noautostart"))) 01125 autostart = false; 01126 else if (_tcsstr(ext_options,TEXT("-autostart"))) 01127 autostart = true; 01128 01129 #ifndef __WINE__ 01130 if (_tcsstr(ext_options,TEXT("-console"))) { 01131 AllocConsole(); 01132 01133 _dup2(_open_osfhandle((long)GetStdHandle(STD_INPUT_HANDLE), _O_RDONLY), 0); 01134 _dup2(_open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE), 0), 1); 01135 _dup2(_open_osfhandle((long)GetStdHandle(STD_ERROR_HANDLE), 0), 2); 01136 01137 g_Globals._log = _fdopen(1, "w"); 01138 setvbuf(g_Globals._log, 0, _IONBF, 0); 01139 01140 LOG(TEXT("starting explorer debug log\n")); 01141 } 01142 #endif 01143 01144 01145 if (startup_desktop) { 01146 // hide the XP login screen (Credit to Nicolas Escuder) 01147 // another undocumented event: "Global\\msgina: ReturnToWelcome" 01148 if (!SetShellReadyEvent(TEXT("msgina: ShellReadyEvent"))) 01149 SetShellReadyEvent(TEXT("Global\\msgina: ShellReadyEvent")); 01150 } 01151 #ifdef ROSSHELL 01152 else 01153 return 0; // no shell to launch, so exit immediatelly 01154 #endif 01155 01156 01157 if (!any_desktop_running) { 01158 // launch the shell DDE server 01159 if (g_SHDOCVW_ShellDDEInit) 01160 (*g_SHDOCVW_ShellDDEInit)(TRUE); 01161 } 01162 01163 01164 bool use_gdb_stub = false; // !IsDebuggerPresent(); 01165 01166 if (_tcsstr(ext_options,TEXT("-debug"))) 01167 use_gdb_stub = true; 01168 01169 if (_tcsstr(ext_options,TEXT("-break"))) { 01170 LOG(TEXT("debugger breakpoint")); 01171 #ifdef _MSC_VER 01172 __asm int 3 01173 #else 01174 asm("int3"); 01175 #endif 01176 } 01177 01178 // activate GDB remote debugging stub if no other debugger is running 01179 if (use_gdb_stub) { 01180 LOG(TEXT("waiting for debugger connection...\n")); 01181 01182 initialize_gdb_stub(); 01183 } 01184 01185 g_Globals.init(hInstance); 01186 01187 // initialize COM and OLE before creating the desktop window 01188 OleInit usingCOM; 01189 01190 // init common controls library 01191 CommonControlInit usingCmnCtrl; 01192 01193 g_Globals.read_persistent(); 01194 01195 if (startup_desktop) { 01196 WaitCursor wait; 01197 01198 g_Globals._desktops.init(); 01199 01200 g_Globals._hwndDesktop = DesktopWindow::Create(); 01201 #ifdef _USE_HDESK 01202 g_Globals._desktops.get_current_Desktop()->_hwndDesktop = g_Globals._hwndDesktop; 01203 #endif 01204 } 01205 01206 if (_tcsstr(ext_options,TEXT("-?"))) { 01207 MessageBoxA(g_Globals._hwndDesktop, 01208 "/e open cabinet window in explorer mode\r\n" 01209 "/root open cabinet window in rooted mode\r\n" 01210 "/mdi open cabinet window in MDI mode\r\n" 01211 "/sdi open cabinet window in SDI mode\r\n" 01212 "\r\n" 01213 "-? display command line options\r\n" 01214 "\r\n" 01215 "-desktop start in desktop mode regardless of an already running shell\r\n" 01216 "-nodesktop disable desktop mode\r\n" 01217 "-explorer display cabinet window regardless of enabled desktop mode\r\n" 01218 "\r\n" 01219 "-install replace previous shell application with ROS Explorer\r\n" 01220 "\r\n" 01221 "-noautostart disable autostarts\r\n" 01222 "-autostart enable autostarts regardless of debug build\r\n" 01223 "\r\n" 01224 "-console open debug console\r\n" 01225 "\r\n" 01226 "-debug activate GDB remote debugging stub\r\n" 01227 "-break activate debugger breakpoint\r\n", 01228 "ROS Explorer - command line options", MB_OK); 01229 } 01230 01231 Thread* pSSOThread = NULL; 01232 01233 if (startup_desktop) { 01234 // launch SSO thread to allow message processing independent from the explorer main thread 01235 pSSOThread = new SSOThread; 01236 pSSOThread->Start(); 01237 } 01238 01239 /**TODO launching autostart programs can be moved into a background thread. */ 01240 if (autostart) { 01241 const char* argv[] = {"", "s"}; // call startup routine in SESSION_START mode 01242 startup(2, argv); 01243 } 01244 01245 #ifndef ROSSHELL 01246 if (g_Globals._hwndDesktop) 01247 g_Globals._desktop_mode = true; 01248 #endif 01249 01250 01251 int ret = explorer_main(hInstance, lpCmdLine, nShowCmd); 01252 01253 01254 // write configuration file 01255 g_Globals.write_persistent(); 01256 01257 if (pSSOThread) { 01258 pSSOThread->Stop(); 01259 delete pSSOThread; 01260 } 01261 01262 if (!any_desktop_running) { 01263 // shutdown the shell DDE server 01264 if (g_SHDOCVW_ShellDDEInit) 01265 (*g_SHDOCVW_ShellDDEInit)(FALSE); 01266 } 01267 01268 return ret; 01269 }
ROS Explorer Source Code Documentation
generated on 02.01.2013 by ![]() |