- userinit, usetup, vmwinst, welcome, winefile, winlogon, winver.
[reactos.git] / reactos / subsys / system / winefile / winefile.c
index 03667f8..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
  */
 
-#ifndef _WIN32
+#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
 
-#include <locale.h>
+#define COBJMACROS
 
 #include "winefile.h"
-#include "resource.h"
-
-#ifdef _ROS_
-#include "externals.h"
-#endif
 
+#include "resource.h"
 
-/* for read_directory_unix() */
-#if !defined(_NO_EXTENSIONS) && !defined(_WIN32)
-#include <dirent.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <time.h>
-#endif
 
 #ifdef _NO_EXTENSIONS
 #undef _LEFT_FILES
@@ -53,8 +47,8 @@
 #define _MAX_PATH           260
 #endif
 
-#ifdef __linux__
-#define        UNION_MEMBER(x) DUMMYUNIONNAME.##x
+#ifdef NONAMELESSUNION
+#define        UNION_MEMBER(x) DUMMYUNIONNAME.x
 #else
 #define        UNION_MEMBER(x) x
 #endif
 #endif
 
 
-WINEFILE_GLOBALS Globals;
-
-extern void WineLicense(HWND hwnd);
-extern void WineWarranty(HWND hwnd);
-
 enum ENTRY_TYPE {
        ET_WINDOWS,
        ET_UNIX,
@@ -164,38 +153,141 @@ typedef struct {
        BOOL    header_wdths_ok;
 
        TCHAR   path[MAX_PATH];
+       TCHAR   filter_pattern[MAX_PATH];
+       int             filter_flags;
        Root    root;
 
        SORT_ORDER sortOrder;
 } ChildWnd;
 
 
+
 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);
+
+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'};
+const static TCHAR sSpace[] = {' ', '\0'};
+const static TCHAR sNumFmt[] = {'%','d','\0'};
+const static TCHAR sQMarks[] = {'?','?','?','\0'};
+
+/* window class names */
+const static TCHAR sWINEFILEFRAME[] = {'W','F','S','_','F','r','a','m','e','\0'};
+const static TCHAR sWINEFILETREE[] = {'W','F','S','_','T','r','e','e','\0'};
+
+#ifdef _MSC_VER
+/* #define LONGLONGARG _T("I64") */
+const static TCHAR sLongHexFmt[] = {'%','I','6','4','X','\0'};
+const static TCHAR sLongNumFmt[] = {'%','I','6','4','d','\0'};
+#else
+/* #define LONGLONGARG _T("L") */
+const static TCHAR sLongHexFmt[] = {'%','L','X','\0'};
+const static TCHAR sLongNumFmt[] = {'%','L','d','\0'};
+#endif
 
-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);
+
+/* load resource string */
+static LPTSTR load_string(LPTSTR buffer, UINT id)
+{
+       LoadString(Globals.hInstance, id, buffer, BUFFER_LEN);
+
+       return buffer;
+}
+
+#define        RS(b, i) load_string(b, i)
 
 
 /* display error message for the specified WIN32 error code */
 static void display_error(HWND hwnd, DWORD error)
 {
+       TCHAR b1[BUFFER_LEN], b2[BUFFER_LEN];
        PTSTR msg;
 
        if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
                0, error, MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), (PTSTR)&msg, 0, NULL))
-               MessageBox(hwnd, msg, TEXT("Winefile"), MB_OK);
+               MessageBox(hwnd, msg, RS(b2,IDS_WINEFILE), MB_OK);
        else
-               MessageBox(hwnd, TEXT("Error"), TEXT("Winefile"), MB_OK);
+               MessageBox(hwnd, RS(b1,IDS_ERROR), RS(b2,IDS_WINEFILE), MB_OK);
 
        LocalFree(msg);
 }
 
 
