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

 

 

 

posted on 2011-01-14 15:14  Daywei  阅读(254)  评论(0编辑  收藏  举报

导航

技术追求卓越 梦想创造未来