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

📄 ftptreedlg.cpp

📁 《Visual C++.NET MFC类库应用详解》程序实例
💻 CPP
字号:
// FTPTREEDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "FTPTREE.h"
#include "FTPTREEDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// 对话框数据
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()


// CFTPTREEDlg 对话框

CFTPTREEDlg::CFTPTREEDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CFTPTREEDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

CFTPTREEDlg::~CFTPTREEDlg()
{
	// clean up any objets that are still lying around
	if (m_pConn != NULL)
	{
		m_pConn->Close();
		delete m_pConn;
	}
	if (m_pIS != NULL)
	{
		m_pIS->Close();
		delete m_pIS;
	}
}

void CFTPTREEDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_FTPSITE, m_comboWebSite);
	DDX_Control(pDX, IDC_FTPTREE, m_TreeCtl);
}

BEGIN_MESSAGE_MAP(CFTPTREEDlg, CDialog)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(ID_BROWSE_SITE, OnBnClickedBrowseSite)
	ON_WM_GETMINMAXINFO()
	ON_WM_SIZE()
	ON_NOTIFY(TVN_ITEMEXPANDING, IDC_FTPTREE, OnTvnItemexpandingFtptree)
	ON_WM_DESTROY()
END_MESSAGE_MAP()


// CFTPTREEDlg 消息处理程序

BOOL CFTPTREEDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// 将\“关于...\”菜单项添加到系统菜单中。
	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO:在此添加额外的初始化代码
	CRect rect;
	GetWindowRect(rect);
	m_OrigSize.cx = rect.Width();
	m_OrigSize.cy = rect.Height();

// 初始化变量m_pFtpConnection
	m_pConn = NULL;
	
	CString str;
	if (!str.LoadString(IDS_APPNAME))
		str = _T("AppUnknown");
  //创建Internet会话,直到对话框关闭
	m_pIS = new CInternetSession(str, 1, PRE_CONFIG_INTERNET_ACCESS);
	// 如果会话创建失败,提示并关闭程序
	if (!m_pIS)
	{
		AfxMessageBox(IDS_BAD_SESSION, MB_OK);
		OnCancel();
	}
  
  //添加目录树控件中使用的位图资源
	CImageList* pImageList = new CImageList();
	pImageList->Create(16, 15, TRUE, 3, 2);

	CBitmap bitmap;
	for (UINT iCnt=IDB_BITMAP1; iCnt<=IDB_BITMAP3; iCnt++)
	{
		bitmap.LoadBitmap(iCnt);
		pImageList->Add(&bitmap, (COLORREF)0xFFFFFF);
		bitmap.DeleteObject();
	}

	m_TreeCtl.SetImageList(pImageList, TVSIL_NORMAL);
	//初始化目录树控件
	PopulateTree();

	//初始化组合框,因为在属性设置时为组合框添加两个默认值,在这里显示第一个默认值 
	m_comboWebSite.GetLBText(0, str);
	m_comboWebSite.SetWindowText(str);
	return TRUE; 
}


void CFTPTREEDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮,则需要下面的代码来绘制该图标。
// 对于使用文档/视图模型的 MFC 应用程序,这将由框架自动完成。
void CFTPTREEDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标显示。
HCURSOR CFTPTREEDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

