explorer: Add dropdown entries to explorer's combobox.
[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 #include <commoncontrols.h>
35 #include <commctrl.h>
36
37 WINE_DEFAULT_DEBUG_CHANNEL(explorer);
38
39 #define EXPLORER_INFO_INDEX 0
40
41 #define NAV_TOOLBAR_HEIGHT 30
42 #define PATHBOX_HEIGHT 24
43
44 #define DEFAULT_WIDTH 640
45 #define DEFAULT_HEIGHT 480
46
47
48 static const WCHAR EXPLORER_CLASS[] = {'W','I','N','E','_','E','X','P','L','O','R','E','R','\0'};
49 static const WCHAR PATH_BOX_NAME[] = {'\0'};
50
51 HINSTANCE explorer_hInstance;
52
53 typedef struct parametersTAG {
54     BOOL    explorer_mode;
55     WCHAR   root[MAX_PATH];
56     WCHAR   selection[MAX_PATH];
57 } parameters_struct;
58
59 typedef struct
60 {
61     IExplorerBrowser *browser;
62     HWND main_window,path_box;
63     INT rebar_height;
64     LPCITEMIDLIST pidl;
65     IImageList *icon_list;
66 } explorer_info;
67
68 enum
69 {
70     BACK_BUTTON,FORWARD_BUTTON,UP_BUTTON
71 };
72
73 typedef struct
74 {
75     IExplorerBrowserEvents IExplorerBrowserEvents_iface;
76     explorer_info* info;
77     LONG ref;
78 } IExplorerBrowserEventsImpl;
79
80 static IExplorerBrowserEventsImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
81 {
82     return CONTAINING_RECORD(iface, IExplorerBrowserEventsImpl, IExplorerBrowserEvents_iface);
83 }
84
85 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnQueryInterface(IExplorerBrowserEvents *iface, REFIID riid, void **ppvObject)
86 {
87     return E_NOINTERFACE;
88 }
89
90 static ULONG WINAPI IExplorerBrowserEventsImpl_fnAddRef(IExplorerBrowserEvents *iface)
91 {
92     IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
93     return InterlockedIncrement(&This->ref);
94 }
95
96 static ULONG WINAPI IExplorerBrowserEventsImpl_fnRelease(IExplorerBrowserEvents *iface)
97 {
98     IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
99     ULONG ref = InterlockedDecrement(&This->ref);
100     if(!ref)
101         HeapFree(GetProcessHeap(),0,This);
102     return ref;
103 }
104
105 static BOOL create_combobox_item(IShellFolder *folder, LPCITEMIDLIST pidl, IImageList *icon_list, COMBOBOXEXITEMW *item)
106 {
107     STRRET strret;
108     HRESULT hres;
109     IExtractIconW *extract_icon;
110     UINT reserved;
111     WCHAR icon_file[MAX_PATH];
112     INT icon_index;
113     UINT icon_flags;
114     HICON icon;
115     strret.uType=STRRET_WSTR;
116     hres = IShellFolder_GetDisplayNameOf(folder,pidl,SHGDN_FORADDRESSBAR,&strret);
117     if(FAILED(hres))
118     {
119         WINE_WARN("Could not get name for pidl\n");
120         return FALSE;
121     }
122     switch(strret.uType)
123     {
124     case STRRET_WSTR:
125         item->pszText = strret.pOleStr;
126         break;
127     default:
128         WINE_FIXME("Unimplemented STRRET type:%u\n",strret.uType);
129         break;
130     }
131     hres = IShellFolder_GetUIObjectOf(folder,NULL,1,&pidl,&IID_IExtractIconW,
132                                       &reserved,(void**)&extract_icon);
133     if(SUCCEEDED(hres))
134     {
135         item->mask |= CBEIF_IMAGE;
136         IExtractIconW_GetIconLocation(extract_icon,GIL_FORSHELL,icon_file,
137                                       sizeof(icon_file)/sizeof(WCHAR),
138                                       &icon_index,&icon_flags);
139         IExtractIconW_Extract(extract_icon,icon_file,icon_index,NULL,&icon,20);
140         item->iImage = ImageList_AddIcon((HIMAGELIST)icon_list,icon);
141     }
142     else
143     {
144         item->mask &= ~CBEIF_IMAGE;
145         WINE_WARN("Could not get an icon for %s\n",wine_dbgstr_w(item->pszText));
146     }
147     return TRUE;
148 }
149
150 static void update_path_box(explorer_info *info)
151 {
152     COMBOBOXEXITEMW item;
153     COMBOBOXEXITEMW main_item;
154     IShellFolder *desktop;
155     IPersistFolder2 *persist;
156     LPITEMIDLIST desktop_pidl;
157     IEnumIDList *ids;
158
159     ImageList_Remove((HIMAGELIST)info->icon_list,-1);
160     SendMessageW(info->path_box,CB_RESETCONTENT,0,0);
161     SHGetDesktopFolder(&desktop);
162     IShellFolder_QueryInterface(desktop,&IID_IPersistFolder2,(void**)&persist);
163     IPersistFolder2_GetCurFolder(persist,&desktop_pidl);
164     IPersistFolder2_Release(persist);
165     persist = NULL;
166     /*Add Desktop*/
167     item.iItem = -1;
168     item.mask = CBEIF_TEXT | CBEIF_INDENT | CBEIF_LPARAM;
169     item.iIndent = 0;
170     create_combobox_item(desktop,desktop_pidl,info->icon_list,&item);
171     item.lParam = (LPARAM)desktop_pidl;
172     SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item);
173     if(ILIsEqual(info->pidl,desktop_pidl))
174         main_item = item;
175     else
176         CoTaskMemFree(item.pszText);
177     /*Add all direct subfolders of Desktop*/
178     if(SUCCEEDED(IShellFolder_EnumObjects(desktop,NULL,SHCONTF_FOLDERS,&ids))
179        && ids!=NULL)
180     {
181         LPITEMIDLIST curr_pidl;
182         HRESULT hres;
183
184         item.iIndent = 1;
185         while(1)
186         {
187             hres = IEnumIDList_Next(ids,1,&curr_pidl,NULL);
188             if(FAILED(hres) || hres == S_FALSE)
189                 break;
190             if(!create_combobox_item(desktop,curr_pidl,info->icon_list,&item))
191                 WINE_WARN("Could not create a combobox item\n");
192             else
193             {
194                 LPITEMIDLIST full_pidl = ILCombine(desktop_pidl,curr_pidl);
195                 item.lParam = (LPARAM)full_pidl;
196                 SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item);
197                 if(ILIsEqual(full_pidl,info->pidl))
198                     main_item = item;
199                 else if(ILIsParent(full_pidl,info->pidl,FALSE))
200                 {
201                     /*add all parents of the pidl passed in*/
202                     LPITEMIDLIST next_pidl = ILFindChild(full_pidl,info->pidl);
203                     IShellFolder *curr_folder = NULL, *temp;
204                     hres = IShellFolder_BindToObject(desktop,curr_pidl,NULL,
205                                                      &IID_IShellFolder,
206                                                      (void**)&curr_folder);
207                     if(FAILED(hres))
208                         WINE_WARN("Could not get an IShellFolder\n");
209                     while(!ILIsEmpty(next_pidl))
210                     {
211                         LPITEMIDLIST first = ILCloneFirst(next_pidl);
212                         CoTaskMemFree(item.pszText);
213                         if(!create_combobox_item(curr_folder,first,
214                                                  info->icon_list,&item))
215                         {
216                             WINE_WARN("Could not create a combobox item\n");
217                             break;
218                         }
219                         ++item.iIndent;
220                         full_pidl = ILCombine(full_pidl,first);
221                         item.lParam = (LPARAM)full_pidl;
222                         SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item);
223                         temp=NULL;
224                         hres = IShellFolder_BindToObject(curr_folder,first,NULL,
225                                                          &IID_IShellFolder,
226                                                          (void**)&temp);
227                         if(FAILED(hres))
228                         {
229                             WINE_WARN("Could not get an IShellFolder\n");
230                             break;
231                         }
232                         IShellFolder_Release(curr_folder);
233                         curr_folder = temp;
234
235                         ILFree(first);
236                         next_pidl = ILGetNext(next_pidl);
237                     }
238                     memcpy(&main_item,&item,sizeof(item));
239                     if(curr_folder)
240                         IShellFolder_Release(curr_folder);
241                     item.iIndent = 1;
242                 }
243                 else
244                     CoTaskMemFree(item.pszText);
245             }
246         }
247     }
248     else
249         WINE_WARN("Could not enumerate the desktop\n");
250     SendMessageW(info->path_box,CBEM_SETITEMW,0,(LPARAM)&main_item);
251     CoTaskMemFree(main_item.pszText);
252 }
253
254 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnNavigationComplete(IExplorerBrowserEvents *iface, PCIDLIST_ABSOLUTE pidl)
255 {
256     IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
257     This->info->pidl = pidl;
258     update_path_box(This->info);
259     return S_OK;
260 }
261
262 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnNavigationFailed(IExplorerBrowserEvents *iface, PCIDLIST_ABSOLUTE pidl)
263 {
264     return S_OK;
265 }
266
267 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnNavigationPending(IExplorerBrowserEvents *iface, PCIDLIST_ABSOLUTE pidl)
268 {
269     return S_OK;
270 }
271
272 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnViewCreated(IExplorerBrowserEvents *iface, IShellView *psv)
273 {
274     return S_OK;
275 }
276
277 static IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents =
278 {
279     IExplorerBrowserEventsImpl_fnQueryInterface,
280     IExplorerBrowserEventsImpl_fnAddRef,
281     IExplorerBrowserEventsImpl_fnRelease,
282     IExplorerBrowserEventsImpl_fnOnNavigationPending,
283     IExplorerBrowserEventsImpl_fnOnViewCreated,
284     IExplorerBrowserEventsImpl_fnOnNavigationComplete,
285     IExplorerBrowserEventsImpl_fnOnNavigationFailed
286 };
287
288 static IExplorerBrowserEvents *make_explorer_events(explorer_info *info)
289 {
290     IExplorerBrowserEventsImpl *ret
291         = HeapAlloc(GetProcessHeap(), 0, sizeof(IExplorerBrowserEventsImpl));
292     ret->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents;
293     ret->info = info;
294     SHGetImageList(SHIL_SMALL,&IID_IImageList,(void**)&(ret->info->icon_list));
295     SendMessageW(info->path_box,CBEM_SETIMAGELIST,0,(LPARAM)ret->info->icon_list);
296     IExplorerBrowserEvents_AddRef(&ret->IExplorerBrowserEvents_iface);
297     return &ret->IExplorerBrowserEvents_iface;
298 }
299
300 static void make_explorer_window(IShellFolder* startFolder)
301 {
302     RECT explorerRect;
303     HWND rebar,nav_toolbar;
304     FOLDERSETTINGS fs;
305     IExplorerBrowserEvents *events;
306     explorer_info *info;
307     HRESULT hres;
308     DWORD cookie;
309     WCHAR explorer_title[100];
310     WCHAR pathbox_label[50];
311     TBADDBITMAP bitmap_info;
312     TBBUTTON nav_buttons[3];
313     int hist_offset,view_offset;
314     REBARBANDINFOW band_info;
315     memset(nav_buttons,0,sizeof(nav_buttons));
316     LoadStringW(explorer_hInstance,IDS_EXPLORER_TITLE,explorer_title,
317                 sizeof(explorer_title)/sizeof(WCHAR));
318     LoadStringW(explorer_hInstance,IDS_PATHBOX_LABEL,pathbox_label,
319                 sizeof(pathbox_label)/sizeof(WCHAR));
320     info = HeapAlloc(GetProcessHeap(),0,sizeof(explorer_info));
321     if(!info)
322     {
323         WINE_ERR("Could not allocate a explorer_info struct\n");
324         return;
325     }
326     hres = CoCreateInstance(&CLSID_ExplorerBrowser,NULL,CLSCTX_INPROC_SERVER,
327                             &IID_IExplorerBrowser,(LPVOID*)&info->browser);
328     if(!SUCCEEDED(hres))
329     {
330         WINE_ERR("Could not obtain an instance of IExplorerBrowser\n");
331         HeapFree(GetProcessHeap(),0,info);
332         return;
333     }
334     info->rebar_height=0;
335     info->main_window
336         = CreateWindowW(EXPLORER_CLASS,explorer_title,WS_OVERLAPPEDWINDOW,
337                         CW_USEDEFAULT,CW_USEDEFAULT,DEFAULT_WIDTH,
338                         DEFAULT_HEIGHT,NULL,NULL,explorer_hInstance,NULL);
339
340     fs.ViewMode = FVM_DETAILS;
341     fs.fFlags = FWF_AUTOARRANGE;
342     explorerRect.left = 0;
343     explorerRect.top = 0;
344     explorerRect.right = DEFAULT_WIDTH;
345     explorerRect.bottom = DEFAULT_HEIGHT;
346
347     IExplorerBrowser_Initialize(info->browser,info->main_window,&explorerRect,&fs);
348     IExplorerBrowser_SetOptions(info->browser,EBO_SHOWFRAMES);
349     SetWindowLongPtrW(info->main_window,EXPLORER_INFO_INDEX,(LONG)info);
350
351     /*setup navbar*/
352     rebar = CreateWindowExW(WS_EX_TOOLWINDOW,REBARCLASSNAMEW,NULL,
353                             WS_CHILD|WS_VISIBLE|RBS_VARHEIGHT|CCS_TOP|CCS_NODIVIDER,
354                             0,0,0,0,info->main_window,NULL,explorer_hInstance,NULL);
355     nav_toolbar
356         = CreateWindowExW(TBSTYLE_EX_MIXEDBUTTONS,TOOLBARCLASSNAMEW,NULL,
357                           WS_CHILD|WS_VISIBLE|TBSTYLE_FLAT,0,0,0,0,rebar,NULL,
358                           explorer_hInstance,NULL);
359
360     bitmap_info.hInst = HINST_COMMCTRL;
361     bitmap_info.nID = IDB_HIST_LARGE_COLOR;
362     hist_offset= SendMessageW(nav_toolbar,TB_ADDBITMAP,0,(LPARAM)&bitmap_info);
363     bitmap_info.nID = IDB_VIEW_LARGE_COLOR;
364     view_offset= SendMessageW(nav_toolbar,TB_ADDBITMAP,0,(LPARAM)&bitmap_info);
365
366     nav_buttons[0].iBitmap=hist_offset+HIST_BACK;
367     nav_buttons[0].idCommand=BACK_BUTTON;
368     nav_buttons[0].fsState=TBSTATE_ENABLED;
369     nav_buttons[0].fsStyle=BTNS_BUTTON|BTNS_AUTOSIZE;
370     nav_buttons[1].iBitmap=hist_offset+HIST_FORWARD;
371     nav_buttons[1].idCommand=FORWARD_BUTTON;
372     nav_buttons[1].fsState=TBSTATE_ENABLED;
373     nav_buttons[1].fsStyle=BTNS_BUTTON|BTNS_AUTOSIZE;
374     nav_buttons[2].iBitmap=view_offset+VIEW_PARENTFOLDER;
375     nav_buttons[2].idCommand=UP_BUTTON;
376     nav_buttons[2].fsState=TBSTATE_ENABLED;
377     nav_buttons[2].fsStyle=BTNS_BUTTON|BTNS_AUTOSIZE;
378     SendMessageW(nav_toolbar,TB_BUTTONSTRUCTSIZE,sizeof(TBBUTTON),0);
379     SendMessageW(nav_toolbar,TB_ADDBUTTONSW,sizeof(nav_buttons)/sizeof(TBBUTTON),(LPARAM)nav_buttons);
380
381     band_info.cbSize = sizeof(band_info);
382     band_info.fMask = RBBIM_STYLE|RBBIM_CHILD|RBBIM_CHILDSIZE|RBBIM_SIZE;
383     band_info.hwndChild = nav_toolbar;
384     band_info.fStyle=RBBS_GRIPPERALWAYS|RBBS_CHILDEDGE;
385     band_info.cyChild=NAV_TOOLBAR_HEIGHT;
386     band_info.cx=0;
387     band_info.cyMinChild=NAV_TOOLBAR_HEIGHT;
388     band_info.cxMinChild=0;
389     SendMessageW(rebar,RB_INSERTBANDW,-1,(LPARAM)&band_info);
390     info->path_box = CreateWindowW(WC_COMBOBOXEXW,PATH_BOX_NAME,
391                                    WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
392                                    0,0,DEFAULT_WIDTH,PATHBOX_HEIGHT,rebar,NULL,
393                                    explorer_hInstance,NULL);
394     band_info.cyChild=PATHBOX_HEIGHT;
395     band_info.cx=0;
396     band_info.cyMinChild=PATHBOX_HEIGHT;
397     band_info.cxMinChild=0;
398     band_info.fMask|=RBBIM_TEXT;
399     band_info.lpText=pathbox_label;
400     band_info.fStyle|=RBBS_BREAK;
401     band_info.hwndChild=info->path_box;
402     SendMessageW(rebar,RB_INSERTBANDW,-1,(LPARAM)&band_info);
403     events = make_explorer_events(info);
404     IExplorerBrowser_Advise(info->browser,events,&cookie);
405     IExplorerBrowser_BrowseToObject(info->browser,(IUnknown*)startFolder,
406                                     SBSP_ABSOLUTE);
407     ShowWindow(info->main_window,SW_SHOWDEFAULT);
408     UpdateWindow(info->main_window);
409     IExplorerBrowserEvents_Release(events);
410 }
411
412 static void update_window_size(explorer_info *info, int height, int width)
413 {
414     RECT new_rect;
415     new_rect.left = 0;
416     new_rect.top = info->rebar_height;
417     new_rect.right = width;
418     new_rect.bottom = height;
419     IExplorerBrowser_SetRect(info->browser,NULL,new_rect);
420 }
421
422 static void do_exit(int code)
423 {
424     OleUninitialize();
425     ExitProcess(code);
426 }
427
428 static LRESULT explorer_on_end_edit(explorer_info *info,NMCBEENDEDITW *edit_info)
429 {
430     LPITEMIDLIST pidl = NULL;
431
432     WINE_TRACE("iWhy=%x\n",edit_info->iWhy);
433     switch(edit_info->iWhy)
434     {
435     case CBENF_DROPDOWN:
436         if(edit_info->iNewSelection!=CB_ERR)
437             pidl = (LPITEMIDLIST)SendMessageW(edit_info->hdr.hwndFrom,
438                                               CB_GETITEMDATA,
439                                               edit_info->iNewSelection,0);
440         break;
441     case CBENF_RETURN:
442         {
443             WCHAR path[MAX_PATH];
444             HWND edit_ctrl = (HWND)SendMessageW(edit_info->hdr.hwndFrom,
445                                                 CBEM_GETEDITCONTROL,0,0);
446             *((WORD*)path)=MAX_PATH;
447             SendMessageW(edit_ctrl,EM_GETLINE,0,(LPARAM)path);
448             pidl = ILCreateFromPathW(path);
449             break;
450         }
451     case CBENF_ESCAPE:
452         /*make sure the that the path box resets*/
453         update_path_box(info);
454         return 0;
455     default:
456         return 0;
457     }
458     if(pidl)
459         IExplorerBrowser_BrowseToIDList(info->browser,pidl,SBSP_ABSOLUTE);
460     if(edit_info->iWhy==CBENF_RETURN)
461         ILFree(pidl);
462     return 0;
463 }
464
465 static LRESULT update_rebar_size(explorer_info* info,NMRBAUTOSIZE *size_info)
466 {
467     RECT new_rect;
468     RECT window_rect;
469     info->rebar_height = size_info->rcTarget.bottom-size_info->rcTarget.top;
470     GetWindowRect(info->main_window,&window_rect);
471     new_rect.left = 0;
472     new_rect.top = info->rebar_height;
473     new_rect.right = window_rect.right-window_rect.left;
474     new_rect.bottom = window_rect.bottom-window_rect.top;
475     IExplorerBrowser_SetRect(info->browser,NULL,new_rect);
476     return 0;
477 }
478
479 static LRESULT explorer_on_notify(explorer_info* info,NMHDR* notification)
480 {
481     WINE_TRACE("code=%i\n",notification->code);
482     switch(notification->code)
483     {
484     case CBEN_BEGINEDIT:
485         {
486             WCHAR path[MAX_PATH];
487             HWND edit_ctrl = (HWND)SendMessageW(notification->hwndFrom,
488                                                 CBEM_GETEDITCONTROL,0,0);
489             SHGetPathFromIDListW(info->pidl,path);
490             SetWindowTextW(edit_ctrl,path);
491             break;
492         }
493     case CBEN_ENDEDITA:
494         {
495             NMCBEENDEDITA *edit_info_a = (NMCBEENDEDITA*)notification;
496             NMCBEENDEDITW edit_info_w;
497             edit_info_w.hdr = edit_info_a->hdr;
498             edit_info_w.fChanged = edit_info_a->fChanged;
499             edit_info_w.iNewSelection = edit_info_a->iNewSelection;
500             MultiByteToWideChar(CP_ACP,0,edit_info_a->szText,-1,
501                                 edit_info_w.szText,CBEMAXSTRLEN);
502             edit_info_w.iWhy = edit_info_a->iWhy;
503             return explorer_on_end_edit(info,&edit_info_w);
504         }
505     case CBEN_ENDEDITW:
506         return explorer_on_end_edit(info,(NMCBEENDEDITW*)notification);
507     case CBEN_DELETEITEM:
508         {
509             NMCOMBOBOXEXW *entry = (NMCOMBOBOXEXW*)notification;
510             if(entry->ceItem.lParam)
511                 ILFree((LPITEMIDLIST)entry->ceItem.lParam);
512             break;
513         }
514     case RBN_AUTOSIZE:
515         return update_rebar_size(info,(NMRBAUTOSIZE*)notification);
516     default:
517         break;
518     }
519     return 0;
520 }
521
522 static LRESULT CALLBACK explorer_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
523 {
524     explorer_info *info
525         = (explorer_info*)GetWindowLongPtrW(hwnd,EXPLORER_INFO_INDEX);
526     IExplorerBrowser *browser = NULL;
527
528     WINE_TRACE("(hwnd=%p,uMsg=%u,wParam=%lx,lParam=%lx)\n",hwnd,uMsg,wParam,lParam);
529     if(info)
530         browser = info->browser;
531     switch(uMsg)
532     {
533     case WM_DESTROY:
534         IExplorerBrowser_Release(browser);
535         HeapFree(GetProcessHeap(),0,info);
536         PostQuitMessage(0);
537         break;
538     case WM_QUIT:
539         do_exit(wParam);
540     case WM_NOTIFY:
541         return explorer_on_notify(info,(NMHDR*)lParam);
542     case WM_COMMAND:
543         if(HIWORD(wParam)==BN_CLICKED)
544         {
545             switch(LOWORD(wParam))
546             {
547             case BACK_BUTTON:
548                 IExplorerBrowser_BrowseToObject(browser,NULL,SBSP_NAVIGATEBACK);
549                 break;
550             case FORWARD_BUTTON:
551                 IExplorerBrowser_BrowseToObject(browser,NULL,SBSP_NAVIGATEFORWARD);
552                 break;
553             case UP_BUTTON:
554                 IExplorerBrowser_BrowseToObject(browser,NULL,SBSP_PARENT);
555                 break;
556             }
557         }
558         break;
559     case WM_SIZE:
560         update_window_size(info,HIWORD(lParam),LOWORD(lParam));
561         break;
562     default:
563         return DefWindowProcW(hwnd,uMsg,wParam,lParam);
564     }
565     return 0;
566 }
567
568 static void register_explorer_window_class(void)
569 {
570     WNDCLASSEXW window_class;
571     window_class.cbSize = sizeof(WNDCLASSEXW);
572     window_class.style = 0;
573     window_class.cbClsExtra = 0;
574     window_class.cbWndExtra = sizeof(LONG_PTR);
575     window_class.lpfnWndProc = explorer_wnd_proc;
576     window_class.hInstance = explorer_hInstance;
577     window_class.hIcon = NULL;
578     window_class.hCursor = NULL;
579     window_class.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
580     window_class.lpszMenuName = NULL;
581     window_class.lpszClassName = EXPLORER_CLASS;
582     window_class.hIconSm = NULL;
583     RegisterClassExW(&window_class);
584 }
585
586 static IShellFolder* get_starting_shell_folder(parameters_struct* params)
587 {
588     IShellFolder* desktop,*folder;
589     LPITEMIDLIST root_pidl;
590     HRESULT hres;
591
592     SHGetDesktopFolder(&desktop);
593     if (!params->root[0])
594     {
595         return desktop;
596     }
597     hres = IShellFolder_ParseDisplayName(desktop,NULL,NULL,
598                                          params->root,NULL,
599                                          &root_pidl,NULL);
600
601     if(FAILED(hres))
602     {
603         return desktop;
604     }
605     hres = IShellFolder_BindToObject(desktop,root_pidl,NULL,
606                                      &IID_IShellFolder,
607                                      (void**)&folder);
608     if(FAILED(hres))
609     {
610         return desktop;
611     }
612     IShellFolder_Release(desktop);
613     return folder;
614 }
615
616 static int copy_path_string(LPWSTR target, LPWSTR source)
617 {
618     INT i = 0;
619
620     while (isspaceW(*source)) source++;
621
622     if (*source == '\"')
623     {
624         source ++;
625         while (*source != '\"') target[i++] = *source++;
626         target[i] = 0;
627         source ++;
628         i+=2;
629     }
630     else
631     {
632         while (*source && !isspaceW(*source)) target[i++] = *source++;
633         target[i] = 0;
634     }
635     return i;
636 }
637
638
639 static void copy_path_root(LPWSTR root, LPWSTR path)
640 {
641     LPWSTR p,p2;
642     INT i = 0;
643
644     p = path;
645     while (*p!=0)
646         p++;
647
648     while (*p!='\\' && p > path)
649         p--;
650
651     if (p == path)
652         return;
653
654     p2 = path;
655     while (p2 != p)
656     {
657         root[i] = *p2;
658         i++;
659         p2++;
660     }
661     root[i] = 0;
662 }
663
664 /*
665  * Command Line parameters are:
666  * [/n]  Opens in single-paned view for each selected items. This is default
667  * [/e,] Uses Windows Explorer View
668  * [/root,object] Specifies the root level of the view
669  * [/select,object] parent folder is opened and specified object is selected
670  */
671 static void parse_command_line(LPWSTR commandline,parameters_struct *parameters)
672 {
673     static const WCHAR arg_n[] = {'/','n'};
674     static const WCHAR arg_e[] = {'/','e',','};
675     static const WCHAR arg_root[] = {'/','r','o','o','t',','};
676     static const WCHAR arg_select[] = {'/','s','e','l','e','c','t',','};
677     static const WCHAR arg_desktop[] = {'/','d','e','s','k','t','o','p'};
678
679     LPWSTR p, p2;
680
681     p2 = commandline;
682     p = strchrW(commandline,'/');
683     while(p)
684     {
685         if (strncmpW(p, arg_n, sizeof(arg_n)/sizeof(WCHAR))==0)
686         {
687             parameters->explorer_mode = FALSE;
688             p += sizeof(arg_n)/sizeof(WCHAR);
689         }
690         else if (strncmpW(p, arg_e, sizeof(arg_e)/sizeof(WCHAR))==0)
691         {
692             parameters->explorer_mode = TRUE;
693             p += sizeof(arg_e)/sizeof(WCHAR);
694         }
695         else if (strncmpW(p, arg_root, sizeof(arg_root)/sizeof(WCHAR))==0)
696         {
697             p += sizeof(arg_root)/sizeof(WCHAR);
698             p+=copy_path_string(parameters->root,p);
699         }
700         else if (strncmpW(p, arg_select, sizeof(arg_select)/sizeof(WCHAR))==0)
701         {
702             p += sizeof(arg_select)/sizeof(WCHAR);
703             p+=copy_path_string(parameters->selection,p);
704             if (!parameters->root[0])
705                 copy_path_root(parameters->root,
706                                parameters->selection);
707         }
708         else if (strncmpW(p, arg_desktop, sizeof(arg_desktop)/sizeof(WCHAR))==0)
709         {
710             p += sizeof(arg_desktop)/sizeof(WCHAR);
711             manage_desktop( p );  /* the rest of the command line is handled by desktop mode */
712         }
713         else p++;
714
715         p2 = p;
716         p = strchrW(p,'/');
717     }
718     if (p2 && *p2)
719     {
720         /* left over command line is generally the path to be opened */
721         copy_path_string(parameters->root,p2);
722     }
723 }
724
725 int WINAPI wWinMain(HINSTANCE hinstance,
726                     HINSTANCE previnstance,
727                     LPWSTR cmdline,
728                     int cmdshow)
729 {
730
731     parameters_struct   parameters;
732     HRESULT hres;
733     MSG msg;
734     IShellFolder *folder;
735     INITCOMMONCONTROLSEX init_info;
736
737     memset(&parameters,0,sizeof(parameters));
738     explorer_hInstance = hinstance;
739     parse_command_line(cmdline,&parameters);
740     hres = OleInitialize(NULL);
741     if(!SUCCEEDED(hres))
742     {
743         WINE_ERR("Could not initialize COM\n");
744         ExitProcess(EXIT_FAILURE);
745     }
746     init_info.dwSize = sizeof(INITCOMMONCONTROLSEX);
747     init_info.dwICC = ICC_USEREX_CLASSES | ICC_BAR_CLASSES | ICC_COOL_CLASSES;
748     if(!InitCommonControlsEx(&init_info))
749     {
750         WINE_ERR("Could not initialize Comctl\n");
751         ExitProcess(EXIT_FAILURE);
752     }
753     register_explorer_window_class();
754     folder = get_starting_shell_folder(&parameters);
755     make_explorer_window(folder);
756     IShellFolder_Release(folder);
757     while(GetMessageW( &msg, NULL, 0, 0 ) != 0)
758     {
759             TranslateMessage(&msg);
760             DispatchMessageW(&msg);
761     }
762     return 0;
763 }