用什么方法调用控制台程序

szramon 2010-07-15 07:21:49
-------------------------------用什么方法调用控制台程序,同时做到:1.隐藏控制台窗口;2.获取控制台程序的exit status -----------------------------------------

用什么方法调用控制台程序,同时做到:1.隐藏控制台窗口;2.获取控制台程序的exit status

我用system和_spawnlp,返回值就是exit code,但无法隐藏窗口。
用WinExec(command,SW_HIDE)可以隐藏窗口,但是得不到exit code。

请指点,谢谢~

问题点数:100、回复次数:6
1楼 keiy () 回复于 2005-03-26 17:37:04 得分 0

用 CreateProcess + GetExitCodeProcess 试试

Top
2楼 wly033 (明) 回复于 2005-03-26 18:06:31 得分 5

CreateProcess + waitforsingleobject + GetExitCodeProcess

Top
3楼 subtop (seeking job...) 回复于 2005-03-26 18:44:58 得分 5

按楼上的方法试试看.

Top
4楼 keiy () 回复于 2005-03-26 19:04:11 得分 0

我试了一下,有问题
CreateProcess如果用STARTF_USESHOWWINDOW+SW_HIDE
WaitForSingleObject不会返回
GetExitCodeProcess也得不到返回值
如果不用STARTF_USESHOWWINDOW,可正常得到ExitCode



Top
5楼 keiy () 回复于 2005-03-26 19:48:06 得分 90

成功:
PROCESS_INFORMATION pi;
STARTUPINFO si;

// Set up the start up info struct.
ZeroMemory(&si,sizeof(STARTUPINFO));

si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;

CreateProcess(NULL,"d:\\temp\\t.exe", NULL, NULL, 0,
NULL, NULL, NULL, &si, &pi);
WaitForSingleObject(pi.hThread,INFINITE);
CloseHandle(pi.hThread);
DWORD excode=0;
GetExitCodeProcess(pi.hProcess,&excode);
//excode为返回值

Top
6楼 keiy () 回复于 2005-03-26 19:51:23 得分 0

另外,si.wShowWindow = SW_HIDE;可省
(因为SW_HIDE的值为0)


--------------怎么获得控制台程序输出---------------------------------------------------------
假设我在GUI程序中执行ping 命令,怎么把ping命令产生的控制台输出 在GUI程序中获得.
我现在是用ShellExecute执行的ping命令
HINSTANCE hInstance = ShellExecute(NULL,NULL,"ping.exe","10.57.18.166",NULL,SW_SHOW);
怎么获得输出?
如果这种方法不行,那用哪种方法可以获得输出?

我不想用>a.txt管道形式先输出到文件,然后再读取,我想直接获得,谢谢
---------------------------------------------------------------

用管道重定义标准输出. 用 CreateProcess 可以指定控制台程序的输出流
---------------------------------------------------------------

输出管道重定向
---------------------------------------------------------------

在Windows环境下的所谓shell程序就是dos命令行程序,比如VC的CL.exe命令行编译器,JDK的javac编译器,启动java程序用的java.exe都是标准的shell程序。截获一个shell程序的输出是很有用的,比如说您可以自己编写一个IDE(集成开发环境),当用户发出编译指令时候,你可以在后台启动shell 调用编译器并截获它们的输出,对这些输出信息进行分析后在更为友好的用户界面上显示出来。为了方便起见,我们用VB作为本文的演示语言。

通常,系统启动Shell程序时缺省给定了3个I/O信道,标准输入(stdin), 标准输出stdout, 标准错误输出stderr。之所以这么区分是因为在早期的计算机系统如PDP-11的一些限制。那时没有GUI, 将输出分为stdout,stderr可以避免程序的调试信息和正常输出的信息混杂在一起。

通常, shell程序把它们的输出写入标准输出管道(stdout)、把出错信息写入标准错误管道(stderr)。缺省情况下,系统将管道的输出直接送到屏幕,这样一来我们就能看到应用程序运行结果了。

为了捕获一个标准控制台应用程序的输出,我们必须把standOutput和standError管道输出重定向到我们自定义的管道。

下面的代码可以启动一个shell程序,并将其输出截获。




'执行并返回一个命令行程序(shell程序)的标准输出和标准错误输出
'通常命令行程序的所有输出都直接送到屏幕上
Private Function ExecuteApp(sCmdline As String) As String
Dim proc As PROCESS_INFORMATION, ret As Long
Dim start As STARTUPINFO
Dim sa As SECURITY_ATTRIBUTES
Dim hReadPipe As Long '负责读取的管道
Dim hWritePipe As Long '负责Shell程序的标准输出和标准错误输出的管道
Dim sOutput As String '放返回的数据
Dim lngBytesRead As Long, sBuffer As String * 256

sa.nLength = Len(sa)
sa.bInheritHandle = True

ret = CreatePipe(hReadPipe, hWritePipe, sa, 0)

If ret = 0 Then
MsgBox "CreatePipe failed. Error: " & Err.LastDllError
Exit Function
End If

start.cb = Len(start)
start.dwFlags = STARTF_USESTDHANDLES Or STARTF_USESHOWWINDOW
' 把标准输出和标准错误输出重定向到同一个管道中去。
start.hStdOutput = hWritePipe
start.hStdError = hWritePipe
start.wShowWindow = SW_HIDE '隐含shell程序窗口
' 启动shell程序, sCmdLine指明执行的路径
ret = CreateProcessA(0&, sCmdline, sa, sa, True, NORMAL_PRIORITY_CLASS, _
0&, 0&, start, proc)
If ret = 0 Then
MsgBox "无法建立新进程,错误码:" & Err.LastDllError
Exit Function
End If
' 本例中不必向shell程序送信息,因此可以先关闭hWritePipe
CloseHandle hWritePipe
' 循环读取shell程序的输出,每次读取256个字节。
Do
ret = ReadFile(hReadPipe, sBuffer, 256, lngBytesRead, 0&)
sOutput = sOutput & Left$(sBuffer, lngBytesRead)
Loop While ret <> 0 ' 如果ret=0代表没有更多的信息需要读取了

' 释放相关资源
CloseHandle proc.hProcess
CloseHandle proc.hThread
CloseHandle hReadPipe
ExecuteApp = sOutput ' 输出结果
End Function



我对这个程序进行一些解释。

ret = CreatePipe(hReadPipe, hWritePipe, sa, 0)

大家可以看到,首先我们建立一个匿名管道。该匿名管道稍候将用来取得与被截获的应用程序的联系。其中hReadPipe用来获取shell程序的输出,而hWritePipe可以用来向应用程序发送信息。如同现实世界中的水管一样,水从管道的一端流进从另一端流出。您把水想象为信息,水管就是匿名管道,这样一来就很好理解这段程序了。
然后就是设置shell应用程序的初始属性。 Dwflags可以指示系统在创建新进程时新进程使用了自定义的wShowWindow, hStdInput,hStdOutput和hStdError。(windows显示属性,标准输入,标准输出,标准错误输出。)
再把shell应用程序的标准输出和标准错误输出都定向到我们预先建好的管道中。
代码如下:

start.dwFlags = STARTF_USESTDHANDLES Or STARTF_USESHOWWINDOW
start.hStdOutput = hWritePipe
start.hStdError = hWritePipe
好,现在可以调用建立新进程的函数了:
ret = CreateProcessA(0&, sCmdline, sa, sa, True, NORMAL_PRIORITY_CLASS, 0&, 0&, start, proc)
然后,循环读管道里的数据直到无数据可读为止。
Do
ret = ReadFile(hReadPipe, sBuffer, 256, lngBytesRead, 0&) '每次读256字节
sOutput = sOutput & Left$(sBuffer, lngBytesRead) '送入一个字符串中
Loop While ret <> 0 '若 ret = 0 表明没有数据等待读取。
然后,释放不用的资源。