+/* 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));
 
@@ -216,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);
@@ -261,12 +353,23 @@ static void read_directory_win(Entry* dir, LPCTSTR path)
        for(p=buffer; *path; )
                *p++ = *path++;
 
-       lstrcpy(p, TEXT("\\*"));
+       *p++ = '\\';
+       p[0] = '*';
+       p[1] = '\0';
 
        hFind = FindFirstFile(buffer, &w32fd);
 
        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)
@@ -282,19 +385,11 @@ 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;
 
-                       lstrcpy(p+1, entry->data.cFileName);
+                       lstrcpy(p, entry->data.cFileName);
 
                        hFile = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
                                                                0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
@@ -308,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);
        }
@@ -386,25 +482,53 @@ static Entry* read_tree_win(Root* root, LPCTSTR path, SORT_ORDER sortOrder, HWND
 }
 
 
-#if !defined(_NO_EXTENSIONS) && defined(__linux__)
+#if !defined(_NO_EXTENSIONS) && defined(__WINE__)
+
+static BOOL time_to_filetime(const time_t* t, FILETIME* ftime)
+{
+       struct tm* tm = gmtime(t);
+       SYSTEMTIME stime;
+
+       if (!tm)
+               return FALSE;
+
+       stime.wYear = tm->tm_year+1900;
+       stime.wMonth = tm->tm_mon+1;
+       /* stime.wDayOfWeek */
+       stime.wDay = tm->tm_mday;
+       stime.wHour = tm->tm_hour;
+       stime.wMinute = tm->tm_min;
+       stime.wSecond = tm->tm_sec;
+
+       return SystemTimeToFileTime(&stime, ftime);
+}
 
 static void read_directory_unix(Entry* dir, LPCTSTR path)
 {
        Entry* first_entry = NULL;
        Entry* last = NULL;
        Entry* entry;
+       DIR* pdir;
 
        int level = dir->level + 1;
+#ifdef UNICODE
+       char cpath[MAX_PATH];
 
-       DIR* pdir = opendir(path);
+       WideCharToMultiByte(CP_UNIXCP, 0, path, -1, cpath, MAX_PATH, NULL, NULL);
+#else
+       const char* cpath = path;
+#endif
+
+       pdir = opendir(cpath);
 
        if (pdir) {
                struct stat st;
                struct dirent* ent;
-               TCHAR buffer[MAX_PATH], *p;
+               char buffer[MAX_PATH], *p;
+               const char* s;
 
-               for(p=buffer; *path; )
-                       *p++ = *path++;
+               for(p=buffer,s=cpath; *s; )
+                       *p++ = *s++;
 
                if (p==buffer || p[-1]!='/')
                        *p++ = '/';
@@ -420,12 +544,16 @@ static void read_directory_unix(Entry* dir, LPCTSTR path)
 
                        entry->etype = ET_UNIX;
 
-                       lstrcpy(entry->data.cFileName, ent->d_name);
-                       entry->data.dwFileAttributes = ent->d_name[0]=='.'? FILE_ATTRIBUTE_HIDDEN: 0;
-
                        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
 
                        if (!stat(buffer, &st)) {
+                               entry->data.dwFileAttributes = p[0]=='.'? FILE_ATTRIBUTE_HIDDEN: 0;
+
                                if (S_ISDIR(st.st_mode))
                                        entry->data.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
 
@@ -457,7 +585,8 @@ static void read_directory_unix(Entry* dir, LPCTSTR path)
                        last = entry;
                }
 
-               last->next = NULL;
+               if (last)
+                       last->next = NULL;
 
                closedir(pdir);
        }
@@ -520,37 +649,33 @@ static Entry* read_tree_unix(Root* root, LPCTSTR path, SORT_ORDER sortOrder, HWN
        return entry;
 }
 
-#endif // !defined(_NO_EXTENSIONS) && defined(__linux__)
+#endif /* !defined(_NO_EXTENSIONS) && defined(__WINE__) */
 
 
 #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--;
@@ -558,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) {
@@ -575,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) {
@@ -592,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);
@@ -615,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)
-{
-       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)
+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);
+        /* SHGDN_FORPARSING: get full path of id list */
+       HRESULT hr = IShellFolder_GetDisplayNameOf(folder, pidl, SHGDN_FORPARSING, &str);
 
        if (SUCCEEDED(hr)) {
                get_strretW(&str, &pidl->mkid, buffer, len);
@@ -663,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;
 
@@ -685,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;
@@ -703,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;
@@ -737,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;
 
@@ -774,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;
 
@@ -795,7 +925,7 @@ static Entry* read_tree_shell(Root* root, LPITEMIDLIST pidl, SORT_ORDER sortOrde
                folder = child;
                entry = next;
 
-                // go to next element
+                /* go to next element */
                pidl = (LPITEMIDLIST) ((LPBYTE)pidl+pidl->mkid.cb);
        }
 
@@ -815,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));
@@ -873,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(;;) {
@@ -885,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;
 
@@ -904,9 +1034,9 @@ static void read_directory_shell(Entry* dir, HWND hwnd)
                                memset(&entry->data, 0, sizeof(WIN32_FIND_DATA));
                                entry->bhfi_valid = FALSE;
 
-                               attribs = ~SFGAO_FILESYSTEM;    //SFGAO_HASSUBFOLDER|SFGAO_FOLDER; SFGAO_FILESYSTEM sorgt dafür, daß "My Documents" anstatt von "Martin's Documents" angezeigt wird
+                               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) {
@@ -921,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;
@@ -958,7 +1088,7 @@ static void read_directory_shell(Entry* dir, HWND hwnd)
                        }
                }
 
-               (*idlist->lpVtbl->Release)(idlist);
+               IEnumIDList_Release(idlist);
        }
 
        if (last)
@@ -968,7 +1098,7 @@ static void read_directory_shell(Entry* dir, HWND hwnd)
        dir->scanned = TRUE;
 }
 
-#endif // _SHELL_FOLDERS
+#endif /* _SHELL_FOLDERS */
 
 
 /* sort order for different directory/file types */
@@ -995,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;
@@ -1010,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)
@@ -1022,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);
@@ -1041,12 +1171,12 @@ static int compareExt(const void* arg1, const void* arg2)
        if (ext1)
                ext1++;
        else
-               ext1 = TEXT("");
+               ext1 = sEmpty;
 
        if (ext2)
                ext2++;
        else
-               ext2 = TEXT("");
+               ext2 = sEmpty;
 
        cmp = lstrcmpi(ext1, ext2);
        if (cmp)
@@ -1055,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)
@@ -1076,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)
@@ -1089,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 */
@@ -1108,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)
@@ -1123,6 +1253,8 @@ static void SortDirectory(Entry* dir, SORT_ORDER sortOrder)
                        p[0]->next = p[1];
 
                (*p)->next = 0;
+
+               HeapFree(GetProcessHeap(), 0, array);
        }
 }
 
