Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

A comprehensive CE class library to replace ATL and MFC

, 4 Oct 2000
A collection of classes for CE that do not use ATL or MFC, plus an FTP client, database viewer, and sample application that solves beam deflection equations.
kgwince-old.zip
WinCe
BeamEx
app.ico
BeamEx.dsp
BeamEx.dsw
BeamEx.ini
BeamEx.plg
bitmap1.bmp
bmp00001.bmp
bmp00002.bmp
calc.bmp
calc16.bmp
circ_cross.ico
cir_cross.ico
cross_4.ico
help16.bmp
help4.bmp
ico00001.ico
ico00002.ico
ico00005.ico
ico00008.ico
ico00009.ico
ico00010.ico
icon1.ico
icon2.ico
icon4.ico
id_downl.bmp
Install
BeamEx.inf
BeamEx.ini
BeamEx.MIPS_PPCBW.CAB
BeamEx.MIPS_PPCColor.CAB
BeamEx.SH3_PPCColor.CAB
Setup.exe
i_cross.ico
l_cross.ico
magenic.ico
mssccprj.scc
obl_corss.ico
obl_cross.ico
options.bmp
options1.bmp
ping16.bmp
rect_cross.ico
scene_5.ico
scene_6.ico
tri_cross.ico
vssver.scc
CeLib
CeLabel.inl
CeLib.aps
CeLib.dsp
CeLib.dsw
CeLib.old
CeLib.plg
CeLib.vcp
CeMisc.inl
CeProperty.inl
CeTab.inl
CeWnd.inl
mssccprj.scc
vssver.scc
WinLib.dsp
WinLib.dsw
dbView
bitmap1.bmp
bmp00001.bmp
db5.bmp
dbView.aps
DbView.dsp
dbView.dsw
dbView.old
dbView.plg
DbView.vcp
deldb.bp2
deldb5.bmp
delrec.bp2
delrecor.bmp
help16.bmp
help4.bmp
icon1.ico
icon2.ico
Install
dbView.inf
dbView.ini
Setup.exe
magenic.bmp
magenic.ico
mssccprj.scc
vssver.scc
ftpView
appicon.ico
bitmap1.bmp
bitmap2.bmp
bitmap3.bmp
bitmap4.bmp
bmp00001.bmp
bmp00002.bmp
db5.bmp
deldb.bp2
delrec.bp2
FtpView.dsp
ftpView.dsw
FtpView.old
ftpView.plg
FtpView.vcl
FtpView.vcp
help16.bmp
help4.bmp
ico00001.ico
ico00002.ico
ico171.ico
ico35.ico
icon1.ico
icon2.ico
imagelis.bmp
IMAGES.bmp
Install
ftpView.inf
ftpView.ini
Setup.exe
vssver.scc
magenic.bmp
magenic.ico
mssccprj.scc
options.bmp
options1.bmp
seperato.bmp
vssver.scc
Setup
ico101.ico
Setup.aps
Setup.dsp
setup.ico
Setup.plg
WinCe.dsw
WinLib.dsw
kgwince.zip
app.ico
BeamEx.dsp
BeamEx.dsw
BeamEx.ini
BeamEx.plg
BeamEx.vcl
BeamEx.vcp
bitmap1.bmp
bmp00001.bmp
bmp00002.bmp
calc.bmp
calc16.bmp
circ_cross.ico
cir_cross.ico
cross_4.ico
help16.bmp
help4.bmp
ico00001.ico
ico00002.ico
ico00005.ico
ico00008.ico
ico00009.ico
ico00010.ico
icon1.ico
icon2.ico
icon4.ico
id_downl.bmp
BeamEx.inf
BeamEx.ini
Setup.exe
i_cross.ico
l_cross.ico
magenic.ico
mssccprj.scc
obl_corss.ico
obl_cross.ico
options.bmp
options1.bmp
ping16.bmp
rect_cross.ico
scene_5.ico
scene_6.ico
tri_cross.ico
vssver.scc
CeFtp.vcp
CeFtp.vcw
CeLabel.inl
CeLib.aps
CeLib.dsp
CeLib.dsw
CeLib.plg
CeLib.vcl
CeLib.vcp
CeMisc.inl
CeProperty.inl
CeTab.inl
CeWnd.inl
mssccprj.scc
vssver.scc
WinLib.dsp
WinLib.dsw
bitmap1.bmp
bitmap2.bmp
bmp00001.bmp
db5.bmp
DbView.dsp
dbView.dsw
dbView.plg
DbView.vcl
DbView.vcp
deldb.bp2
deldb5.bmp
delrec.bp2
delrecor.bmp
help16.bmp
help4.bmp
icon1.ico
icon2.ico
dbView.inf
dbView.ini
Setup.exe
magenic.bmp
magenic.ico
menu1_5.bmp
mssccprj.scc
vssver.scc
appicon.ico
bitmap1.bmp
bitmap2.bmp
bitmap3.bmp
bitmap4.bmp
bmp00001.bmp
bmp00002.bmp
db5.bmp
deldb.bp2
delrec.bp2
FtpView.dsp
ftpView.dsw
ftpView.plg
FtpView.vcl
FtpView.vcp
FtpView.vcw
help16.bmp
help4.bmp
ico00001.ico
ico00002.ico
ico171.ico
ico35.ico
icon1.ico
icon2.ico
imagelis.bmp
IMAGES.bmp
ftpView.inf
ftpView.ini
Setup.exe
vssver.scc
magenic.bmp
magenic.ico
mssccprj.scc
newmenu.bmp
options.bmp
options1.bmp
rcdata1.bin
seperato.bmp
toolbar1.bmp
vssver.scc
WinCe.dsw
WinCe.vcw
#include "StdAfx.h"
#include <shlobj.h>
#include <afxres.h>

#include <CeFontDlg.h>
#include <CeFindFile.h>
#include <CeLabel.h>

#include <math.h>

#include "MainWnd.h"
#include "FtpViewRes.h"
#include "FtpTransDlg.h"

#include "ftpSite.h"

#include "OptDlg.h"
#include "PropertyDlg.h"

//#if defined(_WIN32_WCE_PSPC)
//	#include <aygshell.h>
//	#pragma comment(lib, "aygshell.lib")
//#endif

#if defined(_WIN32_WCE_POCKETPC)
	static SHACTIVATEINFO s_saiDlgBox;
	static SHACTIVATEINFO s_sai;
#endif


LISTSORTINFO g_sortinfo;
OPTIONS g_options;
CeArray<int>	g_arColumns;
OSVERSIONINFO g_osvi = {sizeof(g_osvi)};

#define _WIN32_HR(err)	HRESULT_FROM_WIN32(err)

static HRESULT (STDAPICALLTYPE *g_pfnVarDateFromStr)(OLECHAR FAR* strIn, LCID lcid, unsigned long dwFlags, DATE FAR* pdateOut) = NULL;

CeString TreeView_GetItemText(HWND hTree, HTREEITEM hItem)
{
	CeString str;

	TV_ITEM tvi;
	tvi.mask = TVIF_TEXT | TVIF_HANDLE;
	tvi.hItem = hItem;
	tvi.pszText = str.GetBuffer(128);
	tvi.cchTextMax = 128;

	TreeView_GetItem(hTree, &tvi);

	str.ReleaseBuffer();

	return str;
}

LPARAM TreeView_GetLParam(HWND hTree, HTREEITEM hItem)
{
	TV_ITEM tvi;
	CeString str;
	tvi.mask = TVIF_PARAM | TVIF_HANDLE;
	tvi.hItem = hItem;

	TreeView_GetItem(hTree, &tvi);

	return tvi.lParam;
}

extern HINSTANCE g_hInst;

#define IDC_BAND		102
#define IDC_TREE		100
//#define IDC_LIST		101

#define IDC_MENU_BAND	201
#define IDC_BUTTON_BAND	202


enum eTreeNodeType
{
	tntDesktop = 1,
	tntDevice = 2,
	tntFtpSite = 3,
	tntLocalDir = 4,
	tntFtpSiteDir = 5,
};

enum eImages
{
	imFolderOpen = 0,
	imFolderClose = 1,
	imApp = 2,
	imHeir = 3,
	imDoc = 4,
	imDesktop = 5,
	imFtpSite = 6,
	imFtpOpenFolder = 7,
	imFtpClosedFolder = 8,
	imPPC = 9,
	imHPC = 10,
	imHPCPro = 11,
	imFlashOpen = 12,
	imFlashClose = 13,
	imDocUnknown = 14
};


BOOL LoadProc(FARPROC* pProc, LPCTSTR pszFuncName, LPCTSTR pszLibName)
{
	HINSTANCE hInst = LoadLibrary(pszLibName);
	if (NULL == hInst)
		return FALSE;

	return ((*pProc = GetProcAddress(hInst, pszFuncName)) != NULL);
}


void FormatDateTime(FILETIME ft, LPTSTR sz, SYSTEMTIME* pT)
{
	SYSTEMTIME st;
	BOOL bSuccess = ::FileTimeToSystemTime(&ft, &st);
	if (! bSuccess || st.wYear > 9999)
	{
		sz[0] = 0;
	}
	else
	{
		int nSize = 0;
		bool bToday = (pT && pT->wYear == st.wYear && pT->wMonth == st.wMonth && pT->wDay == st.wDay);

		if (pT == NULL || !bToday)
			nSize = ::GetDateFormat(LOCALE_SYSTEM_DEFAULT, DATE_SHORTDATE, &st,	NULL, sz, 32);

		if (pT == NULL)
			sz[nSize-1] = _T(' ');

		if (pT == NULL || bToday)
			::GetTimeFormat(LOCALE_SYSTEM_DEFAULT, TIME_NOSECONDS, &st, NULL, sz + nSize, 32);
	}
}


double NumDate(DATE dt)
{
	// No problem if positive
	if (dt >= 0)
		return dt;

	// If negative, must convert since negative dates not continuous
	// (examples: -1.25 to -.75, -1.50 to -.50, -1.75 to -.25)
	double temp = ceil(dt);
	return temp - (dt - temp);
}


class CeFileListItem
{
public:
	CeFileListItem(LPCTSTR lpsz, DWORD dwSize, DWORD dwAttrib, FILETIME ft, LPCTSTR lpszExt)
	{
		LPSTR sz = (LPSTR) &m_dwName;

		// Little endian copy
		sz[3] = (char) towupper(lpsz[0]);
		sz[2] = (char) towupper(lpsz[1]);
		sz[1] = (char) towupper(lpsz[2]);
		sz[0] = (char) towupper(lpsz[3]);

		m_dwSize = dwSize;
		m_dwAttrib = dwAttrib;
		m_ft = ft;
	}

	DWORD	m_dwName;
	DWORD	m_dwSize;
	DWORD	m_dwAttrib;
	FILETIME m_ft;
};

int CALLBACK CmpList(LPARAM lpOne, LPARAM lpTwo, LPARAM lpArg)
{
	LISTSORTINFO* pSortInfo = (LISTSORTINFO *) lpArg;
	int nResult = 0;

	CeFileListItem *pItem = (CeFileListItem *) lpOne;
	CeFileListItem *pItem2 = (CeFileListItem *) lpTwo;

	//
	// Attempt to sort my an easily accessable value,
	// or if that isn't possible, use the column value
	//
	switch (pSortInfo->nColType)
	{
	case SORTCOL_NAME:
		if (pItem->m_dwName != pItem2->m_dwName)
		{
			if (!pSortInfo->bAscending)
				return pItem2->m_dwName - pItem->m_dwName;
			else
				return pItem->m_dwName - pItem2->m_dwName;
		}
		break;

	case SORTCOL_SIZE:
		if (!pSortInfo->bAscending)
			return (int) pItem2->m_dwSize - pItem->m_dwSize;
		else
			return (int) pItem->m_dwSize - pItem2->m_dwSize;

	case SORTCOL_DATE:
		if (!pSortInfo->bAscending)
			return (int) CompareFileTime(&pItem->m_ft, &pItem2->m_ft);
		else
			return (int) CompareFileTime(&pItem2->m_ft, &pItem->m_ft);
	
	case SORTCOL_ATTRIB:
		if (!pSortInfo->bAscending)
			return (int) pItem2->m_dwAttrib - pItem->m_dwAttrib;
		else
			return (int) pItem->m_dwAttrib - pItem2->m_dwAttrib;
	}


	// Find the specified lParam
	LV_FINDINFO fi;
	// use LVFI_WRAP for cases where lpTwo represents a row before lpOne
	fi.flags = LVFI_PARAM | LVFI_WRAP;
	fi.lParam = lpOne;
	int lFirstData = ListView_FindItem(pSortInfo->hwndList, -1, &fi);

	fi.lParam = lpTwo;
	// reduce searching time by setting the start row as lFirstData
	int lSecondData = ListView_FindItem(pSortInfo->hwndList, lFirstData, &fi);

	// because we are searching for LPARAM sent to us, FindItem() on 
	// these values should always be successful
	ASSERT(lFirstData != -1);
	ASSERT(lSecondData != -1);

	// Go and lookup the lParam text
	wchar_t szFirst[64], szSecond[64];
	ListView_GetItemText(pSortInfo->hwndList, lFirstData, pSortInfo->nColumnNo, szFirst, 64);
	ListView_GetItemText(pSortInfo->hwndList, lSecondData, pSortInfo->nColumnNo, szSecond, 64);

	int nCompareValue  = _tcsnicmp(szFirst, szSecond, 64);
	return nCompareValue * ((pSortInfo->bAscending) ? 1: -1);
}


///////////////////////////////////////////////////////////////////////////////
//
// CeAboutDlg = Dialog for displaying information about the product
//
///////////////////////////////////////////////////////////////////////////////

