📄 winefile.c
字号:
/*
* Winefile
*
* 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
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef __WINE__
#include "config.h"
#include "wine/port.h"
/* for unix filesystem function calls */
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#endif
#define COBJMACROS
#include "winefile.h"
#include "resource.h"
#ifdef _NO_EXTENSIONS
#undef _LEFT_FILES
#endif
#ifndef _MAX_PATH
#define _MAX_DRIVE 3
#define _MAX_FNAME 256
#define _MAX_DIR _MAX_FNAME
#define _MAX_EXT _MAX_FNAME
#define _MAX_PATH 260
#endif
#ifdef NONAMELESSUNION
#define UNION_MEMBER(x) DUMMYUNIONNAME.x
#else
#define UNION_MEMBER(x) x
#endif
#ifdef _SHELL_FOLDERS
#define DEFAULT_SPLIT_POS 300
#else
#define DEFAULT_SPLIT_POS 200
#endif
enum ENTRY_TYPE {
ET_WINDOWS,
ET_UNIX,
#ifdef _SHELL_FOLDERS
ET_SHELL
#endif
};
typedef struct _Entry {
struct _Entry* next;
struct _Entry* down;
struct _Entry* up;
BOOL expanded;
BOOL scanned;
int level;
WIN32_FIND_DATA data;
#ifndef _NO_EXTENSIONS
BY_HANDLE_FILE_INFORMATION bhfi;
BOOL bhfi_valid;
enum ENTRY_TYPE etype;
#endif
#ifdef _SHELL_FOLDERS
LPITEMIDLIST pidl;
IShellFolder* folder;
HICON hicon;
#endif
} Entry;
typedef struct {
Entry entry;
TCHAR path[MAX_PATH];
TCHAR volname[_MAX_FNAME];
TCHAR fs[_MAX_DIR];
DWORD drive_type;
DWORD fs_flags;
} Root;
enum COLUMN_FLAGS {
COL_SIZE = 0x01,
COL_DATE = 0x02,
COL_TIME = 0x04,
COL_ATTRIBUTES = 0x08,
COL_DOSNAMES = 0x10,
#ifdef _NO_EXTENSIONS
COL_ALL = COL_SIZE|COL_DATE|COL_TIME|COL_ATTRIBUTES|COL_DOSNAMES
#else
COL_INDEX = 0x20,
COL_LINKS = 0x40,
COL_ALL = COL_SIZE|COL_DATE|COL_TIME|COL_ATTRIBUTES|COL_DOSNAMES|COL_INDEX|COL_LINKS
#endif
};
typedef enum {
SORT_NAME,
SORT_EXT,
SORT_SIZE,
SORT_DATE
} SORT_ORDER;
typedef struct {
HWND hwnd;
#ifndef _NO_EXTENSIONS
HWND hwndHeader;
#endif
#ifndef _NO_EXTENSIONS
#define COLUMNS 10
#else
#define COLUMNS 5
#endif
int widths[COLUMNS];
int positions[COLUMNS+1];
BOOL treePane;
int visible_cols;
Entry* root;
Entry* cur;
} Pane;
typedef struct {
HWND hwnd;
Pane left;
Pane right;
int focus_pane; /* 0: left 1: right */
WINDOWPLACEMENT pos;
int split_pos;
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, 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
/* 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, RS(b2,IDS_WINEFILE), MB_OK);
else
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__
static VOID WineLicense(HWND Wnd)
{
TCHAR cap[20], text[1024];
LoadString(Globals.hInstance, IDS_LICENSE, text, 1024);
LoadString(Globals.hInstance, IDS_LICENSE_CAPTION, cap, 20);
MessageBox(Wnd, text, cap, MB_ICONINFORMATION | MB_OK);
}
static VOID WineWarranty(HWND Wnd)
{
TCHAR cap[20], text[1024];
LoadString(Globals.hInstance, IDS_WARRANTY, text, 1024);
LoadString(Globals.hInstance, IDS_WARRANTY_CAPTION, cap, 20);
MessageBox(Wnd, text, cap, MB_ICONEXCLAMATION | MB_OK);
}
#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(void)
{
Entry* entry = (Entry*) malloc(sizeof(Entry));
#ifdef _SHELL_FOLDERS
entry->pidl = NULL;
entry->folder = NULL;
entry->hicon = 0;
#endif
return entry;
}
/* free a directory entry */
static void free_entry(Entry* entry)
{
#ifdef _SHELL_FOLDERS
if (entry->hicon && entry->hicon!=(HICON)-1)
DestroyIcon(entry->hicon);
if (entry->folder && entry->folder!=Globals.iDesktop)
IShellFolder_Release(entry->folder);
if (entry->pidl)
IMalloc_Free(Globals.iMalloc, entry->pidl);
#endif
free(entry);
}
/* recursively free all child entries */
static void free_entries(Entry* dir)
{
Entry *entry, *next=dir->down;
if (next) {
dir->down = 0;
do {
entry = next;
next = entry->next;
free_entries(entry);
free_entry(entry);
} while(next);
}
}
static void read_directory_win(Entry* dir, LPCTSTR path)
{
Entry* first_entry = NULL;
Entry* last = NULL;
Entry* entry;
int level = dir->level + 1;
WIN32_FIND_DATA w32fd;
HANDLE hFind;
#ifndef _NO_EXTENSIONS
HANDLE hFile;
#endif
TCHAR buffer[MAX_PATH], *p;
for(p=buffer; *path; )
*p++ = *path++;
*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)
first_entry = entry;
if (last)
last->next = entry;
memcpy(&entry->data, &w32fd, sizeof(WIN32_FIND_DATA));
entry->down = NULL;
entry->up = dir;
entry->expanded = FALSE;
entry->scanned = FALSE;
entry->level = level;
#ifndef _NO_EXTENSIONS
entry->etype = ET_WINDOWS;
entry->bhfi_valid = FALSE;
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);
if (hFile != INVALID_HANDLE_VALUE) {
if (GetFileInformationByHandle(hFile, &entry->bhfi))
entry->bhfi_valid = TRUE;
CloseHandle(hFile);
}
#endif
last = entry;
} while(FindNextFile(hFind, &w32fd));
if (last)
last->next = NULL;
FindClose(hFind);
}
dir->down = first_entry;
dir->scanned = TRUE;
}
static Entry* find_entry_win(Entry* dir, LPCTSTR name)
{
Entry* entry;
for(entry=dir->down; entry; entry=entry->next) {
LPCTSTR p = name;
LPCTSTR q = entry->data.cFileName;
do {
if (!*p || *p==TEXT('\\') || *p==TEXT('/'))
return entry;
} while(tolower(*p++) == tolower(*q++));
p = name;
q = entry->data.cAlternateFileName;
do {
if (!*p || *p==TEXT('\\') || *p==TEXT('/'))
return entry;
} while(tolower(*p++) == tolower(*q++));
}
return 0;
}
static Entry* read_tree_win(Root* root, LPCTSTR path, SORT_ORDER sortOrder, HWND hwnd)
{
TCHAR buffer[MAX_PATH];
Entry* entry = &root->entry;
LPCTSTR s = path;
PTSTR d = buffer;
HCURSOR old_cursor = SetCursor(LoadCursor(0, IDC_WAIT));
#ifndef _NO_EXTENSIONS
entry->etype = ET_WINDOWS;
#endif
while(entry) {
while(*s && *s!=TEXT('\\') && *s!=TEXT('/'))
*d++ = *s++;
while(*s==TEXT('\\') || *s==TEXT('/'))
s++;
*d++ = TEXT('\\');
*d = TEXT('\0');
read_directory(entry, buffer, sortOrder, hwnd);
if (entry->down)
entry->expanded = TRUE;
if (!*s)
break;
entry = find_entry_win(entry, s);
}
SetCursor(old_cursor);
return entry;
}
#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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -