explorer.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885
  1. /*
  2. * explorer.exe
  3. *
  4. * Copyright 2004 CodeWeavers, Mike Hearn
  5. * Copyright 2005,2006 CodeWeavers, Aric Stewart
  6. * Copyright 2011 Jay Yang
  7. *
  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.
  12. *
  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.
  17. *
  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
  21. */
  22. #define COBJMACROS
  23. #include "wine/debug.h"
  24. #include "wine/heap.h"
  25. #include "explorer_private.h"
  26. #include "resource.h"
  27. #include <initguid.h>
  28. #include <windows.h>
  29. #include <shellapi.h>
  30. #include <shobjidl.h>
  31. #include <shlobj.h>
  32. #include <shlwapi.h>
  33. #include <commoncontrols.h>
  34. #include <commctrl.h>
  35. WINE_DEFAULT_DEBUG_CHANNEL(explorer);
  36. #define EXPLORER_INFO_INDEX 0
  37. #define NAV_TOOLBAR_HEIGHT 30
  38. #define PATHBOX_HEIGHT 24
  39. static int nav_toolbar_height;
  40. static int pathbox_height;
  41. #define DEFAULT_WIDTH 640
  42. #define DEFAULT_HEIGHT 480
  43. static int default_width;
  44. static int default_height;
  45. static const WCHAR EXPLORER_CLASS[] = {'E','x','p','l','o','r','e','r','W','C','l','a','s','s',0};
  46. static const WCHAR PATH_BOX_NAME[] = {'\0'};
  47. HINSTANCE explorer_hInstance;
  48. typedef struct parametersTAG {
  49. BOOL explorer_mode;
  50. WCHAR root[MAX_PATH];
  51. WCHAR selection[MAX_PATH];
  52. } parameters_struct;
  53. typedef struct
  54. {
  55. IExplorerBrowser *browser;
  56. HWND main_window,path_box;
  57. INT rebar_height;
  58. LPITEMIDLIST pidl;
  59. IImageList *icon_list;
  60. DWORD advise_cookie;
  61. IShellWindows *sw;
  62. LONG sw_cookie;
  63. } explorer_info;
  64. enum
  65. {
  66. BACK_BUTTON,FORWARD_BUTTON,UP_BUTTON
  67. };
  68. static void variant_from_pidl(VARIANT *var, const ITEMIDLIST *pidl)
  69. {
  70. V_VT(var) = VT_ARRAY | VT_UI1;
  71. V_ARRAY(var) = SafeArrayCreateVector(VT_UI1, 0, ILGetSize(pidl));
  72. memcpy(V_ARRAY(var)->pvData, pidl, ILGetSize(pidl));
  73. }
  74. typedef struct
  75. {
  76. IExplorerBrowserEvents IExplorerBrowserEvents_iface;
  77. explorer_info* info;
  78. LONG ref;
  79. } IExplorerBrowserEventsImpl;
  80. static IExplorerBrowserEventsImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
  81. {
  82. return CONTAINING_RECORD(iface, IExplorerBrowserEventsImpl, IExplorerBrowserEvents_iface);
  83. }
  84. static HRESULT WINAPI IExplorerBrowserEventsImpl_fnQueryInterface(IExplorerBrowserEvents *iface, REFIID riid, void **ppvObject)
  85. {
  86. return E_NOINTERFACE;
  87. }
  88. static ULONG WINAPI IExplorerBrowserEventsImpl_fnAddRef(IExplorerBrowserEvents *iface)
  89. {
  90. IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
  91. return InterlockedIncrement(&This->ref);
  92. }
  93. static ULONG WINAPI IExplorerBrowserEventsImpl_fnRelease(IExplorerBrowserEvents *iface)
  94. {
  95. IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
  96. ULONG ref = InterlockedDecrement(&This->ref);
  97. if(!ref)
  98. HeapFree(GetProcessHeap(),0,This);
  99. return ref;
  100. }
  101. static BOOL create_combobox_item(IShellFolder *folder, LPCITEMIDLIST child_pidl, IImageList *icon_list, COMBOBOXEXITEMW *item)
  102. {
  103. STRRET strret;
  104. HRESULT hres;
  105. PIDLIST_ABSOLUTE parent_pidl, pidl;
  106. SHFILEINFOW info;
  107. IImageList *list;
  108. strret.uType=STRRET_WSTR;
  109. hres = IShellFolder_GetDisplayNameOf( folder, child_pidl, SHGDN_FORADDRESSBAR, &strret );
  110. if(SUCCEEDED(hres))
  111. hres = StrRetToStrW(&strret, child_pidl, &item->pszText);
  112. if(FAILED(hres))
  113. {
  114. WINE_WARN("Could not get name for pidl\n");
  115. return FALSE;
  116. }
  117. item->mask &= ~CBEIF_IMAGE;
  118. hres = SHGetIDListFromObject( (IUnknown *)folder, &parent_pidl );
  119. if (FAILED(hres)) return FALSE;
  120. pidl = ILCombine( parent_pidl, child_pidl );
  121. if (pidl)
  122. {
  123. list = (IImageList *)SHGetFileInfoW( (WCHAR *)pidl, 0, &info, sizeof(info),
  124. SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_SYSICONINDEX );
  125. if (list)
  126. {
  127. IImageList_Release( list );
  128. item->iImage = info.iIcon;
  129. item->mask |= CBEIF_IMAGE;
  130. }
  131. ILFree( pidl );
  132. }
  133. ILFree( parent_pidl );
  134. return TRUE;
  135. }
  136. static void update_path_box(explorer_info *info)
  137. {
  138. COMBOBOXEXITEMW item;
  139. COMBOBOXEXITEMW main_item;
  140. IShellFolder *desktop;
  141. IPersistFolder2 *persist;
  142. LPITEMIDLIST desktop_pidl;
  143. IEnumIDList *ids;
  144. SendMessageW(info->path_box,CB_RESETCONTENT,0,0);
  145. SHGetDesktopFolder(&desktop);
  146. IShellFolder_QueryInterface(desktop,&IID_IPersistFolder2,(void**)&persist);
  147. IPersistFolder2_GetCurFolder(persist,&desktop_pidl);
  148. IPersistFolder2_Release(persist);
  149. persist = NULL;
  150. /*Add Desktop*/
  151. item.iItem = -1;
  152. item.mask = CBEIF_TEXT | CBEIF_INDENT | CBEIF_LPARAM;
  153. item.iIndent = 0;
  154. create_combobox_item(desktop,desktop_pidl,info->icon_list,&item);
  155. item.lParam = (LPARAM)desktop_pidl;
  156. SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item);
  157. if(ILIsEqual(info->pidl,desktop_pidl))
  158. main_item = item;
  159. else
  160. CoTaskMemFree(item.pszText);
  161. /*Add all direct subfolders of Desktop*/
  162. if(SUCCEEDED(IShellFolder_EnumObjects(desktop,NULL,SHCONTF_FOLDERS,&ids))
  163. && ids!=NULL)
  164. {
  165. LPITEMIDLIST curr_pidl=NULL;
  166. HRESULT hres;
  167. item.iIndent = 1;
  168. while(1)
  169. {
  170. ILFree(curr_pidl);
  171. curr_pidl=NULL;
  172. hres = IEnumIDList_Next(ids,1,&curr_pidl,NULL);
  173. if(FAILED(hres) || hres == S_FALSE)
  174. break;
  175. if(!create_combobox_item(desktop,curr_pidl,info->icon_list,&item))
  176. WINE_WARN("Could not create a combobox item\n");
  177. else
  178. {
  179. LPITEMIDLIST full_pidl = ILCombine(desktop_pidl,curr_pidl);
  180. item.lParam = (LPARAM)full_pidl;
  181. SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item);
  182. if(ILIsEqual(full_pidl,info->pidl))
  183. main_item = item;
  184. else if(ILIsParent(full_pidl,info->pidl,FALSE))
  185. {
  186. /*add all parents of the pidl passed in*/
  187. LPITEMIDLIST next_pidl = ILFindChild(full_pidl,info->pidl);
  188. IShellFolder *curr_folder = NULL, *temp;
  189. hres = IShellFolder_BindToObject(desktop,curr_pidl,NULL,
  190. &IID_IShellFolder,
  191. (void**)&curr_folder);
  192. if(FAILED(hres))
  193. WINE_WARN("Could not get an IShellFolder\n");
  194. while(!ILIsEmpty(next_pidl))
  195. {
  196. LPITEMIDLIST first = ILCloneFirst(next_pidl);
  197. CoTaskMemFree(item.pszText);
  198. if(!create_combobox_item(curr_folder,first,
  199. info->icon_list,&item))
  200. {
  201. WINE_WARN("Could not create a combobox item\n");
  202. break;
  203. }
  204. ++item.iIndent;
  205. full_pidl = ILCombine(full_pidl,first);
  206. item.lParam = (LPARAM)full_pidl;
  207. SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item);
  208. temp=NULL;
  209. hres = IShellFolder_BindToObject(curr_folder,first,NULL,
  210. &IID_IShellFolder,
  211. (void**)&temp);
  212. if(FAILED(hres))
  213. {
  214. WINE_WARN("Could not get an IShellFolder\n");
  215. break;
  216. }
  217. IShellFolder_Release(curr_folder);
  218. curr_folder = temp;
  219. ILFree(first);
  220. next_pidl = ILGetNext(next_pidl);
  221. }
  222. memcpy(&main_item,&item,sizeof(item));
  223. if(curr_folder)
  224. IShellFolder_Release(curr_folder);
  225. item.iIndent = 1;
  226. }
  227. else
  228. CoTaskMemFree(item.pszText);
  229. }
  230. }
  231. ILFree(curr_pidl);
  232. IEnumIDList_Release(ids);
  233. }
  234. else
  235. WINE_WARN("Could not enumerate the desktop\n");
  236. SendMessageW(info->path_box,CBEM_SETITEMW,0,(LPARAM)&main_item);
  237. CoTaskMemFree(main_item.pszText);
  238. }
  239. static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnNavigationComplete(IExplorerBrowserEvents *iface, PCIDLIST_ABSOLUTE pidl)
  240. {
  241. IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
  242. IShellFolder *parent;
  243. PCUITEMID_CHILD child_pidl;
  244. HRESULT hres;
  245. STRRET strret;
  246. WCHAR *name;
  247. if (This->info->sw)
  248. {
  249. VARIANT var;
  250. variant_from_pidl(&var, pidl);
  251. IShellWindows_OnNavigate(This->info->sw, This->info->sw_cookie, &var);
  252. VariantClear(&var);
  253. }
  254. ILFree(This->info->pidl);
  255. This->info->pidl = ILClone(pidl);
  256. update_path_box(This->info);
  257. hres = SHBindToParent(pidl, &IID_IShellFolder, (void **)&parent, &child_pidl);
  258. if (SUCCEEDED(hres))
  259. {
  260. hres = IShellFolder_GetDisplayNameOf(parent, child_pidl, SHGDN_FORADDRESSBAR, &strret);
  261. if (SUCCEEDED(hres))
  262. hres = StrRetToStrW(&strret, child_pidl, &name);
  263. if (SUCCEEDED(hres))
  264. {
  265. SetWindowTextW(This->info->main_window, name);
  266. CoTaskMemFree(name);
  267. }
  268. IShellFolder_Release(parent);
  269. }
  270. return hres;
  271. }
  272. static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnNavigationFailed(IExplorerBrowserEvents *iface, PCIDLIST_ABSOLUTE pidl)
  273. {
  274. return S_OK;
  275. }
  276. static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnNavigationPending(IExplorerBrowserEvents *iface, PCIDLIST_ABSOLUTE pidl)
  277. {
  278. return S_OK;
  279. }
  280. static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnViewCreated(IExplorerBrowserEvents *iface, IShellView *psv)
  281. {
  282. return S_OK;
  283. }
  284. static IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents =
  285. {
  286. IExplorerBrowserEventsImpl_fnQueryInterface,
  287. IExplorerBrowserEventsImpl_fnAddRef,
  288. IExplorerBrowserEventsImpl_fnRelease,
  289. IExplorerBrowserEventsImpl_fnOnNavigationPending,
  290. IExplorerBrowserEventsImpl_fnOnViewCreated,
  291. IExplorerBrowserEventsImpl_fnOnNavigationComplete,
  292. IExplorerBrowserEventsImpl_fnOnNavigationFailed
  293. };
  294. static IExplorerBrowserEvents *make_explorer_events(explorer_info *info)
  295. {
  296. IExplorerBrowserEventsImpl *ret
  297. = HeapAlloc(GetProcessHeap(), 0, sizeof(IExplorerBrowserEventsImpl));
  298. ret->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents;
  299. ret->info = info;
  300. ret->ref = 1;
  301. SHGetImageList(SHIL_SMALL,&IID_IImageList,(void**)&(ret->info->icon_list));
  302. SendMessageW(info->path_box,CBEM_SETIMAGELIST,0,(LPARAM)ret->info->icon_list);
  303. return &ret->IExplorerBrowserEvents_iface;
  304. }
  305. static IShellFolder *get_starting_shell_folder(WCHAR *path)
  306. {
  307. IShellFolder* desktop,*folder;
  308. LPITEMIDLIST root_pidl;
  309. HRESULT hres;
  310. SHGetDesktopFolder(&desktop);
  311. if (!path)
  312. return desktop;
  313. hres = IShellFolder_ParseDisplayName(desktop, NULL, NULL, path, NULL, &root_pidl, NULL);
  314. if(FAILED(hres))
  315. {
  316. return desktop;
  317. }
  318. hres = IShellFolder_BindToObject(desktop,root_pidl,NULL,
  319. &IID_IShellFolder,
  320. (void**)&folder);
  321. ILFree(root_pidl);
  322. if(FAILED(hres))
  323. {
  324. return desktop;
  325. }
  326. IShellFolder_Release(desktop);
  327. return folder;
  328. }
  329. static void make_explorer_window(parameters_struct *params)
  330. {
  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. VARIANT var, empty_var;
  344. IShellFolder *folder;
  345. IDispatch *dispatch;
  346. WCHAR *path = NULL;
  347. IShellWindows *sw;
  348. ITEMIDLIST *pidl;
  349. UINT dpix, dpiy;
  350. DWORD size;
  351. LONG hwnd;
  352. HDC hdc;
  353. MSG msg;
  354. CoCreateInstance(&CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER,
  355. &IID_IShellWindows, (void **)&sw);
  356. if (params->root[0])
  357. {
  358. size = GetFullPathNameW(params->root, 0, NULL, NULL);
  359. path = malloc( size * sizeof(WCHAR) );
  360. GetFullPathNameW(params->root, size, path, NULL);
  361. }
  362. if (sw && path)
  363. {
  364. if (!(pidl = ILCreateFromPathW(path)))
  365. {
  366. ERR("Failed to create PIDL for %s.\n", debugstr_w(path));
  367. IShellWindows_Release(sw);
  368. return;
  369. }
  370. variant_from_pidl(&var, pidl);
  371. V_VT(&empty_var) = VT_EMPTY;
  372. if (IShellWindows_FindWindowSW(sw, &var, &empty_var, SWC_EXPLORER, &hwnd, 0, &dispatch) == S_OK)
  373. {
  374. TRACE("Found window %#x already browsing path %s.\n", hwnd, debugstr_w(path));
  375. SetForegroundWindow((HWND)(LONG_PTR)hwnd);
  376. IShellWindows_Release(sw);
  377. return;
  378. }
  379. ILFree(pidl);
  380. VariantClear(&var);
  381. }
  382. memset(nav_buttons,0,sizeof(nav_buttons));
  383. LoadStringW(explorer_hInstance,IDS_EXPLORER_TITLE,explorer_title, ARRAY_SIZE( explorer_title ));
  384. LoadStringW(explorer_hInstance,IDS_PATHBOX_LABEL,pathbox_label, ARRAY_SIZE( pathbox_label ));
  385. hdc = GetDC(0);
  386. dpix = GetDeviceCaps(hdc, LOGPIXELSX);
  387. dpiy = GetDeviceCaps(hdc, LOGPIXELSY);
  388. ReleaseDC(0, hdc);
  389. nav_toolbar_height = MulDiv(NAV_TOOLBAR_HEIGHT, dpiy, USER_DEFAULT_SCREEN_DPI);
  390. pathbox_height = MulDiv(PATHBOX_HEIGHT, dpiy, USER_DEFAULT_SCREEN_DPI);
  391. default_width = MulDiv(DEFAULT_WIDTH, dpix, USER_DEFAULT_SCREEN_DPI);
  392. default_height = MulDiv(DEFAULT_HEIGHT, dpiy, USER_DEFAULT_SCREEN_DPI);
  393. info = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(explorer_info));
  394. if(!info)
  395. {
  396. WINE_ERR("Could not allocate an explorer_info struct\n");
  397. return;
  398. }
  399. hres = CoCreateInstance(&CLSID_ExplorerBrowser,NULL,CLSCTX_INPROC_SERVER,
  400. &IID_IExplorerBrowser,(LPVOID*)&info->browser);
  401. if(FAILED(hres))
  402. {
  403. WINE_ERR("Could not obtain an instance of IExplorerBrowser\n");
  404. HeapFree(GetProcessHeap(),0,info);
  405. return;
  406. }
  407. info->rebar_height=0;
  408. info->main_window
  409. = CreateWindowW(EXPLORER_CLASS,explorer_title,WS_OVERLAPPEDWINDOW,
  410. CW_USEDEFAULT,CW_USEDEFAULT,default_width,
  411. default_height,NULL,NULL,explorer_hInstance,NULL);
  412. if (sw)
  413. {
  414. IShellWindows_Register(sw, NULL, (LONG_PTR)info->main_window, SWC_EXPLORER, &info->sw_cookie);
  415. info->sw = sw;
  416. }
  417. fs.ViewMode = FVM_DETAILS;
  418. fs.fFlags = FWF_AUTOARRANGE;
  419. SetRect(&rect, 0, 0, default_width, default_height);
  420. IExplorerBrowser_Initialize(info->browser,info->main_window,&rect,&fs);
  421. IExplorerBrowser_SetOptions(info->browser,EBO_SHOWFRAMES);
  422. SetWindowLongPtrW(info->main_window,EXPLORER_INFO_INDEX,(LONG_PTR)info);
  423. /*setup navbar*/
  424. rebar = CreateWindowExW(WS_EX_TOOLWINDOW,REBARCLASSNAMEW,NULL,
  425. WS_CHILD|WS_VISIBLE|RBS_VARHEIGHT|CCS_TOP|CCS_NODIVIDER,
  426. 0,0,0,0,info->main_window,NULL,explorer_hInstance,NULL);
  427. nav_toolbar
  428. = CreateWindowExW(TBSTYLE_EX_MIXEDBUTTONS,TOOLBARCLASSNAMEW,NULL,
  429. WS_CHILD|WS_VISIBLE|TBSTYLE_FLAT,0,0,0,0,rebar,NULL,
  430. explorer_hInstance,NULL);
  431. bitmap_info.hInst = HINST_COMMCTRL;
  432. bitmap_info.nID = IDB_HIST_LARGE_COLOR;
  433. hist_offset= SendMessageW(nav_toolbar,TB_ADDBITMAP,0,(LPARAM)&bitmap_info);
  434. bitmap_info.nID = IDB_VIEW_LARGE_COLOR;
  435. view_offset= SendMessageW(nav_toolbar,TB_ADDBITMAP,0,(LPARAM)&bitmap_info);
  436. nav_buttons[0].iBitmap=hist_offset+HIST_BACK;
  437. nav_buttons[0].idCommand=BACK_BUTTON;
  438. nav_buttons[0].fsState=TBSTATE_ENABLED;
  439. nav_buttons[0].fsStyle=BTNS_BUTTON|BTNS_AUTOSIZE;
  440. nav_buttons[1].iBitmap=hist_offset+HIST_FORWARD;
  441. nav_buttons[1].idCommand=FORWARD_BUTTON;
  442. nav_buttons[1].fsState=TBSTATE_ENABLED;
  443. nav_buttons[1].fsStyle=BTNS_BUTTON|BTNS_AUTOSIZE;
  444. nav_buttons[2].iBitmap=view_offset+VIEW_PARENTFOLDER;
  445. nav_buttons[2].idCommand=UP_BUTTON;
  446. nav_buttons[2].fsState=TBSTATE_ENABLED;
  447. nav_buttons[2].fsStyle=BTNS_BUTTON|BTNS_AUTOSIZE;
  448. SendMessageW(nav_toolbar,TB_BUTTONSTRUCTSIZE,sizeof(TBBUTTON),0);
  449. SendMessageW(nav_toolbar,TB_ADDBUTTONSW,ARRAY_SIZE( nav_buttons ),(LPARAM)nav_buttons);
  450. band_info.cbSize = sizeof(band_info);
  451. band_info.fMask = RBBIM_STYLE|RBBIM_CHILD|RBBIM_CHILDSIZE|RBBIM_SIZE;
  452. band_info.hwndChild = nav_toolbar;
  453. band_info.fStyle=RBBS_GRIPPERALWAYS|RBBS_CHILDEDGE;
  454. band_info.cyChild=nav_toolbar_height;
  455. band_info.cx=0;
  456. band_info.cyMinChild=nav_toolbar_height;
  457. band_info.cxMinChild=0;
  458. SendMessageW(rebar,RB_INSERTBANDW,-1,(LPARAM)&band_info);
  459. info->path_box = CreateWindowW(WC_COMBOBOXEXW,PATH_BOX_NAME,
  460. WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
  461. 0,0,default_width,pathbox_height,rebar,NULL,
  462. explorer_hInstance,NULL);
  463. GetWindowRect(info->path_box, &rect);
  464. band_info.cyChild = rect.bottom - rect.top;
  465. band_info.cx=0;
  466. band_info.cyMinChild = rect.bottom - rect.top;
  467. band_info.cxMinChild=0;
  468. band_info.fMask|=RBBIM_TEXT;
  469. band_info.lpText=pathbox_label;
  470. band_info.fStyle|=RBBS_BREAK;
  471. band_info.hwndChild=info->path_box;
  472. SendMessageW(rebar,RB_INSERTBANDW,-1,(LPARAM)&band_info);
  473. events = make_explorer_events(info);
  474. IExplorerBrowser_Advise(info->browser,events,&info->advise_cookie);
  475. folder = get_starting_shell_folder(path);
  476. IExplorerBrowser_BrowseToObject(info->browser, (IUnknown *)folder, SBSP_ABSOLUTE);
  477. IShellFolder_Release(folder);
  478. ShowWindow(info->main_window,SW_SHOWDEFAULT);
  479. UpdateWindow(info->main_window);
  480. IExplorerBrowserEvents_Release(events);
  481. while (GetMessageW(&msg, NULL, 0, 0))
  482. {
  483. TranslateMessage(&msg);
  484. DispatchMessageW(&msg);
  485. }
  486. }
  487. static void update_window_size(explorer_info *info, int height, int width)
  488. {
  489. RECT new_rect;
  490. new_rect.left = 0;
  491. new_rect.top = info->rebar_height;
  492. new_rect.right = width;
  493. new_rect.bottom = height;
  494. IExplorerBrowser_SetRect(info->browser,NULL,new_rect);
  495. }
  496. static void do_exit(int code)
  497. {
  498. OleUninitialize();
  499. ExitProcess(code);
  500. }
  501. static LRESULT explorer_on_end_edit(explorer_info *info,NMCBEENDEDITW *edit_info)
  502. {
  503. LPITEMIDLIST pidl = NULL;
  504. WINE_TRACE("iWhy=%x\n",edit_info->iWhy);
  505. switch(edit_info->iWhy)
  506. {
  507. case CBENF_DROPDOWN:
  508. if(edit_info->iNewSelection!=CB_ERR)
  509. pidl = (LPITEMIDLIST)SendMessageW(edit_info->hdr.hwndFrom,
  510. CB_GETITEMDATA,
  511. edit_info->iNewSelection,0);
  512. break;
  513. case CBENF_RETURN:
  514. {
  515. WCHAR path[MAX_PATH];
  516. HWND edit_ctrl = (HWND)SendMessageW(edit_info->hdr.hwndFrom,
  517. CBEM_GETEDITCONTROL,0,0);
  518. *((WORD*)path)=MAX_PATH;
  519. SendMessageW(edit_ctrl,EM_GETLINE,0,(LPARAM)path);
  520. pidl = ILCreateFromPathW(path);
  521. break;
  522. }
  523. case CBENF_ESCAPE:
  524. /*make sure the that the path box resets*/
  525. update_path_box(info);
  526. return 0;
  527. default:
  528. return 0;
  529. }
  530. if(pidl)
  531. IExplorerBrowser_BrowseToIDList(info->browser,pidl,SBSP_ABSOLUTE);
  532. if(edit_info->iWhy==CBENF_RETURN)
  533. ILFree(pidl);
  534. return 0;
  535. }
  536. static LRESULT update_rebar_size(explorer_info* info,NMRBAUTOSIZE *size_info)
  537. {
  538. RECT new_rect;
  539. RECT window_rect;
  540. info->rebar_height = size_info->rcTarget.bottom-size_info->rcTarget.top;
  541. GetWindowRect(info->main_window,&window_rect);
  542. new_rect.left = 0;
  543. new_rect.top = info->rebar_height;
  544. new_rect.right = window_rect.right-window_rect.left;
  545. new_rect.bottom = window_rect.bottom-window_rect.top;
  546. IExplorerBrowser_SetRect(info->browser,NULL,new_rect);
  547. return 0;
  548. }
  549. static LRESULT explorer_on_notify(explorer_info* info,NMHDR* notification)
  550. {
  551. WINE_TRACE("code=%i\n",notification->code);
  552. switch(notification->code)
  553. {
  554. case CBEN_BEGINEDIT:
  555. {
  556. WCHAR path[MAX_PATH];
  557. HWND edit_ctrl = (HWND)SendMessageW(notification->hwndFrom,
  558. CBEM_GETEDITCONTROL,0,0);
  559. SHGetPathFromIDListW(info->pidl,path);
  560. SetWindowTextW(edit_ctrl,path);
  561. break;
  562. }
  563. case CBEN_ENDEDITA:
  564. {
  565. NMCBEENDEDITA *edit_info_a = (NMCBEENDEDITA*)notification;
  566. NMCBEENDEDITW edit_info_w;
  567. edit_info_w.hdr = edit_info_a->hdr;
  568. edit_info_w.fChanged = edit_info_a->fChanged;
  569. edit_info_w.iNewSelection = edit_info_a->iNewSelection;
  570. MultiByteToWideChar(CP_ACP,0,edit_info_a->szText,-1,
  571. edit_info_w.szText,CBEMAXSTRLEN);
  572. edit_info_w.iWhy = edit_info_a->iWhy;
  573. return explorer_on_end_edit(info,&edit_info_w);
  574. }
  575. case CBEN_ENDEDITW:
  576. return explorer_on_end_edit(info,(NMCBEENDEDITW*)notification);
  577. case CBEN_DELETEITEM:
  578. {
  579. NMCOMBOBOXEXW *entry = (NMCOMBOBOXEXW*)notification;
  580. if(entry->ceItem.lParam)
  581. ILFree((LPITEMIDLIST)entry->ceItem.lParam);
  582. break;
  583. }
  584. case RBN_AUTOSIZE:
  585. return update_rebar_size(info,(NMRBAUTOSIZE*)notification);
  586. default:
  587. break;
  588. }
  589. return 0;
  590. }
  591. static LRESULT CALLBACK explorer_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  592. {
  593. explorer_info *info
  594. = (explorer_info*)GetWindowLongPtrW(hwnd,EXPLORER_INFO_INDEX);
  595. IExplorerBrowser *browser = NULL;
  596. WINE_TRACE("(hwnd=%p,uMsg=%u,wParam=%lx,lParam=%lx)\n",hwnd,uMsg,wParam,lParam);
  597. if(info)
  598. browser = info->browser;
  599. switch(uMsg)
  600. {
  601. case WM_DESTROY:
  602. IShellWindows_Revoke(info->sw, info->sw_cookie);
  603. IShellWindows_Release(info->sw);
  604. IExplorerBrowser_Unadvise(browser,info->advise_cookie);
  605. IExplorerBrowser_Destroy(browser);
  606. IExplorerBrowser_Release(browser);
  607. ILFree(info->pidl);
  608. IImageList_Release(info->icon_list);
  609. HeapFree(GetProcessHeap(),0,info);
  610. SetWindowLongPtrW(hwnd,EXPLORER_INFO_INDEX,0);
  611. PostQuitMessage(0);
  612. break;
  613. case WM_QUIT:
  614. do_exit(wParam);
  615. case WM_NOTIFY:
  616. return explorer_on_notify(info,(NMHDR*)lParam);
  617. case WM_COMMAND:
  618. if(HIWORD(wParam)==BN_CLICKED)
  619. {
  620. switch(LOWORD(wParam))
  621. {
  622. case BACK_BUTTON:
  623. IExplorerBrowser_BrowseToObject(browser,NULL,SBSP_NAVIGATEBACK);
  624. break;
  625. case FORWARD_BUTTON:
  626. IExplorerBrowser_BrowseToObject(browser,NULL,SBSP_NAVIGATEFORWARD);
  627. break;
  628. case UP_BUTTON:
  629. IExplorerBrowser_BrowseToObject(browser,NULL,SBSP_PARENT);
  630. break;
  631. }
  632. }
  633. break;
  634. case WM_SIZE:
  635. update_window_size(info,HIWORD(lParam),LOWORD(lParam));
  636. break;
  637. default:
  638. return DefWindowProcW(hwnd,uMsg,wParam,lParam);
  639. }
  640. return 0;
  641. }
  642. static void register_explorer_window_class(void)
  643. {
  644. WNDCLASSEXW window_class;
  645. window_class.cbSize = sizeof(WNDCLASSEXW);
  646. window_class.style = 0;
  647. window_class.cbClsExtra = 0;
  648. window_class.cbWndExtra = sizeof(LONG_PTR);
  649. window_class.lpfnWndProc = explorer_wnd_proc;
  650. window_class.hInstance = explorer_hInstance;
  651. window_class.hIcon = NULL;
  652. window_class.hCursor = NULL;
  653. window_class.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
  654. window_class.lpszMenuName = NULL;
  655. window_class.lpszClassName = EXPLORER_CLASS;
  656. window_class.hIconSm = NULL;
  657. RegisterClassExW(&window_class);
  658. }
  659. static WCHAR *copy_path_string(WCHAR *target, WCHAR *source)
  660. {
  661. INT i = 0;
  662. while (iswspace(*source)) source++;
  663. if (*source == '\"')
  664. {
  665. source ++;
  666. while (*source && *source != '\"') target[i++] = *source++;
  667. target[i] = 0;
  668. if (*source) source++;
  669. }
  670. else
  671. {
  672. while (*source && *source != ',') target[i++] = *source++;
  673. target[i] = 0;
  674. }
  675. PathRemoveBackslashW(target);
  676. return source;
  677. }
  678. static void copy_path_root(LPWSTR root, LPWSTR path)
  679. {
  680. LPWSTR p,p2;
  681. INT i = 0;
  682. p = path;
  683. while (*p!=0)
  684. p++;
  685. while (*p!='\\' && p > path)
  686. p--;
  687. if (p == path)
  688. return;
  689. p2 = path;
  690. while (p2 != p)
  691. {
  692. root[i] = *p2;
  693. i++;
  694. p2++;
  695. }
  696. root[i] = 0;
  697. }
  698. /*
  699. * Command Line parameters are:
  700. * [/n] Opens in single-paned view for each selected items. This is default
  701. * [/e,] Uses Windows Explorer View
  702. * [/cd,object] Specifies the root level of the view
  703. * [/root,object] Specifies the root level of the view
  704. * [/select,object] parent folder is opened and specified object is selected
  705. */
  706. static void parse_command_line(LPWSTR commandline,parameters_struct *parameters)
  707. {
  708. static const WCHAR arg_n[] = {'/','n'};
  709. static const WCHAR arg_e[] = {'/','e',','};
  710. static const WCHAR arg_cd[] = {'/','c','d',','};
  711. static const WCHAR arg_root[] = {'/','r','o','o','t',','};
  712. static const WCHAR arg_select[] = {'/','s','e','l','e','c','t',','};
  713. static const WCHAR arg_desktop[] = {'/','d','e','s','k','t','o','p'};
  714. static const WCHAR arg_desktop_quotes[] = {'"','/','d','e','s','k','t','o','p'};
  715. LPWSTR p = commandline;
  716. while (*p)
  717. {
  718. while (iswspace(*p)) p++;
  719. if (wcsncmp(p, arg_n, ARRAY_SIZE( arg_n ))==0)
  720. {
  721. parameters->explorer_mode = FALSE;
  722. p += ARRAY_SIZE( arg_n );
  723. }
  724. else if (wcsncmp(p, arg_e, ARRAY_SIZE( arg_e ))==0)
  725. {
  726. parameters->explorer_mode = TRUE;
  727. p += ARRAY_SIZE( arg_e );
  728. }
  729. else if (wcsncmp(p, arg_cd, ARRAY_SIZE( arg_cd ))==0)
  730. {
  731. p += ARRAY_SIZE( arg_cd );
  732. p = copy_path_string(parameters->root,p);
  733. }
  734. else if (wcsncmp(p, arg_root, ARRAY_SIZE( arg_root ))==0)
  735. {
  736. p += ARRAY_SIZE( arg_root );
  737. p = copy_path_string(parameters->root,p);
  738. }
  739. else if (wcsncmp(p, arg_select, ARRAY_SIZE( arg_select ))==0)
  740. {
  741. p += ARRAY_SIZE( arg_select );
  742. p = copy_path_string(parameters->selection,p);
  743. if (!parameters->root[0])
  744. copy_path_root(parameters->root,
  745. parameters->selection);
  746. }
  747. else if (wcsncmp(p, arg_desktop, ARRAY_SIZE( arg_desktop ))==0)
  748. {
  749. p += ARRAY_SIZE( arg_desktop );
  750. manage_desktop( p ); /* the rest of the command line is handled by desktop mode */
  751. }
  752. /* workaround for Worms Armageddon that hardcodes a /desktop option with quotes */
  753. else if (wcsncmp(p, arg_desktop_quotes, ARRAY_SIZE( arg_desktop_quotes ))==0)
  754. {
  755. p += ARRAY_SIZE( arg_desktop_quotes );
  756. manage_desktop( p ); /* the rest of the command line is handled by desktop mode */
  757. }
  758. else
  759. {
  760. /* left over command line is generally the path to be opened */
  761. copy_path_string(parameters->root,p);
  762. break;
  763. }
  764. }
  765. }
  766. int WINAPI wWinMain(HINSTANCE hinstance,
  767. HINSTANCE previnstance,
  768. LPWSTR cmdline,
  769. int cmdshow)
  770. {
  771. parameters_struct parameters;
  772. HRESULT hres;
  773. INITCOMMONCONTROLSEX init_info;
  774. memset(&parameters,0,sizeof(parameters));
  775. explorer_hInstance = hinstance;
  776. parse_command_line(cmdline,&parameters);
  777. hres = OleInitialize(NULL);
  778. if(FAILED(hres))
  779. {
  780. WINE_ERR("Could not initialize COM\n");
  781. ExitProcess(EXIT_FAILURE);
  782. }
  783. if(parameters.root[0] && !PathIsDirectoryW(parameters.root))
  784. if(ShellExecuteW(NULL,NULL,parameters.root,NULL,NULL,SW_SHOWDEFAULT) > (HINSTANCE)32)
  785. ExitProcess(EXIT_SUCCESS);
  786. init_info.dwSize = sizeof(INITCOMMONCONTROLSEX);
  787. init_info.dwICC = ICC_USEREX_CLASSES | ICC_BAR_CLASSES | ICC_COOL_CLASSES;
  788. if(!InitCommonControlsEx(&init_info))
  789. {
  790. WINE_ERR("Could not initialize Comctl\n");
  791. ExitProcess(EXIT_FAILURE);
  792. }
  793. register_explorer_window_class();
  794. make_explorer_window(&parameters);
  795. return 0;
  796. }