Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/programs/explorer/explorer.c
4389 views
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
23
#define COBJMACROS
24
25
#include "wine/debug.h"
26
#include "explorer_private.h"
27
#include "resource.h"
28
29
#include <initguid.h>
30
#include <windows.h>
31
#include <shellapi.h>
32
#include <shobjidl.h>
33
#include <shlobj.h>
34
#include <shlwapi.h>
35
#include <commoncontrols.h>
36
#include <commctrl.h>
37
38
WINE_DEFAULT_DEBUG_CHANNEL(explorer);
39
40
#define EXPLORER_INFO_INDEX 0
41
42
#define NAV_TOOLBAR_HEIGHT 30
43
#define PATHBOX_HEIGHT 24
44
static int nav_toolbar_height;
45
static int pathbox_height;
46
47
#define DEFAULT_WIDTH 640
48
#define DEFAULT_HEIGHT 480
49
static int default_width;
50
static int default_height;
51
52
53
HINSTANCE explorer_hInstance;
54
55
typedef struct parametersTAG {
56
BOOL explorer_mode;
57
WCHAR root[MAX_PATH];
58
WCHAR selection[MAX_PATH];
59
} parameters_struct;
60
61
typedef struct
62
{
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
70
IShellWindows *sw;
71
LONG sw_cookie;
72
} explorer_info;
73
74
enum
75
{
76
BACK_BUTTON,FORWARD_BUTTON,UP_BUTTON
77
};
78
79
static void variant_from_pidl(VARIANT *var, const ITEMIDLIST *pidl)
80
{
81
V_VT(var) = VT_ARRAY | VT_UI1;
82
V_ARRAY(var) = SafeArrayCreateVector(VT_UI1, 0, ILGetSize(pidl));
83
memcpy(V_ARRAY(var)->pvData, pidl, ILGetSize(pidl));
84
}
85
86
typedef struct
87
{
88
IExplorerBrowserEvents IExplorerBrowserEvents_iface;
89
explorer_info* info;
90
LONG ref;
91
} IExplorerBrowserEventsImpl;
92
93
static IExplorerBrowserEventsImpl *impl_from_IExplorerBrowserEvents(IExplorerBrowserEvents *iface)
94
{
95
return CONTAINING_RECORD(iface, IExplorerBrowserEventsImpl, IExplorerBrowserEvents_iface);
96
}
97
98
static HRESULT WINAPI IExplorerBrowserEventsImpl_fnQueryInterface(IExplorerBrowserEvents *iface, REFIID riid, void **ppvObject)
99
{
100
return E_NOINTERFACE;
101
}
102
103
static ULONG WINAPI IExplorerBrowserEventsImpl_fnAddRef(IExplorerBrowserEvents *iface)
104
{
105
IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
106
return InterlockedIncrement(&This->ref);
107
}
108
109
static ULONG WINAPI IExplorerBrowserEventsImpl_fnRelease(IExplorerBrowserEvents *iface)
110
{
111
IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
112
ULONG ref = InterlockedDecrement(&This->ref);
113
if(!ref) free(This);
114
return ref;
115
}
116
117
static BOOL create_combobox_item(IShellFolder *folder, LPCITEMIDLIST child_pidl, IImageList *icon_list, COMBOBOXEXITEMW *item)
118
{
119
STRRET strret;
120
HRESULT hres;
121
PIDLIST_ABSOLUTE parent_pidl, pidl;
122
SHFILEINFOW info;
123
IImageList *list;
124
125
strret.uType=STRRET_WSTR;
126
hres = IShellFolder_GetDisplayNameOf( folder, child_pidl, SHGDN_FORADDRESSBAR, &strret );
127
if(SUCCEEDED(hres))
128
hres = StrRetToStrW(&strret, child_pidl, &item->pszText);
129
if(FAILED(hres))
130
{
131
WARN( "Could not get name for pidl\n" );
132
return FALSE;
133
}
134
135
item->mask &= ~CBEIF_IMAGE;
136
hres = SHGetIDListFromObject( (IUnknown *)folder, &parent_pidl );
137
if (FAILED(hres)) return FALSE;
138
139
pidl = ILCombine( parent_pidl, child_pidl );
140
if (pidl)
141
{
142
list = (IImageList *)SHGetFileInfoW( (WCHAR *)pidl, 0, &info, sizeof(info),
143
SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_SYSICONINDEX );
144
if (list)
145
{
146
IImageList_Release( list );
147
item->iImage = info.iIcon;
148
item->mask |= CBEIF_IMAGE;
149
}
150
ILFree( pidl );
151
}
152
ILFree( parent_pidl );
153
154
return TRUE;
155
}
156
157
static void update_path_box(explorer_info *info)
158
{
159
COMBOBOXEXITEMW item;
160
COMBOBOXEXITEMW main_item;
161
IShellFolder *desktop;
162
IPersistFolder2 *persist;
163
LPITEMIDLIST desktop_pidl;
164
IEnumIDList *ids;
165
166
SendMessageW(info->path_box,CB_RESETCONTENT,0,0);
167
SHGetDesktopFolder(&desktop);
168
IShellFolder_QueryInterface(desktop,&IID_IPersistFolder2,(void**)&persist);
169
IPersistFolder2_GetCurFolder(persist,&desktop_pidl);
170
IPersistFolder2_Release(persist);
171
persist = NULL;
172
/*Add Desktop*/
173
item.iItem = -1;
174
item.mask = CBEIF_TEXT | CBEIF_INDENT | CBEIF_LPARAM;
175
item.iIndent = 0;
176
create_combobox_item(desktop,desktop_pidl,info->icon_list,&item);
177
item.lParam = (LPARAM)desktop_pidl;
178
SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item);
179
if(ILIsEqual(info->pidl,desktop_pidl))
180
main_item = item;
181
else
182
CoTaskMemFree(item.pszText);
183
/*Add all direct subfolders of Desktop*/
184
if(SUCCEEDED(IShellFolder_EnumObjects(desktop,NULL,SHCONTF_FOLDERS,&ids))
185
&& ids!=NULL)
186
{
187
LPITEMIDLIST curr_pidl=NULL;
188
HRESULT hres;
189
190
item.iIndent = 1;
191
while(1)
192
{
193
ILFree(curr_pidl);
194
curr_pidl=NULL;
195
hres = IEnumIDList_Next(ids,1,&curr_pidl,NULL);
196
if(FAILED(hres) || hres == S_FALSE)
197
break;
198
if (!create_combobox_item( desktop, curr_pidl, info->icon_list, &item ))
199
WARN( "Could not create a combobox item\n" );
200
else
201
{
202
LPITEMIDLIST full_pidl = ILCombine(desktop_pidl,curr_pidl);
203
item.lParam = (LPARAM)full_pidl;
204
SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item);
205
if(ILIsEqual(full_pidl,info->pidl))
206
main_item = item;
207
else if(ILIsParent(full_pidl,info->pidl,FALSE))
208
{
209
/*add all parents of the pidl passed in*/
210
LPITEMIDLIST next_pidl = ILFindChild(full_pidl,info->pidl);
211
IShellFolder *curr_folder = NULL, *temp;
212
hres = IShellFolder_BindToObject(desktop,curr_pidl,NULL,
213
&IID_IShellFolder,
214
(void**)&curr_folder);
215
if (FAILED(hres)) WARN( "Could not get an IShellFolder\n" );
216
while(!ILIsEmpty(next_pidl))
217
{
218
LPITEMIDLIST first = ILCloneFirst(next_pidl);
219
CoTaskMemFree(item.pszText);
220
if(!create_combobox_item(curr_folder,first,
221
info->icon_list,&item))
222
{
223
WARN( "Could not create a combobox item\n" );
224
break;
225
}
226
++item.iIndent;
227
full_pidl = ILCombine(full_pidl,first);
228
item.lParam = (LPARAM)full_pidl;
229
SendMessageW(info->path_box,CBEM_INSERTITEMW,0,(LPARAM)&item);
230
temp=NULL;
231
hres = IShellFolder_BindToObject(curr_folder,first,NULL,
232
&IID_IShellFolder,
233
(void**)&temp);
234
if(FAILED(hres))
235
{
236
WARN( "Could not get an IShellFolder\n" );
237
break;
238
}
239
IShellFolder_Release(curr_folder);
240
curr_folder = temp;
241
242
ILFree(first);
243
next_pidl = ILGetNext(next_pidl);
244
}
245
memcpy(&main_item,&item,sizeof(item));
246
if(curr_folder)
247
IShellFolder_Release(curr_folder);
248
item.iIndent = 1;
249
}
250
else
251
CoTaskMemFree(item.pszText);
252
}
253
}
254
ILFree(curr_pidl);
255
IEnumIDList_Release(ids);
256
}
257
else WARN( "Could not enumerate the desktop\n" );
258
SendMessageW(info->path_box,CBEM_SETITEMW,0,(LPARAM)&main_item);
259
CoTaskMemFree(main_item.pszText);
260
}
261
262
static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnNavigationComplete(IExplorerBrowserEvents *iface, PCIDLIST_ABSOLUTE pidl)
263
{
264
IExplorerBrowserEventsImpl *This = impl_from_IExplorerBrowserEvents(iface);
265
IShellFolder *parent;
266
PCUITEMID_CHILD child_pidl;
267
HRESULT hres;
268
STRRET strret;
269
WCHAR *name;
270
271
if (This->info->sw)
272
{
273
VARIANT var;
274
275
variant_from_pidl(&var, pidl);
276
IShellWindows_OnNavigate(This->info->sw, This->info->sw_cookie, &var);
277
VariantClear(&var);
278
}
279
280
ILFree(This->info->pidl);
281
This->info->pidl = ILClone(pidl);
282
update_path_box(This->info);
283
284
hres = SHBindToParent(pidl, &IID_IShellFolder, (void **)&parent, &child_pidl);
285
if (SUCCEEDED(hres))
286
{
287
hres = IShellFolder_GetDisplayNameOf(parent, child_pidl, SHGDN_FORADDRESSBAR, &strret);
288
if (SUCCEEDED(hres))
289
hres = StrRetToStrW(&strret, child_pidl, &name);
290
if (SUCCEEDED(hres))
291
{
292
SetWindowTextW(This->info->main_window, name);
293
CoTaskMemFree(name);
294
}
295
296
IShellFolder_Release(parent);
297
}
298
299
return hres;
300
}
301
302
static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnNavigationFailed(IExplorerBrowserEvents *iface, PCIDLIST_ABSOLUTE pidl)
303
{
304
return S_OK;
305
}
306
307
static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnNavigationPending(IExplorerBrowserEvents *iface, PCIDLIST_ABSOLUTE pidl)
308
{
309
return S_OK;
310
}
311
312
static HRESULT WINAPI IExplorerBrowserEventsImpl_fnOnViewCreated(IExplorerBrowserEvents *iface, IShellView *psv)
313
{
314
return S_OK;
315
}
316
317
static IExplorerBrowserEventsVtbl vt_IExplorerBrowserEvents =
318
{
319
IExplorerBrowserEventsImpl_fnQueryInterface,
320
IExplorerBrowserEventsImpl_fnAddRef,
321
IExplorerBrowserEventsImpl_fnRelease,
322
IExplorerBrowserEventsImpl_fnOnNavigationPending,
323
IExplorerBrowserEventsImpl_fnOnViewCreated,
324
IExplorerBrowserEventsImpl_fnOnNavigationComplete,
325
IExplorerBrowserEventsImpl_fnOnNavigationFailed
326
};
327
328
static IExplorerBrowserEvents *make_explorer_events(explorer_info *info)
329
{
330
IExplorerBrowserEventsImpl *ret = malloc( sizeof(IExplorerBrowserEventsImpl) );
331
ret->IExplorerBrowserEvents_iface.lpVtbl = &vt_IExplorerBrowserEvents;
332
ret->info = info;
333
ret->ref = 1;
334
SHGetImageList(SHIL_SMALL,&IID_IImageList,(void**)&(ret->info->icon_list));
335
SendMessageW(info->path_box,CBEM_SETIMAGELIST,0,(LPARAM)ret->info->icon_list);
336
return &ret->IExplorerBrowserEvents_iface;
337
}
338
339
static IShellFolder *get_starting_shell_folder(WCHAR *path)
340
{
341
IShellFolder* desktop,*folder;
342
LPITEMIDLIST root_pidl;
343
HRESULT hres;
344
345
SHGetDesktopFolder(&desktop);
346
347
if (!path)
348
return desktop;
349
350
hres = IShellFolder_ParseDisplayName(desktop, NULL, NULL, path, NULL, &root_pidl, NULL);
351
if(FAILED(hres))
352
{
353
return desktop;
354
}
355
hres = IShellFolder_BindToObject(desktop,root_pidl,NULL,
356
&IID_IShellFolder,
357
(void**)&folder);
358
ILFree(root_pidl);
359
if(FAILED(hres))
360
{
361
return desktop;
362
}
363
IShellFolder_Release(desktop);
364
return folder;
365
}
366
367
static void make_explorer_window(parameters_struct *params)
368
{
369
RECT rect;
370
HWND rebar,nav_toolbar;
371
FOLDERSETTINGS fs;
372
IExplorerBrowserEvents *events;
373
explorer_info *info;
374
HRESULT hres;
375
WCHAR explorer_title[100];
376
WCHAR pathbox_label[50];
377
TBADDBITMAP bitmap_info;
378
TBBUTTON nav_buttons[3];
379
int hist_offset,view_offset;
380
REBARBANDINFOW band_info;
381
VARIANT var, empty_var;
382
IShellFolder *folder;
383
IDispatch *dispatch;
384
WCHAR *path = NULL;
385
IShellWindows *sw;
386
ITEMIDLIST *pidl;
387
UINT dpix, dpiy;
388
DWORD size;
389
LONG hwnd;
390
HDC hdc;
391
MSG msg;
392
393
CoCreateInstance(&CLSID_ShellWindows, NULL, CLSCTX_LOCAL_SERVER,
394
&IID_IShellWindows, (void **)&sw);
395
396
if (params->root[0])
397
{
398
size = GetFullPathNameW(params->root, 0, NULL, NULL);
399
path = malloc( size * sizeof(WCHAR) );
400
GetFullPathNameW(params->root, size, path, NULL);
401
}
402
403
if (sw && path)
404
{
405
if (!(pidl = ILCreateFromPathW(path)))
406
{
407
ERR("Failed to create PIDL for %s.\n", debugstr_w(path));
408
IShellWindows_Release(sw);
409
free(path);
410
return;
411
}
412
413
variant_from_pidl(&var, pidl);
414
V_VT(&empty_var) = VT_EMPTY;
415
hres = IShellWindows_FindWindowSW(sw, &var, &empty_var, SWC_EXPLORER, &hwnd, 0, &dispatch);
416
VariantClear(&var);
417
ILFree(pidl);
418
if (hres == S_OK)
419
{
420
TRACE("Found window %#lx already browsing path %s.\n", hwnd, debugstr_w(path));
421
SetForegroundWindow((HWND)(LONG_PTR)hwnd);
422
IShellWindows_Release(sw);
423
free(path);
424
return;
425
}
426
}
427
428
memset(nav_buttons,0,sizeof(nav_buttons));
429
430
LoadStringW(explorer_hInstance,IDS_EXPLORER_TITLE,explorer_title, ARRAY_SIZE( explorer_title ));
431
LoadStringW(explorer_hInstance,IDS_PATHBOX_LABEL,pathbox_label, ARRAY_SIZE( pathbox_label ));
432
433
hdc = GetDC(0);
434
dpix = GetDeviceCaps(hdc, LOGPIXELSX);
435
dpiy = GetDeviceCaps(hdc, LOGPIXELSY);
436
ReleaseDC(0, hdc);
437
nav_toolbar_height = MulDiv(NAV_TOOLBAR_HEIGHT, dpiy, USER_DEFAULT_SCREEN_DPI);
438
pathbox_height = MulDiv(PATHBOX_HEIGHT, dpiy, USER_DEFAULT_SCREEN_DPI);
439
default_width = MulDiv(DEFAULT_WIDTH, dpix, USER_DEFAULT_SCREEN_DPI);
440
default_height = MulDiv(DEFAULT_HEIGHT, dpiy, USER_DEFAULT_SCREEN_DPI);
441
442
info = calloc( 1, sizeof(explorer_info) );
443
if(!info)
444
{
445
ERR( "Could not allocate an explorer_info struct\n" );
446
IShellWindows_Release(sw);
447
free(path);
448
return;
449
}
450
hres = CoCreateInstance(&CLSID_ExplorerBrowser,NULL,CLSCTX_INPROC_SERVER,
451
&IID_IExplorerBrowser,(LPVOID*)&info->browser);
452
if(FAILED(hres))
453
{
454
ERR( "Could not obtain an instance of IExplorerBrowser\n" );
455
free(info);
456
IShellWindows_Release(sw);
457
free(path);
458
return;
459
}
460
info->rebar_height=0;
461
info->main_window
462
= CreateWindowW(L"ExplorerWClass",explorer_title,WS_OVERLAPPEDWINDOW,
463
CW_USEDEFAULT,CW_USEDEFAULT,default_width,
464
default_height,NULL,NULL,explorer_hInstance,NULL);
465
466
if (sw)
467
{
468
IShellWindows_Register(sw, NULL, (LONG_PTR)info->main_window, SWC_EXPLORER, &info->sw_cookie);
469
info->sw = sw;
470
}
471
472
fs.ViewMode = FVM_DETAILS;
473
fs.fFlags = FWF_AUTOARRANGE;
474
475
SetRect(&rect, 0, 0, default_width, default_height);
476
IExplorerBrowser_Initialize(info->browser,info->main_window,&rect,&fs);
477
IExplorerBrowser_SetOptions(info->browser,EBO_SHOWFRAMES);
478
SetWindowLongPtrW(info->main_window,EXPLORER_INFO_INDEX,(LONG_PTR)info);
479
480
/*setup navbar*/
481
rebar = CreateWindowExW(WS_EX_TOOLWINDOW,REBARCLASSNAMEW,NULL,
482
WS_CHILD|WS_VISIBLE|RBS_VARHEIGHT|CCS_TOP|CCS_NODIVIDER,
483
0,0,0,0,info->main_window,NULL,explorer_hInstance,NULL);
484
nav_toolbar
485
= CreateWindowExW(TBSTYLE_EX_MIXEDBUTTONS,TOOLBARCLASSNAMEW,NULL,
486
WS_CHILD|WS_VISIBLE|TBSTYLE_FLAT,0,0,0,0,rebar,NULL,
487
explorer_hInstance,NULL);
488
489
bitmap_info.hInst = HINST_COMMCTRL;
490
bitmap_info.nID = IDB_HIST_LARGE_COLOR;
491
hist_offset= SendMessageW(nav_toolbar,TB_ADDBITMAP,0,(LPARAM)&bitmap_info);
492
bitmap_info.nID = IDB_VIEW_LARGE_COLOR;
493
view_offset= SendMessageW(nav_toolbar,TB_ADDBITMAP,0,(LPARAM)&bitmap_info);
494
495
nav_buttons[0].iBitmap=hist_offset+HIST_BACK;
496
nav_buttons[0].idCommand=BACK_BUTTON;
497
nav_buttons[0].fsState=TBSTATE_ENABLED;
498
nav_buttons[0].fsStyle=BTNS_BUTTON|BTNS_AUTOSIZE;
499
nav_buttons[1].iBitmap=hist_offset+HIST_FORWARD;
500
nav_buttons[1].idCommand=FORWARD_BUTTON;
501
nav_buttons[1].fsState=TBSTATE_ENABLED;
502
nav_buttons[1].fsStyle=BTNS_BUTTON|BTNS_AUTOSIZE;
503
nav_buttons[2].iBitmap=view_offset+VIEW_PARENTFOLDER;
504
nav_buttons[2].idCommand=UP_BUTTON;
505
nav_buttons[2].fsState=TBSTATE_ENABLED;
506
nav_buttons[2].fsStyle=BTNS_BUTTON|BTNS_AUTOSIZE;
507
SendMessageW(nav_toolbar,TB_BUTTONSTRUCTSIZE,sizeof(TBBUTTON),0);
508
SendMessageW(nav_toolbar,TB_ADDBUTTONSW,ARRAY_SIZE( nav_buttons ),(LPARAM)nav_buttons);
509
510
band_info.cbSize = sizeof(band_info);
511
band_info.fMask = RBBIM_STYLE|RBBIM_CHILD|RBBIM_CHILDSIZE|RBBIM_SIZE;
512
band_info.hwndChild = nav_toolbar;
513
band_info.fStyle=RBBS_GRIPPERALWAYS|RBBS_CHILDEDGE;
514
band_info.cyChild=nav_toolbar_height;
515
band_info.cx=0;
516
band_info.cyMinChild=nav_toolbar_height;
517
band_info.cxMinChild=0;
518
SendMessageW(rebar,RB_INSERTBANDW,-1,(LPARAM)&band_info);
519
info->path_box = CreateWindowW(WC_COMBOBOXEXW,L"",
520
WS_CHILD | WS_VISIBLE | CBS_DROPDOWN,
521
0,0,default_width,pathbox_height,rebar,NULL,
522
explorer_hInstance,NULL);
523
GetWindowRect(info->path_box, &rect);
524
band_info.cyChild = rect.bottom - rect.top;
525
band_info.cx=0;
526
band_info.cyMinChild = rect.bottom - rect.top;
527
band_info.cxMinChild=0;
528
band_info.fMask|=RBBIM_TEXT;
529
band_info.lpText=pathbox_label;
530
band_info.fStyle|=RBBS_BREAK;
531
band_info.hwndChild=info->path_box;
532
SendMessageW(rebar,RB_INSERTBANDW,-1,(LPARAM)&band_info);
533
events = make_explorer_events(info);
534
IExplorerBrowser_Advise(info->browser,events,&info->advise_cookie);
535
536
folder = get_starting_shell_folder(path);
537
IExplorerBrowser_BrowseToObject(info->browser, (IUnknown *)folder, SBSP_ABSOLUTE);
538
IShellFolder_Release(folder);
539
free(path);
540
541
ShowWindow(info->main_window,SW_SHOWDEFAULT);
542
UpdateWindow(info->main_window);
543
IExplorerBrowserEvents_Release(events);
544
545
while (GetMessageW(&msg, NULL, 0, 0))
546
{
547
TranslateMessage(&msg);
548
DispatchMessageW(&msg);
549
}
550
}
551
552
static void update_window_size(explorer_info *info, int height, int width)
553
{
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);
560
}
561
562
static void do_exit(int code)
563
{
564
OleUninitialize();
565
ExitProcess(code);
566
}
567
568
static LRESULT explorer_on_end_edit(explorer_info *info,NMCBEENDEDITW *edit_info)
569
{
570
LPITEMIDLIST pidl = NULL;
571
572
TRACE( "iWhy=%x\n", edit_info->iWhy );
573
switch(edit_info->iWhy)
574
{
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:
582
{
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;
590
}
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;
597
}
598
if(pidl)
599
IExplorerBrowser_BrowseToIDList(info->browser,pidl,SBSP_ABSOLUTE);
600
if(edit_info->iWhy==CBENF_RETURN)
601
ILFree(pidl);
602
return 0;
603
}
604
605
static LRESULT update_rebar_size(explorer_info* info,NMRBAUTOSIZE *size_info)
606
{
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;
617
}
618
619
static LRESULT explorer_on_notify(explorer_info* info,NMHDR* notification)
620
{
621
TRACE( "code=%i\n", notification->code );
622
switch(notification->code)
623
{
624
case CBEN_BEGINEDIT:
625
{
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;
632
}
633
case CBEN_ENDEDITA:
634
{
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);
644
}
645
case CBEN_ENDEDITW:
646
return explorer_on_end_edit(info,(NMCBEENDEDITW*)notification);
647
case CBEN_DELETEITEM:
648
{
649
NMCOMBOBOXEXW *entry = (NMCOMBOBOXEXW*)notification;
650
if(entry->ceItem.lParam)
651
ILFree((LPITEMIDLIST)entry->ceItem.lParam);
652
break;
653
}
654
case RBN_AUTOSIZE:
655
return update_rebar_size(info,(NMRBAUTOSIZE*)notification);
656
default:
657
break;
658
}
659
return 0;
660
}
661
662
static BOOL handle_copydata(const explorer_info *info, const COPYDATASTRUCT *cds)
663
{
664
static const unsigned int magic = 0xe32ee32e;
665
unsigned int i, flags, count;
666
const ITEMIDLIST *child;
667
unsigned char *ptr;
668
IShellView *sv;
669
SVSIF sv_flags;
670
671
TRACE("\n");
672
673
/* For SHOpenFolderAndSelectItems() */
674
if (cds->dwData != magic)
675
return FALSE;
676
677
ptr = cds->lpData;
678
memcpy(&count, ptr, sizeof(count));
679
ptr += sizeof(count);
680
memcpy(&flags, ptr, sizeof(flags));
681
ptr += sizeof(flags);
682
683
sv_flags = flags & OFASI_EDIT ? SVSI_EDIT : SVSI_SELECT;
684
685
IExplorerBrowser_GetCurrentView(info->browser, &IID_IShellView, (void **)&sv);
686
for (i = 0; i < count; ++i)
687
{
688
child = (const ITEMIDLIST *)ptr;
689
if (i == 0)
690
IShellView_SelectItem(sv, child, sv_flags | SVSI_ENSUREVISIBLE | SVSI_FOCUSED | SVSI_DESELECTOTHERS);
691
else
692
IShellView_SelectItem(sv, child, sv_flags);
693
ptr += ILGetSize(child);
694
}
695
IShellView_Release(sv);
696
return TRUE;
697
}
698
699
static LRESULT CALLBACK explorer_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
700
{
701
explorer_info *info
702
= (explorer_info*)GetWindowLongPtrW(hwnd,EXPLORER_INFO_INDEX);
703
IExplorerBrowser *browser = NULL;
704
705
TRACE( "(hwnd=%p,uMsg=%u,wParam=%Ix,lParam=%Ix)\n", hwnd, uMsg, wParam, lParam );
706
if(info)
707
browser = info->browser;
708
switch(uMsg)
709
{
710
case WM_DESTROY:
711
if(info->sw)
712
{
713
IShellWindows_Revoke(info->sw, info->sw_cookie);
714
IShellWindows_Release(info->sw);
715
}
716
717
IExplorerBrowser_Unadvise(browser,info->advise_cookie);
718
IExplorerBrowser_Destroy(browser);
719
IExplorerBrowser_Release(browser);
720
ILFree(info->pidl);
721
IImageList_Release(info->icon_list);
722
free(info);
723
SetWindowLongPtrW(hwnd,EXPLORER_INFO_INDEX,0);
724
PostQuitMessage(0);
725
break;
726
case WM_QUIT:
727
do_exit(wParam);
728
case WM_NOTIFY:
729
return explorer_on_notify(info,(NMHDR*)lParam);
730
case WM_COMMAND:
731
if(HIWORD(wParam)==BN_CLICKED)
732
{
733
switch(LOWORD(wParam))
734
{
735
case BACK_BUTTON:
736
IExplorerBrowser_BrowseToObject(browser,NULL,SBSP_NAVIGATEBACK);
737
break;
738
case FORWARD_BUTTON:
739
IExplorerBrowser_BrowseToObject(browser,NULL,SBSP_NAVIGATEFORWARD);
740
break;
741
case UP_BUTTON:
742
IExplorerBrowser_BrowseToObject(browser,NULL,SBSP_PARENT);
743
break;
744
}
745
}
746
break;
747
case WM_APPCOMMAND:
748
switch(GET_APPCOMMAND_LPARAM(lParam))
749
{
750
case APPCOMMAND_BROWSER_BACKWARD:
751
IExplorerBrowser_BrowseToObject(browser,NULL,SBSP_NAVIGATEBACK);
752
break;
753
case APPCOMMAND_BROWSER_FORWARD:
754
IExplorerBrowser_BrowseToObject(browser,NULL,SBSP_NAVIGATEFORWARD);
755
break;
756
}
757
break;
758
case WM_SIZE:
759
update_window_size(info,HIWORD(lParam),LOWORD(lParam));
760
break;
761
case WM_COPYDATA:
762
return handle_copydata(info, (const COPYDATASTRUCT *)lParam);
763
default:
764
return DefWindowProcW(hwnd,uMsg,wParam,lParam);
765
}
766
return 0;
767
}
768
769
static void register_explorer_window_class(void)
770
{
771
WNDCLASSEXW window_class;
772
window_class.cbSize = sizeof(WNDCLASSEXW);
773
window_class.style = 0;
774
window_class.cbClsExtra = 0;
775
window_class.cbWndExtra = sizeof(LONG_PTR);
776
window_class.lpfnWndProc = explorer_wnd_proc;
777
window_class.hInstance = explorer_hInstance;
778
window_class.hIcon = NULL;
779
window_class.hCursor = NULL;
780
window_class.hbrBackground = (HBRUSH)COLOR_BACKGROUND;
781
window_class.lpszMenuName = NULL;
782
window_class.lpszClassName = L"ExplorerWClass";
783
window_class.hIconSm = NULL;
784
RegisterClassExW(&window_class);
785
}
786
787
static WCHAR *copy_path_string(WCHAR *target, WCHAR *source)
788
{
789
INT i = 0;
790
791
while (iswspace(*source)) source++;
792
793
if (*source == '\"')
794
{
795
source ++;
796
while (*source && *source != '\"') target[i++] = *source++;
797
target[i] = 0;
798
if (*source) source++;
799
}
800
else
801
{
802
while (*source && *source != ',') target[i++] = *source++;
803
target[i] = 0;
804
}
805
PathRemoveBackslashW(target);
806
return source;
807
}
808
809
810
static void copy_path_root(LPWSTR root, LPWSTR path)
811
{
812
LPWSTR p,p2;
813
INT i = 0;
814
815
p = path;
816
while (*p!=0)
817
p++;
818
819
while (*p!='\\' && p > path)
820
p--;
821
822
if (p == path)
823
return;
824
825
p2 = path;
826
while (p2 != p)
827
{
828
root[i] = *p2;
829
i++;
830
p2++;
831
}
832
root[i] = 0;
833
}
834
835
/*
836
* Command Line parameters are:
837
* [/n] Opens in single-paned view for each selected items. This is default
838
* [/e,] Uses Windows Explorer View
839
* [/cd,object] Specifies the root level of the view
840
* [/root,object] Specifies the root level of the view
841
* [/select,object] parent folder is opened and specified object is selected
842
*/
843
static void parse_command_line(LPWSTR commandline,parameters_struct *parameters)
844
{
845
static const WCHAR arg_n[] = L"/n";
846
static const WCHAR arg_e[] = L"/e,";
847
static const WCHAR arg_cd[] = L"/cd,";
848
static const WCHAR arg_root[] = L"/root,";
849
static const WCHAR arg_select[] = L"/select,";
850
static const WCHAR arg_desktop[] = L"/desktop";
851
static const WCHAR arg_desktop_quotes[] = L"\"/desktop";
852
const size_t len_n = wcslen(arg_n);
853
const size_t len_e = wcslen(arg_e);
854
const size_t len_cd = wcslen(arg_cd);
855
const size_t len_root = wcslen(arg_root);
856
const size_t len_select = wcslen(arg_select);
857
const size_t len_desktop = wcslen(arg_desktop);
858
const size_t len_desktop_quotes = wcslen(arg_desktop_quotes);
859
860
LPWSTR p = commandline;
861
862
while (*p)
863
{
864
while (iswspace(*p)) p++;
865
if (wcsnicmp(p, arg_n, len_n )==0)
866
{
867
parameters->explorer_mode = FALSE;
868
p += len_n;
869
if (*p == ',') p++;
870
}
871
else if (wcsnicmp(p, arg_e, len_e )==0)
872
{
873
parameters->explorer_mode = TRUE;
874
p += len_e;
875
}
876
else if (wcsnicmp(p, arg_cd, len_cd )==0)
877
{
878
p += len_cd;
879
p = copy_path_string(parameters->root,p);
880
}
881
else if (wcsnicmp(p, arg_root, len_root )==0)
882
{
883
p += len_root;
884
p = copy_path_string(parameters->root,p);
885
}
886
else if (wcsnicmp(p, arg_select, len_select )==0)
887
{
888
p += len_select;
889
p = copy_path_string(parameters->selection,p);
890
if (!parameters->root[0])
891
copy_path_root(parameters->root,
892
parameters->selection);
893
}
894
else if (wcsnicmp(p, arg_desktop, len_desktop )==0)
895
{
896
p += len_desktop;
897
manage_desktop( p ); /* the rest of the command line is handled by desktop mode */
898
}
899
/* workaround for Worms Armageddon that hardcodes a /desktop option with quotes */
900
else if (wcsnicmp(p, arg_desktop_quotes, len_desktop_quotes )==0)
901
{
902
p += len_desktop_quotes;
903
manage_desktop( p ); /* the rest of the command line is handled by desktop mode */
904
}
905
else
906
{
907
/* left over command line is generally the path to be opened */
908
copy_path_string(parameters->root,p);
909
break;
910
}
911
}
912
}
913
914
int WINAPI wWinMain(HINSTANCE hinstance,
915
HINSTANCE previnstance,
916
LPWSTR cmdline,
917
int cmdshow)
918
{
919
920
parameters_struct parameters;
921
HRESULT hres;
922
INITCOMMONCONTROLSEX init_info;
923
924
memset(&parameters,0,sizeof(parameters));
925
explorer_hInstance = hinstance;
926
parse_command_line(cmdline,&parameters);
927
hres = OleInitialize(NULL);
928
if(FAILED(hres))
929
{
930
ERR( "Could not initialize COM\n" );
931
ExitProcess(EXIT_FAILURE);
932
}
933
if(parameters.root[0] && !PathIsDirectoryW(parameters.root))
934
if(ShellExecuteW(NULL,NULL,parameters.root,NULL,NULL,SW_SHOWDEFAULT) > (HINSTANCE)32)
935
ExitProcess(EXIT_SUCCESS);
936
init_info.dwSize = sizeof(INITCOMMONCONTROLSEX);
937
init_info.dwICC = ICC_USEREX_CLASSES | ICC_BAR_CLASSES | ICC_COOL_CLASSES;
938
if(!InitCommonControlsEx(&init_info))
939
{
940
ERR( "Could not initialize Comctl\n" );
941
ExitProcess(EXIT_FAILURE);
942
}
943
register_explorer_window_class();
944
make_explorer_window(&parameters);
945
return 0;
946
}
947
948