2 * Copyright 2003, 2004, 2005, 2006 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 // Martin Fuchs, 23.07.2003
27 // Credits: Thanks to Leon Finker for his explorer cabinet window example
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
35 #include <locale.h> // for setlocale()
40 #include <io.h> // for dup2()
41 #include <fcntl.h> // for _O_RDONLY
44 //#include "dialogs/settings.h" // for MdiSdiDlg
46 #include "services/shellservices.h"
49 extern "C" int initialize_gdb_stub(); // start up GDB stub
52 DynamicLoadLibFct
<void(__stdcall
*)(BOOL
)> g_SHDOCVW_ShellDDEInit(TEXT("SHDOCVW"), 118);
55 ExplorerGlobals g_Globals
;
56 boolean SelectOpt
=FALSE
;
59 ExplorerGlobals::ExplorerGlobals()
67 _desktop_mode
= false;
68 _prescan_nodes
= false;
72 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
81 void ExplorerGlobals::init(HINSTANCE hInstance
)
83 _hInstance
= hInstance
;
85 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
86 _SHRestricted
= (DWORD(STDAPICALLTYPE
*)(RESTRICTIONS
)) GetProcAddress(GetModuleHandle(TEXT("SHELL32")), "SHRestricted");
93 void ExplorerGlobals::read_persistent()
95 // read configuration file
96 _cfg_dir
.printf(TEXT("%s\\ReactOS"), (LPCTSTR
)SpecialFolderFSPath(CSIDL_APPDATA
,0));
97 _cfg_path
.printf(TEXT("%s\\ros-explorer-cfg.xml"), _cfg_dir
.c_str());
99 if (!_cfg
.read_file(_cfg_path
)) {
100 if (!_cfg
._errors
.empty()) {
101 MessageBox(_hwndDesktop
,
103 TEXT("ROS Explorer - reading user settings"),
106 _cfg
.read_file(TEXT("explorer-cfg-template.xml"));
110 _favorites_path
.printf(TEXT("%s\\ros-explorer-bookmarks.xml"), _cfg_dir
.c_str());
112 if (!_favorites
.read(_favorites_path
)) {
113 _favorites
.import_IE_favorites(0);
114 _favorites
.write(_favorites_path
);
118 void ExplorerGlobals::write_persistent()
120 // write configuration file
121 RecursiveCreateDirectory(_cfg_dir
);
123 _cfg
.write_file(_cfg_path
);
124 _favorites
.write(_favorites_path
);
128 XMLPos
ExplorerGlobals::get_cfg()
130 XMLPos
cfg_pos(&_cfg
);
132 cfg_pos
.smart_create("explorer-cfg");
137 XMLPos
ExplorerGlobals::get_cfg(const char* path
)
139 XMLPos
cfg_pos(&_cfg
);
141 cfg_pos
.smart_create("explorer-cfg");
142 cfg_pos
.create_relative(path
);
148 void _log_(LPCTSTR txt
)
150 FmtString
msg(TEXT("%s\n"), txt
);
153 _fputts(msg
, g_Globals
._log
);
155 OutputDebugString(msg
);
159 bool FileTypeManager::is_exe_file(LPCTSTR ext
)
161 static const LPCTSTR s_executable_extensions
[] = {
172 TCHAR ext_buffer
[_MAX_EXT
];
177 for(s
=ext
+1,d
=ext_buffer
; (*d
=toupper(*s
)); s
++)
180 for(p
=s_executable_extensions
; *p
; p
++)
181 if (!lstrcmp(ext_buffer
, *p
))
188 const FileTypeInfo
& FileTypeManager::operator[](String ext
)
192 iterator found
= find(ext
);
194 return found
->second
;
196 FileTypeInfo
& ftype
= super::operator[](ext
);
198 ftype
._neverShowExt
= false;
201 TCHAR value
[MAX_PATH
], display_name
[MAX_PATH
];
202 LONG valuelen
= sizeof(value
);
204 if (!RegQueryValue(HKEY_CLASSES_ROOT
, ext
, value
, &valuelen
)) {
205 ftype
._classname
= value
;
207 valuelen
= sizeof(display_name
);
208 if (!RegQueryValue(HKEY_CLASSES_ROOT
, ftype
._classname
, display_name
, &valuelen
))
209 ftype
._displayname
= display_name
;
211 if (!RegOpenKey(HKEY_CLASSES_ROOT
, ftype
._classname
, &hkey
)) {
212 if (!RegQueryValueEx(hkey
, TEXT("NeverShowExt"), 0, NULL
, NULL
, NULL
))
213 ftype
._neverShowExt
= true;
222 LPCTSTR
FileTypeManager::set_type(Entry
* entry
, bool dont_hide_ext
)
224 LPCTSTR ext
= _tcsrchr(entry
->_data
.cFileName
, TEXT('.'));
227 const FileTypeInfo
& type
= (*this)[ext
];
229 if (!type
._displayname
.empty())
230 entry
->_type_name
= _tcsdup(type
._displayname
);
232 // hide some file extensions
233 if (type
._neverShowExt
&& !dont_hide_ext
) {
234 int len
= ext
- entry
->_data
.cFileName
;
236 if (entry
->_display_name
!= entry
->_data
.cFileName
)
237 free(entry
->_display_name
);
239 entry
->_display_name
= (LPTSTR
) malloc((len
+1)*sizeof(TCHAR
));
240 lstrcpyn(entry
->_display_name
, entry
->_data
.cFileName
, len
+ 1);
243 if (is_exe_file(ext
))
244 entry
->_data
.dwFileAttributes
|= ATTRIBUTE_EXECUTABLE
;
258 Icon::Icon(ICON_ID id
, UINT nid
) //, int cx, int cy
261 _hicon(ResIcon(nid
)) // ResIconEx(nid, cx, cy)
265 Icon::Icon(ICON_ID id
, UINT nid
, int icon_size
)
268 _hicon(ResIconEx(nid
, icon_size
, icon_size
))
272 Icon::Icon(ICON_TYPE itype
, int id
, HICON hIcon
)
279 Icon::Icon(ICON_TYPE itype
, int id
, int sys_idx
)
286 void Icon::draw(HDC hdc
, int x
, int y
, int cx
, int cy
, COLORREF bk_color
, HBRUSH bk_brush
) const
288 if (_itype
== IT_SYSCACHE
)
289 ImageList_DrawEx(g_Globals
._icon_cache
.get_sys_imagelist(), _sys_idx
, hdc
, x
, y
, cx
, cy
, bk_color
, CLR_DEFAULT
, ILD_NORMAL
);
291 DrawIconEx(hdc
, x
, y
, _hicon
, cx
, cy
, 0, bk_brush
, DI_NORMAL
);
294 HBITMAP
Icon::create_bitmap(COLORREF bk_color
, HBRUSH hbrBkgnd
, HDC hdc_wnd
) const
296 if (_itype
== IT_SYSCACHE
) {
297 HIMAGELIST himl
= g_Globals
._icon_cache
.get_sys_imagelist();
300 ImageList_GetIconSize(himl
, &cx
, &cy
);
302 HBITMAP hbmp
= CreateCompatibleBitmap(hdc_wnd
, cx
, cy
);
303 HDC hdc
= CreateCompatibleDC(hdc_wnd
);
304 HBITMAP hbmp_old
= SelectBitmap(hdc
, hbmp
);
305 ImageList_DrawEx(himl
, _sys_idx
, hdc
, 0, 0, cx
, cy
, bk_color
, CLR_DEFAULT
, ILD_NORMAL
);
306 SelectBitmap(hdc
, hbmp_old
);
311 return create_bitmap_from_icon(_hicon
, hbrBkgnd
, hdc_wnd
);
315 int Icon::add_to_imagelist(HIMAGELIST himl
, HDC hdc_wnd
, COLORREF bk_color
, HBRUSH bk_brush
) const
319 if (_itype
== IT_SYSCACHE
) {
320 HIMAGELIST himl
= g_Globals
._icon_cache
.get_sys_imagelist();
323 ImageList_GetIconSize(himl
, &cx
, &cy
);
325 HBITMAP hbmp
= CreateCompatibleBitmap(hdc_wnd
, cx
, cy
);
326 HDC hdc
= CreateCompatibleDC(hdc_wnd
);
327 HBITMAP hbmp_old
= SelectBitmap(hdc
, hbmp
);
328 ImageList_DrawEx(himl
, _sys_idx
, hdc
, 0, 0, cx
, cy
, bk_color
, CLR_DEFAULT
, ILD_NORMAL
);
329 SelectBitmap(hdc
, hbmp_old
);
332 ret
= ImageList_Add(himl
, hbmp
, 0);
336 ret
= ImageList_AddAlphaIcon(himl
, _hicon
, bk_brush
, hdc_wnd
);
341 HBITMAP
create_bitmap_from_icon(HICON hIcon
, HBRUSH hbrush_bkgnd
, HDC hdc_wnd
/*, int icon_size*/)
343 int cx
= ICON_SIZE_SMALL
;
344 int cy
= ICON_SIZE_SMALL
;
345 HBITMAP hbmp
= CreateCompatibleBitmap(hdc_wnd
, cx
, cy
);
348 BitmapSelection
sel(canvas
, hbmp
);
350 RECT rect
= {0, 0, cx
, cy
};
351 FillRect(canvas
, &rect
, hbrush_bkgnd
);
353 DrawIconEx(canvas
, 0, 0, hIcon
, cx
, cy
, 0, hbrush_bkgnd
, DI_NORMAL
);
358 HBITMAP
create_small_bitmap_from_icon(HICON hIcon
, HBRUSH hbrush_bkgnd
, HDC hdc_wnd
)
360 int cx
= GetSystemMetrics(SM_CXSMICON
);
361 int cy
= GetSystemMetrics(SM_CYSMICON
);
362 HBITMAP hbmp
= CreateCompatibleBitmap(hdc_wnd
, cx
, cy
);
365 BitmapSelection
sel(canvas
, hbmp
);
367 RECT rect
= {0, 0, cx
, cy
};
368 FillRect(canvas
, &rect
, hbrush_bkgnd
);
370 DrawIconEx(canvas
, 0, 0, hIcon
, cx
, cy
, 0, hbrush_bkgnd
, DI_NORMAL
);
375 int ImageList_AddAlphaIcon(HIMAGELIST himl
, HICON hIcon
, HBRUSH hbrush_bkgnd
, HDC hdc_wnd
)
377 HBITMAP hbmp
= create_bitmap_from_icon(hIcon
, hbrush_bkgnd
, hdc_wnd
);
379 int ret
= ImageList_Add(himl
, hbmp
, 0);
387 int IconCache::s_next_id
= ICID_DYNAMIC
;
390 void IconCache::init()
392 int icon_size
= STARTMENUROOT_ICON_SIZE
;
394 _icons
[ICID_NONE
] = Icon(IT_STATIC
, ICID_NONE
, (HICON
)0);
396 _icons
[ICID_FOLDER
] = Icon(ICID_FOLDER
, IDI_FOLDER
);
397 //_icons[ICID_DOCUMENT] = Icon(ICID_DOCUMENT, IDI_DOCUMENT);
398 _icons
[ICID_EXPLORER
] = Icon(ICID_EXPLORER
, IDI_EXPLORER
);
399 //_icons[ICID_APP] = Icon(ICID_APP, IDI_APPICON);
401 _icons
[ICID_CONFIG
] = Icon(ICID_CONFIG
, IDI_CONFIG
, icon_size
);
402 _icons
[ICID_DOCUMENTS
] = Icon(ICID_DOCUMENTS
, IDI_DOCUMENTS
, icon_size
);
403 _icons
[ICID_FAVORITES
] = Icon(ICID_FAVORITES
, IDI_FAVORITES
, icon_size
);
404 _icons
[ICID_INFO
] = Icon(ICID_INFO
, IDI_INFO
, icon_size
);
405 _icons
[ICID_APPS
] = Icon(ICID_APPS
, IDI_APPS
, icon_size
);
406 _icons
[ICID_SEARCH
] = Icon(ICID_SEARCH
, IDI_SEARCH
, icon_size
);
407 _icons
[ICID_ACTION
] = Icon(ICID_ACTION
, IDI_ACTION
, icon_size
);
408 _icons
[ICID_SEARCH_DOC
] = Icon(ICID_SEARCH_DOC
, IDI_SEARCH_DOC
, icon_size
);
409 _icons
[ICID_PRINTER
] = Icon(ICID_PRINTER
, IDI_PRINTER
, icon_size
);
410 _icons
[ICID_NETWORK
] = Icon(ICID_NETWORK
, IDI_NETWORK
, icon_size
);
411 _icons
[ICID_COMPUTER
] = Icon(ICID_COMPUTER
, IDI_COMPUTER
, icon_size
);
412 _icons
[ICID_LOGOFF
] = Icon(ICID_LOGOFF
, IDI_LOGOFF
, icon_size
);
413 _icons
[ICID_SHUTDOWN
] = Icon(ICID_SHUTDOWN
, IDI_SHUTDOWN
, icon_size
);
414 _icons
[ICID_RESTART
] = Icon(ICID_RESTART
, IDI_RESTART
, icon_size
);
415 _icons
[ICID_BOOKMARK
] = Icon(ICID_BOOKMARK
, IDI_DOT_TRANS
, icon_size
);
416 _icons
[ICID_MINIMIZE
] = Icon(ICID_MINIMIZE
, IDI_MINIMIZE
, icon_size
);
417 _icons
[ICID_CONTROLPAN
] = Icon(ICID_CONTROLPAN
, IDI_CONTROLPAN
, icon_size
);
418 _icons
[ICID_DESKSETTING
]= Icon(ICID_DESKSETTING
,IDI_DESKSETTING
,icon_size
);
419 _icons
[ICID_NETCONNS
] = Icon(ICID_NETCONNS
, IDI_NETCONNS
, icon_size
);
420 _icons
[ICID_ADMIN
] = Icon(ICID_ADMIN
, IDI_ADMIN
, icon_size
);
421 _icons
[ICID_RECENT
] = Icon(ICID_RECENT
, IDI_RECENT
, icon_size
);
425 const Icon
& IconCache::extract(LPCTSTR path
, ICONCACHE_FLAGS flags
)
427 // search for matching icon with unchanged flags in the cache
428 CacheKey
mapkey(path
, flags
);
429 PathCacheMap::iterator found
= _pathCache
.find(mapkey
);
431 if (found
!= _pathCache
.end())
432 return _icons
[found
->second
];
434 // search for matching icon with handle
435 CacheKey
mapkey_hicon(path
, flags
|ICF_HICON
);
436 if (flags
!= mapkey_hicon
.second
) {
437 found
= _pathCache
.find(mapkey_hicon
);
439 if (found
!= _pathCache
.end())
440 return _icons
[found
->second
];
443 // search for matching icon in the system image list cache
444 CacheKey
mapkey_syscache(path
, flags
|ICF_SYSCACHE
);
445 if (flags
!= mapkey_syscache
.second
) {
446 found
= _pathCache
.find(mapkey_syscache
);
448 if (found
!= _pathCache
.end())
449 return _icons
[found
->second
];
456 if (flags
& ICF_OPEN
)
457 shgfi_flags
|= SHGFI_OPENICON
;
459 if ((flags
&(ICF_LARGE
|ICF_MIDDLE
|ICF_OVERLAYS
|ICF_HICON
)) && !(flags
&ICF_SYSCACHE
)) {
460 shgfi_flags
|= SHGFI_ICON
;
462 if (!(flags
& (ICF_LARGE
|ICF_MIDDLE
)))
463 shgfi_flags
|= SHGFI_SMALLICON
;
465 if (flags
& ICF_OVERLAYS
)
466 shgfi_flags
|= SHGFI_ADDOVERLAYS
;
468 // get small/big icons with/without overlays
469 if (SHGetFileInfo(path
, 0, &sfi
, sizeof(sfi
), shgfi_flags
)) {
470 const Icon
& icon
= add(sfi
.hIcon
, IT_CACHED
);
472 ///@todo limit cache size
473 _pathCache
[mapkey_hicon
] = icon
;
478 assert(!(flags
&ICF_OVERLAYS
));
480 shgfi_flags
|= SHGFI_SYSICONINDEX
|SHGFI_SMALLICON
;
482 // use system image list - the "search program dialog" needs it
483 HIMAGELIST himlSys_small
= (HIMAGELIST
) SHGetFileInfo(path
, 0, &sfi
, sizeof(sfi
), shgfi_flags
);
486 _himlSys_small
= himlSys_small
;
488 const Icon
& icon
= add(sfi
.iIcon
/*, IT_SYSCACHE*/);
490 ///@todo limit cache size
491 _pathCache
[mapkey_syscache
] = icon
;
497 return _icons
[ICID_NONE
];
500 const Icon
& IconCache::extract(LPCTSTR path
, int icon_idx
, ICONCACHE_FLAGS flags
)
502 IdxCacheKey
key(path
, make_pair(icon_idx
, (flags
|ICF_HICON
)&~ICF_SYSCACHE
));
506 IdxCacheMap::iterator found
= _idxCache
.find(key
);
508 if (found
!= _idxCache
.end())
509 return _icons
[found
->second
];
513 if ((int)ExtractIconEx(path
, icon_idx
, NULL
, &hIcon
, 1) > 0) {
514 const Icon
& icon
= add(hIcon
, IT_CACHED
);
516 _idxCache
[key
] = icon
;
521 ///@todo retreive "http://.../favicon.ico" format icons
523 return _icons
[ICID_NONE
];
527 const Icon
& IconCache::extract(IExtractIcon
* pExtract
, LPCTSTR path
, int icon_idx
, ICONCACHE_FLAGS flags
)
529 HICON hIconLarge
= 0;
532 int icon_size
= ICON_SIZE_FROM_ICF(flags
);
533 HRESULT hr
= pExtract
->Extract(path
, icon_idx
, &hIconLarge
, &hIcon
, MAKELONG(GetSystemMetrics(SM_CXICON
), icon_size
));
535 if (hr
== NOERROR
) { //@@ oder SUCCEEDED(hr) ?
536 if (icon_size
> ICON_SIZE_SMALL
) { //@@ OK?
543 DestroyIcon(hIconLarge
);
547 return add(hIcon
); //@@ When do we want not to free this icons?
550 return _icons
[ICID_NONE
];
553 const Icon
& IconCache::extract(LPCITEMIDLIST pidl
, ICONCACHE_FLAGS flags
)
555 // search for matching icon with unchanged flags in the cache
556 PidlCacheKey
mapkey(pidl
, flags
);
557 PidlCacheMap::iterator found
= _pidlcache
.find(mapkey
);
559 if (found
!= _pidlcache
.end())
560 return _icons
[found
->second
];
562 // search for matching icon with handle
563 PidlCacheKey
mapkey_hicon(pidl
, flags
|ICF_HICON
);
564 if (flags
!= mapkey_hicon
.second
) {
565 found
= _pidlcache
.find(mapkey_hicon
);
567 if (found
!= _pidlcache
.end())
568 return _icons
[found
->second
];
571 // search for matching icon in the system image list cache
572 PidlCacheKey
mapkey_syscache(pidl
, flags
|ICF_SYSCACHE
);
573 if (flags
!= mapkey_syscache
.second
) {
574 found
= _pidlcache
.find(mapkey_syscache
);
576 if (found
!= _pidlcache
.end())
577 return _icons
[found
->second
];
582 int shgfi_flags
= SHGFI_PIDL
;
584 if (!(flags
& (ICF_LARGE
|ICF_MIDDLE
)))
585 shgfi_flags
|= SHGFI_SMALLICON
;
587 if (flags
& ICF_OPEN
)
588 shgfi_flags
|= SHGFI_OPENICON
;
590 if (flags
& ICF_SYSCACHE
) {
591 assert(!(flags
&ICF_OVERLAYS
));
593 HIMAGELIST himlSys
= (HIMAGELIST
) SHGetFileInfo((LPCTSTR
)pidl
, 0, &sfi
, sizeof(sfi
), SHGFI_SYSICONINDEX
|shgfi_flags
);
595 const Icon
& icon
= add(sfi
.iIcon
/*, IT_SYSCACHE*/);
597 ///@todo limit cache size
598 _pidlcache
[mapkey_syscache
] = icon
;
603 if (flags
& ICF_OVERLAYS
)
604 shgfi_flags
|= SHGFI_ADDOVERLAYS
;
606 if (SHGetFileInfo((LPCTSTR
)pidl
, 0, &sfi
, sizeof(sfi
), SHGFI_ICON
|shgfi_flags
)) {
607 const Icon
& icon
= add(sfi
.hIcon
, IT_CACHED
);
609 ///@todo limit cache size
610 _pidlcache
[mapkey_hicon
] = icon
;
616 return _icons
[ICID_NONE
];
620 const Icon
& IconCache::add(HICON hIcon
, ICON_TYPE type
)
622 int id
= ++s_next_id
;
624 return _icons
[id
] = Icon(type
, id
, hIcon
);
627 const Icon
& IconCache::add(int sys_idx
/*, ICON_TYPE type=IT_SYSCACHE*/)
629 int id
= ++s_next_id
;
631 return _icons
[id
] = SysCacheIcon(id
, sys_idx
);
634 const Icon
& IconCache::get_icon(int id
)
639 IconCache::~IconCache()
641 /* We don't need to free cached resources - they are automatically freed at process termination
642 for (int index = s_next_id; index >= 0; index--) {
643 IconMap::iterator found = _icons.find(index);
645 if (found != _icons.end()) {
646 Icon& icon = found->second;
648 if ((icon.get_icontype() == IT_DYNAMIC) ||
649 (icon.get_icontype() == IT_CACHED))
651 DestroyIcon(icon.get_hicon());
659 void IconCache::free_icon(int icon_id
)
661 IconMap::iterator found
= _icons
.find(icon_id
);
663 if (found
!= _icons
.end()) {
664 Icon
& icon
= found
->second
;
672 ResString::ResString(UINT nid
)
674 TCHAR buffer
[BUFFER_LEN
];
676 int len
= LoadString(g_Globals
._hInstance
, nid
, buffer
, sizeof(buffer
)/sizeof(TCHAR
));
678 super::assign(buffer
, len
);
682 ResIcon::ResIcon(UINT nid
)
684 _hicon
= LoadIcon(g_Globals
._hInstance
, MAKEINTRESOURCE(nid
));
687 SmallIcon::SmallIcon(UINT nid
)
689 _hicon
= (HICON
)LoadImage(g_Globals
._hInstance
, MAKEINTRESOURCE(nid
), IMAGE_ICON
, GetSystemMetrics(SM_CXSMICON
), GetSystemMetrics(SM_CYSMICON
), LR_SHARED
);
692 ResIconEx::ResIconEx(UINT nid
, int w
, int h
)
694 _hicon
= (HICON
)LoadImage(g_Globals
._hInstance
, MAKEINTRESOURCE(nid
), IMAGE_ICON
, w
, h
, LR_SHARED
);
698 void SetWindowIcon(HWND hwnd
, UINT nid
)
700 HICON hIcon
= ResIcon(nid
);
701 (void)Window_SetIcon(hwnd
, ICON_BIG
, hIcon
);
703 HICON hIconSmall
= SmallIcon(nid
);
704 (void)Window_SetIcon(hwnd
, ICON_SMALL
, hIconSmall
);
708 ResBitmap::ResBitmap(UINT nid
)
710 _hBmp
= LoadBitmap(g_Globals
._hInstance
, MAKEINTRESOURCE(nid
));
716 void explorer_show_frame(int cmdShow
, LPTSTR lpCmdLine
)
720 if (g_Globals
._hMainWnd
) {
721 if (IsIconic(g_Globals
._hMainWnd
))
722 ShowWindow(g_Globals
._hMainWnd
, SW_RESTORE
);
724 SetForegroundWindow(g_Globals
._hMainWnd
);
729 g_Globals
._prescan_nodes
= false;
732 cmd
._cmdShow
= cmdShow
;
734 // parse command line options, which may overwrite the MDI flag
736 cmd
.ParseCmdLine(lpCmdLine
);
738 // create main window
739 MainFrameBase::Create(cmd
);
742 bool ExplorerCmd::ParseCmdLine(LPCTSTR lpCmdLine
)
746 LPCTSTR b
= lpCmdLine
;
750 // remove leading space
751 while(_istspace((unsigned)*b
))
758 // options are separated by ','
760 if (*p
== '"') // Quote characters may appear at any position in the command line.
762 else if (*p
==',' && !quote
)
769 // remove trailing space
770 while(l
>0 && _istspace((unsigned)b
[l
-1]))
773 if (!EvaluateOption(String(b
, l
)))
786 bool ExplorerCmd::EvaluateOption(LPCTSTR option
)
790 // Remove quote characters, as they are evaluated at this point.
791 for(; *option
; ++option
)
797 if (option
[0] == '/') {
800 // option /e for windows in explorer mode
801 if (!_tcsicmp(option
, TEXT("e")))
802 _flags
|= OWM_EXPLORE
;
803 // option /root for rooted explorer windows
804 else if (!_tcsicmp(option
, TEXT("root")))
805 _flags
|= OWM_ROOTED
;
806 // non-standard options: /mdi, /sdi
807 else if (!_tcsicmp(option
, TEXT("mdi")))
809 else if (!_tcsicmp(option
, TEXT("sdi")))
811 else if (!_tcsicmp(option
, TEXT("n")))
815 else if (!_tcsicmp(option
, TEXT("select")))
826 if((SelectOpt
== TRUE
) && (PathFileExists(option
)))
828 WCHAR szDir
[MAX_PATH
];
830 _wsplitpath(option
, szPath
, szDir
, NULL
, NULL
);
831 wcscat(szPath
, szDir
);
832 PathRemoveBackslash(szPath
);
843 bool ExplorerCmd::IsValidPath() const
845 if (!_path
.empty()) {
846 DWORD attribs
= GetFileAttributes(_path
);
848 if (attribs
!=INVALID_FILE_ATTRIBUTES
&& (attribs
&FILE_ATTRIBUTE_DIRECTORY
))
849 return true; // file system path
850 else if (*_path
==':' && _path
.at(1)==':')
851 return true; // text encoded IDL
859 void explorer_show_frame(int cmdShow
, LPTSTR lpCmdLine
)
862 lpCmdLine
= TEXT("explorer.exe");
864 launch_file(GetDesktopWindow(), lpCmdLine
, cmdShow
);
870 PopupMenu::PopupMenu(UINT nid
)
872 HMENU hMenu
= LoadMenu(g_Globals
._hInstance
, MAKEINTRESOURCE(nid
));
873 _hmenu
= GetSubMenu(hMenu
, 0);
874 RemoveMenu(hMenu
, 0, MF_BYPOSITION
);
879 /// "About Explorer" Dialog
880 struct ExplorerAboutDlg
: public
882 OwnerDrawParent
<Dialog
>
885 typedef CtlColorParent
<
886 OwnerDrawParent
<Dialog
>
889 ExplorerAboutDlg(HWND hwnd
)
892 SetWindowIcon(hwnd
, IDI_REACTOS
);
894 new FlatButton(hwnd
, IDOK
);
896 _hfont
= CreateFont(20, 0, 0, 0, FW_BOLD
, TRUE
, 0, 0, 0, 0, 0, 0, 0, TEXT("Sans Serif"));
897 new ColorStatic(hwnd
, IDC_ROS_EXPLORER
, RGB(32,32,128), 0, _hfont
);
899 new HyperlinkCtrl(hwnd
, IDC_WWW
);
901 FmtString
ver_txt(ResString(IDS_EXPLORER_VERSION_STR
), (LPCTSTR
)ResString(IDS_VERSION_STR
));
902 SetWindowText(GetDlgItem(hwnd
, IDC_VERSION_TXT
), ver_txt
);
904 HWND hwnd_winver
= GetDlgItem(hwnd
, IDC_WIN_VERSION
);
905 SetWindowText(hwnd_winver
, get_windows_version_str());
906 SetWindowFont(hwnd_winver
, GetStockFont(DEFAULT_GUI_FONT
), FALSE
);
913 DeleteObject(_hfont
);
916 LRESULT
WndProc(UINT nmsg
, WPARAM wparam
, LPARAM lparam
)
924 return super::WndProc(nmsg
, wparam
, lparam
);
932 PaintCanvas
canvas(_hwnd
);
934 HICON hicon
= (HICON
) LoadImage(g_Globals
._hInstance
, MAKEINTRESOURCE(IDI_REACTOS_BIG
), IMAGE_ICON
, 0, 0, LR_SHARED
);
936 DrawIconEx(canvas
, 20, 10, hicon
, 0, 0, 0, 0, DI_NORMAL
);
943 void explorer_about(HWND hwndParent
)
945 Dialog::DoModal(IDD_ABOUT_EXPLORER
, WINDOW_CREATOR(ExplorerAboutDlg
), hwndParent
);
949 static void InitInstance(HINSTANCE hInstance
)
951 CONTEXT("InitInstance");
953 setlocale(LC_COLLATE
, ""); // set collating rules to local settings for compareName
956 // register frame window class
957 g_Globals
._hframeClass
= IconWindowClass(CLASSNAME_FRAME
,IDI_EXPLORER
);
959 // register child window class
960 WindowClass(CLASSNAME_CHILDWND
, CS_CLASSDC
|CS_DBLCLKS
).Register();
962 // register tree window class
963 WindowClass(CLASSNAME_WINEFILETREE
, CS_CLASSDC
|CS_DBLCLKS
).Register();
966 g_Globals
._cfStrFName
= RegisterClipboardFormat(CFSTR_FILENAME
);
970 int explorer_main(HINSTANCE hInstance
, LPTSTR lpCmdLine
, int cmdShow
)
972 CONTEXT("explorer_main");
974 // initialize Common Controls library
975 CommonControlInit usingCmnCtrl
;
978 InitInstance(hInstance
);
979 } catch(COMException
& e
) {
980 HandleException(e
, GetDesktopWindow());
985 if (cmdShow
!= SW_HIDE
) {
986 /* // don't maximize if being called from the ROS desktop
987 if (cmdShow == SW_SHOWNORMAL)
988 ///@todo read window placement from registry
989 cmdShow = SW_MAXIMIZE;
992 explorer_show_frame(cmdShow
, lpCmdLine
);
996 Window::MessageLoop();
1002 // MinGW does not provide a Unicode startup routine, so we have to implement an own.
1003 #if defined(__MINGW32__) && defined(UNICODE)
1005 #define _tWinMain wWinMain
1006 int WINAPI
wWinMain(HINSTANCE
, HINSTANCE
, LPWSTR
, int);
1008 int main(int argc
, char* argv
[])
1012 STARTUPINFO startupinfo
;
1013 int nShowCmd
= SW_SHOWNORMAL
;
1015 GetStartupInfo(&startupinfo
);
1017 if (startupinfo
.dwFlags
& STARTF_USESHOWWINDOW
)
1018 nShowCmd
= startupinfo
.wShowWindow
;
1020 LPWSTR cmdline
= GetCommandLineW();
1022 while(*cmdline
&& !_istspace((unsigned)*cmdline
))
1025 while(_istspace((unsigned)*cmdline
))
1028 return wWinMain(GetModuleHandle(NULL
), 0, cmdline
, nShowCmd
);
1031 #endif // __MINGW && UNICODE
1034 static bool SetShellReadyEvent(LPCTSTR evtName
)
1036 HANDLE hEvent
= OpenEvent(EVENT_MODIFY_STATE
, FALSE
, evtName
);
1041 CloseHandle(hEvent
);
1047 int WINAPI
_tWinMain(HINSTANCE hInstance
, HINSTANCE hPrevInstance
, LPTSTR lpCmdLine
, int nShowCmd
)
1049 CONTEXT("WinMain()");
1051 BOOL any_desktop_running
= IsAnyDesktopRunning();
1053 BOOL startup_desktop
;
1055 // strip extended options from the front of the command line
1058 while(*lpCmdLine
== '-') {
1059 while(*lpCmdLine
&& !_istspace((unsigned)*lpCmdLine
))
1060 ext_options
+= *lpCmdLine
++;
1062 while(_istspace((unsigned)*lpCmdLine
))
1066 // command line option "-install" to replace previous shell application with ROS Explorer
1067 if (_tcsstr(ext_options
,TEXT("-install"))) {
1068 // install ROS Explorer into the registry
1069 TCHAR path
[MAX_PATH
];
1071 int l
= GetModuleFileName(0, path
, COUNTOF(path
));
1075 if (!RegOpenKey(HKEY_LOCAL_MACHINE
, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"), &hkey
)) {
1077 ///@todo save previous shell application in config file
1079 RegSetValueEx(hkey
, TEXT("Shell"), 0, REG_SZ
, (LPBYTE
)path
, l
*sizeof(TCHAR
));
1083 if (!RegOpenKey(HKEY_CURRENT_USER
, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"), &hkey
)) {
1085 ///@todo save previous shell application in config file
1087 RegSetValueEx(hkey
, TEXT("Shell"), 0, REG_SZ
, (LPBYTE
)TEXT(""), l
*sizeof(TCHAR
));
1092 HWND shellWindow
= GetShellWindow();
1097 // terminate shell process for NT like systems
1098 GetWindowThreadProcessId(shellWindow
, &pid
);
1099 HANDLE hProcess
= OpenProcess(PROCESS_ALL_ACCESS
, FALSE
, pid
);
1101 // On Win 9x it's sufficient to destroy the shell window.
1102 DestroyWindow(shellWindow
);
1104 if (TerminateProcess(hProcess
, 0))
1105 WaitForSingleObject(hProcess
, INFINITE
);
1107 CloseHandle(hProcess
);
1110 startup_desktop
= TRUE
;
1112 // create desktop window and task bar only, if there is no other shell and we are
1113 // the first explorer instance
1114 // MS Explorer looks additionally into the registry entry HKCU\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\shell,
1115 // to decide wether it is currently configured as shell application.
1116 startup_desktop
= !any_desktop_running
;
1120 bool autostart
= !any_desktop_running
;
1122 // disable autostart if the SHIFT key is pressed
1123 if (GetAsyncKeyState(VK_SHIFT
) < 0)
1126 #ifdef _DEBUG //MF: disabled for debugging
1130 // If there is given the command line option "-desktop", create desktop window anyways
1131 if (_tcsstr(ext_options
,TEXT("-desktop")))
1132 startup_desktop
= TRUE
;
1134 else if (_tcsstr(ext_options
,TEXT("-nodesktop")))
1135 startup_desktop
= FALSE
;
1137 // Don't display cabinet window in desktop mode
1138 if (startup_desktop
&& !_tcsstr(ext_options
,TEXT("-explorer")))
1142 if (_tcsstr(ext_options
,TEXT("-noautostart")))
1144 else if (_tcsstr(ext_options
,TEXT("-autostart")))
1148 if (_tcsstr(ext_options
,TEXT("-console"))) {
1151 _dup2(_open_osfhandle((long)GetStdHandle(STD_INPUT_HANDLE
), _O_RDONLY
), 0);
1152 _dup2(_open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE
), 0), 1);
1153 _dup2(_open_osfhandle((long)GetStdHandle(STD_ERROR_HANDLE
), 0), 2);
1155 g_Globals
._log
= _fdopen(1, "w");
1156 setvbuf(g_Globals
._log
, 0, _IONBF
, 0);
1158 LOG(TEXT("starting explorer debug log\n"));
1163 if (startup_desktop
) {
1164 // hide the XP login screen (Credit to Nicolas Escuder)
1165 // another undocumented event: "Global\\msgina: ReturnToWelcome"
1166 if (!SetShellReadyEvent(TEXT("msgina: ShellReadyEvent")))
1167 SetShellReadyEvent(TEXT("Global\\msgina: ShellReadyEvent"));
1171 return 0; // no shell to launch, so exit immediatelly
1175 if (!any_desktop_running
) {
1176 // launch the shell DDE server
1177 if (g_SHDOCVW_ShellDDEInit
)
1178 (*g_SHDOCVW_ShellDDEInit
)(TRUE
);
1182 bool use_gdb_stub
= false; // !IsDebuggerPresent();
1184 if (_tcsstr(ext_options
,TEXT("-debug")))
1185 use_gdb_stub
= true;
1187 if (_tcsstr(ext_options
,TEXT("-break"))) {
1188 LOG(TEXT("debugger breakpoint"));
1196 // activate GDB remote debugging stub if no other debugger is running
1198 LOG(TEXT("waiting for debugger connection...\n"));
1200 initialize_gdb_stub();
1203 g_Globals
.init(hInstance
);
1205 // initialize COM and OLE before creating the desktop window
1208 // init common controls library
1209 CommonControlInit usingCmnCtrl
;
1211 g_Globals
.read_persistent();
1213 if (startup_desktop
) {
1216 g_Globals
._desktops
.init();
1218 g_Globals
._hwndDesktop
= DesktopWindow::Create();
1220 g_Globals
._desktops
.get_current_Desktop()->_hwndDesktop
= g_Globals
._hwndDesktop
;
1224 if (_tcsstr(ext_options
,TEXT("-?"))) {
1225 MessageBoxA(g_Globals
._hwndDesktop
,
1226 "/e open cabinet window in explorer mode\r\n"
1227 "/root open cabinet window in rooted mode\r\n"
1228 "/mdi open cabinet window in MDI mode\r\n"
1229 "/sdi open cabinet window in SDI mode\r\n"
1231 "-? display command line options\r\n"
1233 "-desktop start in desktop mode regardless of an already running shell\r\n"
1234 "-nodesktop disable desktop mode\r\n"
1235 "-explorer display cabinet window regardless of enabled desktop mode\r\n"
1237 "-install replace previous shell application with ROS Explorer\r\n"
1239 "-noautostart disable autostarts\r\n"
1240 "-autostart enable autostarts regardless of debug build\r\n"
1242 "-console open debug console\r\n"
1244 "-debug activate GDB remote debugging stub\r\n"
1245 "-break activate debugger breakpoint\r\n",
1246 "ROS Explorer - command line options", MB_OK
);
1249 Thread
* pSSOThread
= NULL
;
1251 if (startup_desktop
) {
1252 // launch SSO thread to allow message processing independent from the explorer main thread
1253 pSSOThread
= new SSOThread
;
1254 pSSOThread
->Start();
1257 /**TODO launching autostart programs can be moved into a background thread. */
1259 const char* argv
[] = {"", "s"}; // call startup routine in SESSION_START mode
1264 if (g_Globals
._hwndDesktop
)
1265 g_Globals
._desktop_mode
= true;
1269 int ret
= explorer_main(hInstance
, lpCmdLine
, nShowCmd
);
1272 // write configuration file
1273 g_Globals
.write_persistent();
1280 if (!any_desktop_running
) {
1281 // shutdown the shell DDE server
1282 if (g_SHDOCVW_ShellDDEInit
)
1283 (*g_SHDOCVW_ShellDDEInit
)(FALSE
);