class CeAboutDlg: public CeScrollDialog
{
private:
	CeChildMgr m_mgr;

public:
	CeAboutDlg(): CeScrollDialog(IDD_ABOUT) {}
	virtual BOOL OnInitDialog();
	virtual void OnSize(UINT nType, int cx, int cy, bool& bHandled);
};

#define IDT_ANIM_ICON	100

BOOL CeAboutDlg::OnInitDialog()
{
	BOOL bRet = CeScrollDialog::OnInitDialog();

	m_mgr.Manage(GetDlgItem(IDC_NAME_STATIC), AL_ADJUST_SIZE);

#ifdef _WIN32_WCE_POCKETPC
	// Create a Done button and size it.  
	SHINITDLGINFO shidi;
	shidi.dwMask = SHIDIM_FLAGS;
	shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN;
	shidi.hDlg = m_hWnd;

	SHInitDialog(&shidi);
#endif

	// allow controls to be created
	return bRet;
}


void CeAboutDlg::OnSize(UINT nType, int cx, int cy, bool& bHandled)
{
	m_mgr.OnSize(nType, cx, cy);

	CeScrollDialog::OnSize(nType, cx, cy, bHandled);
}


///////////////////////////////////////////////////////////////////////////////
//
// CeDropFileDlg = Dialog for querying the user as to thier intensions on
//                 dropping a file
//
///////////////////////////////////////////////////////////////////////////////

class CeDropFileDlg: public CeScrollDialog
{
private:
	CeChildMgr m_mgr;

public:
	int m_nWhich;

	CeDropFileDlg(): CeScrollDialog(IDD_DROPFILE)
		{ m_nWhich = IDCANCEL; }

	virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam, bool& bHandled);
	virtual BOOL OnInitDialog();
	virtual void OnSize(UINT nType, int cx, int cy, bool& bHandled);
	virtual void OnOK();
	virtual void OnSettingChange(WORD wFlag, LPCTSTR pszSection, bool& bHandled);
};

#define IDT_ANIM_ICON	100

BOOL CeDropFileDlg::OnInitDialog()
{
	BOOL bRet = CeScrollDialog::OnInitDialog();

	m_mgr.Manage(GetDlgItem(IDC_COPY), AL_ADJUST_WIDTH);
	m_mgr.Manage(GetDlgItem(IDC_MOVE), AL_ADJUST_WIDTH);
	m_mgr.Manage(GetDlgItem(IDC_SHORTCUT), AL_ADJUST_WIDTH);
	m_mgr.Manage(GetDlgItem(IDCANCEL), AL_ADJUST_WIDTH);

#ifdef _WIN32_WCE_POCKETPC
	// Create a Done button and size it.  
	SHINITDLGINFO shidi;
	shidi.dwMask = SHIDIM_FLAGS;
	shidi.dwFlags = SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN;
	shidi.hDlg = m_hWnd;

	SHInitDialog(&shidi);
#endif

	// allow controls to be created
	return bRet;
}


void CeDropFileDlg::OnSize(UINT nType, int cx, int cy, bool& bHandled)
{
	m_mgr.OnSize(nType, cx, cy);

	CeScrollDialog::OnSize(nType, cx, cy, bHandled);
}


void CeDropFileDlg::OnOK()
{
//	m_nWhich = IDC_RADIOCOPY;
//	for (int nID = IDC_RADIOCOPY; nID <= IDC_RADIOSHORTCUT; nID++)
//	{
//		if ((UINT)::SendMessage( GetDlgItem(nID), BM_GETCHECK, 0, 0 ))
//			m_nWhich = nID; // id that matched
//	}

	CeScrollDialog::OnOK();	// call base class
}


BOOL CeDropFileDlg::OnCommand(WPARAM wParam, LPARAM lParam, bool& bHandled)
{
	WORD wNotify = HIWORD(wParam);	// notification code 
	WORD wId	 = LOWORD(wParam);	// item, control, or accelerator identifier 
	HWND hwndCtl = (HWND) lParam;	// handle of control 

	m_nWhich = wId;

	//default to handled
	bHandled = true;

	OnOK();

	return FALSE;
}


void CeDropFileDlg::OnSettingChange( WORD wFlag, LPCTSTR pszSection, bool& bHandled )
{
#if defined(_WIN32_WCE_POCKETPC)

	s_saiDlgBox.cbSize = sizeof s_saiDlgBox;
	SHHandleWMSettingChange(m_hWnd, wFlag, (long) pszSection, &s_saiDlgBox);
	bHandled = true;

#endif
}


///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////

CeMainWnd::CeMainWnd()
{
	m_hFont = NULL;
	m_hImages = NULL;
	m_dwFontSize = 0;
	m_hwndList = NULL;
	m_hwndTree = NULL;

	m_hwndLast = NULL;

	m_hConnected = NULL;

	// Drag and drop info....
	m_hDragImage = NULL;
	m_bDragging = false;
	m_hDropWnd = NULL;
	m_ptDropPoint.x = 0;
	m_ptDropPoint.y = 0;

	m_dwDragItem = 0xffffffff;
	m_dwDropItem = 0xffffffff;

	memset(&m_nid, 0, sizeof m_nid);
}


BOOL CeMainWnd::OnCommand(WPARAM wParam, LPARAM lParam, bool& bHandled)
{
	WORD wNotify = HIWORD(wParam);	// notification code 
	WORD wId	 = LOWORD(wParam);	// item, control, or accelerator identifier 
	HWND hwndCtl = (HWND) lParam;	// handle of control 

	//default to handled
	bHandled = false;

	//menu commands
	if (0 == wNotify)
	{
		// Parse the menu selections:
		bHandled = true;
		switch (wId)
		{
		case ID_FILE_OPEN:			OnRun();			break;
		case ID_FILE_PROPERTIES:	OnProperties();		break;
		case ID_FILE_DELETE:		OnDelete();			break;
		case ID_FILE_RENAME:		OnRename();			break;
		case ID_FILE_ABOUT:			OnAbout();			break;
		case ID_FILE_NEW_FOLDER:	OnNewFolder();		break;
		case ID_FILE_CLOSE:			DestroyWindow();	break;

		case ID_TOOLS_OPTIONS:		OnOptions();		break;
		case ID_TOOLS_FONT:			OnFont();			break;

		// E_NOTIMPL
		case ID_EDIT_PASTE:								break;
		case ID_EDIT_CUT:								break;
		case ID_EDIT_COPY:								break;

		case ID_ACTIONS_REFRESH:	OnRefresh();		break;
		case ID_ACTIONS_CONNECT:	OnConnect();		break;
		case ID_ACTIONS_DISCONNECT:	OnDisconnect();		break;
		case ID_ACTIONS_NEWSITE:	OnNewSite();		break;

		default:
			bHandled = false;
			break;
		}
	}

	return 0;
}

void CeMainWnd::OnRun()
{
	HWND hwndFocus = GetFocus();
	if (hwndFocus != m_hwndList)
		return;

	if (m_bCurrentFtp || m_strCurrentDirectory.IsEmpty())
		// nothing yet
		return;

	int nSel = ListView_GetNextItem(m_hwndList, -1, LVIS_SELECTED);
	if (nSel < 0)
		return;

	TCHAR szFile[MAX_PATH];
	ListView_GetItemText(m_hwndList, nSel, 1, szFile, MAX_PATH);

	if (*szFile == 0)
	{
		// change directory, this is a folder
		// ListView_GetItemText(m_hwndList, nSel, 0, szFile, MAX_PATH);
	}
	else
	{
		ListView_GetItemText(m_hwndList, nSel, 0, szFile, MAX_PATH);
		Execute(m_strCurrentDirectory, szFile);
	}
}

void CeMainWnd::OnRename()
{
	HWND hwndFocus = GetFocus();
	if (hwndFocus == m_hwndList)
	{
		int nSel = ListView_GetNextItem(m_hwndList, -1, LVIS_FOCUSED);
		if (nSel >= 0)
			ListView_EditLabel(m_hwndList, nSel);
	}
	else if (hwndFocus == m_hwndTree)
	{
		HTREEITEM hItem = TreeView_GetSelection(m_hwndTree);
		if (hItem != 0)
			TreeView_EditLabel(m_hwndTree, hItem);
	}
}


bool RecursiveRemoveDirectory(LPCTSTR lpszDir, bool bAndSubs = true)
{
	CeString str;
	str.Format(_T("%s*.*"), lpszDir);

	CeFindFile ff;
	if (! ff.FindFirst(str))
		return true;

	do
	{
		if (ff.IsDirectory())
		{
			RecursiveRemoveDirectory(ff.cFileName);
			RemoveDirectory(ff.cFileName);
		}
		else
		{
			CeString strFile = lpszDir;
			strFile += ff.cFileName;
			DeleteFile(strFile);
		}
	}
	while (ff.FindNext());

	if (bAndSubs)
		RemoveDirectory(ff.cFileName);

	return true;
}


void CeMainWnd::OnEmptyRecycleBin()
{
	RecursiveRemoveDirectory(_T("\\Recycled\\"), false);
}


void CeMainWnd::OnNewFolder()
{
	HWND hwndFocus = GetFocus();

	// Check for focus and selection, otherwise forget it...
	if (hwndFocus != m_hwndTree)
		return;

	HTREEITEM hItem = TreeView_GetSelection(m_hwndTree);
	if (NULL == hItem)
		return;

	eTreeNodeType eType = (eTreeNodeType) TreeView_GetLParam(m_hwndTree, hItem);
	if 	(tntDesktop == eType || (tntFtpSite == eType && ! m_ftpConn.IsConnected()))
		return;

	bool bFtp;
	CeString str = GetTreePath(hItem, bFtp);
	str += _T("New Folder");

	TreeView_Expand(m_hwndTree, hItem, TVE_EXPAND);

	if (bFtp)
	{
		if (! m_ftpConn.CreateDir(str))
		{
			MessageBox(m_ftpConn.GetFtpErrorReplyString(), str, MB_OK|MB_ICONWARNING);
		}
	}
	else
	{
		if (! ::CreateDirectory(str, NULL))
		{
			MessageBox(_T("Unable to create directory!"), str, MB_OK|MB_ICONWARNING);
			return;
		}
	}

	// create the node off the root and enter edit mode
	//
	// initialize the tree
	TVINSERTSTRUCT is;
	is.hInsertAfter = TVI_SORT;
	is.hParent = hItem;
	is.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN | TVIF_PARAM;
	is.item.pszText = _T("New Folder");
	is.item.cChildren = 0;

	if (bFtp)
	{
		is.item.lParam = tntFtpSiteDir;
		is.item.iSelectedImage = imFtpOpenFolder;
		is.item.iImage = imFtpClosedFolder;
	}
	else
	{
		is.item.lParam = tntLocalDir;
		is.item.iSelectedImage = imFolderOpen;
		is.item.iImage = imFolderClose;
	}

	// insert and edit...
	TreeView_EditLabel(m_hwndTree, TreeView_InsertItem(m_hwndTree, &is) );
}


void CeMainWnd::OnDelete()
{
	//HWND hwndFocus = GetFocus();
	HWND hwndFocus = m_hwndLast;
	if (hwndFocus == m_hwndList)
	{
		int nSel;
		if ((nSel = ListView_GetNextItem(m_hwndList, -1, LVNI_FOCUSED)) < 0)
		{
			if ((nSel = ListView_GetNextItem(m_hwndList, -1, LVIS_SELECTED)) < 0)
				return;
		}

		CeString strFile;

		LVITEM lvi;
		lvi.mask       = LVIF_TEXT | LVIF_PARAM;
		lvi.iItem      = nSel;
		lvi.iSubItem   = 0;
		lvi.pszText    = strFile.GetBufferSetLength(64);
		lvi.cchTextMax = 64;

		ListView_GetItem(m_hwndList, &lvi);

		strFile.ReleaseBuffer();

		CeFileListItem *pItem = (CeFileListItem *) lvi.lParam;
		if (pItem->m_dwAttrib & FILE_ATTRIBUTE_INROM)
		{
			MessageBox(L"Files in ROM cannot be removed.", L"ROM File",
				MB_OK|MB_ICONINFORMATION);
			return;
		}

		CeString strPrompt;
		strPrompt.Format(_T("Are you sure you want to remove '%s'?"), (LPCTSTR)strFile);
		if (IDYES != MessageBox(strPrompt, L"Confirm File Delete", MB_YESNO|MB_ICONINFORMATION))
			return;

		CeString strDir = m_strCurrentDirectory;
		strDir += strFile;

		if (m_bCurrentFtp)
		{
			if (! m_ftpConn.DeleteFile(strDir))
			{
				CeString str = m_ftpConn.GetFtpErrorReplyString();
				MessageBox(str, _T("FTP delete failed!"), MB_OK|MB_ICONERROR);
				return;
			}
		}
		else
		{
			if (! DeleteFile(strDir))
				return;
		}

		ListView_DeleteItem(m_hwndList, nSel);

		if (nSel > ListView_GetItemCount(m_hwndList))
			nSel--;

		::SetFocus(hwndFocus);
		
		ListView_SetItemState(m_hwndList, nSel, LVIS_FOCUSED|LVIS_SELECTED,
			LVIS_FOCUSED|LVIS_SELECTED);
	}
	else if (hwndFocus == m_hwndTree)
	{
		HTREEITEM hItem = TreeView_GetSelection(m_hwndTree);

		bool bFtp;
		CeString str = GetTreePath(hItem, bFtp);

		if (bFtp && str == _T("\\") && ! m_ftpConn.IsConnected())
		{
			// remove the ftp site from the data base
			str = TreeView_GetItemText(m_hwndTree, hItem);

			if (CeFtpSite::Remove(str))
				TreeView_DeleteItem(m_hwndTree, hItem);

			return;
		}

		if (str.IsEmpty() || str == _T("\\") || str == _T("\\Windows\\"))
		{
			MessageBox(_T("Removing system files from the device won't work, sorry."),
				_T("Remove file"), MB_ICONWARNING|MB_OK);
			return;
		}

		int nResp = MessageBox(_T("Are you certain you wish to remove the selected directory?"),
			str, MB_YESNO|MB_ICONINFORMATION);

		if (nResp != IDYES)
			return;

		// remove the trailing "\"
		CeString strDir((LPCTSTR)str, str.GetLength()-1);

		if (bFtp)
		{
			if (m_ftpConn.DeleteDir(str))
			{
				TreeView_DeleteItem(m_hwndTree, hItem);
				// refresh the list view....
			}
			else
			{
				MessageBox(m_ftpConn.GetFtpErrorReplyString(), _T("Remove Directory"), MB_OK|MB_ICONWARNING);
			}
		}
		else
		{
			if (::RemoveDirectory(str))
			{
				TreeView_DeleteItem(m_hwndTree, hItem);
				// refresh the list view....
			}
			else
			{
				if (ERROR_DIR_NOT_EMPTY == GetLastError())
				{
					MessageBox(_T("You must remove the files in this directory before you can remove it."),
						_T("Error"), MB_ICONWARNING|MB_OK);
				}
				else
				{
					CeString strErr;
					strErr.Format(_T("Error number %lu occured while removing directory"), GetLastError());
					MessageBox(strErr, _T("Remove Directory"), MB_ICONWARNING|MB_OK);
				}
			}
		}
	}
}