@@ -1157,7 +1289,7 @@ static void read_directory(Entry* dir, LPCTSTR path, SORT_ORDER sortOrder, HWND
        }
        else
 #endif
-#if !defined(_NO_EXTENSIONS) && defined(__linux__)
+#if !defined(_NO_EXTENSIONS) && defined(__WINE__)
        if (dir->etype == ET_UNIX)
        {
                read_directory_unix(dir, path);
@@ -1206,9 +1338,74 @@ static void read_directory(Entry* dir, LPCTSTR path, SORT_ORDER sortOrder, HWND
 }
 
 
+static Entry* read_tree(Root* root, LPCTSTR path, LPITEMIDLIST pidl, LPTSTR drv, SORT_ORDER sortOrder, HWND hwnd)
+{
+#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;
        Entry* entry;
@@ -1245,59 +1442,26 @@ static ChildWnd* alloc_child_window(LPCTSTR path, LPITEMIDLIST pidl, HWND hwnd)
                _tsplitpath(path, drv, dir, name, ext);
        }
 
-       root->entry.level = 0;
-
-#ifdef _SHELL_FOLDERS
-       if (pidl)
-       {
-               root->drive_type = DRIVE_UNKNOWN;
-               lstrcpy(drv, TEXT("\\"));
-               lstrcpy(root->volname, TEXT("Desktop"));
-               root->fs_flags = 0;
-               lstrcpy(root->fs, TEXT("Shell"));
-
-               entry = read_tree_shell(root, pidl, child->sortOrder, hwnd);
-       }
-       else
-#endif
-#if !defined(_NO_EXTENSIONS) && defined(__linux__)
-       if (*path == '/')
-       {
-               root->drive_type = GetDriveType(path);
-
-               lstrcat(drv, TEXT("/"));
-               lstrcpy(root->volname, TEXT("root fs"));
-               root->fs_flags = 0;
-               lstrcpy(root->fs, TEXT("unixfs"));
-
-               lstrcpy(root->path, TEXT("/"));
-               entry = read_tree_unix(root, path, child->sortOrder, hwnd);
-       }
-       else
-#endif
-       {
-               root->drive_type = GetDriveType(path);
+       lstrcpy(child->filter_pattern, sAsterics);
+       child->filter_flags = TF_ALL;
 
-               lstrcat(drv, TEXT("\\"));
-               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)
-               lstrcpy(root->entry.data.cFileName, TEXT("Desktop"));
+               load_string(root->entry.data.cFileName, IDS_DESKTOP);
        else
 #endif
-               wsprintf(root->entry.data.cFileName, TEXT("%s - %s"), drv, root->fs);
+               wsprintf(root->entry.data.cFileName, RS(b1,IDS_TITLEFMT), drv, root->fs);
 
        root->entry.data.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
 
        child->left.root = &root->entry;
        child->right.root = NULL;
 
-       set_curdir(child, entry, hwnd);
+       set_curdir(child, entry, 0, hwnd);
 
        return child;
 }
@@ -1329,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;
@@ -1448,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);
@@ -1466,7 +1630,7 @@ static HWND create_child_window(ChildWnd* child)
        MDICREATESTRUCT mcs;
        int idx;
 
-       mcs.szClass = WINEFILETREE;
+       mcs.szClass = sWINEFILETREE;
        mcs.szTitle = (LPTSTR)child->path;
        mcs.hOwner  = Globals.hInstance;
        mcs.x       = child->pos.rcNormalPosition.left;
@@ -1489,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;
@@ -1501,8 +1666,7 @@ struct ExecuteDialog {
        int             cmdshow;
 };
 
-
-static BOOL CALLBACK ExecuteDialogDlgProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
+static INT_PTR CALLBACK ExecuteDialogDlgProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
 {
        static struct ExecuteDialog* dlg;
 
@@ -1528,11 +1692,15 @@ static BOOL CALLBACK ExecuteDialogDlgProc(HWND hwnd, UINT nmsg, WPARAM wparam, L
        return 0;
 }
 
-static BOOL CALLBACK sDestinationDlgProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
+
+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: {
@@ -1540,7 +1708,7 @@ static BOOL CALLBACK sDestinationDlgProc(HWND hwnd, UINT nmsg, WPARAM wparam, LP
 
                        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;}
@@ -1550,7 +1718,7 @@ static BOOL CALLBACK sDestinationDlgProc(HWND hwnd, UINT nmsg, WPARAM wparam, LP
                                break;
 
                          case 254:
-                               MessageBox(hwnd, TEXT("Not yet implemented"), TEXT("Winefile"), MB_OK);
+                               MessageBox(hwnd, RS(b1,IDS_NO_IMPL), RS(b2,IDS_WINEFILE), MB_OK);
                                break;
                        }
 
@@ -1562,6 +1730,240 @@ static BOOL CALLBACK sDestinationDlgProc(HWND hwnd, UINT nmsg, WPARAM wparam, LP
 }
 
 
+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 {
@@ -1574,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;
 
@@ -1675,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;
@@ -1684,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);
@@ -1703,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)) {
@@ -1726,13 +2128,15 @@ 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];
+
        switch(nmsg) {
                case WM_CLOSE:
                        DestroyWindow(hwnd);
 
-                        // clear handle variables
+                        /* clear handle variables */
                        Globals.hMenuFrame = 0;
                        Globals.hMenuView = 0;
                        Globals.hMenuOptions = 0;
@@ -1742,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);
@@ -1795,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;
@@ -1810,7 +2223,7 @@ LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam
                                case ID_WINDOW_ARRANGE:
                                        SendMessage(Globals.hmdiclient, WM_MDIICONARRANGE, 0, 0);
                                        break;
