merge ROS Shell without integrated explorer part into trunk
[reactos.git] / reactos / subsys / system / explorer / explorer.cpp
index fb55a7c..435fb23 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003, 2004 Martin Fuchs
+ * Copyright 2003, 2004, 2005 Martin Fuchs
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #include <fcntl.h>     // for _O_RDONLY
 #endif
 
+#include "dialogs/settings.h"  // for MdiSdiDlg
+
+#include "services/shellservices.h"
+
 
 extern "C" int initialize_gdb_stub();  // start up GDB stub
 
 
+DynamicLoadLibFct<void(__stdcall*)(BOOL)> g_SHDOCVW_ShellDDEInit(TEXT("SHDOCVW"), 118);
+
+
 ExplorerGlobals g_Globals;
 
 
 ExplorerGlobals::ExplorerGlobals()
 {
        _hInstance = 0;
-       _hframeClass = 0;
        _cfStrFName = 0;
+
+#ifndef ROSSHELL
+       _hframeClass = 0;
        _hMainWnd = 0;
-       _prescan_nodes = false;
        _desktop_mode = false;
+       _prescan_nodes = false;
+#endif
+
        _log = NULL;
 #ifndef __MINGW32__    // SHRestricted() missing in MinGW (as of 29.10.2003)
        _SHRestricted = 0;
@@ -111,21 +122,21 @@ void ExplorerGlobals::write_persistent()
 
 XMLPos ExplorerGlobals::get_cfg()
 {
-       XMLPos pos(&_cfg);
+       XMLPos cfg_pos(&_cfg);
 
-       pos.smart_create("explorer-cfg");
+       cfg_pos.smart_create("explorer-cfg");
 
-       return pos;
+       return cfg_pos;
 }
 
-XMLPos ExplorerGlobals::get_cfg(const String& name)
+XMLPos ExplorerGlobals::get_cfg(const char* path)
 {
-       XMLPos pos(&_cfg);
+       XMLPos cfg_pos(&_cfg);
 
-       pos.smart_create("explorer-cfg");
-       pos.smart_create(name);
+       cfg_pos.smart_create("explorer-cfg");
+       cfg_pos.create_relative(path);
 
-       return pos;
+       return cfg_pos;
 }
 
 
@@ -380,7 +391,7 @@ const Icon& IconCache::extract(const String& path)
 
        SHFILEINFO sfi;
 
-#if 1  // use system image list
+#if 1  // use system image list - the "search program dialog" needs it
        HIMAGELIST himlSys = (HIMAGELIST) SHGetFileInfo(path, 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX|SHGFI_SMALLICON);
 
        if (himlSys) {
@@ -436,7 +447,7 @@ const Icon& IconCache::extract(IExtractIcon* pExtract, LPCTSTR path, int idx)
 
        HRESULT hr = pExtract->Extract(path, idx, &hIconLarge, &hIcon, MAKELONG(0/*GetSystemMetrics(SM_CXICON)*/,GetSystemMetrics(SM_CXSMICON)));
 
-       if (hr == NOERROR) {
+       if (hr == NOERROR) {    //@@ oder SUCCEEDED(hr) ?
                if (hIconLarge)
                        DestroyIcon(hIconLarge);
 
@@ -521,6 +532,8 @@ ResBitmap::ResBitmap(UINT nid)
 }
 
 
+#ifndef ROSSHELL
+
 void explorer_show_frame(int cmdshow, LPTSTR lpCmdLine)
 {
        if (g_Globals._hMainWnd) {
@@ -534,34 +547,30 @@ void explorer_show_frame(int cmdshow, LPTSTR lpCmdLine)
 
        g_Globals._prescan_nodes = false;
 
-        // create main window
-       HWND hMainFrame = MainFrame::Create();
+       XMLPos explorer_options = g_Globals.get_cfg("general/explorer");
+       XS_String mdiStr = XMLString(explorer_options, "mdi");
 
-       if (hMainFrame) {
-               g_Globals._hMainWnd = hMainFrame;
+       if (mdiStr.empty())
+               Dialog::DoModal(IDD_MDI_SDI, WINDOW_CREATOR(MdiSdiDlg), g_Globals._hwndDesktop);
 
-               ShowWindow(hMainFrame, cmdshow);
-               UpdateWindow(hMainFrame);
+       bool mdi = XMLBool(explorer_options, "mdi", true);
 
-               bool valid_dir = false;
+        // create main window
+       MainFrameBase::Create(lpCmdLine, mdi, cmdshow);
+}
 
-               if (lpCmdLine) {
-                       DWORD attribs = GetFileAttributes(lpCmdLine);
+#else
 
-                       if (attribs!=INVALID_FILE_ATTRIBUTES && (attribs&FILE_ATTRIBUTE_DIRECTORY))
-                               valid_dir = true;
-                       else if (*lpCmdLine==':' || *lpCmdLine=='"')
-                               valid_dir = true;
-               }
+void explorer_show_frame(int cmdshow, LPTSTR lpCmdLine)
+{
+       if (!lpCmdLine)
+               lpCmdLine = TEXT("explorer.exe");
 
-                // Open the first child window after initializing the application
-               if (valid_dir)
-                       PostMessage(hMainFrame, PM_OPEN_WINDOW, 0, (LPARAM)lpCmdLine);
-               else
-                       PostMessage(hMainFrame, PM_OPEN_WINDOW, OWM_EXPLORE|OWM_DETAILS, 0);
-       }
+       launch_file(GetDesktopWindow(), lpCmdLine, cmdshow);
 }
 
+#endif
+
 
 PopupMenu::PopupMenu(UINT nid)
 {
@@ -592,6 +601,13 @@ struct ExplorerAboutDlg : public
 
                new HyperlinkCtrl(hwnd, IDC_WWW);
 
+               FmtString ver_txt(ResString(IDS_EXPLORER_VERSION_STR), (LPCTSTR)ResString(IDS_VERSION_STR));
+               SetWindowText(GetDlgItem(hwnd, IDC_VERSION_TXT), ver_txt);
+
+               HWND hwnd_winver = GetDlgItem(hwnd, IDC_WIN_VERSION);
+               SetWindowText(hwnd_winver, get_windows_version_str());
+               SetWindowFont(hwnd_winver, GetStockFont(DEFAULT_GUI_FONT), FALSE);
+
                CenterWindow(hwnd);
        }
 
@@ -639,14 +655,16 @@ static void InitInstance(HINSTANCE hInstance)
 
        setlocale(LC_COLLATE, "");      // set collating rules to local settings for compareName
 
+#ifndef ROSSHELL
         // register frame window class
        g_Globals._hframeClass = IconWindowClass(CLASSNAME_FRAME,IDI_EXPLORER);
 
-        // register child windows class
+        // register child window class
        WindowClass(CLASSNAME_CHILDWND, CS_CLASSDC|CS_DBLCLKS|CS_VREDRAW).Register();
 
-        // register tree windows class
+        // register tree window class
        WindowClass(CLASSNAME_WINEFILETREE, CS_CLASSDC|CS_DBLCLKS|CS_VREDRAW).Register();
+#endif
 
        g_Globals._cfStrFName = RegisterClipboardFormat(CFSTR_FILENAME);
 }
@@ -666,6 +684,7 @@ int explorer_main(HINSTANCE hInstance, LPTSTR lpCmdLine, int cmdshow)
                return -1;
        }
 
+#ifndef ROSSHELL
        if (cmdshow != SW_HIDE) {
 /*     // don't maximize if being called from the ROS desktop
                if (cmdshow == SW_SHOWNORMAL)
@@ -675,6 +694,7 @@ int explorer_main(HINSTANCE hInstance, LPTSTR lpCmdLine, int cmdshow)
 
                explorer_show_frame(cmdshow, lpCmdLine);
        }
+#endif
 
        return Window::MessageLoop();
 }
@@ -703,12 +723,28 @@ int main(int argc, char* argv[])
        while(*cmdline && !_istspace(*cmdline))
                ++cmdline;
 
+       while(_istspace(*cmdline))
+               ++cmdline;
+
        return wWinMain(GetModuleHandle(NULL), 0, cmdline, nShowCmd);
 }
 
 #endif // __MINGW && UNICODE
 
 
+static bool SetShellReadyEvent(LPCTSTR evtName)
+{
+       HANDLE hEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE, evtName);
+       if (!hEvent)
+               return false;
+
+       SetEvent(hEvent);
+       CloseHandle(hEvent);
+
+       return true;
+}
+
+
 int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd)
 {
        CONTEXT("WinMain()");
@@ -733,6 +769,14 @@ int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdL
                                RegSetValueEx(hkey, TEXT("Shell"), 0, REG_SZ, (LPBYTE)path, l*sizeof(TCHAR));
                                RegCloseKey(hkey);
                        }
+
+                       if (!RegOpenKey(HKEY_CURRENT_USER, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"), &hkey)) {
+
+                               ///@todo save previous shell application in config file
+
+                               RegSetValueEx(hkey, TEXT("Shell"), 0, REG_SZ, (LPBYTE)TEXT(""), l*sizeof(TCHAR));
+                               RegCloseKey(hkey);
+                       }
                }
 
                HWND shellWindow = GetShellWindow();
@@ -754,10 +798,14 @@ int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdL
                }
 
                startup_desktop = TRUE;
-       } else
+       } else {
                 // create desktop window and task bar only, if there is no other shell and we are
                 // the first explorer instance
+                // MS Explorer looks additionally into the registry entry HKCU\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\shell,
+                // to decide wether it is currently configured as shell application.
                startup_desktop = !any_desktop_running;
+       }
+
 
        bool autostart = !any_desktop_running;
 
@@ -772,12 +820,14 @@ int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdL
         // If there is given the command line option "-desktop", create desktop window anyways
        if (_tcsstr(lpCmdLine,TEXT("-desktop")))
                startup_desktop = TRUE;
+#ifndef ROSSHELL
        else if (_tcsstr(lpCmdLine,TEXT("-nodesktop")))
                startup_desktop = FALSE;
 
         // Don't display cabinet window in desktop mode
        if (startup_desktop && !_tcsstr(lpCmdLine,TEXT("-explorer")))
                nShowCmd = SW_HIDE;
+#endif
 
        if (_tcsstr(lpCmdLine,TEXT("-noautostart")))
                autostart = false;
@@ -799,6 +849,26 @@ int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdL
        }
 #endif
 
+
+       if (startup_desktop) {
+                // hide the XP login screen (Credit to Nicolas Escuder)
+                // another undocumented event: "Global\\msgina: ReturnToWelcome"
+               if (!SetShellReadyEvent(TEXT("msgina: ShellReadyEvent")))
+                       SetShellReadyEvent(TEXT("Global\\msgina: ShellReadyEvent"));
+       }
+#ifdef ROSSHELL
+       else
+               return 0;       // no shell to launch, so exit immediatelly
+#endif
+
+
+       if (!any_desktop_running) {
+                // launch the shell DDE server
+               if (g_SHDOCVW_ShellDDEInit)
+                       (*g_SHDOCVW_ShellDDEInit)(TRUE);
+       }
+
+
        bool use_gdb_stub = false;      // !IsDebuggerPresent();
 
        if (_tcsstr(lpCmdLine,TEXT("-debug")))
@@ -831,32 +901,57 @@ int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdL
        g_Globals.read_persistent();
 
        if (startup_desktop) {
+               WaitCursor wait;
+
                g_Globals._desktops.init();
 
                g_Globals._hwndDesktop = DesktopWindow::Create();
 #ifdef _USE_HDESK
                g_Globals._desktops.get_current_Desktop()->_hwndDesktop = g_Globals._hwndDesktop;
 #endif
+       }
 
-               if (autostart) {
-                       char* argv[] = {"", "s"};       // call startup routine in SESSION_START mode
-                       startup(2, argv);
-               }
+       Thread* pSSOThread = NULL;
+
+       if (startup_desktop) {
+                // launch SSO thread to allow message processing independent from the explorer main thread
+               pSSOThread = new SSOThread;
+               pSSOThread->Start();
+       }
+
+       /**TODO launching autostart programs can be moved into a background thread. */
+       if (autostart) {
+               char* argv[] = {"", "s"};       // call startup routine in SESSION_START mode
+               startup(2, argv);
        }
 
+#ifndef ROSSHELL
+       if (g_Globals._hwndDesktop)
+               g_Globals._desktop_mode = true;
+
        /**TODO fix command line handling */
        if (*lpCmdLine=='"' && lpCmdLine[_tcslen(lpCmdLine)-1]=='"') {
                ++lpCmdLine;
                lpCmdLine[_tcslen(lpCmdLine)-1] = '\0';
        }
+#endif
 
-       if (g_Globals._hwndDesktop)
-               g_Globals._desktop_mode = true;
 
        int ret = explorer_main(hInstance, lpCmdLine, nShowCmd);
 
         // write configuration file
        g_Globals.write_persistent();
 
+       if (pSSOThread) {
+               pSSOThread->Stop();
+               delete pSSOThread;
+       }
+
+       if (!any_desktop_running) {
+                // shutdown the shell DDE server
+               if (g_SHDOCVW_ShellDDEInit)
+                       (*g_SHDOCVW_ShellDDEInit)(FALSE);
+       }
+
        return ret;
 }