void CeMainWnd::OnDisconnect()
{
	if (m_ftpConn.IsConnected())
		m_ftpConn.Disconnect();

	if (NULL == m_hConnected)
		return;

	HTREEITEM hItem;
	while (NULL != (hItem = TreeView_GetChild(m_hwndTree, m_hConnected)))
		TreeView_DeleteItem(m_hwndTree, hItem);

	TVITEM item;
	item.hItem = m_hConnected;
	item.mask = TVIF_STATE | TVIF_CHILDREN;
	item.state = 0;
	item.stateMask = TVIS_BOLD;
	item.cChildren = 0;
	TreeView_SetItem(m_hwndTree, &item);

	// remove all the sun nodes and remove 
	TreeView_Expand(m_hwndTree, m_hConnected, TVE_COLLAPSERESET);

	// clean out the file list
	PopulateFilelist(m_hConnected, _T(""), true);

	m_hConnected = NULL;
}


void CeMainWnd::OnConnect()
{
	if (m_ftpConn.IsConnected())
	{
		MessageBox(_T("Already connected to an FTP site, this software currently supports a single connection"),
			NULL, MB_OK|MB_ICONWARNING);
		return;
	}

	HTREEITEM hItem = TreeView_GetSelection(m_hwndTree);
	TVITEM item;

	TCHAR szBuf[64];
	item.hItem = hItem;
	item.mask = TVIF_PARAM | TVIF_TEXT;
	item.pszText = szBuf;
	item.cchTextMax = 64;
	TreeView_GetItem(m_hwndTree, &item);

	if (item.lParam != tntFtpSite)
		return;

	CeFtpSite site;

	if (! site.Find(szBuf))
		return;

	BOOL bConnect;

	{
		m_ftpConn.SetPassive(site.m_bPassive);

		CeWaitCursor wait;
		if (site.m_bAnon)
			bConnect = m_ftpConn.Connect(site.m_strAddress);
		else
			bConnect = m_ftpConn.Connect(site.m_strAddress, site.m_strUser, site.m_strPassword);
	}

	if (! bConnect)
	{
		CeString strErr = _T("Unable to establish a connection.\n");
		strErr += m_ftpConn.GetFtpErrorReplyString();
		MessageBox(strErr, _T("Connect to FTP Site"), MB_OK|MB_ICONWARNING);
		return;
	}
	else
	{
		if (! PopulateFilelist(hItem, m_ftpConn.GetRoot(), true))
		{
			// we will disconnect if we can't get a directory listing
			// on an initial connection
			m_ftpConn.Disconnect();
			bConnect = FALSE;
			return;
		}
		else
			MessageBox(_T("Connection established."), NULL, MB_OK|MB_ICONINFORMATION);

		m_hConnected = hItem;

		item.hItem = hItem;
		item.mask = TVIF_STATE | TVIF_CHILDREN;
		item.cChildren = I_CHILDRENCALLBACK;
		item.state = TVIS_BOLD;
		item.stateMask = TVIS_BOLD;
		TreeView_SetItem(m_hwndTree, &item);

		ASSERT(hItem != TreeView_GetRoot(m_hwndTree));
	}
}

/*
RasConnect()
{
	// Dial up the network via RAS
	// Get all available devices
//
//		CeRasDevInfoArray arDevInfo;
//		CeRasDevInfo::GetAll(arDevInfo);
//		if (arDevInfo.GetSize() <= 0)
//		{
//			LogEvent(EVENT_ERROR, _T("No Remote Access devices configured."));
//			throw Error(_T("No Remote Access devices configured."), IID_IWHCSRepository, REPOS_E_CONNECTION);
//		}
//
		// get all the available connections
		RASCONN* pConn;
		CeRasConn::GetAll(&pConn);

		// Go through all the available lines and find one we can connect on
		BOOL bFound = FALSE;
//		for (int ii = 0; ! bFound && ii < arDevInfo.GetSize(); ii++)
//		{
			for (int jj = 0; ! bFound && jj < arConn.GetSize(); jj++)
			{
				if (! _tcscmp(arConn[jj].szDeviceName, arDevInfo[ii].szDeviceName))
				{
					// break out the the inner loop, we found
					// the device active
					break;
				}
			}

			if (jj >= arConn.GetSize())
				// not found with the other active connections
				bFound = TRUE;
		}

//		if (! bFound)
		{
			// good generic error (actually no devices ready)
//			throw Error(_T("No Remote Access devices available."), IID_IWHCSRepository,
//				REPOS_E_DEVICE_UNAVAILABLE);
		}


		CeString strPhoneNumber("707-5772"), strAreaCode("612"), strCountryCode("1");

		// Set up the RAS entry
		CeRasEntry rasEntry(_T(""), strPhoneNumber, strAreaCode, strCountryCode);
		if (! m_strHCSIPAddr.IsEmpty())
		{
			rasEntry.ipaddr = CRASEntry::StringToRASIP(m_strHCSIPAddr);
			rasEntry.dwfOptions |= RASEO_SpecificIpAddr;
		}

		CeString strRASName("Desktop MAS");

		// remove any conflicting entry
		CeRasEntry ::Delete(strRASName);

		// create our new entry
		rasEntry.Set(strRASName, NULL);
//		rasEntry.SetWin95(m_strRASName, "", bSpeaker);

		// set up the dial out parameters
		LPCTSTR szUser = _T("Kenny"), szPassword = _T("Fred");
		CeRasDialParams rasParam(strRASName, szUser, szPassword);

		CeRasConn rasConn;
		rasConn.SetTimeout(150000U);

		DWORD dwFlags = RDEOPT_UsePrefixSuffix | RDEOPT_IgnoreModemSpeaker;
//		if (bSpeaker)
//			dwFlags |= RDEOPT_SetModemSpeaker;

		CeRasDialExt rasDialExt(dwFlags);

		// dial
		rasConn.Dial(&rasParam, TRUE, &rasDialExt);

//		CRASPppIp PppIp;
//		rasConn.GetProjectionInfo(&PppIp);

//		m_strHCSIPAddr = PppIp.szIpAddress;
//		if (m_strRCSIPAddr.IsEmpty())
//			// use the overrride address of the PPP server
//			m_strRCSIPAddr = PppIp.szServerIpAddress;

//		CString str;
//		str.Format("FMS IP: %s, RCS IP: %s", (LPCTSTR) m_strHCSIPAddr, (LPCTSTR) m_strRCSIPAddr);
	}
*/


void CeMainWnd::OnNewSite()
{
	CePropertyDlg dlg;
	CeFtpSite site;

	dlg.AddFtpSiteProperty(site);

	UINT uRet = dlg.DoModal(IDD_PROPERTY);

	CeString strName = dlg.m_pageFtp.m_site.m_strName;

	if (IDOK == uRet && ! strName.IsEmpty())
	{
		TVINSERTSTRUCT is;
		is.hParent = TreeView_GetRoot(m_hwndTree);
		is.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
		is.item.pszText = (LPTSTR) (LPCTSTR) strName;
		is.item.iImage = imFtpSite;
		is.item.iSelectedImage = imFtpSite;
		is.item.lParam = tntFtpSite;

		CeString str;
		HTREEITEM hAfter;
		for (hAfter = TreeView_GetChild(m_hwndTree, is.hParent); 
			 hAfter != NULL;
			 hAfter = TreeView_GetNextSibling(m_hwndTree, hAfter))
		{
			str = TreeView_GetItemText(m_hwndTree, hAfter);
			if (str.CompareNoCase(site.m_strName))
			{
				hAfter = TreeView_GetPrevSibling(m_hwndTree, hAfter);
				break;
			}
		}

		is.hInsertAfter = hAfter;
		
		TreeView_InsertItem(m_hwndTree, &is);
	}
}


TCHAR* g_szSmallTips[] =
{
	_T("Delete"),
	_T("New Folder"),
	_T("Properties"),
	_T("Options"),
	_T("Site Connect"),
	_T("Site Disconnect"),
	_T("About ftpView"),// no seperator skipping 
};

TBBUTTON g_tb[] =
{
	{0, ID_FILE_DELETE,			TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},
	{0, ID_FILE_NEW_FOLDER,		TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},
	{0, ID_FILE_PROPERTIES,		TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},
	{0, 0,						TBSTATE_ENABLED, TBSTYLE_SEP,    0, 0},
	{0, ID_ACTIONS_CONNECT,		TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},
	{0, ID_ACTIONS_DISCONNECT,	TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, 0},
};


void CeMainWnd::CreateBars()
{
#if defined(_WIN32_WCE_POCKETPC)

	#pragma comment(lib, "aygshell.lib")

	SHMENUBARINFO mbi;

	//set up menu bar structure
	memset(&mbi, 0, sizeof(SHMENUBARINFO));
	mbi.cbSize     = sizeof(SHMENUBARINFO);
	mbi.hwndParent = m_hWnd;
	mbi.nToolBarId = IDM_MENUNEW;
	mbi.hInstRes   = g_hInst;
	mbi.nBmpId     = IDB_MENUNEW;
	mbi.cBmpImages = 2;
	mbi.dwFlags    = 0; //SHCMBF_EMPTYBAR;

	if (!SHCreateMenuBar(&mbi))
	{
		DWORD dw = GetLastError();
		MessageBox(_T("SHCreateMenuBar Failed"), _T("Error"), MB_OK|MB_ICONERROR);
	}

	//m_hwndCmdBar = mbi.hwndMB;

#elif defined(_WIN32_WCE)

	HIMAGELIST hImage = ImageList_LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_SEPERATORS), 16, 0, RGB(0,255,255));
	m_cmdband.Create(m_hWnd, IDC_BAND, RBS_SMARTLABELS|RBS_VARHEIGHT|RBS_BANDBORDERS, hImage);

	REBARBANDINFO rbbi[2];
	memset(&rbbi, 0, sizeof rbbi);

	// specific init
	rbbi[0].cbSize = sizeof REBARBANDINFO;
	rbbi[0].wID    = IDC_MENU_BAND;
	rbbi[0].fMask  = RBBIM_ID|RBBIM_IMAGE|RBBIM_STYLE;
	rbbi[0].fStyle = RBBS_NOGRIPPER;
	rbbi[0].iImage = 0;

	rbbi[1].cbSize = sizeof REBARBANDINFO;
	rbbi[1].wID    = IDC_BUTTON_BAND;
	rbbi[1].fMask  = RBBIM_ID|RBBIM_IMAGE;
	rbbi[1].iImage = 1;

	if (m_cmdband.AddBands(2, rbbi))
	{
		// Add the menu bar first
		m_cmdband.GetCommandBar(0).InsertMenubar(IDM_MENUNEW, 0);

		// Need: properties, del db, del record, ...
		int nStd = m_cmdband.GetCommandBar(1).AddStdBitmap(IDB_STD_SMALL_COLOR);
		int nView = m_cmdband.GetCommandBar(1).AddStdBitmap(IDB_VIEW_SMALL_COLOR);
		int nLocal = m_cmdband.GetCommandBar(1).AddBitmap(IDB_HELP4, 1, 16, 16);
		m_cmdband.GetCommandBar(1).AddBitmap(IDB_OPTIONS4, 1, 16, 16);
		 
		g_tb[0].iBitmap = nStd + STD_DELETE;
		g_tb[1].iBitmap = nView + VIEW_NEWFOLDER;
		g_tb[2].iBitmap = nStd + STD_PROPERTIES;
		g_tb[4].iBitmap = nView + VIEW_NETCONNECT;
		g_tb[5].iBitmap = nView + VIEW_NETDISCONNECT;

		m_cmdband.GetCommandBar(1).AddButtons(sizeof(g_tb) / sizeof(TBBUTTON), g_tb);

		// Add tooltips for the buttons we added
	    m_cmdband.GetCommandBar(1).AddToolTips(sizeof(g_szSmallTips)/sizeof(TCHAR*), (LPTSTR) g_szSmallTips);
	}
#endif	// _WIN32_WCE
}

