explorer: Fix command-line parameter parsing.
[wine.git] / programs / explorer / explorer.c
blob26f3c8d6d9c95bcb1f64d681c9813f1b60a9e309
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
25 #include "wine/debug.h"
26 #include "explorer_private.h"
27 #include "resource.h"
29 #include <initguid.h>
30 #include <windows.h>
31 #include <shellapi.h>
32 #include <shobjidl.h>
33 #include <shlobj.h>
34 #include <shlwapi.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
44 static int nav_toolbar_height;
45 static int pathbox_height;
47 #define DEFAULT_WIDTH 640
48 #define DEFAULT_HEIGHT 480
49 static int default_width;
50 static int default_height;
53 HINSTANCE explorer_hInstance;
55 typedef struct parametersTAG {
56 BOOL explorer_mode;
57 WCHAR root[MAX_PATH];
58 WCHAR selection[MAX_PATH];
59 } parameters_struct;
61 typedef struct
63 IExplorerBrowser *browser;
64 HWND main_window,path_box;
65 INT rebar_height;
66 LPITEMIDLIST pidl;
67 IImageList *icon_list;
68 DWORD advise_cookie;
70 IShellWindows *sw;
71 LONG sw_cookie;
72 } explorer_info;
74 enum
76 BACK_BUTTON,FORWARD_BUTTON,UP_BUTTON
79 static void variant_from_pidl(VARIANT *var, const ITEMIDLIST *pidl)
81 V_VT(var) = VT_ARRAY | VT_UI1;
82 V_ARRAY(var) = SafeArrayCreateVector(VT_UI1, 0, ILGetSize(pidl));
83 memcpy(V_ARRAY(var)->pvData, pidl, ILGetSize(pidl));
86 typedef struct
88 IExplorerBrowserEvents IExplorerBrowserEvents_iface;
89 explorer_info* info;
90 LONG ref;
91 } IExplorerBrowserEventsImpl;
93 static IExplorerBrowserEventsImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
95 return CONTAINING_RECORD(iface, IExplorerBrowserEventsImpl, IExplorerBrowserEvents_iface);
98 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnQueryInterface(IExplorerBrowserEvents *iface, REFIID riid, void **ppvObject)
100 return E_NOINTERFACE;
103 static ULONG WINAPI IExplorerBrowserEventsImpl_fnAddRef(IExplorerBrowserEvents *iface)
105 IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
106 return InterlockedIncrement(&This->ref);
109 static ULONG WINAPI IExplorerBrowserEventsImpl_fnRelease(IExplorerBrowserEvents *iface)
111 IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
112 ULONG ref = InterlockedDecrement(&This->ref);
113 if(!ref) free(This);
114 return ref;
117 static BOOL create_combobox_item(IShellFolder *folder, LPCITEMIDLIST child_pidl, IImageList *icon_list, COMBOBOXEXITEMW *item)
119 STRRET strret;
120 HRESULT hres;
121 PIDLIST_ABSOLUTE parent_pidl, pidl;
122 SHFILEINFOW info;
123 IImageList *list;
125 strret.uType=STRRET_WSTR;
126 hres = IShellFolder_GetDisplayNameOf( folder, child_pidl, SHGDN_FORADDRESSBAR, &strret );
127 if(SUCCEEDED(hres))
128 hres = StrRetToStrW(&strret, child_pidl, &item->pszText);
129 if(FAILED(hres))
131 WARN( "Could not get name for pidl\n" );
132 return FALSE;
135 item->mask &= ~CBEIF_IMAGE;
136 hres = SHGetIDListFromObject( (IUnknown *)folder, &parent_pidl );
137 if (FAILED(hres)) return FALSE;
139 pidl = ILCombine( parent_pidl, child_pidl );
140 if (pidl)
142 list = (IImageList *)SHGetFileInfoW( (WCHAR *)pidl, 0, &info, sizeof(info),
143 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_SYSICONINDEX );
144 if (list)
146 IImageList_Release( list );
147 item->iImage = info.iIcon;
148 item->mask |= CBEIF_IMAGE;
150 ILFree( pidl );
152 ILFree( parent_pidl );
154 return TRUE;
157 static void update_path_box(explorer_info *info)
159 COMBOBOXEXITEMW item;
160 COMBOBOXEXITEMW main_item;
161 IShellFolder *desktop;
162 IPersistFolder2 *persist;
163 LPITEMIDLIST desktop_pidl;
164 IEnumIDList *ids;
166 SendMessageW(info->path_box,CB_RESETCONTENT,0,0);
167 SHGetDesktopFolder(&desktop);
168 IShellFolder_QueryInterface(desktop,&IID_IPersistFolder2,(void**)&persist);
169 IPersistFolder2_GetCurFolder(persist,&desktop_pidl);
170 IPersistFolder2_Release(persist);
171 persist = NULL;
172 /*Add Desktop*/
173 item.iItem = -1;
174 item.mask = CBEIF_TEXT | CBEIF_INDENT | CBEIF_LPARAM;
175 item.iIndent = 0;
176 create_combobox_item(desktop,desktop_pidl,info->icon_list,&item);
177 item.lParam = (LPARAM)desktop_pidl;
178 SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item);
179 if(ILIsEqual(info->pidl,desktop_pidl))
180 main_item = item;
181 else
182 CoTaskMemFree(item.pszText);
183 /*Add all direct subfolders of Desktop*/
184 if(SUCCEEDED(IShellFolder_EnumObjects(desktop,NULL,SHCONTF_FOLDERS,&ids))
185 && ids!=NULL)
187 LPITEMIDLIST curr_pidl=NULL;
188 HRESULT hres;
190 item.iIndent = 1;
191 while(1)
193 ILFree(curr_pidl);
194 curr_pidl=NULL;
195 hres = IEnumIDList_Next(ids,1,&curr_pidl,NULL);
196 if(FAILED(hres) || hres == S_FALSE)
197 break;
198 if (!create_combobox_item( desktop, curr_pidl, info->icon_list, &item ))
199 WARN( "Could not create a combobox item\n" );
200 else
202 LPITEMIDLIST full_pidl = ILCombine(desktop_pidl,curr_pidl);
203 item.lParam = (LPARAM)full_pidl;
204 SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item);
205 if(ILIsEqual(full_pidl,info->pidl))
206 main_item = item;
207 else if(ILIsParent(full_pidl,info->pidl,FALSE))
209 /*add all parents of the pidl passed in*/
210 LPITEMIDLIST next_pidl = ILFindChild(full_pidl,info->pidl);
211 IShellFolder *curr_folder = NULL, *temp;
212 hres = IShellFolder_BindToObject(desktop,curr_pidl,NULL,
213 &IID_IShellFolder,
214 (void**)&curr_folder);
215 if (FAILED(hres)) WARN( "Could not get an IShellFolder\n" );
216 while(!ILIsEmpty(next_pidl))
218 LPITEMIDLIST first = ILCloneFirst(next_pidl);
219 CoTaskMemFree(item.pszText);
220 if(!create_combobox_item(curr_folder,first,
221 info->icon_list,&item))
223 WARN( "Could not create a combobox item\n" );
224 break;
226 ++item.iIndent;
227 full_pidl = ILCombine(full_pidl,first);
228 item.lParam = (LPARAM)full_pidl;
229 SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item);
230 temp=NULL;
231 hres = IShellFolder_BindToObject(curr_folder,first,NULL,
232 &IID_IShellFolder,
233 (void**)&temp);
234 if(FAILED(hres))
236 WARN( "Could not get an IShellFolder\n" );
237 break;
239 IShellFolder_Release(curr_folder);
240 curr_folder = temp;
242 ILFree(first);
243 next_pidl = ILGetNext(next_pidl);
245 memcpy(&main_item,&item,sizeof(item));
246 if(curr_folder)
247 IShellFolder_Release(curr_folder);
248 item.iIndent = 1;
250 else
251 CoTaskMemFree(item.pszText);
254 ILFree(curr_pidl);
255 IEnumIDList_Release(ids);
257 else WARN( "Could not enumerate the desktop\n" );
258 SendMessageW(info->path_box,CBEM_SETITEMW,0,(LPARAM)&main_item);
259 CoTaskMemFree(main_item.pszText);
262 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnNavigationComplete(IExplorerBrowserEvents *iface, PCIDLIST_ABSOLUTE pidl)
264 IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
265 IShellFolder *parent;
266 PCUITEMID_CHILD child_pidl;
267 HRESULT hres;
268 STRRET strret;
269 WCHAR *name;
271 if (This->info->sw)
273 VARIANT var;
275 variant_from_pidl(&var, pidl);
276 IShellWindows_OnNavigate(This->info->sw, This->info->sw_cookie, &var);
277 VariantClear(&var);
280 ILFree(This->info->pidl);
281 This->info->pidl = ILClone(pidl);
282 update_path_box(This->info);
284 hres = SHBindToParent(pidl, &IID_IShellFolder, (void **)&parent, &child_pidl);
285 if (SUCCEEDED(hres))
287 hres = IShellFolder_GetDisplayNameOf(parent, child_pidl, SHGDN_FORADDRESSBAR, &strret);
288 if (SUCCEEDED(hres))
289 hres = StrRetToStrW(&strret, child_pidl, &name);
290 if (SUCCEEDED(hres))
292 SetWindowTextW(This->info->main_window, name);
293 CoTaskMemFree(name);
296 IShellFolder_Release(parent);
299 return hres;
302 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnNavigationFailed(IExplorerBrowserEvents *iface, PCIDLIST_ABSOLUTE pidl)
304 return S_OK;
307 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnNavigationPending(IExplorerBrowserEvents *iface, PCIDLIST_ABSOLUTE pidl)
309 return S_OK;
312 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnViewCreated(IExplorerBrowserEvents *iface, IShellView *psv)
314 return S_OK;
317 static IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents =
319 IExplorerBrowserEventsImpl_fnQueryInterface,
320 IExplorerBrowserEventsImpl_fnAddRef,
321 IExplorerBrowserEventsImpl_fnRelease,
322 IExplorerBrowserEventsImpl_fnOnNavigationPending,
323 IExplorerBrowserEventsImpl_fnOnViewCreated,
324 IExplorerBrowserEventsImpl_fnOnNavigationComplete,
325 IExplorerBrowserEventsImpl_fnOnNavigationFailed
328 static IExplorerBrowserEvents *make_explorer_events(explorer_info *info)
330 IExplorerBrowserEventsImpl *ret = malloc( sizeof(IExplorerBrowserEventsImpl) );
331 ret->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents;
332 ret->info = info;
333 ret->ref = 1;
334 SHGetImageList(SHIL_SMALL,&IID_IImageList,(void**)&(ret->info->icon_list));
335 SendMessageW(info->path_box,CBEM_SETIMAGELIST,0,(LPARAM)ret->info->icon_list);
336 return &ret->IExplorerBrowserEvents_iface;
339 static IShellFolder *get_starting_shell_folder(WCHAR *path)
341 IShellFolder* desktop,*folder;
342 LPITEMIDLIST root_pidl;
343 HRESULT hres;
345 SHGetDesktopFolder(&desktop);
347 if (!path)
348 return desktop;
350 hres = IShellFolder_ParseDisplayName(desktop, NULL, NULL, path, NULL, &root_pidl, NULL);
351 if(FAILED(hres))
353 return desktop;
355 hres = IShellFolder_BindToObject(desktop,root_pidl,NULL,
356 &IID_IShellFolder,
357 (void**)&folder);
358 ILFree(root_pidl);
359 if(FAILED(hres))
361 return desktop;
363 IShellFolder_Release(desktop);
364 return folder;
367 static void make_explorer_window(parameters_struct *params)
369 RECT rect;
370 HWND rebar,nav_toolbar;
371 FOLDERSETTINGS fs;
372 IExplorerBrowserEvents *events;
373 explorer_info *info;
374 HRESULT hres;
375 WCHAR explorer_title[100];
376 WCHAR pathbox_label[50];
377 TBADDBITMAP bitmap_info;
378 TBBUTTON nav_buttons[3];
379 int hist_offset,view_offset;
380 REBARBANDINFOW band_info;
381 VARIANT var, empty_var;
382 IShellFolder *folder;
383 IDispatch *dispatch;
384 WCHAR *path = NULL;
385 IShellWindows *sw;
386 ITEMIDLIST *pidl;
387 UINT dpix, dpiy;
388 DWORD size;
389 LONG hwnd;
390 HDC hdc;
391 MSG msg;
393 CoCreateInstance(&CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER,
394 &IID_IShellWindows, (void **)&sw);
396 if (params->root[0])
398 size = GetFullPathNameW(params->root, 0, NULL, NULL);
399 path = malloc( size * sizeof(WCHAR) );
400 GetFullPathNameW(params->root, size, path, NULL);
403 if (sw && path)
405 if (!(pidl = ILCreateFromPathW(path)))
407 ERR("Failed to create PIDL for %s.\n", debugstr_w(path));
408 IShellWindows_Release(sw);
409 free(path);
410 return;
413 variant_from_pidl(&var, pidl);
414 V_VT(&empty_var) = VT_EMPTY;
415 hres = IShellWindows_FindWindowSW(sw, &var, &empty_var, SWC_EXPLORER, &hwnd, 0, &dispatch);
416 VariantClear(&var);
417 ILFree(pidl);
418 if (hres == S_OK)
420 TRACE("Found window %#lx already browsing path %s.\n", hwnd, debugstr_w(path));
421 SetForegroundWindow((HWND)(LONG_PTR)hwnd);
422 IShellWindows_Release(sw);
423 free(path);
424 return;
428 memset(nav_buttons,0,sizeof(nav_buttons));
430 LoadStringW(explorer_hInstance,IDS_EXPLORER_TITLE,explorer_title, ARRAY_SIZE( explorer_title ));
431 LoadStringW(explorer_hInstance,IDS_PATHBOX_LABEL,pathbox_label, ARRAY_SIZE( pathbox_label ));
433 hdc = GetDC(0);
434 dpix = GetDeviceCaps(hdc, LOGPIXELSX);
435 dpiy = GetDeviceCaps(hdc, LOGPIXELSY);
436 ReleaseDC(0, hdc);
437 nav_toolbar_height = MulDiv(NAV_TOOLBAR_HEIGHT, dpiy, USER_DEFAULT_SCREEN_DPI);
438 pathbox_height = MulDiv(PATHBOX_HEIGHT, dpiy, USER_DEFAULT_SCREEN_DPI);
439 default_width = MulDiv(DEFAULT_WIDTH, dpix, USER_DEFAULT_SCREEN_DPI);
440 default_height = MulDiv(DEFAULT_HEIGHT, dpiy, USER_DEFAULT_SCREEN_DPI);
442 info = calloc( 1, sizeof(explorer_info) );
443 if(!info)
445 ERR( "Could not allocate an explorer_info struct\n" );
446 IShellWindows_Release(sw);
447 free(path);
448 return;
450 hres = CoCreateInstance(&CLSID_ExplorerBrowser,NULL,CLSCTX_INPROC_SERVER,
451 &IID_IExplorerBrowser,(LPVOID*)&info->browser);
452 if(FAILED(hres))
454 ERR( "Could not obtain an instance of IExplorerBrowser\n" );
455 free(info);
456 IShellWindows_Release(sw);
457 free(path);
458 return;
460 info->rebar_height=0;
461 info->main_window
462 = CreateWindowW(L"ExplorerWClass",explorer_title,WS_OVERLAPPEDWINDOW,
463 CW_USEDEFAULT,CW_USEDEFAULT,default_width,
464 default_height,NULL,NULL,explorer_hInstance,NULL);
466 if (sw)
468 IShellWindows_Register(sw, NULL, (LONG_PTR)info->main_window, SWC_EXPLORER, &info->sw_cookie);
469 info->sw = sw;
472 fs.ViewMode = FVM_DETAILS;
473 fs.fFlags = FWF_AUTOARRANGE;
475 SetRect(&rect, 0, 0, default_width, default_height);
476 IExplorerBrowser_Initialize(info->browser,info->main_window,&rect,&fs);
477 IExplorerBrowser_SetOptions(info->browser,EBO_SHOWFRAMES);
478 SetWindowLongPtrW(info->main_window,EXPLORER_INFO_INDEX,(LONG_PTR)info);
480 /*setup navbar*/
481 rebar = CreateWindowExW(WS_EX_TOOLWINDOW,REBARCLASSNAMEW,NULL,
482 WS_CHILD|WS_VISIBLE|RBS_VARHEIGHT|CCS_TOP|CCS_NODIVIDER,
483 0,0,0,0,info->main_window,NULL,explorer_hInstance,NULL);
484 nav_toolbar
485 = CreateWindowExW(TBSTYLE_EX_MIXEDBUTTONS,TOOLBARCLASSNAMEW,NULL,
486 WS_CHILD|WS_VISIBLE|TBSTYLE_FLAT,0,0,0,0,rebar,NULL,
487 explorer_hInstance,NULL);
489 bitmap_info.hInst = HINST_COMMCTRL;
490 bitmap_info.nID = IDB_HIST_LARGE_COLOR;
491 hist_offset= SendMessageW(nav_toolbar,TB_ADDBITMAP,0,(LPARAM)&bitmap_info);
492 bitmap_info.nID = IDB_VIEW_LARGE_COLOR;
493 view_offset= SendMessageW(nav_toolbar,TB_ADDBITMAP,0,(LPARAM)&bitmap_info);
495 nav_buttons[0].iBitmap=hist_offset+HIST_BACK;
496 nav_buttons[0].idCommand=BACK_BUTTON;
497 nav_buttons[0].fsState=TBSTATE_ENABLED;
498 nav_buttons[0].fsStyle=BTNS_BUTTON|BTNS_AUTOSIZE;
499 nav_buttons[1].iBitmap=hist_offset+HIST_FORWARD;
500 nav_buttons[1].idCommand=FORWARD_BUTTON;
501 nav_buttons[1].fsState=TBSTATE_ENABLED;
502 nav_buttons[1].fsStyle=BTNS_BUTTON|BTNS_AUTOSIZE;
503 nav_buttons[2].iBitmap=view_offset+VIEW_PARENTFOLDER;
504 nav_buttons[2].idCommand=UP_BUTTON;
505 nav_buttons[2].fsState=TBSTATE_ENABLED;
506 nav_buttons[2].fsStyle=BTNS_BUTTON|BTNS_AUTOSIZE;
507 SendMessageW(nav_toolbar,TB_BUTTONSTRUCTSIZE,sizeof(TBBUTTON),0);
508 SendMessageW(nav_toolbar,TB_ADDBUTTONSW,ARRAY_SIZE( nav_buttons ),(LPARAM)nav_buttons);
510 band_info.cbSize = sizeof(band_info);
511 band_info.fMask = RBBIM_STYLE|RBBIM_CHILD|RBBIM_CHILDSIZE|RBBIM_SIZE;
512 band_info.hwndChild = nav_toolbar;
513 band_info.fStyle=RBBS_GRIPPERALWAYS|RBBS_CHILDEDGE;
514 band_info.cyChild=nav_toolbar_height;
515 band_info.cx=0;
516 band_info.cyMinChild=nav_toolbar_height;
517 band_info.cxMinChild=0;
518 SendMessageW(rebar,RB_INSERTBANDW,-1,(LPARAM)&band_info);
519 info->path_box = CreateWindowW(WC_COMBOBOXEXW,L"",
520 WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
521 0,0,default_width,pathbox_height,rebar,NULL,
522 explorer_hInstance,NULL);
523 GetWindowRect(info->path_box, &rect);
524 band_info.cyChild = rect.bottom - rect.top;
525 band_info.cx=0;
526 band_info.cyMinChild = rect.bottom - rect.top;
527 band_info.cxMinChild=0;
528 band_info.fMask|=RBBIM_TEXT;
529 band_info.lpText=pathbox_label;
530 band_info.fStyle|=RBBS_BREAK;
531 band_info.hwndChild=info->path_box;
532 SendMessageW(rebar,RB_INSERTBANDW,-1,(LPARAM)&band_info);
533 events = make_explorer_events(info);
534 IExplorerBrowser_Advise(info->browser,events,&info->advise_cookie);
536 folder = get_starting_shell_folder(path);
537 IExplorerBrowser_BrowseToObject(info->browser, (IUnknown *)folder, SBSP_ABSOLUTE);
538 IShellFolder_Release(folder);
539 free(path);
541 ShowWindow(info->main_window,SW_SHOWDEFAULT);
542 UpdateWindow(info->main_window);
543 IExplorerBrowserEvents_Release(events);
545 while (GetMessageW(&msg, NULL, 0, 0))
547 TranslateMessage(&msg);
548 DispatchMessageW(&msg);
552 static void update_window_size(explorer_info *info, int height, int width)
554 RECT new_rect;
555 new_rect.left = 0;
556 new_rect.top = info->rebar_height;
557 new_rect.right = width;
558 new_rect.bottom = height;
559 IExplorerBrowser_SetRect(info->browser,NULL,new_rect);
562 static void do_exit(int code)
564 OleUninitialize();
565 ExitProcess(code);
568 static LRESULT explorer_on_end_edit(explorer_info *info,NMCBEENDEDITW *edit_info)
570 LPITEMIDLIST pidl = NULL;
572 TRACE( "iWhy=%x\n", edit_info->iWhy );
573 switch(edit_info->iWhy)
575 case CBENF_DROPDOWN:
576 if(edit_info->iNewSelection!=CB_ERR)
577 pidl = (LPITEMIDLIST)SendMessageW(edit_info->hdr.hwndFrom,
578 CB_GETITEMDATA,
579 edit_info->iNewSelection,0);
580 break;
581 case CBENF_RETURN:
583 WCHAR path[MAX_PATH];
584 HWND edit_ctrl = (HWND)SendMessageW(edit_info->hdr.hwndFrom,
585 CBEM_GETEDITCONTROL,0,0);
586 *((WORD*)path)=MAX_PATH;
587 SendMessageW(edit_ctrl,EM_GETLINE,0,(LPARAM)path);
588 pidl = ILCreateFromPathW(path);
589 break;
591 case CBENF_ESCAPE:
592 /*make sure the that the path box resets*/
593 update_path_box(info);
594 return 0;
595 default:
596 return 0;
598 if(pidl)
599 IExplorerBrowser_BrowseToIDList(info->browser,pidl,SBSP_ABSOLUTE);
600 if(edit_info->iWhy==CBENF_RETURN)
601 ILFree(pidl);
602 return 0;
605 static LRESULT update_rebar_size(explorer_info* info,NMRBAUTOSIZE *size_info)
607 RECT new_rect;
608 RECT window_rect;
609 info->rebar_height = size_info->rcTarget.bottom-size_info->rcTarget.top;
610 GetWindowRect(info->main_window,&window_rect);
611 new_rect.left = 0;
612 new_rect.top = info->rebar_height;
613 new_rect.right = window_rect.right-window_rect.left;
614 new_rect.bottom = window_rect.bottom-window_rect.top;
615 IExplorerBrowser_SetRect(info->browser,NULL,new_rect);
616 return 0;
619 static LRESULT explorer_on_notify(explorer_info* info,NMHDR* notification)
621 TRACE( "code=%i\n", notification->code );
622 switch(notification->code)
624 case CBEN_BEGINEDIT:
626 WCHAR path[MAX_PATH];
627 HWND edit_ctrl = (HWND)SendMessageW(notification->hwndFrom,
628 CBEM_GETEDITCONTROL,0,0);
629 SHGetPathFromIDListW(info->pidl,path);
630 SetWindowTextW(edit_ctrl,path);
631 break;
633 case CBEN_ENDEDITA:
635 NMCBEENDEDITA *edit_info_a = (NMCBEENDEDITA*)notification;
636 NMCBEENDEDITW edit_info_w;
637 edit_info_w.hdr = edit_info_a->hdr;
638 edit_info_w.fChanged = edit_info_a->fChanged;
639 edit_info_w.iNewSelection = edit_info_a->iNewSelection;
640 MultiByteToWideChar(CP_ACP,0,edit_info_a->szText,-1,
641 edit_info_w.szText,CBEMAXSTRLEN);
642 edit_info_w.iWhy = edit_info_a->iWhy;
643 return explorer_on_end_edit(info,&edit_info_w);
645 case CBEN_ENDEDITW:
646 return explorer_on_end_edit(info,(NMCBEENDEDITW*)notification);
647 case CBEN_DELETEITEM:
649 NMCOMBOBOXEXW *entry = (NMCOMBOBOXEXW*)notification;
650 if(entry->ceItem.lParam)
651 ILFree((LPITEMIDLIST)entry->ceItem.lParam);
652 break;
654 case RBN_AUTOSIZE:
655 return update_rebar_size(info,(NMRBAUTOSIZE*)notification);
656 default:
657 break;
659 return 0;
662 static BOOL handle_copydata(const explorer_info *info, const COPYDATASTRUCT *cds)
664 static const unsigned int magic = 0xe32ee32e;
665 unsigned int i, flags, count;
666 const ITEMIDLIST *child;
667 unsigned char *ptr;
668 IShellView *sv;
669 SVSIF sv_flags;
671 TRACE("\n");
673 /* For SHOpenFolderAndSelectItems() */
674 if (cds->dwData != magic)
675 return FALSE;
677 ptr = cds->lpData;
678 memcpy(&count, ptr, sizeof(count));
679 ptr += sizeof(count);
680 memcpy(&flags, ptr, sizeof(flags));
681 ptr += sizeof(flags);
683 sv_flags = flags & OFASI_EDIT ? SVSI_EDIT : SVSI_SELECT;
685 IExplorerBrowser_GetCurrentView(info->browser, &IID_IShellView, (void **)&sv);
686 for (i = 0; i < count; ++i)
688 child = (const ITEMIDLIST *)ptr;
689 if (i == 0)
690 IShellView_SelectItem(sv, child, sv_flags | SVSI_ENSUREVISIBLE | SVSI_FOCUSED | SVSI_DESELECTOTHERS);
691 else
692 IShellView_SelectItem(sv, child, sv_flags);
693 ptr += ILGetSize(child);
695 IShellView_Release(sv);
696 return TRUE;
699 static LRESULT CALLBACK explorer_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
701 explorer_info *info
702 = (explorer_info*)GetWindowLongPtrW(hwnd,EXPLORER_INFO_INDEX);
703 IExplorerBrowser *browser = NULL;
705 TRACE( "(hwnd=%p,uMsg=%u,wParam=%Ix,lParam=%Ix)\n", hwnd, uMsg, wParam, lParam );
706 if(info)
707 browser = info->browser;
708 switch(uMsg)
710 case WM_DESTROY:
711 if(info->sw)
713 IShellWindows_Revoke(info->sw, info->sw_cookie);
714 IShellWindows_Release(info->sw);
717 IExplorerBrowser_Unadvise(browser,info->advise_cookie);
718 IExplorerBrowser_Destroy(browser);
719 IExplorerBrowser_Release(browser);
720 ILFree(info->pidl);
721 IImageList_Release(info->icon_list);
722 free(info);
723 SetWindowLongPtrW(hwnd,EXPLORER_INFO_INDEX,0);
724 PostQuitMessage(0);
725 break;
726 case WM_QUIT:
727 do_exit(wParam);
728 case WM_NOTIFY:
729 return explorer_on_notify(info,(NMHDR*)lParam);
730 case WM_COMMAND:
731 if(HIWORD(wParam)==BN_CLICKED)
733 switch(LOWORD(wParam))
735 case BACK_BUTTON:
736 IExplorerBrowser_BrowseToObject(browser,NULL,SBSP_NAVIGATEBACK);
737 break;
738 case FORWARD_BUTTON:
739 IExplorerBrowser_BrowseToObject(browser,NULL,SBSP_NAVIGATEFORWARD);
740 break;
741 case UP_BUTTON:
742 IExplorerBrowser_BrowseToObject(browser,NULL,SBSP_PARENT);
743 break;
746 break;
747 case WM_SIZE:
748 update_window_size(info,HIWORD(lParam),LOWORD(lParam));
749 break;
750 case WM_COPYDATA:
751 return handle_copydata(info, (const COPYDATASTRUCT *)lParam);
752 default:
753 return DefWindowProcW(hwnd,uMsg,wParam,lParam);
755 return 0;
758 static void register_explorer_window_class(void)
760 WNDCLASSEXW window_class;
761 window_class.cbSize = sizeof(WNDCLASSEXW);
762 window_class.style = 0;
763 window_class.cbClsExtra = 0;
764 window_class.cbWndExtra = sizeof(LONG_PTR);
765 window_class.lpfnWndProc = explorer_wnd_proc;
766 window_class.hInstance = explorer_hInstance;
767 window_class.hIcon = NULL;
768 window_class.hCursor = NULL;
769 window_class.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
770 window_class.lpszMenuName = NULL;
771 window_class.lpszClassName = L"ExplorerWClass";
772 window_class.hIconSm = NULL;
773 RegisterClassExW(&window_class);
776 static WCHAR *copy_path_string(WCHAR *target, WCHAR *source)
778 INT i = 0;
780 while (iswspace(*source)) source++;
782 if (*source == '\"')
784 source ++;
785 while (*source && *source != '\"') target[i++] = *source++;
786 target[i] = 0;
787 if (*source) source++;
789 else
791 while (*source && *source != ',') target[i++] = *source++;
792 target[i] = 0;
794 PathRemoveBackslashW(target);
795 return source;
799 static void copy_path_root(LPWSTR root, LPWSTR path)
801 LPWSTR p,p2;
802 INT i = 0;
804 p = path;
805 while (*p!=0)
806 p++;
808 while (*p!='\\' && p > path)
809 p--;
811 if (p == path)
812 return;
814 p2 = path;
815 while (p2 != p)
817 root[i] = *p2;
818 i++;
819 p2++;
821 root[i] = 0;
825 * Command Line parameters are:
826 * [/n] Opens in single-paned view for each selected items. This is default
827 * [/e,] Uses Windows Explorer View
828 * [/cd,object] Specifies the root level of the view
829 * [/root,object] Specifies the root level of the view
830 * [/select,object] parent folder is opened and specified object is selected
832 static void parse_command_line(LPWSTR commandline,parameters_struct *parameters)
834 static const WCHAR arg_n[] = L"/n";
835 static const WCHAR arg_e[] = L"/e,";
836 static const WCHAR arg_cd[] = L"/cd,";
837 static const WCHAR arg_root[] = L"/root,";
838 static const WCHAR arg_select[] = L"/select,";
839 static const WCHAR arg_desktop[] = L"/desktop";
840 static const WCHAR arg_desktop_quotes[] = L"\"/desktop";
841 const size_t len_n = wcslen(arg_n);
842 const size_t len_e = wcslen(arg_e);
843 const size_t len_cd = wcslen(arg_cd);
844 const size_t len_root = wcslen(arg_root);
845 const size_t len_select = wcslen(arg_select);
846 const size_t len_desktop = wcslen(arg_desktop);
847 const size_t len_desktop_quotes = wcslen(arg_desktop_quotes);
849 LPWSTR p = commandline;
851 while (*p)
853 while (iswspace(*p)) p++;
854 if (wcsncmp(p, arg_n, len_n )==0)
856 parameters->explorer_mode = FALSE;
857 p += len_n;
859 else if (wcsncmp(p, arg_e, len_e )==0)
861 parameters->explorer_mode = TRUE;
862 p += len_e;
864 else if (wcsncmp(p, arg_cd, len_cd )==0)
866 p += len_cd;
867 p = copy_path_string(parameters->root,p);
869 else if (wcsncmp(p, arg_root, len_root )==0)
871 p += len_root;
872 p = copy_path_string(parameters->root,p);
874 else if (wcsncmp(p, arg_select, len_select )==0)
876 p += len_select;
877 p = copy_path_string(parameters->selection,p);
878 if (!parameters->root[0])
879 copy_path_root(parameters->root,
880 parameters->selection);
882 else if (wcsncmp(p, arg_desktop, len_desktop )==0)
884 p += len_desktop;
885 manage_desktop( p ); /* the rest of the command line is handled by desktop mode */
887 /* workaround for Worms Armageddon that hardcodes a /desktop option with quotes */
888 else if (wcsncmp(p, arg_desktop_quotes, len_desktop_quotes )==0)
890 p += len_desktop_quotes;
891 manage_desktop( p ); /* the rest of the command line is handled by desktop mode */
893 else
895 /* left over command line is generally the path to be opened */
896 copy_path_string(parameters->root,p);
897 break;
902 int WINAPI wWinMain(HINSTANCE hinstance,
903 HINSTANCE previnstance,
904 LPWSTR cmdline,
905 int cmdshow)
908 parameters_struct parameters;
909 HRESULT hres;
910 INITCOMMONCONTROLSEX init_info;
912 memset(&parameters,0,sizeof(parameters));
913 explorer_hInstance = hinstance;
914 parse_command_line(cmdline,&parameters);
915 hres = OleInitialize(NULL);
916 if(FAILED(hres))
918 ERR( "Could not initialize COM\n" );
919 ExitProcess(EXIT_FAILURE);
921 if(parameters.root[0] && !PathIsDirectoryW(parameters.root))
922 if(ShellExecuteW(NULL,NULL,parameters.root,NULL,NULL,SW_SHOWDEFAULT) > (HINSTANCE)32)
923 ExitProcess(EXIT_SUCCESS);
924 init_info.dwSize = sizeof(INITCOMMONCONTROLSEX);
925 init_info.dwICC = ICC_USEREX_CLASSES | ICC_BAR_CLASSES | ICC_COOL_CLASSES;
926 if(!InitCommonControlsEx(&init_info))
928 ERR( "Could not initialize Comctl\n" );
929 ExitProcess(EXIT_FAILURE);
931 register_explorer_window_class();
932 make_explorer_window(&parameters);
933 return 0;