⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 winefile.c

📁 一个Windows下的资源管理器
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * 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 + -