void CeMainWnd::LoadOptions()
{
	CeRegKey key;
	key.Create(HKEY_LOCAL_MACHINE, _T("Software\\Magenic\\FtpView"));

	DWORD bTmp;
	key.QueryValue(bTmp, _T("SysIcons"));	g_options.m_bUseSysIcons = (bTmp != 0);
	key.QueryValue(bTmp, _T("TrayIcon"));	g_options.m_bIconbar = (bTmp != 0);
	key.QueryValue(bTmp, _T("Close"));		g_options.m_bCloseButton = (bTmp != 0);
	key.QueryValue(bTmp, _T("ROM"));		g_options.m_bROM = (bTmp != 0);
	key.QueryValue(bTmp, _T("Hidden"));		g_options.m_bHidden = (bTmp != 0);
	key.QueryValue(bTmp, _T("ColType"));	g_options.m_bCol_Type = (bTmp != 0);
	key.QueryValue(bTmp, _T("ColDate"));	g_options.m_bCol_Date = (bTmp != 0);
	key.QueryValue(bTmp, _T("ColSize"));	g_options.m_bCol_Size = (bTmp != 0);
	key.QueryValue(bTmp, _T("ColAttrib"));	g_options.m_bCol_Attrib = (bTmp != 0);

	//Get the font back from the settings
	LOGFONT lf;
	DWORD dwByteCnt = sizeof(LOGFONT);
	if (S_OK == key.QueryValue((BYTE*) &lf, _T("Font"), &dwByteCnt))
	{
		if (sizeof(LOGFONT) == dwByteCnt)
		{
			// create an initial font from the LOGFONT structure written
			// out to the registry
			HFONT hFont = ::CreateFontIndirect(&lf);
			SetCtrlFont(hFont);
		}
	}
	key.QueryValue(m_dwFontSize, _T("FontSize"));
}


void CeMainWnd::StoreOptions()
{
	CeRegKey key;
	key.Create(HKEY_LOCAL_MACHINE, _T("Software\\Magenic\\FtpView"));

	if (NULL != m_hFont)
	{
		LOGFONT lf;
		::GetObject((HGDIOBJ) m_hFont, sizeof LOGFONT, &lf);

		DWORD dwByteCnt = sizeof(LOGFONT);
		key.SetValue((BYTE*) &lf, sizeof LOGFONT, _T("Font"));
	}

	key.SetValue(m_dwFontSize, _T("FontSize"));

	key.SetValue(g_options.m_bUseSysIcons, _T("SysIcons"));
	key.SetValue(g_options.m_bIconbar, _T("TrayIcon"));
	key.SetValue(g_options.m_bCloseButton, _T("Close"));
	key.SetValue(g_options.m_bROM, _T("ROM"));
	key.SetValue(g_options.m_bHidden, _T("Hidden"));
	key.SetValue(g_options.m_bCol_Type, _T("ColType"));
	key.SetValue(g_options.m_bCol_Date, _T("ColDate"));
	key.SetValue(g_options.m_bCol_Size, _T("ColSize"));
	key.SetValue(g_options.m_bCol_Attrib, _T("ColAttrib"));
}


BOOL CeMainWnd::OnCreate(LPCREATESTRUCT lpCS, bool& bHandled)
{
	bHandled = true;

	// get the version info
	GetVersionEx(&g_osvi);

	// Open the settings key
	LoadOptions();
	
	// Initialize our one automation function for 2.01 clients,
	// the DLL will stay loaded "forever"
	LoadProc((FARPROC*) &g_pfnVarDateFromStr, _T("VarDateFromStr"), _T(CEPLAT_WCE_OLEAUT32_DLL));

	// Add the tool bars
	CreateBars();

	// adjust client to their size
	CeRect rc;
	GetClientRect(&rc);

#if defined(_WIN32_WCE)
	if (m_cmdband)
		rc.top += m_cmdband.Height();
#endif

	CeRect rcTree, rcList;
	GetWindowPlacements(rc, rcTree, rcList);

	//
	DWORD dwStyle =	WS_VISIBLE | WS_CHILD |
		TVS_HASBUTTONS |
		TVS_HASLINES |
		TVS_EDITLABELS |
		TVS_NOTOOLTIPS |
		TVS_SHOWSELALWAYS ;

	m_hwndTree = CreateWindowEx(0 /*WS_EX_CLIENTEDGE*/,
		WC_TREEVIEW, NULL, dwStyle, 
		rcTree.left, rcTree.top, rcTree.Width(), rcTree.Height(),
		*this, (HMENU) IDC_TREE, g_hInst, NULL);

	::SendMessage(m_hwndTree, WM_SETFONT, (WPARAM) m_hFont, TRUE);

	// Create the image list
	HIMAGELIST hImages;
	hImages = ImageList_LoadImage(g_hInst, MAKEINTRESOURCE(IDB_IMAGELIST),
		16, 0, RGB(255,255,255), IMAGE_BITMAP, 0);
	TreeView_SetImageList(m_hwndTree, hImages, TVSIL_NORMAL);
	TreeView_SetImageList(m_hwndTree, hImages, TVSIL_STATE);

	m_hImages = ImageList_LoadImage(g_hInst, MAKEINTRESOURCE(IDB_IMAGELIST),
		16, 0, RGB(255,255,255), IMAGE_BITMAP, 0);

	InitTree();

	// Create the list view
	dwStyle = WS_VISIBLE | WS_CHILD |
		LVS_EDITLABELS |
		LVS_REPORT |
		LVS_SINGLESEL ;

	if (g_options.m_bUseSysIcons)
		dwStyle |= LVS_SHAREIMAGELISTS;

	m_hwndList = CreateWindowEx(0 /*WS_EX_CLIENTEDGE*/,
		WC_LISTVIEW, NULL, dwStyle, 
		rcList.left, rcList.top, rcList.Width(), rcList.Height(),
		*this, (HMENU) IDC_LIST, g_hInst, NULL);

	::SendMessage(m_hwndList, WM_SETFONT, (WPARAM) m_hFont, TRUE);

	// initialize sort list
	g_sortinfo.hwndList = m_hwndList;

	// causes weird effects with drag and drop
//	ListView_SetExtendedListViewStyle(m_hwndList, LVS_EX_FULLROWSELECT);

	// Add the columns
	AddColumns();

	// Set the image list
	if (g_options.m_bUseSysIcons)
	{
		SHFILEINFO shinfo;
		memset(&shinfo, 0, sizeof shinfo);
		HIMAGELIST hSysImages = (HIMAGELIST) SHGetFileInfo(_T(".ZZZ"), 0, &shinfo, sizeof shinfo,
			SHGFI_SYSICONINDEX | SHGFI_ICON | SHGFI_SMALLICON | SHGFI_USEFILEATTRIBUTES);
		ListView_SetImageList(m_hwndList, hSysImages, LVSIL_SMALL);
	}
	else
	{
		ListView_SetImageList(m_hwndList, hImages, LVSIL_SMALL);
	}

    // Add Close button
	if (m_cmdband && g_options.m_bCloseButton)
	{
		m_cmdband.AddAdornments(0 /*CMDBAR_HELP*/, NULL);
	}

	// Set the panes
	SetPanes(m_hwndTree, m_hwndList);

	// Show or hide the icon bar
	ShowIconBar(g_options.m_bIconbar);

	// set focus to the root of the tree
	TreeView_SelectItem( m_hwndTree, TreeView_GetRoot(m_hwndTree) );
	::SetFocus(m_hwndTree);

	// Done
	return TRUE;
}


void CeMainWnd::InitTree()
{
	TreeView_DeleteAllItems(m_hwndTree);

	// initialize the tree
	TVINSERTSTRUCT is;
	is.hInsertAfter = TVI_SORT;
	is.hParent = TVI_ROOT;
	is.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_PARAM | TVIF_SELECTEDIMAGE;
	if ( CeIsPPC() || CeIsPocketPC() )
		is.item.pszText = _T("My Palm");
	else
		is.item.pszText = _T("My Hand");
	is.item.lParam = tntDesktop;
	is.item.iSelectedImage = is.item.iImage = imDesktop;

	HTREEITEM hRoot = TreeView_InsertItem(m_hwndTree, &is);

	is.hParent = hRoot;
	is.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_CHILDREN | TVIF_PARAM | TVIF_SELECTEDIMAGE;
	is.hInsertAfter = TVI_FIRST;
	is.item.cChildren = I_CHILDRENCALLBACK;
	is.item.lParam = tntDevice;
	is.item.pszText = _T("My Pocket PC");
	if (CeIsPPC() || CeIsPocketPC())
	{
		is.item.iSelectedImage = is.item.iImage = imPPC;
	}
	else if (CeIsHPCPro())
	{
		is.item.iSelectedImage = is.item.iImage = imHPCPro;
	}
	else
	{
		is.item.iSelectedImage = is.item.iImage = imHPC;
	}
	TreeView_InsertItem(m_hwndTree, &is);

	PopulateFtpSites(hRoot);

	TreeView_Expand(m_hwndTree, hRoot, TVE_EXPAND);
}


void CeMainWnd::AddColumns()
{
	while (ListView_DeleteColumn(m_hwndList, 0))
		;

	int nCol = 0;
	LVCOLUMN col;

	col.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH; 
	col.fmt = LVCFMT_LEFT;
	col.cx = 88;
	col.pszText = _T("Name");
	ListView_InsertColumn(m_hwndList, nCol++, &col);

	int nColType;
	g_arColumns.Add(nColType = SORTCOL_NAME);

	if (g_options.m_bCol_Size)
	{
		col.fmt = LVCFMT_RIGHT;
		col.cx = 60;
		col.pszText = _T("Size");
		ListView_InsertColumn(m_hwndList, nCol++, &col);

		g_arColumns.Add(nColType = SORTCOL_SIZE);
	}

	if (g_options.m_bCol_Type)
	{
		col.fmt = LVCFMT_LEFT;
		col.cx = 80;
		col.pszText = _T("Type");
		ListView_InsertColumn(m_hwndList, nCol++, &col);

		g_arColumns.Add(nColType = SORTCOL_TYPE);
	}

	if (g_options.m_bCol_Date)
	{
		col.fmt = LVCFMT_LEFT;
		col.cx = 90;
		col.pszText = _T("Modified");
		ListView_InsertColumn(m_hwndList, nCol++, &col);

		g_arColumns.Add(nColType = SORTCOL_DATE);
	}

	if (g_options.m_bCol_Attrib)
	{
		col.fmt = LVCFMT_RIGHT;
		col.cx = 40;
		col.pszText = _T("Attributes");
		ListView_InsertColumn(m_hwndList, nCol++, &col);

		g_arColumns.Add(nColType = SORTCOL_ATTRIB);
	}
}



void CeMainWnd::ShowIconBar(bool bShow)
{
	// Set up the icon in the taskbar for bring us to the front
	m_nid.cbSize	= sizeof NOTIFYICONDATA;
	m_nid.hWnd		= m_hWnd;
	m_nid.uID		= IDI_APPICON;
	m_nid.uFlags	= NIF_MESSAGE | NIF_TIP;
	m_nid.uCallbackMessage = WM_USER + 1000;

	if (bShow)
	{
		m_nid.uFlags |= NIF_ICON;
		m_nid.hIcon	= (HICON) LoadImage(CeGetAppInstance(),
			MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 16, 16, 0);

		Shell_NotifyIcon(NIM_ADD, &m_nid);
	}
	else
	{
		Shell_NotifyIcon(NIM_DELETE, &m_nid);
	}
}


void CeMainWnd::OnOptions()
{
	CeOptionsDlg dlg;

	dlg.m_bSysIcons = g_options.m_bUseSysIcons;
	dlg.m_bClose = g_options.m_bCloseButton;
	dlg.m_bIconbar = g_options.m_bIconbar;
	dlg.m_bROM = g_options.m_bROM;
	dlg.m_bHidden = g_options.m_bHidden;

	dlg.m_bCol_Type = g_options.m_bCol_Type;
	dlg.m_bCol_Size = g_options.m_bCol_Size;
	dlg.m_bCol_Date = g_options.m_bCol_Date;
	dlg.m_bCol_Attrib = g_options.m_bCol_Attrib;

	if (IDOK == dlg.DoModal())
	{
		if (g_options.m_bCol_Type != dlg.m_bCol_Type ||
			g_options.m_bCol_Size != dlg.m_bCol_Size ||
			g_options.m_bCol_Date != dlg.m_bCol_Date ||
			g_options.m_bCol_Attrib != dlg.m_bCol_Attrib)
		{
			g_options.m_bCol_Type = dlg.m_bCol_Type;
			g_options.m_bCol_Size = dlg.m_bCol_Size;
			g_options.m_bCol_Date = dlg.m_bCol_Date;
			g_options.m_bCol_Attrib = dlg.m_bCol_Attrib;

			AddColumns();
			RefreshList();
		}

		if (g_options.m_bIconbar != dlg.m_bIconbar)
		{
			g_options.m_bIconbar = dlg.m_bIconbar;
			// Show or hide the icon bar
			ShowIconBar(g_options.m_bIconbar);
		}
		
		if (g_options.m_bROM != dlg.m_bROM ||
			g_options.m_bHidden != dlg.m_bHidden)
		{
			g_options.m_bROM = dlg.m_bROM;
			g_options.m_bHidden = dlg.m_bHidden;
			RefreshList();
		}

		// must be done after restart
		g_options.m_bUseSysIcons = dlg.m_bSysIcons;
		g_options.m_bCloseButton = dlg.m_bClose;
	}
}


void CeMainWnd::OnFont()
{
	LOGFONT logfont;
	if (NULL == m_hFont)
	{
		m_dwFontSize = 9;
		GetObject(GetStockObject(SYSTEM_FONT), sizeof LOGFONT, &logfont);
	}
	else
	{
		GetObject(m_hFont, sizeof LOGFONT, &logfont);
	}

	CeFontDlg dlg(m_dwFontSize, &logfont);

	if (IDOK == dlg.DoModal(IDD_FONTDLG))
	{
		SetCtrlFont(dlg.m_hFont);
		m_dwFontSize = dlg.m_nPointSize;
	}
}