-                                       
+
                                case ID_SELECT_FONT: {
                                        TCHAR dlg_name[BUFFER_LEN], dlg_info[BUFFER_LEN];
                                        CHOOSEFONT chFont;
@@ -1834,19 +2247,25 @@ 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);
-                                               GetTextExtentPoint32(hdc, TEXT(" "), 1, &Globals.spaceSize);
+                                               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));
+                                                       ListBox_SetItemHeight(child->right.hwnd, 1, max(Globals.spaceSize.cy,IMAGE_HEIGHT+3));
                                                        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);
@@ -1883,8 +2302,41 @@ 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, TEXT("winfile"), HELP_INDEX, 0);
+                                       WinHelp(hwnd, RS(b1,IDS_WINEFILE), HELP_INDEX, 0);
                                        break;
 
 #ifndef _NO_EXTENSIONS
@@ -1892,27 +2344,37 @@ LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam
                                        CheckMenuItem(Globals.hMenuOptions, cmd, toggle_fullscreen(hwnd)?MF_CHECKED:0);
                                        break;
 
-#ifdef __linux__
+#ifdef __WINE__
                                case ID_DRIVE_UNIX_FS: {
                                        TCHAR path[MAX_PATH];
+#ifdef UNICODE
+                                       char cpath[MAX_PATH];
+#endif
                                        ChildWnd* child;
 
-                                       if (activate_fs_window(TEXT("unixfs")))
+                                       if (activate_fs_window(RS(b1,IDS_UNIXFS)))
                                                break;
 
+
+#ifdef UNICODE
+                                       getcwd(cpath, MAX_PATH);
+                                       MultiByteToWideChar(CP_UNIXCP, 0, cpath, -1, path, MAX_PATH);
+#else
                                        getcwd(path, MAX_PATH);
+#endif
                                        child = alloc_child_window(path, NULL, hwnd);
 
                                        if (!create_child_window(child))
                                                free(child);
                                        break;}
 #endif
+
 #ifdef _SHELL_FOLDERS
                                case ID_DRIVE_SHELL_NS: {
                                        TCHAR path[MAX_PATH];
                                        ChildWnd* child;
 
-                                       if (activate_fs_window(TEXT("Shell")))
+                                       if (activate_fs_window(RS(b1,IDS_SHELL)))
                                                break;
 
                                        GetCurrentDirectory(MAX_PATH, path);
@@ -1935,23 +2397,23 @@ 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, TEXT("WINE"), TEXT("Winefile"), 0);
+                                       ShellAbout(hwnd, RS(b2,IDS_WINE), RS(b1,IDS_WINEFILE), 0);
                                        break;
+#endif
 
-                               case ID_ABOUT:  //ID_ABOUT_WINE:
-                                       ShellAbout(hwnd, TEXT("Winefile"), NULL, 0);
+                               case ID_ABOUT:
+                                       ShellAbout(hwnd, RS(b1,IDS_WINEFILE), NULL, 0);
                                        break;
-#endif // _NO_EXTENSIONS
+#endif /* _NO_EXTENSIONS */
 
                                default:
                                        /*TODO: if (wParam >= PM_FIRST_LANGUAGE && wParam <= PM_LAST_LANGUAGE)
                                                STRING_SelectLanguageByNumber(wParam - PM_FIRST_LANGUAGE);
                                        else */if ((cmd<IDW_FIRST_CHILD || cmd>=IDW_FIRST_CHILD+0x100) &&
                                                (cmd<SC_SIZE || cmd>SC_RESTORE))
-                                               MessageBox(hwnd, TEXT("Not yet implemented"), TEXT("Winefile"), MB_OK);
+                                               MessageBox(hwnd, RS(b2,IDS_NO_IMPL), RS(b1,IDS_WINEFILE), MB_OK);
 
                                        return DefFrameProc(hwnd, Globals.hmdiclient, nmsg, wparam, lparam);
                        }
@@ -1972,7 +2434,7 @@ LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam
                case FRM_CALC_CLIENT:
                        frame_get_clientspace(hwnd, (PRECT)lparam);
                        return TRUE;
-#endif // _NO_EXTENSIONS
+#endif /* _NO_EXTENSIONS */
 
                default:
                        return DefFrameProc(hwnd, Globals.hmdiclient, nmsg, wparam, lparam);
@@ -1982,21 +2444,8 @@ LRESULT CALLBACK FrameWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam
 }
 
 
