017 文件下载打开功能实现

布局操作

给list 控件添加一个右键单击事件

在资源文件里面添加一个菜单,在菜单里面添加下载文件、打开文件、删除文件选项,并设置对应的id

为ID_DOWNFILE、ID_OPENFILE、ID_DELETEFILE

给菜单资源文件添加id:IDR_MENU_RCLICK

弹出菜单代码实现

void CRemoteClientDlg::OnNMRClickListFile(NMHDR* pNMHDR, LRESULT* pResult)
{
    LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
    // TODO: 在此添加控件通知处理程序代码
    *pResult = 0;
    // 获取当前点击的客户端坐标
    CPoint ptMouse, ptList;
    GetCursorPos(&ptMouse);
    ptList = ptMouse;
    m_list.ScreenToClient(&ptList);
    // 获取当前选中的节点
    int ListSelected = m_list.HitTest(ptList);
    if (ListSelected < 0)
    {
        return;
    }
    // 创建菜单对象
    CMenu menu;
    // 从可执行文件加载菜单资源并将其附加到 CMenu 对象。
    menu.LoadMenu(IDR_MENU_RCLICK);
    // 指定菜单中包含的弹出菜单的位置。 第一个菜单项的位置值从 0 开始。 
    CMenu* pPupup = menu.GetSubMenu(0);
    if (pPupup != NULL)
    {
        // 在指定位置显示浮动弹出菜单,并跟踪弹出菜单上项的选择情况。
        pPupup->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON, ptMouse.x, ptMouse.y, this);
    }
}

文件下载功能并给大文件传输添加了状态

文件的下载是非常的耗时的,为了避免界面的卡死,选择新开一个线程来下载文件

1 开启线程下载

// 下载文件,按钮事件
void CRemoteClientDlg::OnDownfile()
{
    _beginthread(&CRemoteClientDlg::threadEntryForDownFile, 0, this);
    // 将光标设置为等待状态
    BeginWaitCursor();
    m_statusDlg.m_info.SetWindowTextA(_T("命令正在执行中")); 
    // 显示窗口
    m_statusDlg.ShowWindow(SW_SHOW);
    // 窗口居中
    m_statusDlg.CenterWindow(this);
    // 激活dlg设置到前台
    m_statusDlg.SetActiveWindow();
​
}

2 线程入口函数

// 下载文件线程函数入口
void CRemoteClientDlg::threadEntryForDownFile(void* arg)
{
    CRemoteClientDlg* thiz = (CRemoteClientDlg*)arg;
    thiz->threadDownFile();
    _endthread();
}

3 下载文件线程函数