void CFTPTREEDlg::OnBnClickedBrowseSite()
{
	// TODO:在此添加控件通知处理程序代码
	CString strFtpSite;
	CString strServerName;
	CString strObject;
	INTERNET_PORT nPort;
	DWORD dwServiceType;
  //假如FTP连接已经建立则首先关闭该连接
	if (m_pConn != NULL)
		m_pConn->Close();
	delete m_pConn;
	m_pConn = NULL;
	m_comboWebSite.GetWindowText(strFtpSite);

	//更新组合框,并使最近使用的URL处于最顶端
	int nListCount = m_comboWebSite.GetCount();
	CString strTemp;
	while (nListCount > 0)
	{
		m_comboWebSite.GetLBText(--nListCount, strTemp);
		if (strFtpSite.Compare(strTemp) == 0)
		{
			m_comboWebSite.DeleteString(nListCount);
			nListCount = 0;
		}
	}

	m_comboWebSite.InsertString(0, strFtpSite);

	//组合框最多可以有5项
	if (m_comboWebSite.GetCount() > 5)
	{
		m_comboWebSite.DeleteString(5);
	}

	// 检查URL的合法性 --
	if (!AfxParseURL(strFtpSite, dwServiceType, strServerName, strObject, nPort))
	{
		CString strFtpURL = _T("ftp://");
		strFtpURL += strFtpSite;
		if (!AfxParseURL(strFtpURL, dwServiceType, strServerName, strObject, nPort))
		{
			AfxMessageBox(IDS_INVALID_URL, MB_OK);
			PopulateTree();
			return;
		}
	}
	CWaitCursor cursor; // 显示等待光标
	// 替换组合框中的URL地址显示
	m_comboWebSite.SetWindowText(strFtpSite);
	m_comboWebSite.SetEditSel(-1,-1);

	// 现在建立一个匿名FTP连接
	if ((dwServiceType == INTERNET_SERVICE_FTP) && !strServerName.IsEmpty())
	{
		try
		{
			m_pConn = m_pIS->GetFtpConnection(strServerName);
		}
		catch (CInternetException* pEx)
		{
			// 出现异常,提示用户
			TCHAR szErr[1024];
			if (pEx->GetErrorMessage(szErr, 1024))
				AfxMessageBox(szErr, MB_OK);
			else
				AfxMessageBox(IDS_EXCEPTION, MB_OK);
			pEx->Delete();

			m_pConn = NULL;
		}
	}
	else
	{
		AfxMessageBox(IDS_INVALID_URL, MB_OK);
	}

	// 如果FTP连接创建成功,则显示根目录结构,否则在目录树控件中显示错误信息。
	if (m_pConn != NULL)
	{
		PopulateTree(m_pConn, strObject);
	}
	else
	{
		PopulateTree();
	}
}


void CFTPTREEDlg::OnGetMinMaxInfo(MINMAXINFO* lpMMI)
{
	// TODO:在此添加消息处理程序代码和/或调用默认值

	CDialog::OnGetMinMaxInfo(lpMMI);

	static BOOL bSetSize;

	if (bSetSize)
	{
		lpMMI->ptMinTrackSize.x = m_OrigSize.cx;
		lpMMI->ptMinTrackSize.y = m_OrigSize.cy;
	}
	else
	{
		bSetSize = TRUE;
	}
}

void CFTPTREEDlg::OnSize(UINT nType, int cx, int cy)
{
	CDialog::OnSize(nType, cx, cy);

	// TODO:在此添加消息处理程序代码
	// resize the tree control to appropriately match the new size
	if ((cx > 0) && (cy > 0))
	{
		CRect rect;
		if (m_TreeCtl.m_hWnd != NULL)
		{
			m_TreeCtl.GetWindowRect(rect);
			ScreenToClient(rect);
			m_TreeCtl.MoveWindow(rect.left, rect.top,
				cx-(2*rect.left), cy-rect.top-rect.left);
		}
	}
}

void CFTPTREEDlg::OnTvnItemexpandingFtptree(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
	// TODO: 在此添加控件通知处理程序代码
	//在MFC消息映射中,定义了统一的格式NMHDR来发送附加数据,
	//随同消息传递到相应的消息处理函数;将系统定义的NMHDR型 
	//参数pNMHDR强制赋值给NM_TREEVIEW型变量pNMTreeView;
	// 寻找被展开的项
	if (pNMTreeView->hdr.code == TVN_ITEMEXPANDING)
	{
		HTREEITEM hIT = pNMTreeView->itemNew.hItem;
		CString cstr, strPath;
		// 创建htreeitem路径
		strPath = m_TreeCtl.GetItemText(hIT);
		while (hIT != m_TreeCtl.GetRootItem())
		{
			hIT = m_TreeCtl.GetParentItem(hIT);
			if (hIT == m_TreeCtl.GetRootItem())
				cstr.Format(_T("/%s"), (LPCTSTR)strPath);
			else
				cstr.Format(_T("%s/%s"), (LPCTSTR)m_TreeCtl.GetItemText(hIT), (LPCTSTR)strPath);
			strPath = cstr;
		}
		// 调用函数ExploreDir
		ExploreDir(strPath, pNMTreeView->itemNew.hItem);
	}

	*pResult = 0;
}