void CeMainWnd::SetCtrlFont(HFONT hFont)
{
	if (m_hFont)
		::DeleteObject(m_hFont);

	if (NULL == hFont)
	{
		m_hFont = NULL;
		return;
	}

	LOGFONT logfont;
	GetObject(hFont, sizeof logfont, &logfont);
	m_hFont = ::CreateFontIndirect(&logfont);
	::SendMessage(m_hwndTree, WM_SETFONT, (WPARAM) m_hFont, TRUE);
	::SendMessage(m_hwndList, WM_SETFONT, (WPARAM) m_hFont, TRUE);
}


void CeMainWnd::OnAbout()
{
	CeAboutDlg dlg;
	dlg.DoModal();
}

void CeMainWnd::OnProperties()
{
	HWND hwndFocus = GetFocus();

	WIN32_FIND_DATA fd;
	CePropertyDlg dlg;

	CeString strFullName;
	CeString strName;
	
	if (hwndFocus == m_hwndList)
	{
		int nSel = ListView_GetNextItem(m_hwndList, -1, LVIS_SELECTED);
		if (nSel < 0)
			// list has focus but no selection, go away
			return;

		ListView_GetItemText(m_hwndList, nSel, 0, strName.GetBufferSetLength(64), 64);
		strName.ReleaseBuffer();

		strFullName = m_strCurrentDirectory;
		strFullName += strName;

		if (m_bCurrentFtp)
		{
			m_ftpConn.GetFileInfo(strFullName, fd);
		}
		else
		{
			CeFindFile ff;
			if (ff.FindFirst(strFullName))
				fd = ff;
		}

		dlg.AddFileProperty(m_strCurrentDirectory, fd, !m_bCurrentFtp);
	}
	else if (hwndFocus == m_hwndTree)
	{
		HTREEITEM hItem = TreeView_GetSelection(m_hwndTree);
		if (NULL == hItem || !m_strCurrentDirectory.Length())
			return;

		strFullName = CeString((LPCTSTR) m_strCurrentDirectory, m_strCurrentDirectory.Length() - 1);
		strName = TreeView_GetItemText(m_hwndTree, hItem);

		eTreeNodeType eType = (eTreeNodeType) TreeView_GetLParam(m_hwndTree, hItem);

		if (tntFtpSite == eType)
		{
			// edit the ftp site properties

			CeFtpSite site;
			if (! site.Find(strName))
				return;

			dlg.AddFtpSiteProperty(site);
		}
		else if (tntDesktop == eType)
		{
			dlg.AddSystemProperty();
			dlg.AddTaskProperty();
		}
		else if (tntFtpSiteDir == eType)
		{
			memset(&fd, 0, sizeof fd);
			fd.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;

			dlg.AddFileProperty(strFullName, fd, false);
		}
		else if (tntLocalDir == eType)
		{
			bool bPath;
			HTREEITEM hParent = TreeView_GetParent(m_hwndTree, hItem);
			CeString strTmp = GetTreePath(hParent, bPath);

			CeFindFile ff;
			if (ff.FindFirst(strFullName))
				fd = ff;

			dlg.AddFileProperty(strTmp, fd, true);
		}
		else if (tntDevice == eType)
		{
			dlg.AddSystemProperty();
			dlg.AddTaskProperty();
		}
	}
	else
	{
		// focus is gone somewhere
		return;
	}

	if (IDOK == dlg.DoModal(IDD_PROPERTY))
	{
		if (hwndFocus == m_hwndList)
		{
			// refresh the current list item
			int nSel = ListView_GetNextItem(m_hwndList, -1, LVIS_SELECTED);

			ListView_DeleteItem(m_hwndList, nSel);
			InsertFile(m_strCurrentDirectory, &dlg.m_pageFile.m_finddata, FALSE, nSel);
			ListView_SetItemState(m_hwndList, nSel, LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED);
		}
		else
		{
			// tree had focus, copy new name if there was one
		}
	}

	// place focus back on the previous location
	::SetFocus(hwndFocus);
}


void CeMainWnd::OnDestroy(bool& bHandled)
{
	StoreOptions();

	// Remove the icon in the taskbar for bring us to the front
	Shell_NotifyIcon(NIM_DELETE, &m_nid);

	bHandled = true;
	PostQuitMessage(0);
}


void CeMainWnd::OnClose(bool& bHandled)
{
	bHandled = true;
	if (m_ftpConn.IsConnected())
		m_ftpConn.Disconnect();
	DestroyWindow();
}


void CeMainWnd::OnSettingChange( WORD wFlag, LPCTSTR pszSection, bool& bHandled )
{
#if defined(_WIN32_WCE_POCKETPC)

	s_sai.cbSize = sizeof s_sai;
  	SHHandleWMSettingChange(m_hWnd, wFlag, (long) pszSection, &s_sai);
	bHandled = true;

#elif defined(_WIN32_WCE_PSPC)

	switch (wFlag)
	{
	case SPI_SETSIPINFO:
		{
			SIPINFO si;
			memset( &si, 0, sizeof( si ) );
			si.cbSize = sizeof( si );
			if( SHSipInfo( SPI_GETSIPINFO, 0, &si, 0 ) ) 
			{
				MoveWindow(
					si.rcVisibleDesktop.left,
					si.rcVisibleDesktop.top,
					si.rcVisibleDesktop.right - si.rcVisibleDesktop.left,
					si.rcVisibleDesktop.bottom -
					si.rcVisibleDesktop.top,
					TRUE );
			}
		}
		break;
	default:
		break;
	}

#endif // _WIN32_PPC_

}


void CeMainWnd::OnSetFocus(HWND hWndOld)
{
	::SetFocus(m_hwndLast);

	TRACE0("SetFocus()\n");
}

#pragma comment(lib, "note_prj.lib")

LRESULT CeMainWnd::OnMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, bool& bHandled)
{
	switch (uMsg)
	{

	// A bit of a a hack for simplicity, but it works for the most part
	// it detects a change in the number of flash devices and uses that to
	// know if it should refresh.  It has the potential of being wrong if
	// the power goes off and a flash card is changed and then re-powered
	case WM_FTPVIEW_CARDNOTIFY:
		{
			extern int g_nFlashDevices;
			int nFlash = 0;
			CeFindFile ff;
			if ( ff.FindFirstFlash() )
			{
				nFlash++;
				for ( ; ff.FindNextFlash() ; )
					nFlash++;
			}

			if (g_nFlashDevices != nFlash)
				OnRefresh();

			g_nFlashDevices = nFlash;
			break;
		}

	case WM_HELP:
		{
		//	PROCESS_INFORMATION pi;
		//	::CreateProcess(_T("peghelp.exe"), _T("file:BeamEx.htc"),
		//		NULL, NULL, FALSE, 0, NULL, NULL, NULL, &pi);
		//	CloseHandle(pi.hProcess);
		//	CloseHandle(pi.hThread);
		}
		break;

	case WM_SETFOCUS:
		OnSetFocus((HWND) wParam);
		break;

	case WM_USER + 1000:
		{
			bHandled = true;
			if (lParam == WM_LBUTTONUP || lParam == WM_LBUTTONDBLCLK)
			{
				SetForegroundWindow (m_hWnd);    
			}
			else if (lParam == WM_LBUTTONDOWN)
			{
				;
			}
		}
	}
	return 1;
}


LRESULT CeMainWnd::OnNotify(int nCtrlId, LPNMHDR pNMH, bool& bHandled)
{
	bHandled = false;
	LRESULT  bRet = FALSE;	// default
	if (IDC_TREE == nCtrlId)
	{
		bRet = OnTreeViewNotify((LPNMTREEVIEW) pNMH);
		bHandled = true;
	}
	else if (IDC_LIST == nCtrlId)
	{
		bRet = OnListViewNotify((NMLISTVIEW*) pNMH);
		bHandled = true;
	}
	else if (IDC_BAND == nCtrlId)
	{
	    if (pNMH->code == RBN_HEIGHTCHANGE)
		{
			CeRect rc;
			GetClientRect(&rc);
			rc.top += m_cmdband.Height();

			CeRect rcTree, rcList;
			GetWindowPlacements(rc, rcTree, rcList);

			::MoveWindow(m_hwndList, rcList.left, rcList.top, 
				rcList.Width(), rcList.Height(), TRUE);

			::MoveWindow(m_hwndTree, rcTree.left, rcTree.top, 
				rcTree.Width(), rcTree.Height(), TRUE);
			//TRACE0("Size Change\n");
		}
	}

	return bRet;
}


LRESULT CeMainWnd::OnListViewNotify(NMLISTVIEW* pNMLV)
{
	LV_DISPINFO* pDI = (LV_DISPINFO *) pNMLV;
	NMKEY* pNMK = (NMKEY*) pNMLV;

	switch (pNMLV->hdr.code)
	{
	case NM_KEYDOWN:
		// here for future ab(use) currently not sent by this control (ala 2.11)
		if (pNMK->wVKey == VK_DELETE)
			OnDelete();
		else if (pNMK->wVKey == VK_RETURN)
			OnRun();
		break;

	case NM_SETFOCUS:
		TRACE0("OnListViewNotify: SetFocus()\n");
		m_hwndLast = m_hwndList;
		break;

	case NM_KILLFOCUS:
		TRACE0("OnListViewNotify: KillFocus()\n");
		break;
	case NM_DBLCLK:
		OnRun();
		break;

	case LVN_BEGINDRAG:
        // Notifies the tree view control's parent window that a drag 
        // and drop operation is being initiated. 
		OnBeginDragList(pNMLV);
        return 0;

	case LVN_COLUMNCLICK:
		OnColumnClick(pNMLV);
		break;

	case LVN_ENDLABELEDIT:
		{
			// rename the current list entry
			if (NULL == pDI->item.pszText)
				// cancelled
				return FALSE;

			//get the old file name
			CeString strFile;
			ListView_GetItemText(m_hwndList, pDI->item.iItem, 0, strFile.GetBuffer(120), 120);
			strFile.ReleaseBuffer();

			CeString strOld = m_strCurrentDirectory;
			CeString strNew = m_strCurrentDirectory;

			strNew += pDI->item.pszText;
			strOld += strFile;

			if (m_bCurrentFtp)
			{
				if (! m_ftpConn.RenameFile(strOld, strNew))
				{
					CeString strErr = m_ftpConn.GetFtpErrorReplyString();
					MessageBox(strErr, _T("FTP rename failed!"), MB_OK|MB_ICONERROR);
					return FALSE;
				}
			}
			else
			{
				if (! MoveFile(strOld, strNew))
				{
					CeString strErr;
					strErr.Format(_T("Error %lu while renaming."), GetLastError());
					MessageBox(strErr, _T("Rename failed!"), MB_OK|MB_ICONERROR);
					return FALSE;
				}
			}

			WIN32_FIND_DATA fd;
			if (m_bCurrentFtp)
			{
				m_ftpConn.GetFileInfo(strNew, fd);
			}
			else
			{
				CeFindFile ff;
				if (ff.FindFirst(strNew))
					fd = ff;
			}

			//
			// Update 
			int nSel = ListView_GetNextItem(m_hwndList, -1, LVIS_SELECTED);
			ListView_DeleteItem(m_hwndList, nSel);
			InsertFile(m_strCurrentDirectory, &fd, FALSE, nSel);
			ListView_SetItemState(m_hwndList, nSel, LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED);
		}
		break;

	case LVN_BEGINLABELEDIT:
		return FALSE;
/*
	Causes strange behaviour, need to work on this
	case NM_CLICK:
		{
			//check with the tree control to see if we are on an item
			LVHITTESTINFO lvht;
			//lvht.flags = LVHT_ONITEM;
			lvht.pt = pNMLV->ptAction;
			::ScreenToClient(m_hwndList, &(lvht.pt));

			int nItem = ListView_HitTest(m_hwndList,&lvht);
			if ( nItem >= 0 )
			{
				ListView_SetItemState(m_hwndList, nItem, LVIS_FOCUSED|LVIS_SELECTED,
					LVIS_FOCUSED|LVIS_SELECTED);
			}
		}
		// fall through to execution
*/
/*
    Conflicts with the drag and drop handling built in to the list
	case GN_CONTEXTMENU:
		{
			TRACE0("OnListViewNotify: GN_CONTEXTMENU\n");

			//check with the tree control to see if we are on an item
			LVHITTESTINFO lvht;
			lvht.flags = LVHT_ONITEM;
			lvht.pt = pNMLV->ptAction;

			int nItem = ListView_HitTest(m_hwndList,&lvht);
			if ( nItem >= 0 )
			{
				ListView_SetItemState(m_hwndList, nItem, LVIS_FOCUSED|LVIS_SELECTED,
					LVIS_FOCUSED|LVIS_SELECTED);
			}

			HMENU hMenu = CreatePopupMenu();

			AppendMenu(hMenu, MF_STRING|MF_ENABLED, ID_FILE_OPEN, _T("Open"));
			AppendMenu(hMenu, MF_STRING|MF_ENABLED, ID_FILE_PROPERTIES, _T("Properties"));
			AppendMenu(hMenu, MF_STRING|MF_ENABLED, ID_FILE_DELETE, _T("Delete"));
			AppendMenu(hMenu, MF_STRING|MF_ENABLED, ID_FILE_RENAME, _T("Rename"));

			NMRGINFO* pnmhdr = (NMRGINFO*) pNMLV;
			POINT point = pnmhdr->ptAction;

			TrackPopupMenu(hMenu, TPM_RIGHTALIGN|TPM_TOPALIGN, point.x, point.y, 0, m_hWnd, NULL);

			DestroyMenu(hMenu);
		}
		return FALSE;
*/
	default:
		TRACE2(_T("Unhandled WM_NOTIFY to LIST 0x%x or 0x%x:\n"), pNMLV->hdr.code, 
			(UINT) 0 - pNMLV->hdr.code);
		break;
	}

	return 0;
}


