explorer: Remove useless array NULL check (Coverity).
[wine] / programs / explorer / explorer.c
1 /*
2  * explorer.exe
3  *
4  * Copyright 2004 CodeWeavers, Mike Hearn
5  * Copyright 2005,2006 CodeWeavers, Aric Stewart
6  * Copyright 2011 Jay Yang
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22
23 #define COBJMACROS
24
25 #include "wine/unicode.h"
26 #include "wine/debug.h"
27 #include "explorer_private.h"
28 #include "resource.h"
29
30 #include <initguid.h>
31 #include <windows.h>
32 #include <shobjidl.h>
33 #include <shlobj.h>
34
35
36 WINE_DEFAULT_DEBUG_CHANNEL(explorer);
37
38 #define EXPLORER_INFO_INDEX 0
39
40 #define DEFAULT_WIDTH 640
41 #define DEFAULT_HEIGHT 480
42
43
44 static const WCHAR EXPLORER_CLASS[] = {'W','I','N','E','_','E','X','P','L','O','R','E','R','\0'};
45
46 HINSTANCE explorer_hInstance;
47
48 typedef struct parametersTAG {
49     BOOL    explorer_mode;
50     WCHAR   root[MAX_PATH];
51     WCHAR   selection[MAX_PATH];
52 } parameters_struct;
53
54 typedef struct
55 {
56     IExplorerBrowser *browser;
57 } explorer_info;
58
59 static void make_explorer_window(IShellFolder* startFolder)
60 {
61     RECT explorerRect;
62     HWND window;
63     FOLDERSETTINGS fs;
64     explorer_info *info;
65     HRESULT hres;
66     WCHAR explorer_title[100];
67     LoadStringW(explorer_hInstance,IDS_EXPLORER_TITLE,explorer_title,
68                 sizeof(explorer_title)/sizeof(WCHAR));
69     info = HeapAlloc(GetProcessHeap(),0,sizeof(explorer_info));
70     if(!info)
71     {
72         WINE_ERR("Could not allocate a explorer_info struct\n");
73         return;
74     }
75     hres = CoCreateInstance(&CLSID_ExplorerBrowser,NULL,CLSCTX_INPROC_SERVER,
76                             &IID_IExplorerBrowser,(LPVOID*)&info->browser);
77     if(!SUCCEEDED(hres))
78     {
79         WINE_ERR("Could not obtain an instance of IExplorerBrowser\n");
80         HeapFree(GetProcessHeap(),0,info);
81         return;
82     }
83
84     window = CreateWindowW(EXPLORER_CLASS,explorer_title,WS_OVERLAPPEDWINDOW,
85                            CW_USEDEFAULT,CW_USEDEFAULT,DEFAULT_WIDTH,
86                            DEFAULT_HEIGHT,NULL,NULL,explorer_hInstance,NULL);
87     fs.ViewMode = FVM_DETAILS;
88     fs.fFlags = FWF_AUTOARRANGE;
89     explorerRect.left = 0;
90     explorerRect.top = 0;
91     explorerRect.right = DEFAULT_WIDTH;
92     explorerRect.bottom = DEFAULT_HEIGHT;
93
94     IExplorerBrowser_Initialize(info->browser,window,&explorerRect,&fs);
95     IExplorerBrowser_SetOptions(info->browser,EBO_SHOWFRAMES);
96     SetWindowLongPtrW(window,EXPLORER_INFO_INDEX,(LONG_PTR)info);
97     IExplorerBrowser_BrowseToObject(info->browser,(IUnknown*)startFolder,
98                                     SBSP_ABSOLUTE);
99     ShowWindow(window,SW_SHOWDEFAULT);
100     UpdateWindow(window);
101 }
102
103 static void update_window_size(explorer_info *info, int height, int width)
104 {
105     RECT new_rect;
106     new_rect.left = 0;
107     new_rect.top = 0;
108     new_rect.right = width;
109     new_rect.bottom = height;
110     IExplorerBrowser_SetRect(info->browser,NULL,new_rect);
111 }
112
113 static void do_exit(int code)
114 {
115     OleUninitialize();
116     ExitProcess(code);
117 }
118
119 static LRESULT CALLBACK explorer_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
120 {
121     explorer_info *info
122         = (explorer_info*)GetWindowLongPtrW(hwnd,EXPLORER_INFO_INDEX);
123     IExplorerBrowser *browser = NULL;
124
125     if(info)
126         browser = info->browser;
127     switch(uMsg)
128     {
129     case WM_DESTROY:
130         IExplorerBrowser_Release(browser);
131         HeapFree(GetProcessHeap(),0,info);
132         PostQuitMessage(0);
133         break;
134     case WM_QUIT:
135         do_exit(wParam);
136     case WM_SIZE:
137         update_window_size(info,HIWORD(lParam),LOWORD(lParam));
138         break;
139     default:
140         return DefWindowProcW(hwnd,uMsg,wParam,lParam);
141     }
142     return 0;
143 }
144
145 static void register_explorer_window_class(void)
146 {
147     WNDCLASSEXW window_class;
148     window_class.cbSize = sizeof(WNDCLASSEXW);
149     window_class.style = 0;
150     window_class.cbClsExtra = 0;
151     window_class.cbWndExtra = sizeof(LONG_PTR);
152     window_class.lpfnWndProc = explorer_wnd_proc;
153     window_class.hInstance = explorer_hInstance;
154     window_class.hIcon = NULL;
155     window_class.hCursor = NULL;
156     window_class.hbrBackground = NULL;
157     window_class.lpszMenuName = NULL;
158     window_class.lpszClassName = EXPLORER_CLASS;
159     window_class.hIconSm = NULL;
160     RegisterClassExW(&window_class);
161 }
162
163 static IShellFolder* get_starting_shell_folder(parameters_struct* params)
164 {
165     IShellFolder* desktop,*folder;
166     LPITEMIDLIST root_pidl;
167     HRESULT hres;
168
169     SHGetDesktopFolder(&desktop);
170     if (!params->root[0])
171     {
172         return desktop;
173     }
174     hres = IShellFolder_ParseDisplayName(desktop,NULL,NULL,
175                                          params->root,NULL,
176                                          &root_pidl,NULL);
177
178     if(FAILED(hres))
179     {
180         return desktop;
181     }
182     hres = IShellFolder_BindToObject(desktop,root_pidl,NULL,
183                                      &IID_IShellFolder,
184                                      (void**)&folder);
185     if(FAILED(hres))
186     {
187         return desktop;
188     }
189     IShellFolder_Release(desktop);
190     return folder;
191 }
192
193 static int copy_path_string(LPWSTR target, LPWSTR source)
194 {
195     INT i = 0;
196
197     while (isspaceW(*source)) source++;
198
199     if (*source == '\"')
200     {
201         source ++;
202         while (*source != '\"') target[i++] = *source++;
203         target[i] = 0;
204         source ++;
205         i+=2;
206     }
207     else
208     {
209         while (*source && !isspaceW(*source)) target[i++] = *source++;
210         target[i] = 0;
211     }
212     return i;
213 }
214
215
216 static void copy_path_root(LPWSTR root, LPWSTR path)
217 {
218     LPWSTR p,p2;
219     INT i = 0;
220
221     p = path;
222     while (*p!=0)
223         p++;
224
225     while (*p!='\\' && p > path)
226         p--;
227
228     if (p == path)
229         return;
230
231     p2 = path;
232     while (p2 != p)
233     {
234         root[i] = *p2;
235         i++;
236         p2++;
237     }
238     root[i] = 0;
239 }
240
241 /*
242  * Command Line parameters are:
243  * [/n]  Opens in single-paned view for each selected items. This is default
244  * [/e,] Uses Windows Explorer View
245  * [/root,object] Specifies the root level of the view
246  * [/select,object] parent folder is opened and specified object is selected
247  */
248 static void parse_command_line(LPWSTR commandline,parameters_struct *parameters)
249 {
250     static const WCHAR arg_n[] = {'/','n'};
251     static const WCHAR arg_e[] = {'/','e',','};
252     static const WCHAR arg_root[] = {'/','r','o','o','t',','};
253     static const WCHAR arg_select[] = {'/','s','e','l','e','c','t',','};
254     static const WCHAR arg_desktop[] = {'/','d','e','s','k','t','o','p'};
255
256     LPWSTR p, p2;
257
258     p2 = commandline;
259     p = strchrW(commandline,'/');
260     while(p)
261     {
262         if (strncmpW(p, arg_n, sizeof(arg_n)/sizeof(WCHAR))==0)
263         {
264             parameters->explorer_mode = FALSE;
265             p += sizeof(arg_n)/sizeof(WCHAR);
266         }
267         else if (strncmpW(p, arg_e, sizeof(arg_e)/sizeof(WCHAR))==0)
268         {
269             parameters->explorer_mode = TRUE;
270             p += sizeof(arg_e)/sizeof(WCHAR);
271         }
272         else if (strncmpW(p, arg_root, sizeof(arg_root)/sizeof(WCHAR))==0)
273         {
274             p += sizeof(arg_root)/sizeof(WCHAR);
275             p+=copy_path_string(parameters->root,p);
276         }
277         else if (strncmpW(p, arg_select, sizeof(arg_select)/sizeof(WCHAR))==0)
278         {
279             p += sizeof(arg_select)/sizeof(WCHAR);
280             p+=copy_path_string(parameters->selection,p);
281             if (!parameters->root[0])
282                 copy_path_root(parameters->root,
283                                parameters->selection);
284         }
285         else if (strncmpW(p, arg_desktop, sizeof(arg_desktop)/sizeof(WCHAR))==0)
286         {
287             p += sizeof(arg_desktop)/sizeof(WCHAR);
288             manage_desktop( p );  /* the rest of the command line is handled by desktop mode */
289         }
290         else p++;
291
292         p2 = p;
293         p = strchrW(p,'/');
294     }
295     if (p2 && *p2)
296     {
297         /* left over command line is generally the path to be opened */
298         copy_path_string(parameters->root,p2);
299     }
300 }
301
302 int WINAPI wWinMain(HINSTANCE hinstance,
303                     HINSTANCE previnstance,
304                     LPWSTR cmdline,
305                     int cmdshow)
306 {
307
308     parameters_struct   parameters;
309     HRESULT hres;
310     MSG msg;
311     IShellFolder *folder;
312
313     memset(&parameters,0,sizeof(parameters));
314     explorer_hInstance = hinstance;
315     parse_command_line(cmdline,&parameters);
316     hres = OleInitialize(NULL);
317     if(!SUCCEEDED(hres))
318     {
319         WINE_ERR("Could not initialize COM\n");
320         ExitProcess(EXIT_FAILURE);
321     }
322     register_explorer_window_class();
323     folder = get_starting_shell_folder(&parameters);
324     make_explorer_window(folder);
325     IShellFolder_Release(folder);
326     while(GetMessageW( &msg, NULL, 0, 0 ) != 0)
327     {
328             TranslateMessage(&msg);
329             DispatchMessageW(&msg);
330     }
331     return 0;
332 }