-static const LPTSTR g_pos_names[COLUMNS] = {
-       TEXT(""),                       /* symbol */
-       TEXT("Name"),
-       TEXT("Size"),
-       TEXT("CDate"),
-#ifndef _NO_EXTENSIONS
-       TEXT("ADate"),
-       TEXT("MDate"),
-       TEXT("Index/Inode"),
-       TEXT("Links"),
-#endif // _NO_EXTENSIONS
-       TEXT("Attributes"),
-#ifndef _NO_EXTENSIONS
-       TEXT("Security")
-#endif
+static TCHAR g_pos_names[COLUMNS][20] = {
+       {'\0'}  /* symbol */
 };
 
 static const int g_pos_align[] = {
@@ -2043,7 +2492,7 @@ static void resize_tree(ChildWnd* child, int cx, int cy)
                DeferWindowPos(hdwp, child->right.hwndHeader, wp.hwndInsertAfter,
                                                rt.left+cx+1, wp.y, wp.cx-cx+2, wp.cy, wp.flags);
        }
-#endif // _NO_EXTENSIONS
+#endif /* _NO_EXTENSIONS */
 
        DeferWindowPos(hdwp, child->left.hwnd, 0, rt.left, rt.top, child->split_pos-SPLIT_WIDTH/2-rt.left, rt.bottom-rt.top, SWP_NOZORDER|SWP_NOACTIVATE);
        DeferWindowPos(hdwp, child->right.hwnd, 0, rt.left+cx+1, rt.top, rt.right-cx, rt.bottom-rt.top, SWP_NOZORDER|SWP_NOACTIVATE);
@@ -2078,22 +2527,24 @@ static HWND create_header(HWND parent, Pane* pane, int id)
        return hwnd;
 }
 
-#endif // _NO_EXTENSIONS
+#endif /* _NO_EXTENSIONS */
 
 
 static void init_output(HWND hwnd)
 {
+       const static TCHAR s1000[] = {'1','0','0','0','\0'};
+
        TCHAR b[16];
        HFONT old_font;
        HDC hdc = GetDC(hwnd);
 
-       if (GetNumberFormat(LOCALE_USER_DEFAULT, 0, TEXT("1000"), 0, b, 16) > 4)
+       if (GetNumberFormat(LOCALE_USER_DEFAULT, 0, s1000, 0, b, 16) > 4)
                Globals.num_sep = b[1];
        else
                Globals.num_sep = TEXT('.');
 
        old_font = SelectFont(hdc, Globals.hfont);
-       GetTextExtentPoint32(hdc, TEXT(" "), 1, &Globals.spaceSize);
+       GetTextExtentPoint32(hdc, sSpace, 1, &Globals.spaceSize);
        SelectFont(hdc, old_font);
        ReleaseDC(hwnd, hdc);
 }
@@ -2101,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)
 {
@@ -2188,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)
 {
@@ -2248,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);
 
@@ -2265,48 +2765,127 @@ 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);
+       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'};
+
        static int s_init = 0;
        Entry* entry = pane->root;
 
-       pane->hwnd = CreateWindow(TEXT("ListBox"), TEXT(""), WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL|
+       pane->hwnd = CreateWindow(sListBox, sEmpty, WS_CHILD|WS_VISIBLE|WS_HSCROLL|WS_VSCROLL|
                                                                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) {
@@ -2324,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);
 }
 
 
@@ -2341,7 +2920,7 @@ static void format_date(const FILETIME* ft, TCHAR* buffer, int visible_cols)
                return;
 
        if (!FileTimeToLocalFileTime(ft, &lft))
-               {err: _tcscpy(buffer,TEXT("???")); return;}
+               {err: lstrcpy(buffer,sQMarks); return;}
 
        if (!FileTimeToSystemTime(&lft, &systime))
                goto err;
@@ -2450,41 +3029,57 @@ 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 LPCTSTR executable_extensions[] = {
-               TEXT("COM"),
-               TEXT("EXE"),
-               TEXT("BAT"),
-               TEXT("CMD"),
+       static const TCHAR executable_extensions[][4] = {
+               {'C','O','M','\0'},
+               {'E','X','E','\0'},
+               {'B','A','T','\0'},
+               {'C','M','D','\0'},
 #ifndef _NO_EXTENSIONS
-               TEXT("CMM"),
-               TEXT("BTM"),
-               TEXT("AWK"),
-#endif // _NO_EXTENSIONS
-               0
+               {'C','M','M','\0'},
+               {'B','T','M','\0'},
+               {'A','W','K','\0'},
+#endif /* _NO_EXTENSIONS */
+               {'\0'}
        };
 
        TCHAR ext_buffer[_MAX_EXT];
-       const LPCTSTR* p;
+       const TCHAR (*p)[4];
        LPCTSTR s;
        LPTSTR d;
 
        for(s=ext+1,d=ext_buffer; (*d=tolower(*s)); s++)
                d++;
 
-       for(p=executable_extensions; *p; p++)
-               if (!_tcscmp(ext_buffer, *p))
-                       return 1;
+       for(p=executable_extensions; (*p)[0]; p++)
+               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;
 }
 
 