void CeMainWnd::OnRefresh()
{
	RefreshTree();
}


void CeMainWnd::RefreshTree()
{
	InitTree();
	RefreshList();
}


void CeMainWnd::RefreshList()
{
	// Create a directory name going backward using the path, and determine
	// if the selected node is on an FTP site
	bool bFtp;
	HTREEITEM hItem = TreeView_GetSelection(m_hwndTree);

	CeString strDir = GetTreePath(hItem, bFtp);

	PopulateFilelist(hItem, strDir, bFtp);
}


BOOL CeMainWnd::Execute(LPCTSTR lpszDir, LPCTSTR lpszFile)
{
	if (0 == *lpszDir)
		return FALSE;

	CeString str(lpszDir);
	if (str[str.Length() - 1] != _T('\\'))
		str += _T('\\');
	str += lpszFile;

	SHELLEXECUTEINFO sei;
	memset(&sei, 0, sizeof(sei));
	sei.cbSize = sizeof sei;
	sei.nShow = SW_SHOWNORMAL;
	sei.lpVerb = _T("open");
	sei.fMask = 0; // Allow function to put up an error SEE_MASK_FLAG_NO_UI;
	sei.lpFile = str;

	return ShellExecuteEx(&sei);
}


LRESULT CeMainWnd::OnTreeViewNotify(NMTREEVIEW* pNMTV)
{
	bool bFtp;

	HTREEITEM hRoot = TreeView_GetRoot(m_hwndTree);

	switch (pNMTV->hdr.code)
	{
	case NM_KEYDOWN:
		{
			// here for future ab(use) currently not sent by this control (ala 2.11)
			NMKEY* pNMK = (NMKEY*) pNMTV;
			if (pNMK->wVKey == VK_DELETE)
				OnDelete();
			else if (pNMK->wVKey == VK_RETURN)
				OnRun();
		}
		break;

	case NM_SETFOCUS:
		TRACE0("OnTreeViewNotify: SetFocus()\n");
		m_hwndLast = m_hwndTree;
		break;

	case NM_KILLFOCUS:
		TRACE0("OnTreeViewNotify: KillFocus()\n");
		break;

	case NM_DBLCLK:
		{
			HTREEITEM hItem = TreeView_GetSelection(m_hwndTree);
			eTreeNodeType eType = (eTreeNodeType) TreeView_GetLParam(m_hwndTree, hItem);
			switch (eType)
			{
			case tntFtpSite:
				if (m_ftpConn.IsConnected() && hItem == m_hConnected)
					OnDisconnect();
				else
					OnConnect();
				break;
			}
		}
		break;

    case TVN_BEGINDRAG:
        // a drag operation has been initiated. 
        OnBeginDragTree(pNMTV);
        return FALSE;

    case TVN_BEGINLABELEDIT:
		{
			// an edit operation has been initiated. 
			TV_DISPINFO* pTVDI = (TV_DISPINFO*) pNMTV;

			bool bFtp;
			CeString strDir = GetTreePath(pTVDI->item.hItem, bFtp);

			if (strDir.IsEmpty() || (strDir == _T("\\") && ! bFtp))
				// don't allow renaming the roots...
				return TRUE;
		}			
		return FALSE;

	case TVN_ENDLABELEDIT:
		{
			TV_DISPINFO* pTVDI = (TV_DISPINFO*) pNMTV;
			if (pTVDI->item.pszText == NULL || *pTVDI->item.pszText == 0)
				return TRUE;

			bool bFtp;
			HTREEITEM hParent = TreeView_GetParent(m_hwndTree, pTVDI->item.hItem);
			CeString strDir = GetTreePath(hParent, bFtp);

			CeString strNew = strDir;
			CeString strOld = strDir;

			strNew += pTVDI->item.pszText;
			strOld += TreeView_GetItemText(m_hwndTree, pTVDI->item.hItem);

			if (pTVDI->item.lParam == tntFtpSite || bFtp)
			{
				if (strDir.IsEmpty())
				{
					if (strNew.IsEmpty() || strOld.IsEmpty())
						// ignore
						return TRUE;

					if (! CeFtpSite::Rename(strOld, strNew))
						//
						return FALSE;
				}
				else if (! m_ftpConn.RenameFile(strOld, strNew))
				{
					MessageBox(m_ftpConn.GetFtpErrorReplyString(), _T("FTP RENAME failed"), MB_OK|MB_ICONERROR);
					return FALSE;
				}

				return TRUE;
			}
			else
			{
				if (! MoveFile(strOld, strNew))
				{
					CeString strErr;
					strErr.Format(_T("Error %lu while renaming."), GetLastError());
					MessageBox(strErr, _T("Rename failed!"), MB_OK|MB_ICONERROR);
					return FALSE;
				}
				else
					return TRUE;
			}
		}
	    return FALSE;

	case TVN_SELCHANGED:
		if (pNMTV->action == TVC_BYKEYBOARD || pNMTV->action == TVC_BYMOUSE)
		{
			//TRACE0("Tree item changed\n");

			// Create a directory name going backward using the path, and determine
			// if the selected node is on an FTP site
			CeString strDir = GetTreePath(pNMTV->itemNew.hItem, bFtp);
			PopulateFilelist(pNMTV->itemNew.hItem, strDir, bFtp);
		}
		break;

	case TVN_GETDISPINFO:
		{
			TV_DISPINFO* pTVDI = (TV_DISPINFO*) pNMTV;

			//TRACE0("Tree item dispinfo request\n");

			if (pTVDI->item.mask & TVIF_CHILDREN)
				pTVDI->item.cChildren = I_CHILDRENCALLBACK;
		}
		break;

	// A directory node has been collapsed.  Now we can remove the child items
	// from the node.
	case TVN_ITEMEXPANDED:
		if (pNMTV->action == TVE_COLLAPSE)
		{
			// Now actually remove the child items within this directory
			if (pNMTV->itemNew.lParam == tntDesktop)
				// skip the root all items there are added manually
				return 0;

			//TRACE0("Tree item collapsed\n");
			
			//HTREEITEM hItem;
			//while (NULL != (hItem = TreeView_GetChild(m_hwndTree, pNMTV->itemNew.hItem)))
			//	TreeView_DeleteItem(m_hwndTree, hItem);

			HTREEITEM hSel = TreeView_GetSelection(m_hwndTree);

			// Create a directory name going backward using the path, and determine
			// if the selected node is on an FTP site
			bool bFtp;
			CeString strDir = GetTreePath(hSel, bFtp);
			PopulateFilelist(hSel, strDir, bFtp);
		}
		break;

	// A node is expanding or collapsing.  We need to update the folder
	// images to reflect either a closed or open folder depending on it's
	// new state.
	case TVN_ITEMEXPANDING:
		if (pNMTV->action == TVE_COLLAPSE || pNMTV->action == TVE_COLLAPSERESET)
		{
			if (pNMTV->itemNew.hItem == hRoot)
				// skip the root all items there are added manually
				return 1;

			//TRACE0("Tree item collapsing\n");
		}
		else
		{
			//TRACE0("Item expanding\n");

			if (pNMTV->itemNew.hItem == TreeView_GetRoot(m_hwndTree))
				// skip the root all items there are added manually
				return 0;

			if (! (pNMTV->itemNew.state & TVIS_EXPANDEDONCE))
			{
				// one time addition
				//TRACE0("Item expanding\n");
				
				//
				// Create a directory name going backward using the path
				//
				CeString strDir = GetTreePath(pNMTV->itemNew.hItem, bFtp);
				BOOL bSubs = PopulateDirectory(pNMTV->itemNew.hItem, strDir, bFtp);

				// Retrieve the image from the current item
				pNMTV->itemNew.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN | TVIF_PARAM;
				TreeView_GetItem(m_hwndTree, &(pNMTV->itemNew));

				pNMTV->itemNew.mask = TVIF_CHILDREN;
				pNMTV->itemNew.cChildren = bSubs ? 1: 0;

				TreeView_SetItem(m_hwndTree, &(pNMTV->itemNew));
			}
		}
		break;

	case NM_CLICK:
		TRACE0("NM_CLICK\n");
		break;

/*
    Conflicts with the drag and drop handling built in to the list
	case GN_CONTEXTMENU:
		{
			TRACE0("OnTreeViewNotify: GN_CONTEXTMENU\n");

			NMRGINFO* pnmhdr = (NMRGINFO*) pNMTV;
			POINT point = pnmhdr->ptAction;

			TV_HITTESTINFO hti;
			hti.pt = point;
			::ScreenToClient(m_hwndTree, &hti.pt);
			HTREEITEM hHit = TreeView_HitTest(m_hwndTree, &hti);

			// Build a standard popup, depending on the tree type
			HTREEITEM hItem = TreeView_GetSelection(m_hwndTree);
			if (! hItem || ! hHit)
				return FALSE;

			if (hItem != hHit)
			{
				TRACE0("OnTreeViewNotify: Item Changed\n");
				TreeView_SelectItem(m_hwndTree, hHit);
				hItem = hHit;

				// Fix the list
				OnRefresh();
			}

			HMENU hMenu = CreatePopupMenu();

			eTreeNodeType eType = (eTreeNodeType) TreeView_GetLParam(m_hwndTree, hItem);
			switch (eType)
			{
			case tntDesktop:
				AppendMenu(hMenu, MF_STRING|MF_ENABLED, ID_FILE_PROPERTIES, _T("Properties"));
				break;

			case tntDevice:
				AppendMenu(hMenu, MF_STRING|MF_ENABLED, ID_FILE_PROPERTIES, _T("Properties"));
				AppendMenu(hMenu, MF_STRING|MF_ENABLED, ID_ACTIONS_NEWSITE, _T("New Site..."));
				break;

			case tntLocalDir:
			case tntFtpSiteDir:
				AppendMenu(hMenu, MF_STRING|MF_ENABLED, ID_FILE_PROPERTIES, _T("Properties"));
				AppendMenu(hMenu, MF_STRING|MF_ENABLED, ID_FILE_DELETE, _T("Delete"));
				AppendMenu(hMenu, MF_STRING|MF_ENABLED, ID_FILE_RENAME, _T("Rename"));
				AppendMenu(hMenu, MF_STRING|MF_ENABLED, ID_FILE_NEW_FOLDER, _T("New Folder"));
				break;

			case tntFtpSite:
				if (! m_ftpConn.IsConnected())
				{
					AppendMenu(hMenu, MF_STRING|MF_ENABLED, ID_FILE_PROPERTIES, _T("Properties"));
					AppendMenu(hMenu, MF_STRING|MF_ENABLED, ID_FILE_DELETE, _T("Delete"));
					AppendMenu(hMenu, MF_STRING|MF_ENABLED, ID_FILE_RENAME, _T("Rename"));
				}
				else 
				{
					if (hItem == m_hConnected)
						AppendMenu(hMenu, MF_STRING|MF_ENABLED, ID_ACTIONS_DISCONNECT, _T("Disconnect"));
					else
						AppendMenu(hMenu, MF_STRING|MF_ENABLED, ID_ACTIONS_CONNECT, _T("Connect"));
				}
				break;
			}

			TrackPopupMenu(hMenu, TPM_RIGHTALIGN|TPM_TOPALIGN, point.x, point.y, 0, m_hWnd, NULL);
			DestroyMenu(hMenu);
		}
		return FALSE;
*/
	default:
		TRACE2(_T("Unhandled WM_NOTIFY to TREE 0x%x or 0x%x:\n"), pNMTV->hdr.code, 
			(UINT) 0 - pNMTV->hdr.code);
		break;
	}

	return 0;
}


CeString CeMainWnd::GetTreePath(HTREEITEM hDir, bool& bFtp)
{
	// assume failure
	bFtp = false;

	TVITEM tvi;
	TCHAR szBuf[MAX_PATH];
	tvi.mask = TVIF_TEXT | TVIF_PARAM;
	tvi.pszText = szBuf;
	tvi.cchTextMax = MAX_PATH;
	tvi.hItem = hDir;
	
	CeString strDir;
	CeString strTmp;

	while (TreeView_GetItem(m_hwndTree, &tvi) && tvi.lParam != tntDesktop)
	{
		if (tvi.lParam == tntFtpSite)
			bFtp = true;

		if (tvi.lParam == tntLocalDir || tvi.lParam == tntFtpSiteDir)
		{
			strTmp = tvi.pszText;
			strTmp += _T("\\");

			strDir = strTmp + strDir;
		}
		else if (tvi.lParam == tntFtpSite || tvi.lParam == tntDevice)
		{
			strTmp = _T("\\");

			strDir = strTmp + strDir;
		}

		// the NEXT node up the tree
		tvi.hItem = TreeView_GetParent(m_hwndTree, tvi.hItem);

		TreeView_GetItem(m_hwndTree, &tvi);
	}

	if (strDir.IsEmpty())
	{
		LPITEMIDLIST lppidl = NULL;
		SHGetSpecialFolderLocation(NULL, CSIDL_DESKTOP, &lppidl);
		SHGetPathFromIDList(lppidl, szBuf);
		strDir = szBuf;
		strDir += _T("\\");
	}

	return strDir;
}


