- userinit, usetup, vmwinst, welcome, winefile, winlogon, winver.
[reactos.git] / reactos / subsys / system / winefile / winefile.c
index 013cdca..395876b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Winefile
  *
- * Copyright 2000, 2003, 2004 Martin Fuchs
+ * Copyright 2000, 2003, 2004, 2005 Martin Fuchs
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+#ifdef __WINE__
+#include "config.h"
+#include "wine/port.h"
+
+/* for unix filesystem function calls */
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#endif
+
+#define COBJMACROS
+
 #include "winefile.h"
 
 #include "resource.h"
@@ -141,67 +153,32 @@ typedef struct {
        BOOL    header_wdths_ok;
 
        TCHAR   path[MAX_PATH];
+       TCHAR   filter_pattern[MAX_PATH];
+       int             filter_flags;
        Root    root;
 
        SORT_ORDER sortOrder;
 } ChildWnd;
 
 
-extern void WineLicense(HWND hwnd);
-extern void WineWarranty(HWND hwnd);
-
-
-#ifdef __WINE__
-
-/* functions in unixcalls.c */
-
-extern void call_getcwd(char* buffer, size_t len);
-extern void* call_opendir(const char* path);
-extern int call_readdir(void* pdir, char* name, unsigned* pinode);
-extern void call_closedir(void* pdir);
-
-extern int call_stat(
-       const char* path, int* pis_dir,
-       unsigned long* psize_low, unsigned long* psize_high,
-       time_t* patime, time_t* pmtime,
-       unsigned long* plinks
-);
-
-/* call vswprintf() in msvcrt.dll */
-int swprintf(wchar_t* buffer, const wchar_t* fmt, ...)
-{
-       static int (__cdecl *vswprintf)(wchar_t*, const wchar_t*, va_list);
-
-       va_list ap;
-       int ret;
-
-       if (!vswprintf) {
-               HMODULE hmod = LoadLibraryA("msvcrt");
-               vswprintf = (int(__cdecl*)(wchar_t*,const wchar_t*,va_list)) GetProcAddress(hmod, "vswprintf");
-       }
-
-       va_start(ap, fmt);
-       ret = vswprintf(buffer, fmt, ap);
-       va_end(ap);
-
-       return 0;
-}
-
-#endif
-
 
 static void read_directory(Entry* dir, LPCTSTR path, SORT_ORDER sortOrder, HWND hwnd);
-static void set_curdir(ChildWnd* child, Entry* entry, HWND hwnd);
+static void set_curdir(ChildWnd* child, Entry* entry, int idx, HWND hwnd);
+static void refresh_child(ChildWnd* child);
+static void refresh_drives(void);
 static void get_path(Entry* dir, PTSTR path);
+static void format_date(const FILETIME* ft, TCHAR* buffer, int visible_cols);
 
-LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam);
-LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam);
-LRESULT CALLBACK TreeWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam);
+static LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam);
+static LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam);
+static LRESULT CALLBACK TreeWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam);
 
 
 /* globals */
 WINEFILE_GLOBALS Globals;
 
+static int last_split;
+
 
 /* some common string constants */
 const static TCHAR sEmpty[] = {'\0'};
@@ -251,8 +228,66 @@ static void display_error(HWND hwnd, DWORD error)
 }
 
 
+/* display network error message using WNetGetLastError() */
+static void display_network_error(HWND hwnd)
+{
+       TCHAR msg[BUFFER_LEN], provider[BUFFER_LEN], b2[BUFFER_LEN];
+       DWORD error;
+
+       if (WNetGetLastError(&error, msg, BUFFER_LEN, provider, BUFFER_LEN) == NO_ERROR)
+               MessageBox(hwnd, msg, RS(b2,IDS_WINEFILE), MB_OK);
+}
+
+
+#ifdef __WINE__
+
+#ifdef UNICODE
+
+/* call vswprintf() in msvcrt.dll */
+/*TODO: fix swprintf() in non-msvcrt mode, so that this dynamic linking function can be removed */
+static int msvcrt_swprintf(WCHAR* buffer, const WCHAR* fmt, ...)
+{
+       static int (__cdecl *pvswprintf)(WCHAR*, const WCHAR*, va_list) = NULL;
+       va_list ap;
+       int ret;
+
+       if (!pvswprintf) {
+               HMODULE hModMsvcrt = LoadLibraryA("msvcrt");
+               pvswprintf = (int(__cdecl*)(WCHAR*,const WCHAR*,va_list)) GetProcAddress(hModMsvcrt, "vswprintf");
+       }
+
+       va_start(ap, fmt);
+       ret = (*pvswprintf)(buffer, fmt, ap);
+       va_end(ap);
+
+       return ret;
+}
+
+static LPCWSTR my_wcsrchr(LPCWSTR str, WCHAR c)
+{
+       LPCWSTR p = str;
+
+       while(*p)
+               ++p;
+
+       do {
+               if (--p < str)
+                       return NULL;
+       } while(*p != c);
+
+       return p;
+}
+
+#define _tcsrchr my_wcsrchr
+#else  /* UNICODE */
+#define _tcsrchr strrchr
+#endif /* UNICODE */
+
+#endif /* __WINE__ */
+
+
 /* allocate and initialise a directory entry */
-static Entry* alloc_entry()
+static Entry* alloc_entry(void)
 {
        Entry* entry = (Entry*) malloc(sizeof(Entry));
 
@@ -273,10 +308,10 @@ static void free_entry(Entry* entry)
                DestroyIcon(entry->hicon);
 
        if (entry->folder && entry->folder!=Globals.iDesktop)
-               (*entry->folder->lpVtbl->Release)(entry->folder);
+               IShellFolder_Release(entry->folder);
 
        if (entry->pidl)
-               (*Globals.iMalloc->lpVtbl->Free)(Globals.iMalloc, entry->pidl);
+               IMalloc_Free(Globals.iMalloc, entry->pidl);
 #endif
 
        free(entry);
@@ -326,6 +361,15 @@ static void read_directory_win(Entry* dir, LPCTSTR path)
 
        if (hFind != INVALID_HANDLE_VALUE) {
                do {
+#ifdef _NO_EXTENSIONS
+                       /* hide directory entry "." */
+                       if (w32fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+                               LPCTSTR name = w32fd.cFileName;
+
+                               if (name[0]=='.' && name[1]=='\0')
+                                       continue;
+                       }
+#endif
                        entry = alloc_entry();
 
                        if (!first_entry)
@@ -341,15 +385,7 @@ static void read_directory_win(Entry* dir, LPCTSTR path)
                        entry->scanned = FALSE;
                        entry->level = level;
 
-#ifdef _NO_EXTENSIONS
-                       /* hide directory entry "." */
-                       if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
-                               LPCTSTR name = entry->data.cFileName;
-
-                               if (name[0]=='.' && name[1]=='\0')
-                                       continue;
-                       }
-#else
+#ifndef _NO_EXTENSIONS
                        entry->etype = ET_WINDOWS;
                        entry->bhfi_valid = FALSE;
 
@@ -367,9 +403,10 @@ static void read_directory_win(Entry* dir, LPCTSTR path)
 #endif
 
                        last = entry;
-               } while(FindNextFile(hFind, &entry->data));
+               } while(FindNextFile(hFind, &w32fd));
 
-               last->next = NULL;
+               if (last)
+                       last->next = NULL;
 
                FindClose(hFind);
        }
@@ -471,8 +508,9 @@ static void read_directory_unix(Entry* dir, LPCTSTR path)
        Entry* first_entry = NULL;
        Entry* last = NULL;
        Entry* entry;
-       void* pdir;
+       DIR* pdir;
 
+       int level = dir->level + 1;
 #ifdef UNICODE
        char cpath[MAX_PATH];
 
@@ -481,17 +519,13 @@ static void read_directory_unix(Entry* dir, LPCTSTR path)
        const char* cpath = path;
 #endif
 