@@ -2520,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 = TEXT("");
-
-                       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;
@@ -2538,7 +3128,7 @@ static void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWi
 
        if (pane->treePane) {
                if (entry) {
-                       img_pos = dis->rcItem.left + entry->level*(IMAGE_WIDTH+Globals.spaceSize.cx);
+                       img_pos = dis->rcItem.left + entry->level*(IMAGE_WIDTH+TREE_LINE_DX);
 
                        if (calcWidthCol == -1) {
                                int x;
@@ -2571,7 +3161,7 @@ static void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWi
                                        x = img_pos - IMAGE_WIDTH/2;
 
                                        do {
-                                               x -= IMAGE_WIDTH+Globals.spaceSize.cx;
+                                               x -= IMAGE_WIDTH+TREE_LINE_DX;
 
                                                if (up->next
 #ifndef _LEFT_FILES
@@ -2596,17 +3186,11 @@ 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+Globals.spaceSize.cx;
-                                       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); */
                        } else if (calcWidthCol==col || calcWidthCol==COLUMNS) {
-                               int right = img_pos + IMAGE_WIDTH - Globals.spaceSize.cx;
+                               int right = img_pos + IMAGE_WIDTH - TREE_LINE_DX;
 
                                if (right > pane->widths[col])
                                        pane->widths[col] = right;
@@ -2630,21 +3214,21 @@ static void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWi
 
                        DrawText(dis->hDC, entry->data.cFileName, -1, &rt, DT_CALCRECT|DT_SINGLELINE|DT_NOPREFIX);
 
-                       focusRect.right = dis->rcItem.left+pane->positions[col+1]+Globals.spaceSize.cx + rt.right +2;
+                       focusRect.right = dis->rcItem.left+pane->positions[col+1]+TREE_LINE_DX + rt.right +2;
                }
 #else
 
                if (attrs & FILE_ATTRIBUTE_COMPRESSED)
                        textcolor = COLOR_COMPRESSED;
                else
-#endif // _NO_EXTENSIONS
+#endif /* _NO_EXTENSIONS */
                        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);
@@ -2701,9 +3285,9 @@ static void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWi
                {
                        ULONGLONG size;
 
-                        size = ((ULONGLONG)entry->data.nFileSizeHigh << 32) | entry->data.nFileSizeLow;
+                       size = ((ULONGLONG)entry->data.nFileSizeHigh << 32) | entry->data.nFileSizeLow;
 
-                       _stprintf(buffer, TEXT("%") LONGLONGARG TEXT("d"), size);
+                       _stprintf(buffer, sLongNumFmt, size);
 
                        if (calcWidthCol == -1)
                                output_number(pane, dis, col, buffer);
@@ -2730,7 +3314,7 @@ static void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWi
                else if (calcWidthCol==col || calcWidthCol==COLUMNS)
                        calc_width(pane, dis, col, buffer);
                col++;
-#endif // _NO_EXTENSIONS
+#endif /* _NO_EXTENSIONS */
 
                format_date(&entry->data.ftLastWriteTime, buffer, visible_cols);
                if (calcWidthCol == -1)
@@ -2745,32 +3329,38 @@ static void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWi
             ULONGLONG index = ((ULONGLONG)entry->bhfi.nFileIndexHigh << 32) | entry->bhfi.nFileIndexLow;
 
                if (visible_cols & COL_INDEX) {
-                       _stprintf(buffer, TEXT("%") LONGLONGARG TEXT("X"), index);
+                       _stprintf(buffer, sLongHexFmt, index);
+
                        if (calcWidthCol == -1)
                                output_text(pane, dis, col, buffer, DT_RIGHT);
                        else if (calcWidthCol==col || calcWidthCol==COLUMNS)
                                calc_width(pane, dis, col, buffer);
+
                        col++;
                }
 
                if (visible_cols & COL_LINKS) {
-                       wsprintf(buffer, TEXT("%d"), entry->bhfi.nNumberOfLinks);
+                       wsprintf(buffer, sNumFmt, entry->bhfi.nNumberOfLinks);
+
                        if (calcWidthCol == -1)
                                output_text(pane, dis, col, buffer, DT_CENTER);
                        else if (calcWidthCol==col || calcWidthCol==COLUMNS)
                                calc_width(pane, dis, col, buffer);
+
                        col++;
                }
        } else
                col += 2;
-#endif // _NO_EXTENSIONS
+#endif /* _NO_EXTENSIONS */
 
        /* show file attributes */
        if (visible_cols & COL_ATTRIBUTES) {
 #ifdef _NO_EXTENSIONS
-               _tcscpy(buffer, TEXT(" \t \t \t \t "));
+               const static TCHAR s4Tabs[] = {' ','\t',' ','\t',' ','\t',' ','\t',' ','\0'};
+               lstrcpy(buffer, s4Tabs);
 #else
-               _tcscpy(buffer, TEXT(" \t \t \t \t \t \t \t \t \t \t \t "));
+               const static TCHAR s11Tabs[] = {' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\t',' ','\0'};
+               lstrcpy(buffer, s11Tabs);
 #endif
 
                if (attrs & FILE_ATTRIBUTE_NORMAL)                                      buffer[ 0] = 'N';
@@ -2788,7 +3378,7 @@ static void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWi
                        if (attrs & FILE_ATTRIBUTE_REPARSE_POINT)               buffer[20] = 'Q';
                        if (attrs & FILE_ATTRIBUTE_OFFLINE)                             buffer[22] = 'O';
                        if (attrs & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED) buffer[24] = 'X';
-#endif // _NO_EXTENSIONS
+#endif /* _NO_EXTENSIONS */
                }
 
                if (calcWidthCol == -1)
@@ -2801,9 +3391,18 @@ static void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWi
 
 /*TODO
        if (flags.security) {
+               const static TCHAR sSecTabs[] = {
+                       ' ','\t',' ','\t',' ','\t',' ',
+                       ' ','\t',' ',
+                       ' ','\t',' ','\t',' ','\t',' ',
+                       ' ','\t',' ',
+                       ' ','\t',' ','\t',' ','\t',' ',
+                       '\0'
+               };
+
                DWORD rights = get_access_mask();
 
-               tcscpy(buffer, TEXT(" \t \t \t  \t  \t \t \t  \t  \t \t \t "));
+               lstrcpy(buffer, sSecTabs);
 
                if (rights & FILE_READ_DATA)                    buffer[ 0] = 'R';
                if (rights & FILE_WRITE_DATA)                   buffer[ 2] = 'W';
@@ -2838,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
@@ -2852,7 +3451,7 @@ static void draw_item(Pane* pane, LPDRAWITEMSTRUCT dis, Entry* entry, int calcWi
                SelectObject(dis->hDC, lastPen);
                DeleteObject(hpen);
        }
-#endif // _NO_EXTENSIONS
+#endif /* _NO_EXTENSIONS */
 }
 
 
@@ -2873,7 +3472,7 @@ static void draw_splitbar(HWND hwnd, int x)
        ReleaseDC(hwnd, hdc);
 }
 
