Click here to Skip to main content
15,886,067 members
Articles / Web Development / HTML

A Comprehensive CE Class Library to Replace ATL and MFC

Rate me:
Please Sign up or sign in to vote.
4.48/5 (14 votes)
4 Oct 2000CPOL 278.8K   998   70  
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.
#include "StdAfx.h"
#include <shlobj.h>

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

#include "ShortcutDlg.h"
#include "OptDlg.h"

#include "ftpSite.h"

#include "PropertyDlg.h"

#include "CeFontDlg.h"
#include "CeFindFile.h"
#include "CeLabel.h"

#include "afxres.h"

#include <math.h>

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)
{
	TV_ITEM tvi;
	CeString str;
	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 st;
	BOOL bSuccess = ::FileTimeToSystemTime(&ft, &st);
	if (! bSuccess || st.wYear > 9999)
	{
		sz[0] = 0;
	}
	else
	{
		int nSize = ::GetDateFormat(LOCALE_SYSTEM_DEFAULT, DATE_SHORTDATE,
			&st, NULL, sz, 32);

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

		::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:

public:
	CeAboutDlg(): CeScrollDialog(IDD_ABOUT) {}
	virtual BOOL OnInitDialog();
};

#define IDT_ANIM_ICON	100

BOOL CeAboutDlg::OnInitDialog()
{
	// allow controls to be created
	return CeScrollDialog::OnInitDialog();
}


///////////////////////////////////////////////////////////////////////////////
/*
class CeConnectDlg: public CeDialog
{
public:
	CeMainWnd* m_pMainWnd;

	CeConnectDlg()
	{
		m_pMainWnd = NULL;
	}
	virtual BOOL OnInitDialog();
};


BOOL CeConnectDlg::OnInitDialog()
{
	CeDialog::OnInitDialog();

	HWND hList = GetDlgItem(IDC_ENTRIES);

	LVCOLUMN col;
	col.mask = LVCF_FMT | LVCF_TEXT;
	col.fmt = LVCFMT_CENTER;
	col.pszText = _T("Entries");
	ListView_InsertColumn(hList, 0, &col);

	RASENTRYNAME* pEntries = NULL;

	int nEntries = CeRasEntry::GetAll(&pEntries);
	if (nEntries > 0)
	{
		for (int ii = 0; ii < nEntries; ii++)
		{
			LVITEM item;

			item.iItem = ii;
			item.iSubItem = 0;
			item.mask = LVIF_TEXT;
			item.pszText = pEntries[ii].szEntryName;
			ListView_InsertItem(hList, &item);
		}
	}

	ListView_SetColumnWidth(hList, 0, LVSCW_AUTOSIZE_USEHEADER);
	return TRUE;
}

*/
///////////////////////////////////////////////////////////////////////////////

CeMainWnd::CeMainWnd()
{
	m_hFont = NULL;
	m_hImages = NULL;
	m_dwFontSize = 0;
	m_hwndList = NULL;
	m_hwndTree = 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_NEWSHORTCUT:	OnNewShortcut();	break;
		case ID_FILE_CLOSE:			DestroyWindow();	break;

		case ID_EDIT_OPTIONS:		OnOptions();		break;
		case ID_EDIT_FONT:			OnFont();			break;

		// E_NOTIMPL
		case ID_EDIT_PASTEASSHORTCUT:					break;
		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::OnNewShortcut()
{
	CeShortcutDlg dlg;
	dlg.DoModal();
}


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))
		{
			CeString strErr = m_ftpConn.GetFtpErrorReplyString();
			MessageBox(strErr, 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();
	if (hwndFocus == m_hwndList)
	{
		int nSel = ListView_GetNextItem(m_hwndList, -1, LVIS_SELECTED);
		if (nSel < 0)
			return;

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

		CeString strDir = m_strCurrentDirectory;
		if (m_strCurrentDirectory[strDir.Length() - 1] != _T('\\'))
			strDir += _T('\\');
		strDir += strFile;

		int nResp = MessageBox(_T("Are you certain you wish to remove the selected file?"),
			strDir, MB_OKCANCEL);

		if (nResp != IDOK)
			return;

		if (m_bCurrentFtp)
		{
			if (! m_ftpConn.DeleteFile(strDir))
			{
				CeString str = m_ftpConn.GetFtpErrorReplyString();
				MessageBox(str, _T("FTP delete failed!"), MB_OK);
				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("\\"))
		{
			MessageBox(_T("That's not something you can delete, sorry."),
				_T("Error"), MB_ICONWARNING|MB_OK);

			return;
		}

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

		if (nResp != IDOK)
			return;

		// remove the trailing "\"
		str.GetBufferSetLength(str.GetLength()-1);
		str.ReleaseBuffer();

		if (bFtp)
		{
			if (m_ftpConn.DeleteDir(str))
			{
				TreeView_DeleteItem(m_hwndTree, hItem);
				// refresh the list view....
			}
			else
			{
				CeString str = m_ftpConn.GetFtpErrorReplyString();
				MessageBox(str, _T("FTP command failed!"), MB_OK|MB_ICONWARNING);
			}
		}
		else
		{
			if (::RemoveDirectory(str))
			{
				TreeView_DeleteItem(m_hwndTree, hItem);

				// refresh the list view....
			}
			else
			{
				CeString str;
				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
				{
					str.Format(_T("Error %lu remove directory"), GetLastError());
					MessageBox(str, _T("Error"), 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_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, NULL, MB_ICONWARNING);
		return;
	}
	else
	{
		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));

		PopulateFilelist(hItem, m_ftpConn.GetRoot(), true);

		MessageBox(_T("Connection established."));
	}

}

/*
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);

	if (IDOK == dlg.DoModal(IDD_PROPERTY) && ! site.m_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) site.m_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()
{
#ifdef _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(IDR_MENU1, 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
}

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("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_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)
	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);

	// 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())
		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())
	{
		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);

	// Create the tree 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 (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);

	// Done
	return TRUE;
}


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_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();
			OnRefresh();
		}

		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_bROM = dlg.m_bROM;
			OnRefresh();
		}

		// 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)
	{
		strFullName = m_strCurrentDirectory;

		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 += 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)
			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();
		}
		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();
		}
	}
	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();
}


LRESULT CeMainWnd::OnMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, bool& bHandled)
{
	switch (uMsg)
	{
	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_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_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);
					return FALSE;
				}
			}
			else
			{
				if (! MoveFile(strOld, strNew))
				{
					CeString strErr;
					strErr.Format(_T("Error %lu while renaming."), GetLastError());
					MessageBox(strErr, _T("Rename failed!"), MB_OK);
					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;
	}

	return 0;
}


void CeMainWnd::OnRefresh()
{
	// 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_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))
				{
					CeString str = m_ftpConn.GetFtpErrorReplyString();
					MessageBox(str, _T("FTP rename failed!"), MB_OK);
					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);
					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;
	}

	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;
	}

	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"));
			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;
}


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

	// Might take a while
	CeWaitCursor wait;

	CeString str(szDir);
	ListView_DeleteAllItems(m_hwndList);

	if (str.IsEmpty())
		return;

	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;

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

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

			if (ff.IsInROM() && (! g_options.m_bROM))
				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;

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

		CeWaitCursor wait;

		::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);
		}
		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);
}


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;

	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;
			for (int ii = 0; *lpsz != 0; lpsz++)
			{
				if (*lpsz == _T('"'))
					continue;

				if (_istspace(*lpsz))
					break;

				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);

		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);

		//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.x = point.x;
			tvht.pt.y = point.y;
			::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.

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

			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);
			}

			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(m_ptDropPoint.x, m_ptDropPoint.y);

		//lock the screen again
		ImageList_DragEnter(HWND_DESKTOP, point.x, point.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);
		}
		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))
				{
					CeString str = m_ftpConn.GetFtpErrorReplyString();
					MessageBox(str, _T("FTP rename failed!"), MB_OK);
				}
				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)
			{
				// local destination and source
				if (! ::CopyFile(strOld, strNew, FALSE))
				{
					MessageBox(_T("Copy failed"), _T("Copy failed"), MB_OK);
				}
			}
			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)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions