多线程创建模态进度条窗口

来源:互联网 发布:62数据源码 编辑:程序博客网 时间:2024/06/06 17:19
主窗体的类名为:CModifyFileDlg;进度条窗体的类名为:CDlgProgress;进度条实例作为的CDlgProgress成员的变量名为:m_ProgressCtrl (类型为CProgressCtrl)
 
第一步:主窗体的按钮事件响应。
在主窗体的按钮事件响应中声明进度条窗口对象,调用其成员函数,把参数传给CDlgProgress的当前实例。
void CModifyFileDlg::OnBTNModifyFile()
{
      UpdateData();
      CDlgProgress ProgDlg; // 创建进度条窗口实例
    // 用于传递参数、创建线程和显示模态窗口的函数
      ProgDlg.DoModifyProgress(m_strFileName, m_strExpFileName); // 传入两个文件路径
}
 
第二步:进度条窗口的成员函数
这个函数在主窗口的按钮事件相应中被调用。
其作用是:
1、接受参数,作为进程的参数传递给进程;
2、创建进程,挂起的;
3、显示模态的进程条对话框;
4、等待线程结束;
5、获取线程结束码。
DWORD CDlgProgress::DoModifyProgress(LPCSTR lpszSecFilePathName,
                                                   LPCSTR lpszDestFilePathName)
{
      // 1.给线程变量赋值
      PARAM_ModifyFile ThreadParam; // 传递个线程的变量的结构体
      ThreadParam.m_strSecFilePathName = lpszSecFilePathName;
      ThreadParam.m_strDestFilePathName = lpszDestFilePathName;
      ThreadParam.pWnd = this;
 
      // 2.创建一个被挂起的线程
      m_hThread = CreateThread(NULL, 0, THREAD_File,
                                     (LPVOID)&ThreadParam,
                                              CREATE_SUSPENDED , NULL);
 
      // 3.显示模态对话框
      DoModal();
 
      // 4.等待线程结束
      while (WAIT_TIMEOUT == WaitForSingleObject(m_hThread, 0))
      {
           Sleep(100);
      }
     
      // 5.获取线程结束码
      DWORD dwRet;
      GetExitCodeThread(m_hThread, &dwRet);
      CloseHandle(m_hThread);
 
      return dwRet; // 返回结束码
}
 
第三步:在进度条窗口类的OnInitDialog函数中启动挂起的线程
BOOL CDlgProgress::OnInitDialog()
{
      CDialog::OnInitDialog();
      // TODO: Add extra initialization here
      if (m_hThread)
      {
           ResumeThread(m_hThread); // 启动线程(线程句柄是类的成员变量)
      }
     
      return TRUE;
}
 
第四步:定义线程函数
注意:线程函数如作为类的成员函数,须是静态的(static),其调用方式应为:__stdcall
static DWORD WINAPI __stdcall THREAD_File(LPVOID param);
 
在线程函数中要取出参数用于计算;计算进度条总长度和步幅;随着工作的进行设置滚动条的位置;最后工作完成后关闭进度条窗口。
DWORD WINAPI CDlgProgress::THREAD_File(LPVOID param)
{
      // 取出参数值
      CString strSecFilePathName = ((PARAM_ModifyFile *)param)->m_strSecFilePathName;
      CString strDestFilePathName = ((PARAM_ModifyFile *)param)->m_strDestFilePathName;
      CDlgProgress * pWnd = ((PARAM_ModifyFile *)param)->pWnd;
 
      // 如果窗口还没有创建完成,等待
      while (!IsWindow(pWnd->m_hWnd) || !pWnd->IsWindowVisible())
      {
           Sleep(100);
      }
 
      ULARGE_INTEGER ui64SrcFileSize; // 源文件大小
 
      // 打开源文件读取数据
      HANDLE hSecFile = CreateFile(strSecFilePathName, GENERIC_READ,
                       0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
 
      // 打开要写入数据的文件
      HANDLE hDestFile = CreateFile(strDestFilePathName, GENERIC_WRITE,
                       0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
 
      if (!hSecFile || !hDestFile)
      {
           AfxMessageBox("CreateFile failed!");
           return 0;
      }
 
      // 获得源文件大小尺寸
      ui64SrcFileSize.LowPart = GetFileSize(hSecFile, &ui64SrcFileSize.HighPart);
      DWORD dwTotleBlock = (DWORD)(ui64SrcFileSize.QuadPart / 2048);
      pWnd->m_ProgressCtrl.SetRange32(0, dwTotleBlock);
      DWORD dwCurretBlock = 0;
 
      BYTE Buffer[2048];
      BYTE bufBeg[12] = {0}; // 12字节有效
      BYTE bufEnd[4] = {0}; // 4字节有效
      DWORD dwReadByteNum; // 实际读取的数据量
      DWORD dwWriteByteNum; // 实际写入的数据量
 
      // 读取2048字节数据到Buffer
      if (!ReadFile(hSecFile, Buffer, 2048, &dwReadByteNum, NULL))
 
      while (dwReadByteNum)
      {
           if (dwCurretBlock < dwTotleBlock)
           {
                 pWnd->m_ProgressCtrl.SetPos(dwCurretBlock++); // 设置进度条当前位置
           }
          
           // 把数据分3次写入
           if (!WriteFile(hDestFile, bufBeg, 12, &dwWriteByteNum, NULL) ||
                 !WriteFile(hDestFile, Buffer, dwReadByteNum, &dwWriteByteNum, NULL) ||
                 !WriteFile(hDestFile, bufBeg, 4, &dwWriteByteNum, NULL))
           {
                 AfxMessageBox("WriteFile failed!");
                 return 0;
           }
 
           ReadFile(hSecFile, Buffer, 2048, &dwReadByteNum, NULL);
      }
 
      CloseHandle(hDestFile);
      CloseHandle(hSecFile);
     
    // 关闭模态窗口
      while (IsWindow(pWnd->m_hWnd))
      {
           pWnd->SendMessage(WM_CLOSE);
           Sleep(100);
      }
      return 0;
}
注意:要用while关闭窗口,为了线程同步。
 
另外,还有定义线程的参数,在进度条窗口类的cpp文件中,是一个结构体:
struct PARAM_ModifyFile
{
      CString m_strDestFilePathName; // 目的文件名
      CString m_strSecFilePathName; // 源文件名
      CDlgProgress * pWnd; // 进度条窗口指针
};
 
原创粉丝点击