-#endif // _NO_EXTENSIONS
+#endif /* _NO_EXTENSIONS */
 
 
 #ifndef _NO_EXTENSIONS
@@ -2918,7 +3517,7 @@ static LRESULT pane_notify(Pane* pane, NMHDR* pnmh)
                        RECT clnt;
                        GetClientRect(pane->hwnd, &clnt);
 
-                       /* move immediate to simulate HDS_FULLDRAG (for now [04/2000] not realy needed with WINELIB) */
+                       /* move immediate to simulate HDS_FULLDRAG (for now [04/2000] not really needed with WINELIB) */
                        Header_SetItem(pane->hwndHeader, idx, phdn->pitem);
 
                        pane->widths[idx] += dx;
@@ -2976,13 +3575,12 @@ static LRESULT pane_notify(Pane* pane, NMHDR* pnmh)
        return 0;
 }
 
-#endif // _NO_EXTENSIONS
+#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 */
@@ -3016,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);
@@ -3057,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)) {
@@ -3096,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);
@@ -3124,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());
@@ -3152,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];
 
@@ -3181,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;
        }
@@ -3205,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')
@@ -3224,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);
                        }
                }
 
@@ -3236,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);
        }
 }
 
@@ -3273,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);
@@ -3290,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 = CDefFolderMenu_Create2(dir?dir->_pidl:DesktopFolder(), hwndParent, 1, &pidl, shell_folder, NULL, 0, NULL, &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) {
@@ -3345,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;}
 
@@ -3356,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: {
@@ -3490,10 +4328,11 @@ LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam
                        lpmmi->ptMaxTrackSize.x <<= 1;/*2*GetSystemMetrics(SM_CXSCREEN) / SM_CXVIRTUALSCREEN */
                        lpmmi->ptMaxTrackSize.y <<= 1;/*2*GetSystemMetrics(SM_CYSCREEN) / SM_CYVIRTUALSCREEN */
                        break;}
-#endif // _NO_EXTENSIONS
+#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;
 
@@ -3510,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:
@@ -3518,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, sDestinationDlgProc, (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;}
 
-                                               lstrcpy(&old_name[len], new_name);
-                                               lstrcpy(new_name, old_name);
+                               case ID_FILE_COPY: {
+                                       TCHAR source[BUFFER_LEN], target[BUFFER_LEN];
+
+                                       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));
                        }
@@ -3568,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;}
@@ -3587,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
+                        /* 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
+                        /* 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);
@@ -3612,19 +4498,48 @@ LRESULT CALLBACK ChildWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam
                                        IShellFolder* parentFolder;
                                        LPCITEMIDLIST pidlLast;
 
-                                        // get and use the parent folder to display correct context menu in all cases
+                                        /* 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));
@@ -3638,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) {
@@ -3670,9 +4585,12 @@ LRESULT CALLBACK TreeWndProc(HWND hwnd, UINT nmsg, WPARAM wparam, LPARAM lparam)
 
 static void InitInstance(HINSTANCE hinstance)
 {
+       const static TCHAR sFont[] = {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f','\0'};
+
        WNDCLASSEX wcFrame;
        WNDCLASS wcChild;
        ATOM hChildClass;
+       int col;
 
        INITCOMMONCONTROLSEX icc = {
                sizeof(INITCOMMONCONTROLSEX),
@@ -3681,7 +4599,7 @@ static void InitInstance(HINSTANCE hinstance)
 
        HDC hdc = GetDC(0);
 
-       setlocale(LC_COLLATE, "");      // set collating rules to local settings for compareName
+       setlocale(LC_COLLATE, "");      /* set collating rules to local settings for compareName */
 
        InitCommonControlsEx(&icc);
 
@@ -3698,7 +4616,7 @@ static void InitInstance(HINSTANCE hinstance)
        wcFrame.hCursor       = LoadCursor(0, IDC_ARROW);
        wcFrame.hbrBackground = 0;
        wcFrame.lpszMenuName  = 0;
