ws2_32: name is never NULL as array (Coverity).
[wine] / programs / winefile / winefile.c
1 /*
2  * Winefile
3  *
4  * Copyright 2000, 2003, 2004, 2005 Martin Fuchs
5  * Copyright 2006 Jason Green
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #ifdef __WINE__
23 #include "config.h"
24 #include "wine/port.h"
25
26 /* for unix filesystem function calls */
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <dirent.h>
30 #endif
31
32 #define COBJMACROS
33
34 #include "winefile.h"
35 #include "resource.h"
36 #include "wine/unicode.h"
37
38 #ifdef _NO_EXTENSIONS
39 #undef _LEFT_FILES
40 #endif
41
42 #ifndef _MAX_PATH
43 #define _MAX_DRIVE          3
44 #define _MAX_FNAME          256
45 #define _MAX_DIR            _MAX_FNAME
46 #define _MAX_EXT            _MAX_FNAME
47 #define _MAX_PATH           260
48 #endif
49
50 #ifdef NONAMELESSUNION
51 #define UNION_MEMBER(x) DUMMYUNIONNAME.x
52 #else
53 #define UNION_MEMBER(x) x
54 #endif
55
56
57 #ifdef _SHELL_FOLDERS
58 #define DEFAULT_SPLIT_POS       300
59 #else
60 #define DEFAULT_SPLIT_POS       200
61 #endif
62
63 static const WCHAR registry_key[] = { 'S','o','f','t','w','a','r','e','\\',
64                                       'W','i','n','e','\\',
65                                       'W','i','n','e','F','i','l','e','\0'};
66 static const WCHAR reg_start_x[] = { 's','t','a','r','t','X','\0'};
67 static const WCHAR reg_start_y[] = { 's','t','a','r','t','Y','\0'};
68 static const WCHAR reg_width[] = { 'w','i','d','t','h','\0'};
69 static const WCHAR reg_height[] = { 'h','e','i','g','h','t','\0'};
70 static const WCHAR reg_logfont[] = { 'l','o','g','f','o','n','t','\0'};
71
72 enum ENTRY_TYPE {
73         ET_WINDOWS,
74         ET_UNIX,
75 #ifdef _SHELL_FOLDERS
76         ET_SHELL
77 #endif
78 };
79
80 typedef struct _Entry {
81         struct _Entry*  next;
82         struct _Entry*  down;
83         struct _Entry*  up;
84
85         BOOL                    expanded;
86         BOOL                    scanned;
87         int                             level;
88
89         WIN32_FIND_DATAW        data;
90
91 #ifndef _NO_EXTENSIONS
92         BY_HANDLE_FILE_INFORMATION bhfi;
93         BOOL                    bhfi_valid;
94         enum ENTRY_TYPE etype;
95 #endif
96 #ifdef _SHELL_FOLDERS
97         LPITEMIDLIST    pidl;
98         IShellFolder*   folder;
99         HICON                   hicon;
100 #endif
101 } Entry;
102
103 typedef struct {
104         Entry   entry;
105         WCHAR   path[MAX_PATH];
106         WCHAR   volname[_MAX_FNAME];
107         WCHAR   fs[_MAX_DIR];
108         DWORD   drive_type;
109         DWORD   fs_flags;
110 } Root;
111
112 enum COLUMN_FLAGS {
113         COL_SIZE                = 0x01,
114         COL_DATE                = 0x02,
115         COL_TIME                = 0x04,
116         COL_ATTRIBUTES  = 0x08,
117         COL_DOSNAMES    = 0x10,
118 #ifdef _NO_EXTENSIONS
119         COL_ALL = COL_SIZE|COL_DATE|COL_TIME|COL_ATTRIBUTES|COL_DOSNAMES
120 #else
121         COL_INDEX               = 0x20,
122         COL_LINKS               = 0x40,
123         COL_ALL = COL_SIZE|COL_DATE|COL_TIME|COL_ATTRIBUTES|COL_DOSNAMES|COL_INDEX|COL_LINKS
124 #endif
125 };
126
127 typedef enum {
128         SORT_NAME,
129         SORT_EXT,
130         SORT_SIZE,
131         SORT_DATE
132 } SORT_ORDER;
133
134 typedef struct {
135         HWND    hwnd;
136 #ifndef _NO_EXTENSIONS
137         HWND    hwndHeader;
138 #endif
139
140 #ifndef _NO_EXTENSIONS
141 #define COLUMNS 10
142 #else
143 #define COLUMNS 5
144 #endif
145         int             widths[COLUMNS];
146         int             positions[COLUMNS+1];
147
148         BOOL    treePane;
149         int             visible_cols;
150         Entry*  root;
151         Entry*  cur;
152 } Pane;
153
154 typedef struct {
155         HWND    hwnd;
156         Pane    left;
157         Pane    right;
158         int             focus_pane;             /* 0: left  1: right */
159         WINDOWPLACEMENT pos;
160         int             split_pos;
161         BOOL    header_wdths_ok;
162
163         WCHAR   path[MAX_PATH];
164         WCHAR   filter_pattern[MAX_PATH];
165         int             filter_flags;
166         Root    root;
167
168         SORT_ORDER sortOrder;
169 } ChildWnd;
170
171
172
173 static void read_directory(Entry* dir, LPCWSTR path, SORT_ORDER sortOrder, HWND hwnd);
174 static void set_curdir(ChildWnd* child, Entry* entry, int idx, HWND hwnd);
175 static void refresh_child(ChildWnd* child);
176 static void refresh_drives(void);
177 static void get_path(Entry* dir, PWSTR path);
178 static void format_date(const FILETIME* ft, WCHAR* buffer, int visible_cols);
179
180 static LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam);
181 static LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam);
182 static LRESULT CALLBACK TreeWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam);
183
184
185 /* globals */
186 WINEFILE_GLOBALS Globals;
187
188 static int last_split;
189
190 /* some common string constants */
191 static const WCHAR sEmpty[] = {'\0'};
192 static const WCHAR sSpace[] = {' ', '\0'};
193 static const WCHAR sNumFmt[] = {'%','d','\0'};
194 static const WCHAR sQMarks[] = {'?','?','?','\0'};
195
196 /* window class names */
197 static const WCHAR sWINEFILEFRAME[] = {'W','F','S','_','F','r','a','m','e','\0'};
198 static const WCHAR sWINEFILETREE[] = {'W','F','S','_','T','r','e','e','\0'};
199
200 static void format_longlong(LPWSTR ret, ULONGLONG val)
201 {
202     WCHAR buffer[65], *p = &buffer[64];
203
204     *p = 0;
205     do {
206         *(--p) = '0' + val % 10;
207         val /= 10;
208     } while (val);
209     lstrcpyW( ret, p );
210 }
211
212
213 /* load resource string */
214 static LPWSTR load_string(LPWSTR buffer, DWORD size, UINT id)
215 {
216         LoadStringW(Globals.hInstance, id, buffer, size);
217         return buffer;
218 }
219
220 #define RS(b, i) load_string(b, sizeof(b)/sizeof(b[0]), i)
221
222
223 /* display error message for the specified WIN32 error code */
224 static void display_error(HWND hwnd, DWORD error)
225 {
226         WCHAR b1[BUFFER_LEN], b2[BUFFER_LEN];
227         PWSTR msg;
228
229         if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
230                 0, error, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), (PWSTR)&msg, 0, NULL))
231                 MessageBoxW(hwnd, msg, RS(b2,IDS_WINEFILE), MB_OK);
232         else
233                 MessageBoxW(hwnd, RS(b1,IDS_ERROR), RS(b2,IDS_WINEFILE), MB_OK);
234
235         LocalFree(msg);
236 }
237
238
239 /* display network error message using WNetGetLastErrorW() */
240 static void display_network_error(HWND hwnd)
241 {
242         WCHAR msg[BUFFER_LEN], provider[BUFFER_LEN], b2[BUFFER_LEN];
243         DWORD error;
244
245         if (WNetGetLastErrorW(&error, msg, BUFFER_LEN, provider, BUFFER_LEN) == NO_ERROR)
246                 MessageBoxW(hwnd, msg, RS(b2,IDS_WINEFILE), MB_OK);
247 }
248
249 static inline BOOL get_check(HWND hwnd, INT id)
250 {
251         return BST_CHECKED&SendMessageW(GetDlgItem(hwnd, id), BM_GETSTATE, 0, 0);
252 }
253
254 static inline INT set_check(HWND hwnd, INT id, BOOL on)
255 {
256         return SendMessageW(GetDlgItem(hwnd, id), BM_SETCHECK, on?BST_CHECKED:BST_UNCHECKED, 0);
257 }
258
259 static inline void choose_font(HWND hwnd)
260 {
261         WCHAR dlg_name[BUFFER_LEN], dlg_info[BUFFER_LEN];
262         CHOOSEFONTW chFont;
263         LOGFONTW lFont;
264
265         HDC hdc = GetDC(hwnd);
266
267         GetObjectW(Globals.hfont, sizeof(LOGFONTW), &lFont);
268
269         chFont.lStructSize = sizeof(CHOOSEFONTW);
270         chFont.hwndOwner = hwnd;
271         chFont.hDC = NULL;
272         chFont.lpLogFont = &lFont;
273         chFont.Flags = CF_SCREENFONTS | CF_FORCEFONTEXIST | CF_LIMITSIZE | CF_NOSCRIPTSEL | CF_INITTOLOGFONTSTRUCT;
274         chFont.rgbColors = RGB(0,0,0);
275         chFont.lCustData = 0;
276         chFont.lpfnHook = NULL;
277         chFont.lpTemplateName = NULL;
278         chFont.hInstance = Globals.hInstance;
279         chFont.lpszStyle = NULL;
280         chFont.nFontType = SIMULATED_FONTTYPE;
281         chFont.nSizeMin = 0;
282         chFont.nSizeMax = 24;
283
284         if (ChooseFontW(&chFont)) {
285                 HWND childWnd;
286                 HFONT hFontOld;
287
288                 DeleteObject(Globals.hfont);
289                 Globals.hfont = CreateFontIndirectW(&lFont);
290                 hFontOld = SelectObject(hdc, Globals.hfont);
291                 GetTextExtentPoint32W(hdc, sSpace, 1, &Globals.spaceSize);
292
293                 /* change font in all open child windows */
294                 for(childWnd=GetWindow(Globals.hmdiclient,GW_CHILD); childWnd; childWnd=GetNextWindow(childWnd,GW_HWNDNEXT)) {
295                         ChildWnd* child = (ChildWnd*) GetWindowLongPtrW(childWnd, GWLP_USERDATA);
296                         SendMessageW(child->left.hwnd, WM_SETFONT, (WPARAM)Globals.hfont, TRUE);
297                         SendMessageW(child->right.hwnd, WM_SETFONT, (WPARAM)Globals.hfont, TRUE);
298                         SendMessageW(child->left.hwnd, LB_SETITEMHEIGHT, 1, max(Globals.spaceSize.cy,IMAGE_HEIGHT+3));
299                         SendMessageW(child->right.hwnd, LB_SETITEMHEIGHT, 1, max(Globals.spaceSize.cy,IMAGE_HEIGHT+3));
300                         InvalidateRect(child->left.hwnd, NULL, TRUE);
301                         InvalidateRect(child->right.hwnd, NULL, TRUE);
302                 }
303
304                 SelectObject(hdc, hFontOld);
305         }
306         else if (CommDlgExtendedError()) {
307                 LoadStringW(Globals.hInstance, IDS_FONT_SEL_DLG_NAME, dlg_name, BUFFER_LEN);
308                 LoadStringW(Globals.hInstance, IDS_FONT_SEL_ERROR, dlg_info, BUFFER_LEN);
309                 MessageBoxW(hwnd, dlg_info, dlg_name, MB_OK);
310         }
311
312         ReleaseDC(hwnd, hdc);
313 }
314
315
316 /* allocate and initialise a directory entry */
317 static Entry* alloc_entry(void)
318 {
319         Entry* entry = HeapAlloc(GetProcessHeap(), 0, sizeof(Entry));
320
321 #ifdef _SHELL_FOLDERS
322         entry->pidl = NULL;
323         entry->folder = NULL;
324         entry->hicon = 0;
325 #endif
326
327         return entry;
328 }
329
330 /* free a directory entry */
331 static void free_entry(Entry* entry)
332 {
333 #ifdef _SHELL_FOLDERS
334         if (entry->hicon && entry->hicon!=(HICON)-1)
335                 DestroyIcon(entry->hicon);
336
337         if (entry->folder && entry->folder!=Globals.iDesktop)
338                 IShellFolder_Release(entry->folder);
339
340         if (entry->pidl)
341                 IMalloc_Free(Globals.iMalloc, entry->pidl);
342 #endif
343
344         HeapFree(GetProcessHeap(), 0, entry);
345 }
346
347 /* recursively free all child entries */
348 static void free_entries(Entry* dir)
349 {
350         Entry *entry, *next=dir->down;
351
352         if (next) {
353                 dir->down = 0;
354
355                 do {
356                         entry = next;
357                         next = entry->next;
358
359                         free_entries(entry);
360                         free_entry(entry);
361                 } while(next);
362         }
363 }
364
365
366 static void read_directory_win(Entry* dir, LPCWSTR path)
367 {
368         Entry* first_entry = NULL;
369         Entry* last = NULL;
370         Entry* entry;
371
372         int level = dir->level + 1;
373         WIN32_FIND_DATAW w32fd;
374         HANDLE hFind;
375 #ifndef _NO_EXTENSIONS
376         HANDLE hFile;
377 #endif
378
379         WCHAR buffer[MAX_PATH], *p;
380         for(p=buffer; *path; )
381                 *p++ = *path++;
382
383         *p++ = '\\';
384         p[0] = '*';
385         p[1] = '\0';
386
387         hFind = FindFirstFileW(buffer, &w32fd);
388
389         if (hFind != INVALID_HANDLE_VALUE) {
390                 do {
391 #ifdef _NO_EXTENSIONS
392                         /* hide directory entry "." */
393                         if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
394                                 LPCWSTR name = w32fd.cFileName;
395
396                                 if (name[0]=='.' && name[1]=='\0')
397                                         continue;
398                         }
399 #endif
400                         entry = alloc_entry();
401
402                         if (!first_entry)
403                                 first_entry = entry;
404
405                         if (last)
406                                 last->next = entry;
407
408                         memcpy(&entry->data, &w32fd, sizeof(WIN32_FIND_DATAW));
409                         entry->down = NULL;
410                         entry->up = dir;
411                         entry->expanded = FALSE;
412                         entry->scanned = FALSE;
413                         entry->level = level;
414
415 #ifndef _NO_EXTENSIONS
416                         entry->etype = ET_WINDOWS;
417                         entry->bhfi_valid = FALSE;
418
419                         lstrcpyW(p, entry->data.cFileName);
420
421                         hFile = CreateFileW(buffer, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
422                                                                 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
423
424                         if (hFile != INVALID_HANDLE_VALUE) {
425                                 if (GetFileInformationByHandle(hFile, &entry->bhfi))
426                                         entry->bhfi_valid = TRUE;
427
428                                 CloseHandle(hFile);
429                         }
430 #endif
431
432                         last = entry;
433                 } while(FindNextFileW(hFind, &w32fd));
434
435                 if (last)
436                         last->next = NULL;
437
438                 FindClose(hFind);
439         }
440
441         dir->down = first_entry;
442         dir->scanned = TRUE;
443 }
444
445
446 static Entry* find_entry_win(Entry* dir, LPCWSTR name)
447 {
448         Entry* entry;
449
450         for(entry=dir->down; entry; entry=entry->next) {
451                 LPCWSTR p = name;
452                 LPCWSTR q = entry->data.cFileName;
453
454                 do {
455                         if (!*p || *p == '\\' || *p == '/')
456                                 return entry;
457                 } while(tolower(*p++) == tolower(*q++));
458
459                 p = name;
460                 q = entry->data.cAlternateFileName;
461
462                 do {
463                         if (!*p || *p == '\\' || *p == '/')
464                                 return entry;
465                 } while(tolower(*p++) == tolower(*q++));
466         }
467
468         return 0;
469 }
470
471
472 static Entry* read_tree_win(Root* root, LPCWSTR path, SORT_ORDER sortOrder, HWND hwnd)
473 {
474         WCHAR buffer[MAX_PATH];
475         Entry* entry = &root->entry;
476         LPCWSTR s = path;
477         PWSTR d = buffer;
478
479         HCURSOR old_cursor = SetCursor(LoadCursorW(0, (LPCWSTR)IDC_WAIT));
480
481 #ifndef _NO_EXTENSIONS
482         entry->etype = ET_WINDOWS;
483 #endif
484
485         while(entry) {
486                 while(*s && *s != '\\' && *s != '/')
487                         *d++ = *s++;
488
489                 while(*s == '\\' || *s == '/')
490                         s++;
491
492                 *d++ = '\\';
493                 *d = '\0';
494
495                 read_directory(entry, buffer, sortOrder, hwnd);
496
497                 if (entry->down)
498                         entry->expanded = TRUE;
499
500                 if (!*s)
501                         break;
502
503                 entry = find_entry_win(entry, s);
504         }
505
506         SetCursor(old_cursor);
507
508         return entry;
509 }
510
511
512 #if !defined(_NO_EXTENSIONS) && defined(__WINE__)
513
514 static BOOL time_to_filetime(const time_t* t, FILETIME* ftime)
515 {
516         struct tm* tm = gmtime(t);
517         SYSTEMTIME stime;
518
519         if (!tm)
520                 return FALSE;
521
522         stime.wYear = tm->tm_year+1900;
523         stime.wMonth = tm->tm_mon+1;
524         /*      stime.wDayOfWeek */
525         stime.wDay = tm->tm_mday;
526         stime.wHour = tm->tm_hour;
527         stime.wMinute = tm->tm_min;
528         stime.wSecond = tm->tm_sec;
529
530         return SystemTimeToFileTime(&stime, ftime);
531 }
532
533 static void read_directory_unix(Entry* dir, LPCWSTR path)
534 {
535         Entry* first_entry = NULL;
536         Entry* last = NULL;
537         Entry* entry;
538         DIR* pdir;
539
540         int level = dir->level + 1;
541         char cpath[MAX_PATH];
542
543         WideCharToMultiByte(CP_UNIXCP, 0, path, -1, cpath, MAX_PATH, NULL, NULL);
544         pdir = opendir(cpath);
545
546         if (pdir) {
547                 struct stat st;
548                 struct dirent* ent;
549                 char buffer[MAX_PATH], *p;
550                 const char* s;
551
552                 for(p=buffer,s=cpath; *s; )
553                         *p++ = *s++;
554
555                 if (p==buffer || p[-1]!='/')
556                         *p++ = '/';
557
558                 while((ent=readdir(pdir))) {
559                         entry = alloc_entry();
560
561                         if (!first_entry)
562                                 first_entry = entry;
563
564                         if (last)
565                                 last->next = entry;
566
567                         entry->etype = ET_UNIX;
568
569                         strcpy(p, ent->d_name);
570                         MultiByteToWideChar(CP_UNIXCP, 0, p, -1, entry->data.cFileName, MAX_PATH);
571
572                         if (!stat(buffer, &st)) {
573                                 entry->data.dwFileAttributes = p[0]=='.'? FILE_ATTRIBUTE_HIDDEN: 0;
574
575                                 if (S_ISDIR(st.st_mode))
576                                         entry->data.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
577
578                                 entry->data.nFileSizeLow = st.st_size & 0xFFFFFFFF;
579                                 entry->data.nFileSizeHigh = st.st_size >> 32;
580
581                                 memset(&entry->data.ftCreationTime, 0, sizeof(FILETIME));
582                                 time_to_filetime(&st.st_atime, &entry->data.ftLastAccessTime);
583                                 time_to_filetime(&st.st_mtime, &entry->data.ftLastWriteTime);
584
585                                 entry->bhfi.nFileIndexLow = ent->d_ino;
586                                 entry->bhfi.nFileIndexHigh = 0;
587
588                                 entry->bhfi.nNumberOfLinks = st.st_nlink;
589
590                                 entry->bhfi_valid = TRUE;
591                         } else {
592                                 entry->data.nFileSizeLow = 0;
593                                 entry->data.nFileSizeHigh = 0;
594                                 entry->bhfi_valid = FALSE;
595                         }
596
597                         entry->down = NULL;
598                         entry->up = dir;
599                         entry->expanded = FALSE;
600                         entry->scanned = FALSE;
601                         entry->level = level;
602
603                         last = entry;
604                 }
605
606                 if (last)
607                         last->next = NULL;
608
609                 closedir(pdir);
610         }
611
612         dir->down = first_entry;
613         dir->scanned = TRUE;
614 }
615
616 static Entry* find_entry_unix(Entry* dir, LPCWSTR name)
617 {
618         Entry* entry;
619
620         for(entry=dir->down; entry; entry=entry->next) {
621                 LPCWSTR p = name;
622                 LPCWSTR q = entry->data.cFileName;
623
624                 do {
625                         if (!*p || *p == '/')
626                                 return entry;
627                 } while(*p++ == *q++);
628         }
629
630         return 0;
631 }
632
633 static Entry* read_tree_unix(Root* root, LPCWSTR path, SORT_ORDER sortOrder, HWND hwnd)
634 {
635         WCHAR buffer[MAX_PATH];
636         Entry* entry = &root->entry;
637         LPCWSTR s = path;
638         PWSTR d = buffer;
639
640         HCURSOR old_cursor = SetCursor(LoadCursorW(0, (LPCWSTR)IDC_WAIT));
641
642         entry->etype = ET_UNIX;
643
644         while(entry) {
645                 while(*s && *s != '/')
646                         *d++ = *s++;
647
648                 while(*s == '/')
649                         s++;
650
651                 *d++ = '/';
652                 *d = '\0';
653
654                 read_directory(entry, buffer, sortOrder, hwnd);
655
656                 if (entry->down)
657                         entry->expanded = TRUE;
658
659                 if (!*s)
660                         break;
661
662                 entry = find_entry_unix(entry, s);
663         }
664
665         SetCursor(old_cursor);
666
667         return entry;
668 }
669
670 #endif /* !defined(_NO_EXTENSIONS) && defined(__WINE__) */
671
672
673 #ifdef _SHELL_FOLDERS
674
675 static void free_strret(STRRET* str)
676 {
677         if (str->uType == STRRET_WSTR)
678                 IMalloc_Free(Globals.iMalloc, str->UNION_MEMBER(pOleStr));
679 }
680
681 static LPWSTR wcscpyn(LPWSTR dest, LPCWSTR source, size_t count)
682 {
683  LPCWSTR s;
684  LPWSTR d = dest;
685
686  for(s=source; count&&(*d++=*s++); )
687   count--;
688
689  return dest;
690 }
691
692 static void get_strretW(STRRET* str, const SHITEMID* shiid, LPWSTR buffer, int len)
693 {
694  switch(str->uType) {
695   case STRRET_WSTR:
696         wcscpyn(buffer, str->UNION_MEMBER(pOleStr), len);
697         break;
698
699   case STRRET_OFFSET:
700         MultiByteToWideChar(CP_ACP, 0, (LPCSTR)shiid+str->UNION_MEMBER(uOffset), -1, buffer, len);
701         break;
702
703   case STRRET_CSTR:
704         MultiByteToWideChar(CP_ACP, 0, str->UNION_MEMBER(cStr), -1, buffer, len);
705  }
706 }
707
708
709 static HRESULT name_from_pidl(IShellFolder* folder, LPITEMIDLIST pidl, LPWSTR buffer, int len, SHGDNF flags)
710 {
711         STRRET str;
712
713         HRESULT hr = IShellFolder_GetDisplayNameOf(folder, pidl, flags, &str);
714
715         if (SUCCEEDED(hr)) {
716                 get_strretW(&str, &pidl->mkid, buffer, len);
717                 free_strret(&str);
718         } else
719                 buffer[0] = '\0';
720
721         return hr;
722 }
723
724
725 static HRESULT path_from_pidlW(IShellFolder* folder, LPITEMIDLIST pidl, LPWSTR buffer, int len)
726 {
727         STRRET str;
728
729          /* SHGDN_FORPARSING: get full path of id list */
730         HRESULT hr = IShellFolder_GetDisplayNameOf(folder, pidl, SHGDN_FORPARSING, &str);
731
732         if (SUCCEEDED(hr)) {
733                 get_strretW(&str, &pidl->mkid, buffer, len);
734                 free_strret(&str);
735         } else
736                 buffer[0] = '\0';
737
738         return hr;
739 }
740
741
742  /* create an item id list from a file system path */
743
744 static LPITEMIDLIST get_path_pidl(LPWSTR path, HWND hwnd)
745 {
746         LPITEMIDLIST pidl;
747         HRESULT hr;
748         ULONG len;
749         LPWSTR buffer = path;
750
751         hr = IShellFolder_ParseDisplayName(Globals.iDesktop, hwnd, NULL, buffer, &len, &pidl, NULL);
752         if (FAILED(hr))
753                 return NULL;
754
755         return pidl;
756 }
757
758
759  /* convert an item id list from relative to absolute (=relative to the desktop) format */
760
761 static LPITEMIDLIST get_to_absolute_pidl(Entry* entry, HWND hwnd)
762 {
763         if (entry->up && entry->up->etype==ET_SHELL) {
764                 LPITEMIDLIST idl = NULL;
765
766                 while (entry->up) {
767                         idl = ILCombine(ILClone(entry->pidl), idl);
768                         entry = entry->up;
769                 }
770
771                 return idl;
772         } else if (entry->etype == ET_WINDOWS) {
773                 WCHAR path[MAX_PATH];
774
775                 get_path(entry, path);
776
777                 return get_path_pidl(path, hwnd);
778         } else if (entry->pidl)
779                 return ILClone(entry->pidl);
780
781         return NULL;
782 }
783
784
785 static HICON extract_icon(IShellFolder* folder, LPCITEMIDLIST pidl)
786 {
787         IExtractIconW* pExtract;
788
789         if (SUCCEEDED(IShellFolder_GetUIObjectOf(folder, 0, 1, (LPCITEMIDLIST*)&pidl, &IID_IExtractIconW, 0, (LPVOID*)&pExtract))) {
790                 WCHAR path[_MAX_PATH];
791                 unsigned flags;
792                 HICON hicon;
793                 int idx;
794
795                 if (SUCCEEDED(IExtractIconW_GetIconLocation(pExtract, GIL_FORSHELL, path, _MAX_PATH, &idx, &flags))) {
796                         if (!(flags & GIL_NOTFILENAME)) {
797                                 if (idx == -1)
798                                         idx = 0;        /* special case for some control panel applications */
799
800                                 if ((int)ExtractIconExW(path, idx, 0, &hicon, 1) > 0)
801                                         flags &= ~GIL_DONTCACHE;
802                         } else {
803                                 HICON hIconLarge = 0;
804
805                                 HRESULT hr = IExtractIconW_Extract(pExtract, path, idx, &hIconLarge, &hicon, MAKELONG(0/*GetSystemMetrics(SM_CXICON)*/,GetSystemMetrics(SM_CXSMICON)));
806
807                                 if (SUCCEEDED(hr))
808                                         DestroyIcon(hIconLarge);
809                         }
810
811                         return hicon;
812                 }
813         }
814
815         return 0;
816 }
817
818
819 static Entry* find_entry_shell(Entry* dir, LPCITEMIDLIST pidl)
820 {
821         Entry* entry;
822
823         for(entry=dir->down; entry; entry=entry->next) {
824                 if (entry->pidl->mkid.cb == pidl->mkid.cb &&
825                         !memcmp(entry->pidl, pidl, entry->pidl->mkid.cb))
826                         return entry;
827         }
828
829         return 0;
830 }
831
832 static Entry* read_tree_shell(Root* root, LPITEMIDLIST pidl, SORT_ORDER sortOrder, HWND hwnd)
833 {
834         Entry* entry = &root->entry;
835         Entry* next;
836         LPITEMIDLIST next_pidl = pidl;
837         IShellFolder* folder;
838         IShellFolder* child = NULL;
839         HRESULT hr;
840
841         HCURSOR old_cursor = SetCursor(LoadCursorW(0, (LPCWSTR)IDC_WAIT));
842
843 #ifndef _NO_EXTENSIONS
844         entry->etype = ET_SHELL;
845 #endif
846
847         folder = Globals.iDesktop;
848
849         while(entry) {
850                 entry->pidl = next_pidl;
851                 entry->folder = folder;
852
853                 if (!pidl->mkid.cb)
854                         break;
855
856                  /* copy first element of item idlist */
857                 next_pidl = IMalloc_Alloc(Globals.iMalloc, pidl->mkid.cb+sizeof(USHORT));
858                 memcpy(next_pidl, pidl, pidl->mkid.cb);
859                 ((LPITEMIDLIST)((LPBYTE)next_pidl+pidl->mkid.cb))->mkid.cb = 0;
860
861                 hr = IShellFolder_BindToObject(folder, next_pidl, 0, &IID_IShellFolder, (void**)&child);
862                 if (FAILED(hr))
863                         break;
864
865                 read_directory(entry, NULL, sortOrder, hwnd);
866
867                 if (entry->down)
868                         entry->expanded = TRUE;
869
870                 next = find_entry_shell(entry, next_pidl);
871                 if (!next)
872                         break;
873
874                 folder = child;
875                 entry = next;
876
877                  /* go to next element */
878                 pidl = (LPITEMIDLIST) ((LPBYTE)pidl+pidl->mkid.cb);
879         }
880
881         SetCursor(old_cursor);
882
883         return entry;
884 }
885
886
887 static void fill_w32fdata_shell(IShellFolder* folder, LPCITEMIDLIST pidl, SFGAOF attribs, WIN32_FIND_DATAW* w32fdata)
888 {
889         if (!(attribs & SFGAO_FILESYSTEM) ||
890                         FAILED(SHGetDataFromIDListW(folder, pidl, SHGDFIL_FINDDATA, w32fdata, sizeof(WIN32_FIND_DATAW)))) {
891                 WIN32_FILE_ATTRIBUTE_DATA fad;
892                 IDataObject* pDataObj;
893
894                 STGMEDIUM medium = {0, {0}, 0};
895                 FORMATETC fmt = {Globals.cfStrFName, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
896
897                 HRESULT hr = IShellFolder_GetUIObjectOf(folder, 0, 1, &pidl, &IID_IDataObject, 0, (LPVOID*)&pDataObj);
898
899                 if (SUCCEEDED(hr)) {
900                         hr = IDataObject_GetData(pDataObj, &fmt, &medium);
901
902                         IDataObject_Release(pDataObj);
903
904                         if (SUCCEEDED(hr)) {
905                                 LPCWSTR path = GlobalLock(medium.UNION_MEMBER(hGlobal));
906                                 UINT sem_org = SetErrorMode(SEM_FAILCRITICALERRORS);
907
908                                 if (GetFileAttributesExW(path, GetFileExInfoStandard, &fad)) {
909                                         w32fdata->dwFileAttributes = fad.dwFileAttributes;
910                                         w32fdata->ftCreationTime = fad.ftCreationTime;
911                                         w32fdata->ftLastAccessTime = fad.ftLastAccessTime;
912                                         w32fdata->ftLastWriteTime = fad.ftLastWriteTime;
913
914                                         if (!(fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
915                                                 w32fdata->nFileSizeLow = fad.nFileSizeLow;
916                                                 w32fdata->nFileSizeHigh = fad.nFileSizeHigh;
917                                         }
918                                 }
919
920                                 SetErrorMode(sem_org);
921
922                                 GlobalUnlock(medium.UNION_MEMBER(hGlobal));
923                                 GlobalFree(medium.UNION_MEMBER(hGlobal));
924                         }
925                 }
926         }
927
928         if (attribs & (SFGAO_FOLDER|SFGAO_HASSUBFOLDER))
929                 w32fdata->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
930
931         if (attribs & SFGAO_READONLY)
932                 w32fdata->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
933
934         if (attribs & SFGAO_COMPRESSED)
935                 w32fdata->dwFileAttributes |= FILE_ATTRIBUTE_COMPRESSED;
936 }
937
938
939 static void read_directory_shell(Entry* dir, HWND hwnd)
940 {
941         IShellFolder* folder = dir->folder;
942         int level = dir->level + 1;
943         HRESULT hr;
944
945         IShellFolder* child;
946         IEnumIDList* idlist;
947
948         Entry* first_entry = NULL;
949         Entry* last = NULL;
950         Entry* entry;
951
952         if (!folder)
953                 return;
954
955         hr = IShellFolder_EnumObjects(folder, hwnd, SHCONTF_FOLDERS|SHCONTF_NONFOLDERS|SHCONTF_INCLUDEHIDDEN|SHCONTF_SHAREABLE|SHCONTF_STORAGE, &idlist);
956
957         if (SUCCEEDED(hr)) {
958                 for(;;) {
959 #define FETCH_ITEM_COUNT        32
960                         LPITEMIDLIST pidls[FETCH_ITEM_COUNT];
961                         SFGAOF attribs;
962                         ULONG cnt = 0;
963                         ULONG n;
964
965                         memset(pidls, 0, sizeof(pidls));
966
967                         hr = IEnumIDList_Next(idlist, FETCH_ITEM_COUNT, pidls, &cnt);
968                         if (FAILED(hr))
969                                 break;
970
971                         if (hr == S_FALSE)
972                                 break;
973
974                         for(n=0; n<cnt; ++n) {
975                                 entry = alloc_entry();
976
977                                 if (!first_entry)
978                                         first_entry = entry;
979
980                                 if (last)
981                                         last->next = entry;
982
983                                 memset(&entry->data, 0, sizeof(WIN32_FIND_DATAW));
984                                 entry->bhfi_valid = FALSE;
985
986                                 attribs = ~SFGAO_FILESYSTEM;    /*SFGAO_HASSUBFOLDER|SFGAO_FOLDER; SFGAO_FILESYSTEM sorgt dafür, daß "My Documents" anstatt von "Martin's Documents" angezeigt wird */
987
988                                 hr = IShellFolder_GetAttributesOf(folder, 1, (LPCITEMIDLIST*)&pidls[n], &attribs);
989
990                                 if (SUCCEEDED(hr)) {
991                                         if (attribs != (SFGAOF)~SFGAO_FILESYSTEM) {
992                                                 fill_w32fdata_shell(folder, pidls[n], attribs, &entry->data);
993
994                                                 entry->bhfi_valid = TRUE;
995                                         } else
996                                                 attribs = 0;
997                                 } else
998                                         attribs = 0;
999
1000                                 entry->pidl = pidls[n];
1001
1002                                 if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1003                                         hr = IShellFolder_BindToObject(folder, pidls[n], 0, &IID_IShellFolder, (void**)&child);
1004
1005                                         if (SUCCEEDED(hr))
1006                                                 entry->folder = child;
1007                                         else
1008                                                 entry->folder = NULL;
1009                                 }
1010                                 else
1011                                         entry->folder = NULL;
1012
1013                                 if (!entry->data.cFileName[0])
1014                                         /*hr = */name_from_pidl(folder, pidls[n], entry->data.cFileName, MAX_PATH, /*SHGDN_INFOLDER*/0x2000/*0x2000=SHGDN_INCLUDE_NONFILESYS*/);
1015
1016                                  /* get display icons for files and virtual objects */
1017                                 if (!(entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ||
1018                                         !(attribs & SFGAO_FILESYSTEM)) {
1019                                         entry->hicon = extract_icon(folder, pidls[n]);
1020
1021                                         if (!entry->hicon)
1022                                                 entry->hicon = (HICON)-1;       /* don't try again later */
1023                                 }
1024
1025                                 entry->down = NULL;
1026                                 entry->up = dir;
1027                                 entry->expanded = FALSE;
1028                                 entry->scanned = FALSE;
1029                                 entry->level = level;
1030
1031 #ifndef _NO_EXTENSIONS
1032                                 entry->etype = ET_SHELL;
1033                                 entry->bhfi_valid = FALSE;
1034 #endif
1035
1036                                 last = entry;
1037                         }
1038                 }
1039
1040                 IEnumIDList_Release(idlist);
1041         }
1042
1043         if (last)
1044                 last->next = NULL;
1045
1046         dir->down = first_entry;
1047         dir->scanned = TRUE;
1048 }
1049
1050 #endif /* _SHELL_FOLDERS */
1051
1052
1053 /* sort order for different directory/file types */
1054 enum TYPE_ORDER {
1055         TO_DIR = 0,
1056         TO_DOT = 1,
1057         TO_DOTDOT = 2,
1058         TO_OTHER_DIR = 3,
1059         TO_FILE = 4
1060 };
1061
1062 /* distinguish between ".", ".." and any other directory names */
1063 static int TypeOrderFromDirname(LPCWSTR name)
1064 {
1065         if (name[0] == '.') {
1066                 if (name[1] == '\0')
1067                         return TO_DOT;  /* "." */
1068
1069                 if (name[1]=='.' && name[2]=='\0')
1070                         return TO_DOTDOT;       /* ".." */
1071         }
1072
1073         return TO_OTHER_DIR;    /* anything else */
1074 }
1075
1076 /* directories first... */
1077 static int compareType(const WIN32_FIND_DATAW* fd1, const WIN32_FIND_DATAW* fd2)
1078 {
1079         int order1 = fd1->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY? TO_DIR: TO_FILE;
1080         int order2 = fd2->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY? TO_DIR: TO_FILE;
1081
1082         /* Handle "." and ".." as special case and move them at the very first beginning. */
1083         if (order1==TO_DIR && order2==TO_DIR) {
1084                 order1 = TypeOrderFromDirname(fd1->cFileName);
1085                 order2 = TypeOrderFromDirname(fd2->cFileName);
1086         }
1087
1088         return order2==order1? 0: order1<order2? -1: 1;
1089 }
1090
1091
1092 static int compareName(const void* arg1, const void* arg2)
1093 {
1094         const WIN32_FIND_DATAW* fd1 = &(*(const Entry* const*)arg1)->data;
1095         const WIN32_FIND_DATAW* fd2 = &(*(const Entry* const*)arg2)->data;
1096
1097         int cmp = compareType(fd1, fd2);
1098         if (cmp)
1099                 return cmp;
1100
1101         return lstrcmpiW(fd1->cFileName, fd2->cFileName);
1102 }
1103
1104 static int compareExt(const void* arg1, const void* arg2)
1105 {
1106         const WIN32_FIND_DATAW* fd1 = &(*(const Entry* const*)arg1)->data;
1107         const WIN32_FIND_DATAW* fd2 = &(*(const Entry* const*)arg2)->data;
1108         const WCHAR *name1, *name2, *ext1, *ext2;
1109
1110         int cmp = compareType(fd1, fd2);
1111         if (cmp)
1112                 return cmp;
1113
1114         name1 = fd1->cFileName;
1115         name2 = fd2->cFileName;
1116
1117         ext1 = strrchrW(name1, '.');
1118         ext2 = strrchrW(name2, '.');
1119
1120         if (ext1)
1121                 ext1++;
1122         else
1123                 ext1 = sEmpty;
1124
1125         if (ext2)
1126                 ext2++;
1127         else
1128                 ext2 = sEmpty;
1129
1130         cmp = lstrcmpiW(ext1, ext2);
1131         if (cmp)
1132                 return cmp;
1133
1134         return lstrcmpiW(name1, name2);
1135 }
1136
1137 static int compareSize(const void* arg1, const void* arg2)
1138 {
1139         const WIN32_FIND_DATAW* fd1 = &(*(const Entry* const*)arg1)->data;
1140         const WIN32_FIND_DATAW* fd2 = &(*(const Entry* const*)arg2)->data;
1141
1142         int cmp = compareType(fd1, fd2);
1143         if (cmp)
1144                 return cmp;
1145
1146         cmp = fd2->nFileSizeHigh - fd1->nFileSizeHigh;
1147
1148         if (cmp < 0)
1149                 return -1;
1150         else if (cmp > 0)
1151                 return 1;
1152
1153         cmp = fd2->nFileSizeLow - fd1->nFileSizeLow;
1154
1155         return cmp<0? -1: cmp>0? 1: 0;
1156 }
1157
1158 static int compareDate(const void* arg1, const void* arg2)
1159 {
1160         const WIN32_FIND_DATAW* fd1 = &(*(const Entry* const*)arg1)->data;
1161         const WIN32_FIND_DATAW* fd2 = &(*(const Entry* const*)arg2)->data;
1162
1163         int cmp = compareType(fd1, fd2);
1164         if (cmp)
1165                 return cmp;
1166
1167         return CompareFileTime(&fd2->ftLastWriteTime, &fd1->ftLastWriteTime);
1168 }
1169
1170
1171 static int (*sortFunctions[])(const void* arg1, const void* arg2) = {
1172         compareName,    /* SORT_NAME */
1173         compareExt,             /* SORT_EXT */
1174         compareSize,    /* SORT_SIZE */
1175         compareDate             /* SORT_DATE */
1176 };
1177
1178
1179 static void SortDirectory(Entry* dir, SORT_ORDER sortOrder)
1180 {
1181         Entry* entry = dir->down;
1182         Entry** array, **p;
1183         int len;
1184
1185         len = 0;
1186         for(entry=dir->down; entry; entry=entry->next)
1187                 len++;
1188
1189         if (len) {
1190                 array = HeapAlloc(GetProcessHeap(), 0, len*sizeof(Entry*));
1191
1192                 p = array;
1193                 for(entry=dir->down; entry; entry=entry->next)
1194                         *p++ = entry;
1195
1196                 /* call qsort with the appropriate compare function */
1197                 qsort(array, len, sizeof(array[0]), sortFunctions[sortOrder]);
1198
1199                 dir->down = array[0];
1200
1201                 for(p=array; --len; p++)
1202                         p[0]->next = p[1];
1203
1204                 (*p)->next = 0;
1205
1206                 HeapFree(GetProcessHeap(), 0, array);
1207         }
1208 }
1209
1210
1211 static void read_directory(Entry* dir, LPCWSTR path, SORT_ORDER sortOrder, HWND hwnd)
1212 {
1213         WCHAR buffer[MAX_PATH];
1214         Entry* entry;
1215         LPCWSTR s;
1216         PWSTR d;
1217
1218 #ifdef _SHELL_FOLDERS
1219         if (dir->etype == ET_SHELL)
1220         {
1221                 read_directory_shell(dir, hwnd);
1222
1223                 if (Globals.prescan_node) {
1224                         s = path;
1225                         d = buffer;
1226
1227                         while(*s)
1228                                 *d++ = *s++;
1229
1230                         *d++ = '\\';
1231
1232                         for(entry=dir->down; entry; entry=entry->next)
1233                                 if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1234                                         read_directory_shell(entry, hwnd);
1235                                         SortDirectory(entry, sortOrder);
1236                                 }
1237                 }
1238         }
1239         else
1240 #endif
1241 #if !defined(_NO_EXTENSIONS) && defined(__WINE__)
1242         if (dir->etype == ET_UNIX)
1243         {
1244                 read_directory_unix(dir, path);
1245
1246                 if (Globals.prescan_node) {
1247                         s = path;
1248                         d = buffer;
1249
1250                         while(*s)
1251                                 *d++ = *s++;
1252
1253                         *d++ = '/';
1254
1255                         for(entry=dir->down; entry; entry=entry->next)
1256                                 if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1257                                         lstrcpyW(d, entry->data.cFileName);
1258                                         read_directory_unix(entry, buffer);
1259                                         SortDirectory(entry, sortOrder);
1260                                 }
1261                 }
1262         }
1263         else
1264 #endif
1265         {
1266                 read_directory_win(dir, path);
1267
1268                 if (Globals.prescan_node) {
1269                         s = path;
1270                         d = buffer;
1271
1272                         while(*s)
1273                                 *d++ = *s++;
1274
1275                         *d++ = '\\';
1276
1277                         for(entry=dir->down; entry; entry=entry->next)
1278                                 if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1279                                         lstrcpyW(d, entry->data.cFileName);
1280                                         read_directory_win(entry, buffer);
1281                                         SortDirectory(entry, sortOrder);
1282                                 }
1283                 }
1284         }
1285
1286         SortDirectory(dir, sortOrder);
1287 }
1288
1289
1290 static Entry* read_tree(Root* root, LPCWSTR path, LPITEMIDLIST pidl, LPWSTR drv, SORT_ORDER sortOrder, HWND hwnd)
1291 {
1292 #if !defined(_NO_EXTENSIONS) && defined(__WINE__)
1293         static const WCHAR sSlash[] = {'/', '\0'};
1294 #endif
1295         static const WCHAR sBackslash[] = {'\\', '\0'};
1296
1297 #ifdef _SHELL_FOLDERS
1298         if (pidl)
1299         {
1300                  /* read shell namespace tree */
1301                 root->drive_type = DRIVE_UNKNOWN;
1302                 drv[0] = '\\';
1303                 drv[1] = '\0';
1304                 load_string(root->volname, sizeof(root->volname)/sizeof(root->volname[0]), IDS_DESKTOP);
1305                 root->fs_flags = 0;
1306                 load_string(root->fs, sizeof(root->fs)/sizeof(root->fs[0]), IDS_SHELL);
1307
1308                 return read_tree_shell(root, pidl, sortOrder, hwnd);
1309         }
1310         else
1311 #endif
1312 #if !defined(_NO_EXTENSIONS) && defined(__WINE__)
1313         if (*path == '/')
1314         {
1315                 /* read unix file system tree */
1316                 root->drive_type = GetDriveTypeW(path);
1317
1318                 lstrcatW(drv, sSlash);
1319                 load_string(root->volname, sizeof(root->volname)/sizeof(root->volname[0]), IDS_ROOT_FS);
1320                 root->fs_flags = 0;
1321                 load_string(root->fs, sizeof(root->fs)/sizeof(root->fs[0]), IDS_UNIXFS);
1322
1323                 lstrcpyW(root->path, sSlash);
1324
1325                 return read_tree_unix(root, path, sortOrder, hwnd);
1326         }
1327 #endif
1328
1329          /* read WIN32 file system tree */
1330        root->drive_type = GetDriveTypeW(path);
1331
1332         lstrcatW(drv, sBackslash);
1333         GetVolumeInformationW(drv, root->volname, _MAX_FNAME, 0, 0, &root->fs_flags, root->fs, _MAX_DIR);
1334
1335         lstrcpyW(root->path, drv);
1336
1337         return read_tree_win(root, path, sortOrder, hwnd);
1338 }
1339
1340
1341 /* flags to filter different file types */
1342 enum TYPE_FILTER {
1343         TF_DIRECTORIES  = 0x01,
1344         TF_PROGRAMS             = 0x02,
1345         TF_DOCUMENTS    = 0x04,
1346         TF_OTHERS               = 0x08,
1347         TF_HIDDEN               = 0x10,
1348         TF_ALL                  = 0x1F
1349 };
1350
1351
1352 static ChildWnd* alloc_child_window(LPCWSTR path, LPITEMIDLIST pidl, HWND hwnd)
1353 {
1354         WCHAR drv[_MAX_DRIVE+1], dir[_MAX_DIR], name[_MAX_FNAME], ext[_MAX_EXT];
1355         WCHAR dir_path[MAX_PATH];
1356         WCHAR b1[BUFFER_LEN];
1357         static const WCHAR sAsterics[] = {'*', '\0'};
1358
1359         ChildWnd* child = HeapAlloc(GetProcessHeap(), 0, sizeof(ChildWnd));
1360         Root* root = &child->root;
1361         Entry* entry;
1362
1363         memset(child, 0, sizeof(ChildWnd));
1364
1365         child->left.treePane = TRUE;
1366         child->left.visible_cols = 0;
1367
1368         child->right.treePane = FALSE;
1369 #ifndef _NO_EXTENSIONS
1370         child->right.visible_cols = COL_SIZE|COL_DATE|COL_TIME|COL_ATTRIBUTES|COL_INDEX|COL_LINKS;
1371 #else
1372         child->right.visible_cols = COL_SIZE|COL_DATE|COL_TIME|COL_ATTRIBUTES;
1373 #endif
1374
1375         child->pos.length = sizeof(WINDOWPLACEMENT);
1376         child->pos.flags = 0;
1377         child->pos.showCmd = SW_SHOWNORMAL;
1378         child->pos.rcNormalPosition.left = CW_USEDEFAULT;
1379         child->pos.rcNormalPosition.top = CW_USEDEFAULT;
1380         child->pos.rcNormalPosition.right = CW_USEDEFAULT;
1381         child->pos.rcNormalPosition.bottom = CW_USEDEFAULT;
1382
1383         child->focus_pane = 0;
1384         child->split_pos = DEFAULT_SPLIT_POS;
1385         child->sortOrder = SORT_NAME;
1386         child->header_wdths_ok = FALSE;
1387
1388         if (path)
1389         {
1390                 lstrcpyW(child->path, path);
1391
1392                 _wsplitpath(path, drv, dir, name, ext);
1393         }
1394
1395         lstrcpyW(child->filter_pattern, sAsterics);
1396         child->filter_flags = TF_ALL;
1397
1398         root->entry.level = 0;
1399
1400         lstrcpyW(dir_path, drv);
1401         lstrcatW(dir_path, dir);
1402         entry = read_tree(root, dir_path, pidl, drv, child->sortOrder, hwnd);
1403
1404 #ifdef _SHELL_FOLDERS
1405         if (root->entry.etype == ET_SHELL)
1406                 load_string(root->entry.data.cFileName, sizeof(root->entry.data.cFileName)/sizeof(root->entry.data.cFileName[0]), IDS_DESKTOP);
1407         else
1408 #endif
1409                 wsprintfW(root->entry.data.cFileName, RS(b1,IDS_TITLEFMT), drv, root->fs);
1410
1411         root->entry.data.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
1412
1413         child->left.root = &root->entry;
1414         child->right.root = NULL;
1415
1416         set_curdir(child, entry, 0, hwnd);
1417
1418         return child;
1419 }
1420
1421
1422 /* free all memory associated with a child window */
1423 static void free_child_window(ChildWnd* child)
1424 {
1425         free_entries(&child->root.entry);
1426         HeapFree(GetProcessHeap(), 0, child);
1427 }
1428
1429
1430 /* get full path of specified directory entry */
1431 static void get_path(Entry* dir, PWSTR path)
1432 {
1433         Entry* entry;
1434         int len = 0;
1435         int level = 0;
1436
1437 #ifdef _SHELL_FOLDERS
1438         if (dir->etype == ET_SHELL)
1439         {
1440                 SFGAOF attribs;
1441                 HRESULT hr = S_OK;
1442
1443                 path[0] = '\0';
1444
1445                 attribs = 0;
1446
1447                 if (dir->folder)
1448                         hr = IShellFolder_GetAttributesOf(dir->folder, 1, (LPCITEMIDLIST*)&dir->pidl, &attribs);
1449
1450                 if (SUCCEEDED(hr) && (attribs&SFGAO_FILESYSTEM)) {
1451                         IShellFolder* parent = dir->up? dir->up->folder: Globals.iDesktop;
1452
1453                         hr = path_from_pidlW(parent, dir->pidl, path, MAX_PATH);
1454                 }
1455         }
1456         else
1457 #endif
1458         {
1459                 for(entry=dir; entry; level++) {
1460                         LPCWSTR name;
1461                         int l;
1462
1463                         {
1464                                 LPCWSTR s;
1465                                 name = entry->data.cFileName;
1466                                 s = name;
1467
1468                                 for(l=0; *s && *s != '/' && *s != '\\'; s++)
1469                                         l++;
1470                         }
1471
1472                         if (entry->up) {
1473                                 if (l > 0) {
1474                                         memmove(path+l+1, path, len*sizeof(WCHAR));
1475                                         memcpy(path+1, name, l*sizeof(WCHAR));
1476                                         len += l+1;
1477
1478 #ifndef _NO_EXTENSIONS
1479                                         if (entry->etype == ET_UNIX)
1480                                                 path[0] = '/';
1481                                         else
1482 #endif
1483                                         path[0] = '\\';
1484                                 }
1485
1486                                 entry = entry->up;
1487                         } else {
1488                                 memmove(path+l, path, len*sizeof(WCHAR));
1489                                 memcpy(path, name, l*sizeof(WCHAR));
1490                                 len += l;
1491                                 break;
1492                         }
1493                 }
1494
1495                 if (!level) {
1496 #ifndef _NO_EXTENSIONS
1497                         if (entry->etype == ET_UNIX)
1498                                 path[len++] = '/';
1499                         else
1500 #endif
1501                                 path[len++] = '\\';
1502                 }
1503
1504                 path[len] = '\0';
1505         }
1506 }
1507
1508 static windowOptions load_registry_settings(void)
1509 {
1510         DWORD size;
1511         DWORD type;
1512         HKEY hKey;
1513         windowOptions opts;
1514         LOGFONTW logfont;
1515
1516         RegOpenKeyExW( HKEY_CURRENT_USER, registry_key,
1517                        0, KEY_QUERY_VALUE, &hKey );
1518
1519         size = sizeof(DWORD);
1520
1521         if( RegQueryValueExW( hKey, reg_start_x, NULL, &type,
1522                               (LPBYTE) &opts.start_x, &size ) != ERROR_SUCCESS )
1523                 opts.start_x = CW_USEDEFAULT;
1524
1525         if( RegQueryValueExW( hKey, reg_start_y, NULL, &type,
1526                               (LPBYTE) &opts.start_y, &size ) != ERROR_SUCCESS )
1527                 opts.start_y = CW_USEDEFAULT;
1528
1529         if( RegQueryValueExW( hKey, reg_width, NULL, &type,
1530                               (LPBYTE) &opts.width, &size ) != ERROR_SUCCESS )
1531                 opts.width = CW_USEDEFAULT;
1532
1533         if( RegQueryValueExW( hKey, reg_height, NULL, &type,
1534                               (LPBYTE) &opts.height, &size ) != ERROR_SUCCESS )
1535                 opts.height = CW_USEDEFAULT;
1536         size=sizeof(logfont);
1537         if( RegQueryValueExW( hKey, reg_logfont, NULL, &type,
1538                               (LPBYTE) &logfont, &size ) != ERROR_SUCCESS )
1539                 GetObjectW(GetStockObject(DEFAULT_GUI_FONT),sizeof(logfont),&logfont);
1540
1541         RegCloseKey( hKey );
1542
1543         Globals.hfont = CreateFontIndirectW(&logfont);
1544         return opts;
1545 }
1546
1547 static void save_registry_settings(void)
1548 {
1549         WINDOWINFO wi;
1550         HKEY hKey;
1551         INT width, height;
1552         LOGFONTW logfont;
1553
1554         wi.cbSize = sizeof( WINDOWINFO );
1555         GetWindowInfo(Globals.hMainWnd, &wi);
1556         width = wi.rcWindow.right - wi.rcWindow.left;
1557         height = wi.rcWindow.bottom - wi.rcWindow.top;
1558
1559         if ( RegOpenKeyExW( HKEY_CURRENT_USER, registry_key,
1560                             0, KEY_SET_VALUE, &hKey ) != ERROR_SUCCESS )
1561         {
1562                 /* Unable to save registry settings - try to create key */
1563                 if ( RegCreateKeyExW( HKEY_CURRENT_USER, registry_key,
1564                                       0, NULL, REG_OPTION_NON_VOLATILE,
1565                                       KEY_SET_VALUE, NULL, &hKey, NULL ) != ERROR_SUCCESS )
1566                 {
1567                         /* FIXME: Cannot create key */
1568                         return;
1569                 }
1570         }
1571         /* Save all of the settings */
1572         RegSetValueExW( hKey, reg_start_x, 0, REG_DWORD,
1573                         (LPBYTE) &wi.rcWindow.left, sizeof(DWORD) );
1574         RegSetValueExW( hKey, reg_start_y, 0, REG_DWORD,
1575                         (LPBYTE) &wi.rcWindow.top, sizeof(DWORD) );
1576         RegSetValueExW( hKey, reg_width, 0, REG_DWORD,
1577                         (LPBYTE) &width, sizeof(DWORD) );
1578         RegSetValueExW( hKey, reg_height, 0, REG_DWORD,
1579                         (LPBYTE) &height, sizeof(DWORD) );
1580         GetObjectW(Globals.hfont, sizeof(logfont), &logfont);
1581         RegSetValueExW( hKey, reg_logfont, 0, REG_BINARY,
1582                         (LPBYTE)&logfont, sizeof(LOGFONTW) );
1583
1584         /* TODO: Save more settings here (List vs. Detailed View, etc.) */
1585         RegCloseKey( hKey );
1586 }
1587
1588 static void resize_frame_rect(HWND hwnd, PRECT prect)
1589 {
1590         int new_top;
1591         RECT rt;
1592
1593         if (IsWindowVisible(Globals.htoolbar)) {
1594                 SendMessageW(Globals.htoolbar, WM_SIZE, 0, 0);
1595                 GetClientRect(Globals.htoolbar, &rt);
1596                 prect->top = rt.bottom+3;
1597                 prect->bottom -= rt.bottom+3;
1598         }
1599
1600         if (IsWindowVisible(Globals.hdrivebar)) {
1601                 SendMessageW(Globals.hdrivebar, WM_SIZE, 0, 0);
1602                 GetClientRect(Globals.hdrivebar, &rt);
1603                 new_top = --prect->top + rt.bottom+3;
1604                 MoveWindow(Globals.hdrivebar, 0, prect->top, rt.right, new_top, TRUE);
1605                 prect->top = new_top;
1606                 prect->bottom -= rt.bottom+2;
1607         }
1608
1609         if (IsWindowVisible(Globals.hstatusbar)) {
1610                 int parts[] = {300, 500};
1611
1612                 SendMessageW(Globals.hstatusbar, WM_SIZE, 0, 0);
1613                 SendMessageW(Globals.hstatusbar, SB_SETPARTS, 2, (LPARAM)&parts);
1614                 GetClientRect(Globals.hstatusbar, &rt);
1615                 prect->bottom -= rt.bottom;
1616         }
1617
1618         MoveWindow(Globals.hmdiclient, prect->left-1,prect->top-1,prect->right+2,prect->bottom+1, TRUE);
1619 }
1620
1621 static void resize_frame(HWND hwnd, int cx, int cy)
1622 {
1623         RECT rect;
1624
1625         rect.left   = 0;
1626         rect.top    = 0;
1627         rect.right  = cx;
1628         rect.bottom = cy;
1629
1630         resize_frame_rect(hwnd, &rect);
1631 }
1632
1633 static void resize_frame_client(HWND hwnd)
1634 {
1635         RECT rect;
1636
1637         GetClientRect(hwnd, &rect);
1638
1639         resize_frame_rect(hwnd, &rect);
1640 }
1641
1642
1643 static HHOOK hcbthook;
1644 static ChildWnd* newchild = NULL;
1645
1646 static LRESULT CALLBACK CBTProc(int code, WPARAM wparam, LPARAM lparam)
1647 {
1648         if (code==HCBT_CREATEWND && newchild) {
1649                 ChildWnd* child = newchild;
1650                 newchild = NULL;
1651
1652                 child->hwnd = (HWND) wparam;
1653                 SetWindowLongPtrW(child->hwnd, GWLP_USERDATA, (LPARAM)child);
1654         }
1655
1656         return CallNextHookEx(hcbthook, code, wparam, lparam);
1657 }
1658
1659 static HWND create_child_window(ChildWnd* child)
1660 {
1661         MDICREATESTRUCTW mcs;
1662         int idx;
1663
1664         mcs.szClass = sWINEFILETREE;
1665         mcs.szTitle = child->path;
1666         mcs.hOwner  = Globals.hInstance;
1667         mcs.x       = child->pos.rcNormalPosition.left;
1668         mcs.y       = child->pos.rcNormalPosition.top;
1669         mcs.cx      = child->pos.rcNormalPosition.right-child->pos.rcNormalPosition.left;
1670         mcs.cy      = child->pos.rcNormalPosition.bottom-child->pos.rcNormalPosition.top;
1671         mcs.style   = 0;
1672         mcs.lParam  = 0;
1673
1674         hcbthook = SetWindowsHookExW(WH_CBT, CBTProc, 0, GetCurrentThreadId());
1675
1676         newchild = child;
1677         child->hwnd = (HWND)SendMessageW(Globals.hmdiclient, WM_MDICREATE, 0, (LPARAM)&mcs);
1678         if (!child->hwnd) {
1679                 UnhookWindowsHookEx(hcbthook);
1680                 return 0;
1681         }
1682
1683         UnhookWindowsHookEx(hcbthook);
1684
1685         SendMessageW(child->left.hwnd, LB_SETITEMHEIGHT, 1, max(Globals.spaceSize.cy,IMAGE_HEIGHT+3));
1686         SendMessageW(child->right.hwnd, LB_SETITEMHEIGHT, 1, max(Globals.spaceSize.cy,IMAGE_HEIGHT+3));
1687
1688         idx = SendMessageW(child->left.hwnd, LB_FINDSTRING, 0, (LPARAM)child->left.cur);
1689         SendMessageW(child->left.hwnd, LB_SETCURSEL, idx, 0);
1690
1691         return child->hwnd;
1692 }
1693
1694 #define RFF_NODEFAULT           0x02    /* No default item selected. */
1695
1696 static void WineFile_OnRun( HWND hwnd )
1697 {
1698         static const WCHAR shell32_dll[] = {'S','H','E','L','L','3','2','.','D','L','L',0};
1699         void (WINAPI *pRunFileDlgAW )(HWND, HICON, LPWSTR, LPWSTR, LPWSTR, DWORD);
1700         HMODULE hshell = GetModuleHandleW( shell32_dll );
1701
1702         pRunFileDlgAW = (void*)GetProcAddress(hshell, (LPCSTR)61);
1703         if (pRunFileDlgAW) pRunFileDlgAW( hwnd, 0, NULL, NULL, NULL, RFF_NODEFAULT);
1704 }
1705
1706 static INT_PTR CALLBACK DestinationDlgProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
1707 {
1708         WCHAR b1[BUFFER_LEN], b2[BUFFER_LEN];
1709
1710         switch(nmsg) {
1711                 case WM_INITDIALOG:
1712                         SetWindowLongPtrW(hwnd, GWLP_USERDATA, lparam);
1713                         SetWindowTextW(GetDlgItem(hwnd, 201), (LPCWSTR)lparam);
1714                         return 1;
1715
1716                 case WM_COMMAND: {
1717                         int id = (int)wparam;
1718
1719                         switch(id) {
1720                           case IDOK: {
1721                                 LPWSTR dest = (LPWSTR)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
1722                                 GetWindowTextW(GetDlgItem(hwnd, 201), dest, MAX_PATH);
1723                                 EndDialog(hwnd, id);
1724                                 break;}
1725
1726                           case IDCANCEL:
1727                                 EndDialog(hwnd, id);
1728                                 break;
1729
1730                           case 254:
1731                                 MessageBoxW(hwnd, RS(b1,IDS_NO_IMPL), RS(b2,IDS_WINEFILE), MB_OK);
1732                                 break;
1733                         }
1734
1735                         return 1;
1736                 }
1737         }
1738
1739         return 0;
1740 }
1741
1742
1743 struct FilterDialog {
1744         WCHAR   pattern[MAX_PATH];
1745         int             flags;
1746 };
1747
1748 static INT_PTR CALLBACK FilterDialogDlgProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
1749 {
1750         static struct FilterDialog* dlg;
1751
1752         switch(nmsg) {
1753                 case WM_INITDIALOG:
1754                         dlg = (struct FilterDialog*) lparam;
1755                         SetWindowTextW(GetDlgItem(hwnd, IDC_VIEW_PATTERN), dlg->pattern);
1756                         set_check(hwnd, IDC_VIEW_TYPE_DIRECTORIES, dlg->flags&TF_DIRECTORIES);
1757                         set_check(hwnd, IDC_VIEW_TYPE_PROGRAMS, dlg->flags&TF_PROGRAMS);
1758                         set_check(hwnd, IDC_VIEW_TYPE_DOCUMENTS, dlg->flags&TF_DOCUMENTS);
1759                         set_check(hwnd, IDC_VIEW_TYPE_OTHERS, dlg->flags&TF_OTHERS);
1760                         set_check(hwnd, IDC_VIEW_TYPE_HIDDEN, dlg->flags&TF_HIDDEN);
1761                         return 1;
1762
1763                 case WM_COMMAND: {
1764                         int id = (int)wparam;
1765
1766                         if (id == IDOK) {
1767                                 int flags = 0;
1768
1769                                 GetWindowTextW(GetDlgItem(hwnd, IDC_VIEW_PATTERN), dlg->pattern, MAX_PATH);
1770
1771                                 flags |= get_check(hwnd, IDC_VIEW_TYPE_DIRECTORIES) ? TF_DIRECTORIES : 0;
1772                                 flags |= get_check(hwnd, IDC_VIEW_TYPE_PROGRAMS) ? TF_PROGRAMS : 0;
1773                                 flags |= get_check(hwnd, IDC_VIEW_TYPE_DOCUMENTS) ? TF_DOCUMENTS : 0;
1774                                 flags |= get_check(hwnd, IDC_VIEW_TYPE_OTHERS) ? TF_OTHERS : 0;
1775                                 flags |= get_check(hwnd, IDC_VIEW_TYPE_HIDDEN) ? TF_HIDDEN : 0;
1776
1777                                 dlg->flags = flags;
1778
1779                                 EndDialog(hwnd, id);
1780                         } else if (id == IDCANCEL)
1781                                 EndDialog(hwnd, id);
1782
1783                         return 1;}
1784         }
1785
1786         return 0;
1787 }
1788
1789
1790 struct PropertiesDialog {
1791         WCHAR   path[MAX_PATH];
1792         Entry   entry;
1793         void*   pVersionData;
1794 };
1795
1796 /* Structure used to store enumerated languages and code pages. */
1797 struct LANGANDCODEPAGE {
1798         WORD wLanguage;
1799         WORD wCodePage;
1800 } *lpTranslate;
1801
1802 static LPCSTR InfoStrings[] = {
1803         "Comments",
1804         "CompanyName",
1805         "FileDescription",
1806         "FileVersion",
1807         "InternalName",
1808         "LegalCopyright",
1809         "LegalTrademarks",
1810         "OriginalFilename",
1811         "PrivateBuild",
1812         "ProductName",
1813         "ProductVersion",
1814         "SpecialBuild",
1815         NULL
1816 };
1817
1818 static void PropDlg_DisplayValue(HWND hlbox, HWND hedit)
1819 {
1820         int idx = SendMessageW(hlbox, LB_GETCURSEL, 0, 0);
1821
1822         if (idx != LB_ERR) {
1823                 LPCWSTR pValue = (LPCWSTR)SendMessageW(hlbox, LB_GETITEMDATA, idx, 0);
1824
1825                 if (pValue)
1826                         SetWindowTextW(hedit, pValue);
1827         }
1828 }
1829
1830 static void CheckForFileInfo(struct PropertiesDialog* dlg, HWND hwnd, LPCWSTR strFilename)
1831 {
1832         static WCHAR sBackSlash[] = {'\\','\0'};
1833         static WCHAR sTranslation[] = {'\\','V','a','r','F','i','l','e','I','n','f','o','\\','T','r','a','n','s','l','a','t','i','o','n','\0'};
1834         static WCHAR sStringFileInfo[] = {'\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o','\\',
1835                                                                                 '%','0','4','x','%','0','4','x','\\','%','s','\0'};
1836         DWORD dwVersionDataLen = GetFileVersionInfoSizeW(strFilename, NULL);
1837
1838         if (dwVersionDataLen) {
1839                 dlg->pVersionData = HeapAlloc(GetProcessHeap(), 0, dwVersionDataLen);
1840
1841                 if (GetFileVersionInfoW(strFilename, 0, dwVersionDataLen, dlg->pVersionData)) {
1842                         LPVOID pVal;
1843                         UINT nValLen;
1844
1845                         if (VerQueryValueW(dlg->pVersionData, sBackSlash, &pVal, &nValLen)) {
1846                                 if (nValLen == sizeof(VS_FIXEDFILEINFO)) {
1847                                         VS_FIXEDFILEINFO* pFixedFileInfo = (VS_FIXEDFILEINFO*)pVal;
1848                                         char buffer[BUFFER_LEN];
1849
1850                                         sprintf(buffer, "%d.%d.%d.%d",
1851                                                 HIWORD(pFixedFileInfo->dwFileVersionMS), LOWORD(pFixedFileInfo->dwFileVersionMS),
1852                                                 HIWORD(pFixedFileInfo->dwFileVersionLS), LOWORD(pFixedFileInfo->dwFileVersionLS));
1853
1854                                         SetDlgItemTextA(hwnd, IDC_STATIC_PROP_VERSION, buffer);
1855                                 }
1856                         }
1857
1858                         /* Read the list of languages and code pages. */
1859                         if (VerQueryValueW(dlg->pVersionData, sTranslation, &pVal, &nValLen)) {
1860                                 struct LANGANDCODEPAGE* pTranslate = (struct LANGANDCODEPAGE*)pVal;
1861                                 struct LANGANDCODEPAGE* pEnd = (struct LANGANDCODEPAGE*)((LPBYTE)pVal+nValLen);
1862
1863                                 HWND hlbox = GetDlgItem(hwnd, IDC_LIST_PROP_VERSION_TYPES);
1864
1865                                 /* Read the file description for each language and code page. */
1866                                 for(; pTranslate<pEnd; ++pTranslate) {
1867                                         LPCSTR* p;
1868
1869                                         for(p=InfoStrings; *p; ++p) {
1870                                                 WCHAR subblock[200];
1871                                                 WCHAR infoStr[100];
1872                                                 LPCWSTR pTxt;
1873                                                 UINT nValLen;
1874
1875                                                 LPCSTR pInfoString = *p;
1876                                                 MultiByteToWideChar(CP_ACP, 0, pInfoString, -1, infoStr, 100);
1877                                                 wsprintfW(subblock, sStringFileInfo, pTranslate->wLanguage, pTranslate->wCodePage, infoStr);
1878
1879                                                 /* Retrieve file description for language and code page */
1880                                                 if (VerQueryValueW(dlg->pVersionData, subblock, (PVOID)&pTxt, &nValLen)) {
1881                                                         int idx = SendMessageW(hlbox, LB_ADDSTRING, 0L, (LPARAM)infoStr);
1882                                                         SendMessageW(hlbox, LB_SETITEMDATA, idx, (LPARAM)pTxt);
1883                                                 }
1884                                         }
1885                                 }
1886
1887                                 SendMessageW(hlbox, LB_SETCURSEL, 0, 0);
1888
1889                                 PropDlg_DisplayValue(hlbox, GetDlgItem(hwnd,IDC_LIST_PROP_VERSION_VALUES));
1890                         }
1891                 }
1892         }
1893 }
1894
1895 static INT_PTR CALLBACK PropertiesDialogDlgProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
1896 {
1897         static struct PropertiesDialog* dlg;
1898
1899         switch(nmsg) {
1900                 case WM_INITDIALOG: {
1901                         static const WCHAR sByteFmt[] = {'%','s',' ','B','y','t','e','s','\0'};
1902                         WCHAR b1[BUFFER_LEN], b2[BUFFER_LEN];
1903                         LPWIN32_FIND_DATAW pWFD;
1904
1905                         dlg = (struct PropertiesDialog*) lparam;
1906                         pWFD = (LPWIN32_FIND_DATAW)&dlg->entry.data;
1907
1908                         GetWindowTextW(hwnd, b1, MAX_PATH);
1909                         wsprintfW(b2, b1, pWFD->cFileName);
1910                         SetWindowTextW(hwnd, b2);
1911
1912                         format_date(&pWFD->ftLastWriteTime, b1, COL_DATE|COL_TIME);
1913                         SetWindowTextW(GetDlgItem(hwnd, IDC_STATIC_PROP_LASTCHANGE), b1);
1914
1915                         format_longlong( b1, ((ULONGLONG)pWFD->nFileSizeHigh << 32) | pWFD->nFileSizeLow );
1916                         wsprintfW(b2, sByteFmt, b1);
1917                         SetWindowTextW(GetDlgItem(hwnd, IDC_STATIC_PROP_SIZE), b2);
1918
1919                         SetWindowTextW(GetDlgItem(hwnd, IDC_STATIC_PROP_FILENAME), pWFD->cFileName);
1920                         SetWindowTextW(GetDlgItem(hwnd, IDC_STATIC_PROP_PATH), dlg->path);
1921
1922                         set_check(hwnd, IDC_CHECK_READONLY, pWFD->dwFileAttributes&FILE_ATTRIBUTE_READONLY);
1923                         set_check(hwnd, IDC_CHECK_ARCHIVE, pWFD->dwFileAttributes&FILE_ATTRIBUTE_ARCHIVE);
1924                         set_check(hwnd, IDC_CHECK_COMPRESSED, pWFD->dwFileAttributes&FILE_ATTRIBUTE_COMPRESSED);
1925                         set_check(hwnd, IDC_CHECK_HIDDEN, pWFD->dwFileAttributes&FILE_ATTRIBUTE_HIDDEN);
1926                         set_check(hwnd, IDC_CHECK_SYSTEM, pWFD->dwFileAttributes&FILE_ATTRIBUTE_SYSTEM);
1927
1928                         CheckForFileInfo(dlg, hwnd, dlg->path);
1929                         return 1;}
1930
1931                 case WM_COMMAND: {
1932                         int id = (int)wparam;
1933
1934                         switch(HIWORD(wparam)) {
1935                           case LBN_SELCHANGE: {
1936                                 HWND hlbox = GetDlgItem(hwnd, IDC_LIST_PROP_VERSION_TYPES);
1937                                 PropDlg_DisplayValue(hlbox, GetDlgItem(hwnd,IDC_LIST_PROP_VERSION_VALUES));
1938                                 break;
1939                           }
1940
1941                           case BN_CLICKED:
1942                                 if (id==IDOK || id==IDCANCEL)
1943                                         EndDialog(hwnd, id);
1944                         }
1945
1946                         return 1;}
1947
1948                 case WM_NCDESTROY:
1949                         HeapFree(GetProcessHeap(), 0, dlg->pVersionData);
1950                         dlg->pVersionData = NULL;
1951                         break;
1952         }
1953
1954         return 0;
1955 }
1956
1957 static void show_properties_dlg(Entry* entry, HWND hwnd)
1958 {
1959         struct PropertiesDialog dlg;
1960
1961         memset(&dlg, 0, sizeof(struct PropertiesDialog));
1962         get_path(entry, dlg.path);
1963         memcpy(&dlg.entry, entry, sizeof(Entry));
1964
1965         DialogBoxParamW(Globals.hInstance, MAKEINTRESOURCEW(IDD_DIALOG_PROPERTIES), hwnd, PropertiesDialogDlgProc, (LPARAM)&dlg);
1966 }
1967
1968
1969 #ifndef _NO_EXTENSIONS
1970
1971 static struct FullScreenParameters {
1972         BOOL    mode;
1973         RECT    orgPos;
1974         BOOL    wasZoomed;
1975 } g_fullscreen = {
1976     FALSE,      /* mode */
1977         {0, 0, 0, 0},
1978         FALSE
1979 };
1980
1981 static void frame_get_clientspace(HWND hwnd, PRECT prect)
1982 {
1983         RECT rt;
1984
1985         if (!IsIconic(hwnd))
1986                 GetClientRect(hwnd, prect);
1987         else {
1988                 WINDOWPLACEMENT wp;
1989
1990                 GetWindowPlacement(hwnd, &wp);
1991
1992                 prect->left = prect->top = 0;
1993                 prect->right = wp.rcNormalPosition.right-wp.rcNormalPosition.left-
1994                                                 2*(GetSystemMetrics(SM_CXSIZEFRAME)+GetSystemMetrics(SM_CXEDGE));
1995                 prect->bottom = wp.rcNormalPosition.bottom-wp.rcNormalPosition.top-
1996                                                 2*(GetSystemMetrics(SM_CYSIZEFRAME)+GetSystemMetrics(SM_CYEDGE))-
1997                                                 GetSystemMetrics(SM_CYCAPTION)-GetSystemMetrics(SM_CYMENUSIZE);
1998         }
1999
2000         if (IsWindowVisible(Globals.htoolbar)) {
2001                 GetClientRect(Globals.htoolbar, &rt);
2002                 prect->top += rt.bottom+2;
2003         }
2004
2005         if (IsWindowVisible(Globals.hdrivebar)) {
2006                 GetClientRect(Globals.hdrivebar, &rt);
2007                 prect->top += rt.bottom+2;
2008         }
2009
2010         if (IsWindowVisible(Globals.hstatusbar)) {
2011                 GetClientRect(Globals.hstatusbar, &rt);
2012                 prect->bottom -= rt.bottom;
2013         }
2014 }
2015
2016 static BOOL toggle_fullscreen(HWND hwnd)
2017 {
2018         RECT rt;
2019
2020         if ((g_fullscreen.mode=!g_fullscreen.mode)) {
2021                 GetWindowRect(hwnd, &g_fullscreen.orgPos);
2022                 g_fullscreen.wasZoomed = IsZoomed(hwnd);
2023
2024                 Frame_CalcFrameClient(hwnd, &rt);
2025                 MapWindowPoints( hwnd, 0, (POINT *)&rt, 2 );
2026
2027                 rt.left = g_fullscreen.orgPos.left-rt.left;
2028                 rt.top = g_fullscreen.orgPos.top-rt.top;
2029                 rt.right = GetSystemMetrics(SM_CXSCREEN)+g_fullscreen.orgPos.right-rt.right;
2030                 rt.bottom = GetSystemMetrics(SM_CYSCREEN)+g_fullscreen.orgPos.bottom-rt.bottom;
2031
2032                 MoveWindow(hwnd, rt.left, rt.top, rt.right-rt.left, rt.bottom-rt.top, TRUE);
2033         } else {
2034                 MoveWindow(hwnd, g_fullscreen.orgPos.left, g_fullscreen.orgPos.top,
2035                                                         g_fullscreen.orgPos.right-g_fullscreen.orgPos.left,
2036                                                         g_fullscreen.orgPos.bottom-g_fullscreen.orgPos.top, TRUE);
2037
2038                 if (g_fullscreen.wasZoomed)
2039                         ShowWindow(hwnd, WS_MAXIMIZE);
2040         }
2041
2042         return g_fullscreen.mode;
2043 }
2044
2045 static void fullscreen_move(HWND hwnd)
2046 {
2047         RECT rt, pos;
2048         GetWindowRect(hwnd, &pos);
2049
2050         Frame_CalcFrameClient(hwnd, &rt);
2051         MapWindowPoints( hwnd, 0, (POINT *)&rt, 2 );
2052
2053         rt.left = pos.left-rt.left;
2054         rt.top = pos.top-rt.top;
2055         rt.right = GetSystemMetrics(SM_CXSCREEN)+pos.right-rt.right;
2056         rt.bottom = GetSystemMetrics(SM_CYSCREEN)+pos.bottom-rt.bottom;
2057
2058         MoveWindow(hwnd, rt.left, rt.top, rt.right-rt.left, rt.bottom-rt.top, TRUE);
2059 }
2060
2061 #endif
2062
2063
2064 static void toggle_child(HWND hwnd, UINT cmd, HWND hchild)
2065 {
2066         BOOL vis = IsWindowVisible(hchild);
2067
2068         CheckMenuItem(Globals.hMenuOptions, cmd, vis?MF_BYCOMMAND:MF_BYCOMMAND|MF_CHECKED);
2069
2070         ShowWindow(hchild, vis?SW_HIDE:SW_SHOW);
2071
2072 #ifndef _NO_EXTENSIONS
2073         if (g_fullscreen.mode)
2074                 fullscreen_move(hwnd);
2075 #endif
2076
2077         resize_frame_client(hwnd);
2078 }
2079
2080 static BOOL activate_drive_window(LPCWSTR path)
2081 {
2082         WCHAR drv1[_MAX_DRIVE], drv2[_MAX_DRIVE];
2083         HWND child_wnd;
2084
2085         _wsplitpath(path, drv1, 0, 0, 0);
2086
2087         /* search for a already open window for the same drive */
2088         for(child_wnd=GetNextWindow(Globals.hmdiclient,GW_CHILD); child_wnd; child_wnd=GetNextWindow(child_wnd, GW_HWNDNEXT)) {
2089                 ChildWnd* child = (ChildWnd*)GetWindowLongPtrW(child_wnd, GWLP_USERDATA);
2090
2091                 if (child) {
2092                         _wsplitpath(child->root.path, drv2, 0, 0, 0);
2093
2094                         if (!lstrcmpiW(drv2, drv1)) {
2095                                 SendMessageW(Globals.hmdiclient, WM_MDIACTIVATE, (WPARAM)child_wnd, 0);
2096
2097                                 if (IsIconic(child_wnd))
2098                                         ShowWindow(child_wnd, SW_SHOWNORMAL);
2099
2100                                 return TRUE;
2101                         }
2102                 }
2103         }
2104
2105         return FALSE;
2106 }
2107
2108 static BOOL activate_fs_window(LPCWSTR filesys)
2109 {
2110         HWND child_wnd;
2111
2112         /* search for a already open window of the given file system name */
2113         for(child_wnd=GetNextWindow(Globals.hmdiclient,GW_CHILD); child_wnd; child_wnd=GetNextWindow(child_wnd, GW_HWNDNEXT)) {
2114                 ChildWnd* child = (ChildWnd*) GetWindowLongPtrW(child_wnd, GWLP_USERDATA);
2115
2116                 if (child) {
2117                         if (!lstrcmpiW(child->root.fs, filesys)) {
2118                                 SendMessageW(Globals.hmdiclient, WM_MDIACTIVATE, (WPARAM)child_wnd, 0);
2119
2120                                 if (IsIconic(child_wnd))
2121                                         ShowWindow(child_wnd, SW_SHOWNORMAL);
2122
2123                                 return TRUE;
2124                         }
2125                 }
2126         }
2127
2128         return FALSE;
2129 }
2130
2131 static LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
2132 {
2133         WCHAR b1[BUFFER_LEN], b2[BUFFER_LEN];
2134
2135         switch(nmsg) {
2136                 case WM_CLOSE:
2137                         if (Globals.saveSettings)
2138                                 save_registry_settings();  
2139                         
2140                         DestroyWindow(hwnd);
2141
2142                          /* clear handle variables */
2143                         Globals.hMenuFrame = 0;
2144                         Globals.hMenuView = 0;
2145                         Globals.hMenuOptions = 0;
2146                         Globals.hMainWnd = 0;
2147                         Globals.hmdiclient = 0;
2148                         Globals.hdrivebar = 0;
2149                         break;
2150
2151                 case WM_DESTROY:
2152                         PostQuitMessage(0);
2153                         break;
2154
2155                 case WM_INITMENUPOPUP: {
2156                         HWND hwndClient = (HWND)SendMessageW(Globals.hmdiclient, WM_MDIGETACTIVE, 0, 0);
2157
2158                         if (!SendMessageW(hwndClient, WM_INITMENUPOPUP, wparam, lparam))
2159                                 return 0;
2160                         break;}
2161
2162                 case WM_COMMAND: {
2163                         UINT cmd = LOWORD(wparam);
2164                         HWND hwndClient = (HWND)SendMessageW(Globals.hmdiclient, WM_MDIGETACTIVE, 0, 0);
2165
2166                         if (SendMessageW(hwndClient, WM_DISPATCH_COMMAND, wparam, lparam))
2167                                 break;
2168
2169                         if (cmd>=ID_DRIVE_FIRST && cmd<=ID_DRIVE_FIRST+0xFF) {
2170                                 WCHAR drv[_MAX_DRIVE], path[MAX_PATH];
2171                                 ChildWnd* child;
2172                                 LPCWSTR root = Globals.drives;
2173                                 int i;
2174
2175                                 for(i=cmd-ID_DRIVE_FIRST; i--; root++)
2176                                         while(*root)
2177                                                 root++;
2178
2179                                 if (activate_drive_window(root))
2180                                         return 0;
2181
2182                                 _wsplitpath(root, drv, 0, 0, 0);
2183
2184                                 if (!SetCurrentDirectoryW(drv)) {
2185                                         display_error(hwnd, GetLastError());
2186                                         return 0;
2187                                 }
2188
2189                                 GetCurrentDirectoryW(MAX_PATH, path); /*TODO: store last directory per drive */
2190                                 child = alloc_child_window(path, NULL, hwnd);
2191
2192                                 if (!create_child_window(child))
2193                                         HeapFree(GetProcessHeap(), 0, child);
2194                         } else switch(cmd) {
2195                                 case ID_FILE_EXIT:
2196                                         SendMessageW(hwnd, WM_CLOSE, 0, 0);
2197                                         break;
2198
2199                                 case ID_WINDOW_NEW: {
2200                                         WCHAR path[MAX_PATH];
2201                                         ChildWnd* child;
2202
2203                                         GetCurrentDirectoryW(MAX_PATH, path);
2204                                         child = alloc_child_window(path, NULL, hwnd);
2205
2206                                         if (!create_child_window(child))
2207                                                 HeapFree(GetProcessHeap(), 0, child);
2208                                         break;}
2209
2210                                 case ID_REFRESH:
2211                                         refresh_drives();
2212                                         break;
2213
2214                                 case ID_WINDOW_CASCADE:
2215                                         SendMessageW(Globals.hmdiclient, WM_MDICASCADE, 0, 0);
2216                                         break;
2217
2218                                 case ID_WINDOW_TILE_HORZ:
2219                                         SendMessageW(Globals.hmdiclient, WM_MDITILE, MDITILE_HORIZONTAL, 0);
2220                                         break;
2221
2222                                 case ID_WINDOW_TILE_VERT:
2223                                         SendMessageW(Globals.hmdiclient, WM_MDITILE, MDITILE_VERTICAL, 0);
2224                                         break;
2225
2226                                 case ID_WINDOW_ARRANGE:
2227                                         SendMessageW(Globals.hmdiclient, WM_MDIICONARRANGE, 0, 0);
2228                                         break;
2229
2230                                 case ID_SELECT_FONT:
2231                                         choose_font(hwnd);
2232                                         break;
2233
2234                                 case ID_VIEW_TOOL_BAR:
2235                                         toggle_child(hwnd, cmd, Globals.htoolbar);
2236                                         break;
2237
2238                                 case ID_VIEW_DRIVE_BAR:
2239                                         toggle_child(hwnd, cmd, Globals.hdrivebar);
2240                                         break;
2241
2242                                 case ID_VIEW_STATUSBAR:
2243                                         toggle_child(hwnd, cmd, Globals.hstatusbar);
2244                                         break;
2245
2246                                 case ID_VIEW_SAVESETTINGS:
2247                                         Globals.saveSettings = !Globals.saveSettings;
2248                                         CheckMenuItem(Globals.hMenuOptions, ID_VIEW_SAVESETTINGS,
2249                                                       Globals.saveSettings ? MF_CHECKED : MF_UNCHECKED );
2250                                         break;
2251
2252                                 case ID_RUN:
2253                                         WineFile_OnRun( hwnd );
2254                                         break;
2255
2256                                 case ID_CONNECT_NETWORK_DRIVE: {
2257                                         DWORD ret = WNetConnectionDialog(hwnd, RESOURCETYPE_DISK);
2258                                         if (ret == NO_ERROR)
2259                                                 refresh_drives();
2260                                         else if (ret != (DWORD)-1) {
2261                                                 if (ret == ERROR_EXTENDED_ERROR)
2262                                                         display_network_error(hwnd);
2263                                                 else
2264                                                         display_error(hwnd, ret);
2265                                         }
2266                                         break;}
2267
2268                                 case ID_DISCONNECT_NETWORK_DRIVE: {
2269                                         DWORD ret = WNetDisconnectDialog(hwnd, RESOURCETYPE_DISK);
2270                                         if (ret == NO_ERROR)
2271                                                 refresh_drives();
2272                                         else if (ret != (DWORD)-1) {
2273                                                 if (ret == ERROR_EXTENDED_ERROR)
2274                                                         display_network_error(hwnd);
2275                                                 else
2276                                                         display_error(hwnd, ret);
2277                                         }
2278                                         break;}
2279
2280                                 case ID_FORMAT_DISK: {
2281                                         UINT sem_org = SetErrorMode(0); /* Get the current Error Mode settings. */
2282                                         SetErrorMode(sem_org & ~SEM_FAILCRITICALERRORS); /* Force O/S to handle */
2283                                         SHFormatDrive(hwnd, 0 /* A: */, SHFMT_ID_DEFAULT, 0);
2284                                         SetErrorMode(sem_org); /* Put it back the way it was. */
2285                                         break;}
2286
2287                                 case ID_HELP:
2288                                         WinHelpW(hwnd, RS(b1,IDS_WINEFILE), HELP_INDEX, 0);
2289                                         break;
2290
2291 #ifndef _NO_EXTENSIONS
2292                                 case ID_VIEW_FULLSCREEN:
2293                                         CheckMenuItem(Globals.hMenuOptions, cmd, toggle_fullscreen(hwnd)?MF_CHECKED:0);
2294                                         break;
2295
2296 #ifdef __WINE__
2297                                 case ID_DRIVE_UNIX_FS: {
2298                                         WCHAR path[MAX_PATH];
2299                                         char cpath[MAX_PATH];
2300                                         ChildWnd* child;
2301
2302                                         if (activate_fs_window(RS(b1,IDS_UNIXFS)))
2303                                                 break;
2304
2305                                         getcwd(cpath, MAX_PATH);
2306                                         MultiByteToWideChar(CP_UNIXCP, 0, cpath, -1, path, MAX_PATH);
2307                                         child = alloc_child_window(path, NULL, hwnd);
2308
2309                                         if (!create_child_window(child))
2310                                                 HeapFree(GetProcessHeap(), 0, child);
2311                                         break;}
2312 #endif
2313 #ifdef _SHELL_FOLDERS
2314                                 case ID_DRIVE_SHELL_NS: {
2315                                         WCHAR path[MAX_PATH];
2316                                         ChildWnd* child;
2317
2318                                         if (activate_fs_window(RS(b1,IDS_SHELL)))
2319                                                 break;
2320
2321                                         GetCurrentDirectoryW(MAX_PATH, path);
2322                                         child = alloc_child_window(path, get_path_pidl(path,hwnd), hwnd);
2323
2324                                         if (!create_child_window(child))
2325                                                 HeapFree(GetProcessHeap(), 0, child);
2326                                         break;}
2327 #endif
2328 #endif
2329
2330                                 /*TODO: There are even more menu items! */
2331
2332                                 case ID_ABOUT:
2333                                         ShellAboutW(hwnd, RS(b1,IDS_WINEFILE), NULL,
2334                                                    LoadImageW( Globals.hInstance, MAKEINTRESOURCEW(IDI_WINEFILE),
2335                                                               IMAGE_ICON, 48, 48, LR_SHARED ));
2336                                         break;
2337
2338                                 default:
2339                                         /*TODO: if (wParam >= PM_FIRST_LANGUAGE && wParam <= PM_LAST_LANGUAGE)
2340                                                 STRING_SelectLanguageByNumber(wParam - PM_FIRST_LANGUAGE);
2341                                         else */if ((cmd<IDW_FIRST_CHILD || cmd>=IDW_FIRST_CHILD+0x100) &&
2342                                                 (cmd<SC_SIZE || cmd>SC_RESTORE))
2343                                                 MessageBoxW(hwnd, RS(b2,IDS_NO_IMPL), RS(b1,IDS_WINEFILE), MB_OK);
2344
2345                                         return DefFrameProcW(hwnd, Globals.hmdiclient, nmsg, wparam, lparam);
2346                         }
2347                         break;}
2348
2349                 case WM_SIZE:
2350                         resize_frame(hwnd, LOWORD(lparam), HIWORD(lparam));
2351                         break;  /* do not pass message to DefFrameProcW */
2352
2353                 case WM_DEVICECHANGE:
2354                         SendMessageW(hwnd, WM_COMMAND, MAKELONG(ID_REFRESH,0), 0);
2355                         break;
2356
2357 #ifndef _NO_EXTENSIONS
2358                 case WM_GETMINMAXINFO: {
2359                         LPMINMAXINFO lpmmi = (LPMINMAXINFO)lparam;
2360
2361                         lpmmi->ptMaxTrackSize.x <<= 1;/*2*GetSystemMetrics(SM_CXSCREEN) / SM_CXVIRTUALSCREEN */
2362                         lpmmi->ptMaxTrackSize.y <<= 1;/*2*GetSystemMetrics(SM_CYSCREEN) / SM_CYVIRTUALSCREEN */
2363                         break;}
2364
2365                 case FRM_CALC_CLIENT:
2366                         frame_get_clientspace(hwnd, (PRECT)lparam);
2367                         return TRUE;
2368 #endif /* _NO_EXTENSIONS */
2369
2370                 default:
2371                         return DefFrameProcW(hwnd, Globals.hmdiclient, nmsg, wparam, lparam);
2372         }
2373
2374         return 0;
2375 }
2376
2377
2378 static WCHAR g_pos_names[COLUMNS][20] = {
2379         {'\0'}  /* symbol */
2380 };
2381
2382 static const int g_pos_align[] = {
2383         0,
2384         HDF_LEFT,       /* Name */
2385         HDF_RIGHT,      /* Size */
2386         HDF_LEFT,       /* CDate */
2387 #ifndef _NO_EXTENSIONS
2388         HDF_LEFT,       /* ADate */
2389         HDF_LEFT,       /* MDate */
2390         HDF_LEFT,       /* Index */
2391         HDF_CENTER,     /* Links */
2392 #endif
2393         HDF_CENTER,     /* Attributes */
2394 #ifndef _NO_EXTENSIONS
2395         HDF_LEFT        /* Security */
2396 #endif
2397 };
2398
2399 static void resize_tree(ChildWnd* child, int cx, int cy)
2400 {
2401         HDWP hdwp = BeginDeferWindowPos(4);
2402         RECT rt;
2403
2404         rt.left   = 0;
2405         rt.top    = 0;
2406         rt.right  = cx;
2407         rt.bottom = cy;
2408
2409         cx = child->split_pos + SPLIT_WIDTH/2;
2410
2411 #ifndef _NO_EXTENSIONS
2412         {
2413                 WINDOWPOS wp;
2414                 HD_LAYOUT hdl;
2415
2416                 hdl.prc   = &rt;
2417                 hdl.pwpos = &wp;
2418
2419                 SendMessageW(child->left.hwndHeader, HDM_LAYOUT, 0, (LPARAM)&hdl);
2420
2421                 DeferWindowPos(hdwp, child->left.hwndHeader, wp.hwndInsertAfter,
2422                                                 wp.x-1, wp.y, child->split_pos-SPLIT_WIDTH/2+1, wp.cy, wp.flags);
2423                 DeferWindowPos(hdwp, child->right.hwndHeader, wp.hwndInsertAfter,
2424                                                 rt.left+cx+1, wp.y, wp.cx-cx+2, wp.cy, wp.flags);
2425         }
2426 #endif /* _NO_EXTENSIONS */
2427
2428         DeferWindowPos(hdwp, child->left.hwnd, 0, rt.left, rt.top, child->split_pos-SPLIT_WIDTH/2-rt.left, rt.bottom-rt.top, SWP_NOZORDER|SWP_NOACTIVATE);
2429         DeferWindowPos(hdwp, child->right.hwnd, 0, rt.left+cx+1, rt.top, rt.right-cx, rt.bottom-rt.top, SWP_NOZORDER|SWP_NOACTIVATE);
2430
2431         EndDeferWindowPos(hdwp);
2432 }
2433
2434
2435 #ifndef _NO_EXTENSIONS
2436
2437 static HWND create_header(HWND parent, Pane* pane, UINT id)
2438 {
2439         HDITEMW hdi;
2440         int idx;
2441
2442         HWND hwnd = CreateWindowW(WC_HEADERW, 0, WS_CHILD|WS_VISIBLE|HDS_HORZ|HDS_FULLDRAG/*TODO: |HDS_BUTTONS + sort orders*/,
2443                                  0, 0, 0, 0, parent, (HMENU)ULongToHandle(id), Globals.hInstance, 0);
2444         if (!hwnd)
2445                 return 0;
2446
2447         SendMessageW(hwnd, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), FALSE);
2448
2449         hdi.mask = HDI_TEXT|HDI_WIDTH|HDI_FORMAT;
2450
2451         for(idx=0; idx<COLUMNS; idx++) {
2452                 hdi.pszText = g_pos_names[idx];
2453                 hdi.fmt = HDF_STRING | g_pos_align[idx];
2454                 hdi.cxy = pane->widths[idx];
2455                 SendMessageW(hwnd, HDM_INSERTITEMW, idx, (LPARAM)&hdi);
2456         }
2457
2458         return hwnd;
2459 }
2460
2461 #endif /* _NO_EXTENSIONS */
2462
2463
2464 static void init_output(HWND hwnd)
2465 {
2466         static const WCHAR s1000[] = {'1','0','0','0','\0'};
2467         WCHAR b[16];
2468         HFONT old_font;
2469         HDC hdc = GetDC(hwnd);
2470
2471         if (GetNumberFormatW(LOCALE_USER_DEFAULT, 0, s1000, 0, b, 16) > 4)
2472                 Globals.num_sep = b[1];
2473         else
2474                 Globals.num_sep = '.';
2475
2476         old_font = SelectObject(hdc, Globals.hfont);
2477         GetTextExtentPoint32W(hdc, sSpace, 1, &Globals.spaceSize);
2478         SelectObject(hdc, old_font);
2479         ReleaseDC(hwnd, hdc);
2480 }
2481
2482 static void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWidthCol);
2483
2484
2485 /* calculate preferred width for all visible columns */
2486
2487 static BOOL calc_widths(Pane* pane, BOOL anyway)
2488 {
2489         int col, x, cx, spc=3*Globals.spaceSize.cx;
2490         int entries = SendMessageW(pane->hwnd, LB_GETCOUNT, 0, 0);
2491         int orgWidths[COLUMNS];
2492         int orgPositions[COLUMNS+1];
2493         HFONT hfontOld;
2494         HDC hdc;
2495         int cnt;
2496
2497         if (!anyway) {
2498                 memcpy(orgWidths, pane->widths, sizeof(orgWidths));
2499                 memcpy(orgPositions, pane->positions, sizeof(orgPositions));
2500         }
2501
2502         for(col=0; col<COLUMNS; col++)
2503                 pane->widths[col] = 0;
2504
2505         hdc = GetDC(pane->hwnd);
2506         hfontOld = SelectObject(hdc, Globals.hfont);
2507
2508         for(cnt=0; cnt<entries; cnt++) {
2509                 Entry* entry = (Entry*)SendMessageW(pane->hwnd, LB_GETITEMDATA, cnt, 0);
2510
2511                 DRAWITEMSTRUCT dis;
2512
2513                 dis.CtlType               = 0;
2514                 dis.CtlID                 = 0;
2515                 dis.itemID                = 0;
2516                 dis.itemAction    = 0;
2517                 dis.itemState     = 0;
2518                 dis.hwndItem      = pane->hwnd;
2519                 dis.hDC                   = hdc;
2520                 dis.rcItem.left   = 0;
2521                 dis.rcItem.top    = 0;
2522                 dis.rcItem.right  = 0;
2523                 dis.rcItem.bottom = 0;
2524                 /*dis.itemData    = 0; */
2525
2526                 draw_item(pane, &dis, entry, COLUMNS);
2527         }
2528
2529         SelectObject(hdc, hfontOld);
2530         ReleaseDC(pane->hwnd, hdc);
2531
2532         x = 0;
2533         for(col=0; col<COLUMNS; col++) {
2534                 pane->positions[col] = x;
2535                 cx = pane->widths[col];
2536
2537                 if (cx) {
2538                         cx += spc;
2539
2540                         if (cx < IMAGE_WIDTH)
2541                                 cx = IMAGE_WIDTH;
2542
2543                         pane->widths[col] = cx;
2544                 }
2545
2546                 x += cx;
2547         }
2548
2549         pane->positions[COLUMNS] = x;
2550
2551         SendMessageW(pane->hwnd, LB_SETHORIZONTALEXTENT, x, 0);
2552
2553         /* no change? */
2554         if (!anyway && !memcmp(orgWidths, pane->widths, sizeof(orgWidths)))
2555                 return FALSE;
2556
2557         /* don't move, if only collapsing an entry */
2558         if (!anyway && pane->widths[0]<orgWidths[0] &&
2559                 !memcmp(orgWidths+1, pane->widths+1, sizeof(orgWidths)-sizeof(int))) {
2560                 pane->widths[0] = orgWidths[0];
2561                 memcpy(pane->positions, orgPositions, sizeof(orgPositions));
2562
2563                 return FALSE;
2564         }
2565
2566         InvalidateRect(pane->hwnd, 0, TRUE);
2567
2568         return TRUE;
2569 }
2570
2571
2572 /* calculate one preferred column width */
2573
2574 static void calc_single_width(Pane* pane, int col)
2575 {
2576         HFONT hfontOld;
2577         int x, cx;
2578         int entries = SendMessageW(pane->hwnd, LB_GETCOUNT, 0, 0);
2579         int cnt;
2580         HDC hdc;
2581
2582         pane->widths[col] = 0;
2583
2584         hdc = GetDC(pane->hwnd);
2585         hfontOld = SelectObject(hdc, Globals.hfont);
2586
2587         for(cnt=0; cnt<entries; cnt++) {
2588                 Entry* entry = (Entry*)SendMessageW(pane->hwnd, LB_GETITEMDATA, cnt, 0);
2589                 DRAWITEMSTRUCT dis;
2590
2591                 dis.CtlType               = 0;
2592                 dis.CtlID                 = 0;
2593                 dis.itemID                = 0;
2594                 dis.itemAction    = 0;
2595                 dis.itemState     = 0;
2596                 dis.hwndItem      = pane->hwnd;
2597                 dis.hDC                   = hdc;
2598                 dis.rcItem.left   = 0;
2599                 dis.rcItem.top    = 0;
2600                 dis.rcItem.right  = 0;
2601                 dis.rcItem.bottom = 0;
2602                 /*dis.itemData    = 0; */
2603
2604                 draw_item(pane, &dis, entry, col);
2605         }
2606
2607         SelectObject(hdc, hfontOld);
2608         ReleaseDC(pane->hwnd, hdc);
2609
2610         cx = pane->widths[col];
2611
2612         if (cx) {
2613                 cx += 3*Globals.spaceSize.cx;
2614
2615                 if (cx < IMAGE_WIDTH)
2616                         cx = IMAGE_WIDTH;
2617         }
2618
2619         pane->widths[col] = cx;
2620
2621         x = pane->positions[col] + cx;
2622
2623         for(; col<COLUMNS-1; ) {
2624                 pane->positions[++col] = x;
2625                 x += pane->widths[col];
2626         }
2627
2628         SendMessageW(pane->hwnd, LB_SETHORIZONTALEXTENT, x, 0);
2629 }
2630
2631
2632 static BOOL pattern_match(LPCWSTR str, LPCWSTR pattern)
2633 {
2634         for( ; *str&&*pattern; str++,pattern++) {
2635                 if (*pattern == '*') {
2636                         do pattern++;
2637                         while(*pattern == '*');
2638
2639                         if (!*pattern)
2640                                 return TRUE;
2641
2642                         for(; *str; str++)
2643                                 if (*str==*pattern && pattern_match(str, pattern))
2644                                         return TRUE;
2645
2646                         return FALSE;
2647                 }
2648                 else if (*str!=*pattern && *pattern!='?')
2649                         return FALSE;
2650         }
2651
2652         if (*str || *pattern)
2653                 if (*pattern!='*' || pattern[1]!='\0')
2654                         return FALSE;
2655
2656         return TRUE;
2657 }
2658
2659 static BOOL pattern_imatch(LPCWSTR str, LPCWSTR pattern)
2660 {
2661         WCHAR b1[BUFFER_LEN], b2[BUFFER_LEN];
2662
2663         lstrcpyW(b1, str);
2664         lstrcpyW(b2, pattern);
2665         CharUpperW(b1);
2666         CharUpperW(b2);
2667
2668         return pattern_match(b1, b2);
2669 }
2670
2671
2672 enum FILE_TYPE {
2673         FT_OTHER                = 0,
2674         FT_EXECUTABLE   = 1,
2675         FT_DOCUMENT             = 2
2676 };
2677
2678 static enum FILE_TYPE get_file_type(LPCWSTR filename);
2679
2680
2681 /* insert listbox entries after index idx */
2682
2683 static int insert_entries(Pane* pane, Entry* dir, LPCWSTR pattern, int filter_flags, int idx)
2684 {
2685         Entry* entry = dir;
2686
2687         if (!entry)
2688                 return idx;
2689
2690         ShowWindow(pane->hwnd, SW_HIDE);
2691
2692         for(; entry; entry=entry->next) {
2693 #ifndef _LEFT_FILES
2694                 if (pane->treePane && !(entry->data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY))
2695                         continue;
2696 #endif
2697
2698                 if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
2699                         /* don't display entries "." and ".." in the left pane */
2700                         if (pane->treePane && entry->data.cFileName[0] == '.')
2701                                 if (
2702 #ifndef _NO_EXTENSIONS
2703                                         entry->data.cFileName[1] == '\0' ||
2704 #endif
2705                                         (entry->data.cFileName[1] == '.' && entry->data.cFileName[2] == '\0'))
2706                                         continue;
2707
2708                         /* filter directories in right pane */
2709                         if (!pane->treePane && !(filter_flags&TF_DIRECTORIES))
2710                                 continue;
2711                 }
2712
2713                 /* filter using the file name pattern */
2714                 if (pattern)
2715                         if (!pattern_imatch(entry->data.cFileName, pattern))
2716                                 continue;
2717
2718                 /* filter system and hidden files */
2719                 if (!(filter_flags&TF_HIDDEN) && (entry->data.dwFileAttributes&(FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)))
2720                         continue;
2721
2722                 /* filter looking at the file type */
2723                 if ((filter_flags&(TF_PROGRAMS|TF_DOCUMENTS|TF_OTHERS)) != (TF_PROGRAMS|TF_DOCUMENTS|TF_OTHERS))
2724                         switch(get_file_type(entry->data.cFileName)) {
2725                           case FT_EXECUTABLE:
2726                                 if (!(filter_flags & TF_PROGRAMS))
2727                                         continue;
2728                                 break;
2729
2730                           case FT_DOCUMENT:
2731                                 if (!(filter_flags & TF_DOCUMENTS))
2732                                         continue;
2733                                 break;
2734
2735                           default: /* TF_OTHERS */
2736                                 if (!(filter_flags & TF_OTHERS))
2737                                         continue;
2738                         }
2739
2740                 if (idx != -1)
2741                         idx++;
2742
2743                 SendMessageW(pane->hwnd, LB_INSERTSTRING, idx, (LPARAM)entry);
2744
2745                 if (pane->treePane && entry->expanded)
2746                         idx = insert_entries(pane, entry->down, pattern, filter_flags, idx);
2747         }
2748
2749         ShowWindow(pane->hwnd, SW_SHOW);
2750
2751         return idx;
2752 }
2753
2754
2755 static void format_bytes(LPWSTR buffer, LONGLONG bytes)
2756 {
2757         static const WCHAR sFmtGB[] = {'%', '.', '1', 'f', ' ', 'G', 'B', '\0'};
2758         static const WCHAR sFmtMB[] = {'%', '.', '1', 'f', ' ', 'M', 'B', '\0'};
2759         static const WCHAR sFmtkB[] = {'%', '.', '1', 'f', ' ', 'k', 'B', '\0'};
2760         static const WCHAR sFmtB[]  = {'%', 'u', 0};
2761
2762         float fBytes = (float)bytes;
2763
2764         if (bytes >= 1073741824)        /* 1 GB */
2765                 sprintfW(buffer, sFmtGB, fBytes/1073741824.f+.5f);
2766         else if (bytes >= 1048576)      /* 1 MB */
2767                 sprintfW(buffer, sFmtMB, fBytes/1048576.f+.5f);
2768         else if (bytes >= 1024)         /* 1 kB */
2769                 sprintfW(buffer, sFmtkB, fBytes/1024.f+.5f);
2770         else
2771                 sprintfW(buffer, sFmtB, (DWORD)bytes);
2772 }
2773
2774 static void set_space_status(void)
2775 {
2776         ULARGE_INTEGER ulFreeBytesToCaller, ulTotalBytes, ulFreeBytes;
2777         WCHAR fmt[64], b1[64], b2[64], buffer[BUFFER_LEN];
2778
2779         if (GetDiskFreeSpaceExW(NULL, &ulFreeBytesToCaller, &ulTotalBytes, &ulFreeBytes)) {
2780                 format_bytes(b1, ulFreeBytesToCaller.QuadPart);
2781                 format_bytes(b2, ulTotalBytes.QuadPart);
2782                 wsprintfW(buffer, RS(fmt,IDS_FREE_SPACE_FMT), b1, b2);
2783         } else
2784                 lstrcpyW(buffer, sQMarks);
2785
2786         SendMessageW(Globals.hstatusbar, SB_SETTEXTW, 0, (LPARAM)buffer);
2787 }
2788
2789
2790 static WNDPROC g_orgTreeWndProc;
2791
2792 static void create_tree_window(HWND parent, Pane* pane, UINT id, UINT id_header, LPCWSTR pattern, int filter_flags)
2793 {
2794         static const WCHAR sListBox[] = {'L','i','s','t','B','o','x','\0'};
2795
2796         static int s_init = 0;
2797         Entry* entry = pane->root;
2798
2799         pane->hwnd = CreateWindowW(sListBox, sEmpty, WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL|
2800                                   LBS_DISABLENOSCROLL|LBS_NOINTEGRALHEIGHT|LBS_OWNERDRAWFIXED|LBS_NOTIFY,
2801                                   0, 0, 0, 0, parent, (HMENU)ULongToHandle(id), Globals.hInstance, 0);
2802
2803         SetWindowLongPtrW(pane->hwnd, GWLP_USERDATA, (LPARAM)pane);
2804         g_orgTreeWndProc = (WNDPROC)SetWindowLongPtrW(pane->hwnd, GWLP_WNDPROC, (LPARAM)TreeWndProc);
2805
2806         SendMessageW(pane->hwnd, WM_SETFONT, (WPARAM)Globals.hfont, FALSE);
2807
2808         /* insert entries into listbox */
2809         if (entry)
2810                 insert_entries(pane, entry, pattern, filter_flags, -1);
2811
2812         /* calculate column widths */
2813         if (!s_init) {
2814                 s_init = 1;
2815                 init_output(pane->hwnd);
2816         }
2817
2818         calc_widths(pane, TRUE);
2819
2820 #ifndef _NO_EXTENSIONS
2821         pane->hwndHeader = create_header(parent, pane, id_header);
2822 #endif
2823 }
2824
2825
2826 static void InitChildWindow(ChildWnd* child)
2827 {
2828         create_tree_window(child->hwnd, &child->left, IDW_TREE_LEFT, IDW_HEADER_LEFT, NULL, TF_ALL);
2829         create_tree_window(child->hwnd, &child->right, IDW_TREE_RIGHT, IDW_HEADER_RIGHT, child->filter_pattern, child->filter_flags);
2830 }
2831
2832
2833 static void format_date(const FILETIME* ft, WCHAR* buffer, int visible_cols)
2834 {
2835         SYSTEMTIME systime;
2836         FILETIME lft;
2837         int len = 0;
2838
2839         *buffer = '\0';
2840
2841         if (!ft->dwLowDateTime && !ft->dwHighDateTime)
2842                 return;
2843
2844         if (!FileTimeToLocalFileTime(ft, &lft))
2845                 {err: lstrcpyW(buffer,sQMarks); return;}
2846
2847         if (!FileTimeToSystemTime(&lft, &systime))
2848                 goto err;
2849
2850         if (visible_cols & COL_DATE) {
2851                 len = GetDateFormatW(LOCALE_USER_DEFAULT, 0, &systime, 0, buffer, BUFFER_LEN);
2852                 if (!len)
2853                         goto err;
2854         }
2855
2856         if (visible_cols & COL_TIME) {
2857                 if (len)
2858                         buffer[len-1] = ' ';
2859
2860                 buffer[len++] = ' ';
2861
2862                 if (!GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systime, 0, buffer+len, BUFFER_LEN-len))
2863                         buffer[len] = '\0';
2864         }
2865 }
2866
2867
2868 static void calc_width(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCWSTR str)
2869 {
2870         RECT rt = {0, 0, 0, 0};
2871
2872         DrawTextW(dis->hDC, str, -1, &rt, DT_CALCRECT|DT_SINGLELINE|DT_NOPREFIX);
2873
2874         if (rt.right > pane->widths[col])
2875                 pane->widths[col] = rt.right;
2876 }
2877
2878 static void calc_tabbed_width(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCWSTR str)
2879 {
2880         RECT rt = {0, 0, 0, 0};
2881
2882 /*      DRAWTEXTPARAMS dtp = {sizeof(DRAWTEXTPARAMS), 2};
2883         DrawTextExW(dis->hDC, (LPWSTR)str, -1, &rt, DT_CALCRECT|DT_SINGLELINE|DT_NOPREFIX|DT_EXPANDTABS|DT_TABSTOP, &dtp);*/
2884
2885         DrawTextW(dis->hDC, str, -1, &rt, DT_CALCRECT|DT_SINGLELINE|DT_EXPANDTABS|DT_TABSTOP|(2<<8));
2886         /*FIXME rt (0,0) ??? */
2887
2888         if (rt.right > pane->widths[col])
2889                 pane->widths[col] = rt.right;
2890 }
2891
2892
2893 static void output_text(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCWSTR str, DWORD flags)
2894 {
2895         int x = dis->rcItem.left;
2896         RECT rt;
2897
2898         rt.left   = x+pane->positions[col]+Globals.spaceSize.cx;
2899         rt.top    = dis->rcItem.top;
2900         rt.right  = x+pane->positions[col+1]-Globals.spaceSize.cx;
2901         rt.bottom = dis->rcItem.bottom;
2902
2903         DrawTextW(dis->hDC, str, -1, &rt, DT_SINGLELINE|DT_NOPREFIX|flags);
2904 }
2905
2906 static void output_tabbed_text(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCWSTR str)
2907 {
2908         int x = dis->rcItem.left;
2909         RECT rt;
2910
2911         rt.left   = x+pane->positions[col]+Globals.spaceSize.cx;
2912         rt.top    = dis->rcItem.top;
2913         rt.right  = x+pane->positions[col+1]-Globals.spaceSize.cx;
2914         rt.bottom = dis->rcItem.bottom;
2915
2916 /*      DRAWTEXTPARAMS dtp = {sizeof(DRAWTEXTPARAMS), 2};
2917         DrawTextExW(dis->hDC, (LPWSTR)str, -1, &rt, DT_SINGLELINE|DT_NOPREFIX|DT_EXPANDTABS|DT_TABSTOP, &dtp);*/
2918
2919         DrawTextW(dis->hDC, str, -1, &rt, DT_SINGLELINE|DT_EXPANDTABS|DT_TABSTOP|(2<<8));
2920 }
2921
2922 static void output_number(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCWSTR str)
2923 {
2924         int x = dis->rcItem.left;
2925         RECT rt;
2926         LPCWSTR s = str;
2927         WCHAR b[128];
2928         LPWSTR d = b;
2929         int pos;
2930
2931         rt.left   = x+pane->positions[col]+Globals.spaceSize.cx;
2932         rt.top    = dis->rcItem.top;
2933         rt.right  = x+pane->positions[col+1]-Globals.spaceSize.cx;
2934         rt.bottom = dis->rcItem.bottom;
2935
2936         if (*s)
2937                 *d++ = *s++;
2938
2939         /* insert number separator characters */
2940         pos = lstrlenW(s) % 3;
2941
2942         while(*s)
2943                 if (pos--)
2944                         *d++ = *s++;
2945                 else {
2946                         *d++ = Globals.num_sep;
2947                         pos = 3;
2948                 }
2949
2950         DrawTextW(dis->hDC, b, d-b, &rt, DT_RIGHT|DT_SINGLELINE|DT_NOPREFIX|DT_END_ELLIPSIS);
2951 }
2952
2953
2954 static BOOL is_exe_file(LPCWSTR ext)
2955 {
2956         static const WCHAR executable_extensions[][4] = {
2957                 {'C','O','M','\0'},
2958                 {'E','X','E','\0'},
2959                 {'B','A','T','\0'},
2960                 {'C','M','D','\0'},
2961 #ifndef _NO_EXTENSIONS
2962                 {'C','M','M','\0'},
2963                 {'B','T','M','\0'},
2964                 {'A','W','K','\0'},
2965 #endif /* _NO_EXTENSIONS */
2966                 {'\0'}
2967         };
2968
2969         WCHAR ext_buffer[_MAX_EXT];
2970         const WCHAR (*p)[4];
2971         LPCWSTR s;
2972         LPWSTR d;
2973
2974         for(s=ext+1,d=ext_buffer; (*d=tolower(*s)); s++)
2975                 d++;
2976
2977         for(p=executable_extensions; (*p)[0]; p++)
2978                 if (!lstrcmpiW(ext_buffer, *p))
2979                         return TRUE;
2980
2981         return FALSE;
2982 }
2983
2984 static BOOL is_registered_type(LPCWSTR ext)
2985 {
2986         /* check if there exists a classname for this file extension in the registry */
2987         if (!RegQueryValueW(HKEY_CLASSES_ROOT, ext, NULL, NULL))
2988                 return TRUE;
2989
2990         return FALSE;
2991 }
2992
2993 static enum FILE_TYPE get_file_type(LPCWSTR filename)
2994 {
2995         LPCWSTR ext = strrchrW(filename, '.');
2996         if (!ext)
2997                 ext = sEmpty;
2998
2999         if (is_exe_file(ext))
3000                 return FT_EXECUTABLE;
3001         else if (is_registered_type(ext))
3002                 return FT_DOCUMENT;
3003         else
3004                 return FT_OTHER;
3005 }
3006
3007
3008 static void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWidthCol)
3009 {
3010         WCHAR buffer[BUFFER_LEN];
3011         DWORD attrs;
3012         int visible_cols = pane->visible_cols;
3013         COLORREF bkcolor, textcolor;
3014         RECT focusRect = dis->rcItem;
3015         HBRUSH hbrush;
3016         enum IMAGE img;
3017         int img_pos, cx;
3018         int col = 0;
3019
3020         if (entry) {
3021                 attrs = entry->data.dwFileAttributes;
3022
3023                 if (attrs & FILE_ATTRIBUTE_DIRECTORY) {
3024                         if (entry->data.cFileName[0] == '.' && entry->data.cFileName[1] == '.'
3025                                         && entry->data.cFileName[2] == '\0')
3026                                 img = IMG_FOLDER_UP;
3027 #ifndef _NO_EXTENSIONS
3028                         else if (entry->data.cFileName[0] == '.' && entry->data.cFileName[1] == '\0')
3029                                 img = IMG_FOLDER_CUR;
3030 #endif
3031                         else if (
3032 #ifdef _NO_EXTENSIONS
3033                                          entry->expanded ||
3034 #endif
3035                                          (pane->treePane && (dis->itemState&ODS_FOCUS)))
3036                                 img = IMG_OPEN_FOLDER;
3037                         else
3038                                 img = IMG_FOLDER;
3039                 } else {
3040                         switch(get_file_type(entry->data.cFileName)) {
3041                           case FT_EXECUTABLE:   img = IMG_EXECUTABLE;   break;
3042                           case FT_DOCUMENT:             img = IMG_DOCUMENT;             break;
3043                           default:                              img = IMG_FILE;
3044                         }
3045                 }
3046         } else {
3047                 attrs = 0;
3048                 img = IMG_NONE;
3049         }
3050
3051         if (pane->treePane) {
3052                 if (entry) {
3053                         img_pos = dis->rcItem.left + entry->level*(IMAGE_WIDTH+TREE_LINE_DX);
3054
3055                         if (calcWidthCol == -1) {
3056                                 int x;
3057                                 int y = dis->rcItem.top + IMAGE_HEIGHT/2;
3058                                 Entry* up;
3059                                 RECT rt_clip;
3060                                 HRGN hrgn_org = CreateRectRgn(0, 0, 0, 0);
3061                                 HRGN hrgn;
3062
3063                                 rt_clip.left   = dis->rcItem.left;
3064                                 rt_clip.top    = dis->rcItem.top;
3065                                 rt_clip.right  = dis->rcItem.left+pane->widths[col];
3066                                 rt_clip.bottom = dis->rcItem.bottom;
3067
3068                                 hrgn = CreateRectRgnIndirect(&rt_clip);
3069
3070                                 if (!GetClipRgn(dis->hDC, hrgn_org)) {
3071                                         DeleteObject(hrgn_org);
3072                                         hrgn_org = 0;
3073                                 }
3074
3075                                 /* HGDIOBJ holdPen = SelectObject(dis->hDC, GetStockObject(BLACK_PEN)); */
3076                                 ExtSelectClipRgn(dis->hDC, hrgn, RGN_AND);
3077                                 DeleteObject(hrgn);
3078
3079                                 if ((up=entry->up) != NULL) {
3080                                         MoveToEx(dis->hDC, img_pos-IMAGE_WIDTH/2, y, 0);
3081                                         LineTo(dis->hDC, img_pos-2, y);
3082
3083                                         x = img_pos - IMAGE_WIDTH/2;
3084
3085                                         do {
3086                                                 x -= IMAGE_WIDTH+TREE_LINE_DX;
3087
3088                                                 if (up->next
3089 #ifndef _LEFT_FILES
3090                                                         && (up->next->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
3091 #endif
3092                                                         ) {
3093                                                         MoveToEx(dis->hDC, x, dis->rcItem.top, 0);
3094                                                         LineTo(dis->hDC, x, dis->rcItem.bottom);
3095                                                 }
3096                                         } while((up=up->up) != NULL);
3097                                 }
3098
3099                                 x = img_pos - IMAGE_WIDTH/2;
3100
3101                                 MoveToEx(dis->hDC, x, dis->rcItem.top, 0);
3102                                 LineTo(dis->hDC, x, y);
3103
3104                                 if (entry->next
3105 #ifndef _LEFT_FILES
3106                                         && (entry->next->data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
3107 #endif
3108                                         )
3109                                         LineTo(dis->hDC, x, dis->rcItem.bottom);
3110
3111                                 SelectClipRgn(dis->hDC, hrgn_org);
3112                                 if (hrgn_org) DeleteObject(hrgn_org);
3113                                 /* SelectObject(dis->hDC, holdPen); */
3114                         } else if (calcWidthCol==col || calcWidthCol==COLUMNS) {
3115                                 int right = img_pos + IMAGE_WIDTH - TREE_LINE_DX;
3116
3117                                 if (right > pane->widths[col])
3118                                         pane->widths[col] = right;
3119                         }
3120                 } else  {
3121                         img_pos = dis->rcItem.left;
3122                 }
3123         } else {
3124                 img_pos = dis->rcItem.left;
3125
3126                 if (calcWidthCol==col || calcWidthCol==COLUMNS)
3127                         pane->widths[col] = IMAGE_WIDTH;
3128         }
3129
3130         if (calcWidthCol == -1) {
3131                 focusRect.left = img_pos -2;
3132
3133 #ifdef _NO_EXTENSIONS
3134                 if (pane->treePane && entry) {
3135                         RECT rt = {0};
3136
3137                         DrawTextW(dis->hDC, entry->data.cFileName, -1, &rt, DT_CALCRECT|DT_SINGLELINE|DT_NOPREFIX);
3138
3139                         focusRect.right = dis->rcItem.left+pane->positions[col+1]+TREE_LINE_DX + rt.right +2;
3140                 }
3141 #else
3142
3143                 if (attrs & FILE_ATTRIBUTE_COMPRESSED)
3144                         textcolor = COLOR_COMPRESSED;
3145                 else
3146 #endif /* _NO_EXTENSIONS */
3147                         textcolor = RGB(0,0,0);
3148
3149                 if (dis->itemState & ODS_FOCUS) {
3150                         textcolor = RGB(255,255,255);
3151                         bkcolor = COLOR_SELECTION;
3152                 } else {
3153                         bkcolor = RGB(255,255,255);
3154                 }
3155
3156                 hbrush = CreateSolidBrush(bkcolor);
3157                 FillRect(dis->hDC, &focusRect, hbrush);
3158                 DeleteObject(hbrush);
3159
3160                 SetBkMode(dis->hDC, TRANSPARENT);
3161                 SetTextColor(dis->hDC, textcolor);
3162
3163                 cx = pane->widths[col];
3164
3165                 if (cx && img!=IMG_NONE) {
3166                         if (cx > IMAGE_WIDTH)
3167                                 cx = IMAGE_WIDTH;
3168
3169 #ifdef _SHELL_FOLDERS
3170                         if (entry->hicon && entry->hicon!=(HICON)-1)
3171                                 DrawIconEx(dis->hDC, img_pos, dis->rcItem.top, entry->hicon, cx, GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
3172                         else
3173 #endif
3174                                 ImageList_DrawEx(Globals.himl, img, dis->hDC,
3175                                                                  img_pos, dis->rcItem.top, cx,
3176                                                                  IMAGE_HEIGHT, bkcolor, CLR_DEFAULT, ILD_NORMAL);
3177                 }
3178         }
3179
3180         if (!entry)
3181                 return;
3182
3183 #ifdef _NO_EXTENSIONS
3184         if (img >= IMG_FOLDER_UP)
3185                 return;
3186 #endif
3187
3188         col++;
3189
3190         /* ouput file name */
3191         if (calcWidthCol == -1)
3192                 output_text(pane, dis, col, entry->data.cFileName, 0);
3193         else if (calcWidthCol==col || calcWidthCol==COLUMNS)
3194                 calc_width(pane, dis, col, entry->data.cFileName);
3195
3196         col++;
3197
3198 #ifdef _NO_EXTENSIONS
3199   if (!pane->treePane) {
3200 #endif
3201
3202         /* display file size */
3203         if (visible_cols & COL_SIZE) {
3204 #ifdef _NO_EXTENSIONS
3205                 if (!(attrs&FILE_ATTRIBUTE_DIRECTORY))
3206 #endif
3207                 {
3208                         format_longlong( buffer, ((ULONGLONG)entry->data.nFileSizeHigh << 32) | entry->data.nFileSizeLow );
3209
3210                         if (calcWidthCol == -1)
3211                                 output_number(pane, dis, col, buffer);
3212                         else if (calcWidthCol==col || calcWidthCol==COLUMNS)
3213                                 calc_width(pane, dis, col, buffer);/*TODO: not ever time enough */
3214                 }
3215
3216                 col++;
3217         }
3218
3219         /* display file date */
3220         if (visible_cols & (COL_DATE|COL_TIME)) {
3221 #ifndef _NO_EXTENSIONS
3222                 format_date(&entry->data.ftCreationTime, buffer, visible_cols);
3223                 if (calcWidthCol == -1)
3224                         output_text(pane, dis, col, buffer, 0);
3225                 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
3226                         calc_width(pane, dis, col, buffer);
3227                 col++;
3228
3229                 format_date(&entry->data.ftLastAccessTime, buffer, visible_cols);
3230                 if (calcWidthCol == -1)
3231                         output_text(pane, dis, col, buffer, 0);
3232                 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
3233                         calc_width(pane, dis, col, buffer);
3234                 col++;
3235 #endif /* _NO_EXTENSIONS */
3236
3237                 format_date(&entry->data.ftLastWriteTime, buffer, visible_cols);
3238                 if (calcWidthCol == -1)
3239                         output_text(pane, dis, col, buffer, 0);
3240                 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
3241                         calc_width(pane, dis, col, buffer);
3242                 col++;
3243         }
3244
3245 #ifndef _NO_EXTENSIONS
3246         if (entry->bhfi_valid) {
3247                 if (visible_cols & COL_INDEX) {
3248                         static const WCHAR fmtlow[] = {'%','X',0};
3249                         static const WCHAR fmthigh[] = {'%','X','%','0','8','X',0};
3250
3251                         if (entry->bhfi.nFileIndexHigh)
3252                             wsprintfW(buffer, fmthigh,
3253                                      entry->bhfi.nFileIndexHigh, entry->bhfi.nFileIndexLow );
3254                         else
3255                             wsprintfW(buffer, fmtlow, entry->bhfi.nFileIndexLow );
3256
3257                         if (calcWidthCol == -1)
3258                                 output_text(pane, dis, col, buffer, DT_RIGHT);
3259                         else if (calcWidthCol==col || calcWidthCol==COLUMNS)
3260                                 calc_width(pane, dis, col, buffer);
3261
3262                         col++;
3263                 }
3264
3265                 if (visible_cols & COL_LINKS) {
3266                         wsprintfW(buffer, sNumFmt, entry->bhfi.nNumberOfLinks);
3267
3268                         if (calcWidthCol == -1)
3269                                 output_text(pane, dis, col, buffer, DT_CENTER);
3270                         else if (calcWidthCol==col || calcWidthCol==COLUMNS)
3271                                 calc_width(pane, dis, col, buffer);
3272
3273                         col++;
3274                 }
3275         } else
3276                 col += 2;
3277 #endif /* _NO_EXTENSIONS */
3278
3279         /* show file attributes */
3280         if (visible_cols & COL_ATTRIBUTES) {
3281 #ifdef _NO_EXTENSIONS
3282                 static const WCHAR s4Tabs[] = {' ','\t',' ','\t',' ','\t',' ','\t',' ','\0'};
3283                 lstrcpyW(buffer, s4Tabs);
3284 #else
3285                 static const WCHAR s11Tabs[] = {' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\0'};
3286                 lstrcpyW(buffer, s11Tabs);
3287 #endif
3288
3289                 if (attrs & FILE_ATTRIBUTE_NORMAL)                                      buffer[ 0] = 'N';
3290                 else {
3291                         if (attrs & FILE_ATTRIBUTE_READONLY)                    buffer[ 2] = 'R';
3292                         if (attrs & FILE_ATTRIBUTE_HIDDEN)                              buffer[ 4] = 'H';
3293                         if (attrs & FILE_ATTRIBUTE_SYSTEM)                              buffer[ 6] = 'S';
3294                         if (attrs & FILE_ATTRIBUTE_ARCHIVE)                             buffer[ 8] = 'A';
3295                         if (attrs & FILE_ATTRIBUTE_COMPRESSED)                  buffer[10] = 'C';
3296 #ifndef _NO_EXTENSIONS
3297                         if (attrs & FILE_ATTRIBUTE_DIRECTORY)                   buffer[12] = 'D';
3298                         if (attrs & FILE_ATTRIBUTE_ENCRYPTED)                   buffer[14] = 'E';
3299                         if (attrs & FILE_ATTRIBUTE_TEMPORARY)                   buffer[16] = 'T';
3300                         if (attrs & FILE_ATTRIBUTE_SPARSE_FILE)                 buffer[18] = 'P';
3301                         if (attrs & FILE_ATTRIBUTE_REPARSE_POINT)               buffer[20] = 'Q';
3302                         if (attrs & FILE_ATTRIBUTE_OFFLINE)                             buffer[22] = 'O';
3303                         if (attrs & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED) buffer[24] = 'X';
3304 #endif /* _NO_EXTENSIONS */
3305                 }
3306
3307                 if (calcWidthCol == -1)
3308                         output_tabbed_text(pane, dis, col, buffer);
3309                 else if (calcWidthCol==col || calcWidthCol==COLUMNS)
3310                         calc_tabbed_width(pane, dis, col, buffer);
3311
3312                 col++;
3313         }
3314
3315 /*TODO
3316         if (flags.security) {
3317                 static const WCHAR sSecTabs[] = {
3318                         ' ','\t',' ','\t',' ','\t',' ',
3319                         ' ','\t',' ',
3320                         ' ','\t',' ','\t',' ','\t',' ',
3321                         ' ','\t',' ',
3322                         ' ','\t',' ','\t',' ','\t',' ',
3323                         '\0'
3324                 };
3325
3326                 DWORD rights = get_access_mask();
3327
3328                 lstrcpyW(buffer, sSecTabs);
3329
3330                 if (rights & FILE_READ_DATA)                    buffer[ 0] = 'R';
3331                 if (rights & FILE_WRITE_DATA)                   buffer[ 2] = 'W';
3332                 if (rights & FILE_APPEND_DATA)                  buffer[ 4] = 'A';
3333                 if (rights & FILE_READ_EA)                              {buffer[6] = 'entry'; buffer[ 7] = 'R';}
3334                 if (rights & FILE_WRITE_EA)                             {buffer[9] = 'entry'; buffer[10] = 'W';}
3335                 if (rights & FILE_EXECUTE)                              buffer[12] = 'X';
3336                 if (rights & FILE_DELETE_CHILD)                 buffer[14] = 'D';
3337                 if (rights & FILE_READ_ATTRIBUTES)              {buffer[16] = 'a'; buffer[17] = 'R';}
3338                 if (rights & FILE_WRITE_ATTRIBUTES)             {buffer[19] = 'a'; buffer[20] = 'W';}
3339                 if (rights & WRITE_DAC)                                 buffer[22] = 'C';
3340                 if (rights & WRITE_OWNER)                               buffer[24] = 'O';
3341                 if (rights & SYNCHRONIZE)                               buffer[26] = 'S';
3342
3343                 output_text(dis, col++, buffer, DT_LEFT, 3, psize);
3344         }
3345
3346         if (flags.description) {
3347                 get_description(buffer);
3348                 output_text(dis, col++, buffer, 0, psize);
3349         }
3350 */
3351
3352 #ifdef _NO_EXTENSIONS
3353   }
3354
3355         /* draw focus frame */
3356         if ((dis->itemState&ODS_FOCUS) && calcWidthCol==-1) {
3357                 /* Currently [04/2000] Wine neither behaves exactly the same */
3358                 /* way as WIN 95 nor like Windows NT... */
3359                 HGDIOBJ lastBrush;
3360                 HPEN lastPen;
3361                 HPEN hpen;
3362
3363                 if (!(GetVersion() & 0x80000000)) {     /* Windows NT? */
3364                         LOGBRUSH lb = {PS_SOLID, RGB(255,255,255)};
3365                         hpen = ExtCreatePen(PS_COSMETIC|PS_ALTERNATE, 1, &lb, 0, 0);
3366                 } else
3367                         hpen = CreatePen(PS_DOT, 0, RGB(255,255,255));
3368
3369                 lastPen = SelectPen(dis->hDC, hpen);
3370                 lastBrush = SelectObject(dis->hDC, GetStockObject(HOLLOW_BRUSH));
3371                 SetROP2(dis->hDC, R2_XORPEN);
3372                 Rectangle(dis->hDC, focusRect.left, focusRect.top, focusRect.right, focusRect.bottom);
3373                 SelectObject(dis->hDC, lastBrush);
3374                 SelectObject(dis->hDC, lastPen);
3375                 DeleteObject(hpen);
3376         }
3377 #endif /* _NO_EXTENSIONS */
3378 }
3379
3380
3381 #ifdef _NO_EXTENSIONS
3382
3383 static void draw_splitbar(HWND hwnd, int x)
3384 {
3385         RECT rt;
3386         HDC hdc = GetDC(hwnd);
3387
3388         GetClientRect(hwnd, &rt);
3389
3390         rt.left = x - SPLIT_WIDTH/2;
3391         rt.right = x + SPLIT_WIDTH/2+1;
3392
3393         InvertRect(hdc, &rt);
3394
3395         ReleaseDC(hwnd, hdc);
3396 }
3397
3398 #endif /* _NO_EXTENSIONS */
3399
3400
3401 #ifndef _NO_EXTENSIONS
3402
3403 static void set_header(Pane* pane)
3404 {
3405         HDITEMW item;
3406         int scroll_pos = GetScrollPos(pane->hwnd, SB_HORZ);
3407         int i=0, x=0;
3408
3409         item.mask = HDI_WIDTH;
3410         item.cxy = 0;
3411
3412         for(; x+pane->widths[i]<scroll_pos && i<COLUMNS; i++) {
3413                 x += pane->widths[i];
3414                 SendMessageW(pane->hwndHeader, HDM_SETITEMW, i, (LPARAM)&item);
3415         }
3416
3417         if (i < COLUMNS) {
3418                 x += pane->widths[i];
3419                 item.cxy = x - scroll_pos;
3420                 SendMessageW(pane->hwndHeader, HDM_SETITEMW, i++, (LPARAM)&item);
3421
3422                 for(; i<COLUMNS; i++) {
3423                         item.cxy = pane->widths[i];
3424                         x += pane->widths[i];
3425                         SendMessageW(pane->hwndHeader, HDM_SETITEMW, i, (LPARAM)&item);
3426                 }
3427         }
3428 }
3429
3430 static LRESULT pane_notify(Pane* pane, NMHDR* pnmh)
3431 {
3432         switch(pnmh->code) {
3433                 case HDN_ITEMCHANGEDW: {
3434                         LPNMHEADERW phdn = (LPNMHEADERW)pnmh;
3435                         int idx = phdn->iItem;
3436                         int dx = phdn->pitem->cxy - pane->widths[idx];
3437                         int i;
3438
3439                         RECT clnt;
3440                         GetClientRect(pane->hwnd, &clnt);
3441
3442                         pane->widths[idx] += dx;
3443
3444                         for(i=idx; ++i<=COLUMNS; )
3445                                 pane->positions[i] += dx;
3446
3447                         {
3448                                 int scroll_pos = GetScrollPos(pane->hwnd, SB_HORZ);
3449                                 RECT rt_scr;
3450                                 RECT rt_clip;
3451
3452                                 rt_scr.left   = pane->positions[idx+1]-scroll_pos;
3453                                 rt_scr.top    = 0;
3454                                 rt_scr.right  = clnt.right;
3455                                 rt_scr.bottom = clnt.bottom;
3456
3457                                 rt_clip.left   = pane->positions[idx]-scroll_pos;
3458                                 rt_clip.top    = 0;
3459                                 rt_clip.right  = clnt.right;
3460                                 rt_clip.bottom = clnt.bottom;
3461
3462                                 if (rt_scr.left < 0) rt_scr.left = 0;
3463                                 if (rt_clip.left < 0) rt_clip.left = 0;
3464
3465                                 ScrollWindowEx(pane->hwnd, dx, 0, &rt_scr, &rt_clip, 0, 0, SW_INVALIDATE);
3466
3467                                 rt_clip.right = pane->positions[idx+1];
3468                                 RedrawWindow(pane->hwnd, &rt_clip, 0, RDW_INVALIDATE|RDW_UPDATENOW);
3469
3470                                 if (pnmh->code == HDN_ENDTRACKW) {
3471                                         SendMessageW(pane->hwnd, LB_SETHORIZONTALEXTENT, pane->positions[COLUMNS], 0);
3472
3473                                         if (GetScrollPos(pane->hwnd, SB_HORZ) != scroll_pos)
3474                                                 set_header(pane);
3475                                 }
3476                         }
3477
3478                         return FALSE;
3479                 }
3480
3481                 case HDN_DIVIDERDBLCLICKW: {
3482                         LPNMHEADERW phdn = (LPNMHEADERW)pnmh;
3483                         HDITEMW item;
3484
3485                         calc_single_width(pane, phdn->iItem);
3486                         item.mask = HDI_WIDTH;
3487                         item.cxy = pane->widths[phdn->iItem];
3488
3489                         SendMessageW(pane->hwndHeader, HDM_SETITEMW, phdn->iItem, (LPARAM)&item);
3490                         InvalidateRect(pane->hwnd, 0, TRUE);
3491                         break;}
3492         }
3493
3494         return 0;
3495 }
3496
3497 #endif /* _NO_EXTENSIONS */
3498
3499
3500 static void scan_entry(ChildWnd* child, Entry* entry, int idx, HWND hwnd)
3501 {
3502         WCHAR path[MAX_PATH];
3503         HCURSOR old_cursor = SetCursor(LoadCursorW(0, (LPCWSTR)IDC_WAIT));
3504
3505         /* delete sub entries in left pane */
3506         for(;;) {
3507                 LRESULT res = SendMessageW(child->left.hwnd, LB_GETITEMDATA, idx+1, 0);
3508                 Entry* sub = (Entry*) res;
3509
3510                 if (res==LB_ERR || !sub || sub->level<=entry->level)
3511                         break;
3512
3513                 SendMessageW(child->left.hwnd, LB_DELETESTRING, idx+1, 0);
3514         }
3515
3516         /* empty right pane */
3517         SendMessageW(child->right.hwnd, LB_RESETCONTENT, 0, 0);
3518
3519         /* release memory */
3520         free_entries(entry);
3521
3522         /* read contents from disk */
3523 #ifdef _SHELL_FOLDERS
3524         if (entry->etype == ET_SHELL)
3525         {
3526                 read_directory(entry, NULL, child->sortOrder, hwnd);
3527         }
3528         else
3529 #endif
3530         {
3531                 get_path(entry, path);
3532                 read_directory(entry, path, child->sortOrder, hwnd);
3533         }
3534
3535         /* insert found entries in right pane */
3536         insert_entries(&child->right, entry->down, child->filter_pattern, child->filter_flags, -1);
3537         calc_widths(&child->right, FALSE);
3538 #ifndef _NO_EXTENSIONS
3539         set_header(&child->right);
3540 #endif
3541
3542         child->header_wdths_ok = FALSE;
3543
3544         SetCursor(old_cursor);
3545 }
3546
3547
3548 /* expand a directory entry */
3549
3550 static BOOL expand_entry(ChildWnd* child, Entry* dir)
3551 {
3552         int idx;
3553         Entry* p;
3554
3555         if (!dir || dir->expanded || !dir->down)
3556                 return FALSE;
3557
3558         p = dir->down;
3559
3560         if (p->data.cFileName[0]=='.' && p->data.cFileName[1]=='\0' && p->next) {
3561                 p = p->next;
3562
3563                 if (p->data.cFileName[0]=='.' && p->data.cFileName[1]=='.' &&
3564                                 p->data.cFileName[2]=='\0' && p->next)
3565                         p = p->next;
3566         }
3567
3568         /* no subdirectories ? */
3569         if (!(p->data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY))
3570                 return FALSE;
3571
3572         idx = SendMessageW(child->left.hwnd, LB_FINDSTRING, 0, (LPARAM)dir);
3573
3574         dir->expanded = TRUE;
3575
3576         /* insert entries in left pane */
3577         insert_entries(&child->left, p, NULL, TF_ALL, idx);
3578
3579         if (!child->header_wdths_ok) {
3580                 if (calc_widths(&child->left, FALSE)) {
3581 #ifndef _NO_EXTENSIONS
3582                         set_header(&child->left);
3583 #endif
3584
3585                         child->header_wdths_ok = TRUE;
3586                 }
3587         }
3588
3589         return TRUE;
3590 }
3591
3592
3593 static void collapse_entry(Pane* pane, Entry* dir)
3594 {
3595         int idx = SendMessageW(pane->hwnd, LB_FINDSTRING, 0, (LPARAM)dir);
3596
3597         ShowWindow(pane->hwnd, SW_HIDE);
3598
3599         /* hide sub entries */
3600         for(;;) {
3601                 LRESULT res = SendMessageW(pane->hwnd, LB_GETITEMDATA, idx+1, 0);
3602                 Entry* sub = (Entry*) res;
3603
3604                 if (res==LB_ERR || !sub || sub->level<=dir->level)
3605                         break;
3606
3607                 SendMessageW(pane->hwnd, LB_DELETESTRING, idx+1, 0);
3608         }
3609
3610         dir->expanded = FALSE;
3611
3612         ShowWindow(pane->hwnd, SW_SHOW);
3613 }
3614
3615
3616 static void refresh_right_pane(ChildWnd* child)
3617 {
3618         SendMessageW(child->right.hwnd, LB_RESETCONTENT, 0, 0);
3619         insert_entries(&child->right, child->right.root, child->filter_pattern, child->filter_flags, -1);
3620         calc_widths(&child->right, FALSE);
3621
3622 #ifndef _NO_EXTENSIONS
3623         set_header(&child->right);
3624 #endif
3625 }
3626
3627 static void set_curdir(ChildWnd* child, Entry* entry, int idx, HWND hwnd)
3628 {
3629         WCHAR path[MAX_PATH];
3630
3631         if (!entry)
3632                 return;
3633
3634         path[0] = '\0';
3635
3636         child->left.cur = entry;
3637
3638         child->right.root = entry->down? entry->down: entry;
3639         child->right.cur = entry;
3640
3641         if (!entry->scanned)
3642                 scan_entry(child, entry, idx, hwnd);
3643         else
3644                 refresh_right_pane(child);
3645
3646         get_path(entry, path);
3647         lstrcpyW(child->path, path);
3648
3649         if (child->hwnd)        /* only change window title, if the window already exists */
3650                 SetWindowTextW(child->hwnd, path);
3651
3652         if (path[0])
3653                 if (SetCurrentDirectoryW(path))
3654                         set_space_status();
3655 }
3656
3657
3658 static void refresh_child(ChildWnd* child)
3659 {
3660         WCHAR path[MAX_PATH], drv[_MAX_DRIVE+1];
3661         Entry* entry;
3662         int idx;
3663
3664         get_path(child->left.cur, path);
3665         _wsplitpath(path, drv, NULL, NULL, NULL);
3666
3667         child->right.root = NULL;
3668
3669         scan_entry(child, &child->root.entry, 0, child->hwnd);
3670
3671 #ifdef _SHELL_FOLDERS
3672
3673         if (child->root.entry.etype == ET_SHELL)
3674         {
3675                 LPITEMIDLIST local_pidl = get_path_pidl(path,child->hwnd);
3676                 if (local_pidl)
3677                         entry = read_tree(&child->root, NULL, local_pidl , drv, child->sortOrder, child->hwnd);
3678                 else
3679                         entry = NULL;
3680         }
3681         else
3682 #endif
3683                 entry = read_tree(&child->root, path, NULL, drv, child->sortOrder, child->hwnd);
3684
3685         if (!entry)
3686                 entry = &child->root.entry;
3687
3688         insert_entries(&child->left, child->root.entry.down, NULL, TF_ALL, 0);
3689
3690         set_curdir(child, entry, 0, child->hwnd);
3691
3692         idx = SendMessageW(child->left.hwnd, LB_FINDSTRING, 0, (LPARAM)child->left.cur);
3693         SendMessageW(child->left.hwnd, LB_SETCURSEL, idx, 0);
3694 }
3695
3696
3697 static void create_drive_bar(void)
3698 {
3699         TBBUTTON drivebarBtn = {0, 0, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0};
3700 #ifndef _NO_EXTENSIONS
3701         WCHAR b1[BUFFER_LEN];
3702 #endif
3703         int btn = 1;
3704         PWSTR p;
3705
3706         GetLogicalDriveStringsW(BUFFER_LEN, Globals.drives);
3707
3708         Globals.hdrivebar = CreateToolbarEx(Globals.hMainWnd, WS_CHILD|WS_VISIBLE|CCS_NOMOVEY|TBSTYLE_LIST,
3709                                 IDW_DRIVEBAR, 2, Globals.hInstance, IDB_DRIVEBAR, &drivebarBtn,
3710                                 0, 16, 13, 16, 13, sizeof(TBBUTTON));
3711
3712 #ifndef _NO_EXTENSIONS
3713 #ifdef __WINE__
3714         /* insert unix file system button */
3715         b1[0] = '/';
3716         b1[1] = '\0';
3717         b1[2] = '\0';
3718         SendMessageW(Globals.hdrivebar, TB_ADDSTRINGW, 0, (LPARAM)b1);
3719
3720         drivebarBtn.idCommand = ID_DRIVE_UNIX_FS;
3721         SendMessageW(Globals.hdrivebar, TB_INSERTBUTTONW, btn++, (LPARAM)&drivebarBtn);
3722         drivebarBtn.iString++;
3723 #endif
3724 #ifdef _SHELL_FOLDERS
3725         /* insert shell namespace button */
3726         load_string(b1, sizeof(b1)/sizeof(b1[0]), IDS_SHELL);
3727         b1[lstrlenW(b1)+1] = '\0';
3728         SendMessageW(Globals.hdrivebar, TB_ADDSTRINGW, 0, (LPARAM)b1);
3729
3730         drivebarBtn.idCommand = ID_DRIVE_SHELL_NS;
3731         SendMessageW(Globals.hdrivebar, TB_INSERTBUTTONW, btn++, (LPARAM)&drivebarBtn);
3732         drivebarBtn.iString++;
3733 #endif
3734
3735         /* register windows drive root strings */
3736         SendMessageW(Globals.hdrivebar, TB_ADDSTRINGW, 0, (LPARAM)Globals.drives);
3737 #endif
3738
3739         drivebarBtn.idCommand = ID_DRIVE_FIRST;
3740
3741         for(p=Globals.drives; *p; ) {
3742 #ifdef _NO_EXTENSIONS
3743                 /* insert drive letter */
3744                 WCHAR b[3] = {tolower(*p)};
3745                 SendMessageW(Globals.hdrivebar, TB_ADDSTRINGW, 0, (LPARAM)b);
3746 #endif
3747                 switch(GetDriveTypeW(p)) {
3748                         case DRIVE_REMOVABLE:   drivebarBtn.iBitmap = 1;        break;
3749                         case DRIVE_CDROM:               drivebarBtn.iBitmap = 3;        break;
3750                         case DRIVE_REMOTE:              drivebarBtn.iBitmap = 4;        break;
3751                         case DRIVE_RAMDISK:             drivebarBtn.iBitmap = 5;        break;
3752                         default:/*DRIVE_FIXED*/ drivebarBtn.iBitmap = 2;
3753                 }
3754
3755                 SendMessageW(Globals.hdrivebar, TB_INSERTBUTTONW, btn++, (LPARAM)&drivebarBtn);
3756                 drivebarBtn.idCommand++;
3757                 drivebarBtn.iString++;
3758
3759                 while(*p++);
3760         }
3761 }
3762
3763 static void refresh_drives(void)
3764 {
3765         RECT rect;
3766
3767         /* destroy drive bar */
3768         DestroyWindow(Globals.hdrivebar);
3769         Globals.hdrivebar = 0;
3770
3771         /* re-create drive bar */
3772         create_drive_bar();
3773
3774         /* update window layout */
3775         GetClientRect(Globals.hMainWnd, &rect);
3776         SendMessageW(Globals.hMainWnd, WM_SIZE, 0, MAKELONG(rect.right, rect.bottom));
3777 }
3778
3779
3780 static BOOL launch_file(HWND hwnd, LPCWSTR cmd, UINT nCmdShow)
3781 {
3782         HINSTANCE hinst = ShellExecuteW(hwnd, NULL/*operation*/, cmd, NULL/*parameters*/, NULL/*dir*/, nCmdShow);
3783
3784         if (PtrToUlong(hinst) <= 32) {
3785                 display_error(hwnd, GetLastError());
3786                 return FALSE;
3787         }
3788
3789         return TRUE;
3790 }
3791
3792
3793 static BOOL launch_entry(Entry* entry, HWND hwnd, UINT nCmdShow)
3794 {
3795         WCHAR cmd[MAX_PATH];
3796
3797 #ifdef _SHELL_FOLDERS
3798         if (entry->etype == ET_SHELL) {
3799                 BOOL ret = TRUE;
3800
3801                 SHELLEXECUTEINFOW shexinfo;
3802
3803                 shexinfo.cbSize = sizeof(SHELLEXECUTEINFOW);
3804                 shexinfo.fMask = SEE_MASK_IDLIST;
3805                 shexinfo.hwnd = hwnd;
3806                 shexinfo.lpVerb = NULL;
3807                 shexinfo.lpFile = NULL;
3808                 shexinfo.lpParameters = NULL;
3809                 shexinfo.lpDirectory = NULL;
3810                 shexinfo.nShow = nCmdShow;
3811                 shexinfo.lpIDList = get_to_absolute_pidl(entry, hwnd);
3812
3813                 if (!ShellExecuteExW(&shexinfo)) {
3814                         display_error(hwnd, GetLastError());
3815                         ret = FALSE;
3816                 }
3817
3818                 if (shexinfo.lpIDList != entry->pidl)
3819                         IMalloc_Free(Globals.iMalloc, shexinfo.lpIDList);
3820
3821                 return ret;
3822         }
3823 #endif
3824
3825         get_path(entry, cmd);
3826
3827          /* start program, open document... */
3828         return launch_file(hwnd, cmd, nCmdShow);
3829 }
3830
3831
3832 static void activate_entry(ChildWnd* child, Pane* pane, HWND hwnd)
3833 {
3834         Entry* entry = pane->cur;
3835
3836         if (!entry)
3837                 return;
3838
3839         if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
3840                 int scanned_old = entry->scanned;
3841
3842                 if (!scanned_old)
3843                 {
3844                         int idx = SendMessageW(child->left.hwnd, LB_GETCURSEL, 0, 0);
3845                         scan_entry(child, entry, idx, hwnd);
3846                 }
3847
3848 #ifndef _NO_EXTENSIONS
3849                 if (entry->data.cFileName[0]=='.' && entry->data.cFileName[1]=='\0')
3850                         return;
3851 #endif
3852
3853                 if (entry->data.cFileName[0]=='.' && entry->data.cFileName[1]=='.' && entry->data.cFileName[2]=='\0') {
3854                         entry = child->left.cur->up;
3855                         collapse_entry(&child->left, entry);
3856                         goto focus_entry;
3857                 } else if (entry->expanded)
3858                         collapse_entry(pane, child->left.cur);
3859                 else {
3860                         expand_entry(child, child->left.cur);
3861
3862                         if (!pane->treePane) focus_entry: {
3863                                 int idxstart = SendMessageW(child->left.hwnd, LB_GETCURSEL, 0, 0);
3864                                 int idx = SendMessageW(child->left.hwnd, LB_FINDSTRING, idxstart, (LPARAM)entry);
3865                                 SendMessageW(child->left.hwnd, LB_SETCURSEL, idx, 0);
3866                                 set_curdir(child, entry, idx, hwnd);
3867                         }
3868                 }
3869
3870                 if (!scanned_old) {
3871                         calc_widths(pane, FALSE);
3872
3873 #ifndef _NO_EXTENSIONS
3874                         set_header(pane);
3875 #endif
3876                 }
3877         } else {
3878                 if (GetKeyState(VK_MENU) < 0)
3879                         show_properties_dlg(entry, child->hwnd);
3880                 else
3881                         launch_entry(entry, child->hwnd, SW_SHOWNORMAL);
3882         }
3883 }
3884
3885
3886 static BOOL pane_command(Pane* pane, UINT cmd)
3887 {
3888         switch(cmd) {
3889                 case ID_VIEW_NAME:
3890                         if (pane->visible_cols) {
3891                                 pane->visible_cols = 0;
3892                                 calc_widths(pane, TRUE);
3893 #ifndef _NO_EXTENSIONS
3894                                 set_header(pane);
3895 #endif
3896                                 InvalidateRect(pane->hwnd, 0, TRUE);
3897                                 CheckMenuItem(Globals.hMenuView, ID_VIEW_NAME, MF_BYCOMMAND|MF_CHECKED);
3898                                 CheckMenuItem(Globals.hMenuView, ID_VIEW_ALL_ATTRIBUTES, MF_BYCOMMAND);
3899                                 CheckMenuItem(Globals.hMenuView, ID_VIEW_SELECTED_ATTRIBUTES, MF_BYCOMMAND);
3900                         }
3901                         break;
3902
3903                 case ID_VIEW_ALL_ATTRIBUTES:
3904                         if (pane->visible_cols != COL_ALL) {
3905                                 pane->visible_cols = COL_ALL;
3906                                 calc_widths(pane, TRUE);
3907 #ifndef _NO_EXTENSIONS
3908                                 set_header(pane);
3909 #endif
3910                                 InvalidateRect(pane->hwnd, 0, TRUE);
3911                                 CheckMenuItem(Globals.hMenuView, ID_VIEW_NAME, MF_BYCOMMAND);
3912                                 CheckMenuItem(Globals.hMenuView, ID_VIEW_ALL_ATTRIBUTES, MF_BYCOMMAND|MF_CHECKED);
3913                                 CheckMenuItem(Globals.hMenuView, ID_VIEW_SELECTED_ATTRIBUTES, MF_BYCOMMAND);
3914                         }
3915                         break;
3916
3917 #ifndef _NO_EXTENSIONS
3918                 case ID_PREFERRED_SIZES: {
3919                         calc_widths(pane, TRUE);
3920                         set_header(pane);
3921                         InvalidateRect(pane->hwnd, 0, TRUE);
3922                         break;}
3923 #endif
3924
3925                         /* TODO: more command ids... */
3926
3927                 default:
3928                         return FALSE;
3929         }
3930
3931         return TRUE;
3932 }
3933
3934
3935 static void set_sort_order(ChildWnd* child, SORT_ORDER sortOrder)
3936 {
3937         if (child->sortOrder != sortOrder) {
3938                 child->sortOrder = sortOrder;
3939                 refresh_child(child);
3940         }
3941 }
3942
3943 static void update_view_menu(ChildWnd* child)
3944 {
3945         CheckMenuItem(Globals.hMenuView, ID_VIEW_SORT_NAME, child->sortOrder==SORT_NAME? MF_CHECKED: MF_UNCHECKED);
3946         CheckMenuItem(Globals.hMenuView, ID_VIEW_SORT_TYPE, child->sortOrder==SORT_EXT? MF_CHECKED: MF_UNCHECKED);
3947         CheckMenuItem(Globals.hMenuView, ID_VIEW_SORT_SIZE, child->sortOrder==SORT_SIZE? MF_CHECKED: MF_UNCHECKED);
3948         CheckMenuItem(Globals.hMenuView, ID_VIEW_SORT_DATE, child->sortOrder==SORT_DATE? MF_CHECKED: MF_UNCHECKED);
3949 }
3950
3951
3952 static BOOL is_directory(LPCWSTR target)
3953 {
3954         /*TODO correctly handle UNIX paths */
3955         DWORD target_attr = GetFileAttributesW(target);
3956
3957         if (target_attr == INVALID_FILE_ATTRIBUTES)
3958                 return FALSE;
3959
3960         return target_attr&FILE_ATTRIBUTE_DIRECTORY? TRUE: FALSE;
3961 }
3962
3963 static BOOL prompt_target(Pane* pane, LPWSTR source, LPWSTR target)
3964 {
3965         WCHAR path[MAX_PATH];
3966         int len;
3967
3968         get_path(pane->cur, path);
3969
3970         if (DialogBoxParamW(Globals.hInstance, MAKEINTRESOURCEW(IDD_SELECT_DESTINATION), pane->hwnd, DestinationDlgProc, (LPARAM)path) != IDOK)
3971                 return FALSE;
3972
3973         get_path(pane->cur, source);
3974
3975         /* convert relative targets to absolute paths */
3976         if (path[0]!='/' && path[1]!=':') {
3977                 get_path(pane->cur->up, target);
3978                 len = lstrlenW(target);
3979
3980                 if (target[len-1]!='\\' && target[len-1]!='/')
3981                         target[len++] = '/';
3982
3983                 lstrcpyW(target+len, path);
3984         } else
3985                 lstrcpyW(target, path);
3986
3987         /* If the target already exists as directory, create a new target below this. */
3988         if (is_directory(path)) {
3989                 WCHAR fname[_MAX_FNAME], ext[_MAX_EXT];
3990                 static const WCHAR sAppend[] = {'%','s','/','%','s','%','s','\0'};
3991
3992                 _wsplitpath(source, NULL, NULL, fname, ext);
3993
3994                 wsprintfW(target, sAppend, path, fname, ext);
3995         }
3996
3997         return TRUE;
3998 }
3999
4000
4001 static IContextMenu2* s_pctxmenu2 = NULL;
4002 static IContextMenu3* s_pctxmenu3 = NULL;
4003
4004 static void CtxMenu_reset(void)
4005 {
4006         s_pctxmenu2 = NULL;
4007         s_pctxmenu3 = NULL;
4008 }
4009
4010 static IContextMenu* CtxMenu_query_interfaces(IContextMenu* pcm1)
4011 {
4012         IContextMenu* pcm = NULL;
4013
4014         CtxMenu_reset();
4015
4016         if (IContextMenu_QueryInterface(pcm1, &IID_IContextMenu3, (void**)&pcm) == NOERROR)
4017                 s_pctxmenu3 = (LPCONTEXTMENU3)pcm;
4018         else if (IContextMenu_QueryInterface(pcm1, &IID_IContextMenu2, (void**)&pcm) == NOERROR)
4019                 s_pctxmenu2 = (LPCONTEXTMENU2)pcm;
4020
4021         if (pcm) {
4022                 IContextMenu_Release(pcm1);
4023                 return pcm;
4024         } else
4025                 return pcm1;
4026 }
4027
4028 static BOOL CtxMenu_HandleMenuMsg(UINT nmsg, WPARAM wparam, LPARAM lparam)
4029 {
4030         if (s_pctxmenu3) {
4031                 if (SUCCEEDED(IContextMenu3_HandleMenuMsg(s_pctxmenu3, nmsg, wparam, lparam)))
4032                         return TRUE;
4033         }
4034
4035         if (s_pctxmenu2)
4036                 if (SUCCEEDED(IContextMenu2_HandleMenuMsg(s_pctxmenu2, nmsg, wparam, lparam)))
4037                         return TRUE;
4038
4039         return FALSE;
4040 }
4041
4042
4043 static HRESULT ShellFolderContextMenu(IShellFolder* shell_folder, HWND hwndParent, int cidl, LPCITEMIDLIST* apidl, int x, int y)
4044 {
4045         IContextMenu* pcm;
4046         BOOL executed = FALSE;
4047
4048         HRESULT hr = IShellFolder_GetUIObjectOf(shell_folder, hwndParent, cidl, apidl, &IID_IContextMenu, NULL, (LPVOID*)&pcm);
4049 /*      HRESULT hr = CDefFolderMenu_Create2(dir?dir->_pidl:DesktopFolder(), hwndParent, 1, &pidl, shell_folder, NULL, 0, NULL, &pcm); */
4050
4051         if (SUCCEEDED(hr)) {
4052                 HMENU hmenu = CreatePopupMenu();
4053
4054                 pcm = CtxMenu_query_interfaces(pcm);
4055
4056                 if (hmenu) {
4057                         hr = IContextMenu_QueryContextMenu(pcm, hmenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_NORMAL);
4058
4059                         if (SUCCEEDED(hr)) {
4060                                 UINT idCmd = TrackPopupMenu(hmenu, TPM_LEFTALIGN|TPM_RETURNCMD|TPM_RIGHTBUTTON, x, y, 0, hwndParent, NULL);
4061
4062                                 CtxMenu_reset();
4063
4064                                 if (idCmd) {
4065                                   CMINVOKECOMMANDINFO cmi;
4066
4067                                   cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
4068                                   cmi.fMask = 0;
4069                                   cmi.hwnd = hwndParent;
4070                                   cmi.lpVerb = (LPCSTR)(INT_PTR)(idCmd - FCIDM_SHVIEWFIRST);
4071                                   cmi.lpParameters = NULL;
4072                                   cmi.lpDirectory = NULL;
4073                                   cmi.nShow = SW_SHOWNORMAL;
4074                                   cmi.dwHotKey = 0;
4075                                   cmi.hIcon = 0;
4076
4077                                   hr = IContextMenu_InvokeCommand(pcm, &cmi);
4078                                         executed = TRUE;
4079                                 }
4080                         } else
4081                                 CtxMenu_reset();
4082                 }
4083
4084                 IContextMenu_Release(pcm);
4085         }
4086
4087         return FAILED(hr)? hr: executed? S_OK: S_FALSE;
4088 }
4089
4090
4091 static LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
4092 {
4093         ChildWnd* child = (ChildWnd*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
4094         ASSERT(child);
4095
4096         switch(nmsg) {
4097                 case WM_DRAWITEM: {
4098                         LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lparam;
4099                         Entry* entry = (Entry*) dis->itemData;
4100
4101                         if (dis->CtlID == IDW_TREE_LEFT)
4102                                 draw_item(&child->left, dis, entry, -1);
4103                         else if (dis->CtlID == IDW_TREE_RIGHT)
4104                                 draw_item(&child->right, dis, entry, -1);
4105                         else
4106                                 goto draw_menu_item;
4107
4108                         return TRUE;}
4109
4110                 case WM_CREATE:
4111                         InitChildWindow(child);
4112                         break;
4113
4114                 case WM_NCDESTROY:
4115                         free_child_window(child);
4116                         SetWindowLongPtrW(hwnd, GWLP_USERDATA, 0);
4117                         break;
4118
4119                 case WM_PAINT: {
4120                         PAINTSTRUCT ps;
4121                         HBRUSH lastBrush;
4122                         RECT rt;
4123                         GetClientRect(hwnd, &rt);
4124                         BeginPaint(hwnd, &ps);
4125                         rt.left = child->split_pos-SPLIT_WIDTH/2;
4126                         rt.right = child->split_pos+SPLIT_WIDTH/2+1;
4127                         lastBrush = SelectObject(ps.hdc, GetStockObject(COLOR_SPLITBAR));
4128                         Rectangle(ps.hdc, rt.left, rt.top-1, rt.right, rt.bottom+1);
4129                         SelectObject(ps.hdc, lastBrush);
4130 #ifdef _NO_EXTENSIONS
4131                         rt.top = rt.bottom - GetSystemMetrics(SM_CYHSCROLL);
4132                         FillRect(ps.hdc, &rt, GetStockObject(BLACK_BRUSH));
4133 #endif
4134                         EndPaint(hwnd, &ps);
4135                         break;}
4136
4137                 case WM_SETCURSOR:
4138                         if (LOWORD(lparam) == HTCLIENT) {
4139                                 POINT pt;
4140                                 GetCursorPos(&pt);
4141                                 ScreenToClient(hwnd, &pt);
4142
4143                                 if (pt.x>=child->split_pos-SPLIT_WIDTH/2 && pt.x<child->split_pos+SPLIT_WIDTH/2+1) {
4144                                         SetCursor(LoadCursorW(0, (LPCWSTR)IDC_SIZEWE));
4145                                         return TRUE;
4146                                 }
4147                         }
4148                         goto def;
4149
4150                 case WM_LBUTTONDOWN: {
4151                         RECT rt;
4152                         int x = (short)LOWORD(lparam);
4153
4154                         GetClientRect(hwnd, &rt);
4155
4156                         if (x>=child->split_pos-SPLIT_WIDTH/2 && x<child->split_pos+SPLIT_WIDTH/2+1) {
4157                                 last_split = child->split_pos;
4158 #ifdef _NO_EXTENSIONS
4159                                 draw_splitbar(hwnd, last_split);
4160 #endif
4161                                 SetCapture(hwnd);
4162                         }
4163
4164                         break;}
4165
4166                 case WM_LBUTTONUP:
4167                         if (GetCapture() == hwnd) {
4168 #ifdef _NO_EXTENSIONS
4169                                 RECT rt;
4170                                 int x = (short)LOWORD(lparam);
4171                                 draw_splitbar(hwnd, last_split);
4172                                 last_split = -1;
4173                                 GetClientRect(hwnd, &rt);
4174                                 child->split_pos = x;
4175                                 resize_tree(child, rt.right, rt.bottom);
4176 #endif
4177                                 ReleaseCapture();
4178                         }
4179                         break;
4180
4181 #ifdef _NO_EXTENSIONS
4182                 case WM_CAPTURECHANGED:
4183                         if (GetCapture()==hwnd && last_split>=0)
4184                                 draw_splitbar(hwnd, last_split);
4185                         break;
4186 #endif
4187
4188                 case WM_KEYDOWN:
4189                         if (wparam == VK_ESCAPE)
4190                                 if (GetCapture() == hwnd) {
4191                                         RECT rt;
4192 #ifdef _NO_EXTENSIONS
4193                                         draw_splitbar(hwnd, last_split);
4194 #else
4195                                         child->split_pos = last_split;
4196 #endif
4197                                         GetClientRect(hwnd, &rt);
4198                                         resize_tree(child, rt.right, rt.bottom);
4199                                         last_split = -1;
4200                                         ReleaseCapture();
4201                                         SetCursor(LoadCursorW(0, (LPCWSTR)IDC_ARROW));
4202                                 }
4203                         break;
4204
4205                 case WM_MOUSEMOVE:
4206                         if (GetCapture() == hwnd) {
4207                                 RECT rt;
4208                                 int x = (short)LOWORD(lparam);
4209
4210 #ifdef _NO_EXTENSIONS
4211                                 HDC hdc = GetDC(hwnd);
4212                                 GetClientRect(hwnd, &rt);
4213
4214                                 rt.left = last_split-SPLIT_WIDTH/2;
4215                                 rt.right = last_split+SPLIT_WIDTH/2+1;
4216                                 InvertRect(hdc, &rt);
4217
4218                                 last_split = x;
4219                                 rt.left = x-SPLIT_WIDTH/2;
4220                                 rt.right = x+SPLIT_WIDTH/2+1;
4221                                 InvertRect(hdc, &rt);
4222
4223                                 ReleaseDC(hwnd, hdc);
4224 #else
4225                                 GetClientRect(hwnd, &rt);
4226
4227                                 if (x>=0 && x<rt.right) {
4228                                         child->split_pos = x;
4229                                         resize_tree(child, rt.right, rt.bottom);
4230                                         rt.left = x-SPLIT_WIDTH/2;
4231                                         rt.right = x+SPLIT_WIDTH/2+1;
4232                                         InvalidateRect(hwnd, &rt, FALSE);
4233                                         UpdateWindow(child->left.hwnd);
4234                                         UpdateWindow(hwnd);
4235                                         UpdateWindow(child->right.hwnd);
4236                                 }
4237 #endif
4238                         }
4239                         break;
4240
4241 #ifndef _NO_EXTENSIONS
4242                 case WM_GETMINMAXINFO:
4243                         DefMDIChildProcW(hwnd, nmsg, wparam, lparam);
4244
4245                         {LPMINMAXINFO lpmmi = (LPMINMAXINFO)lparam;
4246
4247                         lpmmi->ptMaxTrackSize.x <<= 1;/*2*GetSystemMetrics(SM_CXSCREEN) / SM_CXVIRTUALSCREEN */
4248                         lpmmi->ptMaxTrackSize.y <<= 1;/*2*GetSystemMetrics(SM_CYSCREEN) / SM_CYVIRTUALSCREEN */
4249                         break;}
4250 #endif /* _NO_EXTENSIONS */
4251
4252                 case WM_SETFOCUS:
4253                         if (SetCurrentDirectoryW(child->path))
4254                                 set_space_status();
4255                         SetFocus(child->focus_pane? child->right.hwnd: child->left.hwnd);
4256                         break;
4257
4258                 case WM_DISPATCH_COMMAND: {
4259                         Pane* pane = GetFocus()==child->left.hwnd? &child->left: &child->right;
4260
4261                         switch(LOWORD(wparam)) {
4262                                 case ID_WINDOW_NEW: {
4263                                         ChildWnd* new_child = alloc_child_window(child->path, NULL, hwnd);
4264
4265                                         if (!create_child_window(new_child))
4266                                                 HeapFree(GetProcessHeap(), 0, new_child);
4267
4268                                         break;}
4269
4270                                 case ID_REFRESH:
4271                                         refresh_drives();
4272                                         refresh_child(child);
4273                                         break;
4274
4275                                 case ID_ACTIVATE:
4276                                         activate_entry(child, pane, hwnd);
4277                                         break;
4278
4279                                 case ID_FILE_MOVE: {
4280                                         WCHAR source[BUFFER_LEN], target[BUFFER_LEN];
4281
4282                                         if (prompt_target(pane, source, target)) {
4283                                                 SHFILEOPSTRUCTW shfo = {hwnd, FO_MOVE, source, target};
4284
4285                                                 source[lstrlenW(source)+1] = '\0';
4286                                                 target[lstrlenW(target)+1] = '\0';
4287
4288                                                 if (!SHFileOperationW(&shfo))
4289                                                         refresh_child(child);
4290                                         }
4291                                         break;}
4292
4293                                 case ID_FILE_COPY: {
4294                                         WCHAR source[BUFFER_LEN], target[BUFFER_LEN];
4295
4296                                         if (prompt_target(pane, source, target)) {
4297                                                 SHFILEOPSTRUCTW shfo = {hwnd, FO_COPY, source, target};
4298
4299                                                 source[lstrlenW(source)+1] = '\0';
4300                                                 target[lstrlenW(target)+1] = '\0';
4301
4302                                                 if (!SHFileOperationW(&shfo))
4303                                                         refresh_child(child);
4304                                         }
4305                                         break;}
4306
4307                                 case ID_FILE_DELETE: {
4308                                         WCHAR path[BUFFER_LEN];
4309                                         SHFILEOPSTRUCTW shfo = {hwnd, FO_DELETE, path, NULL, FOF_ALLOWUNDO};
4310
4311                                         get_path(pane->cur, path);
4312
4313                                         path[lstrlenW(path)+1] = '\0';
4314
4315                                         if (!SHFileOperationW(&shfo))
4316                                                 refresh_child(child);
4317                                         break;}
4318
4319                                 case ID_VIEW_SORT_NAME:
4320                                         set_sort_order(child, SORT_NAME);
4321                                         break;
4322
4323                                 case ID_VIEW_SORT_TYPE:
4324                                         set_sort_order(child, SORT_EXT);
4325                                         break;
4326
4327                                 case ID_VIEW_SORT_SIZE:
4328                                         set_sort_order(child, SORT_SIZE);
4329                                         break;
4330
4331                                 case ID_VIEW_SORT_DATE:
4332                                         set_sort_order(child, SORT_DATE);
4333                                         break;
4334
4335                                 case ID_VIEW_FILTER: {
4336                                         struct FilterDialog dlg;
4337
4338                                         memset(&dlg, 0, sizeof(struct FilterDialog));
4339                                         lstrcpyW(dlg.pattern, child->filter_pattern);
4340                                         dlg.flags = child->filter_flags;
4341
4342                                         if (DialogBoxParamW(Globals.hInstance, MAKEINTRESOURCEW(IDD_DIALOG_VIEW_TYPE), hwnd, FilterDialogDlgProc, (LPARAM)&dlg) == IDOK) {
4343                                                 lstrcpyW(child->filter_pattern, dlg.pattern);
4344                                                 child->filter_flags = dlg.flags;
4345                                                 refresh_right_pane(child);
4346                                         }
4347                                         break;}
4348
4349                                 case ID_VIEW_SPLIT: {
4350                                         last_split = child->split_pos;
4351 #ifdef _NO_EXTENSIONS
4352                                         draw_splitbar(hwnd, last_split);
4353 #endif
4354                                         SetCapture(hwnd);
4355                                         break;}
4356
4357                                 case ID_EDIT_PROPERTIES:
4358                                         show_properties_dlg(pane->cur, child->hwnd);
4359                                         break;
4360
4361                                 default:
4362                                         return pane_command(pane, LOWORD(wparam));
4363                         }
4364
4365                         return TRUE;}
4366
4367                 case WM_COMMAND: {
4368                         Pane* pane = GetFocus()==child->left.hwnd? &child->left: &child->right;
4369
4370                         switch(HIWORD(wparam)) {
4371                                 case LBN_SELCHANGE: {
4372                                         int idx = SendMessageW(pane->hwnd, LB_GETCURSEL, 0, 0);
4373                                         Entry* entry = (Entry*)SendMessageW(pane->hwnd, LB_GETITEMDATA, idx, 0);
4374
4375                                         if (pane == &child->left)
4376                                                 set_curdir(child, entry, idx, hwnd);
4377                                         else
4378                                                 pane->cur = entry;
4379                                         break;}
4380
4381                                 case LBN_DBLCLK:
4382                                         activate_entry(child, pane, hwnd);
4383                                         break;
4384                         }
4385                         break;}
4386
4387 #ifndef _NO_EXTENSIONS
4388                 case WM_NOTIFY: {
4389                         NMHDR* pnmh = (NMHDR*) lparam;
4390                         return pane_notify(pnmh->idFrom==IDW_HEADER_LEFT? &child->left: &child->right, pnmh);}
4391 #endif
4392
4393 #ifdef _SHELL_FOLDERS
4394                 case WM_CONTEXTMENU: {
4395                         POINT pt, pt_clnt;
4396                         Pane* pane;
4397                         int idx;
4398
4399                          /* first select the current item in the listbox */
4400                         HWND hpanel = (HWND) wparam;
4401                         pt_clnt.x = pt.x = (short)LOWORD(lparam);
4402                         pt_clnt.y = pt.y = (short)HIWORD(lparam);
4403                         ScreenToClient(hpanel, &pt_clnt);
4404                         SendMessageW(hpanel, WM_LBUTTONDOWN, 0, MAKELONG(pt_clnt.x, pt_clnt.y));
4405                         SendMessageW(hpanel, WM_LBUTTONUP, 0, MAKELONG(pt_clnt.x, pt_clnt.y));
4406
4407                          /* now create the popup menu using shell namespace and IContextMenu */
4408                         pane = GetFocus()==child->left.hwnd? &child->left: &child->right;
4409                         idx = SendMessageW(pane->hwnd, LB_GETCURSEL, 0, 0);
4410
4411                         if (idx != -1) {
4412                                 Entry* entry = (Entry*)SendMessageW(pane->hwnd, LB_GETITEMDATA, idx, 0);
4413
4414                                 LPITEMIDLIST pidl_abs = get_to_absolute_pidl(entry, hwnd);
4415
4416                                 if (pidl_abs) {
4417                                         IShellFolder* parentFolder;
4418                                         LPCITEMIDLIST pidlLast;
4419
4420                                          /* get and use the parent folder to display correct context menu in all cases */
4421                                         if (SUCCEEDED(SHBindToParent(pidl_abs, &IID_IShellFolder, (LPVOID*)&parentFolder, &pidlLast))) {
4422                                                 if (ShellFolderContextMenu(parentFolder, hwnd, 1, &pidlLast, pt.x, pt.y) == S_OK)
4423                                                         refresh_child(child);
4424
4425                                                 IShellFolder_Release(parentFolder);
4426                                         }
4427
4428                                         IMalloc_Free(Globals.iMalloc, pidl_abs);
4429                                 }
4430                         }
4431                         break;}
4432 #endif
4433
4434                   case WM_MEASUREITEM:
4435                   draw_menu_item:
4436                         if (!wparam)    /* Is the message menu-related? */
4437                                 if (CtxMenu_HandleMenuMsg(nmsg, wparam, lparam))
4438                                         return TRUE;
4439
4440                         break;
4441
4442                   case WM_INITMENUPOPUP:
4443                         if (CtxMenu_HandleMenuMsg(nmsg, wparam, lparam))
4444                                 return 0;
4445
4446                         update_view_menu(child);
4447                         break;
4448
4449                   case WM_MENUCHAR:     /* only supported by IContextMenu3 */
4450                    if (s_pctxmenu3) {
4451                            LRESULT lResult = 0;
4452
4453                            IContextMenu3_HandleMenuMsg2(s_pctxmenu3, nmsg, wparam, lparam, &lResult);
4454
4455                            return lResult;
4456                    }
4457
4458                    break;
4459
4460                 case WM_SIZE:
4461                         if (wparam != SIZE_MINIMIZED)
4462                                 resize_tree(child, LOWORD(lparam), HIWORD(lparam));
4463                         /* fall through */
4464
4465                 default: def:
4466                         return DefMDIChildProcW(hwnd, nmsg, wparam, lparam);
4467         }
4468
4469         return 0;
4470 }
4471
4472
4473 static LRESULT CALLBACK TreeWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
4474 {
4475         ChildWnd* child = (ChildWnd*)GetWindowLongPtrW(GetParent(hwnd), GWLP_USERDATA);
4476         Pane* pane = (Pane*)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
4477         ASSERT(child);
4478
4479         switch(nmsg) {
4480 #ifndef _NO_EXTENSIONS
4481                 case WM_HSCROLL:
4482                         set_header(pane);
4483                         break;
4484 #endif
4485
4486                 case WM_SETFOCUS:
4487                         child->focus_pane = pane==&child->right? 1: 0;
4488                         SendMessageW(hwnd, LB_SETSEL, TRUE, 1);
4489                         /*TODO: check menu items */
4490                         break;
4491
4492                 case WM_KEYDOWN:
4493                         if (wparam == VK_TAB) {
4494                                 /*TODO: SetFocus(Globals.hdrivebar) */
4495                                 SetFocus(child->focus_pane? child->left.hwnd: child->right.hwnd);
4496                         }
4497         }
4498
4499         return CallWindowProcW(g_orgTreeWndProc, hwnd, nmsg, wparam, lparam);
4500 }
4501
4502
4503 static void InitInstance(HINSTANCE hinstance)
4504 {
4505         static const WCHAR sFont[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
4506
4507         WNDCLASSEXW wcFrame;
4508         WNDCLASSW wcChild;
4509         int col;
4510
4511         INITCOMMONCONTROLSEX icc = {
4512                 sizeof(INITCOMMONCONTROLSEX),
4513                 ICC_BAR_CLASSES
4514         };
4515
4516         HDC hdc = GetDC(0);
4517
4518         setlocale(LC_COLLATE, "");      /* set collating rules to local settings for compareName */
4519
4520         InitCommonControlsEx(&icc);
4521
4522
4523         /* register frame window class */
4524
4525         wcFrame.cbSize        = sizeof(WNDCLASSEXW);
4526         wcFrame.style         = 0;
4527         wcFrame.lpfnWndProc   = FrameWndProc;
4528         wcFrame.cbClsExtra    = 0;
4529         wcFrame.cbWndExtra    = 0;
4530         wcFrame.hInstance     = hinstance;
4531         wcFrame.hIcon         = LoadIconW(hinstance, MAKEINTRESOURCEW(IDI_WINEFILE));
4532         wcFrame.hCursor       = LoadCursorW(0, (LPCWSTR)IDC_ARROW);
4533         wcFrame.hbrBackground = 0;
4534         wcFrame.lpszMenuName  = 0;
4535         wcFrame.lpszClassName = sWINEFILEFRAME;
4536         wcFrame.hIconSm       = LoadImageW(hinstance, MAKEINTRESOURCEW(IDI_WINEFILE), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_SHARED);
4537
4538         Globals.hframeClass = RegisterClassExW(&wcFrame);
4539
4540
4541         /* register tree windows class */
4542
4543         wcChild.style         = CS_CLASSDC|CS_DBLCLKS|CS_VREDRAW;
4544         wcChild.lpfnWndProc   = ChildWndProc;
4545         wcChild.cbClsExtra    = 0;
4546         wcChild.cbWndExtra    = 0;
4547         wcChild.hInstance     = hinstance;
4548         wcChild.hIcon         = 0;
4549         wcChild.hCursor       = LoadCursorW(0, (LPCWSTR)IDC_ARROW);
4550         wcChild.hbrBackground = 0;
4551         wcChild.lpszMenuName  = 0;
4552         wcChild.lpszClassName = sWINEFILETREE;
4553
4554         RegisterClassW(&wcChild);
4555
4556
4557         Globals.haccel = LoadAcceleratorsW(hinstance, MAKEINTRESOURCEW(IDA_WINEFILE));
4558
4559         Globals.hfont = CreateFontW(-MulDiv(8,GetDeviceCaps(hdc,LOGPIXELSY),72), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, sFont);
4560
4561         ReleaseDC(0, hdc);
4562
4563         Globals.hInstance = hinstance;
4564
4565 #ifdef _SHELL_FOLDERS
4566         CoInitialize(NULL);
4567         CoGetMalloc(MEMCTX_TASK, &Globals.iMalloc);
4568         SHGetDesktopFolder(&Globals.iDesktop);
4569         Globals.cfStrFName = RegisterClipboardFormatW(CFSTR_FILENAMEW);
4570 #endif
4571
4572         /* load column strings */
4573         col = 1;
4574
4575         load_string(g_pos_names[col++], sizeof(g_pos_names[col])/sizeof(g_pos_names[col][0]), IDS_COL_NAME);
4576         load_string(g_pos_names[col++], sizeof(g_pos_names[col])/sizeof(g_pos_names[col][0]), IDS_COL_SIZE);
4577         load_string(g_pos_names[col++], sizeof(g_pos_names[col])/sizeof(g_pos_names[col][0]), IDS_COL_CDATE);
4578 #ifndef _NO_EXTENSIONS
4579         load_string(g_pos_names[col++], sizeof(g_pos_names[col])/sizeof(g_pos_names[col][0]), IDS_COL_ADATE);
4580         load_string(g_pos_names[col++], sizeof(g_pos_names[col])/sizeof(g_pos_names[col][0]), IDS_COL_MDATE);
4581         load_string(g_pos_names[col++], sizeof(g_pos_names[col])/sizeof(g_pos_names[col][0]), IDS_COL_IDX);
4582         load_string(g_pos_names[col++], sizeof(g_pos_names[col])/sizeof(g_pos_names[col][0]), IDS_COL_LINKS);
4583 #endif
4584         load_string(g_pos_names[col++], sizeof(g_pos_names[col])/sizeof(g_pos_names[col][0]), IDS_COL_ATTR);
4585 #ifndef _NO_EXTENSIONS
4586         load_string(g_pos_names[col++], sizeof(g_pos_names[col])/sizeof(g_pos_names[col][0]), IDS_COL_SEC);
4587 #endif
4588 }
4589
4590
4591 static BOOL show_frame(HWND hwndParent, int cmdshow, LPCWSTR path)
4592 {
4593         static const WCHAR sMDICLIENT[] = {'M','D','I','C','L','I','E','N','T','\0'};
4594
4595         WCHAR buffer[MAX_PATH], b1[BUFFER_LEN];
4596         ChildWnd* child;
4597         HMENU hMenuFrame, hMenuWindow;
4598         windowOptions opts;
4599
4600         CLIENTCREATESTRUCT ccs;
4601
4602         if (Globals.hMainWnd)
4603                 return TRUE;
4604
4605         opts = load_registry_settings();
4606         hMenuFrame = LoadMenuW(Globals.hInstance, MAKEINTRESOURCEW(IDM_WINEFILE));
4607         hMenuWindow = GetSubMenu(hMenuFrame, GetMenuItemCount(hMenuFrame)-2);
4608
4609         Globals.hMenuFrame = hMenuFrame;
4610         Globals.hMenuView = GetSubMenu(hMenuFrame, 3);
4611         Globals.hMenuOptions = GetSubMenu(hMenuFrame, 4);
4612
4613         ccs.hWindowMenu  = hMenuWindow;
4614         ccs.idFirstChild = IDW_FIRST_CHILD;
4615
4616
4617         /* create main window */
4618         Globals.hMainWnd = CreateWindowExW(0, MAKEINTRESOURCEW(Globals.hframeClass), RS(b1,IDS_WINE_FILE), WS_OVERLAPPEDWINDOW,
4619                                         opts.start_x, opts.start_y, opts.width, opts.height,
4620                                         hwndParent, Globals.hMenuFrame, Globals.hInstance, 0/*lpParam*/);
4621
4622
4623         Globals.hmdiclient = CreateWindowExW(0, sMDICLIENT, NULL,
4624                                         WS_CHILD|WS_CLIPCHILDREN|WS_VSCROLL|WS_HSCROLL|WS_VISIBLE|WS_BORDER,
4625                                         0, 0, 0, 0,
4626                                         Globals.hMainWnd, 0, Globals.hInstance, &ccs);
4627   
4628         CheckMenuItem(Globals.hMenuOptions, ID_VIEW_DRIVE_BAR, MF_BYCOMMAND|MF_CHECKED);
4629         CheckMenuItem(Globals.hMenuOptions, ID_VIEW_SAVESETTINGS, MF_BYCOMMAND);
4630
4631         create_drive_bar();
4632
4633         {
4634                 TBBUTTON toolbarBtns[] = {
4635                         {0, 0, 0, BTNS_SEP, {0, 0}, 0, 0},
4636                         {0, ID_WINDOW_NEW, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0},
4637                         {1, ID_WINDOW_CASCADE, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0},
4638                         {2, ID_WINDOW_TILE_HORZ, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0},
4639                         {3, ID_WINDOW_TILE_VERT, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0},
4640 /*TODO
4641                         {4, ID_... , TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0},
4642                         {5, ID_... , TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0},
4643 */              };
4644
4645                 Globals.htoolbar = CreateToolbarEx(Globals.hMainWnd, WS_CHILD|WS_VISIBLE,
4646                         IDW_TOOLBAR, 2, Globals.hInstance, IDB_TOOLBAR, toolbarBtns,
4647                         sizeof(toolbarBtns)/sizeof(TBBUTTON), 16, 15, 16, 15, sizeof(TBBUTTON));
4648                 CheckMenuItem(Globals.hMenuOptions, ID_VIEW_TOOL_BAR, MF_BYCOMMAND|MF_CHECKED);
4649         }
4650
4651         Globals.hstatusbar = CreateStatusWindowW(WS_CHILD|WS_VISIBLE, 0, Globals.hMainWnd, IDW_STATUSBAR);
4652         CheckMenuItem(Globals.hMenuOptions, ID_VIEW_STATUSBAR, MF_BYCOMMAND|MF_CHECKED);
4653
4654 /* CreateStatusWindowW does not accept WS_BORDER
4655         Globals.hstatusbar = CreateWindowExW(WS_EX_NOPARENTNOTIFY, STATUSCLASSNAME, 0,
4656                                         WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_BORDER|CCS_NODIVIDER, 0,0,0,0,
4657                                         Globals.hMainWnd, (HMENU)IDW_STATUSBAR, hinstance, 0);*/
4658
4659         /*TODO: read paths from registry */
4660
4661         if (!path || !*path) {
4662                 GetCurrentDirectoryW(MAX_PATH, buffer);
4663                 path = buffer;
4664         }
4665
4666         ShowWindow(Globals.hMainWnd, cmdshow);
4667
4668 #if defined(_SHELL_FOLDERS) && !defined(__WINE__)
4669          /* Shell Namespace as default: */
4670         child = alloc_child_window(path, get_path_pidl(path,Globals.hMainWnd), Globals.hMainWnd);
4671 #else
4672         child = alloc_child_window(path, NULL, Globals.hMainWnd);
4673 #endif
4674
4675         child->pos.showCmd = SW_SHOWMAXIMIZED;
4676         child->pos.rcNormalPosition.left = 0;
4677         child->pos.rcNormalPosition.top = 0;
4678         child->pos.rcNormalPosition.right = 320;
4679         child->pos.rcNormalPosition.bottom = 280;
4680
4681         if (!create_child_window(child)) {
4682                 HeapFree(GetProcessHeap(), 0, child);
4683                 return FALSE;
4684         }
4685
4686         SetWindowPlacement(child->hwnd, &child->pos);
4687
4688         Globals.himl = ImageList_LoadImageW(Globals.hInstance, MAKEINTRESOURCEW(IDB_IMAGES), 16, 0, RGB(0,255,0), IMAGE_BITMAP, 0);
4689
4690         Globals.prescan_node = FALSE;
4691
4692         UpdateWindow(Globals.hMainWnd);
4693
4694         if (child->hwnd && path && path[0])
4695         {
4696                 int index,count;
4697                 WCHAR drv[_MAX_DRIVE+1], dir[_MAX_DIR], name[_MAX_FNAME], ext[_MAX_EXT];
4698                 WCHAR fullname[_MAX_FNAME+_MAX_EXT+1];
4699
4700                 memset(name,0,sizeof(name));
4701                 memset(name,0,sizeof(ext));
4702                 _wsplitpath(path, drv, dir, name, ext);
4703                 if (name[0])
4704                 {
4705                         count = SendMessageW(child->right.hwnd, LB_GETCOUNT, 0, 0);
4706                         lstrcpyW(fullname,name);
4707                         lstrcatW(fullname,ext);
4708
4709                         for (index = 0; index < count; index ++)
4710                         {
4711                                 Entry* entry = (Entry*)SendMessageW(child->right.hwnd, LB_GETITEMDATA, index, 0);
4712                                 if (lstrcmpW(entry->data.cFileName,fullname)==0 ||
4713                                                 lstrcmpW(entry->data.cAlternateFileName,fullname)==0)
4714                                 {
4715                                         SendMessageW(child->right.hwnd, LB_SETCURSEL, index, 0);
4716                                         SetFocus(child->right.hwnd);
4717                                         break;
4718                                 }
4719                         }
4720                 }
4721         }
4722         return TRUE;
4723 }
4724
4725 static void ExitInstance(void)
4726 {
4727 #ifdef _SHELL_FOLDERS
4728         IShellFolder_Release(Globals.iDesktop);
4729         IMalloc_Release(Globals.iMalloc);
4730         CoUninitialize();
4731 #endif
4732
4733         DeleteObject(Globals.hfont);
4734         ImageList_Destroy(Globals.himl);
4735 }
4736
4737 #ifdef _NO_EXTENSIONS
4738
4739 /* search for already running win[e]files */
4740
4741 static int g_foundPrevInstance = 0;
4742
4743 static BOOL CALLBACK EnumWndProc(HWND hwnd, LPARAM lparam)
4744 {
4745         WCHAR cls[128];
4746
4747         GetClassName(hwnd, cls, 128);
4748
4749         if (!lstrcmpW(cls, (LPCWSTR)lparam)) {
4750                 g_foundPrevInstance++;
4751                 return FALSE;
4752         }
4753
4754         return TRUE;
4755 }
4756
4757 /* search for window of given class name to allow only one running instance */
4758 static int find_window_class(LPCWSTR classname)
4759 {
4760         EnumWindows(EnumWndProc, (LPARAM)classname);
4761
4762         if (g_foundPrevInstance)
4763                 return 1;
4764
4765         return 0;
4766 }
4767
4768 #endif
4769
4770 static int winefile_main(HINSTANCE hinstance, int cmdshow, LPCWSTR path)
4771 {
4772         MSG msg;
4773
4774         InitInstance(hinstance);
4775
4776         if( !show_frame(0, cmdshow, path) )
4777         {
4778                 ExitInstance();
4779                 return 1;
4780         }
4781
4782         while(GetMessageW(&msg, 0, 0, 0)) {
4783                 if (Globals.hmdiclient && TranslateMDISysAccel(Globals.hmdiclient, &msg))
4784                         continue;
4785
4786                 if (Globals.hMainWnd && TranslateAcceleratorW(Globals.hMainWnd, Globals.haccel, &msg))
4787                         continue;
4788
4789                 TranslateMessage(&msg);
4790                 DispatchMessageW(&msg);
4791         }
4792
4793         ExitInstance();
4794
4795         return msg.wParam;
4796 }
4797
4798
4799 #if defined(_MSC_VER)
4800 int APIENTRY wWinMain(HINSTANCE hinstance, HINSTANCE previnstance, LPWSTR cmdline, int cmdshow)
4801 #else
4802 int APIENTRY WinMain(HINSTANCE hinstance, HINSTANCE previnstance, LPSTR cmdline, int cmdshow)
4803 #endif
4804 {
4805 #ifdef _NO_EXTENSIONS
4806         if (find_window_class(sWINEFILEFRAME))
4807                 return 1;
4808 #endif
4809
4810         { /* convert ANSI cmdline into WCS path string */
4811         WCHAR buffer[MAX_PATH];
4812         MultiByteToWideChar(CP_ACP, 0, cmdline, -1, buffer, MAX_PATH);
4813         winefile_main(hinstance, cmdshow, buffer);
4814         }
4815
4816         return 0;
4817 }