gdiplus/metafile: Implement DrawArc() recording.
[wine/zf.git] / programs / explorer / explorer.c
blob43bd4ef13a851260368223e5fbe03cdf95dd0036
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 "wine/heap.h"
27 #include "explorer_private.h"
28 #include "resource.h"
30 #include <initguid.h>
31 #include <windows.h>
32 #include <shellapi.h>
33 #include <shobjidl.h>
34 #include <shlobj.h>
35 #include <shlwapi.h>
36 #include <commoncontrols.h>
37 #include <commctrl.h>
39 WINE_DEFAULT_DEBUG_CHANNEL(explorer);
41 #define EXPLORER_INFO_INDEX 0
43 #define NAV_TOOLBAR_HEIGHT 30
44 #define PATHBOX_HEIGHT 24
45 static int nav_toolbar_height;
46 static int pathbox_height;
48 #define DEFAULT_WIDTH 640
49 #define DEFAULT_HEIGHT 480
50 static int default_width;
51 static int default_height;
54 static const WCHAR EXPLORER_CLASS[] = {'E','x','p','l','o','r','e','r','W','C','l','a','s','s',0};
55 static const WCHAR PATH_BOX_NAME[] = {'\0'};
57 HINSTANCE explorer_hInstance;
59 typedef struct parametersTAG {
60 BOOL explorer_mode;
61 WCHAR root[MAX_PATH];
62 WCHAR selection[MAX_PATH];
63 } parameters_struct;
65 typedef struct
67 IExplorerBrowser *browser;
68 HWND main_window,path_box;
69 INT rebar_height;
70 LPITEMIDLIST pidl;
71 IImageList *icon_list;
72 DWORD advise_cookie;
74 IShellWindows *sw;
75 LONG sw_cookie;
76 } explorer_info;
78 enum
80 BACK_BUTTON,FORWARD_BUTTON,UP_BUTTON
83 static void variant_from_pidl(VARIANT *var, const ITEMIDLIST *pidl)
85 V_VT(var) = VT_ARRAY | VT_UI1;
86 V_ARRAY(var) = SafeArrayCreateVector(VT_UI1, 0, ILGetSize(pidl));
87 memcpy(V_ARRAY(var)->pvData, pidl, ILGetSize(pidl));
90 typedef struct
92 IExplorerBrowserEvents IExplorerBrowserEvents_iface;
93 explorer_info* info;
94 LONG ref;
95 } IExplorerBrowserEventsImpl;
97 static IExplorerBrowserEventsImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
99 return CONTAINING_RECORD(iface, IExplorerBrowserEventsImpl, IExplorerBrowserEvents_iface);
102 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnQueryInterface(IExplorerBrowserEvents *iface, REFIID riid, void **ppvObject)
104 return E_NOINTERFACE;
107 static ULONG WINAPI IExplorerBrowserEventsImpl_fnAddRef(IExplorerBrowserEvents *iface)
109 IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
110 return InterlockedIncrement(&This->ref);
113 static ULONG WINAPI IExplorerBrowserEventsImpl_fnRelease(IExplorerBrowserEvents *iface)
115 IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
116 ULONG ref = InterlockedDecrement(&This->ref);
117 if(!ref)
118 HeapFree(GetProcessHeap(),0,This);
119 return ref;
122 static BOOL create_combobox_item(IShellFolder *folder, LPCITEMIDLIST child_pidl, IImageList *icon_list, COMBOBOXEXITEMW *item)
124 STRRET strret;
125 HRESULT hres;
126 PIDLIST_ABSOLUTE parent_pidl, pidl;
127 SHFILEINFOW info;
128 IImageList *list;
130 strret.uType=STRRET_WSTR;
131 hres = IShellFolder_GetDisplayNameOf( folder, child_pidl, SHGDN_FORADDRESSBAR, &strret );
132 if(SUCCEEDED(hres))
133 hres = StrRetToStrW(&strret, child_pidl, &item->pszText);
134 if(FAILED(hres))
136 WINE_WARN("Could not get name for pidl\n");
137 return FALSE;
140 item->mask &= ~CBEIF_IMAGE;
141 hres = SHGetIDListFromObject( (IUnknown *)folder, &parent_pidl );
142 if (FAILED(hres)) return FALSE;
144 pidl = ILCombine( parent_pidl, child_pidl );
145 if (pidl)
147 list = (IImageList *)SHGetFileInfoW( (WCHAR *)pidl, 0, &info, sizeof(info),
148 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_SYSICONINDEX );
149 if (list)
151 IImageList_Release( list );
152 item->iImage = info.iIcon;
153 item->mask |= CBEIF_IMAGE;
155 ILFree( pidl );
157 ILFree( parent_pidl );
159 return TRUE;
162 static void update_path_box(explorer_info *info)
164 COMBOBOXEXITEMW item;
165 COMBOBOXEXITEMW main_item;
166 IShellFolder *desktop;
167 IPersistFolder2 *persist;
168 LPITEMIDLIST desktop_pidl;
169 IEnumIDList *ids;
171 SendMessageW(info->path_box,CB_RESETCONTENT,0,0);
172 SHGetDesktopFolder(&desktop);
173 IShellFolder_QueryInterface(desktop,&IID_IPersistFolder2,(void**)&persist);
174 IPersistFolder2_GetCurFolder(persist,&desktop_pidl);
175 IPersistFolder2_Release(persist);
176 persist = NULL;
177 /*Add Desktop*/
178 item.iItem = -1;
179 item.mask = CBEIF_TEXT | CBEIF_INDENT | CBEIF_LPARAM;
180 item.iIndent = 0;
181 create_combobox_item(desktop,desktop_pidl,info->icon_list,&item);
182 item.lParam = (LPARAM)desktop_pidl;
183 SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item);
184 if(ILIsEqual(info->pidl,desktop_pidl))
185 main_item = item;
186 else
187 CoTaskMemFree(item.pszText);
188 /*Add all direct subfolders of Desktop*/
189 if(SUCCEEDED(IShellFolder_EnumObjects(desktop,NULL,SHCONTF_FOLDERS,&ids))
190 && ids!=NULL)
192 LPITEMIDLIST curr_pidl=NULL;
193 HRESULT hres;
195 item.iIndent = 1;
196 while(1)
198 ILFree(curr_pidl);
199 curr_pidl=NULL;
200 hres = IEnumIDList_Next(ids,1,&curr_pidl,NULL);
201 if(FAILED(hres) || hres == S_FALSE)
202 break;
203 if(!create_combobox_item(desktop,curr_pidl,info->icon_list,&item))
204 WINE_WARN("Could not create a combobox item\n");
205 else
207 LPITEMIDLIST full_pidl = ILCombine(desktop_pidl,curr_pidl);
208 item.lParam = (LPARAM)full_pidl;
209 SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item);
210 if(ILIsEqual(full_pidl,info->pidl))
211 main_item = item;
212 else if(ILIsParent(full_pidl,info->pidl,FALSE))
214 /*add all parents of the pidl passed in*/
215 LPITEMIDLIST next_pidl = ILFindChild(full_pidl,info->pidl);
216 IShellFolder *curr_folder = NULL, *temp;
217 hres = IShellFolder_BindToObject(desktop,curr_pidl,NULL,
218 &IID_IShellFolder,
219 (void**)&curr_folder);
220 if(FAILED(hres))
221 WINE_WARN("Could not get an IShellFolder\n");
222 while(!ILIsEmpty(next_pidl))
224 LPITEMIDLIST first = ILCloneFirst(next_pidl);
225 CoTaskMemFree(item.pszText);
226 if(!create_combobox_item(curr_folder,first,
227 info->icon_list,&item))
229 WINE_WARN("Could not create a combobox item\n");
230 break;
232 ++item.iIndent;
233 full_pidl = ILCombine(full_pidl,first);
234 item.lParam = (LPARAM)full_pidl;
235 SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item);
236 temp=NULL;
237 hres = IShellFolder_BindToObject(curr_folder,first,NULL,
238 &IID_IShellFolder,
239 (void**)&temp);
240 if(FAILED(hres))
242 WINE_WARN("Could not get an IShellFolder\n");
243 break;
245 IShellFolder_Release(curr_folder);
246 curr_folder = temp;
248 ILFree(first);
249 next_pidl = ILGetNext(next_pidl);
251 memcpy(&main_item,&item,sizeof(item));
252 if(curr_folder)
253 IShellFolder_Release(curr_folder);
254 item.iIndent = 1;
256 else
257 CoTaskMemFree(item.pszText);
260 ILFree(curr_pidl);
261 IEnumIDList_Release(ids);
263 else
264 WINE_WARN("Could not enumerate the desktop\n");
265 SendMessageW(info->path_box,CBEM_SETITEMW,0,(LPARAM)&main_item);
266 CoTaskMemFree(main_item.pszText);
269 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnNavigationComplete(IExplorerBrowserEvents *iface, PCIDLIST_ABSOLUTE pidl)
271 IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
272 IShellFolder *parent;
273 PCUITEMID_CHILD child_pidl;
274 HRESULT hres;
275 STRRET strret;
276 WCHAR *name;
278 if (This->info->sw)
280 VARIANT var;
282 variant_from_pidl(&var, pidl);
283 IShellWindows_OnNavigate(This->info->sw, This->info->sw_cookie, &var);
284 VariantClear(&var);
287 ILFree(This->info->pidl);
288 This->info->pidl = ILClone(pidl);
289 update_path_box(This->info);
291 hres = SHBindToParent(pidl, &IID_IShellFolder, (void **)&parent, &child_pidl);
292 if (SUCCEEDED(hres))
294 hres = IShellFolder_GetDisplayNameOf(parent, child_pidl, SHGDN_FORADDRESSBAR, &strret);
295 if (SUCCEEDED(hres))
296 hres = StrRetToStrW(&strret, child_pidl, &name);
297 if (SUCCEEDED(hres))
299 SetWindowTextW(This->info->main_window, name);
300 CoTaskMemFree(name);
303 IShellFolder_Release(parent);
306 return hres;
309 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnNavigationFailed(IExplorerBrowserEvents *iface, PCIDLIST_ABSOLUTE pidl)
311 return S_OK;
314 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnNavigationPending(IExplorerBrowserEvents *iface, PCIDLIST_ABSOLUTE pidl)
316 return S_OK;
319 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnViewCreated(IExplorerBrowserEvents *iface, IShellView *psv)
321 return S_OK;
324 static IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents =
326 IExplorerBrowserEventsImpl_fnQueryInterface,
327 IExplorerBrowserEventsImpl_fnAddRef,
328 IExplorerBrowserEventsImpl_fnRelease,
329 IExplorerBrowserEventsImpl_fnOnNavigationPending,
330 IExplorerBrowserEventsImpl_fnOnViewCreated,
331 IExplorerBrowserEventsImpl_fnOnNavigationComplete,
332 IExplorerBrowserEventsImpl_fnOnNavigationFailed
335 static IExplorerBrowserEvents *make_explorer_events(explorer_info *info)
337 IExplorerBrowserEventsImpl *ret
338 = HeapAlloc(GetProcessHeap(), 0, sizeof(IExplorerBrowserEventsImpl));
339 ret->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents;
340 ret->info = info;
341 ret->ref = 1;
342 SHGetImageList(SHIL_SMALL,&IID_IImageList,(void**)&(ret->info->icon_list));
343 SendMessageW(info->path_box,CBEM_SETIMAGELIST,0,(LPARAM)ret->info->icon_list);
344 return &ret->IExplorerBrowserEvents_iface;
347 static IShellFolder *get_starting_shell_folder(WCHAR *path)
349 IShellFolder* desktop,*folder;
350 LPITEMIDLIST root_pidl;
351 HRESULT hres;
353 SHGetDesktopFolder(&desktop);
355 if (!path)
356 return desktop;
358 hres = IShellFolder_ParseDisplayName(desktop, NULL, NULL, path, NULL, &root_pidl, NULL);
359 if(FAILED(hres))
361 return desktop;
363 hres = IShellFolder_BindToObject(desktop,root_pidl,NULL,
364 &IID_IShellFolder,
365 (void**)&folder);
366 ILFree(root_pidl);
367 if(FAILED(hres))
369 return desktop;
371 IShellFolder_Release(desktop);
372 return folder;
375 static void make_explorer_window(parameters_struct *params)
377 RECT rect;
378 HWND rebar,nav_toolbar;
379 FOLDERSETTINGS fs;
380 IExplorerBrowserEvents *events;
381 explorer_info *info;
382 HRESULT hres;
383 WCHAR explorer_title[100];
384 WCHAR pathbox_label[50];
385 TBADDBITMAP bitmap_info;
386 TBBUTTON nav_buttons[3];
387 int hist_offset,view_offset;
388 REBARBANDINFOW band_info;
389 VARIANT var, empty_var;
390 IShellFolder *folder;
391 IDispatch *dispatch;
392 WCHAR *path = NULL;
393 IShellWindows *sw;
394 ITEMIDLIST *pidl;
395 UINT dpix, dpiy;
396 DWORD size;
397 LONG hwnd;
398 HDC hdc;
399 MSG msg;
401 CoCreateInstance(&CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER,
402 &IID_IShellWindows, (void **)&sw);
404 if (params->root[0])
406 size = GetFullPathNameW(params->root, 0, NULL, NULL);
407 path = malloc(size);
408 GetFullPathNameW(params->root, size, path, NULL);
411 if (sw && path)
413 if (!(pidl = ILCreateFromPathW(path)))
415 ERR("Failed to create PIDL for %s.\n", debugstr_w(path));
416 IShellWindows_Release(sw);
417 return;
420 variant_from_pidl(&var, pidl);
421 V_VT(&empty_var) = VT_EMPTY;
422 if (IShellWindows_FindWindowSW(sw, &var, &empty_var, SWC_EXPLORER, &hwnd, 0, &dispatch) == S_OK)
424 TRACE("Found window %#x already browsing path %s.\n", hwnd, debugstr_w(path));
425 SetForegroundWindow((HWND)(LONG_PTR)hwnd);
426 IShellWindows_Release(sw);
427 return;
429 ILFree(pidl);
430 VariantClear(&var);
433 memset(nav_buttons,0,sizeof(nav_buttons));
435 LoadStringW(explorer_hInstance,IDS_EXPLORER_TITLE,explorer_title, ARRAY_SIZE( explorer_title ));
436 LoadStringW(explorer_hInstance,IDS_PATHBOX_LABEL,pathbox_label, ARRAY_SIZE( pathbox_label ));
438 hdc = GetDC(0);
439 dpix = GetDeviceCaps(hdc, LOGPIXELSX);
440 dpiy = GetDeviceCaps(hdc, LOGPIXELSY);
441 ReleaseDC(0, hdc);
442 nav_toolbar_height = MulDiv(NAV_TOOLBAR_HEIGHT, dpiy, USER_DEFAULT_SCREEN_DPI);
443 pathbox_height = MulDiv(PATHBOX_HEIGHT, dpiy, USER_DEFAULT_SCREEN_DPI);
444 default_width = MulDiv(DEFAULT_WIDTH, dpix, USER_DEFAULT_SCREEN_DPI);
445 default_height = MulDiv(DEFAULT_HEIGHT, dpiy, USER_DEFAULT_SCREEN_DPI);
447 info = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(explorer_info));
448 if(!info)
450 WINE_ERR("Could not allocate an explorer_info struct\n");
451 return;
453 hres = CoCreateInstance(&CLSID_ExplorerBrowser,NULL,CLSCTX_INPROC_SERVER,
454 &IID_IExplorerBrowser,(LPVOID*)&info->browser);
455 if(FAILED(hres))
457 WINE_ERR("Could not obtain an instance of IExplorerBrowser\n");
458 HeapFree(GetProcessHeap(),0,info);
459 return;
461 info->rebar_height=0;
462 info->main_window
463 = CreateWindowW(EXPLORER_CLASS,explorer_title,WS_OVERLAPPEDWINDOW,
464 CW_USEDEFAULT,CW_USEDEFAULT,default_width,
465 default_height,NULL,NULL,explorer_hInstance,NULL);
467 if (sw)
469 IShellWindows_Register(sw, NULL, (LONG_PTR)info->main_window, SWC_EXPLORER, &info->sw_cookie);
470 info->sw = sw;
473 fs.ViewMode = FVM_DETAILS;
474 fs.fFlags = FWF_AUTOARRANGE;
476 SetRect(&rect, 0, 0, default_width, default_height);
477 IExplorerBrowser_Initialize(info->browser,info->main_window,&rect,&fs);
478 IExplorerBrowser_SetOptions(info->browser,EBO_SHOWFRAMES);
479 SetWindowLongPtrW(info->main_window,EXPLORER_INFO_INDEX,(LONG_PTR)info);
481 /*setup navbar*/
482 rebar = CreateWindowExW(WS_EX_TOOLWINDOW,REBARCLASSNAMEW,NULL,
483 WS_CHILD|WS_VISIBLE|RBS_VARHEIGHT|CCS_TOP|CCS_NODIVIDER,
484 0,0,0,0,info->main_window,NULL,explorer_hInstance,NULL);
485 nav_toolbar
486 = CreateWindowExW(TBSTYLE_EX_MIXEDBUTTONS,TOOLBARCLASSNAMEW,NULL,
487 WS_CHILD|WS_VISIBLE|TBSTYLE_FLAT,0,0,0,0,rebar,NULL,
488 explorer_hInstance,NULL);
490 bitmap_info.hInst = HINST_COMMCTRL;
491 bitmap_info.nID = IDB_HIST_LARGE_COLOR;
492 hist_offset= SendMessageW(nav_toolbar,TB_ADDBITMAP,0,(LPARAM)&bitmap_info);
493 bitmap_info.nID = IDB_VIEW_LARGE_COLOR;
494 view_offset= SendMessageW(nav_toolbar,TB_ADDBITMAP,0,(LPARAM)&bitmap_info);
496 nav_buttons[0].iBitmap=hist_offset+HIST_BACK;
497 nav_buttons[0].idCommand=BACK_BUTTON;
498 nav_buttons[0].fsState=TBSTATE_ENABLED;
499 nav_buttons[0].fsStyle=BTNS_BUTTON|BTNS_AUTOSIZE;
500 nav_buttons[1].iBitmap=hist_offset+HIST_FORWARD;
501 nav_buttons[1].idCommand=FORWARD_BUTTON;
502 nav_buttons[1].fsState=TBSTATE_ENABLED;
503 nav_buttons[1].fsStyle=BTNS_BUTTON|BTNS_AUTOSIZE;
504 nav_buttons[2].iBitmap=view_offset+VIEW_PARENTFOLDER;
505 nav_buttons[2].idCommand=UP_BUTTON;
506 nav_buttons[2].fsState=TBSTATE_ENABLED;
507 nav_buttons[2].fsStyle=BTNS_BUTTON|BTNS_AUTOSIZE;
508 SendMessageW(nav_toolbar,TB_BUTTONSTRUCTSIZE,sizeof(TBBUTTON),0);
509 SendMessageW(nav_toolbar,TB_ADDBUTTONSW,ARRAY_SIZE( nav_buttons ),(LPARAM)nav_buttons);
511 band_info.cbSize = sizeof(band_info);
512 band_info.fMask = RBBIM_STYLE|RBBIM_CHILD|RBBIM_CHILDSIZE|RBBIM_SIZE;
513 band_info.hwndChild = nav_toolbar;
514 band_info.fStyle=RBBS_GRIPPERALWAYS|RBBS_CHILDEDGE;
515 band_info.cyChild=nav_toolbar_height;
516 band_info.cx=0;
517 band_info.cyMinChild=nav_toolbar_height;
518 band_info.cxMinChild=0;
519 SendMessageW(rebar,RB_INSERTBANDW,-1,(LPARAM)&band_info);
520 info->path_box = CreateWindowW(WC_COMBOBOXEXW,PATH_BOX_NAME,
521 WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
522 0,0,default_width,pathbox_height,rebar,NULL,
523 explorer_hInstance,NULL);
524 GetWindowRect(info->path_box, &rect);
525 band_info.cyChild = rect.bottom - rect.top;
526 band_info.cx=0;
527 band_info.cyMinChild = rect.bottom - rect.top;
528 band_info.cxMinChild=0;
529 band_info.fMask|=RBBIM_TEXT;
530 band_info.lpText=pathbox_label;
531 band_info.fStyle|=RBBS_BREAK;
532 band_info.hwndChild=info->path_box;
533 SendMessageW(rebar,RB_INSERTBANDW,-1,(LPARAM)&band_info);
534 events = make_explorer_events(info);
535 IExplorerBrowser_Advise(info->browser,events,&info->advise_cookie);
537 folder = get_starting_shell_folder(path);
538 IExplorerBrowser_BrowseToObject(info->browser, (IUnknown *)folder, SBSP_ABSOLUTE);
539 IShellFolder_Release(folder);
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 WINE_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 WINE_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 LRESULT CALLBACK explorer_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
664 explorer_info *info
665 = (explorer_info*)GetWindowLongPtrW(hwnd,EXPLORER_INFO_INDEX);
666 IExplorerBrowser *browser = NULL;
668 WINE_TRACE("(hwnd=%p,uMsg=%u,wParam=%lx,lParam=%lx)\n",hwnd,uMsg,wParam,lParam);
669 if(info)
670 browser = info->browser;
671 switch(uMsg)
673 case WM_DESTROY:
674 IShellWindows_Revoke(info->sw, info->sw_cookie);
675 IShellWindows_Release(info->sw);
677 IExplorerBrowser_Unadvise(browser,info->advise_cookie);
678 IExplorerBrowser_Destroy(browser);
679 IExplorerBrowser_Release(browser);
680 ILFree(info->pidl);
681 IImageList_Release(info->icon_list);
682 HeapFree(GetProcessHeap(),0,info);
683 SetWindowLongPtrW(hwnd,EXPLORER_INFO_INDEX,0);
684 PostQuitMessage(0);
685 break;
686 case WM_QUIT:
687 do_exit(wParam);
688 case WM_NOTIFY:
689 return explorer_on_notify(info,(NMHDR*)lParam);
690 case WM_COMMAND:
691 if(HIWORD(wParam)==BN_CLICKED)
693 switch(LOWORD(wParam))
695 case BACK_BUTTON:
696 IExplorerBrowser_BrowseToObject(browser,NULL,SBSP_NAVIGATEBACK);
697 break;
698 case FORWARD_BUTTON:
699 IExplorerBrowser_BrowseToObject(browser,NULL,SBSP_NAVIGATEFORWARD);
700 break;
701 case UP_BUTTON:
702 IExplorerBrowser_BrowseToObject(browser,NULL,SBSP_PARENT);
703 break;
706 break;
707 case WM_SIZE:
708 update_window_size(info,HIWORD(lParam),LOWORD(lParam));
709 break;
710 default:
711 return DefWindowProcW(hwnd,uMsg,wParam,lParam);
713 return 0;
716 static void register_explorer_window_class(void)
718 WNDCLASSEXW window_class;
719 window_class.cbSize = sizeof(WNDCLASSEXW);
720 window_class.style = 0;
721 window_class.cbClsExtra = 0;
722 window_class.cbWndExtra = sizeof(LONG_PTR);
723 window_class.lpfnWndProc = explorer_wnd_proc;
724 window_class.hInstance = explorer_hInstance;
725 window_class.hIcon = NULL;
726 window_class.hCursor = NULL;
727 window_class.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
728 window_class.lpszMenuName = NULL;
729 window_class.lpszClassName = EXPLORER_CLASS;
730 window_class.hIconSm = NULL;
731 RegisterClassExW(&window_class);
734 static WCHAR *copy_path_string(WCHAR *target, WCHAR *source)
736 INT i = 0;
738 while (iswspace(*source)) source++;
740 if (*source == '\"')
742 source ++;
743 while (*source && *source != '\"') target[i++] = *source++;
744 target[i] = 0;
745 if (*source) source++;
747 else
749 while (*source && *source != ',') target[i++] = *source++;
750 target[i] = 0;
752 PathRemoveBackslashW(target);
753 return source;
757 static void copy_path_root(LPWSTR root, LPWSTR path)
759 LPWSTR p,p2;
760 INT i = 0;
762 p = path;
763 while (*p!=0)
764 p++;
766 while (*p!='\\' && p > path)
767 p--;
769 if (p == path)
770 return;
772 p2 = path;
773 while (p2 != p)
775 root[i] = *p2;
776 i++;
777 p2++;
779 root[i] = 0;
783 * Command Line parameters are:
784 * [/n] Opens in single-paned view for each selected items. This is default
785 * [/e,] Uses Windows Explorer View
786 * [/cd,object] Specifies the root level of the view
787 * [/root,object] Specifies the root level of the view
788 * [/select,object] parent folder is opened and specified object is selected
790 static void parse_command_line(LPWSTR commandline,parameters_struct *parameters)
792 static const WCHAR arg_n[] = {'/','n'};
793 static const WCHAR arg_e[] = {'/','e',','};
794 static const WCHAR arg_cd[] = {'/','c','d',','};
795 static const WCHAR arg_root[] = {'/','r','o','o','t',','};
796 static const WCHAR arg_select[] = {'/','s','e','l','e','c','t',','};
797 static const WCHAR arg_desktop[] = {'/','d','e','s','k','t','o','p'};
798 static const WCHAR arg_desktop_quotes[] = {'"','/','d','e','s','k','t','o','p'};
800 LPWSTR p = commandline;
802 while (*p)
804 while (iswspace(*p)) p++;
805 if (wcsncmp(p, arg_n, ARRAY_SIZE( arg_n ))==0)
807 parameters->explorer_mode = FALSE;
808 p += ARRAY_SIZE( arg_n );
810 else if (wcsncmp(p, arg_e, ARRAY_SIZE( arg_e ))==0)
812 parameters->explorer_mode = TRUE;
813 p += ARRAY_SIZE( arg_e );
815 else if (wcsncmp(p, arg_cd, ARRAY_SIZE( arg_cd ))==0)
817 p += ARRAY_SIZE( arg_cd );
818 p = copy_path_string(parameters->root,p);
820 else if (wcsncmp(p, arg_root, ARRAY_SIZE( arg_root ))==0)
822 p += ARRAY_SIZE( arg_root );
823 p = copy_path_string(parameters->root,p);
825 else if (wcsncmp(p, arg_select, ARRAY_SIZE( arg_select ))==0)
827 p += ARRAY_SIZE( arg_select );
828 p = copy_path_string(parameters->selection,p);
829 if (!parameters->root[0])
830 copy_path_root(parameters->root,
831 parameters->selection);
833 else if (wcsncmp(p, arg_desktop, ARRAY_SIZE( arg_desktop ))==0)
835 p += ARRAY_SIZE( arg_desktop );
836 manage_desktop( p ); /* the rest of the command line is handled by desktop mode */
838 /* workaround for Worms Armageddon that hardcodes a /desktop option with quotes */
839 else if (wcsncmp(p, arg_desktop_quotes, ARRAY_SIZE( arg_desktop_quotes ))==0)
841 p += ARRAY_SIZE( arg_desktop_quotes );
842 manage_desktop( p ); /* the rest of the command line is handled by desktop mode */
844 else
846 /* left over command line is generally the path to be opened */
847 copy_path_string(parameters->root,p);
848 break;
853 int WINAPI wWinMain(HINSTANCE hinstance,
854 HINSTANCE previnstance,
855 LPWSTR cmdline,
856 int cmdshow)
859 parameters_struct parameters;
860 HRESULT hres;
861 INITCOMMONCONTROLSEX init_info;
863 memset(&parameters,0,sizeof(parameters));
864 explorer_hInstance = hinstance;
865 parse_command_line(cmdline,&parameters);
866 hres = OleInitialize(NULL);
867 if(FAILED(hres))
869 WINE_ERR("Could not initialize COM\n");
870 ExitProcess(EXIT_FAILURE);
872 if(parameters.root[0] && !PathIsDirectoryW(parameters.root))
873 if(ShellExecuteW(NULL,NULL,parameters.root,NULL,NULL,SW_SHOWDEFAULT) > (HINSTANCE)32)
874 ExitProcess(EXIT_SUCCESS);
875 init_info.dwSize = sizeof(INITCOMMONCONTROLSEX);
876 init_info.dwICC = ICC_USEREX_CLASSES | ICC_BAR_CLASSES | ICC_COOL_CLASSES;
877 if(!InitCommonControlsEx(&init_info))
879 WINE_ERR("Could not initialize Comctl\n");
880 ExitProcess(EXIT_FAILURE);
882 register_explorer_window_class();
883 make_explorer_window(&parameters);
884 return 0;