-       wcFrame.lpszClassName = WINEFILEFRAME;
+       wcFrame.lpszClassName = sWINEFILEFRAME;
        wcFrame.hIconSm       = (HICON)LoadImage(hinstance,
                                                                                         MAKEINTRESOURCE(IDI_WINEFILE),
                                                                                         IMAGE_ICON,
@@ -3720,14 +4638,14 @@ static void InitInstance(HINSTANCE hinstance)
        wcChild.hCursor       = LoadCursor(0, IDC_ARROW);
        wcChild.hbrBackground = 0;
        wcChild.lpszMenuName  = 0;
-       wcChild.lpszClassName = WINEFILETREE;
+       wcChild.lpszClassName = sWINEFILETREE;
 
        hChildClass = RegisterClass(&wcChild);
 
 
        Globals.haccel = LoadAccelerators(hinstance, MAKEINTRESOURCE(IDA_WINEFILE));
 
-       Globals.hfont = CreateFont(-MulDiv(8,GetDeviceCaps(hdc,LOGPIXELSY),72), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, TEXT("MS Sans Serif"));
+       Globals.hfont = CreateFont(-MulDiv(8,GetDeviceCaps(hdc,LOGPIXELSY),72), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, sFont);
 
        ReleaseDC(0, hdc);
 
@@ -3737,14 +4655,37 @@ static void InitInstance(HINSTANCE hinstance)
        CoInitialize(NULL);
        CoGetMalloc(MEMCTX_TASK, &Globals.iMalloc);
        SHGetDesktopFolder(&Globals.iDesktop);
+#ifdef __WINE__
+       Globals.cfStrFName = RegisterClipboardFormatA(CFSTR_FILENAME);
+#else
        Globals.cfStrFName = RegisterClipboardFormat(CFSTR_FILENAME);
 #endif
+#endif
+
+       /* load column strings */
+       col = 1;
+
+       load_string(g_pos_names[col++], IDS_COL_NAME);
+       load_string(g_pos_names[col++], IDS_COL_SIZE);
+       load_string(g_pos_names[col++], IDS_COL_CDATE);
+#ifndef _NO_EXTENSIONS
+       load_string(g_pos_names[col++], IDS_COL_ADATE);
+       load_string(g_pos_names[col++], IDS_COL_MDATE);
+       load_string(g_pos_names[col++], IDS_COL_IDX);
+       load_string(g_pos_names[col++], IDS_COL_LINKS);
+#endif
+       load_string(g_pos_names[col++], IDS_COL_ATTR);
+#ifndef _NO_EXTENSIONS
+       load_string(g_pos_names[col++], IDS_COL_SEC);
+#endif
 }
 
 
-void show_frame(HWND hwndParent, int cmdshow)
+static void show_frame(HWND hwndParent, int cmdshow, LPCTSTR path)
 {
-       TCHAR path[MAX_PATH];
+       const static TCHAR sMDICLIENT[] = {'M','D','I','C','L','I','E','N','T','\0'};
+
+       TCHAR buffer[MAX_PATH], b1[BUFFER_LEN];
        ChildWnd* child;
        HMENU hMenuFrame, hMenuWindow;
 
@@ -3753,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);
 
@@ -3767,76 +4706,20 @@ void show_frame(HWND hwndParent, int cmdshow)
 
 
        /* create main window */
-       Globals.hMainWnd = CreateWindowEx(0, (LPCTSTR)(int)Globals.hframeClass, TEXT("Wine File"), WS_OVERLAPPEDWINDOW,
+       Globals.hMainWnd = CreateWindowEx(0, (LPCTSTR)(int)Globals.hframeClass, RS(b1,IDS_WINE_FILE), WS_OVERLAPPEDWINDOW,
                                        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
                                        hwndParent, Globals.hMenuFrame, Globals.hInstance, 0/*lpParam*/);
 
 
-       Globals.hmdiclient = CreateWindowEx(0, TEXT("MDICLIENT"), NULL,
+       Globals.hmdiclient = CreateWindowEx(0, sMDICLIENT, NULL,
                                        WS_CHILD|WS_CLIPCHILDREN|WS_VSCROLL|WS_HSCROLL|WS_VISIBLE|WS_BORDER,
                                        0, 0, 0, 0,
                                        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);
+       CheckMenuItem(Globals.hMenuOptions, ID_VIEW_DRIVE_BAR, MF_BYCOMMAND|MF_CHECKED);
 
-               drivebarBtn.fsStyle = BTNS_BUTTON;
-
-#ifndef _NO_EXTENSIONS
-#ifdef __linux__
-               /* insert unix file system button */
-               SendMessage(Globals.hdrivebar, TB_ADDSTRING, 0, (LPARAM)TEXT("/\0"));
-
-               drivebarBtn.idCommand = ID_DRIVE_UNIX_FS;
-               SendMessage(Globals.hdrivebar, TB_INSERTBUTTON, btn++, (LPARAM)&drivebarBtn);
-               drivebarBtn.iString++;
-#endif
-#ifdef _SHELL_FOLDERS
-               /* insert shell namespace button */
-               SendMessage(Globals.hdrivebar, TB_ADDSTRING, 0, (LPARAM)TEXT("Shell\0"));
-
-               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[] = {
@@ -3865,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);
 
@@ -3894,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 */
 
@@ -3925,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);
 
@@ -3935,20 +4824,19 @@ 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;
 
        InitInstance(hinstance);
 
-#ifndef _ROS_  // don't maximize if being called from the ROS desktop
        if (cmdshow == SW_SHOWNORMAL)
                /*TODO: read window placement from registry */
                cmdshow = SW_MAXIMIZE;
-#endif
 
-       show_frame(hwndParent, cmdshow);
+       show_frame(0, cmdshow, path);
 
        while(GetMessage(&msg, 0, 0, 0)) {
                if (Globals.hmdiclient && TranslateMDISysAccel(Globals.hmdiclient, &msg))
@@ -3967,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(WINEFILEFRAME))
+       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;
 }