BOOL CeMainWnd::PopulateFtpSites(HTREEITEM hRoot)
{
	BOOL bAdded = FALSE;

	// might take a while...
	CeWaitCursor wait;

	CeDb db;
	if (! CeFtpSite::Open(db))
		return bAdded;

	CeDbRecord rec;
	for (CEOID oidRec = db.SeekFirst(); 0 != oidRec; oidRec = db.SeekNext())
	{
		if (!db.ReadRec(rec))
			continue;

		// Get the site name
		CeString str;
		rec.GetIdVal(SITE_NAME, str);

		TCHAR szBuf[64];
		TVITEM tvi;
		tvi.pszText = szBuf;
		tvi.cchTextMax = 64;

		HTREEITEM hItem = NULL, hLast = NULL;
		for (hItem = TreeView_GetChild(m_hwndTree, hRoot); NULL != hItem; )
		{
			tvi.hItem = hItem;
			tvi.mask = TVIF_TEXT | TVIF_PARAM;

			TreeView_GetItem(m_hwndTree, &tvi);

			if (tvi.lParam == tntFtpSite && str >= tvi.pszText)
				// insert after THIS item
				break;

			hLast = hItem;
			hItem = TreeView_GetNextSibling(m_hwndTree, hItem);
		}

		//
		// initialize the tree
		//
		TVINSERTSTRUCT is;
		is.hInsertAfter = hItem ? hItem : TVI_LAST;
		is.hParent = hRoot;
		is.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_CHILDREN | TVIF_PARAM | TVIF_SELECTEDIMAGE;
		is.item.pszText = (LPTSTR) (LPCTSTR) str;
		is.item.cChildren = 0;
		is.item.lParam = tntFtpSite;
		is.item.iSelectedImage = imFtpSite;
		is.item.iImage = imFtpSite;

		TreeView_InsertItem(m_hwndTree, &is);

		bAdded = TRUE;
	}

	return bAdded;
}


