xref: /reactos/base/shell/explorer/explorer.cpp (revision cc3672cb)
1 /*
2  * ReactOS Explorer
3  *
4  * Copyright 2006 - 2007 Thomas Weidenmueller <w3seek@reactos.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20 
21 #include "precomp.h"
22 #include <browseui_undoc.h>
23 
24 HINSTANCE hExplorerInstance;
25 HANDLE hProcessHeap;
26 HKEY hkExplorer = NULL;
27 BOOL bExplorerIsShell = FALSE;
28 
29 class CExplorerModule : public CComModule
30 {
31 public:
32 };
33 
34 BEGIN_OBJECT_MAP(ObjectMap)
35 END_OBJECT_MAP()
36 
37 CExplorerModule gModule;
38 CAtlWinModule   gWinModule;
39 
40 static VOID InitializeAtlModule(HINSTANCE hInstance, BOOL bInitialize)
41 {
42     if (bInitialize)
43     {
44         gModule.Init(ObjectMap, hInstance, NULL);
45     }
46     else
47     {
48         gModule.Term();
49     }
50 }
51 
52 #if !WIN7_DEBUG_MODE
53 static BOOL
54 SetShellReadyEvent(IN LPCWSTR lpEventName)
55 {
56     HANDLE hEvent;
57 
58     hEvent = OpenEventW(EVENT_MODIFY_STATE, FALSE, lpEventName);
59     if (hEvent != NULL)
60     {
61         SetEvent(hEvent);
62 
63         CloseHandle(hEvent);
64         return TRUE;
65     }
66 
67     return FALSE;
68 }
69 
70 static VOID
71 HideMinimizedWindows(IN BOOL bHide)
72 {
73     MINIMIZEDMETRICS mm;
74 
75     mm.cbSize = sizeof(mm);
76     if (!SystemParametersInfoW(SPI_GETMINIMIZEDMETRICS, sizeof(mm), &mm, 0))
77     {
78         ERR("SystemParametersInfoW failed with %lu\n", GetLastError());
79         return;
80     }
81     if (bHide)
82         mm.iArrange |= ARW_HIDE;
83     else
84         mm.iArrange &= ~ARW_HIDE;
85     if (!SystemParametersInfoW(SPI_SETMINIMIZEDMETRICS, sizeof(mm), &mm, 0))
86         ERR("SystemParametersInfoW failed with %lu\n", GetLastError());
87 }
88 #endif
89 
90 static BOOL
91 IsExplorerSystemShell()
92 {
93     BOOL bIsSystemShell = TRUE; // Assume we are the system shell by default.
94     WCHAR szPath[MAX_PATH];
95 
96     if (!GetModuleFileNameW(NULL, szPath, _countof(szPath)))
97         return FALSE;
98 
99     LPWSTR szExplorer = PathFindFileNameW(szPath);
100 
101     HKEY hKeyWinlogon;
102     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
103                       L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
104                       0, KEY_READ, &hKeyWinlogon) == ERROR_SUCCESS)
105     {
106         LSTATUS Status;
107         DWORD dwType;
108         WCHAR szShell[MAX_PATH];
109         DWORD cbShell = sizeof(szShell);
110 
111         // TODO: Add support for paths longer than MAX_PATH
112         Status = RegQueryValueExW(hKeyWinlogon, L"Shell", 0, &dwType, (LPBYTE)szShell, &cbShell);
113         if (Status == ERROR_SUCCESS)
114         {
115             if ((dwType != REG_SZ && dwType != REG_EXPAND_SZ) || !StrStrIW(szShell, szExplorer))
116                 bIsSystemShell = FALSE;
117         }
118 
119         RegCloseKey(hKeyWinlogon);
120     }
121 
122     return bIsSystemShell;
123 }
124 
125 #if !WIN7_COMPAT_MODE
126 static INT
127 StartWithCommandLine(IN HINSTANCE hInstance)
128 {
129     BOOL b = FALSE;
130     EXPLORER_CMDLINE_PARSE_RESULTS parseResults = { 0 };
131 
132     if (SHExplorerParseCmdLine(&parseResults))
133         b = SHCreateFromDesktop(&parseResults);
134 
135     if (parseResults.strPath)
136         SHFree(parseResults.strPath);
137 
138     if (parseResults.pidlPath)
139         ILFree(parseResults.pidlPath);
140 
141     if (parseResults.pidlRoot)
142         ILFree(parseResults.pidlRoot);
143 
144     return b;
145 }
146 #endif
147 
148 static INT
149 StartWithDesktop(IN HINSTANCE hInstance)
150 {
151     InitializeAtlModule(hInstance, TRUE);
152 
153     if (RegOpenKeyW(HKEY_CURRENT_USER,
154         L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer",
155         &hkExplorer) != ERROR_SUCCESS)
156     {
157         WCHAR Message[256];
158         LoadStringW(hInstance, IDS_STARTUP_ERROR, Message, _countof(Message));
159         MessageBox(NULL, Message, NULL, MB_ICONERROR);
160         return 1;
161     }
162 
163     hExplorerInstance = hInstance;
164     hProcessHeap = GetProcessHeap();
165 
166     g_TaskbarSettings.Load();
167 
168     InitCommonControls();
169     OleInitialize(NULL);
170 
171 #if !WIN7_COMPAT_MODE
172     /* Initialize shell dde support */
173     _ShellDDEInit(TRUE);
174 #endif
175 
176     /* Initialize shell icons */
177     FileIconInit(TRUE);
178 
179     /* Initialize CLSID_ShellWindows class */
180     _WinList_Init();
181 
182     CComPtr<ITrayWindow> Tray;
183     CreateTrayWindow(&Tray);
184 
185 #if !WIN7_DEBUG_MODE
186     /* This not only hides the minimized window captions in the bottom
187     left screen corner, but is also needed in order to receive
188     HSHELL_* notification messages (which are required for taskbar
189     buttons to work right) */
190     HideMinimizedWindows(TRUE);
191 
192     ProcessRunOnceItems(); // Must be executed before the desktop is created
193 
194     HANDLE hShellDesktop = NULL;
195     if (Tray != NULL)
196         hShellDesktop = DesktopCreateWindow(Tray);
197 
198     /* WinXP: Notify msgina to hide the welcome screen */
199     if (!SetShellReadyEvent(L"msgina: ShellReadyEvent"))
200         SetShellReadyEvent(L"Global\\msgina: ShellReadyEvent");
201 
202     if (DoStartStartupItems(Tray))
203     {
204         ProcessStartupItems();
205         DoFinishStartupItems();
206     }
207     ReleaseStartupMutex(); // For ProcessRunOnceItems
208 #endif
209 
210     if (Tray != NULL)
211     {
212         TrayMessageLoop(Tray);
213 #if !WIN7_DEBUG_MODE
214         HideMinimizedWindows(FALSE);
215 #endif
216     }
217 
218 #if !WIN7_DEBUG_MODE
219     if (hShellDesktop != NULL)
220         DesktopDestroyShellWindow(hShellDesktop);
221 #endif
222 
223     OleUninitialize();
224 
225     RegCloseKey(hkExplorer);
226     hkExplorer = NULL;
227 
228     InitializeAtlModule(hInstance, FALSE);
229 
230     return 0;
231 }
232 
233 INT WINAPI
234 _tWinMain(IN HINSTANCE hInstance,
235           IN HINSTANCE hPrevInstance,
236           IN LPTSTR lpCmdLine,
237           IN INT nCmdShow)
238 {
239     /*
240     * Set our shutdown parameters: we want to shutdown the very last,
241     * but before any TaskMgr instance (which has a shutdown level of 1).
242     */
243     SetProcessShutdownParameters(2, 0);
244 
245     InitRSHELL();
246 
247     TRACE("Explorer starting... Command line: %S\n", lpCmdLine);
248 
249 #if !WIN7_COMPAT_MODE
250     bExplorerIsShell = (GetShellWindow() == NULL) && IsExplorerSystemShell();
251 
252     if (!bExplorerIsShell)
253     {
254         return StartWithCommandLine(hInstance);
255     }
256 #else
257     bExplorerIsShell = IsExplorerSystemShell();
258 #endif
259 
260     return StartWithDesktop(hInstance);
261 }
262