msi: Avoid using awstring in MsiGetSourcePathW().
[wine.git] / programs / explorer / explorer.c
blobc50933661bb7206d9d5f422ca65852276d88a8f0
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/unicode.h"
26 #include "wine/debug.h"
27 #include "wine/heap.h"
28 #include "explorer_private.h"
29 #include "resource.h"
31 #include <initguid.h>
32 #include <windows.h>
33 #include <shellapi.h>
34 #include <shobjidl.h>
35 #include <shlobj.h>
36 #include <shlwapi.h>
37 #include <commoncontrols.h>
38 #include <commctrl.h>
40 WINE_DEFAULT_DEBUG_CHANNEL(explorer);
42 #define EXPLORER_INFO_INDEX 0
44 #define NAV_TOOLBAR_HEIGHT 30
45 #define PATHBOX_HEIGHT 24
46 static int nav_toolbar_height;
47 static int pathbox_height;
49 #define DEFAULT_WIDTH 640
50 #define DEFAULT_HEIGHT 480
51 static int default_width;
52 static int default_height;
55 static const WCHAR EXPLORER_CLASS[] = {'E','x','p','l','o','r','e','r','W','C','l','a','s','s',0};
56 static const WCHAR PATH_BOX_NAME[] = {'\0'};
58 HINSTANCE explorer_hInstance;
60 typedef struct parametersTAG {
61 BOOL explorer_mode;
62 WCHAR root[MAX_PATH];
63 WCHAR selection[MAX_PATH];
64 } parameters_struct;
66 typedef struct
68 IExplorerBrowser *browser;
69 HWND main_window,path_box;
70 INT rebar_height;
71 LPITEMIDLIST pidl;
72 IImageList *icon_list;
73 DWORD advise_cookie;
74 } explorer_info;
76 enum
78 BACK_BUTTON,FORWARD_BUTTON,UP_BUTTON
81 typedef struct
83 IExplorerBrowserEvents IExplorerBrowserEvents_iface;
84 explorer_info* info;
85 LONG ref;
86 } IExplorerBrowserEventsImpl;
88 static IExplorerBrowserEventsImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
90 return CONTAINING_RECORD(iface, IExplorerBrowserEventsImpl, IExplorerBrowserEvents_iface);
93 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnQueryInterface(IExplorerBrowserEvents *iface, REFIID riid, void **ppvObject)
95 return E_NOINTERFACE;
98 static ULONG WINAPI IExplorerBrowserEventsImpl_fnAddRef(IExplorerBrowserEvents *iface)
100 IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
101 return InterlockedIncrement(&This->ref);
104 static ULONG WINAPI IExplorerBrowserEventsImpl_fnRelease(IExplorerBrowserEvents *iface)
106 IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
107 ULONG ref = InterlockedDecrement(&This->ref);
108 if(!ref)
109 HeapFree(GetProcessHeap(),0,This);
110 return ref;
113 static BOOL create_combobox_item(IShellFolder *folder, LPCITEMIDLIST child_pidl, IImageList *icon_list, COMBOBOXEXITEMW *item)
115 STRRET strret;
116 HRESULT hres;
117 PIDLIST_ABSOLUTE parent_pidl, pidl;
118 SHFILEINFOW info;
119 IImageList *list;
121 strret.uType=STRRET_WSTR;
122 hres = IShellFolder_GetDisplayNameOf( folder, child_pidl, SHGDN_FORADDRESSBAR, &strret );
123 if(SUCCEEDED(hres))
124 hres = StrRetToStrW(&strret, child_pidl, &item->pszText);
125 if(FAILED(hres))
127 WINE_WARN("Could not get name for pidl\n");
128 return FALSE;
131 item->mask &= ~CBEIF_IMAGE;
132 hres = SHGetIDListFromObject( (IUnknown *)folder, &parent_pidl );
133 if (FAILED(hres)) return FALSE;
135 pidl = ILCombine( parent_pidl, child_pidl );
136 if (pidl)
138 list = (IImageList *)SHGetFileInfoW( (WCHAR *)pidl, 0, &info, sizeof(info),
139 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_SYSICONINDEX );
140 if (list)
142 IImageList_Release( list );
143 item->iImage = info.iIcon;
144 item->mask |= CBEIF_IMAGE;
146 ILFree( pidl );
148 ILFree( parent_pidl );
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 SendMessageW(info->path_box,CB_RESETCONTENT,0,0);
163 SHGetDesktopFolder(&desktop);
164 IShellFolder_QueryInterface(desktop,&IID_IPersistFolder2,(void**)&persist);
165 IPersistFolder2_GetCurFolder(persist,&desktop_pidl);
166 IPersistFolder2_Release(persist);
167 persist = NULL;
168 /*Add Desktop*/
169 item.iItem = -1;
170 item.mask = CBEIF_TEXT | CBEIF_INDENT | CBEIF_LPARAM;
171 item.iIndent = 0;
172 create_combobox_item(desktop,desktop_pidl,info->icon_list,&item);
173 item.lParam = (LPARAM)desktop_pidl;
174 SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item);
175 if(ILIsEqual(info->pidl,desktop_pidl))
176 main_item = item;
177 else
178 CoTaskMemFree(item.pszText);
179 /*Add all direct subfolders of Desktop*/
180 if(SUCCEEDED(IShellFolder_EnumObjects(desktop,NULL,SHCONTF_FOLDERS,&ids))
181 && ids!=NULL)
183 LPITEMIDLIST curr_pidl=NULL;
184 HRESULT hres;
186 item.iIndent = 1;
187 while(1)
189 ILFree(curr_pidl);
190 curr_pidl=NULL;
191 hres = IEnumIDList_Next(ids,1,&curr_pidl,NULL);
192 if(FAILED(hres) || hres == S_FALSE)
193 break;
194 if(!create_combobox_item(desktop,curr_pidl,info->icon_list,&item))
195 WINE_WARN("Could not create a combobox item\n");
196 else
198 LPITEMIDLIST full_pidl = ILCombine(desktop_pidl,curr_pidl);
199 item.lParam = (LPARAM)full_pidl;
200 SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item);
201 if(ILIsEqual(full_pidl,info->pidl))
202 main_item = item;
203 else if(ILIsParent(full_pidl,info->pidl,FALSE))
205 /*add all parents of the pidl passed in*/
206 LPITEMIDLIST next_pidl = ILFindChild(full_pidl,info->pidl);
207 IShellFolder *curr_folder = NULL, *temp;
208 hres = IShellFolder_BindToObject(desktop,curr_pidl,NULL,
209 &IID_IShellFolder,
210 (void**)&curr_folder);
211 if(FAILED(hres))
212 WINE_WARN("Could not get an IShellFolder\n");
213 while(!ILIsEmpty(next_pidl))
215 LPITEMIDLIST first = ILCloneFirst(next_pidl);
216 CoTaskMemFree(item.pszText);
217 if(!create_combobox_item(curr_folder,first,
218 info->icon_list,&item))
220 WINE_WARN("Could not create a combobox item\n");
221 break;
223 ++item.iIndent;
224 full_pidl = ILCombine(full_pidl,first);
225 item.lParam = (LPARAM)full_pidl;
226 SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item);
227 temp=NULL;
228 hres = IShellFolder_BindToObject(curr_folder,first,NULL,
229 &IID_IShellFolder,
230 (void**)&temp);
231 if(FAILED(hres))
233 WINE_WARN("Could not get an IShellFolder\n");
234 break;
236 IShellFolder_Release(curr_folder);
237 curr_folder = temp;
239 ILFree(first);
240 next_pidl = ILGetNext(next_pidl);
242 memcpy(&main_item,&item,sizeof(item));
243 if(curr_folder)
244 IShellFolder_Release(curr_folder);
245 item.iIndent = 1;
247 else
248 CoTaskMemFree(item.pszText);
251 ILFree(curr_pidl);
252 IEnumIDList_Release(ids);
254 else
255 WINE_WARN("Could not enumerate the desktop\n");
256 SendMessageW(info->path_box,CBEM_SETITEMW,0,(LPARAM)&main_item);
257 CoTaskMemFree(main_item.pszText);
260 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnNavigationComplete(IExplorerBrowserEvents *iface, PCIDLIST_ABSOLUTE pidl)
262 IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
263 IShellFolder *parent;
264 PCUITEMID_CHILD child_pidl;
265 HRESULT hres;
266 STRRET strret;
267 WCHAR *name;
269 ILFree(This->info->pidl);
270 This->info->pidl = ILClone(pidl);
271 update_path_box(This->info);
273 hres = SHBindToParent(pidl, &IID_IShellFolder, (void **)&parent, &child_pidl);
274 if (SUCCEEDED(hres))
276 hres = IShellFolder_GetDisplayNameOf(parent, child_pidl, SHGDN_FORADDRESSBAR, &strret);
277 if (SUCCEEDED(hres))
278 hres = StrRetToStrW(&strret, child_pidl, &name);
279 if (SUCCEEDED(hres))
281 SetWindowTextW(This->info->main_window, name);
282 CoTaskMemFree(name);
285 IShellFolder_Release(parent);
288 return hres;
291 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnNavigationFailed(IExplorerBrowserEvents *iface, PCIDLIST_ABSOLUTE pidl)
293 return S_OK;
296 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnNavigationPending(IExplorerBrowserEvents *iface, PCIDLIST_ABSOLUTE pidl)
298 return S_OK;
301 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnViewCreated(IExplorerBrowserEvents *iface, IShellView *psv)
303 return S_OK;
306 static IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents =
308 IExplorerBrowserEventsImpl_fnQueryInterface,
309 IExplorerBrowserEventsImpl_fnAddRef,
310 IExplorerBrowserEventsImpl_fnRelease,
311 IExplorerBrowserEventsImpl_fnOnNavigationPending,
312 IExplorerBrowserEventsImpl_fnOnViewCreated,
313 IExplorerBrowserEventsImpl_fnOnNavigationComplete,
314 IExplorerBrowserEventsImpl_fnOnNavigationFailed
317 static IExplorerBrowserEvents *make_explorer_events(explorer_info *info)
319 IExplorerBrowserEventsImpl *ret
320 = HeapAlloc(GetProcessHeap(), 0, sizeof(IExplorerBrowserEventsImpl));
321 ret->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents;
322 ret->info = info;
323 ret->ref = 1;
324 SHGetImageList(SHIL_SMALL,&IID_IImageList,(void**)&(ret->info->icon_list));
325 SendMessageW(info->path_box,CBEM_SETIMAGELIST,0,(LPARAM)ret->info->icon_list);
326 return &ret->IExplorerBrowserEvents_iface;
329 static void make_explorer_window(IShellFolder* startFolder)
331 RECT rect;
332 HWND rebar,nav_toolbar;
333 FOLDERSETTINGS fs;
334 IExplorerBrowserEvents *events;
335 explorer_info *info;
336 HRESULT hres;
337 WCHAR explorer_title[100];
338 WCHAR pathbox_label[50];
339 TBADDBITMAP bitmap_info;
340 TBBUTTON nav_buttons[3];
341 int hist_offset,view_offset;
342 REBARBANDINFOW band_info;
343 UINT dpix, dpiy;
344 HDC hdc;
346 memset(nav_buttons,0,sizeof(nav_buttons));
348 LoadStringW(explorer_hInstance,IDS_EXPLORER_TITLE,explorer_title,
349 sizeof(explorer_title)/sizeof(WCHAR));
350 LoadStringW(explorer_hInstance,IDS_PATHBOX_LABEL,pathbox_label,
351 sizeof(pathbox_label)/sizeof(WCHAR));
353 hdc = GetDC(0);
354 dpix = GetDeviceCaps(hdc, LOGPIXELSX);
355 dpiy = GetDeviceCaps(hdc, LOGPIXELSY);
356 ReleaseDC(0, hdc);
357 nav_toolbar_height = MulDiv(NAV_TOOLBAR_HEIGHT, dpiy, USER_DEFAULT_SCREEN_DPI);
358 pathbox_height = MulDiv(PATHBOX_HEIGHT, dpiy, USER_DEFAULT_SCREEN_DPI);
359 default_width = MulDiv(DEFAULT_WIDTH, dpix, USER_DEFAULT_SCREEN_DPI);
360 default_height = MulDiv(DEFAULT_HEIGHT, dpiy, USER_DEFAULT_SCREEN_DPI);
362 info = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(explorer_info));
363 if(!info)
365 WINE_ERR("Could not allocate an explorer_info struct\n");
366 return;
368 hres = CoCreateInstance(&CLSID_ExplorerBrowser,NULL,CLSCTX_INPROC_SERVER,
369 &IID_IExplorerBrowser,(LPVOID*)&info->browser);
370 if(FAILED(hres))
372 WINE_ERR("Could not obtain an instance of IExplorerBrowser\n");
373 HeapFree(GetProcessHeap(),0,info);
374 return;
376 info->rebar_height=0;
377 info->main_window
378 = CreateWindowW(EXPLORER_CLASS,explorer_title,WS_OVERLAPPEDWINDOW,
379 CW_USEDEFAULT,CW_USEDEFAULT,default_width,
380 default_height,NULL,NULL,explorer_hInstance,NULL);
382 fs.ViewMode = FVM_DETAILS;
383 fs.fFlags = FWF_AUTOARRANGE;
385 SetRect(&rect, 0, 0, default_width, default_height);
386 IExplorerBrowser_Initialize(info->browser,info->main_window,&rect,&fs);
387 IExplorerBrowser_SetOptions(info->browser,EBO_SHOWFRAMES);
388 SetWindowLongPtrW(info->main_window,EXPLORER_INFO_INDEX,(LONG_PTR)info);
390 /*setup navbar*/
391 rebar = CreateWindowExW(WS_EX_TOOLWINDOW,REBARCLASSNAMEW,NULL,
392 WS_CHILD|WS_VISIBLE|RBS_VARHEIGHT|CCS_TOP|CCS_NODIVIDER,
393 0,0,0,0,info->main_window,NULL,explorer_hInstance,NULL);
394 nav_toolbar
395 = CreateWindowExW(TBSTYLE_EX_MIXEDBUTTONS,TOOLBARCLASSNAMEW,NULL,
396 WS_CHILD|WS_VISIBLE|TBSTYLE_FLAT,0,0,0,0,rebar,NULL,
397 explorer_hInstance,NULL);
399 bitmap_info.hInst = HINST_COMMCTRL;
400 bitmap_info.nID = IDB_HIST_LARGE_COLOR;
401 hist_offset= SendMessageW(nav_toolbar,TB_ADDBITMAP,0,(LPARAM)&bitmap_info);
402 bitmap_info.nID = IDB_VIEW_LARGE_COLOR;
403 view_offset= SendMessageW(nav_toolbar,TB_ADDBITMAP,0,(LPARAM)&bitmap_info);
405 nav_buttons[0].iBitmap=hist_offset+HIST_BACK;
406 nav_buttons[0].idCommand=BACK_BUTTON;
407 nav_buttons[0].fsState=TBSTATE_ENABLED;
408 nav_buttons[0].fsStyle=BTNS_BUTTON|BTNS_AUTOSIZE;
409 nav_buttons[1].iBitmap=hist_offset+HIST_FORWARD;
410 nav_buttons[1].idCommand=FORWARD_BUTTON;
411 nav_buttons[1].fsState=TBSTATE_ENABLED;
412 nav_buttons[1].fsStyle=BTNS_BUTTON|BTNS_AUTOSIZE;
413 nav_buttons[2].iBitmap=view_offset+VIEW_PARENTFOLDER;
414 nav_buttons[2].idCommand=UP_BUTTON;
415 nav_buttons[2].fsState=TBSTATE_ENABLED;
416 nav_buttons[2].fsStyle=BTNS_BUTTON|BTNS_AUTOSIZE;
417 SendMessageW(nav_toolbar,TB_BUTTONSTRUCTSIZE,sizeof(TBBUTTON),0);
418 SendMessageW(nav_toolbar,TB_ADDBUTTONSW,sizeof(nav_buttons)/sizeof(TBBUTTON),(LPARAM)nav_buttons);
420 band_info.cbSize = sizeof(band_info);
421 band_info.fMask = RBBIM_STYLE|RBBIM_CHILD|RBBIM_CHILDSIZE|RBBIM_SIZE;
422 band_info.hwndChild = nav_toolbar;
423 band_info.fStyle=RBBS_GRIPPERALWAYS|RBBS_CHILDEDGE;
424 band_info.cyChild=nav_toolbar_height;
425 band_info.cx=0;
426 band_info.cyMinChild=nav_toolbar_height;
427 band_info.cxMinChild=0;
428 SendMessageW(rebar,RB_INSERTBANDW,-1,(LPARAM)&band_info);
429 info->path_box = CreateWindowW(WC_COMBOBOXEXW,PATH_BOX_NAME,
430 WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
431 0,0,default_width,pathbox_height,rebar,NULL,
432 explorer_hInstance,NULL);
433 GetWindowRect(info->path_box, &rect);
434 band_info.cyChild = rect.bottom - rect.top;
435 band_info.cx=0;
436 band_info.cyMinChild = rect.bottom - rect.top;
437 band_info.cxMinChild=0;
438 band_info.fMask|=RBBIM_TEXT;
439 band_info.lpText=pathbox_label;
440 band_info.fStyle|=RBBS_BREAK;
441 band_info.hwndChild=info->path_box;
442 SendMessageW(rebar,RB_INSERTBANDW,-1,(LPARAM)&band_info);
443 events = make_explorer_events(info);
444 IExplorerBrowser_Advise(info->browser,events,&info->advise_cookie);
445 IExplorerBrowser_BrowseToObject(info->browser,(IUnknown*)startFolder,
446 SBSP_ABSOLUTE);
447 ShowWindow(info->main_window,SW_SHOWDEFAULT);
448 UpdateWindow(info->main_window);
449 IExplorerBrowserEvents_Release(events);
452 static void update_window_size(explorer_info *info, int height, int width)
454 RECT new_rect;
455 new_rect.left = 0;
456 new_rect.top = info->rebar_height;
457 new_rect.right = width;
458 new_rect.bottom = height;
459 IExplorerBrowser_SetRect(info->browser,NULL,new_rect);
462 static void do_exit(int code)
464 OleUninitialize();
465 ExitProcess(code);
468 static LRESULT explorer_on_end_edit(explorer_info *info,NMCBEENDEDITW *edit_info)
470 LPITEMIDLIST pidl = NULL;
472 WINE_TRACE("iWhy=%x\n",edit_info->iWhy);
473 switch(edit_info->iWhy)
475 case CBENF_DROPDOWN:
476 if(edit_info->iNewSelection!=CB_ERR)
477 pidl = (LPITEMIDLIST)SendMessageW(edit_info->hdr.hwndFrom,
478 CB_GETITEMDATA,
479 edit_info->iNewSelection,0);
480 break;
481 case CBENF_RETURN:
483 WCHAR path[MAX_PATH];
484 HWND edit_ctrl = (HWND)SendMessageW(edit_info->hdr.hwndFrom,
485 CBEM_GETEDITCONTROL,0,0);
486 *((WORD*)path)=MAX_PATH;
487 SendMessageW(edit_ctrl,EM_GETLINE,0,(LPARAM)path);
488 pidl = ILCreateFromPathW(path);
489 break;
491 case CBENF_ESCAPE:
492 /*make sure the that the path box resets*/
493 update_path_box(info);
494 return 0;
495 default:
496 return 0;
498 if(pidl)
499 IExplorerBrowser_BrowseToIDList(info->browser,pidl,SBSP_ABSOLUTE);
500 if(edit_info->iWhy==CBENF_RETURN)
501 ILFree(pidl);
502 return 0;
505 static LRESULT update_rebar_size(explorer_info* info,NMRBAUTOSIZE *size_info)
507 RECT new_rect;
508 RECT window_rect;
509 info->rebar_height = size_info->rcTarget.bottom-size_info->rcTarget.top;
510 GetWindowRect(info->main_window,&window_rect);
511 new_rect.left = 0;
512 new_rect.top = info->rebar_height;
513 new_rect.right = window_rect.right-window_rect.left;
514 new_rect.bottom = window_rect.bottom-window_rect.top;
515 IExplorerBrowser_SetRect(info->browser,NULL,new_rect);
516 return 0;
519 static LRESULT explorer_on_notify(explorer_info* info,NMHDR* notification)
521 WINE_TRACE("code=%i\n",notification->code);
522 switch(notification->code)
524 case CBEN_BEGINEDIT:
526 WCHAR path[MAX_PATH];
527 HWND edit_ctrl = (HWND)SendMessageW(notification->hwndFrom,
528 CBEM_GETEDITCONTROL,0,0);
529 SHGetPathFromIDListW(info->pidl,path);
530 SetWindowTextW(edit_ctrl,path);
531 break;
533 case CBEN_ENDEDITA:
535 NMCBEENDEDITA *edit_info_a = (NMCBEENDEDITA*)notification;
536 NMCBEENDEDITW edit_info_w;
537 edit_info_w.hdr = edit_info_a->hdr;
538 edit_info_w.fChanged = edit_info_a->fChanged;
539 edit_info_w.iNewSelection = edit_info_a->iNewSelection;
540 MultiByteToWideChar(CP_ACP,0,edit_info_a->szText,-1,
541 edit_info_w.szText,CBEMAXSTRLEN);
542 edit_info_w.iWhy = edit_info_a->iWhy;
543 return explorer_on_end_edit(info,&edit_info_w);
545 case CBEN_ENDEDITW:
546 return explorer_on_end_edit(info,(NMCBEENDEDITW*)notification);
547 case CBEN_DELETEITEM:
549 NMCOMBOBOXEXW *entry = (NMCOMBOBOXEXW*)notification;
550 if(entry->ceItem.lParam)
551 ILFree((LPITEMIDLIST)entry->ceItem.lParam);
552 break;
554 case RBN_AUTOSIZE:
555 return update_rebar_size(info,(NMRBAUTOSIZE*)notification);
556 default:
557 break;
559 return 0;
562 static LRESULT CALLBACK explorer_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
564 explorer_info *info
565 = (explorer_info*)GetWindowLongPtrW(hwnd,EXPLORER_INFO_INDEX);
566 IExplorerBrowser *browser = NULL;
568 WINE_TRACE("(hwnd=%p,uMsg=%u,wParam=%lx,lParam=%lx)\n",hwnd,uMsg,wParam,lParam);
569 if(info)
570 browser = info->browser;
571 switch(uMsg)
573 case WM_DESTROY:
574 IExplorerBrowser_Unadvise(browser,info->advise_cookie);
575 IExplorerBrowser_Destroy(browser);
576 IExplorerBrowser_Release(browser);
577 ILFree(info->pidl);
578 IImageList_Release(info->icon_list);
579 HeapFree(GetProcessHeap(),0,info);
580 SetWindowLongPtrW(hwnd,EXPLORER_INFO_INDEX,0);
581 PostQuitMessage(0);
582 break;
583 case WM_QUIT:
584 do_exit(wParam);
585 case WM_NOTIFY:
586 return explorer_on_notify(info,(NMHDR*)lParam);
587 case WM_COMMAND:
588 if(HIWORD(wParam)==BN_CLICKED)
590 switch(LOWORD(wParam))
592 case BACK_BUTTON:
593 IExplorerBrowser_BrowseToObject(browser,NULL,SBSP_NAVIGATEBACK);
594 break;
595 case FORWARD_BUTTON:
596 IExplorerBrowser_BrowseToObject(browser,NULL,SBSP_NAVIGATEFORWARD);
597 break;
598 case UP_BUTTON:
599 IExplorerBrowser_BrowseToObject(browser,NULL,SBSP_PARENT);
600 break;
603 break;
604 case WM_SIZE:
605 update_window_size(info,HIWORD(lParam),LOWORD(lParam));
606 break;
607 default:
608 return DefWindowProcW(hwnd,uMsg,wParam,lParam);
610 return 0;
613 static void register_explorer_window_class(void)
615 WNDCLASSEXW window_class;
616 window_class.cbSize = sizeof(WNDCLASSEXW);
617 window_class.style = 0;
618 window_class.cbClsExtra = 0;
619 window_class.cbWndExtra = sizeof(LONG_PTR);
620 window_class.lpfnWndProc = explorer_wnd_proc;
621 window_class.hInstance = explorer_hInstance;
622 window_class.hIcon = NULL;
623 window_class.hCursor = NULL;
624 window_class.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
625 window_class.lpszMenuName = NULL;
626 window_class.lpszClassName = EXPLORER_CLASS;
627 window_class.hIconSm = NULL;
628 RegisterClassExW(&window_class);
631 static IShellFolder* get_starting_shell_folder(parameters_struct* params)
633 IShellFolder* desktop,*folder;
634 LPITEMIDLIST root_pidl;
635 WCHAR *fullpath = NULL;
636 HRESULT hres;
637 DWORD size;
639 SHGetDesktopFolder(&desktop);
640 if (!params->root[0])
642 return desktop;
645 size = GetFullPathNameW(params->root, 0, fullpath, NULL);
646 if (!size)
647 return desktop;
648 fullpath = heap_alloc(size * sizeof(WCHAR));
649 GetFullPathNameW(params->root, size, fullpath, NULL);
651 hres = IShellFolder_ParseDisplayName(desktop,NULL,NULL,
652 fullpath,NULL,
653 &root_pidl,NULL);
654 heap_free(fullpath);
656 if(FAILED(hres))
658 return desktop;
660 hres = IShellFolder_BindToObject(desktop,root_pidl,NULL,
661 &IID_IShellFolder,
662 (void**)&folder);
663 ILFree(root_pidl);
664 if(FAILED(hres))
666 return desktop;
668 IShellFolder_Release(desktop);
669 return folder;
672 static WCHAR *copy_path_string(WCHAR *target, WCHAR *source)
674 INT i = 0;
676 while (isspaceW(*source)) source++;
678 if (*source == '\"')
680 source ++;
681 while (*source && *source != '\"') target[i++] = *source++;
682 target[i] = 0;
683 if (*source) source++;
685 else
687 while (*source && *source != ',') target[i++] = *source++;
688 target[i] = 0;
690 PathRemoveBackslashW(target);
691 return source;
695 static void copy_path_root(LPWSTR root, LPWSTR path)
697 LPWSTR p,p2;
698 INT i = 0;
700 p = path;
701 while (*p!=0)
702 p++;
704 while (*p!='\\' && p > path)
705 p--;
707 if (p == path)
708 return;
710 p2 = path;
711 while (p2 != p)
713 root[i] = *p2;
714 i++;
715 p2++;
717 root[i] = 0;
721 * Command Line parameters are:
722 * [/n] Opens in single-paned view for each selected items. This is default
723 * [/e,] Uses Windows Explorer View
724 * [/root,object] Specifies the root level of the view
725 * [/select,object] parent folder is opened and specified object is selected
727 static void parse_command_line(LPWSTR commandline,parameters_struct *parameters)
729 static const WCHAR arg_n[] = {'/','n'};
730 static const WCHAR arg_e[] = {'/','e',','};
731 static const WCHAR arg_root[] = {'/','r','o','o','t',','};
732 static const WCHAR arg_select[] = {'/','s','e','l','e','c','t',','};
733 static const WCHAR arg_desktop[] = {'/','d','e','s','k','t','o','p'};
734 static const WCHAR arg_desktop_quotes[] = {'"','/','d','e','s','k','t','o','p'};
736 LPWSTR p = commandline;
738 while (*p)
740 while (isspaceW(*p)) p++;
741 if (strncmpW(p, arg_n, sizeof(arg_n)/sizeof(WCHAR))==0)
743 parameters->explorer_mode = FALSE;
744 p += sizeof(arg_n)/sizeof(WCHAR);
746 else if (strncmpW(p, arg_e, sizeof(arg_e)/sizeof(WCHAR))==0)
748 parameters->explorer_mode = TRUE;
749 p += sizeof(arg_e)/sizeof(WCHAR);
751 else if (strncmpW(p, arg_root, sizeof(arg_root)/sizeof(WCHAR))==0)
753 p += sizeof(arg_root)/sizeof(WCHAR);
754 p = copy_path_string(parameters->root,p);
756 else if (strncmpW(p, arg_select, sizeof(arg_select)/sizeof(WCHAR))==0)
758 p += sizeof(arg_select)/sizeof(WCHAR);
759 p = copy_path_string(parameters->selection,p);
760 if (!parameters->root[0])
761 copy_path_root(parameters->root,
762 parameters->selection);
764 else if (strncmpW(p, arg_desktop, sizeof(arg_desktop)/sizeof(WCHAR))==0)
766 p += sizeof(arg_desktop)/sizeof(WCHAR);
767 manage_desktop( p ); /* the rest of the command line is handled by desktop mode */
769 /* workaround for Worms Armageddon that hardcodes a /desktop option with quotes */
770 else if (strncmpW(p, arg_desktop_quotes, sizeof(arg_desktop_quotes)/sizeof(WCHAR))==0)
772 p += sizeof(arg_desktop_quotes)/sizeof(WCHAR);
773 manage_desktop( p ); /* the rest of the command line is handled by desktop mode */
775 else
777 /* left over command line is generally the path to be opened */
778 copy_path_string(parameters->root,p);
779 break;
784 int WINAPI wWinMain(HINSTANCE hinstance,
785 HINSTANCE previnstance,
786 LPWSTR cmdline,
787 int cmdshow)
790 parameters_struct parameters;
791 HRESULT hres;
792 MSG msg;
793 IShellFolder *folder;
794 INITCOMMONCONTROLSEX init_info;
796 memset(&parameters,0,sizeof(parameters));
797 explorer_hInstance = hinstance;
798 parse_command_line(cmdline,&parameters);
799 hres = OleInitialize(NULL);
800 if(FAILED(hres))
802 WINE_ERR("Could not initialize COM\n");
803 ExitProcess(EXIT_FAILURE);
805 if(parameters.root[0] && !PathIsDirectoryW(parameters.root))
806 if(ShellExecuteW(NULL,NULL,parameters.root,NULL,NULL,SW_SHOWDEFAULT) > (HINSTANCE)32)
807 ExitProcess(EXIT_SUCCESS);
808 init_info.dwSize = sizeof(INITCOMMONCONTROLSEX);
809 init_info.dwICC = ICC_USEREX_CLASSES | ICC_BAR_CLASSES | ICC_COOL_CLASSES;
810 if(!InitCommonControlsEx(&init_info))
812 WINE_ERR("Could not initialize Comctl\n");
813 ExitProcess(EXIT_FAILURE);
815 register_explorer_window_class();
816 folder = get_starting_shell_folder(&parameters);
817 make_explorer_window(folder);
818 IShellFolder_Release(folder);
819 while(GetMessageW( &msg, NULL, 0, 0 ) != 0)
821 TranslateMessage(&msg);
822 DispatchMessageW(&msg);
824 return 0;