用法很简单:比如:
MsgBox ExecuteApp("c:\windows\command\mem.exe)

是很方便吧?
不过,这些程序是在NT下的,如果要在95下实现还需要一点点改动。因为如果该函数调用一个纯win32的程序,没问题。可是95是16,win32混合的系统,当你试图调用一个16位的DOS应用程序那么,那么这个办法会导致相关进程挂起。因为这涉及到WindowsNT和Windows 95对shell的不同实现。
在win95中,16位shell程序关闭时并不保证重定向的管道也关闭,这样,当你的程序试图读取一个已经关闭的shell程序的重定向管道时,你的程序就挂了。
那么,有解决办法吗?回答是肯定的。
解决办法就是用一个win32的应用程序作为您的应用程序和shell程序的中间人。中间人程序继承并重定向了主程序的输入输出,然后中间人程序启动指定的shell程序。该shell程序也就继承并重定向了主







...全文
509 4 打赏 收藏 转发到动态 举报
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
yixian1188 2011-05-06
  • 打赏
  • 举报
回复
很受用,TKS...
szramon 2010-07-16
  • 打赏
  • 举报
回复
现在是vc中使用ShellExecute函数来调用外部exe程序了.格式为:



de>::ShellExecute(NULL,"open","svm-train.exe",s_train_in,".\\svm\\",SW_HIDE);de>


其中,svm-train.exe为运行程序,s_train_in为传输给该程序的参数字符串,".\\svm\\"为程序存在的默认目录,SW_HIDE表示不显示该命令解释窗口,否则为SW_SHOW显示的时候会看到dos窗口闪一下就没有了.

ShellExecute函数的参数说明可以随意查到,不在详述.

这样我们就可以实现在vc下的libsvm的调用,并且又不需要对该算法有详细的了解.需要做的就是知道这些程序需要哪些参数.

获得参数列表可以不带参数在dos行下执行这些命令,或者查看源代码就会知道.
szramon 2010-07-16
  • 打赏
  • 举报
回复
VC中调用dos程序,如何才能读取dos程序的重定向输出文件?
悬赏分:20 - 解决时间:2007-9-22 04:18
我在代码中使用ShellExecute调用了dos.exe程序,该程序的输出重定向到temp.txt,后面就打开该文件读取内容。从程序执行上看已经生成了temp.txt文件,但是执行到open那里就出错了。
另外,在windows中双击该文件显示“访问拒绝”,这是怎么回事啊?

附代码:
ShellExecute(NULL,_T("open"),_T("Command.com"), _T("dos.exe >temp.txt"),NULL,SW_HIDE);
CFile tempFile;
if (0 == tempFile.Open(_T("temp.txt"), CFile::modeRead | CFile::typeText))
{
m_List.AddString(_T("打开失败"));
}
while(0 != tempFile.Read(str, 100))
{
m_List.AddString((LPTSTR)str);
}
szramon 2010-07-16
  • 打赏
  • 举报
回复
HANDLE hProcess=GetCurrentProcess();
SECURITY_ATTRIBUTES sa;
sa.nLength=sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle=TRUE;
sa.lpSecurityDescriptor=NULL;

HANDLE hStdinRd, hStdinWr, hStdinWrDup;
HANDLE hStdoutRd, hStdoutWr,hStdoutRdDup;

//** 创建读写管道
BOOL rc;
rc=CreatePipe(&hStdoutRd, &hStdoutWr, &sa, 0);
if(!rc) return -1;
rc=CreatePipe(&hStdinRd, hStdinWr, &sa, 0);
if(!rc) return -1;

//** hStdout管道的读取端需保留在本进程,不能继承给子进程,需要复制出一个不可继承的句柄
rc=DuplicateHandle(hProcess, hStdoutRd, hProcess, &hStdoutRdDup, 0, FALSE, DUPLICATE_SAME_ACCESS);
CloseHandle(hStdoutRd);

//** hStdin管道的写入端需保留在本进程,不能继承给子进程,需要复制出一个不可继承的句柄
rc=DuplicateHandle(hProcess, hStdinWr, hProcess, &hStdinWrDup, 0, FALSE, DUPLICATE_SAME_ACCESS);
CloseHandle(hStdinWr);

PROCESS_INFORMATION pi={0};
STARTUPINFO si={sizeof(STARTUPINFO};
si.dwFlags=STARTF_USESTDHANDLES;
si.hStdInput=hStdinRd;
si.hStdOutput=hStdoutWr;
si.hStdError=hStdoutWr;

rc=CreateProcess( "cmd.exe ", NULL, NULL, 0, TRUE, 0, NULL, NULL, &si, &pi);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);

//**将所有命令存到一个字符串中,前后二个命令中间以\r\n分隔。
TCHAR szCmds[4096]=TEXT( "dir\r\nattrib\r\n "); //命令间以\r\n分隔
DWORD dwWrite=lstrlen(szCmd);
//** 从复制后的hstdinWrDup管道端写入dos命令
WriteFile(hStdinWrDup, szCmds, dwWrite, &dwWrite, NULL);

TCHAR buffer[64*1024+1];
DWORD dwBuffer=sizeof(buffer);

//** 从复制后的hstdoutRdDup管道端读取输出结果
ReadFile(hStdoutRdDup, buffer, dwBuffer, &dwBuffer, NULL);

---------------------

我改用WinExec之后速度提高了一点点,45秒左右,但是还是太慢了,呵呵
chehw(chehw)我用你的方法,执行CreateProcess( "cmd.exe ", NULL, NULL, 0, TRUE, 0, NULL, NULL, &si, &pi);时不成功,改成CreateProcess( "cmd.exe ", NULL, NULL, NULL, NULL, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, NULL, NULL, &si, &pi);也不行,什么问题?

------

CreateProcess( "c:\\windows\\system32\\cmd.exe ",

-------

BOOL LaunchExe::PipeResult( const CString& CommandLine, const CString& Parameters,
CString& strOutFile )
{
STARTUPINFO si;
memset( &si, 0, sizeof( si ) );
si.cb = sizeof( si );
// Hide DOS window
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOW;
// Prepare pipe handles for standard output redirection
SECURITY_ATTRIBUTES saAttr;
// Set the bInheritHandle flag so pipe handles are inherited.
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
HANDLE hReadPipe, hWritePipe;
BOOL res = CreatePipe( &hReadPipe, &hWritePipe, &saAttr, 0 );
if ( !res )
{
return res;
}
else
{
si.dwFlags |= STARTF_USESTDHANDLES;
si.hStdOutput = hWritePipe;
si.hStdInput = hWritePipe;
si.hStdError = hWritePipe;
PROCESS_INFORMATION pi;
CString sFullCommand = "\ " " + CommandLine + "\ " " + Parameters;
res = CreateProcess( NULL, (LPTSTR)(LPCTSTR)sFullCommand, NULL, NULL, TRUE,
0, NULL, NULL, &si, &pi );
if (!res)
{
// process error of rsh
return res;
}
else
{
// Close write pipe
CloseHandle( hWritePipe );
DWORD NumberOfBytesRead;
TCHAR Buffer[ 257 ];
while(::ReadFile( hReadPipe, Buffer, sizeof(Buffer)/sizeof(Buffer[ 0 ])-1,
&NumberOfBytesRead, NULL ) )
{
if (NumberOfBytesRead)
{
Buffer[ NumberOfBytesRead ] = TCHAR( 0 );
strOutFile += Buffer;
}
else
break;
};
// Close read pipe and wait for the finish
CloseHandle( hReadPipe );
WaitForSingleObject( pi.hProcess, INFINITE );
CloseHandle (pi.hProcess);
res = TRUE;
}
}
return res;
}

输出信息在strOutFile,把他读到editbox或者直接输出到editbox


15,440

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 非技术区
社区管理员
  • 非技术区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