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