BOOL CeMainWnd::PopulateDirectory(HTREEITEM hItem, LPCTSTR szDir, bool bFtp)
{
	BOOL bAdded = FALSE;

	// Might take a while
	CeWaitCursor wait;

	if (bFtp)
	{
		CeString str(szDir);

		for (int ii = 0; ii < str.GetLength(); ii++)
		{
			if (_T('\\') == str[ii])
				str[ii] = _T('/');
		}

		if (! m_ftpConn.SetCurDir(str))
		{
			CeString str = m_ftpConn.GetFtpErrorReplyString();
			MessageBox(str, _T("FTP Server"), MB_OK|MB_ICONERROR);
			if (! m_ftpConn.IsConnected())
				// only disconnect if the server torched us, might only
				// be a permissions error
				OnDisconnect();
			return FALSE;
		}

		CeFileAttrArray files;
		m_ftpConn.GetFileList(files);
		for (ii = 0; ii < files.GetCount(); ii++)
		{
			if (! (files[ii].dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
				continue;

			if (_tcscmp(files[ii].cFileName, _T(".")) == 0 || _tcscmp(files[ii].cFileName, _T("..")) == 0)
				// skip up and same directory
				continue;

			//
			// initialize the tree
			//
			TVINSERTSTRUCT is;
			is.hInsertAfter = TVI_SORT;
			is.hParent = hItem;
			is.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_CHILDREN | TVIF_PARAM | TVIF_SELECTEDIMAGE;
			is.item.pszText = files[ii].cFileName;
			is.item.cChildren = I_CHILDRENCALLBACK;
			is.item.lParam = tntFtpSiteDir;
			is.item.iSelectedImage = imFtpOpenFolder;
			is.item.iImage = imFtpClosedFolder;

			TreeView_InsertItem(m_hwndTree, &is);

			bAdded = TRUE;
		}
	}
	else
	{
		CeString str(szDir);
		CeFindFile ff;

		if (str[str.Length()-1] != _T('\\'))
			str += _T("\\*.*");
		else
			str += _T("*.*");

		if (! ff.FindFirst(str))
			// no files
			return FALSE;

		do
		{
			if (ff.IsDirectory())
			{
				//
				// initialize the tree
				//
				TVINSERTSTRUCT is;
				is.hInsertAfter = TVI_SORT;
				is.hParent = hItem;
				is.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_CHILDREN | TVIF_PARAM;
				is.item.pszText = ff.cFileName;
				is.item.cChildren = I_CHILDRENCALLBACK;
				is.item.lParam = tntLocalDir;
				is.item.iSelectedImage = ff.IsStorageCard() ? imFlashOpen: imFolderOpen;
				is.item.iImage = ff.IsStorageCard() ? imFlashClose: imFolderClose;

				TreeView_InsertItem(m_hwndTree, &is);

				bAdded = TRUE;
			}
		}
		while (ff.FindNext());
	}

	return bAdded;
}


BOOL CeMainWnd::PopulateFilelist(HTREEITEM hItem, LPCTSTR szDir, bool bFtp)
{
	if (NULL == m_hwndList)
		return FALSE;

	// Might take a while
	CeWaitCursor wait;

	CeString str(szDir);
	ListView_DeleteAllItems(m_hwndList);

	if (str.IsEmpty())
		return TRUE;

	m_strCurrentDirectory = szDir;
	m_bCurrentFtp = bFtp;

	if (! bFtp)
	{
		if (str[str.Length()-1] != _T('\\'))
			str += _T("\\*.*");
		else
			str += _T("*.*");

		CeFindFile ff;
		if (! ff.FindFirst(str))
			// no files
			return TRUE;

		::SendMessage(m_hwndList, WM_SETREDRAW, FALSE, 0);

		int ii = 0;
		do
		{
			if (ff.IsDirectory())
				continue;

			if (ff.IsInROM() && (! g_options.m_bROM))
				continue;

			if (! g_options.m_bHidden && (ff.IsHidden() || ff.IsSystem()))
				continue;

			InsertFile(szDir, &ff, bFtp, ii++);
		}
		while (ff.FindNext());

		::SendMessage(m_hwndList, WM_SETREDRAW, TRUE, 0);
	}
	else
	{
		if (! m_ftpConn.IsConnected())
			// selected an FTP site, but we aren't connected
			return FALSE;

		LPARAM lp = TreeView_GetLParam(m_hwndTree, hItem);
		if (lp == tntFtpSite && hItem != m_hConnected)
		{
			// a different FTP site, skip it
			return TRUE;
		}

		::SendMessage(m_hwndList, WM_SETREDRAW, FALSE, 0);

		CeFileAttrArray files;
		if (! m_ftpConn.GetFileList(files, szDir))
		{
			CeString str = m_ftpConn.GetFtpErrorReplyString();
			MessageBox(str, _T("FTP directory failed!"), MB_OK|MB_ICONERROR);
			return FALSE;
		}
		else
		{
			for (int ii = 0; ii < files.GetCount(); ii++)
				if (! (files[ii].dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
					InsertFile(szDir, &files[ii], bFtp, ii);
		}

		::SendMessage(m_hwndList, WM_SETREDRAW, TRUE, 0);
	}

	// resort
	// for speed, don't sort, if the user clicks a column, then it will sort
	//ListView_SortItems(m_hwndList, CmpList, (LPARAM) &m_sortinfo);
	g_sortinfo.bAscending = true;
	g_sortinfo.nColumnNo = -1;

	// select the first item
	ListView_SetItemState(m_hwndList, 0, LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED);
	return TRUE;
}


BOOL GetShFileInfo(LPCTSTR lpszName, DWORD dwAttrib, SHFILEINFO & shinfo, int nFlags, bool bLocal)
{
	memset(&shinfo, 0, sizeof(SHFILEINFO));

	DWORD dwVersion = g_osvi.dwMajorVersion * 100 + g_osvi.dwMinorVersion;

	if (g_options.m_bUseSysIcons && dwVersion > 201)
	{
		// after version 2.01, this actually worked
		if ( ::SHGetFileInfo(lpszName, dwAttrib, &shinfo, sizeof(SHFILEINFO), nFlags))
			return S_OK;

		// continue on failure
	}

	// 2.01 version of SHGetFileInfo() is broken, implement our own

	LPCTSTR lpsz = _tcsrchr(lpszName, _T('\\'));

	if (NULL != lpsz)
		_tcscpy(shinfo.szDisplayName, lpsz+1);
	else
		_tcscpy(shinfo.szDisplayName, lpszName);
	
	if (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)
	{
		_tcscpy(shinfo.szTypeName, _T("Folder"));
		shinfo.hIcon = LoadIcon(CeGetAppInstance(), MAKEINTRESOURCE(IDI_FOLDER));
	}
	else if (NULL != (lpsz = _tcsrchr(lpszName, _T('.'))))
	{
		HRESULT hr = S_OK;

		// extract the extension
		TCHAR szTmp[MAX_PATH];
		_tcsncpy(szTmp, lpsz, MAX_PATH);
		szTmp[MAX_PATH] = 0;

		// open the registry key
		CeRegKey key;
		if (SUCCEEDED(hr))
			hr = _WIN32_HR(key.Open(HKEY_CLASSES_ROOT, szTmp, KEY_READ));

		DWORD dwCnt;
		if (SUCCEEDED(hr))
			// open file type key
			hr = _WIN32_HR(key.QueryValue(szTmp, _T(""), &(dwCnt = MAX_PATH)));

		key.Close();

		if (SUCCEEDED(hr))
			// open file type key
			hr = _WIN32_HR(key.Open(HKEY_CLASSES_ROOT, szTmp, KEY_READ));

		if (SUCCEEDED(hr))
			// open file type key
			hr = _WIN32_HR(key.QueryValue(szTmp, _T(""), &(dwCnt = MAX_PATH)));

		key.Close();

		if (SUCCEEDED(hr))
		{
			// type name from registry
			_tcscpy(shinfo.szTypeName, szTmp);
			shinfo.iIcon = imDoc;
		}
		else
		{
			if (_tcsicmp(lpsz, _T(".lnk")) == 0)
			{
				_tcscpy(shinfo.szTypeName, _T("Shortcut"));
			}
			else
			{
				// type name from extention
				_tcscpy(shinfo.szTypeName, lpsz+1);
				_tcscat(shinfo.szTypeName, _T(" File"));
				shinfo.iIcon = imDocUnknown;
			}
		}

		if (nFlags & SHGFI_ICON)
		{
			if (_tcsicmp(lpsz, _T(".exe")) == 0)
			{
				if (! (nFlags & SHGFI_SMALLICON))
					shinfo.hIcon = LoadIcon(CeGetAppInstance(), MAKEINTRESOURCE(IDI_EXE));
				shinfo.iIcon = imApp;
			}
			else
			{
				if (! (nFlags & SHGFI_SMALLICON))
					shinfo.hIcon = LoadIcon(CeGetAppInstance(), MAKEINTRESOURCE(IDI_FILE));
			}
		}
	}
	else
	{
		_tcscpy(shinfo.szTypeName, _T("File"));

		if (nFlags & SHGFI_ICON)
		{
			if (! (nFlags & SHGFI_SMALLICON))
				shinfo.hIcon = LoadIcon(CeGetAppInstance(), MAKEINTRESOURCE(IDI_FILE));
			shinfo.iIcon = imDocUnknown;
		}
	}

	return S_OK;
}


void CeMainWnd::InsertFile(LPCTSTR szDir, WIN32_FIND_DATA* pFD, bool bFtp, int iInsertItem)
{
	CeString str;

	SHFILEINFO shinfo;

	SYSTEMTIME stToday;
	GetLocalTime(&stToday);

	UINT nFlags =
		SHGFI_SYSICONINDEX |			// Icon index
		SHGFI_ICON |
		SHGFI_SMALLICON |				// Small icon
		SHGFI_TYPENAME |				// type name (e.g., CPP File)
		SHGFI_DISPLAYNAME;				// display name (no extension)

	if (bFtp)
	{
		nFlags |= SHGFI_USEFILEATTRIBUTES;

		GetShFileInfo(pFD->cFileName, pFD->dwFileAttributes, shinfo, nFlags, ! bFtp);
	}
	else
	{
		str  = szDir;
		str += pFD->cFileName;

		GetShFileInfo(str, pFD->dwFileAttributes, shinfo, nFlags, ! bFtp);
	}

	DWORD dwVersion = g_osvi.dwMajorVersion * 100 + g_osvi.dwMinorVersion;
	int iIcon = shinfo.iIcon;

	if (! bFtp && dwVersion > 201 && !_tcscmp(shinfo.szTypeName, _T("Shortcut")))
	{
		TCHAR szTarget[128];

		// This call always returns an extra character, handle it
		if (::SHGetShortcutTarget(str, szTarget, 128))
		{
			LPTSTR lpsz = szTarget;
			bool bIn = false;
			for (int ii = 0; *lpsz != 0; lpsz++)
			{
				if (*lpsz == _T('"'))
				{
					bIn = !bIn;
				}
				else if (!bIn && _istspace(*lpsz))
				{
					// white space outside of quotes, end of link file name
					break;
				}
				else
				{
					szTarget[ii] = *lpsz;
					ii++;
				}
			}
			szTarget[ii] = 0;

			nFlags =
				SHGFI_SYSICONINDEX |		//
				SHGFI_ICON |				//
				SHGFI_SMALLICON |			// Small icon
				SHGFI_TYPENAME |			// type name (e.g., CPP File)
				SHGFI_DISPLAYNAME;			// display name (no extension)

			if (szTarget[0] != _T('\\'))
				// use atributes when not a full path
				nFlags |= SHGFI_USEFILEATTRIBUTES;

			memset(&shinfo, 0, sizeof shinfo);
			GetShFileInfo(szTarget, 0, shinfo, nFlags, true);
			iIcon = shinfo.iIcon;
		}
	}

	LVITEM item;
	int nSubItem = 0;

	if (iInsertItem < 0)
		item.iItem = ListView_GetItemCount(m_hwndList);
	else
		item.iItem = iInsertItem;

	// Name/Icon
	item.mask     = LVIF_IMAGE | LVIF_TEXT | LVIF_PARAM;
	item.pszText  = pFD->cFileName;
	item.iImage   = iIcon;
	item.iSubItem = nSubItem++; 
	item.lParam   = (DWORD) new CeFileListItem(pFD->cFileName, pFD->nFileSizeLow,
		pFD->dwFileAttributes, pFD->ftLastWriteTime, _T("Type"));

	item.iItem = ListView_InsertItem(m_hwndList, &item);

	TCHAR szTmp[256];

	if (g_options.m_bCol_Size)
	{
		// Size
		if (pFD->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
			szTmp[0] = 0;
		else
			wsprintf(szTmp, _T("%lu"), pFD->nFileSizeLow);
		item.mask = LVIF_TEXT;
		item.pszText = szTmp;
		item.iSubItem = nSubItem++;
		ListView_SetItem(m_hwndList, &item);
	}

	if (g_options.m_bCol_Type)
	{
		// Type
		item.mask = LVIF_TEXT;
		item.pszText = (LPTSTR) (LPCTSTR) shinfo.szTypeName;
		item.iSubItem = nSubItem++;
		ListView_SetItem(m_hwndList, &item);
	}

	if (g_options.m_bCol_Date)
	{
		// Modified
		FILETIME ft = pFD->ftLastWriteTime;
		if (! bFtp)
			// need to convert time to local displayable format
			FileTimeToLocalFileTime(&ft, &ft);

		FormatDateTime(ft, szTmp, &stToday);

		item.mask = LVIF_TEXT;
		item.pszText = szTmp;
		item.iSubItem = nSubItem++;
		ListView_SetItem(m_hwndList, &item);
	}

	if (g_options.m_bCol_Attrib)
	{
		// Attributes
		int ii = 0;
		if (pFD->dwFileAttributes & FILE_ATTRIBUTE_READONLY)	szTmp[ii++] = _T('R');
		if (pFD->dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)		szTmp[ii++] = _T('H');
		if (pFD->dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)		szTmp[ii++] = _T('S');
		if (pFD->dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE)		szTmp[ii++] = _T('A');
		if (pFD->dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED)	szTmp[ii++] = _T('C');
		if (pFD->dwFileAttributes & FILE_ATTRIBUTE_INROM)		szTmp[ii++] = _T('M');
		if (pFD->dwFileAttributes & FILE_ATTRIBUTE_ROMMODULE)	szTmp[ii++] = _T('X');
		szTmp[ii] = 0;

		item.mask = LVIF_TEXT;
		item.pszText = szTmp;
		item.iSubItem = nSubItem++;
		ListView_SetItem(m_hwndList, &item);
	}
}



void CeMainWnd::OnColumnClick(NMLISTVIEW *pLV)
{
	ASSERT(pLV->iItem == -1);

	// Might take a while
	CeWaitCursor wait;

	g_sortinfo.nColType = g_arColumns[ pLV->iSubItem ];

	if (pLV->iSubItem == g_sortinfo.nColumnNo)
		// invert the sort
		g_sortinfo.bAscending = ! g_sortinfo.bAscending;
	else
	{
		// new sort on this column
		g_sortinfo.bAscending = true;
		g_sortinfo.nColumnNo = pLV->iSubItem;
	}

	ListView_SortItems(m_hwndList, CmpList, (LPARAM) &g_sortinfo);
}


LRESULT CeMainWnd::OnBeginDragTree(NMTREEVIEW* pNMTV)
{
	TRACE0("Beginning to Drag the image!!!!\n");

/*  This first pass will be limited to dragging from the 
	Listview to the tree view.  This allows file to be moved, which is 
	all that this aplication is intending to do.

	At some point though, this could be expanded if moving directories is something
	we want to do.

	//SET THE FLAGS INDICATING A DRAG IN PROGRESS
	m_bDragging = true;
	m_dwDragItem = (DWORD) pNMTV->itemNew.hItem;
	m_dwDropItem = 0xffffffff;

	m_hDragImage = TreeView_CreateDragImage(m_hwndTree, (HTREEITEM) m_dwDragItem);

	ImageList_BeginDrag(m_hDragImage, 0, 8, 8);
	if (! ImageList_DragEnter(HWND_DESKTOP, pNMTV->ptDrag.x, pNMTV->ptDrag.y))
		TRACE0("Drag Enter failed!");
	
	//CAPTURE ALL MOUSE MESSAGES IN CASE THE USER DRAGS OUTSIDE OF THE VIEW
	SetCapture();
*/
	return 0;
}


LRESULT CeMainWnd::OnBeginDragList(NMLISTVIEW* pNMLV)
{
	TRACE0("Beginning to Drag the image!!!!\n");

	//SET THE FLAGS INDICATING A DRAG IN PROGRESS
	m_bDragging = true;				// yes, we are dragging
	m_dwDragItem = pNMLV->iItem;	// this is the item to drag
	m_dwDropItem = 0xffffffff;		// no drop yet, clear it

	//CREATE A DRAG IMAGE FROM THE CENTER POINT OF THE ITEM IMAGE
	POINT pt; pt.x = 8; pt.y = 8;
	m_hDragImage = ListView_CreateDragImage(m_hwndList, m_dwDragItem, &pt);

	ImageList_BeginDrag(m_hDragImage, 0, 8, 8);
	ImageList_DragEnter(HWND_DESKTOP, pNMLV->ptAction.x, pNMLV->ptAction.y);

	//CAPTURE ALL MOUSE MESSAGES IN CASE THE USER DRAGS OUTSIDE OF THE VIEW
	SetCapture();

	return 0;
}


void CeMainWnd::OnMouseMove( UINT nFlags, POINT point, bool& bHandled )
{
	if (m_bDragging)
	{
		m_ptDropPoint = point;

		//unlock window and allow updates to occur
		ImageList_DragLeave(HWND_DESKTOP);
		ClientToScreen(&m_ptDropPoint);

		CePoint ptScreen = m_ptDropPoint;

		//CONVERT THE DROP POINT TO CLIENT CO-ORDIANTES
		m_hDropWnd = ::WindowFromPoint(m_ptDropPoint);
		::ScreenToClient(m_hDropWnd, &m_ptDropPoint);

		if (m_hwndTree == m_hDropWnd)
		{
			//check with the tree control to see if we are on an item
			TVHITTESTINFO tvht;
			tvht.flags = TVHT_ONITEM;
			tvht.pt = ptScreen;
			::ScreenToClient(m_hwndTree, &(tvht.pt));
			m_dwDropItem = (DWORD) TreeView_HitTest(m_hwndTree, &tvht);
			if (NULL != m_dwDropItem)
				//if we had a hit, then drop highlite the item
				TreeView_Select(m_hwndTree, m_dwDropItem, TVGN_DROPHILITE);
		}
		else if (m_hwndList == m_hDropWnd)
		{
			/*

			//Nothing at this juncture.  THe user can only drop in the tree at this point.
			int nItem = -1;
			while (-1 != (nItem = ListView_GetNextItem(m_hwndList, nItem, LVIS_DROPHILITED)))
			{
				//if we had a hit, then drop highlite the item
				ListView_SetItemState(m_hwndList, nItem, 0, LVIS_DROPHILITED);
			}

			//check with the tree control to see if we are on an item
			LVHITTESTINFO lvht;
			lvht.flags = LVHT_ONITEM;
			lvht.pt = point;
			::ScreenToClient(m_hwndList, &(lvht.pt));

			m_dwDropItem = ListView_HitTest(m_hwndList,&lvht);
			if (m_dwDropItem >= 0)
			{
				//if we had a hit, then drop highlite the item
				ListView_SetItemState(m_hwndList, m_dwDropItem, LVIS_DROPHILITED, LVIS_DROPHILITED);
			}
			*/
		}

		//paint the image in the new location
		ImageList_DragMove(ptScreen.x, ptScreen.y);

		//lock the screen again
		ImageList_DragEnter(HWND_DESKTOP, ptScreen.x, ptScreen.y);
	}

	CeSplitFrame::OnMouseMove(nFlags, point, bHandled);
}


void CeMainWnd::OnLButtonUp( UINT nFlags, POINT point, bool& bHandled )
{
	if (m_bDragging)
	{
		//RELEASE THE MOUSE CAPTURE AND END THE DRAGGING
		::ReleaseCapture();
		m_bDragging = FALSE;
		ImageList_DragLeave(HWND_DESKTOP);
		ImageList_EndDrag();
		
		//GET THE WINDOW UNDER THE DROP POINT
		POINT pt = point;
		ClientToScreen(&pt);
		m_hDropWnd = ::WindowFromPoint(pt);
		
		//DROP THE ITEM ON THE LIST
		if (m_hDropWnd == m_hwndList)
		{
			// Only drops
			MessageBox(_T("You can only drop files onto a folder in the tree."),
				_T("Info"), MB_OK|MB_ICONINFORMATION);
			return;
		}
/* Duplicate code ??
		else if (m_hDropWnd == m_hwndTree)
		{
			// drop the list item into the tree item
			TreeView_SelectDropTarget(m_hwndTree, NULL);
			// Originally selected the destination, but now leave the selection
			// TreeView_SelectItem(m_hwndTree, (HTREEITEM) m_dwDropItem);
		}
*/
		// always make this call in case we floated over it at some point
		TreeView_SelectDropTarget(m_hwndTree, NULL);

		// Now copy the file to the drop target...
		bool bFtp;
		// PArt of the original code mentioned above...
		//CeString strNew = GetTreePath(TreeView_GetSelection(m_hwndTree), bFtp);
		CeString strNew = GetTreePath((HTREEITEM) m_dwDropItem, bFtp);
		CeString strOld = m_strCurrentDirectory;

		TCHAR szFile[MAX_PATH];
		LV_ITEM lvi;
		lvi.mask = LVIF_TEXT | LVIF_PARAM;
		lvi.iItem = m_dwDragItem;
		lvi.iSubItem = 0;
		lvi.pszText = szFile;
		lvi.cchTextMax = MAX_PATH;

		ListView_GetItem(m_hwndList, &lvi);

		strOld += szFile;
		strNew += szFile;

		if (bFtp)
		{
			if (m_bCurrentFtp)
			{
				// remote source and destination
				if (! m_ftpConn.RenameFile(strOld,strNew))
				{
					MessageBox(m_ftpConn.GetFtpErrorReplyString(), _T("FTP RENAME failed"), MB_OK|MB_ICONERROR);
				}
				else
				{
					ListView_DeleteItem(m_hwndList, m_dwDragItem);
				}
			}
			else if (strOld != strNew)
			{
				// Local source, remote destination
				CeFtpTransferDlg dlg(&m_ftpConn, strOld, strNew,
					((CeFileListItem*) lvi.lParam)->m_dwSize, true);
				dlg.DoModal();
			}
			else
				return;
		}
		else
		{
			if (m_bCurrentFtp)
			{
				// local destination, remote source
				CeFtpTransferDlg dlg(&m_ftpConn, strOld, strNew,
					((CeFileListItem*) lvi.lParam)->m_dwSize, false);
				dlg.DoModal();
			}
			else if (strOld != strNew)
			{
				CeDropFileDlg dlg;

				if (IDOK == dlg.DoModal())
				{
					switch (dlg.m_nWhich)
					{
					case IDC_COPY:
						// local destination and source, don't overrite existing
						if (! ::CopyFile(strOld, strNew, FALSE))
						{
							CeString str;
							str.Format(_T("Encountered error %lu while copying file %s"), GetLastError(), szFile);
							MessageBox(str, _T("Copy failed"), MB_OK|MB_ICONERROR);
						}
						break;

					case IDC_MOVE:
						// local destination and source, don't overrite existing
						if (! ::MoveFile(strOld, strNew))
						{
							CeString str;
							str.Format(_T("Encountered error %lu while moving file %s"), GetLastError(), szFile);
							MessageBox(str, _T("Move failed"), MB_OK|MB_ICONERROR);
						}
						else
						{
							// it should be gone...
							ListView_DeleteItem(m_hwndList, m_dwDragItem);
						}
						break;

					case IDC_SHORTCUT:
						{
							int n = strNew.ReverseFindIndex(_T('.'));
							if (n >= 0)
								strNew = CeString((LPCTSTR) strNew, n);
							strNew += _T(".lnk");

							strOld = _T('"');
							strOld += m_strCurrentDirectory;
							strOld += szFile;
							strOld += _T('"');

							if (! SHCreateShortcut((LPTSTR)(LPCTSTR)strNew, (LPTSTR)(LPCTSTR)strOld))
							{
								CeString str;
								str.Format(_T("Encountered error %lu creating shortcut to file %s"), GetLastError(), szFile);
								MessageBox(str, _T("Create Shortcut failed"), MB_OK|MB_ICONERROR);
							}
						}
						break;
					}
				}
			}
			else
				return;
		}
/*
		// Drop messes up current list directory, re-sync
		// Old-code no longer change to destination...
		HTREEITEM hItem = TreeView_GetSelection(m_hwndTree);
		m_strCurrentDirectory = GetTreePath(hItem, m_bCurrentFtp);
		PopulateFilelist(hItem, m_strCurrentDirectory, m_bCurrentFtp);
*/
		::SetFocus(m_hwndTree);
	}

	CeSplitFrame::OnLButtonUp(nFlags, point, bHandled);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Kenny G

United States United States
No Biography provided

| Advertise | Privacy | Mobile
Web04 | 2.8.140821.2 | Last Updated 5 Oct 2000
Article Copyright 2000 by Kenny G
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid