zoukankan      html  css  js  c++  java
  • AVConverter

    以下是在主线程中创建进程进行AV转换,利用匿名管道技术读写并获取相应信息,然后在UI线程提取字符串然后对整个对话框刷新的代码

    代码
    int CAConverterDlg::mainfun()
    {
    SECURITY_ATTRIBUTES sa;

    sa.nLength
    =sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor
    = NULL;
    sa.bInheritHandle
    = TRUE;
    HANDLE hread_cmd
    =0, hwrite_cmd =0, hread_echo =0, hwrite_echo =0;
    //create a pipe for cmdlines
    if(!CreatePipe(&hread_cmd, &hwrite_cmd, &sa, 0))
    {
    MessageBox(L
    "CreatePipe(cmd) failed!!!");
    return0;
    }
    //create a pipe for echo
    if(!CreatePipe(&hread_echo, &hwrite_echo, &sa, 0))
    {
    MessageBox(L
    "CreatePipe(echo) failed!!!\n");
    return0;
    }
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    ZeroMemory(
    &si, sizeof(STARTUPINFO));
    si.cb
    =sizeof(STARTUPINFO);
    GetStartupInfo(
    &si);
    si.hStdError
    = hwrite_echo;
    si.hStdOutput
    = hwrite_echo;
    si.hStdInput
    = hread_cmd;
    si.wShowWindow
    = SW_HIDE;
    si.dwFlags
    = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;

    CString tmp;
    GetDlgItemTextW(IDC_EDIT_CMD,stredit2);
    //获取编辑框中输入的命令行
    tmp.Format(L"%s",stredit2);

    if(!CreateProcess(L"mencoder.exe", tmp.GetBuffer(), NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi))
    {
    MessageBox(L
    "Create Process failed!!!\n");
    return0;
    }
    CloseHandle(hread_cmd);
    CloseHandle(hwrite_echo);

    //以下程序是在主线程ui上实现对进度百分数的提取
    char buffer[4096] = {0};
    DWORD bytesRead;

    while (true)
    {
    if (ReadFile(hread_echo,buffer,4095,&bytesRead,NULL) == NULL) //读取管道
    break;

    strOutput
    = buffer;

    CAtlString resToken;
    int curPos =0;

    resToken
    = strOutput.Tokenize(_T("()"),curPos);
    while (resToken != _T(""))
    {
    resToken
    = strOutput.Tokenize(_T("()"), curPos);
    if(resToken.GetLength()<5&&resToken.GetLength()>2&&(resToken.FindOneOf(L"1234567890%")!=-1))
    SetDlgItemText(IDC_EDIT_PROGRESS,resToken);
    }
    SetDlgItemText(IDC_EDIT_OUTPUT,strOutput);
    //显示输出信息到编辑框,并刷新窗口

    UpdateWindow();
    Sleep(
    1000);
    memset(buffer,
    0, sizeof(buffer));
    }

    CloseHandle(hwrite_cmd);
    CloseHandle(hread_echo);

    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    MessageBox(L
    "convert OK");

    return1;
    }

    以上代码有个问题,会导致ui很卡,为了解决这个问题采用线程,创建新的线程来完成这项任务,然后再将得到的信息经过提取再返回给ui

    代码如下:

    DWORD WINAPI ReadThread(void*param);
    代码
    void CAConverterDlg::OnBnClickedOk()
    {
    // TODO: 在此添加控件通知处理程序代码
    GetDlgItemText(IDC_EDIT_CMD,stredit2); //获取编辑框中输入的命令行

    DWORD id;
    HANDLE hh;
    CAConverterDlg
    *pDlg =(CAConverterDlg *)AfxGetApp()->m_pMainWnd;
    if(!(hh = CreateThread(NULL, NULL,(LPTHREAD_START_ROUTINE)ReadThread, pDlg, NULL, &id)))
    {
    MessageBox(L
    "fail to create thread");
    return;
    }

    CloseHandle(hh);
    //CDialogEx::OnOK();
    }
    代码
    //---------------创建匿名管道,创建进程
    DWORD WINAPI ReadThread(void*param)
    {
    SECURITY_ATTRIBUTES sa;

    sa.nLength
    =sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor
    = NULL; //使用系统默认的安全描述符
    sa.bInheritHandle = TRUE; //创建的进程继承句柄

    HANDLE hRead,hWrite;

    if (!CreatePipe(&hRead,&hWrite,&sa,0)) //创建匿名管道
    {
    MessageBox(NULL,L
    "CreatePipe Failed!",L"提示",MB_OK | MB_ICONWARNING);
    return0;
    }

    STARTUPINFO si;
    PROCESS_INFORMATION pi
    ={};

    ZeroMemory(
    &si,sizeof(STARTUPINFO));
    ZeroMemory(
    &pi,sizeof(PROCESS_INFORMATION));
    si.cb
    =sizeof(STARTUPINFO);
    GetStartupInfo(
    &si);
    si.hStdError
    = hWrite;
    si.hStdOutput
    = hWrite; //新创建进程的标准输出连在写管道一端
    si.wShowWindow = SW_HIDE; //隐藏窗口
    si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;

    char buf[1024];
    memset(buf,
    0, sizeof(buf));
    DWORD bytesRead;

    if (!CreateProcess(NULL,((CAConverterDlg*)param)->stredit2.GetBuffer(),NULL,NULL,TRUE,NULL,NULL,NULL,&si,&pi))
    {
    MessageBox(((CAConverterDlg
    *)param)->m_hWnd,L"CreateProcess Failed!",L"提示",MB_OK | MB_ICONWARNING);
    return0;
    }

    while (true)
    {
    if(ReadFile(hRead,buf,sizeof(buf) -1,&bytesRead,NULL)==NULL)
    break;

    ((CAConverterDlg
    *)param)->strOutput = buf;// "+=" 表示将cmd屏幕上的内容全部读进strOutput 而“=”则表示覆盖上一次读进去的内容,只显示当前

    CAtlString resToken;
    int curPos =0;

    //--------------------------------提取进度百分数--------------------------------------------------
    resToken= ((CAConverterDlg*)param)->strOutput.Tokenize(_T("()"),curPos);
    while (resToken != _T(""))
    {
    resToken
    = ((CAConverterDlg*)param)->strOutput.Tokenize(_T("()"), curPos);

    if(resToken.GetLength()<4&&resToken.GetLength()>1&&(resToken.FindOneOf(L"1234567890%")!=-1))
    {
    SetDlgItemTextW(((CAConverterDlg
    *)param)->m_hWnd,IDC_EDIT_PROGRESS,resToken);
    }
    }
    SetDlgItemText(((CAConverterDlg
    *)param)->m_hWnd,IDC_EDIT_OUTPUT,((CAConverterDlg*)param)->strOutput); //显示输出信息到编辑框,并刷新窗口
    Sleep(100);
    UpdateWindow(NULL);
    memset(buf,
    0, sizeof(buf));
    //----------------------------------------------------------------------------------------------
    }
    CloseHandle(hWrite);
    //关闭管道句柄
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    CloseHandle(hRead);

    return0;
    }

    另外还可以将得到的信息写入文件,代码如下:

    代码
    static DWORD WINAPI ReadThread_WritToFile(LPVOID lpParam)
    {
    char buf[1024];
    memset(buf,
    0, sizeof(buf));
    DWORD bytesRead;
    HANDLE
    *phread_echo = (HANDLE *)lpParam;
    while(ReadFile(*phread_echo, buf, sizeof(buf) -1, &bytesRead, NULL))
    {
    HANDLE hFileWrite
    = CreateFile(L"a.txt",GENERIC_WRITE,0,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
    if(hFileWrite == INVALID_HANDLE_VALUE)
    {
    MessageBox(NULL,L
    "fail to open",L"",NULL);
    }
    SetFilePointer(hFileWrite,
    0,0,FILE_END);
    DWORD dwWriteDataSize;
    WriteFile(hFileWrite,(LPCWSTR)buf,
    2048,&dwWriteDataSize,NULL);
    CloseHandle(hFileWrite);
    memset(buf,
    0, sizeof(buf));
    Sleep(
    1);
    }
    return0;
    }

     还有一种方法就是向窗口发送消息,这种想法是参考的下面一段文章:

    VC多线程中控制界面控件的几种方法

    为了保证界面的用户体验经常要把数据处理等放到子线程中进行,然后把结果更新到主界面,通常有这样几种方法。

       1.启动线程时把控件关联变量的指针传参给线程函数,这种方法无疑是最简单的方法,但极容易造成访问异常,因为VC6中的控件都不是线程安全的。

       2.就是先进一点的方法,把控件的句柄传给线程函数,在子线程中通过SendNotifyMessage or PostMessage等进行操作。这种方法是线程安全的,但对许多未公开控件你根本不知道要发送什么消息的,比如绝大多数的ActiveX控件,像MSFLEXGRID、DBGRID,它们的消息ID是无从知晓的,这种时候第二种方法就没用了。

       3.这种方法我感觉是最万能的方法了,而且这样代码的逻辑也最清楚。就是在窗口类中针对线程要进行的操作自定义消息,启动线程时直接把窗口的句柄传给线程函数,线程要控制界面时直接给窗口发消息就可以了。窗口类中对自定义消息添加消息映射,在其中进行具体的控制操作

     

    但好像不适合需要对控件刷新,应该和一种方法差不多,会导致UI卡,代码如下:

    #define WM_MY_MESSAGE (WM_USER + 100)  //----------------自定义消息----------------------

    // -----------------------生成的自定义消息映射函数-----------------------
     afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);

    ON_MESSAGE(WM_MY_MESSAGE,OnMyMessage) //---------------自定义消息映射-------------

    代码
    LRESULT CAConverterDlg::OnMyMessage(WPARAM wParam, LPARAM lParam)
    {
    char buf[1024];
    memset(buf,
    0, sizeof(buf));
    DWORD bytesRead;
    HANDLE
    *phread_echo = (HANDLE*)lParam;
    while (true)
    {
    if (ReadFile(*phread_echo,buf,sizeof(buf) -1,&bytesRead,NULL) == NULL) //读取管道
    break;

    strOutput
    += buf;

    CAtlString resToken;
    int curPos =0;

    resToken
    = strOutput.Tokenize(_T("()"),curPos);
    while (resToken != _T(""))
    {
    resToken
    = strOutput.Tokenize(_T("()"), curPos);
    if(resToken.GetLength()<5&&resToken.GetLength()>2)SetDlgItemTextW(IDC_EDIT_PROGRESS,resToken);
    }
    SetDlgItemText(IDC_EDIT_OUTPUT,strOutput);
    //显示输出信息到编辑框,并刷新窗口
    Sleep(100);
    UpdateWindow();
    memset(buf,
    0, sizeof(buf));
    }
    return0;
    }
  • 相关阅读:
    使用Shell脚本查找程序对应的进程ID,并杀死进程
    转,mysql快速保存插入大量数据一些方法总结
    L2TP/IPSec一键安装脚本
    全文搜索引擎 Elasticsearch 入门教程
    vmware设置扩大硬盘后如何在linux内容扩容
    Java序列化说明
    GIT常用命令
    java中的CAS
    Class.forName()用法详解
    Java用pdfbox或icepdf转换PDF为图片时,中文乱码问题
  • 原文地址:https://www.cnblogs.com/Daywei/p/1935604.html
Copyright © 2011-2022 走看看