void CFTPTREEDlg::PopulateTree(CFtpConnection* pConn, const CString& strDir)
{
	CWaitCursor cursor; // 显示等待光标
	// 删除控件中所有内容
	m_TreeCtl.DeleteAllItems();
	// 如果FTP连接为NULL,显示错误信息
	if (!pConn)
	{
		//改变控件类型
		ModifyStyle(TVS_LINESATROOT, 0);
		TV_INSERTSTRUCT tvstruct;
		tvstruct.hParent = NULL;
		tvstruct.hInsertAfter = TVI_FIRST;
		tvstruct.item.iImage = 0;
		tvstruct.item.iSelectedImage = 0;
		tvstruct.item.pszText = _T("未创建与FTP服务器的连接!");
		tvstruct.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
		m_TreeCtl.InsertItem(&tvstruct);
		m_pConn = NULL;
	}
	else
	{
		m_pConn = pConn;
		CString cstr = _T("/");
		//将根目录插入树状结构
		TV_INSERTSTRUCT tvstruct;
		tvstruct.hParent = NULL;
		tvstruct.hInsertAfter = TVI_LAST;
		tvstruct.item.iImage = 1;
		tvstruct.item.iSelectedImage = 1;
		tvstruct.item.pszText = _T("/");
		tvstruct.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
		HTREEITEM hThisItem = m_TreeCtl.InsertItem(&tvstruct);
		// 根目录需要调用Expand()展开子项
		// Expand() will call ExploreDir() to find the root's real children
		tvstruct.hParent = hThisItem;
		m_TreeCtl.InsertItem(&tvstruct);
		m_TreeCtl.Expand(m_TreeCtl.GetRootItem(), TVE_EXPAND);
		//如果没有子项,取消TVS_LINESATROOT风格
		if (!m_TreeCtl.ItemHasChildren(m_TreeCtl.GetRootItem()))
		{
			ModifyStyle(TVS_LINESATROOT, 0);
			return;
		}
		// 如果有子项,则设置TVS_LINESATROOT风格
		ModifyStyle(0, TVS_LINESATROOT);
		if (!strDir)
			return;
		//只要有子项就反复展开
		int nIndex;
		CString strTemp;
		CString strSrc = strDir;
		HTREEITEM hTI = m_TreeCtl.GetRootItem();
		while (!strSrc.IsEmpty())
		{
			nIndex = strSrc.Find(_T("/"));
			if (nIndex < 0)
			{
				cstr = strSrc;
				strSrc.Empty();
			}
			else if (nIndex > 0)
			{ // 跟踪没有列出的目录
				cstr = strSrc.Left(nIndex);
				strTemp = strSrc.Right(strSrc.GetLength() - (nIndex+1));
				strSrc = strTemp;
			}
			if(!cstr.IsEmpty() && (nIndex != 0))
			{
				// 检查CStr是文件还是目录
				hTI = m_TreeCtl.GetChildItem(hTI);
				while ((hTI != NULL) && (cstr != m_TreeCtl.GetItemText(hTI)))
				{
					hTI = m_TreeCtl.GetNextItem(hTI, TVGN_NEXT);
				}
				if ((hTI != NULL) && (cstr == m_TreeCtl.GetItemText(hTI)))
				{
					if (m_TreeCtl.ItemHasChildren(hTI))
						m_TreeCtl.Expand(hTI, TVE_EXPAND);
					else
					{
						m_TreeCtl.SelectItem(hTI);  
						TV_ITEM tv;
						tv.hItem = hTI;
						tv.mask = TVIF_HANDLE | TVIF_STATE;
						tv.stateMask = TVIS_BOLD;
						if (m_TreeCtl.GetItem(&tv))
						{
							tv.mask = TVIF_HANDLE | TVIF_STATE;
							tv.stateMask = TVIS_BOLD;
							tv.state = TVIS_BOLD;
							m_TreeCtl.SetItem(&tv);
						}
						strSrc.Empty(); 
					}
				}
				
				else strSrc.Empty();
			}
			else // nIndex == 0
			{
				strTemp = strSrc.Right(strSrc.GetLength() - 1);
				strSrc = strTemp;
			}
		} // 结束展开
	}
}


