netstat: Use WINAPIV calling convention for variadic functions.
[wine.git] / programs / explorer / explorer.c
blobcc3244d00e3c21082e9f337ff3e2d120db5971be
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 "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
46 #define DEFAULT_WIDTH 640
47 #define DEFAULT_HEIGHT 480
50 static const WCHAR EXPLORER_CLASS[] = {'W','I','N','E','_','E','X','P','L','O','R','E','R','\0'};
51 static const WCHAR PATH_BOX_NAME[] = {'\0'};
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;
69 } explorer_info;
71 enum
73 BACK_BUTTON,FORWARD_BUTTON,UP_BUTTON
76 typedef struct
78 IExplorerBrowserEvents IExplorerBrowserEvents_iface;
79 explorer_info* info;
80 LONG ref;
81 } IExplorerBrowserEventsImpl;
83 static IExplorerBrowserEventsImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
85 return CONTAINING_RECORD(iface, IExplorerBrowserEventsImpl, IExplorerBrowserEvents_iface);
88 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnQueryInterface(IExplorerBrowserEvents *iface, REFIID riid, void **ppvObject)
90 return E_NOINTERFACE;
93 static ULONG WINAPI IExplorerBrowserEventsImpl_fnAddRef(IExplorerBrowserEvents *iface)
95 IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
96 return InterlockedIncrement(&This->ref);
99 static ULONG WINAPI IExplorerBrowserEventsImpl_fnRelease(IExplorerBrowserEvents *iface)
101 IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
102 ULONG ref = InterlockedDecrement(&This->ref);
103 if(!ref)
104 HeapFree(GetProcessHeap(),0,This);
105 return ref;
108 static BOOL create_combobox_item(IShellFolder *folder, LPCITEMIDLIST child_pidl, IImageList *icon_list, COMBOBOXEXITEMW *item)
110 STRRET strret;
111 HRESULT hres;
112 PIDLIST_ABSOLUTE parent_pidl, pidl;
113 SHFILEINFOW info;
114 IImageList *list;
116 strret.uType=STRRET_WSTR;
117 hres = IShellFolder_GetDisplayNameOf( folder, child_pidl, SHGDN_FORADDRESSBAR, &strret );
118 if(SUCCEEDED(hres))
119 hres = StrRetToStrW(&strret, child_pidl, &item->pszText);
120 if(FAILED(hres))
122 WINE_WARN("Could not get name for pidl\n");
123 return FALSE;
126 item->mask &= ~CBEIF_IMAGE;
127 hres = SHGetIDListFromObject( (IUnknown *)folder, &parent_pidl );
128 if (FAILED(hres)) return FALSE;
130 pidl = ILCombine( parent_pidl, child_pidl );
131 if (pidl)
133 list = (IImageList *)SHGetFileInfoW( (WCHAR *)pidl, 0, &info, sizeof(info),
134 SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_SYSICONINDEX );
135 if (list)
137 IImageList_Release( list );
138 item->iImage = info.iIcon;
139 item->mask |= CBEIF_IMAGE;
141 ILFree( pidl );
143 ILFree( parent_pidl );
145 return TRUE;
148 static void update_path_box(explorer_info *info)
150 COMBOBOXEXITEMW item;
151 COMBOBOXEXITEMW main_item;
152 IShellFolder *desktop;
153 IPersistFolder2 *persist;
154 LPITEMIDLIST desktop_pidl;
155 IEnumIDList *ids;
157 SendMessageW(info->path_box,CB_RESETCONTENT,0,0);
158 SHGetDesktopFolder(&desktop);
159 IShellFolder_QueryInterface(desktop,&IID_IPersistFolder2,(void**)&persist);
160 IPersistFolder2_GetCurFolder(persist,&desktop_pidl);
161 IPersistFolder2_Release(persist);
162 persist = NULL;
163 /*Add Desktop*/
164 item.iItem = -1;
165 item.mask = CBEIF_TEXT | CBEIF_INDENT | CBEIF_LPARAM;
166 item.iIndent = 0;
167 create_combobox_item(desktop,desktop_pidl,info->icon_list,&item);
168 item.lParam = (LPARAM)desktop_pidl;
169 SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item);
170 if(ILIsEqual(info->pidl,desktop_pidl))
171 main_item = item;
172 else
173 CoTaskMemFree(item.pszText);
174 /*Add all direct subfolders of Desktop*/
175 if(SUCCEEDED(IShellFolder_EnumObjects(desktop,NULL,SHCONTF_FOLDERS,&ids))
176 && ids!=NULL)
178 LPITEMIDLIST curr_pidl=NULL;
179 HRESULT hres;
181 item.iIndent = 1;
182 while(1)
184 ILFree(curr_pidl);
185 curr_pidl=NULL;
186 hres = IEnumIDList_Next(ids,1,&curr_pidl,NULL);
187 if(FAILED(hres) || hres == S_FALSE)
188 break;
189 if(!create_combobox_item(desktop,curr_pidl,info->icon_list,&item))
190 WINE_WARN("Could not create a combobox item\n");
191 else
193 LPITEMIDLIST full_pidl = ILCombine(desktop_pidl,curr_pidl);
194 item.lParam = (LPARAM)full_pidl;
195 SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item);
196 if(ILIsEqual(full_pidl,info->pidl))
197 main_item = item;
198 else if(ILIsParent(full_pidl,info->pidl,FALSE))
200 /*add all parents of the pidl passed in*/
201 LPITEMIDLIST next_pidl = ILFindChild(full_pidl,info->pidl);
202 IShellFolder *curr_folder = NULL, *temp;
203 hres = IShellFolder_BindToObject(desktop,curr_pidl,NULL,
204 &IID_IShellFolder,
205 (void**)&curr_folder);
206 if(FAILED(hres))
207 WINE_WARN("Could not get an IShellFolder\n");
208 while(!ILIsEmpty(next_pidl))
210 LPITEMIDLIST first = ILCloneFirst(next_pidl);
211 CoTaskMemFree(item.pszText);
212 if(!create_combobox_item(curr_folder,first,
213 info->icon_list,&item))
215 WINE_WARN("Could not create a combobox item\n");
216 break;
218 ++item.iIndent;
219 full_pidl = ILCombine(full_pidl,first);
220 item.lParam = (LPARAM)full_pidl;
221 SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item);
222 temp=NULL;
223 hres = IShellFolder_BindToObject(curr_folder,first,NULL,
224 &IID_IShellFolder,
225 (void**)&temp);
226 if(FAILED(hres))
228 WINE_WARN("Could not get an IShellFolder\n");
229 break;
231 IShellFolder_Release(curr_folder);
232 curr_folder = temp;
234 ILFree(first);
235 next_pidl = ILGetNext(next_pidl);
237 memcpy(&main_item,&item,sizeof(item));
238 if(curr_folder)
239 IShellFolder_Release(curr_folder);
240 item.iIndent = 1;
242 else
243 CoTaskMemFree(item.pszText);
246 ILFree(curr_pidl);
247 IEnumIDList_Release(ids);
249 else
250 WINE_WARN("Could not enumerate the desktop\n");
251 SendMessageW(info->path_box,CBEM_SETITEMW,0,(LPARAM)&main_item);
252 CoTaskMemFree(main_item.pszText);
255 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnNavigationComplete(IExplorerBrowserEvents *iface, PCIDLIST_ABSOLUTE pidl)
257 IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
258 ILFree(This->info->pidl);
259 This->info->pidl = ILClone(pidl);
260 update_path_box(This->info);
261 return S_OK;
264 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnNavigationFailed(IExplorerBrowserEvents *iface, PCIDLIST_ABSOLUTE pidl)
266 return S_OK;
269 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnNavigationPending(IExplorerBrowserEvents *iface, PCIDLIST_ABSOLUTE pidl)
271 return S_OK;
274 static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnViewCreated(IExplorerBrowserEvents *iface, IShellView *psv)
276 return S_OK;
279 static IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents =
281 IExplorerBrowserEventsImpl_fnQueryInterface,
282 IExplorerBrowserEventsImpl_fnAddRef,
283 IExplorerBrowserEventsImpl_fnRelease,
284 IExplorerBrowserEventsImpl_fnOnNavigationPending,
285 IExplorerBrowserEventsImpl_fnOnViewCreated,
286 IExplorerBrowserEventsImpl_fnOnNavigationComplete,
287 IExplorerBrowserEventsImpl_fnOnNavigationFailed
290 static IExplorerBrowserEvents *make_explorer_events(explorer_info *info)
292 IExplorerBrowserEventsImpl *ret
293 = HeapAlloc(GetProcessHeap(), 0, sizeof(IExplorerBrowserEventsImpl));
294 ret->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents;
295 ret->info = info;
296 ret->ref = 1;
297 SHGetImageList(SHIL_SMALL,&IID_IImageList,(void**)&(ret->info->icon_list));
298 SendMessageW(info->path_box,CBEM_SETIMAGELIST,0,(LPARAM)ret->info->icon_list);
299 return &ret->IExplorerBrowserEvents_iface;
302 static void make_explorer_window(IShellFolder* startFolder)
304 RECT rect;
305 HWND rebar,nav_toolbar;
306 FOLDERSETTINGS fs;
307 IExplorerBrowserEvents *events;
308 explorer_info *info;
309 HRESULT hres;
310 WCHAR explorer_title[100];
311 WCHAR pathbox_label[50];
312 TBADDBITMAP bitmap_info;
313 TBBUTTON nav_buttons[3];
314 int hist_offset,view_offset;
315 REBARBANDINFOW band_info;
316 memset(nav_buttons,0,sizeof(nav_buttons));
317 LoadStringW(explorer_hInstance,IDS_EXPLORER_TITLE,explorer_title,
318 sizeof(explorer_title)/sizeof(WCHAR));
319 LoadStringW(explorer_hInstance,IDS_PATHBOX_LABEL,pathbox_label,
320 sizeof(pathbox_label)/sizeof(WCHAR));
321 info = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(explorer_info));
322 if(!info)
324 WINE_ERR("Could not allocate an explorer_info struct\n");
325 return;
327 hres = CoCreateInstance(&CLSID_ExplorerBrowser,NULL,CLSCTX_INPROC_SERVER,
328 &IID_IExplorerBrowser,(LPVOID*)&info->browser);
329 if(FAILED(hres))
331 WINE_ERR("Could not obtain an instance of IExplorerBrowser\n");
332 HeapFree(GetProcessHeap(),0,info);
333 return;
335 info->rebar_height=0;
336 info->main_window
337 = CreateWindowW(EXPLORER_CLASS,explorer_title,WS_OVERLAPPEDWINDOW,
338 CW_USEDEFAULT,CW_USEDEFAULT,DEFAULT_WIDTH,
339 DEFAULT_HEIGHT,NULL,NULL,explorer_hInstance,NULL);
341 fs.ViewMode = FVM_DETAILS;
342 fs.fFlags = FWF_AUTOARRANGE;
344 SetRect(&rect, 0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT);
345 IExplorerBrowser_Initialize(info->browser,info->main_window,&rect,&fs);
346 IExplorerBrowser_SetOptions(info->browser,EBO_SHOWFRAMES);
347 SetWindowLongPtrW(info->main_window,EXPLORER_INFO_INDEX,(LONG_PTR)info);
349 /*setup navbar*/
350 rebar = CreateWindowExW(WS_EX_TOOLWINDOW,REBARCLASSNAMEW,NULL,
351 WS_CHILD|WS_VISIBLE|RBS_VARHEIGHT|CCS_TOP|CCS_NODIVIDER,
352 0,0,0,0,info->main_window,NULL,explorer_hInstance,NULL);
353 nav_toolbar
354 = CreateWindowExW(TBSTYLE_EX_MIXEDBUTTONS,TOOLBARCLASSNAMEW,NULL,
355 WS_CHILD|WS_VISIBLE|TBSTYLE_FLAT,0,0,0,0,rebar,NULL,
356 explorer_hInstance,NULL);
358 bitmap_info.hInst = HINST_COMMCTRL;
359 bitmap_info.nID = IDB_HIST_LARGE_COLOR;
360 hist_offset= SendMessageW(nav_toolbar,TB_ADDBITMAP,0,(LPARAM)&bitmap_info);
361 bitmap_info.nID = IDB_VIEW_LARGE_COLOR;
362 view_offset= SendMessageW(nav_toolbar,TB_ADDBITMAP,0,(LPARAM)&bitmap_info);
364 nav_buttons[0].iBitmap=hist_offset+HIST_BACK;
365 nav_buttons[0].idCommand=BACK_BUTTON;
366 nav_buttons[0].fsState=TBSTATE_ENABLED;
367 nav_buttons[0].fsStyle=BTNS_BUTTON|BTNS_AUTOSIZE;
368 nav_buttons[1].iBitmap=hist_offset+HIST_FORWARD;
369 nav_buttons[1].idCommand=FORWARD_BUTTON;
370 nav_buttons[1].fsState=TBSTATE_ENABLED;
371 nav_buttons[1].fsStyle=BTNS_BUTTON|BTNS_AUTOSIZE;
372 nav_buttons[2].iBitmap=view_offset+VIEW_PARENTFOLDER;
373 nav_buttons[2].idCommand=UP_BUTTON;
374 nav_buttons[2].fsState=TBSTATE_ENABLED;
375 nav_buttons[2].fsStyle=BTNS_BUTTON|BTNS_AUTOSIZE;
376 SendMessageW(nav_toolbar,TB_BUTTONSTRUCTSIZE,sizeof(TBBUTTON),0);
377 SendMessageW(nav_toolbar,TB_ADDBUTTONSW,sizeof(nav_buttons)/sizeof(TBBUTTON),(LPARAM)nav_buttons);
379 band_info.cbSize = sizeof(band_info);
380 band_info.fMask = RBBIM_STYLE|RBBIM_CHILD|RBBIM_CHILDSIZE|RBBIM_SIZE;
381 band_info.hwndChild = nav_toolbar;
382 band_info.fStyle=RBBS_GRIPPERALWAYS|RBBS_CHILDEDGE;
383 band_info.cyChild=NAV_TOOLBAR_HEIGHT;
384 band_info.cx=0;
385 band_info.cyMinChild=NAV_TOOLBAR_HEIGHT;
386 band_info.cxMinChild=0;
387 SendMessageW(rebar,RB_INSERTBANDW,-1,(LPARAM)&band_info);
388 info->path_box = CreateWindowW(WC_COMBOBOXEXW,PATH_BOX_NAME,
389 WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
390 0,0,DEFAULT_WIDTH,PATHBOX_HEIGHT,rebar,NULL,
391 explorer_hInstance,NULL);
392 GetWindowRect(info->path_box, &rect);
393 band_info.cyChild = rect.bottom - rect.top;
394 band_info.cx=0;
395 band_info.cyMinChild = rect.bottom - rect.top;
396 band_info.cxMinChild=0;
397 band_info.fMask|=RBBIM_TEXT;
398 band_info.lpText=pathbox_label;
399 band_info.fStyle|=RBBS_BREAK;
400 band_info.hwndChild=info->path_box;
401 SendMessageW(rebar,RB_INSERTBANDW,-1,(LPARAM)&band_info);
402 events = make_explorer_events(info);
403 IExplorerBrowser_Advise(info->browser,events,&info->advise_cookie);
404 IExplorerBrowser_BrowseToObject(info->browser,(IUnknown*)startFolder,
405 SBSP_ABSOLUTE);
406 ShowWindow(info->main_window,SW_SHOWDEFAULT);
407 UpdateWindow(info->main_window);
408 IExplorerBrowserEvents_Release(events);
411 static void update_window_size(explorer_info *info, int height, int width)
413 RECT new_rect;
414 new_rect.left = 0;
415 new_rect.top = info->rebar_height;
416 new_rect.right = width;
417 new_rect.bottom = height;
418 IExplorerBrowser_SetRect(info->browser,NULL,new_rect);
421 static void do_exit(int code)
423 OleUninitialize();
424 ExitProcess(code);
427 static LRESULT explorer_on_end_edit(explorer_info *info,NMCBEENDEDITW *edit_info)
429 LPITEMIDLIST pidl = NULL;
431 WINE_TRACE("iWhy=%x\n",edit_info->iWhy);
432 switch(edit_info->iWhy)
434 case CBENF_DROPDOWN:
435 if(edit_info->iNewSelection!=CB_ERR)
436 pidl = (LPITEMIDLIST)SendMessageW(edit_info->hdr.hwndFrom,
437 CB_GETITEMDATA,
438 edit_info->iNewSelection,0);
439 break;
440 case CBENF_RETURN:
442 WCHAR path[MAX_PATH];
443 HWND edit_ctrl = (HWND)SendMessageW(edit_info->hdr.hwndFrom,
444 CBEM_GETEDITCONTROL,0,0);
445 *((WORD*)path)=MAX_PATH;
446 SendMessageW(edit_ctrl,EM_GETLINE,0,(LPARAM)path);
447 pidl = ILCreateFromPathW(path);
448 break;
450 case CBENF_ESCAPE:
451 /*make sure the that the path box resets*/
452 update_path_box(info);
453 return 0;
454 default:
455 return 0;
457 if(pidl)
458 IExplorerBrowser_BrowseToIDList(info->browser,pidl,SBSP_ABSOLUTE);
459 if(edit_info->iWhy==CBENF_RETURN)
460 ILFree(pidl);
461 return 0;
464 static LRESULT update_rebar_size(explorer_info* info,NMRBAUTOSIZE *size_info)
466 RECT new_rect;
467 RECT window_rect;
468 info->rebar_height = size_info->rcTarget.bottom-size_info->rcTarget.top;
469 GetWindowRect(info->main_window,&window_rect);
470 new_rect.left = 0;
471 new_rect.top = info->rebar_height;
472 new_rect.right = window_rect.right-window_rect.left;
473 new_rect.bottom = window_rect.bottom-window_rect.top;
474 IExplorerBrowser_SetRect(info->browser,NULL,new_rect);
475 return 0;
478 static LRESULT explorer_on_notify(explorer_info* info,NMHDR* notification)
480 WINE_TRACE("code=%i\n",notification->code);
481 switch(notification->code)
483 case CBEN_BEGINEDIT:
485 WCHAR path[MAX_PATH];
486 HWND edit_ctrl = (HWND)SendMessageW(notification->hwndFrom,
487 CBEM_GETEDITCONTROL,0,0);
488 SHGetPathFromIDListW(info->pidl,path);
489 SetWindowTextW(edit_ctrl,path);
490 break;
492 case CBEN_ENDEDITA:
494 NMCBEENDEDITA *edit_info_a = (NMCBEENDEDITA*)notification;
495 NMCBEENDEDITW edit_info_w;
496 edit_info_w.hdr = edit_info_a->hdr;
497 edit_info_w.fChanged = edit_info_a->fChanged;
498 edit_info_w.iNewSelection = edit_info_a->iNewSelection;
499 MultiByteToWideChar(CP_ACP,0,edit_info_a->szText,-1,
500 edit_info_w.szText,CBEMAXSTRLEN);
501 edit_info_w.iWhy = edit_info_a->iWhy;
502 return explorer_on_end_edit(info,&edit_info_w);
504 case CBEN_ENDEDITW:
505 return explorer_on_end_edit(info,(NMCBEENDEDITW*)notification);
506 case CBEN_DELETEITEM:
508 NMCOMBOBOXEXW *entry = (NMCOMBOBOXEXW*)notification;
509 if(entry->ceItem.lParam)
510 ILFree((LPITEMIDLIST)entry->ceItem.lParam);
511 break;
513 case RBN_AUTOSIZE:
514 return update_rebar_size(info,(NMRBAUTOSIZE*)notification);
515 default:
516 break;
518 return 0;
521 static LRESULT CALLBACK explorer_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
523 explorer_info *info
524 = (explorer_info*)GetWindowLongPtrW(hwnd,EXPLORER_INFO_INDEX);
525 IExplorerBrowser *browser = NULL;
527 WINE_TRACE("(hwnd=%p,uMsg=%u,wParam=%lx,lParam=%lx)\n",hwnd,uMsg,wParam,lParam);
528 if(info)
529 browser = info->browser;
530 switch(uMsg)
532 case WM_DESTROY:
533 IExplorerBrowser_Unadvise(browser,info->advise_cookie);
534 IExplorerBrowser_Destroy(browser);
535 IExplorerBrowser_Release(browser);
536 ILFree(info->pidl);
537 IImageList_Release(info->icon_list);
538 HeapFree(GetProcessHeap(),0,info);
539 SetWindowLongPtrW(hwnd,EXPLORER_INFO_INDEX,0);
540 PostQuitMessage(0);
541 break;
542 case WM_QUIT:
543 do_exit(wParam);
544 case WM_NOTIFY:
545 return explorer_on_notify(info,(NMHDR*)lParam);
546 case WM_COMMAND:
547 if(HIWORD(wParam)==BN_CLICKED)
549 switch(LOWORD(wParam))
551 case BACK_BUTTON:
552 IExplorerBrowser_BrowseToObject(browser,NULL,SBSP_NAVIGATEBACK);
553 break;
554 case FORWARD_BUTTON:
555 IExplorerBrowser_BrowseToObject(browser,NULL,SBSP_NAVIGATEFORWARD);
556 break;
557 case UP_BUTTON:
558 IExplorerBrowser_BrowseToObject(browser,NULL,SBSP_PARENT);
559 break;
562 break;
563 case WM_SIZE:
564 update_window_size(info,HIWORD(lParam),LOWORD(lParam));
565 break;
566 default:
567 return DefWindowProcW(hwnd,uMsg,wParam,lParam);
569 return 0;
572 static void register_explorer_window_class(void)
574 WNDCLASSEXW window_class;
575 window_class.cbSize = sizeof(WNDCLASSEXW);
576 window_class.style = 0;
577 window_class.cbClsExtra = 0;
578 window_class.cbWndExtra = sizeof(LONG_PTR);
579 window_class.lpfnWndProc = explorer_wnd_proc;
580 window_class.hInstance = explorer_hInstance;
581 window_class.hIcon = NULL;
582 window_class.hCursor = NULL;
583 window_class.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
584 window_class.lpszMenuName = NULL;
585 window_class.lpszClassName = EXPLORER_CLASS;
586 window_class.hIconSm = NULL;
587 RegisterClassExW(&window_class);
590 static IShellFolder* get_starting_shell_folder(parameters_struct* params)
592 IShellFolder* desktop,*folder;
593 LPITEMIDLIST root_pidl;
594 HRESULT hres;
596 SHGetDesktopFolder(&desktop);
597 if (!params->root[0])
599 return desktop;
601 hres = IShellFolder_ParseDisplayName(desktop,NULL,NULL,
602 params->root,NULL,
603 &root_pidl,NULL);
605 if(FAILED(hres))
607 return desktop;
609 hres = IShellFolder_BindToObject(desktop,root_pidl,NULL,
610 &IID_IShellFolder,
611 (void**)&folder);
612 if(FAILED(hres))
614 return desktop;
616 IShellFolder_Release(desktop);
617 return folder;
620 static int copy_path_string(LPWSTR target, LPWSTR source)
622 INT i = 0;
624 while (isspaceW(*source)) source++;
626 if (*source == '\"')
628 source ++;
629 while (*source != '\"') target[i++] = *source++;
630 target[i] = 0;
631 source ++;
632 i+=2;
634 else
636 while (*source && *source != ',') target[i++] = *source++;
637 target[i] = 0;
639 PathRemoveBackslashW(target);
640 return i;
644 static void copy_path_root(LPWSTR root, LPWSTR path)
646 LPWSTR p,p2;
647 INT i = 0;
649 p = path;
650 while (*p!=0)
651 p++;
653 while (*p!='\\' && p > path)
654 p--;
656 if (p == path)
657 return;
659 p2 = path;
660 while (p2 != p)
662 root[i] = *p2;
663 i++;
664 p2++;
666 root[i] = 0;
670 * Command Line parameters are:
671 * [/n] Opens in single-paned view for each selected items. This is default
672 * [/e,] Uses Windows Explorer View
673 * [/root,object] Specifies the root level of the view
674 * [/select,object] parent folder is opened and specified object is selected
676 static void parse_command_line(LPWSTR commandline,parameters_struct *parameters)
678 static const WCHAR arg_n[] = {'/','n'};
679 static const WCHAR arg_e[] = {'/','e',','};
680 static const WCHAR arg_root[] = {'/','r','o','o','t',','};
681 static const WCHAR arg_select[] = {'/','s','e','l','e','c','t',','};
682 static const WCHAR arg_desktop[] = {'/','d','e','s','k','t','o','p'};
683 static const WCHAR arg_desktop_quotes[] = {'"','/','d','e','s','k','t','o','p'};
685 LPWSTR p = commandline;
687 while (*p)
689 while (isspaceW(*p)) p++;
690 if (strncmpW(p, arg_n, sizeof(arg_n)/sizeof(WCHAR))==0)
692 parameters->explorer_mode = FALSE;
693 p += sizeof(arg_n)/sizeof(WCHAR);
695 else if (strncmpW(p, arg_e, sizeof(arg_e)/sizeof(WCHAR))==0)
697 parameters->explorer_mode = TRUE;
698 p += sizeof(arg_e)/sizeof(WCHAR);
700 else if (strncmpW(p, arg_root, sizeof(arg_root)/sizeof(WCHAR))==0)
702 p += sizeof(arg_root)/sizeof(WCHAR);
703 p+=copy_path_string(parameters->root,p);
705 else if (strncmpW(p, arg_select, sizeof(arg_select)/sizeof(WCHAR))==0)
707 p += sizeof(arg_select)/sizeof(WCHAR);
708 p+=copy_path_string(parameters->selection,p);
709 if (!parameters->root[0])
710 copy_path_root(parameters->root,
711 parameters->selection);
713 else if (strncmpW(p, arg_desktop, sizeof(arg_desktop)/sizeof(WCHAR))==0)
715 p += sizeof(arg_desktop)/sizeof(WCHAR);
716 manage_desktop( p ); /* the rest of the command line is handled by desktop mode */
718 /* workaround for Worms Armageddon that hardcodes a /desktop option with quotes */
719 else if (strncmpW(p, arg_desktop_quotes, sizeof(arg_desktop_quotes)/sizeof(WCHAR))==0)
721 p += sizeof(arg_desktop_quotes)/sizeof(WCHAR);
722 manage_desktop( p ); /* the rest of the command line is handled by desktop mode */
724 else
726 /* left over command line is generally the path to be opened */
727 copy_path_string(parameters->root,p);
728 break;
733 int WINAPI wWinMain(HINSTANCE hinstance,
734 HINSTANCE previnstance,
735 LPWSTR cmdline,
736 int cmdshow)
739 parameters_struct parameters;
740 HRESULT hres;
741 MSG msg;
742 IShellFolder *folder;
743 INITCOMMONCONTROLSEX init_info;
745 memset(&parameters,0,sizeof(parameters));
746 explorer_hInstance = hinstance;
747 parse_command_line(cmdline,&parameters);
748 hres = OleInitialize(NULL);
749 if(FAILED(hres))
751 WINE_ERR("Could not initialize COM\n");
752 ExitProcess(EXIT_FAILURE);
754 if(parameters.root[0] && !PathIsDirectoryW(parameters.root))
755 if(ShellExecuteW(NULL,NULL,parameters.root,NULL,NULL,SW_SHOWDEFAULT) > (HINSTANCE)32)
756 ExitProcess(EXIT_SUCCESS);
757 init_info.dwSize = sizeof(INITCOMMONCONTROLSEX);
758 init_info.dwICC = ICC_USEREX_CLASSES | ICC_BAR_CLASSES | ICC_COOL_CLASSES;
759 if(!InitCommonControlsEx(&init_info))
761 WINE_ERR("Could not initialize Comctl\n");
762 ExitProcess(EXIT_FAILURE);
764 register_explorer_window_class();
765 folder = get_starting_shell_folder(&parameters);
766 make_explorer_window(folder);
767 IShellFolder_Release(folder);
768 while(GetMessageW( &msg, NULL, 0, 0 ) != 0)
770 TranslateMessage(&msg);
771 DispatchMessageW(&msg);
773 return 0;