// 下载文件线程函数
void CRemoteClientDlg::threadDownFile()
{
    CClientSocket* pclient = CClientSocket::getInstance();
    // 获取文件列表中的文件,获取选中的标签
    int nListSelected = m_list.GetSelectionMark();
    CString strFile = m_list.GetItemText(nListSelected, 0);
    // 创建一个文件对话框来获取保存文件路径
    CFileDialog dlg(FALSE, "*",
        strFile, OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY,
        NULL, this);
    // 在这里程序是阻塞的
    // 用户点了确定后才继续往下执行
    int ret = dlg.DoModal();
    TRACE("error :%d\r\n", CommDlgExtendedError());
    // 这里需要用户点击确认后才继续往下面走
    if (ret == IDOK)
    {
        TRACE("enter ok\r\n");
        // 通过filedlg拿到完整的路径名
        FILE* pFile = fopen(dlg.GetPathName(), "wb+");
        if (pFile == NULL)
        {
            AfxMessageBox("本地没有权限保存文件,或者文件无法创建");
            m_statusDlg.ShowWindow(SW_HIDE);
            EndWaitCursor();
            return;
        }
        // 获取路径
        HTREEITEM hSelected = m_tree.GetSelectedItem();
        strFile = GetItemPath(hSelected) + strFile;
        TRACE("path: %s\r\n", strFile);
        // 发送命令
        // int ret = SendCommandPacket(4, false, (BYTE*)strFile.GetBuffer(), strFile.GetLength());
        // SendCommandPacket中的Updata 会影响界面,所以不能直接用
        int ret = SendMessage(WM_SEND_PACKET, 4 << 1 | 0, (LPARAM)(LPCSTR)strFile);
        if (ret < 0)
        {
            AfxMessageBox("执行下载命令失败");
            TRACE("执行下载命令失败:ret:%d\r\n", ret);
            m_statusDlg.ShowWindow(SW_HIDE);
            EndWaitCursor();
            return;
        }
        // 获取文件长度,第一个包是文件长度
        long long nLength = *(long long*)pclient->GetPacket().strData.c_str();
        if (nLength == 0)
        {
            AfxMessageBox("文件长度为0或无法读取文件");
            m_statusDlg.ShowWindow(SW_HIDE);
            EndWaitCursor();
            return;
        }
        TRACE("length %ld\r\n", nLength);
        long long nCount = 0;
        int count = 0;
​
        // 传输数据
        while (nCount < nLength)
        {
            int ret = pclient->DealCommand();
            count++;
            if (ret < 0)
            {
                AfxMessageBox("传输失败");
                TRACE("传输失败:%d\r\n", ret);
                break;
            }
            fwrite(pclient->GetPacket().strData.c_str(), 1, pclient->GetPacket().strData.size(), pFile);
            nCount += pclient->GetPacket().strData.size();
            TRACE("nCount : %d\r\n", nCount);
        }
        TRACE("recv count : %d", count);
        if (nCount == nLength)
        {
            AfxMessageBox("传输成功");
        }
        fclose(pFile);
    }
    pclient->CloseSocket();
    m_statusDlg.ShowWindow(SW_HIDE);
    EndWaitCursor();
    MessageBox(_T("下载完成"));
}

文件打开功能

void CRemoteClientDlg::OnOpenfile()
{
    // 获取选中的标签
    int nSelected = m_list.GetSelectionMark();
    CString strFile = m_list.GetItemText(nSelected, 0);
    // 获取路径
    HTREEITEM hSelected = m_tree.GetSelectedItem();
    strFile = GetItemPath(hSelected) + strFile;
    int ret = SendCommandPacket(3, true, (BYTE*)strFile.GetBuffer(), strFile.GetLength());
    if (ret < 0)
    {
        AfxMessageBox("打开文件命令失败");
        TRACE("打开文件失败:%d", ret);
    }
}

文件删除功能

// 删除文件
void CRemoteClientDlg::OnDeletefile()
{
    // 获取选中的标签
    int nSelected = m_list.GetSelectionMark();
    CString strFile = m_list.GetItemText(nSelected, 0);
    // 获取路径
    HTREEITEM hSelected = m_tree.GetSelectedItem();
    strFile = GetItemPath(hSelected) + strFile;
    int ret = SendCommandPacket(5, true, (BYTE*)strFile.GetBuffer(), strFile.GetLength());
    if (ret < 0)
    {
        AfxMessageBox("打开文件命令失败");
        TRACE("打开文件失败:%d", ret);
    }
    LoadFileCurrent();
}

遇到问题

当在另一个线程里面使用需要操作到其它线程ui界面的函数时会不允许

解决方案使用自定义消息

自定义消息步骤

1 自定义消息名称

#define WM_SEND_PACKET (WM_USER + 1)

2 声明实现消息函数

// 2 自定义消息响应函数
afx_msg LRESULT OnSendPacket(WPARAM wParam, LPARAM lParam);
​
// 自定义消息函数
LRESULT CRemoteClientDlg::OnSendPacket(WPARAM wParam, LPARAM lParam)
{
    CString strFile = (LPCSTR)lParam;
    int ret = SendCommandPacket(wParam >> 1, wParam & 1, (BYTE*)strFile.GetBuffer(), strFile.GetLength());
    return ret;
}

3 将消息函数和消息绑定起来

// 3 自定义消息,添加到消息映射表里
ON_MESSAGE(WM_SEND_PACKET, &CRemoteClientDlg::OnSendPacket)

  • 21
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值