void CFTPTREEDlg::ExploreDir(const CString& strDir, HTREEITEM hParent)
{
	TV_INSERTSTRUCT tvstruct;
	CString strSearchDir;
	//删除该目录中所有的子项
	HTREEITEM hIT = m_TreeCtl.GetChildItem(hParent);
	HTREEITEM hTemp;
	while (hIT != NULL)
	{	hTemp = m_TreeCtl.GetNextSiblingItem(hIT);
		m_TreeCtl.DeleteItem(hIT);
		hIT = hTemp;
	}
	// 查找该目录中所有的文件
	if (hParent != m_TreeCtl.GetRootItem())
	{
		strSearchDir = strDir + _T("/*");
	}
	else
	{
		strSearchDir = _T("/*");
	}

	//声明CftpFileFind类变量ftpFind;
	CFtpFileFind ftpFind(m_pConn);

	//查找文件
	BOOL bContinue = ftpFind.FindFile(strSearchDir);
	if (!bContinue)
	{
		// 如果目录为空,关闭文件
		ftpFind.Close();
		return;
	}

	BOOL bDir = FALSE;
	HTREEITEM hThisItem;
	CString strFileName;
	while (bContinue) // 为目录中每一项设置并插入一个tvstruct
	{	// 继续查找
		bContinue = ftpFind.FindNextFile();
		strFileName = ftpFind.GetFileName();
		if (ftpFind.IsDirectory())
		{    // 找到一个目录
			bDir = TRUE;
			tvstruct.item.iImage = 1;
			tvstruct.item.iSelectedImage = 1;
		}
		else
		{
			tvstruct.item.iImage = 2;
			tvstruct.item.iSelectedImage = 2;
		}
		tvstruct.hParent = hParent;
		tvstruct.hInsertAfter = TVI_LAST;
		tvstruct.item.pszText = (LPTSTR)(LPCTSTR)strFileName;   // 返回一个CString
		tvstruct.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
		hThisItem = m_TreeCtl.InsertItem(&tvstruct);
	}
	ftpFind.Close();
	// 如果找到非空目录,则创建一个临时子项 
	if (bDir)
	{
		CFtpFileFind* pTempFtpFind = NULL;
		CString strFullSearchPath;
		int nImage, nSelectedImage;
		hThisItem = m_TreeCtl.GetChildItem(hParent);
		while (hThisItem != NULL)
		{
			m_TreeCtl.GetItemImage(hThisItem, nImage, nSelectedImage);
			if (nImage == 1) //为目录
			{
				strFileName = m_TreeCtl.GetItemText(hThisItem);
				// 创建完整的路径
				strFullSearchPath = strDir + _T("/") + strFileName + _T("/*");
				pTempFtpFind = new CFtpFileFind(m_pConn);
				if (pTempFtpFind->FindFile(strFullSearchPath))
				{
					tvstruct.hParent = hThisItem;
					tvstruct.hInsertAfter = TVI_LAST;
					tvstruct.item.iImage = 1;
					tvstruct.item.iSelectedImage = 1;
					tvstruct.item.pszText = _T("1");;
					tvstruct.item.mask = TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_TEXT;
					m_TreeCtl.InsertItem(&tvstruct);
				}
				pTempFtpFind->Close();
				delete pTempFtpFind;
			}
			hThisItem = m_TreeCtl.GetNextSiblingItem(hThisItem);
		}
	}
	return;
}

void CFTPTREEDlg::OnDestroy()
{
	CDialog::OnDestroy();

	// TODO: 在此添加消息处理程序代码
	CImageList  *pimagelist;
	pimagelist = m_TreeCtl.GetImageList(TVSIL_NORMAL);
	pimagelist->DeleteImageList();
	delete pimagelist;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -