1 /* 2 * Copyright 2003, 2004, 2005, 2006 Martin Fuchs 3 * 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. 8 * 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. 13 * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19 20 // 21 // Explorer clone 22 // 23 // explorer.cpp 24 // 25 // Martin Fuchs, 23.07.2003 26 // 27 // Credits: Thanks to Leon Finker for his explorer cabinet window example 28 // 29 30 31 #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 32 33 #include <shlwapi.h> 34 #include <locale.h> // for setlocale() 35 36 #ifndef __WINE__ 37 #include <io.h> // for dup2() 38 #include <fcntl.h> // for _O_RDONLY 39 #endif 40 41 //#include "dialogs/settings.h" // for MdiSdiDlg 42 43 #include "services/shellservices.h" 44 45 46 extern "C" int initialize_gdb_stub(); // start up GDB stub 47 48 49 DynamicLoadLibFct<void(__stdcall*)(BOOL)> g_SHDOCVW_ShellDDEInit(TEXT("SHDOCVW"), 118); 50 51 52 ExplorerGlobals g_Globals; 53 boolean SelectOpt=FALSE; 54 55 56 ExplorerGlobals::ExplorerGlobals() 57 { 58 _hInstance = 0; 59 _cfStrFName = 0; 60 61 #ifndef ROSSHELL 62 _hframeClass = 0; 63 _hMainWnd = 0; 64 _desktop_mode = false; 65 _prescan_nodes = false; 66 #endif 67 68 _log = NULL; 69 _SHRestricted = 0; 70 _hwndDesktopBar = 0; 71 _hwndShellView = 0; 72 _hwndDesktop = 0; 73 } 74 75 76 void ExplorerGlobals::init(HINSTANCE hInstance) 77 { 78 _hInstance = hInstance; 79 _SHRestricted = (DWORD(STDAPICALLTYPE*)(RESTRICTIONS)) GetProcAddress(GetModuleHandle(TEXT("SHELL32")), "SHRestricted"); 80 _icon_cache.init(); 81 } 82 83 84 void ExplorerGlobals::read_persistent() 85 { 86 // read configuration file 87 _cfg_dir.printf(TEXT("%s\\ReactOS"), (LPCTSTR)SpecialFolderFSPath(CSIDL_APPDATA,0)); 88 _cfg_path.printf(TEXT("%s\\ros-explorer-cfg.xml"), _cfg_dir.c_str()); 89 90 if (!_cfg.read_file(_cfg_path)) { 91 if (!_cfg._errors.empty()) { 92 MessageBox(_hwndDesktop, 93 _cfg._errors.str(), 94 TEXT("ROS Explorer - reading user settings"), 95 MB_OK); 96 } 97 _cfg.read_file(TEXT("explorer-cfg-template.xml")); 98 } 99 100 // read bookmarks 101 _favorites_path.printf(TEXT("%s\\ros-explorer-bookmarks.xml"), _cfg_dir.c_str()); 102 103 if (!_favorites.read(_favorites_path)) { 104 _favorites.import_IE_favorites(0); 105 _favorites.write(_favorites_path); 106 } 107 } 108 109 void ExplorerGlobals::write_persistent() 110 { 111 // write configuration file 112 RecursiveCreateDirectory(_cfg_dir); 113 114 _cfg.write_file(_cfg_path); 115 _favorites.write(_favorites_path); 116 } 117 118 119 XMLPos ExplorerGlobals::get_cfg() 120 { 121 XMLPos cfg_pos(&_cfg); 122 123 cfg_pos.smart_create("explorer-cfg"); 124 125 return cfg_pos; 126 } 127 128 XMLPos ExplorerGlobals::get_cfg(const char* path) 129 { 130 XMLPos cfg_pos(&_cfg); 131 132 cfg_pos.smart_create("explorer-cfg"); 133 cfg_pos.create_relative(path); 134 135 return cfg_pos; 136 } 137 138 139 void _log_(LPCTSTR txt) 140 { 141 FmtString msg(TEXT("%s\n"), txt); 142 143 if (g_Globals._log) 144 _fputts(msg, g_Globals._log); 145 146 OutputDebugString(msg); 147 } 148 149 150 bool FileTypeManager::is_exe_file(LPCTSTR ext) 151 { 152 static const LPCTSTR s_executable_extensions[] = { 153 TEXT("COM"), 154 TEXT("EXE"), 155 TEXT("BAT"), 156 TEXT("CMD"), 157 TEXT("CMM"), 158 TEXT("BTM"), 159 TEXT("AWK"), 160 0 161 }; 162 163 TCHAR ext_buffer[_MAX_EXT]; 164 const LPCTSTR* p; 165 LPCTSTR s; 166 LPTSTR d; 167 168 for(s=ext+1,d=ext_buffer; (*d=toupper(*s)); s++) 169 ++d; 170 171 for(p=s_executable_extensions; *p; p++) 172 if (!lstrcmp(ext_buffer, *p)) 173 return true; 174 175 return false; 176 } 177 178 179 const FileTypeInfo& FileTypeManager::operator[](String ext) 180 { 181 ext.toLower(); 182 183 iterator found = find(ext); 184 if (found != end()) 185 return found->second; 186 187 FileTypeInfo& ftype = super::operator[](ext); 188 189 ftype._neverShowExt = false; 190 191 HKEY hkey; 192 TCHAR value[MAX_PATH], display_name[MAX_PATH]; 193 LONG valuelen = sizeof(value); 194 195 if (!RegQueryValue(HKEY_CLASSES_ROOT, ext, value, &valuelen)) { 196 ftype._classname = value; 197 198 valuelen = sizeof(display_name); 199 if (!RegQueryValue(HKEY_CLASSES_ROOT, ftype._classname, display_name, &valuelen)) 200 ftype._displayname = display_name; 201 202 if (!RegOpenKey(HKEY_CLASSES_ROOT, ftype._classname, &hkey)) { 203 if (!RegQueryValueEx(hkey, TEXT("NeverShowExt"), 0, NULL, NULL, NULL)) 204 ftype._neverShowExt = true; 205 206 RegCloseKey(hkey); 207 } 208 } 209 210 return ftype; 211 } 212 213 LPCTSTR FileTypeManager::set_type(Entry* entry, bool dont_hide_ext) 214 { 215 LPCTSTR ext = _tcsrchr(entry->_data.cFileName, TEXT('.')); 216 217 if (ext) { 218 const FileTypeInfo& type = (*this)[ext]; 219 220 if (!type._displayname.empty()) 221 entry->_type_name = _tcsdup(type._displayname); 222 223 // hide some file extensions 224 if (type._neverShowExt && !dont_hide_ext) { 225 int len = ext - entry->_data.cFileName; 226 227 if (entry->_display_name != entry->_data.cFileName) 228 free(entry->_display_name); 229 230 entry->_display_name = (LPTSTR) malloc((len+1)*sizeof(TCHAR)); 231 lstrcpyn(entry->_display_name, entry->_data.cFileName, len + 1); 232 } 233 234 if (is_exe_file(ext)) 235 entry->_data.dwFileAttributes |= ATTRIBUTE_EXECUTABLE; 236 } 237 238 return ext; 239 } 240 241 242 Icon::Icon() 243 : _id(ICID_UNKNOWN), 244 _itype(IT_STATIC), 245 _hicon(0) 246 { 247 } 248 249 Icon::Icon(ICON_ID id, UINT nid) //, int cx, int cy 250 : _id(id), 251 _itype(IT_STATIC), 252 _hicon(ResIcon(nid)) // ResIconEx(nid, cx, cy) 253 { 254 } 255 256 Icon::Icon(ICON_ID id, UINT nid, int icon_size) 257 : _id(id), 258 _itype(IT_STATIC), 259 _hicon(ResIconEx(nid, icon_size, icon_size)) 260 { 261 } 262 263 Icon::Icon(ICON_TYPE itype, int id, HICON hIcon) 264 : _id((ICON_ID)id), 265 _itype(itype), 266 _hicon(hIcon) 267 { 268 } 269 270 Icon::Icon(ICON_TYPE itype, int id, int sys_idx) 271 : _id((ICON_ID)id), 272 _itype(itype), 273 _sys_idx(sys_idx) 274 { 275 } 276 277 void Icon::draw(HDC hdc, int x, int y, int cx, int cy, COLORREF bk_color, HBRUSH bk_brush) const 278 { 279 if (_itype == IT_SYSCACHE) 280 ImageList_DrawEx(g_Globals._icon_cache.get_sys_imagelist(), _sys_idx, hdc, x, y, cx, cy, bk_color, CLR_DEFAULT, ILD_NORMAL); 281 else 282 DrawIconEx(hdc, x, y, _hicon, cx, cy, 0, bk_brush, DI_NORMAL); 283 } 284 285 HBITMAP Icon::create_bitmap(COLORREF bk_color, HBRUSH hbrBkgnd, HDC hdc_wnd) const 286 { 287 if (_itype == IT_SYSCACHE) { 288 HIMAGELIST himl = g_Globals._icon_cache.get_sys_imagelist(); 289 290 int cx, cy; 291 ImageList_GetIconSize(himl, &cx, &cy); 292 293 HBITMAP hbmp = CreateCompatibleBitmap(hdc_wnd, cx, cy); 294 HDC hdc = CreateCompatibleDC(hdc_wnd); 295 HBITMAP hbmp_old = SelectBitmap(hdc, hbmp); 296 ImageList_DrawEx(himl, _sys_idx, hdc, 0, 0, cx, cy, bk_color, CLR_DEFAULT, ILD_NORMAL); 297 SelectBitmap(hdc, hbmp_old); 298 DeleteDC(hdc); 299 300 return hbmp; 301 } else 302 return create_bitmap_from_icon(_hicon, hbrBkgnd, hdc_wnd); 303 } 304 305 306 int Icon::add_to_imagelist(HIMAGELIST himl, HDC hdc_wnd, COLORREF bk_color, HBRUSH bk_brush) const 307 { 308 int ret; 309 310 if (_itype == IT_SYSCACHE) { 311 HIMAGELIST himl = g_Globals._icon_cache.get_sys_imagelist(); 312 313 int cx, cy; 314 ImageList_GetIconSize(himl, &cx, &cy); 315 316 HBITMAP hbmp = CreateCompatibleBitmap(hdc_wnd, cx, cy); 317 HDC hdc = CreateCompatibleDC(hdc_wnd); 318 HBITMAP hbmp_old = SelectBitmap(hdc, hbmp); 319 ImageList_DrawEx(himl, _sys_idx, hdc, 0, 0, cx, cy, bk_color, CLR_DEFAULT, ILD_NORMAL); 320 SelectBitmap(hdc, hbmp_old); 321 DeleteDC(hdc); 322 323 ret = ImageList_Add(himl, hbmp, 0); 324 325 DeleteObject(hbmp); 326 } else 327 ret = ImageList_AddAlphaIcon(himl, _hicon, bk_brush, hdc_wnd); 328 329 return ret; 330 } 331 332 HBITMAP create_bitmap_from_icon(HICON hIcon, HBRUSH hbrush_bkgnd, HDC hdc_wnd/*, int icon_size*/) 333 { 334 int cx = ICON_SIZE_SMALL; 335 int cy = ICON_SIZE_SMALL; 336 HBITMAP hbmp = CreateCompatibleBitmap(hdc_wnd, cx, cy); 337 338 MemCanvas canvas; 339 BitmapSelection sel(canvas, hbmp); 340 341 RECT rect = {0, 0, cx, cy}; 342 FillRect(canvas, &rect, hbrush_bkgnd); 343 344 DrawIconEx(canvas, 0, 0, hIcon, cx, cy, 0, hbrush_bkgnd, DI_NORMAL); 345 346 return hbmp; 347 } 348 349 HBITMAP create_small_bitmap_from_icon(HICON hIcon, HBRUSH hbrush_bkgnd, HDC hdc_wnd) 350 { 351 int cx = GetSystemMetrics(SM_CXSMICON); 352 int cy = GetSystemMetrics(SM_CYSMICON); 353 HBITMAP hbmp = CreateCompatibleBitmap(hdc_wnd, cx, cy); 354 355 MemCanvas canvas; 356 BitmapSelection sel(canvas, hbmp); 357 358 RECT rect = {0, 0, cx, cy}; 359 FillRect(canvas, &rect, hbrush_bkgnd); 360 361 DrawIconEx(canvas, 0, 0, hIcon, cx, cy, 0, hbrush_bkgnd, DI_NORMAL); 362 363 return hbmp; 364 } 365 366 int ImageList_AddAlphaIcon(HIMAGELIST himl, HICON hIcon, HBRUSH hbrush_bkgnd, HDC hdc_wnd) 367 { 368 HBITMAP hbmp = create_bitmap_from_icon(hIcon, hbrush_bkgnd, hdc_wnd); 369 370 int ret = ImageList_Add(himl, hbmp, 0); 371 372 DeleteObject(hbmp); 373 374 return ret; 375 } 376 377 378 int IconCache::s_next_id = ICID_DYNAMIC; 379 380 381 void IconCache::init() 382 { 383 int icon_size = STARTMENUROOT_ICON_SIZE; 384 385 _icons[ICID_NONE] = Icon(IT_STATIC, ICID_NONE, (HICON)0); 386 387 _icons[ICID_FOLDER] = Icon(ICID_FOLDER, IDI_FOLDER); 388 //_icons[ICID_DOCUMENT] = Icon(ICID_DOCUMENT, IDI_DOCUMENT); 389 _icons[ICID_EXPLORER] = Icon(ICID_EXPLORER, IDI_EXPLORER); 390 //_icons[ICID_APP] = Icon(ICID_APP, IDI_APPICON); 391 392 _icons[ICID_CONFIG] = Icon(ICID_CONFIG, IDI_CONFIG, icon_size); 393 _icons[ICID_DOCUMENTS] = Icon(ICID_DOCUMENTS, IDI_DOCUMENTS, icon_size); 394 _icons[ICID_FAVORITES] = Icon(ICID_FAVORITES, IDI_FAVORITES, icon_size); 395 _icons[ICID_INFO] = Icon(ICID_INFO, IDI_INFO, icon_size); 396 _icons[ICID_APPS] = Icon(ICID_APPS, IDI_APPS, icon_size); 397 _icons[ICID_SEARCH] = Icon(ICID_SEARCH, IDI_SEARCH, icon_size); 398 _icons[ICID_ACTION] = Icon(ICID_ACTION, IDI_ACTION, icon_size); 399 _icons[ICID_SEARCH_DOC] = Icon(ICID_SEARCH_DOC, IDI_SEARCH_DOC, icon_size); 400 _icons[ICID_PRINTER] = Icon(ICID_PRINTER, IDI_PRINTER, icon_size); 401 _icons[ICID_NETWORK] = Icon(ICID_NETWORK, IDI_NETWORK, icon_size); 402 _icons[ICID_COMPUTER] = Icon(ICID_COMPUTER, IDI_COMPUTER, icon_size); 403 _icons[ICID_LOGOFF] = Icon(ICID_LOGOFF, IDI_LOGOFF, icon_size); 404 _icons[ICID_SHUTDOWN] = Icon(ICID_SHUTDOWN, IDI_SHUTDOWN, icon_size); 405 _icons[ICID_RESTART] = Icon(ICID_RESTART, IDI_RESTART, icon_size); 406 _icons[ICID_BOOKMARK] = Icon(ICID_BOOKMARK, IDI_DOT_TRANS, icon_size); 407 _icons[ICID_MINIMIZE] = Icon(ICID_MINIMIZE, IDI_MINIMIZE, icon_size); 408 _icons[ICID_CONTROLPAN] = Icon(ICID_CONTROLPAN, IDI_CONTROLPAN, icon_size); 409 _icons[ICID_DESKSETTING]= Icon(ICID_DESKSETTING,IDI_DESKSETTING,icon_size); 410 _icons[ICID_NETCONNS] = Icon(ICID_NETCONNS, IDI_NETCONNS, icon_size); 411 _icons[ICID_ADMIN] = Icon(ICID_ADMIN, IDI_ADMIN, icon_size); 412 _icons[ICID_RECENT] = Icon(ICID_RECENT, IDI_RECENT, icon_size); 413 } 414 415 416 const Icon& IconCache::extract(LPCTSTR path, ICONCACHE_FLAGS flags) 417 { 418 // search for matching icon with unchanged flags in the cache 419 CacheKey mapkey(path, flags); 420 PathCacheMap::iterator found = _pathCache.find(mapkey); 421 422 if (found != _pathCache.end()) 423 return _icons[found->second]; 424 425 // search for matching icon with handle 426 CacheKey mapkey_hicon(path, flags|ICF_HICON); 427 if (flags != mapkey_hicon.second) { 428 found = _pathCache.find(mapkey_hicon); 429 430 if (found != _pathCache.end()) 431 return _icons[found->second]; 432 } 433 434 // search for matching icon in the system image list cache 435 CacheKey mapkey_syscache(path, flags|ICF_SYSCACHE); 436 if (flags != mapkey_syscache.second) { 437 found = _pathCache.find(mapkey_syscache); 438 439 if (found != _pathCache.end()) 440 return _icons[found->second]; 441 } 442 443 SHFILEINFO sfi; 444 445 int shgfi_flags = 0; 446 447 if (flags & ICF_OPEN) 448 shgfi_flags |= SHGFI_OPENICON; 449 450 if ((flags&(ICF_LARGE|ICF_MIDDLE|ICF_OVERLAYS|ICF_HICON)) && !(flags&ICF_SYSCACHE)) { 451 shgfi_flags |= SHGFI_ICON; 452 453 if (!(flags & (ICF_LARGE|ICF_MIDDLE))) 454 shgfi_flags |= SHGFI_SMALLICON; 455 456 if (flags & ICF_OVERLAYS) 457 shgfi_flags |= SHGFI_ADDOVERLAYS; 458 459 // get small/big icons with/without overlays 460 if (SHGetFileInfo(path, 0, &sfi, sizeof(sfi), shgfi_flags)) { 461 const Icon& icon = add(sfi.hIcon, IT_CACHED); 462 463 ///@todo limit cache size 464 _pathCache[mapkey_hicon] = icon; 465 466 return icon; 467 } 468 } else { 469 assert(!(flags&ICF_OVERLAYS)); 470 471 shgfi_flags |= SHGFI_SYSICONINDEX|SHGFI_SMALLICON; 472 473 // use system image list - the "search program dialog" needs it 474 HIMAGELIST himlSys_small = (HIMAGELIST) SHGetFileInfo(path, 0, &sfi, sizeof(sfi), shgfi_flags); 475 476 if (himlSys_small) { 477 _himlSys_small = himlSys_small; 478 479 const Icon& icon = add(sfi.iIcon/*, IT_SYSCACHE*/); 480 481 ///@todo limit cache size 482 _pathCache[mapkey_syscache] = icon; 483 484 return icon; 485 } 486 } 487 488 return _icons[ICID_NONE]; 489 } 490 491 const Icon& IconCache::extract(LPCTSTR path, int icon_idx, ICONCACHE_FLAGS flags) 492 { 493 IdxCacheKey key(path, make_pair(icon_idx, (flags|ICF_HICON)&~ICF_SYSCACHE)); 494 495 key.first.toLower(); 496 497 IdxCacheMap::iterator found = _idxCache.find(key); 498 499 if (found != _idxCache.end()) 500 return _icons[found->second]; 501 502 HICON hIcon; 503 504 if ((int)ExtractIconEx(path, icon_idx, NULL, &hIcon, 1) > 0) { 505 const Icon& icon = add(hIcon, IT_CACHED); 506 507 _idxCache[key] = icon; 508 509 return icon; 510 } else { 511 512 ///@todo retreive "http://.../favicon.ico" format icons 513 514 return _icons[ICID_NONE]; 515 } 516 } 517 518 const Icon& IconCache::extract(IExtractIcon* pExtract, LPCTSTR path, int icon_idx, ICONCACHE_FLAGS flags) 519 { 520 HICON hIconLarge = 0; 521 HICON hIcon; 522 523 int icon_size = ICON_SIZE_FROM_ICF(flags); 524 HRESULT hr = pExtract->Extract(path, icon_idx, &hIconLarge, &hIcon, MAKELONG(GetSystemMetrics(SM_CXICON), icon_size)); 525 526 if (hr == NOERROR) { //@@ oder SUCCEEDED(hr) ? 527 if (icon_size > ICON_SIZE_SMALL) { //@@ OK? 528 if (hIcon) 529 DestroyIcon(hIcon); 530 531 hIcon = hIconLarge; 532 } else { 533 if (hIconLarge) 534 DestroyIcon(hIconLarge); 535 } 536 537 if (hIcon) 538 return add(hIcon); //@@ When do we want not to free this icons? 539 } 540 541 return _icons[ICID_NONE]; 542 } 543 544 const Icon& IconCache::extract(LPCITEMIDLIST pidl, ICONCACHE_FLAGS flags) 545 { 546 // search for matching icon with unchanged flags in the cache 547 PidlCacheKey mapkey(pidl, flags); 548 PidlCacheMap::iterator found = _pidlcache.find(mapkey); 549 550 if (found != _pidlcache.end()) 551 return _icons[found->second]; 552 553 // search for matching icon with handle 554 PidlCacheKey mapkey_hicon(pidl, flags|ICF_HICON); 555 if (flags != mapkey_hicon.second) { 556 found = _pidlcache.find(mapkey_hicon); 557 558 if (found != _pidlcache.end()) 559 return _icons[found->second]; 560 } 561 562 // search for matching icon in the system image list cache 563 PidlCacheKey mapkey_syscache(pidl, flags|ICF_SYSCACHE); 564 if (flags != mapkey_syscache.second) { 565 found = _pidlcache.find(mapkey_syscache); 566 567 if (found != _pidlcache.end()) 568 return _icons[found->second]; 569 } 570 571 SHFILEINFO sfi; 572 573 int shgfi_flags = SHGFI_PIDL; 574 575 if (!(flags & (ICF_LARGE|ICF_MIDDLE))) 576 shgfi_flags |= SHGFI_SMALLICON; 577 578 if (flags & ICF_OPEN) 579 shgfi_flags |= SHGFI_OPENICON; 580 581 if (flags & ICF_SYSCACHE) { 582 assert(!(flags&ICF_OVERLAYS)); 583 584 HIMAGELIST himlSys = (HIMAGELIST) SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX|shgfi_flags); 585 if (himlSys) { 586 const Icon& icon = add(sfi.iIcon/*, IT_SYSCACHE*/); 587 588 ///@todo limit cache size 589 _pidlcache[mapkey_syscache] = icon; 590 591 return icon; 592 } 593 } else { 594 if (flags & ICF_OVERLAYS) 595 shgfi_flags |= SHGFI_ADDOVERLAYS; 596 597 if (SHGetFileInfo((LPCTSTR)pidl, 0, &sfi, sizeof(sfi), SHGFI_ICON|shgfi_flags)) { 598 const Icon& icon = add(sfi.hIcon, IT_CACHED); 599 600 ///@todo limit cache size 601 _pidlcache[mapkey_hicon] = icon; 602 603 return icon; 604 } 605 } 606 607 return _icons[ICID_NONE]; 608 } 609 610 611 const Icon& IconCache::add(HICON hIcon, ICON_TYPE type) 612 { 613 int id = ++s_next_id; 614 615 return _icons[id] = Icon(type, id, hIcon); 616 } 617 618 const Icon& IconCache::add(int sys_idx/*, ICON_TYPE type=IT_SYSCACHE*/) 619 { 620 int id = ++s_next_id; 621 622 return _icons[id] = SysCacheIcon(id, sys_idx); 623 } 624 625 const Icon& IconCache::get_icon(int id) 626 { 627 return _icons[id]; 628 } 629 630 IconCache::~IconCache() 631 { 632 /* We don't need to free cached resources - they are automatically freed at process termination 633 for (int index = s_next_id; index >= 0; index--) { 634 IconMap::iterator found = _icons.find(index); 635 636 if (found != _icons.end()) { 637 Icon& icon = found->second; 638 639 if ((icon.get_icontype() == IT_DYNAMIC) || 640 (icon.get_icontype() == IT_CACHED)) 641 { 642 DestroyIcon(icon.get_hicon()); 643 _icons.erase(found); 644 } 645 } 646 } 647 */ 648 } 649 650 void IconCache::free_icon(int icon_id) 651 { 652 IconMap::iterator found = _icons.find(icon_id); 653 654 if (found != _icons.end()) { 655 Icon& icon = found->second; 656 657 if (icon.destroy()) 658 _icons.erase(found); 659 } 660 } 661 662 663 ResString::ResString(UINT nid) 664 { 665 TCHAR buffer[BUFFER_LEN]; 666 667 int len = LoadString(g_Globals._hInstance, nid, buffer, sizeof(buffer)/sizeof(TCHAR)); 668 669 super::assign(buffer, len); 670 } 671 672 673 ResIcon::ResIcon(UINT nid) 674 { 675 _hicon = LoadIcon(g_Globals._hInstance, MAKEINTRESOURCE(nid)); 676 } 677 678 SmallIcon::SmallIcon(UINT nid) 679 { 680 _hicon = (HICON)LoadImage(g_Globals._hInstance, MAKEINTRESOURCE(nid), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED); 681 } 682 683 ResIconEx::ResIconEx(UINT nid, int w, int h) 684 { 685 _hicon = (HICON)LoadImage(g_Globals._hInstance, MAKEINTRESOURCE(nid), IMAGE_ICON, w, h, LR_SHARED); 686 } 687 688 689 void SetWindowIcon(HWND hwnd, UINT nid) 690 { 691 HICON hIcon = ResIcon(nid); 692 (void)Window_SetIcon(hwnd, ICON_BIG, hIcon); 693 694 HICON hIconSmall = SmallIcon(nid); 695 (void)Window_SetIcon(hwnd, ICON_SMALL, hIconSmall); 696 } 697 698 699 ResBitmap::ResBitmap(UINT nid) 700 { 701 _hBmp = LoadBitmap(g_Globals._hInstance, MAKEINTRESOURCE(nid)); 702 } 703 704 705 #ifndef ROSSHELL 706 707 void explorer_show_frame(int cmdShow, LPTSTR lpCmdLine) 708 { 709 ExplorerCmd cmd; 710 711 if (g_Globals._hMainWnd) { 712 if (IsIconic(g_Globals._hMainWnd)) 713 ShowWindow(g_Globals._hMainWnd, SW_RESTORE); 714 else 715 SetForegroundWindow(g_Globals._hMainWnd); 716 717 return; 718 } 719 720 g_Globals._prescan_nodes = false; 721 722 cmd._mdi = true; 723 cmd._cmdShow = cmdShow; 724 725 // parse command line options, which may overwrite the MDI flag 726 if (lpCmdLine) 727 cmd.ParseCmdLine(lpCmdLine); 728 729 // create main window 730 MainFrameBase::Create(cmd); 731 } 732 733 bool ExplorerCmd::ParseCmdLine(LPCTSTR lpCmdLine) 734 { 735 bool ok = true; 736 737 LPCTSTR b = lpCmdLine; 738 LPCTSTR p = b; 739 740 while(*b) { 741 // remove leading space 742 while(_istspace((unsigned)*b)) 743 ++b; 744 745 p = b; 746 747 bool quote = false; 748 749 // options are separated by ',' 750 for(; *p; ++p) { 751 if (*p == '"') // Quote characters may appear at any position in the command line. 752 quote = !quote; 753 else if (*p==',' && !quote) 754 break; 755 } 756 757 if (p > b) { 758 int l = p - b; 759 760 // remove trailing space 761 while(l>0 && _istspace((unsigned)b[l-1])) 762 --l; 763 764 if (!EvaluateOption(String(b, l))) 765 ok = false; 766 767 if (*p) 768 ++p; 769 770 b = p; 771 } 772 } 773 774 return ok; 775 } 776 777 bool ExplorerCmd::EvaluateOption(LPCTSTR option) 778 { 779 String opt_str; 780 781 // Remove quote characters, as they are evaluated at this point. 782 for(; *option; ++option) 783 if (*option != '"') 784 opt_str += *option; 785 786 option = opt_str; 787 788 if (option[0] == '/') { 789 ++option; 790 791 // option /e for windows in explorer mode 792 if (!_tcsicmp(option, TEXT("e"))) 793 _flags |= OWM_EXPLORE; 794 // option /root for rooted explorer windows 795 else if (!_tcsicmp(option, TEXT("root"))) 796 _flags |= OWM_ROOTED; 797 // non-standard options: /mdi, /sdi 798 else if (!_tcsicmp(option, TEXT("mdi"))) 799 _mdi = true; 800 else if (!_tcsicmp(option, TEXT("sdi"))) 801 _mdi = false; 802 else if (!_tcsicmp(option, TEXT("n"))) 803 { 804 // Do nothing 805 } 806 else if (!_tcsicmp(option, TEXT("select"))) 807 { 808 SelectOpt = TRUE; 809 } 810 else 811 return false; 812 813 } else { 814 if (!_path.empty()) 815 return false; 816 817 if((SelectOpt == TRUE) && (PathFileExists(option))) 818 { 819 WCHAR szDir[MAX_PATH]; 820 821 _wsplitpath(option, szPath, szDir, NULL, NULL); 822 wcscat(szPath, szDir); 823 PathRemoveBackslash(szPath); 824 _path = szPath; 825 SelectOpt = FALSE; 826 } 827 else 828 _path = opt_str; 829 } 830 831 return true; 832 } 833 834 bool ExplorerCmd::IsValidPath() const 835 { 836 if (!_path.empty()) { 837 DWORD attribs = GetFileAttributes(_path); 838 839 if (attribs!=INVALID_FILE_ATTRIBUTES && (attribs&FILE_ATTRIBUTE_DIRECTORY)) 840 return true; // file system path 841 else if (*_path==':' && _path.at(1)==':') 842 return true; // text encoded IDL 843 } 844 845 return false; 846 } 847 848 #else 849 850 void explorer_show_frame(int cmdShow, LPTSTR lpCmdLine) 851 { 852 if (!lpCmdLine) 853 lpCmdLine = TEXT("explorer.exe"); 854 855 launch_file(GetDesktopWindow(), lpCmdLine, cmdShow); 856 } 857 858 #endif 859 860 861 PopupMenu::PopupMenu(UINT nid) 862 { 863 HMENU hMenu = LoadMenu(g_Globals._hInstance, MAKEINTRESOURCE(nid)); 864 _hmenu = GetSubMenu(hMenu, 0); 865 RemoveMenu(hMenu, 0, MF_BYPOSITION); 866 DestroyMenu(hMenu); 867 } 868 869 870 /// "About Explorer" Dialog 871 struct ExplorerAboutDlg : public 872 CtlColorParent< 873 OwnerDrawParent<Dialog> 874 > 875 { 876 typedef CtlColorParent< 877 OwnerDrawParent<Dialog> 878 > super; 879 880 ExplorerAboutDlg(HWND hwnd) 881 : super(hwnd) 882 { 883 SetWindowIcon(hwnd, IDI_REACTOS); 884 885 new FlatButton(hwnd, IDOK); 886 887 _hfont = CreateFont(20, 0, 0, 0, FW_BOLD, TRUE, 0, 0, 0, 0, 0, 0, 0, TEXT("Sans Serif")); 888 new ColorStatic(hwnd, IDC_ROS_EXPLORER, RGB(32,32,128), 0, _hfont); 889 890 new HyperlinkCtrl(hwnd, IDC_WWW); 891 892 FmtString ver_txt(ResString(IDS_EXPLORER_VERSION_STR), (LPCTSTR)ResString(IDS_VERSION_STR)); 893 SetWindowText(GetDlgItem(hwnd, IDC_VERSION_TXT), ver_txt); 894 895 HWND hwnd_winver = GetDlgItem(hwnd, IDC_WIN_VERSION); 896 SetWindowText(hwnd_winver, get_windows_version_str()); 897 SetWindowFont(hwnd_winver, GetStockFont(DEFAULT_GUI_FONT), FALSE); 898 899 CenterWindow(hwnd); 900 } 901 902 ~ExplorerAboutDlg() 903 { 904 DeleteObject(_hfont); 905 } 906 907 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam) 908 { 909 switch(nmsg) { 910 case WM_PAINT: 911 Paint(); 912 break; 913 914 default: 915 return super::WndProc(nmsg, wparam, lparam); 916 } 917 918 return 0; 919 } 920 921 void Paint() 922 { 923 PaintCanvas canvas(_hwnd); 924 925 HICON hicon = (HICON) LoadImage(g_Globals._hInstance, MAKEINTRESOURCE(IDI_REACTOS_BIG), IMAGE_ICON, 0, 0, LR_SHARED); 926 927 DrawIconEx(canvas, 20, 10, hicon, 0, 0, 0, 0, DI_NORMAL); 928 } 929 930 protected: 931 HFONT _hfont; 932 }; 933 934 void explorer_about(HWND hwndParent) 935 { 936 Dialog::DoModal(IDD_ABOUT_EXPLORER, WINDOW_CREATOR(ExplorerAboutDlg), hwndParent); 937 } 938 939 940 static void InitInstance(HINSTANCE hInstance) 941 { 942 CONTEXT("InitInstance"); 943 944 setlocale(LC_COLLATE, ""); // set collating rules to local settings for compareName 945 946 #ifndef ROSSHELL 947 // register frame window class 948 g_Globals._hframeClass = IconWindowClass(CLASSNAME_FRAME,IDI_EXPLORER); 949 950 // register child window class 951 WindowClass(CLASSNAME_CHILDWND, CS_CLASSDC|CS_DBLCLKS).Register(); 952 953 // register tree window class 954 WindowClass(CLASSNAME_WINEFILETREE, CS_CLASSDC|CS_DBLCLKS).Register(); 955 #endif 956 957 g_Globals._cfStrFName = RegisterClipboardFormat(CFSTR_FILENAME); 958 } 959 960 961 int explorer_main(HINSTANCE hInstance, LPTSTR lpCmdLine, int cmdShow) 962 { 963 CONTEXT("explorer_main"); 964 965 // initialize Common Controls library 966 CommonControlInit usingCmnCtrl; 967 968 try { 969 InitInstance(hInstance); 970 } catch(COMException& e) { 971 HandleException(e, GetDesktopWindow()); 972 return -1; 973 } 974 975 #ifndef ROSSHELL 976 if (cmdShow != SW_HIDE) { 977 /* // don't maximize if being called from the ROS desktop 978 if (cmdShow == SW_SHOWNORMAL) 979 ///@todo read window placement from registry 980 cmdShow = SW_MAXIMIZE; 981 */ 982 983 explorer_show_frame(cmdShow, lpCmdLine); 984 } 985 #endif 986 987 Window::MessageLoop(); 988 989 return 1; 990 } 991 992 993 static bool SetShellReadyEvent(LPCTSTR evtName) 994 { 995 HANDLE hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, evtName); 996 if (!hEvent) 997 return false; 998 999 SetEvent(hEvent); 1000 CloseHandle(hEvent); 1001 1002 return true; 1003 } 1004 1005 1006 int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd) 1007 { 1008 CONTEXT("WinMain()"); 1009 1010 BOOL any_desktop_running = IsAnyDesktopRunning(); 1011 1012 BOOL startup_desktop; 1013 1014 // strip extended options from the front of the command line 1015 String ext_options; 1016 1017 while(*lpCmdLine == '-') { 1018 while(*lpCmdLine && !_istspace((unsigned)*lpCmdLine)) 1019 ext_options += *lpCmdLine++; 1020 1021 while(_istspace((unsigned)*lpCmdLine)) 1022 ++lpCmdLine; 1023 } 1024 1025 // command line option "-install" to replace previous shell application with ROS Explorer 1026 if (_tcsstr(ext_options,TEXT("-install"))) { 1027 // install ROS Explorer into the registry 1028 TCHAR path[MAX_PATH]; 1029 1030 int l = GetModuleFileName(0, path, COUNTOF(path)); 1031 if (l) { 1032 HKEY hkey; 1033 1034 if (!RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"), &hkey)) { 1035 1036 ///@todo save previous shell application in config file 1037 1038 RegSetValueEx(hkey, TEXT("Shell"), 0, REG_SZ, (LPBYTE)path, l*sizeof(TCHAR)); 1039 RegCloseKey(hkey); 1040 } 1041 1042 if (!RegOpenKey(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"), &hkey)) { 1043 1044 ///@todo save previous shell application in config file 1045 1046 RegSetValueEx(hkey, TEXT("Shell"), 0, REG_SZ, (LPBYTE)TEXT(""), l*sizeof(TCHAR)); 1047 RegCloseKey(hkey); 1048 } 1049 } 1050 1051 HWND shellWindow = GetShellWindow(); 1052 1053 if (shellWindow) { 1054 DWORD pid; 1055 1056 // terminate shell process for NT like systems 1057 GetWindowThreadProcessId(shellWindow, &pid); 1058 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); 1059 1060 // On Win 9x it's sufficient to destroy the shell window. 1061 DestroyWindow(shellWindow); 1062 1063 if (TerminateProcess(hProcess, 0)) 1064 WaitForSingleObject(hProcess, INFINITE); 1065 1066 CloseHandle(hProcess); 1067 } 1068 1069 startup_desktop = TRUE; 1070 } else { 1071 // create desktop window and task bar only, if there is no other shell and we are 1072 // the first explorer instance 1073 // MS Explorer looks additionally into the registry entry HKCU\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\shell, 1074 // to decide wether it is currently configured as shell application. 1075 startup_desktop = !any_desktop_running; 1076 } 1077 1078 1079 bool autostart = !any_desktop_running; 1080 1081 // disable autostart if the SHIFT key is pressed 1082 if (GetAsyncKeyState(VK_SHIFT) < 0) 1083 autostart = false; 1084 1085 #ifdef _DEBUG //MF: disabled for debugging 1086 autostart = false; 1087 #endif 1088 1089 // If there is given the command line option "-desktop", create desktop window anyways 1090 if (_tcsstr(ext_options,TEXT("-desktop"))) 1091 startup_desktop = TRUE; 1092 #ifndef ROSSHELL 1093 else if (_tcsstr(ext_options,TEXT("-nodesktop"))) 1094 startup_desktop = FALSE; 1095 1096 // Don't display cabinet window in desktop mode 1097 if (startup_desktop && !_tcsstr(ext_options,TEXT("-explorer"))) 1098 nShowCmd = SW_HIDE; 1099 #endif 1100 1101 if (_tcsstr(ext_options,TEXT("-noautostart"))) 1102 autostart = false; 1103 else if (_tcsstr(ext_options,TEXT("-autostart"))) 1104 autostart = true; 1105 1106 #ifndef __WINE__ 1107 if (_tcsstr(ext_options,TEXT("-console"))) { 1108 AllocConsole(); 1109 1110 _dup2(_open_osfhandle((long)GetStdHandle(STD_INPUT_HANDLE), _O_RDONLY), 0); 1111 _dup2(_open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE), 0), 1); 1112 _dup2(_open_osfhandle((long)GetStdHandle(STD_ERROR_HANDLE), 0), 2); 1113 1114 g_Globals._log = _fdopen(1, "w"); 1115 setvbuf(g_Globals._log, 0, _IONBF, 0); 1116 1117 LOG(TEXT("starting explorer debug log\n")); 1118 } 1119 #endif 1120 1121 1122 if (startup_desktop) { 1123 // hide the XP login screen (Credit to Nicolas Escuder) 1124 // another undocumented event: "Global\\msgina: ReturnToWelcome" 1125 if (!SetShellReadyEvent(TEXT("msgina: ShellReadyEvent"))) 1126 SetShellReadyEvent(TEXT("Global\\msgina: ShellReadyEvent")); 1127 } 1128 #ifdef ROSSHELL 1129 else 1130 return 0; // no shell to launch, so exit immediatelly 1131 #endif 1132 1133 1134 if (!any_desktop_running) { 1135 // launch the shell DDE server 1136 if (g_SHDOCVW_ShellDDEInit) 1137 (*g_SHDOCVW_ShellDDEInit)(TRUE); 1138 } 1139 1140 1141 bool use_gdb_stub = false; // !IsDebuggerPresent(); 1142 1143 if (_tcsstr(ext_options,TEXT("-debug"))) 1144 use_gdb_stub = true; 1145 1146 if (_tcsstr(ext_options,TEXT("-break"))) { 1147 LOG(TEXT("debugger breakpoint")); 1148 __debugbreak(); 1149 } 1150 1151 #ifdef _M_IX86 1152 // activate GDB remote debugging stub if no other debugger is running 1153 if (use_gdb_stub) { 1154 LOG(TEXT("waiting for debugger connection...\n")); 1155 1156 initialize_gdb_stub(); 1157 } 1158 #endif 1159 1160 g_Globals.init(hInstance); 1161 1162 // initialize COM and OLE before creating the desktop window 1163 OleInit usingCOM; 1164 1165 // init common controls library 1166 CommonControlInit usingCmnCtrl; 1167 1168 g_Globals.read_persistent(); 1169 1170 if (startup_desktop) { 1171 WaitCursor wait; 1172 1173 g_Globals._desktops.init(); 1174 1175 g_Globals._hwndDesktop = DesktopWindow::Create(); 1176 #ifdef _USE_HDESK 1177 g_Globals._desktops.get_current_Desktop()->_hwndDesktop = g_Globals._hwndDesktop; 1178 #endif 1179 } 1180 1181 if (_tcsstr(ext_options,TEXT("-?"))) { 1182 MessageBoxA(g_Globals._hwndDesktop, 1183 "/e open cabinet window in explorer mode\r\n" 1184 "/root open cabinet window in rooted mode\r\n" 1185 "/mdi open cabinet window in MDI mode\r\n" 1186 "/sdi open cabinet window in SDI mode\r\n" 1187 "\r\n" 1188 "-? display command line options\r\n" 1189 "\r\n" 1190 "-desktop start in desktop mode regardless of an already running shell\r\n" 1191 "-nodesktop disable desktop mode\r\n" 1192 "-explorer display cabinet window regardless of enabled desktop mode\r\n" 1193 "\r\n" 1194 "-install replace previous shell application with ROS Explorer\r\n" 1195 "\r\n" 1196 "-noautostart disable autostarts\r\n" 1197 "-autostart enable autostarts regardless of debug build\r\n" 1198 "\r\n" 1199 "-console open debug console\r\n" 1200 "\r\n" 1201 "-debug activate GDB remote debugging stub\r\n" 1202 "-break activate debugger breakpoint\r\n", 1203 "ROS Explorer - command line options", MB_OK); 1204 } 1205 1206 /* 1207 * Set our shutdown parameters: we want to shutdown the very last, 1208 * but before any TaskMgr instance (which has a shutdown level of 1). 1209 */ 1210 SetProcessShutdownParameters(2, 0); 1211 1212 Thread* pSSOThread = NULL; 1213 1214 if (startup_desktop) { 1215 // launch SSO thread to allow message processing independent from the explorer main thread 1216 pSSOThread = new SSOThread; 1217 pSSOThread->Start(); 1218 } 1219 1220 /**TODO launching autostart programs can be moved into a background thread. */ 1221 if (autostart) { 1222 const char* argv[] = {"", "s"}; // call startup routine in SESSION_START mode 1223 startup(2, argv); 1224 } 1225 1226 #ifndef ROSSHELL 1227 if (g_Globals._hwndDesktop) 1228 g_Globals._desktop_mode = true; 1229 #endif 1230 1231 1232 int ret = explorer_main(hInstance, lpCmdLine, nShowCmd); 1233 1234 1235 // write configuration file 1236 g_Globals.write_persistent(); 1237 1238 if (pSSOThread) { 1239 pSSOThread->Stop(); 1240 delete pSSOThread; 1241 } 1242 1243 if (!any_desktop_running) { 1244 // shutdown the shell DDE server 1245 if (g_SHDOCVW_ShellDDEInit) 1246 (*g_SHDOCVW_ShellDDEInit)(FALSE); 1247 } 1248 1249 return ret; 1250 } 1251