precompiled header support for the lean version of explorer
[reactos.git] / reactos / subsys / system / explorer / explorer.cpp
1 /*
2 * Copyright 2003, 2004 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19
20 //
21 // Explorer clone, lean version
22 //
23 // explorer.cpp
24 //
25 // Martin Fuchs, 23.07.2003
26 //
27 // Credits: Thanks to Leon Finker for his explorer window example
28 //
29
30
31 #include "precomp.h"
32
33 #include "explorer_intres.h"
34
35 #include <locale.h> // for setlocale()
36
37
38 ExplorerGlobals g_Globals;
39
40
41 ExplorerGlobals::ExplorerGlobals()
42 {
43 _hInstance = 0;
44 _hframeClass = 0;
45 _cfStrFName = 0;
46 _hMainWnd = 0;
47 _prescan_nodes = false;
48 _desktop_mode = false;
49 _log = NULL;
50 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
51 _SHRestricted = 0;
52 #endif
53 _hwndDesktopBar = 0;
54 _hwndShellView = 0;
55 _hwndDesktop = 0;
56 }
57
58
59 void ExplorerGlobals::init(HINSTANCE hInstance)
60 {
61 _hInstance = hInstance;
62
63 #ifndef __MINGW32__ // SHRestricted() missing in MinGW (as of 29.10.2003)
64 _SHRestricted = (DWORD(STDAPICALLTYPE*)(RESTRICTIONS)) GetProcAddress(GetModuleHandle(TEXT("SHELL32")), "SHRestricted");
65 #endif
66
67 _icon_cache.init();
68 }
69
70
71 void _log_(LPCTSTR txt)
72 {
73 FmtString msg(TEXT("%s\n"), txt);
74
75 if (g_Globals._log)
76 _fputts(msg, g_Globals._log);
77
78 OutputDebugString(msg);
79 }
80
81
82 bool FileTypeManager::is_exe_file(LPCTSTR ext)
83 {
84 static const LPCTSTR s_executable_extensions[] = {
85 TEXT("COM"),
86 TEXT("EXE"),
87 TEXT("BAT"),
88 TEXT("CMD"),
89 TEXT("CMM"),
90 TEXT("BTM"),
91 TEXT("AWK"),
92 0
93 };
94
95 TCHAR ext_buffer[_MAX_EXT];
96 const LPCTSTR* p;
97 LPCTSTR s;
98 LPTSTR d;
99
100 for(s=ext+1,d=ext_buffer; (*d=toupper(*s)); s++)
101 ++d;
102
103 for(p=s_executable_extensions; *p; p++)
104 if (!lstrcmp(ext_buffer, *p))
105 return true;
106
107 return false;
108 }
109
110
111 const FileTypeInfo& FileTypeManager::operator[](String ext)
112 {
113 _tcslwr((LPTSTR)ext.c_str());
114
115 iterator found = find(ext);
116 if (found != end())
117 return found->second;
118
119 FileTypeInfo& ftype = super::operator[](ext);
120
121 ftype._neverShowExt = false;
122
123 HKEY hkey;
124 TCHAR value[MAX_PATH], display_name[MAX_PATH];;
125 LONG valuelen = sizeof(value);
126
127 if (!RegQueryValue(HKEY_CLASSES_ROOT, ext, value, &valuelen)) {
128 ftype._classname = value;
129
130 valuelen = sizeof(display_name);
131 if (!RegQueryValue(HKEY_CLASSES_ROOT, ftype._classname, display_name, &valuelen))
132 ftype._displayname = display_name;
133
134 if (!RegOpenKey(HKEY_CLASSES_ROOT, ftype._classname, &hkey)) {
135 if (!RegQueryValueEx(hkey, TEXT("NeverShowExt"), 0, NULL, NULL, NULL))
136 ftype._neverShowExt = true;
137
138 RegCloseKey(hkey);
139 }
140 }
141
142 return ftype;
143 }
144
145 LPCTSTR FileTypeManager::set_type(Entry* entry, bool dont_hide_ext)
146 {
147 LPCTSTR ext = _tcsrchr(entry->_data.cFileName, TEXT('.'));
148
149 if (ext) {
150 const FileTypeInfo& type = (*this)[ext];
151
152 if (!type._displayname.empty())
153 entry->_type_name = _tcsdup(type._displayname);
154
155 // hide some file extensions
156 if (type._neverShowExt && !dont_hide_ext) {
157 int len = ext - entry->_data.cFileName;
158 entry->_display_name = (LPTSTR) malloc((len+1)*sizeof(TCHAR));
159 _tcsncpy(entry->_display_name, entry->_data.cFileName, len);
160 entry->_display_name[len] = TEXT('\0');
161 }
162
163 if (is_exe_file(ext))
164 entry->_data.dwFileAttributes |= ATTRIBUTE_EXECUTABLE;
165 }
166
167 return ext;
168 }
169
170
171 Icon::Icon()
172 : _id(ICID_UNKNOWN),
173 _itype(IT_STATIC),
174 _hicon(0)
175 {
176 }
177
178 Icon::Icon(ICON_ID id, UINT nid)
179 : _id(id),
180 _itype(IT_STATIC),
181 _hicon(SmallIcon(nid))
182 {
183 }
184
185 Icon::Icon(ICON_TYPE itype, int id, HICON hIcon)
186 : _id((ICON_ID)id),
187 _itype(itype),
188 _hicon(hIcon)
189 {
190 }
191
192 Icon::Icon(ICON_TYPE itype, int id, int sys_idx)
193 : _id((ICON_ID)id),
194 _itype(itype),
195 _sys_idx(sys_idx)
196 {
197 }
198
199 void Icon::draw(HDC hdc, int x, int y, int cx, int cy, COLORREF bk_color, HBRUSH bk_brush) const
200 {
201 if (_itype == IT_SYSCACHE)
202 ImageList_DrawEx(g_Globals._icon_cache.get_sys_imagelist(), _sys_idx, hdc, x, y, cx, cy, bk_color, CLR_DEFAULT, ILD_NORMAL);
203 else
204 DrawIconEx(hdc, x, y, _hicon, cx, cy, 0, bk_brush, DI_NORMAL);
205 }
206
207 HBITMAP Icon::create_bitmap(COLORREF bk_color, HBRUSH hbrBkgnd, HDC hdc_wnd) const
208 {
209 if (_itype == IT_SYSCACHE) {
210 HIMAGELIST himl = g_Globals._icon_cache.get_sys_imagelist();
211
212 int cx, cy;
213 ImageList_GetIconSize(himl, &cx, &cy);
214
215 HBITMAP hbmp = CreateCompatibleBitmap(hdc_wnd, cx, cy);
216 HDC hdc = CreateCompatibleDC(hdc_wnd);
217 HBITMAP hbmp_old = SelectBitmap(hdc, hbmp);
218 ImageList_DrawEx(himl, _sys_idx, hdc, 0, 0, cx, cy, bk_color, CLR_DEFAULT, ILD_NORMAL);
219 SelectBitmap(hdc, hbmp_old);
220 DeleteDC(hdc);
221 return hbmp;
222 } else
223 return create_bitmap_from_icon(_hicon, hbrBkgnd, hdc_wnd);
224 }
225
226 HBITMAP create_bitmap_from_icon(HICON hIcon, HBRUSH hbrush_bkgnd, HDC hdc_wnd)
227 {
228 HBITMAP hbmp = CreateCompatibleBitmap(hdc_wnd, 16, 16);
229
230 MemCanvas canvas;
231 BitmapSelection sel(canvas, hbmp);
232
233 RECT rect = {0, 0, 16, 16};
234 FillRect(canvas, &rect, hbrush_bkgnd);
235
236 DrawIconEx(canvas, 0, 0, hIcon, 16, 16, 0, hbrush_bkgnd, DI_NORMAL);
237
238 return hbmp;
239 }
240
241
242 int IconCache::s_next_id = ICID_DYNAMIC;
243
244
245 void IconCache::init()
246 {
247 _icons[ICID_NONE] = Icon(IT_STATIC, ICID_NONE, (HICON)0);
248
249 _icons[ICID_FOLDER] = Icon(ICID_FOLDER, IDI_FOLDER);
250 //_icons[ICID_DOCUMENT] = Icon(ICID_DOCUMENT, IDI_DOCUMENT);
251 _icons[ICID_EXPLORER] = Icon(ICID_EXPLORER, IDI_EXPLORER);
252 _icons[ICID_APP] = Icon(ICID_APP, IDI_APPICON);
253
254 _icons[ICID_CONFIG] = Icon(ICID_CONFIG, IDI_CONFIG);
255 _icons[ICID_DOCUMENTS] = Icon(ICID_DOCUMENTS, IDI_DOCUMENTS);
256 _icons[ICID_FAVORITES] = Icon(ICID_FAVORITES, IDI_FAVORITES);
257 _icons[ICID_INFO] = Icon(ICID_INFO, IDI_INFO);
258 _icons[ICID_APPS] = Icon(ICID_APPS, IDI_APPS);
259 _icons[ICID_SEARCH] = Icon(ICID_SEARCH, IDI_SEARCH);
260 _icons[ICID_ACTION] = Icon(ICID_ACTION, IDI_ACTION);
261 _icons[ICID_SEARCH_DOC] = Icon(ICID_SEARCH_DOC, IDI_SEARCH_DOC);
262 _icons[ICID_PRINTER] = Icon(ICID_PRINTER, IDI_PRINTER);
263 _icons[ICID_NETWORK] = Icon(ICID_NETWORK, IDI_NETWORK);
264 _icons[ICID_COMPUTER] = Icon(ICID_COMPUTER, IDI_COMPUTER);
265 _icons[ICID_LOGOFF] = Icon(ICID_LOGOFF, IDI_LOGOFF);
266 }
267
268
269 const Icon& IconCache::extract(const String& path)
270 {
271 PathMap::iterator found = _pathMap.find(path);
272
273 if (found != _pathMap.end())
274 return _icons[found->second];
275
276 SHFILEINFO sfi;
277
278 #if 1 // use system image list
279 HIMAGELIST himlSys = (HIMAGELIST) SHGetFileInfo(path, 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX|SHGFI_SMALLICON);
280
281 if (himlSys) {
282 _himlSys = himlSys;
283
284 const Icon& icon = add(sfi.iIcon/*, IT_SYSCACHE*/);
285 #else
286 if (SHGetFileInfo(path, 0, &sfi, sizeof(sfi), SHGFI_ICON|SHGFI_SMALLICON)) {
287 const Icon& icon = add(sfi.hIcon, IT_CACHED);
288 #endif
289
290 ///@todo limit cache size
291 _pathMap[path] = icon;
292
293 return icon;
294 } else
295 return _icons[ICID_NONE];
296 }
297
298 const Icon& IconCache::extract(LPCTSTR path, int idx)
299 {
300 CachePair key(path, idx);
301
302 _tcslwr((LPTSTR)key.first.c_str());
303
304 PathIdxMap::iterator found = _pathIdxMap.find(key);
305
306 if (found != _pathIdxMap.end())
307 return _icons[found->second];
308
309 HICON hIcon;
310
311 if ((int)ExtractIconEx(path, idx, NULL, &hIcon, 1) > 0) {
312 const Icon& icon = add(hIcon, IT_CACHED);
313
314 _pathIdxMap[key] = icon;
315
316 return icon;
317 } else
318 return _icons[ICID_NONE];
319 }
320
321 const Icon& IconCache::extract(IExtractIcon* pExtract, LPCTSTR path, int idx)
322 {
323 HICON hIconLarge = 0;
324 HICON hIcon;
325
326 HRESULT hr = pExtract->Extract(path, idx, &hIconLarge, &hIcon, MAKELONG(0/*GetSystemMetrics(SM_CXICON)*/,GetSystemMetrics(SM_CXSMICON)));
327
328 if (hr == NOERROR) {
329 if (hIconLarge)
330 DestroyIcon(hIconLarge);
331
332 if (hIcon)
333 return add(hIcon);
334 }
335
336 return _icons[ICID_NONE];
337 }
338
339 const Icon& IconCache::add(HICON hIcon, ICON_TYPE type)
340 {
341 int id = ++s_next_id;
342
343 return _icons[id] = Icon(type, id, hIcon);
344 }
345
346 const Icon& IconCache::add(int sys_idx/*, ICON_TYPE type=IT_SYSCACHE*/)
347 {
348 int id = ++s_next_id;
349
350 return _icons[id] = SysCacheIcon(id, sys_idx);
351 }
352
353 const Icon& IconCache::get_icon(int id)
354 {
355 return _icons[id];
356 }
357
358 void IconCache::free_icon(int icon_id)
359 {
360 IconMap::iterator found = _icons.find(icon_id);
361
362 if (found != _icons.end()) {
363 Icon& icon = found->second;
364
365 if (icon.destroy())
366 _icons.erase(found);
367 }
368 }
369
370
371 ResString::ResString(UINT nid)
372 {
373 TCHAR buffer[BUFFER_LEN];
374
375 int len = LoadString(g_Globals._hInstance, nid, buffer, sizeof(buffer)/sizeof(TCHAR));
376
377 super::assign(buffer, len);
378 }
379
380
381 ResIcon::ResIcon(UINT nid)
382 {
383 _hicon = LoadIcon(g_Globals._hInstance, MAKEINTRESOURCE(nid));
384 }
385
386 SmallIcon::SmallIcon(UINT nid)
387 {
388 _hicon = (HICON)LoadImage(g_Globals._hInstance, MAKEINTRESOURCE(nid), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED);
389 }
390
391 ResIconEx::ResIconEx(UINT nid, int w, int h)
392 {
393 _hicon = (HICON)LoadImage(g_Globals._hInstance, MAKEINTRESOURCE(nid), IMAGE_ICON, w, h, LR_SHARED);
394 }
395
396
397 void SetWindowIcon(HWND hwnd, UINT nid)
398 {
399 HICON hIcon = ResIcon(nid);
400 Window_SetIcon(hwnd, ICON_BIG, hIcon);
401
402 HICON hIconSmall = SmallIcon(nid);
403 Window_SetIcon(hwnd, ICON_SMALL, hIconSmall);
404 }
405
406
407 ResBitmap::ResBitmap(UINT nid)
408 {
409 _hBmp = LoadBitmap(g_Globals._hInstance, MAKEINTRESOURCE(nid));
410 }
411
412
413 void explorer_show_frame(int cmdshow, LPTSTR lpCmdLine)
414 {
415 if (g_Globals._hMainWnd) {
416 if (IsIconic(g_Globals._hMainWnd))
417 ShowWindow(g_Globals._hMainWnd, SW_RESTORE);
418 else
419 SetForegroundWindow(g_Globals._hMainWnd);
420
421 return;
422 }
423
424 g_Globals._prescan_nodes = false;
425
426 // create main window
427 HWND hMainFrame = MainFrame::Create();
428
429 if (hMainFrame) {
430 g_Globals._hMainWnd = hMainFrame;
431
432 ShowWindow(hMainFrame, cmdshow);
433 UpdateWindow(hMainFrame);
434
435 bool valid_dir = false;
436
437 if (lpCmdLine) {
438 DWORD attribs = GetFileAttributes(lpCmdLine);
439
440 if (attribs!=INVALID_FILE_ATTRIBUTES && (attribs&FILE_ATTRIBUTE_DIRECTORY))
441 valid_dir = true;
442 else if (*lpCmdLine==':' || *lpCmdLine=='"')
443 valid_dir = true;
444 }
445
446 // Open the first child window after initializing the application
447 if (valid_dir)
448 PostMessage(hMainFrame, PM_OPEN_WINDOW, 0, (LPARAM)lpCmdLine);
449 else
450 PostMessage(hMainFrame, PM_OPEN_WINDOW, 0/*OWM_EXPLORE|OWM_DETAILS*/, 0);
451 }
452 }
453
454
455 PopupMenu::PopupMenu(UINT nid)
456 {
457 HMENU hMenu = LoadMenu(g_Globals._hInstance, MAKEINTRESOURCE(nid));
458 _hmenu = GetSubMenu(hMenu, 0);
459 }
460
461
462 /// "About Explorer" Dialog
463 struct ExplorerAboutDlg : public
464 CtlColorParent<
465 OwnerDrawParent<Dialog>
466 >
467 {
468 typedef CtlColorParent<
469 OwnerDrawParent<Dialog>
470 > super;
471
472 ExplorerAboutDlg(HWND hwnd)
473 : super(hwnd)
474 {
475 SetWindowIcon(hwnd, IDI_REACTOS);
476
477 new FlatButton(hwnd, IDOK);
478
479 _hfont = CreateFont(20, 0, 0, 0, FW_BOLD, TRUE, 0, 0, 0, 0, 0, 0, 0, TEXT("Sans Serif"));
480 new ColorStatic(hwnd, IDC_ROS_EXPLORER, RGB(32,32,128), 0, _hfont);
481
482 new HyperlinkCtrl(hwnd, IDC_WWW);
483
484 CenterWindow(hwnd);
485 }
486
487 ~ExplorerAboutDlg()
488 {
489 DeleteObject(_hfont);
490 }
491
492 LRESULT WndProc(UINT nmsg, WPARAM wparam, LPARAM lparam)
493 {
494 switch(nmsg) {
495 case WM_PAINT:
496 Paint();
497 break;
498
499 default:
500 return super::WndProc(nmsg, wparam, lparam);
501 }
502
503 return 0;
504 }
505
506 void Paint()
507 {
508 PaintCanvas canvas(_hwnd);
509
510 HICON hicon = (HICON) LoadImage(g_Globals._hInstance, MAKEINTRESOURCE(IDI_REACTOS_BIG), IMAGE_ICON, 0, 0, LR_SHARED);
511
512 DrawIconEx(canvas, 20, 10, hicon, 0, 0, 0, 0, DI_NORMAL);
513 }
514
515 protected:
516 HFONT _hfont;
517 };
518
519 void explorer_about(HWND hwndParent)
520 {
521 Dialog::DoModal(IDD_ABOUT_EXPLORER, WINDOW_CREATOR(ExplorerAboutDlg), hwndParent);
522 }
523
524
525 static void InitInstance(HINSTANCE hInstance)
526 {
527 CONTEXT("InitInstance");
528
529 setlocale(LC_COLLATE, ""); // set collating rules to local settings for compareName
530
531 // register frame window class
532 g_Globals._hframeClass = IconWindowClass(CLASSNAME_FRAME,IDI_EXPLORER);
533
534 // register child windows class
535 WindowClass(CLASSNAME_CHILDWND, CS_CLASSDC|CS_DBLCLKS|CS_VREDRAW).Register();
536
537 // register tree windows class
538 WindowClass(CLASSNAME_WINEFILETREE, CS_CLASSDC|CS_DBLCLKS|CS_VREDRAW).Register();
539
540 g_Globals._cfStrFName = RegisterClipboardFormat(CFSTR_FILENAME);
541 }
542
543
544 int explorer_main(HINSTANCE hInstance, LPTSTR lpCmdLine, int cmdshow)
545 {
546 CONTEXT("explorer_main");
547
548 // initialize Common Controls library
549 CommonControlInit usingCmnCtrl;
550
551 try {
552 InitInstance(hInstance);
553 } catch(COMException& e) {
554 HandleException(e, GetDesktopWindow());
555 return -1;
556 }
557
558 if (cmdshow != SW_HIDE) {
559 /* // don't maximize if being called from the ROS desktop
560 if (cmdshow == SW_SHOWNORMAL)
561 ///@todo read window placement from registry
562 cmdshow = SW_MAXIMIZE;
563 */
564
565 explorer_show_frame(cmdshow, lpCmdLine);
566 }
567
568 return Window::MessageLoop();
569 }
570
571
572 // MinGW does not provide a Unicode startup routine, so we have to implement an own.
573 #if defined(__MINGW32__) && defined(UNICODE)
574
575 #define _tWinMain wWinMain
576 int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int);
577
578 int main(int argc, char* argv[])
579 {
580 CONTEXT("main");
581
582 STARTUPINFO startupinfo;
583 int nShowCmd = SW_SHOWNORMAL;
584
585 GetStartupInfo(&startupinfo);
586
587 if (startupinfo.dwFlags & STARTF_USESHOWWINDOW)
588 nShowCmd = startupinfo.wShowWindow;
589
590 LPWSTR cmdline = GetCommandLineW();
591
592 while(*cmdline && !_istspace(*cmdline))
593 ++cmdline;
594
595 return wWinMain(GetModuleHandle(NULL), 0, cmdline, nShowCmd);
596 }
597
598 #endif // __MINGW && UNICODE
599
600
601 int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd)
602 {
603 CONTEXT("WinMain()");
604
605 BOOL any_desktop_running = IsAnyDesktopRunning();
606
607 BOOL startup_desktop;
608
609 // command line option "-install" to replace previous shell application with ROS Explorer
610 if (_tcsstr(lpCmdLine,TEXT("-install"))) {
611 // install ROS Explorer into the registry
612 TCHAR path[MAX_PATH];
613
614 int l = GetModuleFileName(0, path, MAX_PATH);
615 if (l) {
616 HKEY hkey;
617
618 if (!RegOpenKey(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"), &hkey)) {
619
620 ///@todo save previous shell application in config file
621
622 RegSetValueEx(hkey, TEXT("Shell"), 0, REG_SZ, (LPBYTE)path, l*sizeof(TCHAR));
623 RegCloseKey(hkey);
624 }
625 }
626
627 HWND shellWindow = GetShellWindow();
628
629 if (shellWindow) {
630 DWORD pid;
631
632 // terminate shell process for NT like systems
633 GetWindowThreadProcessId(shellWindow, &pid);
634 HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
635
636 // On Win 9x it's sufficient to destroy the shell window.
637 DestroyWindow(shellWindow);
638
639 if (TerminateProcess(hProcess, 0))
640 WaitForSingleObject(hProcess, INFINITE);
641
642 CloseHandle(hProcess);
643 }
644
645 startup_desktop = TRUE;
646 } else
647 // create desktop window and task bar only, if there is no other shell and we are
648 // the first explorer instance
649 startup_desktop = !any_desktop_running;
650
651 bool autostart = !any_desktop_running;
652
653 // disable autostart if the SHIFT key is pressed
654 if (GetAsyncKeyState(VK_SHIFT) < 0)
655 autostart = false;
656
657 #ifdef _DEBUG //MF: disabled for debugging
658 autostart = false;
659 #endif
660
661 // If there is given the command line option "-desktop", create desktop window anyways
662 if (_tcsstr(lpCmdLine,TEXT("-desktop")))
663 startup_desktop = TRUE;
664 else if (_tcsstr(lpCmdLine,TEXT("-nodesktop")))
665 startup_desktop = FALSE;
666
667 // Don't display cabinet window in desktop mode
668 if (startup_desktop && !_tcsstr(lpCmdLine,TEXT("-explorer")))
669 nShowCmd = SW_HIDE;
670
671 if (_tcsstr(lpCmdLine,TEXT("-noautostart")))
672 autostart = false;
673
674 g_Globals.init(hInstance);
675
676 // initialize COM and OLE before creating the desktop window
677 OleInit usingCOM;
678
679 if (startup_desktop) {
680 g_Globals._desktops.init();
681
682 g_Globals._hwndDesktop = DesktopWindow::Create();
683
684 if (autostart) {
685 char* argv[] = {"", "s"}; // call startup routine in SESSION_START mode
686 startup(2, argv);
687 }
688 }
689
690 /**TODO fix command line handling */
691 if (*lpCmdLine=='"' && lpCmdLine[_tcslen(lpCmdLine)-1]=='"') {
692 ++lpCmdLine;
693 lpCmdLine[_tcslen(lpCmdLine)-1] = '\0';
694 }
695
696 if (g_Globals._hwndDesktop)
697 g_Globals._desktop_mode = true;
698
699 int ret = explorer_main(hInstance, lpCmdLine, nShowCmd);
700
701 return ret;
702 }