-       pdir = call_opendir(cpath);
-
-       int level = dir->level + 1;
+       pdir = opendir(cpath);
 
        if (pdir) {
-               char buffer[MAX_PATH];
-               time_t atime, mtime;
-               unsigned inode;
-               int is_dir;
+               struct stat st;
+               struct dirent* ent;
+               char buffer[MAX_PATH], *p;
                const char* s;
-               char* p;
 
                for(p=buffer,s=cpath; *s; )
                        *p++ = *s++;
@@ -499,7 +533,7 @@ static void read_directory_unix(Entry* dir, LPCTSTR path)
                if (p==buffer || p[-1]!='/')
                        *p++ = '/';
 
-               while(call_readdir(pdir, p, &inode)) {
+               while((ent=readdir(pdir))) {
                        entry = alloc_entry();
 
                        if (!first_entry)
@@ -510,28 +544,31 @@ static void read_directory_unix(Entry* dir, LPCTSTR path)
 
                        entry->etype = ET_UNIX;
 
+                       strcpy(p, ent->d_name);
 #ifdef UNICODE
                        MultiByteToWideChar(CP_UNIXCP, 0, p, -1, entry->data.cFileName, MAX_PATH);
 #else
                        lstrcpy(entry->data.cFileName, p);
 #endif
 
-                       entry->data.dwFileAttributes = p[0]=='.'? FILE_ATTRIBUTE_HIDDEN: 0;
+                       if (!stat(buffer, &st)) {
+                               entry->data.dwFileAttributes = p[0]=='.'? FILE_ATTRIBUTE_HIDDEN: 0;
 
-                       if (!call_stat(buffer, &is_dir,
-                               &entry->data.nFileSizeLow, &entry->data.nFileSizeHigh,
-                               &atime, &mtime, &entry->bhfi.nNumberOfLinks))
-                       {
-                               if (is_dir)
+                               if (S_ISDIR(st.st_mode))
                                        entry->data.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
 
+                               entry->data.nFileSizeLow = st.st_size & 0xFFFFFFFF;
+                               entry->data.nFileSizeHigh = st.st_size >> 32;
+
                                memset(&entry->data.ftCreationTime, 0, sizeof(FILETIME));
-                               time_to_filetime(&atime, &entry->data.ftLastAccessTime);
-                               time_to_filetime(&mtime, &entry->data.ftLastWriteTime);
+                               time_to_filetime(&st.st_atime, &entry->data.ftLastAccessTime);
+                               time_to_filetime(&st.st_mtime, &entry->data.ftLastWriteTime);
 
-                               entry->bhfi.nFileIndexLow = inode;
+                               entry->bhfi.nFileIndexLow = ent->d_ino;
                                entry->bhfi.nFileIndexHigh = 0;
 
+                               entry->bhfi.nNumberOfLinks = st.st_nlink;
+
                                entry->bhfi_valid = TRUE;
                        } else {
                                entry->data.nFileSizeLow = 0;
@@ -548,9 +585,10 @@ static void read_directory_unix(Entry* dir, LPCTSTR path)
                        last = entry;
                }
 
-               last->next = NULL;
+               if (last)
+                       last->next = NULL;
 
-               call_closedir(pdir);
+               closedir(pdir);
        }
 
        dir->down = first_entry;
@@ -617,31 +655,27 @@ static Entry* read_tree_unix(Root* root, LPCTSTR path, SORT_ORDER sortOrder, HWN
 #ifdef _SHELL_FOLDERS
 
 #ifdef UNICODE
-#define        tcscpyn strcpyn
 #define        get_strret get_strretW
 #define        path_from_pidl path_from_pidlW
 #else
-#define        tcscpyn wcscpyn
 #define        get_strret get_strretA
 #define        path_from_pidl path_from_pidlA
 #endif
 
 
-static LPSTR strcpyn(LPSTR dest, LPCSTR source, size_t count)
+static void free_strret(STRRET* str)
 {
- LPCSTR s;
- LPSTR d = dest;
+       if (str->uType == STRRET_WSTR)
+               IMalloc_Free(Globals.iMalloc, str->UNION_MEMBER(pOleStr));
+}
 
- for(s=source; count&&(*d++=*s++); )
-  count--;
 
- return dest;
-}
+#ifndef UNICODE
 
-static LPWSTR wcscpyn(LPWSTR dest, LPCWSTR source, size_t count)
+static LPSTR strcpyn(LPSTR dest, LPCSTR source, size_t count)
 {
- LPCWSTR s;
- LPWSTR d = dest;
+ LPCSTR s;
+ LPSTR d = dest;
 
  for(s=source; count&&(*d++=*s++); )
   count--;
@@ -649,7 +683,6 @@ static LPWSTR wcscpyn(LPWSTR dest, LPCWSTR source, size_t count)
  return dest;
 }
 
-
 static void get_strretA(STRRET* str, const SHITEMID* shiid, LPSTR buffer, int len)
 {
  switch(str->uType) {
@@ -666,6 +699,35 @@ static void get_strretA(STRRET* str, const SHITEMID* shiid, LPSTR buffer, int le
  }
 }
 
+static HRESULT path_from_pidlA(IShellFolder* folder, LPITEMIDLIST pidl, LPSTR buffer, int len)
+{
+       STRRET str;
+
+        /* SHGDN_FORPARSING: get full path of id list */
+       HRESULT hr = IShellFolder_GetDisplayNameOf(folder, pidl, SHGDN_FORPARSING, &str);
+
+       if (SUCCEEDED(hr)) {
+               get_strretA(&str, &pidl->mkid, buffer, len);
+               free_strret(&str);
+       } else
+               buffer[0] = '\0';
+
+       return hr;
+}
+
+#endif
+
+static LPWSTR wcscpyn(LPWSTR dest, LPCWSTR source, size_t count)
+{
+ LPCWSTR s;
+ LPWSTR d = dest;
+
+ for(s=source; count&&(*d++=*s++); )
+  count--;
+
+ return dest;
+}
+
 static void get_strretW(STRRET* str, const SHITEMID* shiid, LPWSTR buffer, int len)
 {
  switch(str->uType) {
@@ -683,18 +745,11 @@ static void get_strretW(STRRET* str, const SHITEMID* shiid, LPWSTR buffer, int l
 }
 
 
-static void free_strret(STRRET* str)
-{
-       if (str->uType == STRRET_WSTR)
-               (*Globals.iMalloc->lpVtbl->Free)(Globals.iMalloc, str->UNION_MEMBER(pOleStr));
-}
-
-
-HRESULT name_from_pidl(IShellFolder* folder, LPITEMIDLIST pidl, LPTSTR buffer, int len, SHGDNF flags)
+static HRESULT name_from_pidl(IShellFolder* folder, LPITEMIDLIST pidl, LPTSTR buffer, int len, SHGDNF flags)
 {
        STRRET str;
 
-       HRESULT hr = (*folder->lpVtbl->GetDisplayNameOf)(folder, pidl, flags, &str);
+       HRESULT hr = IShellFolder_GetDisplayNameOf(folder, pidl, flags, &str);
 
        if (SUCCEEDED(hr)) {
                get_strret(&str, &pidl->mkid, buffer, len);
@@ -706,28 +761,12 @@ HRESULT name_from_pidl(IShellFolder* folder, LPITEMIDLIST pidl, LPTSTR buffer, i
 }
 
 
-HRESULT path_from_pidlA(IShellFolder* folder, LPITEMIDLIST pidl, LPSTR buffer, int len)
+static HRESULT path_from_pidlW(IShellFolder* folder, LPITEMIDLIST pidl, LPWSTR buffer, int len)
 {
        STRRET str;
 
         /* SHGDN_FORPARSING: get full path of id list */
-       HRESULT hr = (*folder->lpVtbl->GetDisplayNameOf)(folder, pidl, SHGDN_FORPARSING, &str);
-
-       if (SUCCEEDED(hr)) {
-               get_strretA(&str, &pidl->mkid, buffer, len);
-               free_strret(&str);
-       } else
-               buffer[0] = '\0';
-
-       return hr;
-}
-
-HRESULT path_from_pidlW(IShellFolder* folder, LPITEMIDLIST pidl, LPWSTR buffer, int len)
-{
-       STRRET str;
-
-        /* SHGDN_FORPARSING: get full path of id list */
-       HRESULT hr = (*folder->lpVtbl->GetDisplayNameOf)(folder, pidl, SHGDN_FORPARSING, &str);
+       HRESULT hr = IShellFolder_GetDisplayNameOf(folder, pidl, SHGDN_FORPARSING, &str);
 
        if (SUCCEEDED(hr)) {
                get_strretW(&str, &pidl->mkid, buffer, len);
@@ -754,7 +793,7 @@ static LPITEMIDLIST get_path_pidl(LPTSTR path, HWND hwnd)
        MultiByteToWideChar(CP_ACP, 0, path, -1, buffer, MAX_PATH);
 #endif
 
-       hr = (*Globals.iDesktop->lpVtbl->ParseDisplayName)(Globals.iDesktop, hwnd, NULL, buffer, &len, &pidl, NULL);
+       hr = IShellFolder_ParseDisplayName(Globals.iDesktop, hwnd, NULL, buffer, &len, &pidl, NULL);
        if (FAILED(hr))
                return NULL;
 
@@ -776,7 +815,7 @@ static LPITEMIDLIST get_to_absolute_pidl(Entry* entry, HWND hwnd)
                        LPITEMIDLIST pidl;
                        ULONG len;
 
-                       hr = (*Globals.iDesktop->lpVtbl->ParseDisplayName)(Globals.iDesktop, hwnd, NULL, buffer, &len, &pidl, NULL);
+                       hr = IShellFolder_ParseDisplayName(Globals.iDesktop, hwnd, NULL, buffer, &len, &pidl, NULL);
 
                        if (SUCCEEDED(hr))
                                return pidl;
@@ -794,11 +833,11 @@ static LPITEMIDLIST get_to_absolute_pidl(Entry* entry, HWND hwnd)
 }
 
 
-HICON extract_icon(IShellFolder* folder, LPCITEMIDLIST pidl)
+static HICON extract_icon(IShellFolder* folder, LPCITEMIDLIST pidl)
 {
        IExtractIcon* pExtract;
 
-       if (SUCCEEDED((*folder->lpVtbl->GetUIObjectOf)(folder, 0, 1, (LPCITEMIDLIST*)&pidl, &IID_IExtractIcon, 0, (LPVOID*)&pExtract))) {
+       if (SUCCEEDED(IShellFolder_GetUIObjectOf(folder, 0, 1, (LPCITEMIDLIST*)&pidl, &IID_IExtractIcon, 0, (LPVOID*)&pExtract))) {
                TCHAR path[_MAX_PATH];
                unsigned flags;
                HICON hicon;
@@ -828,7 +867,7 @@ HICON extract_icon(IShellFolder* folder, LPCITEMIDLIST pidl)
 }
 
 
-static Entry* find_entry_shell(Entry* dir, LPITEMIDLIST pidl)
+static Entry* find_entry_shell(Entry* dir, LPCITEMIDLIST pidl)
 {
        Entry* entry;
 
@@ -865,12 +904,12 @@ static Entry* read_tree_shell(Root* root, LPITEMIDLIST pidl, SORT_ORDER sortOrde
                if (!pidl->mkid.cb)
                        break;
 
-                /* copy first element of item idlist   -> could be replaced by SHBindToParent() */
-               next_pidl = (*Globals.iMalloc->lpVtbl->Alloc)(Globals.iMalloc, pidl->mkid.cb+sizeof(USHORT));
+                /* copy first element of item idlist */
+               next_pidl = IMalloc_Alloc(Globals.iMalloc, pidl->mkid.cb+sizeof(USHORT));
                memcpy(next_pidl, pidl, pidl->mkid.cb);
                ((LPITEMIDLIST)((LPBYTE)next_pidl+pidl->mkid.cb))->mkid.cb = 0;
 
-               hr = (*folder->lpVtbl->BindToObject)(folder, next_pidl, 0, &IID_IShellFolder, (void**)&child);
+               hr = IShellFolder_BindToObject(folder, next_pidl, 0, &IID_IShellFolder, (void**)&child);
                if (!SUCCEEDED(hr))
                        break;
 
@@ -906,12 +945,12 @@ static void fill_w32fdata_shell(IShellFolder* folder, LPCITEMIDLIST pidl, SFGAOF
                STGMEDIUM medium = {0, {0}, 0};
                FORMATETC fmt = {Globals.cfStrFName, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
 
-               HRESULT hr = (*folder->lpVtbl->GetUIObjectOf)(folder, 0, 1, &pidl, &IID_IDataObject, 0, (LPVOID*)&pDataObj);
+               HRESULT hr = IShellFolder_GetUIObjectOf(folder, 0, 1, &pidl, &IID_IDataObject, 0, (LPVOID*)&pDataObj);
 
                if (SUCCEEDED(hr)) {
-                       hr = (*pDataObj->lpVtbl->GetData)(pDataObj, &fmt, &medium);
+                       hr = IDataObject_GetData(pDataObj, &fmt, &medium);
 
-                       (*pDataObj->lpVtbl->Release)(pDataObj);
+                       IDataObject_Release(pDataObj);
 
                        if (SUCCEEDED(hr)) {
                                LPCTSTR path = (LPCTSTR)GlobalLock(medium.UNION_MEMBER(hGlobal));
@@ -964,7 +1003,7 @@ static void read_directory_shell(Entry* dir, HWND hwnd)
        if (!folder)
                return;
 
-       hr = (*folder->lpVtbl->EnumObjects)(folder, hwnd, SHCONTF_FOLDERS|SHCONTF_NONFOLDERS|SHCONTF_INCLUDEHIDDEN|SHCONTF_SHAREABLE|SHCONTF_STORAGE, &idlist);
+       hr = IShellFolder_EnumObjects(folder, hwnd, SHCONTF_FOLDERS|SHCONTF_NONFOLDERS|SHCONTF_INCLUDEHIDDEN|SHCONTF_SHAREABLE|SHCONTF_STORAGE, &idlist);
 
        if (SUCCEEDED(hr)) {
                for(;;) {
@@ -976,7 +1015,7 @@ static void read_directory_shell(Entry* dir, HWND hwnd)
 
                        memset(pidls, 0, sizeof(pidls));
 
-                       hr = (*idlist->lpVtbl->Next)(idlist, FETCH_ITEM_COUNT, pidls, &cnt);
+                       hr = IEnumIDList_Next(idlist, FETCH_ITEM_COUNT, pidls, &cnt);
                        if (!SUCCEEDED(hr))
                                break;
 
@@ -997,7 +1036,7 @@ static void read_directory_shell(Entry* dir, HWND hwnd)
 
                                attribs = ~SFGAO_FILESYSTEM;    /*SFGAO_HASSUBFOLDER|SFGAO_FOLDER; SFGAO_FILESYSTEM sorgt dafür, daß "My Documents" anstatt von "Martin's Documents" angezeigt wird */
 
-                               hr = (*folder->lpVtbl->GetAttributesOf)(folder, 1, (LPCITEMIDLIST*)&pidls[n], &attribs);
+                               hr = IShellFolder_GetAttributesOf(folder, 1, (LPCITEMIDLIST*)&pidls[n], &attribs);
 
                                if (SUCCEEDED(hr)) {
                                        if (attribs != (SFGAOF)~SFGAO_FILESYSTEM) {
@@ -1012,7 +1051,7 @@ static void read_directory_shell(Entry* dir, HWND hwnd)
                                entry->pidl = pidls[n];
 
                                if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
-                                       hr = (*folder->lpVtbl->BindToObject)(folder, pidls[n], 0, &IID_IShellFolder, (void**)&child);
+                                       hr = IShellFolder_BindToObject(folder, pidls[n], 0, &IID_IShellFolder, (void**)&child);
 
                                        if (SUCCEEDED(hr))
                                                entry->folder = child;
@@ -1049,7 +1088,7 @@ static void read_directory_shell(Entry* dir, HWND hwnd)
                        }
                }
 
-               (*idlist->lpVtbl->Release)(idlist);
+               IEnumIDList_Release(idlist);
        }
 
        if (last)
@@ -1086,7 +1125,7 @@ static int TypeOrderFromDirname(LPCTSTR name)
 }
 
 /* directories first... */
-static int compareType(const WIN32_FIND_DATA* fd1, const WIN32_FIND_DATA* fd2)
+static int __cdecl compareType(const WIN32_FIND_DATA* fd1, const WIN32_FIND_DATA* fd2)
 {
        int order1 = fd1->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY? TO_DIR: TO_FILE;
        int order2 = fd2->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY? TO_DIR: TO_FILE;
@@ -1101,10 +1140,10 @@ static int compareType(const WIN32_FIND_DATA* fd1, const WIN32_FIND_DATA* fd2)
 }
 
 
-static int compareName(const void* arg1, const void* arg2)
+static int __cdecl compareName(const void* arg1, const void* arg2)
 {
-       const WIN32_FIND_DATA* fd1 = &(*(Entry**)arg1)->data;
-       const WIN32_FIND_DATA* fd2 = &(*(Entry**)arg2)->data;
+       const WIN32_FIND_DATA* fd1 = &(*(const Entry* const*)arg1)->data;
+       const WIN32_FIND_DATA* fd2 = &(*(const Entry* const*)arg2)->data;
 
        int cmp = compareType(fd1, fd2);
        if (cmp)
@@ -1113,10 +1152,10 @@ static int compareName(const void* arg1, const void* arg2)
        return lstrcmpi(fd1->cFileName, fd2->cFileName);
 }
 
-static int compareExt(const void* arg1, const void* arg2)
+static int __cdecl compareExt(const void* arg1, const void* arg2)
 {
-       const WIN32_FIND_DATA* fd1 = &(*(Entry**)arg1)->data;
-       const WIN32_FIND_DATA* fd2 = &(*(Entry**)arg2)->data;
+       const WIN32_FIND_DATA* fd1 = &(*(const Entry* const*)arg1)->data;
+       const WIN32_FIND_DATA* fd2 = &(*(const Entry* const*)arg2)->data;
        const TCHAR *name1, *name2, *ext1, *ext2;
 
        int cmp = compareType(fd1, fd2);
@@ -1146,10 +1185,10 @@ static int compareExt(const void* arg1, const void* arg2)
        return lstrcmpi(name1, name2);
 }
 
-static int compareSize(const void* arg1, const void* arg2)
+static int __cdecl compareSize(const void* arg1, const void* arg2)
 {
-       WIN32_FIND_DATA* fd1 = &(*(Entry**)arg1)->data;
-       WIN32_FIND_DATA* fd2 = &(*(Entry**)arg2)->data;
+       const WIN32_FIND_DATA* fd1 = &(*(const Entry* const*)arg1)->data;
+       const WIN32_FIND_DATA* fd2 = &(*(const Entry* const*)arg2)->data;
 
        int cmp = compareType(fd1, fd2);
        if (cmp)
@@ -1167,10 +1206,10 @@ static int compareSize(const void* arg1, const void* arg2)
        return cmp<0? -1: cmp>0? 1: 0;
 }
 
-static int compareDate(const void* arg1, const void* arg2)
+static int __cdecl compareDate(const void* arg1, const void* arg2)
 {
-       WIN32_FIND_DATA* fd1 = &(*(Entry**)arg1)->data;
-       WIN32_FIND_DATA* fd2 = &(*(Entry**)arg2)->data;
+       const WIN32_FIND_DATA* fd1 = &(*(const Entry* const*)arg1)->data;
+       const WIN32_FIND_DATA* fd2 = &(*(const Entry* const*)arg2)->data;
 
        int cmp = compareType(fd1, fd2);
        if (cmp)
@@ -1180,7 +1219,7 @@ static int compareDate(const void* arg1, const void* arg2)
 }
 
 
-static int (*sortFunctions[])(const void* arg1, const void* arg2) = {
+static int (__cdecl *sortFunctions[])(const void* arg1, const void* arg2) = {
        compareName,    /* SORT_NAME */
        compareExt,             /* SORT_EXT */
        compareSize,    /* SORT_SIZE */
@@ -1199,7 +1238,7 @@ static void SortDirectory(Entry* dir, SORT_ORDER sortOrder)
                len++;
 
        if (len) {
-               array = (Entry**) alloca(len*sizeof(Entry*));
+               array = HeapAlloc(GetProcessHeap(), 0, len*sizeof(Entry*));
 
                p = array;
                for(entry=dir->down; entry; entry=entry->next)
@@ -1214,6 +1253,8 @@ static void SortDirectory(Entry* dir, SORT_ORDER sortOrder)
                        p[0]->next = p[1];
 
                (*p)->next = 0;
+
+               HeapFree(GetProcessHeap(), 0, array);
        }
 }
 
@@ -1297,15 +1338,73 @@ static void read_directory(Entry* dir, LPCTSTR path, SORT_ORDER sortOrder, HWND
 }
 
 
-static ChildWnd* alloc_child_window(LPCTSTR path, LPITEMIDLIST pidl, HWND hwnd)
+static Entry* read_tree(Root* root, LPCTSTR path, LPITEMIDLIST pidl, LPTSTR drv, SORT_ORDER sortOrder, HWND hwnd)
 {
-       const static TCHAR sBackslash[] = {'\\', '\0'};
 #if !defined(_NO_EXTENSIONS) && defined(__WINE__)
        const static TCHAR sSlash[] = {'/', '\0'};
 #endif
+       const static TCHAR sBackslash[] = {'\\', '\0'};
+
+#ifdef _SHELL_FOLDERS
+       if (pidl)
+       {
+                /* read shell namespace tree */
+               root->drive_type = DRIVE_UNKNOWN;
+               drv[0] = '\\';
+               drv[1] = '\0';
+               load_string(root->volname, IDS_DESKTOP);
+               root->fs_flags = 0;
+               load_string(root->fs, IDS_SHELL);
+
+               return read_tree_shell(root, pidl, sortOrder, hwnd);
+       }
+       else
+#endif
+#if !defined(_NO_EXTENSIONS) && defined(__WINE__)
+       if (*path == '/')
+       {
+                /* read unix file system tree */
+               root->drive_type = GetDriveType(path);
+
+               lstrcat(drv, sSlash);
+               load_string(root->volname, IDS_ROOT_FS);
+               root->fs_flags = 0;
+               load_string(root->fs, IDS_UNIXFS);
 
+               lstrcpy(root->path, sSlash);
+
+               return read_tree_unix(root, path, sortOrder, hwnd);
+       }
+#endif
+
+        /* read WIN32 file system tree */
+       root->drive_type = GetDriveType(path);
+
+       lstrcat(drv, sBackslash);
+       GetVolumeInformation(drv, root->volname, _MAX_FNAME, 0, 0, &root->fs_flags, root->fs, _MAX_DIR);
+
+       lstrcpy(root->path, drv);
+
+       return read_tree_win(root, path, sortOrder, hwnd);
+}
+
+
+/* flags to filter different file types */
+enum TYPE_FILTER {
+       TF_DIRECTORIES  = 0x01,
+       TF_PROGRAMS             = 0x02,
+       TF_DOCUMENTS    = 0x04,
+       TF_OTHERS               = 0x08,
+       TF_HIDDEN               = 0x10,
+       TF_ALL                  = 0x1F
+};
+
+
+static ChildWnd* alloc_child_window(LPCTSTR path, LPITEMIDLIST pidl, HWND hwnd)
+{
        TCHAR drv[_MAX_DRIVE+1], dir[_MAX_DIR], name[_MAX_FNAME], ext[_MAX_EXT];
        TCHAR b1[BUFFER_LEN];
+       const static TCHAR sAsterics[] = {'*', '\0'};
 
        ChildWnd* child = (ChildWnd*) malloc(sizeof(ChildWnd));
        Root* root = &child->root;
@@ -1343,46 +1442,12 @@ static ChildWnd* alloc_child_window(LPCTSTR path, LPITEMIDLIST pidl, HWND hwnd)
                _tsplitpath(path, drv, dir, name, ext);
        }
 
-       root->entry.level = 0;
+       lstrcpy(child->filter_pattern, sAsterics);
+       child->filter_flags = TF_ALL;
 
-#ifdef _SHELL_FOLDERS
-       if (pidl)
-       {
-               root->drive_type = DRIVE_UNKNOWN;
-               drv[0] = '\\';
-               drv[1] = '\0';
-               load_string(root->volname, IDS_DESKTOP);
-               root->fs_flags = 0;
-               load_string(root->fs, IDS_SHELL);
-
-               entry = read_tree_shell(root, pidl, child->sortOrder, hwnd);
-       }
-       else
-#endif
-#if !defined(_NO_EXTENSIONS) && defined(__WINE__)
-       if (*path == '/')
-       {
-               root->drive_type = GetDriveType(path);
-
-               lstrcat(drv, sSlash);
-               load_string(root->volname, IDS_ROOT_FS);
-               root->fs_flags = 0;
-               load_string(root->fs, IDS_UNIXFS);
-
-               lstrcpy(root->path, sSlash);
-               entry = read_tree_unix(root, path, child->sortOrder, hwnd);
-       }
-       else
-#endif
-       {
-               root->drive_type = GetDriveType(path);
-
-               lstrcat(drv, sBackslash);
-               GetVolumeInformation(drv, root->volname, _MAX_FNAME, 0, 0, &root->fs_flags, root->fs, _MAX_DIR);
+       root->entry.level = 0;
 
-               lstrcpy(root->path, drv);
-               entry = read_tree_win(root, path, child->sortOrder, hwnd);
-       }
+       entry = read_tree(root, path, pidl, drv, child->sortOrder, hwnd);
 
 #ifdef _SHELL_FOLDERS
        if (root->entry.etype == ET_SHELL)
@@ -1396,7 +1461,7 @@ static ChildWnd* alloc_child_window(LPCTSTR path, LPITEMIDLIST pidl, HWND hwnd)
        child->left.root = &root->entry;
        child->right.root = NULL;
 
-       set_curdir(child, entry, hwnd);
+       set_curdir(child, entry, 0, hwnd);
 
        return child;
 }
@@ -1428,7 +1493,7 @@ static void get_path(Entry* dir, PTSTR path)
                attribs = 0;
 
                if (dir->folder)
-                       hr = (*dir->folder->lpVtbl->GetAttributesOf)(dir->folder, 1, (LPCITEMIDLIST*)&dir->pidl, &attribs);
+                       hr = IShellFolder_GetAttributesOf(dir->folder, 1, (LPCITEMIDLIST*)&dir->pidl, &attribs);
 
                if (SUCCEEDED(hr) && (attribs&SFGAO_FILESYSTEM)) {
                        IShellFolder* parent = dir->up? dir->up->folder: Globals.iDesktop;
@@ -1547,14 +1612,14 @@ static void resize_frame_client(HWND hwnd)
 static HHOOK hcbthook;
 static ChildWnd* newchild = NULL;
 
-LRESULT CALLBACK CBTProc(int code, WPARAM wparam, LPARAM lparam)
+static LRESULT CALLBACK CBTProc(int code, WPARAM wparam, LPARAM lparam)
 {
        if (code==HCBT_CREATEWND && newchild) {
                ChildWnd* child = newchild;
                newchild = NULL;
 
                child->hwnd = (HWND) wparam;
-               SetWindowLong(child->hwnd, GWL_USERDATA, (LPARAM)child);
+               SetWindowLongPtr(child->hwnd, GWLP_USERDATA, (LPARAM)child);
        }
 
        return CallNextHookEx(hcbthook, code, wparam, lparam);
@@ -1588,7 +1653,8 @@ static HWND create_child_window(ChildWnd* child)
 
        ListBox_SetItemHeight(child->left.hwnd, 1, max(Globals.spaceSize.cy,IMAGE_HEIGHT+3));
        ListBox_SetItemHeight(child->right.hwnd, 1, max(Globals.spaceSize.cy,IMAGE_HEIGHT+3));
-       idx = ListBox_FindItemData(child->left.hwnd, ListBox_GetCurSel(child->left.hwnd), child->left.cur);
+
+       idx = ListBox_FindItemData(child->left.hwnd, 0, child->left.cur);
        ListBox_SetCurSel(child->left.hwnd, idx);
 
        return child->hwnd;
@@ -1600,7 +1666,6 @@ struct ExecuteDialog {
        int             cmdshow;
 };
 
-
 static INT_PTR CALLBACK ExecuteDialogDlgProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
 {
        static struct ExecuteDialog* dlg;
@@ -1627,13 +1692,15 @@ static INT_PTR CALLBACK ExecuteDialogDlgProc(HWND hwnd, UINT nmsg, WPARAM wparam
        return 0;
 }
 
+
 static INT_PTR CALLBACK DestinationDlgProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
 {
        TCHAR b1[BUFFER_LEN], b2[BUFFER_LEN];
 
        switch(nmsg) {
                case WM_INITDIALOG:
-                       SetWindowLong(hwnd, GWL_USERDATA, lparam);
+                       SetWindowLongPtr(hwnd, GWLP_USERDATA, lparam);
+                       SetWindowText(GetDlgItem(hwnd, 201), (LPCTSTR)lparam);
                        return 1;
 
                case WM_COMMAND: {
@@ -1641,7 +1708,7 @@ static INT_PTR CALLBACK DestinationDlgProc(HWND hwnd, UINT nmsg, WPARAM wparam,
 
                        switch(id) {
                          case IDOK: {
-                               LPTSTR dest = (LPTSTR) GetWindowLong(hwnd, GWL_USERDATA);
+                               LPTSTR dest = (LPTSTR) GetWindowLongPtr(hwnd, GWLP_USERDATA);
                                GetWindowText(GetDlgItem(hwnd, 201), dest, MAX_PATH);
                                EndDialog(hwnd, id);
                                break;}
@@ -1663,6 +1730,240 @@ static INT_PTR CALLBACK DestinationDlgProc(HWND hwnd, UINT nmsg, WPARAM wparam,
 }
 
 
+struct FilterDialog {
+       TCHAR   pattern[MAX_PATH];
+       int             flags;
+};
+
+static INT_PTR CALLBACK FilterDialogDlgProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
+{
+       static struct FilterDialog* dlg;
+
+       switch(nmsg) {
+               case WM_INITDIALOG:
+                       dlg = (struct FilterDialog*) lparam;
+                       SetWindowText(GetDlgItem(hwnd, IDC_VIEW_PATTERN), dlg->pattern);
+                       Button_SetCheck(GetDlgItem(hwnd,IDC_VIEW_TYPE_DIRECTORIES), (dlg->flags&TF_DIRECTORIES? BST_CHECKED: BST_UNCHECKED));
+                       Button_SetCheck(GetDlgItem(hwnd,IDC_VIEW_TYPE_PROGRAMS), dlg->flags&TF_PROGRAMS? BST_CHECKED: BST_UNCHECKED);
+                       Button_SetCheck(GetDlgItem(hwnd,IDC_VIEW_TYPE_DOCUMENTS), dlg->flags&TF_DOCUMENTS? BST_CHECKED: BST_UNCHECKED);
+                       Button_SetCheck(GetDlgItem(hwnd,IDC_VIEW_TYPE_OTHERS), dlg->flags&TF_OTHERS? BST_CHECKED: BST_UNCHECKED);
+                       Button_SetCheck(GetDlgItem(hwnd,IDC_VIEW_TYPE_HIDDEN), dlg->flags&TF_HIDDEN? BST_CHECKED: BST_UNCHECKED);
+                       return 1;
+
+               case WM_COMMAND: {
+                       int id = (int)wparam;
+
+                       if (id == IDOK) {
+                               int flags = 0;
+
+                               GetWindowText(GetDlgItem(hwnd, IDC_VIEW_PATTERN), dlg->pattern, MAX_PATH);
+
+                               flags |= Button_GetCheck(GetDlgItem(hwnd,IDC_VIEW_TYPE_DIRECTORIES))&BST_CHECKED? TF_DIRECTORIES: 0;
+                               flags |= Button_GetCheck(GetDlgItem(hwnd,IDC_VIEW_TYPE_PROGRAMS))&BST_CHECKED? TF_PROGRAMS: 0;
+                               flags |= Button_GetCheck(GetDlgItem(hwnd,IDC_VIEW_TYPE_DOCUMENTS))&BST_CHECKED? TF_DOCUMENTS: 0;
+                               flags |= Button_GetCheck(GetDlgItem(hwnd,IDC_VIEW_TYPE_OTHERS))&BST_CHECKED? TF_OTHERS: 0;
+                               flags |= Button_GetCheck(GetDlgItem(hwnd,IDC_VIEW_TYPE_HIDDEN))&BST_CHECKED? TF_HIDDEN: 0;
+
+                               dlg->flags = flags;
+
+                               EndDialog(hwnd, id);
+                       } else if (id == IDCANCEL)
+                               EndDialog(hwnd, id);
+
+                       return 1;}
+       }
+
+       return 0;
+}
+
+
+struct PropertiesDialog {
+       TCHAR   path[MAX_PATH];
+       Entry   entry;
+       void*   pVersionData;
+};
+
+/* Structure used to store enumerated languages and code pages. */
+struct LANGANDCODEPAGE {
+       WORD wLanguage;
+       WORD wCodePage;
+} *lpTranslate;
+
+static LPCSTR InfoStrings[] = {
+       "Comments",
+       "CompanyName",
+       "FileDescription",
+       "FileVersion",
+       "InternalName",
+       "LegalCopyright",
+       "LegalTrademarks",
+       "OriginalFilename",
+       "PrivateBuild",
+       "ProductName",
+       "ProductVersion",
+       "SpecialBuild",
+       NULL
+};
+
+static void PropDlg_DisplayValue(HWND hlbox, HWND hedit)
+{
+       int idx = ListBox_GetCurSel(hlbox);
+
+       if (idx != LB_ERR) {
+               LPCTSTR pValue = (LPCTSTR) ListBox_GetItemData(hlbox, idx);
+
+               if (pValue)
+                       SetWindowText(hedit, pValue);
+       }
+}
+
+static void CheckForFileInfo(struct PropertiesDialog* dlg, HWND hwnd, LPCTSTR strFilename)
+{
+       static TCHAR sBackSlash[] = {'\\','\0'};
+       static TCHAR sTranslation[] = {'\\','V','a','r','F','i','l','e','I','n','f','o','\\','T','r','a','n','s','l','a','t','i','o','n','\0'};
+       static TCHAR sStringFileInfo[] = {'\\','S','t','r','i','n','g','F','i','l','e','I','n','f','o','\\',
+                                                                               '%','0','4','x','%','0','4','x','\\','%','s','\0'};
+       DWORD dwVersionDataLen = GetFileVersionInfoSize((LPTSTR)strFilename, NULL);     /* VC6 and MinGW headers use LPTSTR instead of LPCTSTR */
+
+       if (dwVersionDataLen) {
+               dlg->pVersionData = malloc(dwVersionDataLen);
+
+               if (GetFileVersionInfo((LPTSTR)strFilename, 0, dwVersionDataLen, dlg->pVersionData)) {  /* VC6 and MinGW headers use LPTSTR instead of LPCTSTR */
+                       LPVOID pVal;
+                       UINT nValLen;
+
+                       if (VerQueryValue(dlg->pVersionData, sBackSlash, &pVal, &nValLen)) {
+                               if (nValLen == sizeof(VS_FIXEDFILEINFO)) {
+                                       VS_FIXEDFILEINFO* pFixedFileInfo = (VS_FIXEDFILEINFO*)pVal;
+                                       char buffer[BUFFER_LEN];
+
+                                       sprintf(buffer, "%d.%d.%d.%d",
+                                               HIWORD(pFixedFileInfo->dwFileVersionMS), LOWORD(pFixedFileInfo->dwFileVersionMS),
+                                               HIWORD(pFixedFileInfo->dwFileVersionLS), LOWORD(pFixedFileInfo->dwFileVersionLS));
+
+                                       SetDlgItemTextA(hwnd, IDC_STATIC_PROP_VERSION, buffer);
+                               }
+                       }
+
+                       /* Read the list of languages and code pages. */
+                       if (VerQueryValue(dlg->pVersionData, sTranslation, &pVal, &nValLen)) {
+                               struct LANGANDCODEPAGE* pTranslate = (struct LANGANDCODEPAGE*)pVal;
+                               struct LANGANDCODEPAGE* pEnd = (struct LANGANDCODEPAGE*)((LPBYTE)pVal+nValLen);
+
+                               HWND hlbox = GetDlgItem(hwnd, IDC_LIST_PROP_VERSION_TYPES);
+
+                               /* Read the file description for each language and code page. */
+                               for(; pTranslate<pEnd; ++pTranslate) {
+                                       LPCSTR* p;
+
+                                       for(p=InfoStrings; *p; ++p) {
+                                               TCHAR subblock[200];
+#ifdef UNICODE
+                                               TCHAR infoStr[100];
+#endif
+                                               LPCTSTR pTxt;
+                                               UINT nValLen;
+
+                                               LPCSTR pInfoString = *p;
+#ifdef UNICODE
+                                               MultiByteToWideChar(CP_ACP, 0, pInfoString, -1, infoStr, 100);
+#else
+#define        infoStr pInfoString
+#endif
+                                               wsprintf(subblock, sStringFileInfo, pTranslate->wLanguage, pTranslate->wCodePage, infoStr);
+
+                                               /* Retrieve file description for language and code page */
+                                               if (VerQueryValue(dlg->pVersionData, subblock, (PVOID)&pTxt, &nValLen)) {
+                                                       int idx = ListBox_AddString(hlbox, infoStr);
+                                                       ListBox_SetItemData(hlbox, idx, pTxt);
+                                               }
+                                       }
+                               }
+
+                               ListBox_SetCurSel(hlbox, 0);
+
+                               PropDlg_DisplayValue(hlbox, GetDlgItem(hwnd,IDC_LIST_PROP_VERSION_VALUES));
+                       }
+               }
+       }
+}
+
+static INT_PTR CALLBACK PropertiesDialogDlgProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
+{
+       static struct PropertiesDialog* dlg;
+
+       switch(nmsg) {
+               case WM_INITDIALOG: {
+                       const static TCHAR sByteFmt[] = {'%','s',' ','B','y','t','e','s','\0'};
+                       TCHAR b1[BUFFER_LEN], b2[BUFFER_LEN];
+                       LPWIN32_FIND_DATA pWFD;
+                       ULONGLONG size;
+
+                       dlg = (struct PropertiesDialog*) lparam;
+                       pWFD = (LPWIN32_FIND_DATA) &dlg->entry.data;
+
+                       GetWindowText(hwnd, b1, MAX_PATH);
+                       wsprintf(b2, b1, pWFD->cFileName);
+                       SetWindowText(hwnd, b2);
+
+                       format_date(&pWFD->ftLastWriteTime, b1, COL_DATE|COL_TIME);
+                       SetWindowText(GetDlgItem(hwnd, IDC_STATIC_PROP_LASTCHANGE), b1);
+
+                       size = ((ULONGLONG)pWFD->nFileSizeHigh << 32) | pWFD->nFileSizeLow;
+                       _stprintf(b1, sLongNumFmt, size);
+                       wsprintf(b2, sByteFmt, b1);
+                       SetWindowText(GetDlgItem(hwnd, IDC_STATIC_PROP_SIZE), b2);
+
+                       SetWindowText(GetDlgItem(hwnd, IDC_STATIC_PROP_FILENAME), pWFD->cFileName);
+                       SetWindowText(GetDlgItem(hwnd, IDC_STATIC_PROP_PATH), dlg->path);
+
+                       Button_SetCheck(GetDlgItem(hwnd,IDC_CHECK_READONLY), (pWFD->dwFileAttributes&FILE_ATTRIBUTE_READONLY? BST_CHECKED: BST_UNCHECKED));
+                       Button_SetCheck(GetDlgItem(hwnd,IDC_CHECK_ARCHIVE), (pWFD->dwFileAttributes&FILE_ATTRIBUTE_ARCHIVE? BST_CHECKED: BST_UNCHECKED));
+                       Button_SetCheck(GetDlgItem(hwnd,IDC_CHECK_COMPRESSED), (pWFD->dwFileAttributes&FILE_ATTRIBUTE_COMPRESSED? BST_CHECKED: BST_UNCHECKED));
+                       Button_SetCheck(GetDlgItem(hwnd,IDC_CHECK_HIDDEN), (pWFD->dwFileAttributes&FILE_ATTRIBUTE_HIDDEN? BST_CHECKED: BST_UNCHECKED));
+                       Button_SetCheck(GetDlgItem(hwnd,IDC_CHECK_SYSTEM), (pWFD->dwFileAttributes&FILE_ATTRIBUTE_SYSTEM? BST_CHECKED: BST_UNCHECKED));
+
+                       CheckForFileInfo(dlg, hwnd, dlg->path);
+                       return 1;}
+
+               case WM_COMMAND: {
+                       int id = (int)wparam;
+
+                       switch(HIWORD(wparam)) {
+                         case LBN_SELCHANGE: {
+                               HWND hlbox = GetDlgItem(hwnd, IDC_LIST_PROP_VERSION_TYPES);
+                               PropDlg_DisplayValue(hlbox, GetDlgItem(hwnd,IDC_LIST_PROP_VERSION_VALUES));
+                               break;
+                         }
+
+                         case BN_CLICKED:
+                               if (id==IDOK || id==IDCANCEL)
+                                       EndDialog(hwnd, id);
+                       }
+
+                       return 1;}
+
+               case WM_NCDESTROY:
+                       free(dlg->pVersionData);
+                       dlg->pVersionData = NULL;
+                       break;
+       }
+
+       return 0;
+}
+
+static void show_properties_dlg(Entry* entry, HWND hwnd)
+{
+       struct PropertiesDialog dlg;
+
+       memset(&dlg, 0, sizeof(struct PropertiesDialog));
+       get_path(entry, dlg.path);
+       memcpy(&dlg.entry, entry, sizeof(Entry));
+
+       DialogBoxParam(Globals.hInstance, MAKEINTRESOURCE(IDD_DIALOG_PROPERTIES), hwnd, PropertiesDialogDlgProc, (LPARAM)&dlg);
+}
+
+
 #ifndef _NO_EXTENSIONS
 
 static struct FullScreenParameters {
@@ -1675,7 +1976,7 @@ static struct FullScreenParameters {
        FALSE
 };
 
-void frame_get_clientspace(HWND hwnd, PRECT prect)
+static void frame_get_clientspace(HWND hwnd, PRECT prect)
 {
        RECT rt;
 
@@ -1776,7 +2077,7 @@ static void toggle_child(HWND hwnd, UINT cmd, HWND hchild)
        resize_frame_client(hwnd);
 }
 
-BOOL activate_drive_window(LPCTSTR path)
+static BOOL activate_drive_window(LPCTSTR path)
 {
        TCHAR drv1[_MAX_DRIVE], drv2[_MAX_DRIVE];
        HWND child_wnd;
@@ -1785,7 +2086,7 @@ BOOL activate_drive_window(LPCTSTR path)
 
        /* search for a already open window for the same drive */
        for(child_wnd=GetNextWindow(Globals.hmdiclient,GW_CHILD); child_wnd; child_wnd=GetNextWindow(child_wnd, GW_HWNDNEXT)) {
-               ChildWnd* child = (ChildWnd*) GetWindowLong(child_wnd, GWL_USERDATA);
+               ChildWnd* child = (ChildWnd*) GetWindowLongPtr(child_wnd, GWLP_USERDATA);
 
                if (child) {
                        _tsplitpath(child->root.path, drv2, 0, 0, 0);
@@ -1804,13 +2105,13 @@ BOOL activate_drive_window(LPCTSTR path)
        return FALSE;
 }
 
-BOOL activate_fs_window(LPCTSTR filesys)
+static BOOL activate_fs_window(LPCTSTR filesys)
 {
        HWND child_wnd;
 
        /* search for a already open window of the given file system name */
        for(child_wnd=GetNextWindow(Globals.hmdiclient,GW_CHILD); child_wnd; child_wnd=GetNextWindow(child_wnd, GW_HWNDNEXT)) {
-               ChildWnd* child = (ChildWnd*) GetWindowLong(child_wnd, GWL_USERDATA);
+               ChildWnd* child = (ChildWnd*) GetWindowLongPtr(child_wnd, GWLP_USERDATA);
 
                if (child) {
                        if (!lstrcmpi(child->root.fs, filesys)) {
@@ -1827,7 +2128,7 @@ BOOL activate_fs_window(LPCTSTR filesys)
        return FALSE;
 }
 
-LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
+static LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
 {
        TCHAR b1[BUFFER_LEN], b2[BUFFER_LEN];
 
@@ -1845,11 +2146,16 @@ LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam
                        break;
 
                case WM_DESTROY:
-                        /* don't exit desktop when closing file manager window */
-                       if (!Globals.hwndParent)
-                               PostQuitMessage(0);
+                       PostQuitMessage(0);
                        break;
 
+               case WM_INITMENUPOPUP: {
+                       HWND hwndClient = (HWND) SendMessage(Globals.hmdiclient, WM_MDIGETACTIVE, 0, 0);
+
+                       if (!SendMessage(hwndClient, WM_INITMENUPOPUP, wparam, lparam))
+                               return 0;
+                       break;}
+
                case WM_COMMAND: {
                        UINT cmd = LOWORD(wparam);
                        HWND hwndClient = (HWND) SendMessage(Globals.hmdiclient, WM_MDIGETACTIVE, 0, 0);
@@ -1898,6 +2204,10 @@ LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam
                                                free(child);
                                        break;}
 
+                               case ID_REFRESH:
+                                       refresh_drives();
+                                       break;
+
                                case ID_WINDOW_CASCADE:
                                        SendMessage(Globals.hmdiclient, WM_MDICASCADE, 0, 0);
                                        break;
@@ -1937,14 +2247,16 @@ LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam
 
                                        if (ChooseFont(&chFont)) {
                                                HWND childWnd;
+                                               HFONT hFontOld;
 
+                                               DeleteObject(Globals.hfont);
                                                Globals.hfont = CreateFontIndirect(&lFont);
-                                               SelectFont(hdc, Globals.hfont);
+                                               hFontOld = SelectFont(hdc, Globals.hfont);
                                                GetTextExtentPoint32(hdc, sSpace, 1, &Globals.spaceSize);
 
                                                /* change font in all open child windows */
                                                for(childWnd=GetWindow(Globals.hmdiclient,GW_CHILD); childWnd; childWnd=GetNextWindow(childWnd,GW_HWNDNEXT)) {
-                                                       ChildWnd* child = (ChildWnd*) GetWindowLong(childWnd, GWL_USERDATA);
+                                                       ChildWnd* child = (ChildWnd*) GetWindowLongPtr(childWnd, GWLP_USERDATA);
                                                        SetWindowFont(child->left.hwnd, Globals.hfont, TRUE);
                                                        SetWindowFont(child->right.hwnd, Globals.hfont, TRUE);
                                                        ListBox_SetItemHeight(child->left.hwnd, 1, max(Globals.spaceSize.cy,IMAGE_HEIGHT+3));
@@ -1952,6 +2264,8 @@ LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam
                                                        InvalidateRect(child->left.hwnd, NULL, TRUE);
                                                        InvalidateRect(child->right.hwnd, NULL, TRUE);
                                                }
+
+                                               SelectFont(hdc, hFontOld);
                                        }
                                        else if (CommDlgExtendedError()) {
                                                LoadString(Globals.hInstance, IDS_FONT_SEL_DLG_NAME, dlg_name, BUFFER_LEN);
@@ -1988,6 +2302,39 @@ LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam
                                        }
                                        break;}
 
+                               case ID_CONNECT_NETWORK_DRIVE: {
+                                       DWORD ret = WNetConnectionDialog(hwnd, RESOURCETYPE_DISK);
+                                       if (ret == NO_ERROR)
+                                               refresh_drives();
+                                       else if (ret != (DWORD)-1) {
+                                               if (ret == ERROR_EXTENDED_ERROR)
+                                                       display_network_error(hwnd);
+                                               else
+                                                       display_error(hwnd, ret);
+                                       }
+                                       break;}
+
+                               case ID_DISCONNECT_NETWORK_DRIVE: {
+                                       DWORD ret = WNetDisconnectDialog(hwnd, RESOURCETYPE_DISK);
+                                       if (ret == NO_ERROR)
+                                               refresh_drives();
+                                       else if (ret != (DWORD)-1) {
+                                               if (ret == ERROR_EXTENDED_ERROR)
+                                                       display_network_error(hwnd);
+                                               else
+                                                       display_error(hwnd, ret);
+                                       }
+                                       break;}
+
+#ifndef __MINGW32__    /* SHFormatDrive missing in MinGW (as of 13.5.2005) */
+                               case ID_FORMAT_DISK: {
+                                       UINT sem_org = SetErrorMode(0); /* Get the current Error Mode settings. */
+                                       SetErrorMode(sem_org & ~SEM_FAILCRITICALERRORS); /* Force O/S to handle */
+                                       SHFormatDrive(hwnd, 0 /* A: */, SHFMT_ID_DEFAULT, 0);
+                                       SetErrorMode(sem_org); /* Put it back the way it was. */
+                                       break;}
+#endif
+
                                case ID_HELP:
                                        WinHelp(hwnd, RS(b1,IDS_WINEFILE), HELP_INDEX, 0);
                                        break;
@@ -2008,12 +2355,12 @@ LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam
                                        if (activate_fs_window(RS(b1,IDS_UNIXFS)))
                                                break;
 
-       
+
 #ifdef UNICODE
-                                       call_getcwd(cpath, MAX_PATH);
+                                       getcwd(cpath, MAX_PATH);
                                        MultiByteToWideChar(CP_UNIXCP, 0, cpath, -1, path, MAX_PATH);
 #else
-                                       call_getcwd(path, MAX_PATH);
+                                       getcwd(path, MAX_PATH);
 #endif
                                        child = alloc_child_window(path, NULL, hwnd);
 
@@ -2050,11 +2397,11 @@ LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam
                                case ID_NO_WARRANTY:
                                        WineWarranty(Globals.hMainWnd);
                                        break;
-#endif
 
                                case ID_ABOUT_WINE:
                                        ShellAbout(hwnd, RS(b2,IDS_WINE), RS(b1,IDS_WINEFILE), 0);
                                        break;
+#endif
 
                                case ID_ABOUT:
                                        ShellAbout(hwnd, RS(b1,IDS_WINEFILE), NULL, 0);
@@ -2205,7 +2552,7 @@ static void init_output(HWND hwnd)
 static void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWidthCol);
 
 
-/* calculate prefered width for all visible columns */
+/* calculate preferred width for all visible columns */
 
 static BOOL calc_widths(Pane* pane, BOOL anyway)
 {
@@ -2292,7 +2639,7 @@ static BOOL calc_widths(Pane* pane, BOOL anyway)
 }
 
 
-/* calculate one prefered column width */
+/* calculate one preferred column width */
 
 static void calc_single_width(Pane* pane, int col)
 {
@@ -2352,14 +2699,63 @@ static void calc_single_width(Pane* pane, int col)
 }
 
 
+static BOOL pattern_match(LPCTSTR str, LPCTSTR pattern)
+{
+       for( ; *str&&*pattern; str++,pattern++) {
+               if (*pattern == '*') {
+                       do pattern++;
+                       while(*pattern == '*');
+
+                       if (!*pattern)
+                               return TRUE;
+
+                       for(; *str; str++)
+                               if (*str==*pattern && pattern_match(str, pattern))
+                                       return TRUE;
+
+                       return FALSE;
+               }
+               else if (*str!=*pattern && *pattern!='?')
+                       return FALSE;
+       }
+
+       if (*str || *pattern)
+               if (*pattern!='*' || pattern[1]!='\0')
+                       return FALSE;
+
+       return TRUE;
+}
+
+static BOOL pattern_imatch(LPCTSTR str, LPCTSTR pattern)
+{
+       TCHAR b1[BUFFER_LEN], b2[BUFFER_LEN];
+
+       lstrcpy(b1, str);
+       lstrcpy(b2, pattern);
+       CharUpper(b1);
+       CharUpper(b2);
+
+       return pattern_match(b1, b2);
+}
+
+
+enum FILE_TYPE {
+       FT_OTHER                = 0,
+       FT_EXECUTABLE   = 1,
+       FT_DOCUMENT             = 2
+};
+
+static enum FILE_TYPE get_file_type(LPCTSTR filename);
+
+
 /* insert listbox entries after index idx */
 
-static void insert_entries(Pane* pane, Entry* dir, int idx)
+static int insert_entries(Pane* pane, Entry* dir, LPCTSTR pattern, int filter_flags, int idx)
 {
        Entry* entry = dir;
 
        if (!entry)
-               return;
+               return idx;
 
        ShowWindow(pane->hwnd, SW_HIDE);
 
@@ -2369,32 +2765,109 @@ static void insert_entries(Pane* pane, Entry* dir, int idx)
                        continue;
 #endif
 
-               /* don't display entries "." and ".." in the left pane */
-               if (pane->treePane && (entry->data.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
-                               && entry->data.cFileName[0]==TEXT('.'))
-                       if (
-#ifndef _NO_EXTENSIONS
-                               entry->data.cFileName[1]==TEXT('\0') ||
-#endif
-                               (entry->data.cFileName[1]==TEXT('.') && entry->data.cFileName[2]==TEXT('\0')))
+               if (entry->data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+                       /* don't display entries "." and ".." in the left pane */
+                       if (pane->treePane && entry->data.cFileName[0]==TEXT('.'))
+                               if (
+       #ifndef _NO_EXTENSIONS
+                                       entry->data.cFileName[1]==TEXT('\0') ||
+       #endif
+                                       (entry->data.cFileName[1]==TEXT('.') && entry->data.cFileName[2]==TEXT('\0')))
+                                       continue;
+
+                       /* filter directories in right pane */
+                       if (!pane->treePane && !(filter_flags&TF_DIRECTORIES))
+                               continue;
+               }
+
+               /* filter using the file name pattern */
+               if (pattern)
+                       if (!pattern_imatch(entry->data.cFileName, pattern))
                                continue;
 
+               /* filter system and hidden files */
+               if (!(filter_flags&TF_HIDDEN) && (entry->data.dwFileAttributes&(FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)))
+                       continue;
+
+               /* filter looking at the file type */
+               if ((filter_flags&(TF_PROGRAMS|TF_DOCUMENTS|TF_OTHERS)) != (TF_PROGRAMS|TF_DOCUMENTS|TF_OTHERS))
+                       switch(get_file_type(entry->data.cFileName)) {
+                         case FT_EXECUTABLE:
+                               if (!(filter_flags & TF_PROGRAMS))
+                                       continue;
+                               break;
+
+                         case FT_DOCUMENT:
+                               if (!(filter_flags & TF_DOCUMENTS))
+                                       continue;
+                               break;
+
+                         default: /* TF_OTHERS */
+                               if (!(filter_flags & TF_OTHERS))
+                                       continue;
+                       }
+
                if (idx != -1)
                        idx++;
 
                ListBox_InsertItemData(pane->hwnd, idx, entry);
 
                if (pane->treePane && entry->expanded)
-                       insert_entries(pane, entry->down, idx);
+                       idx = insert_entries(pane, entry->down, pattern, filter_flags, idx);
        }
 
        ShowWindow(pane->hwnd, SW_SHOW);
+
+       return idx;
+}
+
+
+static void format_bytes(LPTSTR buffer, LONGLONG bytes)
+{
+       const static TCHAR sFmtGB[] = {'%', '.', '1', 'f', ' ', 'G', 'B', '\0'};
+       const static TCHAR sFmtMB[] = {'%', '.', '1', 'f', ' ', 'M', 'B', '\0'};
+       const static TCHAR sFmtkB[] = {'%', '.', '1', 'f', ' ', 'k', 'B', '\0'};
+
+       float fBytes = (float)bytes;
+
+#ifdef __WINE__        /* work around for incorrect implementation of wsprintf()/_stprintf() in WINE */
+       if (bytes >= 1073741824)        /* 1 GB */
+               wsprintf(buffer, sFmtGB, fBytes/1073741824.f+.5f);
+       else if (bytes >= 1048576)      /* 1 MB */
+               wsprintf(buffer, sFmtMB, fBytes/1048576.f+.5f);
+       else if (bytes >= 1024)         /* 1 kB */
+               wsprintf(buffer, sFmtkB, fBytes/1024.f+.5f);
+#else
+       if (bytes >= 1073741824)        /* 1 GB */
+               _stprintf(buffer, sFmtGB, fBytes/1073741824.f+.5f);
+       else if (bytes >= 1048576)      /* 1 MB */
+               _stprintf(buffer, sFmtMB, fBytes/1048576.f+.5f);
+       else if (bytes >= 1024)         /* 1 kB */
+               _stprintf(buffer, sFmtkB, fBytes/1024.f+.5f);
+#endif
+       else
+               _stprintf(buffer, sLongNumFmt, bytes);
+}
+
+static void set_space_status(void)
+{
+       ULARGE_INTEGER ulFreeBytesToCaller, ulTotalBytes, ulFreeBytes;
+       TCHAR fmt[64], b1[64], b2[64], buffer[BUFFER_LEN];
+
+       if (GetDiskFreeSpaceEx(NULL, &ulFreeBytesToCaller, &ulTotalBytes, &ulFreeBytes)) {
+               format_bytes(b1, ulFreeBytesToCaller.QuadPart);
+               format_bytes(b2, ulTotalBytes.QuadPart);
+               wsprintf(buffer, RS(fmt,IDS_FREE_SPACE_FMT), b1, b2);
+       } else
+               lstrcpy(buffer, sQMarks);
+
+       SendMessage(Globals.hstatusbar, SB_SETTEXT, 0, (LPARAM)buffer);
 }
 
 
 static WNDPROC g_orgTreeWndProc;
 
-static void create_tree_window(HWND parent, Pane* pane, int id, int id_header)
+static void create_tree_window(HWND parent, Pane* pane, int id, int id_header, LPCTSTR pattern, int filter_flags)
 {
        const static TCHAR sListBox[] = {'L','i','s','t','B','o','x','\0'};
 
@@ -2405,14 +2878,14 @@ static void create_tree_window(HWND parent, Pane* pane, int id, int id_header)
                                                                LBS_DISABLENOSCROLL|LBS_NOINTEGRALHEIGHT|LBS_OWNERDRAWFIXED|LBS_NOTIFY,
                                                                0, 0, 0, 0, parent, (HMENU)id, Globals.hInstance, 0);
 
-       SetWindowLong(pane->hwnd, GWL_USERDATA, (LPARAM)pane);
+       SetWindowLongPtr(pane->hwnd, GWLP_USERDATA, (LPARAM)pane);
        g_orgTreeWndProc = SubclassWindow(pane->hwnd, TreeWndProc);
 
        SetWindowFont(pane->hwnd, Globals.hfont, FALSE);
 
        /* insert entries into listbox */
        if (entry)
-               insert_entries(pane, entry, -1);
+               insert_entries(pane, entry, pattern, filter_flags, -1);
 
        /* calculate column widths */
        if (!s_init) {
@@ -2430,8 +2903,8 @@ static void create_tree_window(HWND parent, Pane* pane, int id, int id_header)
 
 static void InitChildWindow(ChildWnd* child)
 {
-       create_tree_window(child->hwnd, &child->left, IDW_TREE_LEFT, IDW_HEADER_LEFT);
-       create_tree_window(child->hwnd, &child->right, IDW_TREE_RIGHT, IDW_HEADER_RIGHT);
+       create_tree_window(child->hwnd, &child->left, IDW_TREE_LEFT, IDW_HEADER_LEFT, NULL, TF_ALL);
+       create_tree_window(child->hwnd, &child->right, IDW_TREE_RIGHT, IDW_HEADER_RIGHT, child->filter_pattern, child->filter_flags);
 }
 
 
@@ -2447,7 +2920,7 @@ static void format_date(const FILETIME* ft, TCHAR* buffer, int visible_cols)
                return;
 
        if (!FileTimeToLocalFileTime(ft, &lft))
-               {err: _tcscpy(buffer,sQMarks); return;}
+               {err: lstrcpy(buffer,sQMarks); return;}
 
        if (!FileTimeToSystemTime(&lft, &systime))
                goto err;
@@ -2556,7 +3029,7 @@ static void output_number(Pane* pane, LPDRAWITEMSTRUCT dis, int col, LPCTSTR str
 }
 
 
-static int is_exe_file(LPCTSTR ext)
+static BOOL is_exe_file(LPCTSTR ext)
 {
        static const TCHAR executable_extensions[][4] = {
                {'C','O','M','\0'},
@@ -2580,17 +3053,33 @@ static int is_exe_file(LPCTSTR ext)
                d++;
 
        for(p=executable_extensions; (*p)[0]; p++)
-               if (!_tcscmp(ext_buffer, *p))
-                       return 1;
+               if (!lstrcmpi(ext_buffer, *p))
+                       return TRUE;
 
-       return 0;
+       return FALSE;
 }
 
-static int is_registered_type(LPCTSTR ext)
+static BOOL is_registered_type(LPCTSTR ext)
 {
-        /* TODO */
+       /* check if there exists a classname for this file extension in the registry */
+       if (!RegQueryValue(HKEY_CLASSES_ROOT, ext, NULL, NULL))
+               return TRUE;
+
+       return FALSE;
+}
 
-       return 1;
+static enum FILE_TYPE get_file_type(LPCTSTR filename)
+{
+       LPCTSTR ext = _tcsrchr(filename, '.');
+       if (!ext)
+               ext = sEmpty;
+
+       if (is_exe_file(ext))
+               return FT_EXECUTABLE;
+       else if (is_registered_type(ext))
+               return FT_DOCUMENT;
+       else
+               return FT_OTHER;
 }
 
 
@@ -2626,16 +3115,11 @@ static void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWi
                        else
                                img = IMG_FOLDER;
                } else {
-                       LPCTSTR ext = _tcsrchr(entry->data.cFileName, '.');
-                       if (!ext)
-                               ext = sEmpty;
-
-                       if (is_exe_file(ext))
-                               img = IMG_EXECUTABLE;
-                       else if (is_registered_type(ext))
-                               img = IMG_DOCUMENT;
-                       else
-                               img = IMG_FILE;
+                       switch(get_file_type(entry->data.cFileName)) {
+                         case FT_EXECUTABLE:   img = IMG_EXECUTABLE;   break;
+                         case FT_DOCUMENT:             img = IMG_DOCUMENT;             break;
+                         default:                              img = IMG_FILE;
+                       }
                }
        } else {
                attrs = 0;
@@ -2702,12 +3186,6 @@ static void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWi
                                        )
                                        LineTo(dis->hDC, x, dis->rcItem.bottom);
 
-                               if (entry->down && entry->expanded) {
-                                       x += IMAGE_WIDTH+TREE_LINE_DX;
-                                       MoveToEx(dis->hDC, x, dis->rcItem.top+IMAGE_HEIGHT, 0);
-                                       LineTo(dis->hDC, x, dis->rcItem.bottom);
-                               }
-
                                SelectClipRgn(dis->hDC, hrgn_org);
                                if (hrgn_org) DeleteObject(hrgn_org);
                                /* SelectObject(dis->hDC, holdPen); */
@@ -2747,10 +3225,10 @@ static void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWi
                        textcolor = RGB(0,0,0);
 
                if (dis->itemState & ODS_FOCUS) {
-                       textcolor = RGB(255,255,255);
+                       textcolor = COLOR_SELECTION_TXT;
                        bkcolor = COLOR_SELECTION;
                } else {
-                       bkcolor = RGB(255,255,255);
+                       bkcolor = GetSysColor(COLOR_WINDOW);
                }
 
                hbrush = CreateSolidBrush(bkcolor);
@@ -2879,10 +3357,10 @@ static void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWi
        if (visible_cols & COL_ATTRIBUTES) {
 #ifdef _NO_EXTENSIONS
                const static TCHAR s4Tabs[] = {' ','\t',' ','\t',' ','\t',' ','\t',' ','\0'};
-               _tcscpy(buffer, s4Tabs);
+               lstrcpy(buffer, s4Tabs);
 #else
                const static TCHAR s11Tabs[] = {' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\0'};
-               _tcscpy(buffer, s11Tabs);
+               lstrcpy(buffer, s11Tabs);
 #endif
 
                if (attrs & FILE_ATTRIBUTE_NORMAL)                                      buffer[ 0] = 'N';
@@ -2924,7 +3402,7 @@ static void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWi
 
                DWORD rights = get_access_mask();
 
-               tcscpy(buffer, sSecTabs);
+               lstrcpy(buffer, sSecTabs);
 
                if (rights & FILE_READ_DATA)                    buffer[ 0] = 'R';
                if (rights & FILE_WRITE_DATA)                   buffer[ 2] = 'W';
@@ -2959,7 +3437,7 @@ static void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWi
                HPEN lastPen;
                HPEN hpen;
 
-               if (!(GetVersion() & 0x80000000)) {     /* Windows NT? */
+               if (!(GetVersion() & 0x80000000)) {     /* Windows NT or higher? */
                        LOGBRUSH lb = {PS_SOLID, RGB(255,255,255)};
                        hpen = ExtCreatePen(PS_COSMETIC|PS_ALTERNATE, 1, &lb, 0, 0);
                } else
@@ -3100,10 +3578,9 @@ static LRESULT pane_notify(Pane* pane, NMHDR* pnmh)
 #endif /* _NO_EXTENSIONS */
 
 
-static void scan_entry(ChildWnd* child, Entry* entry, HWND hwnd)
+static void scan_entry(ChildWnd* child, Entry* entry, int idx, HWND hwnd)
 {
        TCHAR path[MAX_PATH];
-       int idx = ListBox_GetCurSel(child->left.hwnd);
        HCURSOR old_cursor = SetCursor(LoadCursor(0, IDC_WAIT));
 
        /* delete sub entries in left pane */
@@ -3137,7 +3614,7 @@ static void scan_entry(ChildWnd* child, Entry* entry, HWND hwnd)
        }
 
        /* insert found entries in right pane */
-       insert_entries(&child->right, entry->down, -1);
+       insert_entries(&child->right, entry->down, child->filter_pattern, child->filter_flags, -1);
        calc_widths(&child->right, FALSE);
 #ifndef _NO_EXTENSIONS
        set_header(&child->right);
@@ -3178,7 +3655,7 @@ static BOOL expand_entry(ChildWnd* child, Entry* dir)
        dir->expanded = TRUE;
 
        /* insert entries in left pane */
-       insert_entries(&child->left, p, idx);
+       insert_entries(&child->left, p, NULL, TF_ALL, idx);
 
        if (!child->header_wdths_ok) {
                if (calc_widths(&child->left, FALSE)) {
@@ -3217,26 +3694,35 @@ static void collapse_entry(Pane* pane, Entry* dir)
 }
 
 
-static void set_curdir(ChildWnd* child, Entry* entry, HWND hwnd)
+static void refresh_right_pane(ChildWnd* child)
+{
+       ListBox_ResetContent(child->right.hwnd);
+       insert_entries(&child->right, child->right.root, child->filter_pattern, child->filter_flags, -1);
+       calc_widths(&child->right, FALSE);
+
+#ifndef _NO_EXTENSIONS
+       set_header(&child->right);
+#endif
+}
+
+static void set_curdir(ChildWnd* child, Entry* entry, int idx, HWND hwnd)
 {
        TCHAR path[MAX_PATH];
 
+       if (!entry)
+               return;
+
        path[0] = '\0';
 
        child->left.cur = entry;
+
        child->right.root = entry->down? entry->down: entry;
        child->right.cur = entry;
 
        if (!entry->scanned)
-               scan_entry(child, entry, hwnd);
-       else {
-               ListBox_ResetContent(child->right.hwnd);
-               insert_entries(&child->right, entry->down, -1);
-               calc_widths(&child->right, FALSE);
-#ifndef _NO_EXTENSIONS
-               set_header(&child->right);
-#endif
-       }
+               scan_entry(child, entry, idx, hwnd);
+       else
+               refresh_right_pane(child);
 
        get_path(entry, path);
        lstrcpy(child->path, path);
@@ -3245,26 +3731,129 @@ static void set_curdir(ChildWnd* child, Entry* entry, HWND hwnd)
                SetWindowText(child->hwnd, path);
 
        if (path[0])
-               SetCurrentDirectory(path);
+               if (SetCurrentDirectory(path))
+                       set_space_status();
 }
 
 
-BOOL launch_file(HWND hwnd, LPCTSTR cmd, UINT nCmdShow)
+static void refresh_child(ChildWnd* child)
 {
-       HINSTANCE hinst = ShellExecute(hwnd, NULL/*operation*/, cmd, NULL/*parameters*/, NULL/*dir*/, nCmdShow);
+       TCHAR path[MAX_PATH], drv[_MAX_DRIVE+1];
+       Entry* entry;
+       int idx;
 
-       if ((int)hinst <= 32) {
-               display_error(hwnd, GetLastError());
-               return FALSE;
+       get_path(child->left.cur, path);
+       _tsplitpath(path, drv, NULL, NULL, NULL);
+
+       child->right.root = NULL;
+
+       scan_entry(child, &child->root.entry, 0, child->hwnd);
+
+#ifdef _SHELL_FOLDERS
+       if (child->root.entry.etype == ET_SHELL)
+               entry = read_tree(&child->root, NULL, get_path_pidl(path,child->hwnd), drv, child->sortOrder, child->hwnd);
+       else
+#endif
+               entry = read_tree(&child->root, path, NULL, drv, child->sortOrder, child->hwnd);
+
+       if (!entry)
+               entry = &child->root.entry;
+
+       insert_entries(&child->left, child->root.entry.down, NULL, TF_ALL, 0);
+
+       set_curdir(child, entry, 0, child->hwnd);
+
+       idx = ListBox_FindItemData(child->left.hwnd, 0, child->left.cur);
+       ListBox_SetCurSel(child->left.hwnd, idx);
+}
+
+
+static void create_drive_bar(void)
+{
+       TBBUTTON drivebarBtn = {0, 0, TBSTATE_ENABLED, BTNS_BUTTON, {0, 0}, 0, 0};
+#ifndef _NO_EXTENSIONS
+       TCHAR b1[BUFFER_LEN];
+#endif
+       int btn = 1;
+       PTSTR p;
+
+       GetLogicalDriveStrings(BUFFER_LEN, Globals.drives);
+
+       Globals.hdrivebar = CreateToolbarEx(Globals.hMainWnd, WS_CHILD|WS_VISIBLE|CCS_NOMOVEY|TBSTYLE_LIST,
+                               IDW_DRIVEBAR, 2, Globals.hInstance, IDB_DRIVEBAR, &drivebarBtn,
+                               0, 16, 13, 16, 13, sizeof(TBBUTTON));
+
+#ifndef _NO_EXTENSIONS
+#ifdef __WINE__
+       /* insert unix file system button */
+       b1[0] = '/';
+       b1[1] = '\0';
+       b1[2] = '\0';
+       SendMessage(Globals.hdrivebar, TB_ADDSTRING, 0, (LPARAM)b1);
+
+       drivebarBtn.idCommand = ID_DRIVE_UNIX_FS;
+       SendMessage(Globals.hdrivebar, TB_INSERTBUTTON, btn++, (LPARAM)&drivebarBtn);
+       drivebarBtn.iString++;
+#endif
+#ifdef _SHELL_FOLDERS
+       /* insert shell namespace button */
+       load_string(b1, IDS_SHELL);
+       b1[lstrlen(b1)+1] = '\0';
+       SendMessage(Globals.hdrivebar, TB_ADDSTRING, 0, (LPARAM)b1);
+
+       drivebarBtn.idCommand = ID_DRIVE_SHELL_NS;
+       SendMessage(Globals.hdrivebar, TB_INSERTBUTTON, btn++, (LPARAM)&drivebarBtn);
+       drivebarBtn.iString++;
+#endif
+
+       /* register windows drive root strings */
+       SendMessage(Globals.hdrivebar, TB_ADDSTRING, 0, (LPARAM)Globals.drives);
+#endif
+
+       drivebarBtn.idCommand = ID_DRIVE_FIRST;
+
+       for(p=Globals.drives; *p; ) {
+#ifdef _NO_EXTENSIONS
+               /* insert drive letter */
+               TCHAR b[3] = {tolower(*p)};
+               SendMessage(Globals.hdrivebar, TB_ADDSTRING, 0, (LPARAM)b);
+#endif
+               switch(GetDriveType(p)) {
+                       case DRIVE_REMOVABLE:   drivebarBtn.iBitmap = 1;        break;
+                       case DRIVE_CDROM:               drivebarBtn.iBitmap = 3;        break;
+                       case DRIVE_REMOTE:              drivebarBtn.iBitmap = 4;        break;
+                       case DRIVE_RAMDISK:             drivebarBtn.iBitmap = 5;        break;
+                       default:/*DRIVE_FIXED*/ drivebarBtn.iBitmap = 2;
+               }
+
+               SendMessage(Globals.hdrivebar, TB_INSERTBUTTON, btn++, (LPARAM)&drivebarBtn);
+               drivebarBtn.idCommand++;
+               drivebarBtn.iString++;
+
+               while(*p++);
        }
+}
 
-       return TRUE;
+static void refresh_drives(void)
+{
+       RECT rect;
+
+       /* destroy drive bar */
+       DestroyWindow(Globals.hdrivebar);
+       Globals.hdrivebar = 0;
+
+       /* re-create drive bar */
+       create_drive_bar();
+
+       /* update window layout */
+       GetClientRect(Globals.hMainWnd, &rect);
+       SendMessage(Globals.hMainWnd, WM_SIZE, 0, MAKELONG(rect.right, rect.bottom));
 }
 
-#ifdef UNICODE
-BOOL launch_fileA(HWND hwnd, LPSTR cmd, UINT nCmdShow)
+
+static BOOL launch_file(HWND hwnd, LPCTSTR cmd, UINT nCmdShow)
 {
-       HINSTANCE hinst = ShellExecuteA(hwnd, NULL/*operation*/, cmd, NULL/*parameters*/, NULL/*dir*/, nCmdShow);
+       HINSTANCE hinst = ShellExecute(hwnd, NULL/*operation*/, cmd, NULL/*parameters*/, NULL/*dir*/, nCmdShow);
 
        if ((int)hinst <= 32) {
                display_error(hwnd, GetLastError());
@@ -3273,10 +3862,9 @@ BOOL launch_fileA(HWND hwnd, LPSTR cmd, UINT nCmdShow)
 
        return TRUE;
 }
-#endif
 
 
-BOOL launch_entry(Entry* entry, HWND hwnd, UINT nCmdShow)
+static BOOL launch_entry(Entry* entry, HWND hwnd, UINT nCmdShow)
 {
        TCHAR cmd[MAX_PATH];
 
@@ -3302,7 +3890,7 @@ BOOL launch_entry(Entry* entry, HWND hwnd, UINT nCmdShow)
                }
 
                if (shexinfo.lpIDList != entry->pidl)
-                       (*Globals.iMalloc->lpVtbl->Free)(Globals.iMalloc, shexinfo.lpIDList);
+                       IMalloc_Free(Globals.iMalloc, shexinfo.lpIDList);
 
                return ret;
        }
@@ -3326,7 +3914,7 @@ static void activate_entry(ChildWnd* child, Pane* pane, HWND hwnd)
                int scanned_old = entry->scanned;
 
                if (!scanned_old)
-                       scan_entry(child, entry, hwnd);
+                       scan_entry(child, entry, ListBox_GetCurSel(child->left.hwnd), hwnd);
 
 #ifndef _NO_EXTENSIONS
                if (entry->data.cFileName[0]=='.' && entry->data.cFileName[1]=='\0')
@@ -3345,7 +3933,7 @@ static void activate_entry(ChildWnd* child, Pane* pane, HWND hwnd)
                        if (!pane->treePane) focus_entry: {
                                int idx = ListBox_FindItemData(child->left.hwnd, ListBox_GetCurSel(child->left.hwnd), entry);
                                ListBox_SetCurSel(child->left.hwnd, idx);
-                               set_curdir(child, entry, hwnd);
+                               set_curdir(child, entry, idx, hwnd);
                        }
                }
 
@@ -3357,7 +3945,10 @@ static void activate_entry(ChildWnd* child, Pane* pane, HWND hwnd)
 #endif
                }
        } else {
-               launch_entry(entry, child->hwnd, SW_SHOWNORMAL);
+               if (GetKeyState(VK_MENU) < 0)
+                       show_properties_dlg(entry, child->hwnd);
+               else
+                       launch_entry(entry, child->hwnd, SW_SHOWNORMAL);
        }
 }
 
@@ -3394,7 +3985,7 @@ static BOOL pane_command(Pane* pane, UINT cmd)
                        break;
 
 #ifndef _NO_EXTENSIONS
-               case ID_PREFERED_SIZES: {
+               case ID_PREFERRED_SIZES: {
                        calc_widths(pane, TRUE);
                        set_header(pane);
                        InvalidateRect(pane->hwnd, 0, TRUE);
@@ -3411,52 +4002,176 @@ static BOOL pane_command(Pane* pane, UINT cmd)
 }
 
 
+static void set_sort_order(ChildWnd* child, SORT_ORDER sortOrder)
+{
+       if (child->sortOrder != sortOrder) {
+               child->sortOrder = sortOrder;
+               refresh_child(child);
+       }
+}
+
+static void update_view_menu(ChildWnd* child)
+{
+       CheckMenuItem(Globals.hMenuView, ID_VIEW_SORT_NAME, child->sortOrder==SORT_NAME? MF_CHECKED: MF_UNCHECKED);
+       CheckMenuItem(Globals.hMenuView, ID_VIEW_SORT_TYPE, child->sortOrder==SORT_EXT? MF_CHECKED: MF_UNCHECKED);
+       CheckMenuItem(Globals.hMenuView, ID_VIEW_SORT_SIZE, child->sortOrder==SORT_SIZE? MF_CHECKED: MF_UNCHECKED);
+       CheckMenuItem(Globals.hMenuView, ID_VIEW_SORT_DATE, child->sortOrder==SORT_DATE? MF_CHECKED: MF_UNCHECKED);
+}
+
+
+static BOOL is_directory(LPCTSTR target)
+{
+       /*TODO correctly handle UNIX paths */
+       DWORD target_attr = GetFileAttributes(target);
+
+       if (target_attr == INVALID_FILE_ATTRIBUTES)
+               return FALSE;
+
+       return target_attr&FILE_ATTRIBUTE_DIRECTORY? TRUE: FALSE;
+}
+
+static BOOL prompt_target(Pane* pane, LPTSTR source, LPTSTR target)
+{
+       TCHAR path[MAX_PATH];
+       int len;
+
+       get_path(pane->cur, path);
+
+       if (DialogBoxParam(Globals.hInstance, MAKEINTRESOURCE(IDD_SELECT_DESTINATION), pane->hwnd, DestinationDlgProc, (LPARAM)path) != IDOK)
+               return FALSE;
+
+       get_path(pane->cur, source);
+
+       /* convert relative targets to absolute paths */
+       if (path[0]!='/' && path[1]!=':') {
+               get_path(pane->cur->up, target);
+               len = lstrlen(target);
+
+               if (target[len-1]!='\\' && target[len-1]!='/')
+                       target[len++] = '/';
+
+               lstrcpy(target+len, path);
+       } else
+               lstrcpy(target, path);
+
+       /* If the target already exists as directory, create a new target below this. */
+       if (is_directory(path)) {
+               TCHAR fname[_MAX_FNAME], ext[_MAX_EXT];
+               const static TCHAR sAppend[] = {'%','s','/','%','s','%','s','\0'};
+
+               _tsplitpath(source, NULL, NULL, fname, ext);
+
+               wsprintf(target, sAppend, path, fname, ext);
+       }
+
+       return TRUE;
+}
+
+
+static IContextMenu2* s_pctxmenu2 = NULL;
+
+#ifndef __MINGW32__    /* IContextMenu3 missing in MinGW (as of 6.2.2005) */
+static IContextMenu3* s_pctxmenu3 = NULL;
+#endif
+
+static void CtxMenu_reset(void)
+{
+       s_pctxmenu2 = NULL;
+
+#ifndef __MINGW32__    /* IContextMenu3 missing in MinGW (as of 6.2.2005) */
+       s_pctxmenu3 = NULL;
+#endif
+}
+
+static IContextMenu* CtxMenu_query_interfaces(IContextMenu* pcm1)
+{
+       IContextMenu* pcm = NULL;
+
+       CtxMenu_reset();
+
+#ifndef __MINGW32__    /* IContextMenu3 missing in MinGW (as of 6.2.2005) */
+       if (IUnknown_QueryInterface(pcm1, &IID_IContextMenu3, (void**)&pcm) == NOERROR)
+               s_pctxmenu3 = (LPCONTEXTMENU3)pcm;
+       else
+#endif
+       if (IUnknown_QueryInterface(pcm1, &IID_IContextMenu2, (void**)&pcm) == NOERROR)
+               s_pctxmenu2 = (LPCONTEXTMENU2)pcm;
+
+       if (pcm) {
+               IUnknown_Release(pcm1);
+               return pcm;
+       } else
+               return pcm1;
+}
+
+static BOOL CtxMenu_HandleMenuMsg(UINT nmsg, WPARAM wparam, LPARAM lparam)
+{
+#ifndef __MINGW32__    /* IContextMenu3 missing in MinGW (as of 6.2.2005) */
+       if (s_pctxmenu3) {
+               if (SUCCEEDED((*s_pctxmenu3->lpVtbl->HandleMenuMsg)(s_pctxmenu3, nmsg, wparam, lparam)))
+                       return TRUE;
+       }
+#endif
+
+       if (s_pctxmenu2)
+               if (SUCCEEDED((*s_pctxmenu2->lpVtbl->HandleMenuMsg)(s_pctxmenu2, nmsg, wparam, lparam)))
+                       return TRUE;
+
+       return FALSE;
+}
+
+
 static HRESULT ShellFolderContextMenu(IShellFolder* shell_folder, HWND hwndParent, int cidl, LPCITEMIDLIST* apidl, int x, int y)
 {
        IContextMenu* pcm;
+       BOOL executed = FALSE;
 
-       HRESULT hr = (*shell_folder->lpVtbl->GetUIObjectOf)(shell_folder, hwndParent, cidl, apidl, &IID_IContextMenu, NULL, (LPVOID*)&pcm);
+       HRESULT hr = IShellFolder_GetUIObjectOf(shell_folder, hwndParent, cidl, apidl, &IID_IContextMenu, NULL, (LPVOID*)&pcm);
 /*     HRESULT hr = CDefFolderMenu_Create2(dir?dir->_pidl:DesktopFolder(), hwndParent, 1, &pidl, shell_folder, NULL, 0, NULL, &pcm); */
 
        if (SUCCEEDED(hr)) {
                HMENU hmenu = CreatePopupMenu();
 
+               pcm = CtxMenu_query_interfaces(pcm);
+
                if (hmenu) {
                        hr = (*pcm->lpVtbl->QueryContextMenu)(pcm, hmenu, 0, FCIDM_SHVIEWFIRST, FCIDM_SHVIEWLAST, CMF_NORMAL);
 
                        if (SUCCEEDED(hr)) {
                                UINT idCmd = TrackPopupMenu(hmenu, TPM_LEFTALIGN|TPM_RETURNCMD|TPM_RIGHTBUTTON, x, y, 0, hwndParent, NULL);
 
+                               CtxMenu_reset();
+
                                if (idCmd) {
-                                 CMINVOKECOMMANDINFO cmi;
-
-                                 cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
-                                 cmi.fMask = 0;
-                                 cmi.hwnd = hwndParent;
-                                 cmi.lpVerb = (LPCSTR)(INT_PTR)(idCmd - FCIDM_SHVIEWFIRST);
-                                 cmi.lpParameters = NULL;
-                                 cmi.lpDirectory = NULL;
-                                 cmi.nShow = SW_SHOWNORMAL;
-                                 cmi.dwHotKey = 0;
-                                 cmi.hIcon = 0;
-
-                                 hr = (*pcm->lpVtbl->InvokeCommand)(pcm, &cmi);
+                                       CMINVOKECOMMANDINFO cmi;
+
+                                       cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
+                                       cmi.fMask = 0;
+                                       cmi.hwnd = hwndParent;
+                                       cmi.lpVerb = (LPCSTR)(INT_PTR)(idCmd - FCIDM_SHVIEWFIRST);
+                                       cmi.lpParameters = NULL;
+                                       cmi.lpDirectory = NULL;
+                                       cmi.nShow = SW_SHOWNORMAL;
+                                       cmi.dwHotKey = 0;
+                                       cmi.hIcon = 0;
+
+                                       hr = (*pcm->lpVtbl->InvokeCommand)(pcm, &cmi);
+                                       executed = TRUE;
                                }
-                       }
+                       } else
+                               CtxMenu_reset();
                }
 
-               (*pcm->lpVtbl->Release)(pcm);
+               IUnknown_Release(pcm);
        }
 
-       return hr;
+       return FAILED(hr)? hr: executed? S_OK: S_FALSE;
 }
 
 
-LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
+static LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
 {
-       static int last_split;
-
-       ChildWnd* child = (ChildWnd*) GetWindowLong(hwnd, GWL_USERDATA);
+       ChildWnd* child = (ChildWnd*) GetWindowLongPtr(hwnd, GWLP_USERDATA);
        ASSERT(child);
 
        switch(nmsg) {
@@ -3466,8 +4181,10 @@ LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam
 
                        if (dis->CtlID == IDW_TREE_LEFT)
                                draw_item(&child->left, dis, entry, -1);
-                       else
+                       else if (dis->CtlID == IDW_TREE_RIGHT)
                                draw_item(&child->right, dis, entry, -1);
+                       else
+                               goto draw_menu_item;
 
                        return TRUE;}
 
@@ -3477,7 +4194,7 @@ LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam
 
                case WM_NCDESTROY:
                        free_child_window(child);
-                       SetWindowLong(hwnd, GWL_USERDATA, 0);
+                       SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
                        break;
 
                case WM_PAINT: {
@@ -3614,7 +4331,8 @@ LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam
 #endif /* _NO_EXTENSIONS */
 
                case WM_SETFOCUS:
-                       SetCurrentDirectory(child->path);
+                       if (SetCurrentDirectory(child->path))
+                               set_space_status();
                        SetFocus(child->focus_pane? child->right.hwnd: child->left.hwnd);
                        break;
 
@@ -3631,7 +4349,8 @@ LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam
                                        break;}
 
                                case ID_REFRESH:
-                                       scan_entry(child, pane->cur, hwnd);
+                                       refresh_drives();
+                                       refresh_child(child);
                                        break;
 
                                case ID_ACTIVATE:
@@ -3639,41 +4358,87 @@ LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam
                                        break;
 
                                case ID_FILE_MOVE: {
-                                       TCHAR new_name[BUFFER_LEN], old_name[BUFFER_LEN];
-                                       int len;
+                                       TCHAR source[BUFFER_LEN], target[BUFFER_LEN];
 
-                                       int ret = DialogBoxParam(Globals.hInstance, MAKEINTRESOURCE(IDD_SELECT_DESTINATION), hwnd, DestinationDlgProc, (LPARAM)new_name);
-                                       if (ret != IDOK)
-                                               break;
+                                       if (prompt_target(pane, source, target)) {
+                                               SHFILEOPSTRUCT shfo = {hwnd, FO_MOVE, source, target};
 
-                                       if (new_name[0]!='/' && new_name[1]!=':') {
-                                               get_path(pane->cur->up, old_name);
-                                               len = lstrlen(old_name);
+                                               source[lstrlen(source)+1] = '\0';
+                                               target[lstrlen(target)+1] = '\0';
 
-                                               if (old_name[len-1]!='\\' && old_name[len-1]!='/') {
-                                                       old_name[len++] = '/';
-                                                       old_name[len] = '\n';
-                                               }
+                                               if (!SHFileOperation(&shfo))
+                                                       refresh_child(child);
+                                       }
+                                       break;}
+
+                               case ID_FILE_COPY: {
+                                       TCHAR source[BUFFER_LEN], target[BUFFER_LEN];
 
-                                               lstrcpy(&old_name[len], new_name);
-                                               lstrcpy(new_name, old_name);
+                                       if (prompt_target(pane, source, target)) {
+                                               SHFILEOPSTRUCT shfo = {hwnd, FO_COPY, source, target};
+
+                                               source[lstrlen(source)+1] = '\0';
+                                               target[lstrlen(target)+1] = '\0';
+
+                                               if (!SHFileOperation(&shfo))
+                                                       refresh_child(child);
                                        }
+                                       break;}
 
-                                       get_path(pane->cur, old_name);
+                               case ID_FILE_DELETE: {
+                                       TCHAR path[BUFFER_LEN];
+                                       SHFILEOPSTRUCT shfo = {hwnd, FO_DELETE, path};
 
-                                       if (MoveFileEx(old_name, new_name, MOVEFILE_COPY_ALLOWED)) {
-                                               if (pane->treePane) {
-                                                       pane->root->scanned = FALSE;
-                                                       pane->cur = pane->root;
-                                                       activate_entry(child, pane, hwnd);
-                                               }
-                                               else
-                                                       scan_entry(child, pane->root, hwnd);
+                                       get_path(pane->cur, path);
+
+                                       path[lstrlen(path)+1] = '\0';
+
+                                       if (!SHFileOperation(&shfo))
+                                               refresh_child(child);
+                                       break;}
+
+                               case ID_VIEW_SORT_NAME:
+                                       set_sort_order(child, SORT_NAME);
+                                       break;
+
+                               case ID_VIEW_SORT_TYPE:
+                                       set_sort_order(child, SORT_EXT);
+                                       break;
+
+                               case ID_VIEW_SORT_SIZE:
+                                       set_sort_order(child, SORT_SIZE);
+                                       break;
+
+                               case ID_VIEW_SORT_DATE:
+                                       set_sort_order(child, SORT_DATE);
+                                       break;
+
+                               case ID_VIEW_FILTER: {
+                                       struct FilterDialog dlg;
+
+                                       memset(&dlg, 0, sizeof(struct FilterDialog));
+                                       lstrcpy(dlg.pattern, child->filter_pattern);
+                                       dlg.flags = child->filter_flags;
+
+                                       if (DialogBoxParam(Globals.hInstance, MAKEINTRESOURCE(IDD_DIALOG_VIEW_TYPE), hwnd, FilterDialogDlgProc, (LPARAM)&dlg) == IDOK) {
+                                               lstrcpy(child->filter_pattern, dlg.pattern);
+                                               child->filter_flags = dlg.flags;
+                                               refresh_right_pane(child);
                                        }
-                                       else
-                                               display_error(hwnd, GetLastError());
                                        break;}
 
+                               case ID_VIEW_SPLIT: {
+                                       last_split = child->split_pos;
+#ifdef _NO_EXTENSIONS
+                                       draw_splitbar(hwnd, last_split);
+#endif
+                                       SetCapture(hwnd);
+                                       break;}
+
+                               case ID_EDIT_PROPERTIES:
+                                       show_properties_dlg(pane->cur, child->hwnd);
+                                       break;
+
                                default:
                                        return pane_command(pane, LOWORD(wparam));
                        }
@@ -3689,7 +4454,7 @@ LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam
                                        Entry* entry = (Entry*) ListBox_GetItemData(pane->hwnd, idx);
 
                                        if (pane == &child->left)
-                                               set_curdir(child, entry, hwnd);
+                                               set_curdir(child, entry, idx, hwnd);
                                        else
                                                pane->cur = entry;
                                        break;}
@@ -3708,23 +4473,23 @@ LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam
 
 #ifdef _SHELL_FOLDERS
                case WM_CONTEXTMENU: {
+                       POINT pt, pt_clnt;
                        Pane* pane;
                        int idx;
 
                         /* first select the current item in the listbox */
                        HWND hpanel = (HWND) wparam;
-                       POINTS* ppos = &MAKEPOINTS(lparam);
-                       POINT pt; POINTSTOPOINT(pt, *ppos);
-                       ScreenToClient(hpanel, &pt);
-                       SendMessage(hpanel, WM_LBUTTONDOWN, 0, MAKELONG(pt.x, pt.y));
-                       SendMessage(hpanel, WM_LBUTTONUP, 0, MAKELONG(pt.x, pt.y));
+                       pt_clnt.x = pt.x = (short)LOWORD(lparam);
+                       pt_clnt.y = pt.y = (short)HIWORD(lparam);
+                       ScreenToClient(hpanel, &pt_clnt);
+                       SendMessage(hpanel, WM_LBUTTONDOWN, 0, MAKELONG(pt_clnt.x, pt_clnt.y));
+                       SendMessage(hpanel, WM_LBUTTONUP, 0, MAKELONG(pt_clnt.x, pt_clnt.y));
 
                         /* now create the popup menu using shell namespace and IContextMenu */
                        pane = GetFocus()==child->left.hwnd? &child->left: &child->right;
                        idx = ListBox_GetCurSel(pane->hwnd);
 
                        if (idx != -1) {
-                               HRESULT hr;
                                Entry* entry = (Entry*) ListBox_GetItemData(pane->hwnd, idx);
 
                                LPITEMIDLIST pidl_abs = get_to_absolute_pidl(entry, hwnd);
@@ -3735,17 +4500,46 @@ LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam
 
                                         /* get and use the parent folder to display correct context menu in all cases */
                                        if (SUCCEEDED(SHBindToParent(pidl_abs, &IID_IShellFolder, (LPVOID*)&parentFolder, &pidlLast))) {
-                                               hr = ShellFolderContextMenu(parentFolder, hwnd, 1, &pidlLast, ppos->x, ppos->y);
+                                               if (ShellFolderContextMenu(parentFolder, hwnd, 1, &pidlLast, pt.x, pt.y) == S_OK)
+                                                       refresh_child(child);
 
-                                               (*parentFolder->lpVtbl->Release)(parentFolder);
+                                               IShellFolder_Release(parentFolder);
                                        }
 
-                                       (*Globals.iMalloc->lpVtbl->Free)(Globals.iMalloc, pidl_abs);
+                                       IMalloc_Free(Globals.iMalloc, pidl_abs);
                                }
                        }
                        break;}
 #endif
 
+                 case WM_MEASUREITEM:
+                 draw_menu_item:
+                       if (!wparam)    /* Is the message menu-related? */
+                               if (CtxMenu_HandleMenuMsg(nmsg, wparam, lparam))
+                                       return TRUE;
+
+                       break;
+
+                 case WM_INITMENUPOPUP:
+                       if (CtxMenu_HandleMenuMsg(nmsg, wparam, lparam))
+                               return 0;
+
+                       update_view_menu(child);
+                       break;
+
+#ifndef __MINGW32__    /* IContextMenu3 missing in MinGW (as of 6.2.2005) */
+                 case WM_MENUCHAR:     /* only supported by IContextMenu3 */
+                  if (s_pctxmenu3) {
+                          LRESULT lResult = 0;
+
+                          (*s_pctxmenu3->lpVtbl->HandleMenuMsg2)(s_pctxmenu3, nmsg, wparam, lparam, &lResult);
+
+                          return lResult;
+                  }
+
+                  break;
+#endif
+
                case WM_SIZE:
                        if (wparam != SIZE_MINIMIZED)
                                resize_tree(child, LOWORD(lparam), HIWORD(lparam));
@@ -3759,10 +4553,10 @@ LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam
 }
 
 
-LRESULT CALLBACK TreeWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
+static LRESULT CALLBACK TreeWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
 {
-       ChildWnd* child = (ChildWnd*) GetWindowLong(GetParent(hwnd), GWL_USERDATA);
-       Pane* pane = (Pane*) GetWindowLong(hwnd, GWL_USERDATA);
+       ChildWnd* child = (ChildWnd*) GetWindowLongPtr(GetParent(hwnd), GWLP_USERDATA);
+       Pane* pane = (Pane*) GetWindowLongPtr(hwnd, GWLP_USERDATA);
        ASSERT(child);
 
        switch(nmsg) {
@@ -3869,7 +4663,7 @@ static void InitInstance(HINSTANCE hinstance)
 #endif
 
        /* load column strings */
-       col = 0;
+       col = 1;
 
        load_string(g_pos_names[col++], IDS_COL_NAME);
        load_string(g_pos_names[col++], IDS_COL_SIZE);
@@ -3887,11 +4681,11 @@ static void InitInstance(HINSTANCE hinstance)
 }
 
 
-void show_frame(HWND hwndParent, int cmdshow)
+static void show_frame(HWND hwndParent, int cmdshow, LPCTSTR path)
 {
        const static TCHAR sMDICLIENT[] = {'M','D','I','C','L','I','E','N','T','\0'};
 
-       TCHAR path[MAX_PATH], b1[BUFFER_LEN];
+       TCHAR buffer[MAX_PATH], b1[BUFFER_LEN];
        ChildWnd* child;
        HMENU hMenuFrame, hMenuWindow;
 
@@ -3900,8 +4694,6 @@ void show_frame(HWND hwndParent, int cmdshow)
        if (Globals.hMainWnd)
                return;
 
-       Globals.hwndParent = hwndParent;
-
        hMenuFrame = LoadMenu(Globals.hInstance, MAKEINTRESOURCE(IDM_WINEFILE));
        hMenuWindow = GetSubMenu(hMenuFrame, GetMenuItemCount(hMenuFrame)-2);
 
@@ -3925,70 +4717,9 @@ void show_frame(HWND hwndParent, int cmdshow)
                                        Globals.hMainWnd, 0, Globals.hInstance, &ccs);
 
 
-       {
-               TBBUTTON drivebarBtn = {0, 0, TBSTATE_ENABLED, BTNS_SEP, {0, 0}, 0, 0};
-               int btn = 1;
-               PTSTR p;
-
-               Globals.hdrivebar = CreateToolbarEx(Globals.hMainWnd, WS_CHILD|WS_VISIBLE|CCS_NOMOVEY|TBSTYLE_LIST,
-                                       IDW_DRIVEBAR, 2, Globals.hInstance, IDB_DRIVEBAR, &drivebarBtn,
-                                       1, 16, 13, 16, 13, sizeof(TBBUTTON));
-               CheckMenuItem(Globals.hMenuOptions, ID_VIEW_DRIVE_BAR, MF_BYCOMMAND|MF_CHECKED);
-
-               GetLogicalDriveStrings(BUFFER_LEN, Globals.drives);
-
-               drivebarBtn.fsStyle = BTNS_BUTTON;
+       CheckMenuItem(Globals.hMenuOptions, ID_VIEW_DRIVE_BAR, MF_BYCOMMAND|MF_CHECKED);
 
-#ifndef _NO_EXTENSIONS
-#ifdef __WINE__
-               /* insert unix file system button */
-               b1[0] = '/';
-               b1[1] = '\0';
-               b1[2] = '\0';
-               SendMessage(Globals.hdrivebar, TB_ADDSTRING, 0, (LPARAM)b1);
-
-               drivebarBtn.idCommand = ID_DRIVE_UNIX_FS;
-               SendMessage(Globals.hdrivebar, TB_INSERTBUTTON, btn++, (LPARAM)&drivebarBtn);
-               drivebarBtn.iString++;
-#endif
-#ifdef _SHELL_FOLDERS
-               /* insert shell namespace button */
-               load_string(b1, IDS_SHELL);
-               b1[lstrlen(b1)+1] = '\0';
-               SendMessage(Globals.hdrivebar, TB_ADDSTRING, 0, (LPARAM)b1);
-
-               drivebarBtn.idCommand = ID_DRIVE_SHELL_NS;
-               SendMessage(Globals.hdrivebar, TB_INSERTBUTTON, btn++, (LPARAM)&drivebarBtn);
-               drivebarBtn.iString++;
-#endif
-
-               /* register windows drive root strings */
-               SendMessage(Globals.hdrivebar, TB_ADDSTRING, 0, (LPARAM)Globals.drives);
-#endif
-
-               drivebarBtn.idCommand = ID_DRIVE_FIRST;
-
-               for(p=Globals.drives; *p; ) {
-#ifdef _NO_EXTENSIONS
-                       /* insert drive letter */
-                       TCHAR b[3] = {tolower(*p)};
-                       SendMessage(Globals.hdrivebar, TB_ADDSTRING, 0, (LPARAM)b);
-#endif
-                       switch(GetDriveType(p)) {
-                               case DRIVE_REMOVABLE:   drivebarBtn.iBitmap = 1;        break;
-                               case DRIVE_CDROM:               drivebarBtn.iBitmap = 3;        break;
-                               case DRIVE_REMOTE:              drivebarBtn.iBitmap = 4;        break;
-                               case DRIVE_RAMDISK:             drivebarBtn.iBitmap = 5;        break;
-                               default:/*DRIVE_FIXED*/ drivebarBtn.iBitmap = 2;
-                       }
-
-                       SendMessage(Globals.hdrivebar, TB_INSERTBUTTON, btn++, (LPARAM)&drivebarBtn);
-                       drivebarBtn.idCommand++;
-                       drivebarBtn.iString++;
-
-                       while(*p++);
-               }
-       }
+       create_drive_bar();
 
        {
                TBBUTTON toolbarBtns[] = {
@@ -4017,7 +4748,11 @@ void show_frame(HWND hwndParent, int cmdshow)
                                        Globals.hMainWnd, (HMENU)IDW_STATUSBAR, hinstance, 0);*/
 
        /*TODO: read paths and window placements from registry */
-       GetCurrentDirectory(MAX_PATH, path);
+
+       if (!path || !*path) {
+               GetCurrentDirectory(MAX_PATH, buffer);
+               path = buffer;
+       }
 
        ShowWindow(Globals.hMainWnd, cmdshow);
 
@@ -4046,17 +4781,19 @@ void show_frame(HWND hwndParent, int cmdshow)
        UpdateWindow(Globals.hMainWnd);
 }
 
-void ExitInstance()
+static void ExitInstance(void)
 {
 #ifdef _SHELL_FOLDERS
-       (*Globals.iDesktop->lpVtbl->Release)(Globals.iDesktop);
-       (*Globals.iMalloc->lpVtbl->Release)(Globals.iMalloc);
+       IShellFolder_Release(Globals.iDesktop);
+       IMalloc_Release(Globals.iMalloc);
        CoUninitialize();
 #endif
 
+       DeleteObject(Globals.hfont);
        ImageList_Destroy(Globals.himl);
 }
 
+#ifdef _NO_EXTENSIONS
 
 /* search for already running win[e]files */
 
@@ -4077,7 +4814,7 @@ static BOOL CALLBACK EnumWndProc(HWND hwnd, LPARAM lparam)
 }
 
 /* search for window of given class name to allow only one running instance */
-int find_window_class(LPCTSTR classname)
+static int find_window_class(LPCTSTR classname)
 {
        EnumWindows(EnumWndProc, (LPARAM)classname);
 
@@ -4087,8 +4824,9 @@ int find_window_class(LPCTSTR classname)
        return 0;
 }
 
+#endif
 
-int winefile_main(HINSTANCE hinstance, HWND hwndParent, int cmdshow)
+static int winefile_main(HINSTANCE hinstance, int cmdshow, LPCTSTR path)
 {
        MSG msg;
 
@@ -4098,7 +4836,7 @@ int winefile_main(HINSTANCE hinstance, HWND hwndParent, int cmdshow)
                /*TODO: read window placement from registry */
                cmdshow = SW_MAXIMIZE;
 
-       show_frame(hwndParent, cmdshow);
+       show_frame(0, cmdshow, path);
 
        while(GetMessage(&msg, 0, 0, 0)) {
                if (Globals.hmdiclient && TranslateMDISysAccel(Globals.hmdiclient, &msg))
@@ -4117,17 +4855,26 @@ int winefile_main(HINSTANCE hinstance, HWND hwndParent, int cmdshow)
 }
 
 
-int APIENTRY WinMain(HINSTANCE hinstance,
-                                        HINSTANCE previnstance,
-                                        LPSTR     cmdline,
-                                        int       cmdshow)
+#if defined(UNICODE) && defined(_MSC_VER)
+int APIENTRY wWinMain(HINSTANCE hinstance, HINSTANCE previnstance, LPWSTR cmdline, int cmdshow)
+#else
+int APIENTRY WinMain(HINSTANCE hinstance, HINSTANCE previnstance, LPSTR cmdline, int cmdshow)
+#endif
 {
 #ifdef _NO_EXTENSIONS
        if (find_window_class(sWINEFILEFRAME))
                return 1;
 #endif
 
-       winefile_main(hinstance, 0, cmdshow);
+#if defined(UNICODE) && !defined(_MSC_VER)
+       { /* convert ANSI cmdline into WCS path string */
+       TCHAR buffer[MAX_PATH];
+       MultiByteToWideChar(CP_ACP, 0, cmdline, -1, buffer, MAX_PATH);
+       winefile_main(hinstance, cmdshow, buffer);
+       }
+#else
+       winefile_main(hinstance, cmdshow, cmdline);
+#endif
 
        return 0;
 }