ShellExecute( NULL, "open", "calc.exe", NULL, NULL, SW_SHOWNORMAL );
int nRet= (int)ShellExecute( 0,"open","calc.exe",0,0,SW_SHOWNORMAL);
if ( nRet <= 32 ) {
DWORD dw= GetLastError();
char szMsg[250];
FormatMessage(
FORMAT_MESSAGE_FROM_SYSTEM,
0, dw, 0,
szMsg, sizeof(szMsg),
NULL
);
MessageBox( szMsg, "Error launching Calculator" );
}
ShellExecute( NULL, "open",
"WinRAR.Exe", // Program to launch
"x c:\\temp\\MyTextArchive.ZIP *.txt c:\\temp\\junk", // parms
NULL, // default dir (don't care)
SW_SHOWNORMAL
);
ShellExecute( NULL, "open",
"c:\\temp\\UserGuide.PDF", // document to launch
NULL, // parms -- not used when launching a document
NULL, // default dir (don't care here)
SW_SHOWNORMAL
);
ShellExecute( NULL, "print", // verb: print
"c:\\temp\\UserGuide.PDF", // document to launch
NULL, // parms -- not used when launching a document"
NULL, // default dir (don't care here)
SW_SHOWNORMAL
);
ShellExecute( NULL, "open",
"c:\\temp\\DoStuff.bat", // program to launch
"Hi There", // parms (will be %1 and %2 in the batch file)
"c:\\temp\\junk", // default dir for the batch
SW_HIDE
);
ShellExecute( NULL, "explore",
"c:\\temp", // folder name
NULL,
NULL,
SW_SHOWNORMAL
);
ShellExecute( NULL, "open",
"http://www.experts-exchange.com/A_1518.html", // URL
NULL,
NULL,
SW_SHOWNORMAL
);
SHELLEXECUTEINFO rSEI ={0};
rSEI.cbSize=sizeof( rSEI );
rSEI.lpVerb= "open";
rSEI.lpFile= "calc.Exe";
rSEI.lpParameters= 0;
rSEI.nShow = SW_NORMAL;
rSEI.fMask = SEE_MASK_NOCLOSEPROCESS;
ShellExecuteEx( &rSEI ); // you should check for an error here
while( TRUE ) {
DWORD nStatus= MsgWaitForMultipleObjects(
1, &rSEI.hProcess, FALSE,
INFINITE, QS_ALLINPUT // drop through on user activity
);
if ( nStatus == WAIT_OBJECT_0 ) { // done: the program has ended
break;
}
MSG msg; // else process some messages while waiting...
while( PeekMessage(&msg,NULL,0,0,PM_REMOVE) ){
DispatchMessage( &msg );
}
} // launched process has exited
DWORD dwCode;
GetExitCodeProcess( rSEI.hProcess, &dwCode ); // ERRORLEVEL value
Something to watch out for when using a message-pumping sequence like that in
lines 18-21: Your U/I is entirely active while waiting for the other program to end. That means that the user could close your program, which puts you in a sort of limbo. A better technique is to not sit there in a loop pumping messages, but rather set a timer and use it to check every so often to see if
rSEI.hProcess has exited, then start the post-launch processing at that point in time. Something like this:
void CMyDlg::OnTimer(UINT_PTR nIDEvent)
{
if ( m_hProcessWeLaunched != 0 ) {
if ( WaitForSingleObject( m_hProcessWeLaunched,0)==WAIT_OBJECT_0 ) {
m_hProcessWeLaunched= 0;
MessageBox("done"); // The program ended. Start the next step.
}
}
CDialog::OnTimer(nIDEvent);
}
#include <process.h>
...
system( "dir c:\\temp > c:\\temp\\output.txt" );
That is, let Cmd.Exe redirect the output into a file by using the standard I/O redirection arrow
>. Later, you can process the resulting file (output.txt) as necessary.
PROCESS_INFORMATION ePI={0};
STARTUPINFO rSI={0};
rSI.cb= sizeof( rSI );
rSI.dwFlags= STARTF_USESHOWWINDOW;
rSI.wShowWindow= SW_SHOWNORMAL; // or SW_HIDE or SW_MINIMIZED
BOOL fRet= CreateProcess(
"c:\\windows\\notepad.exe", // program name
" c:\\temp\\report.txt", // ...and parameters
NULL, NULL, // security stuff (use defaults)
TRUE, // inherit handles (not important here)
0, // don't need to set priority or other flags
NULL, // use default Environment vars
NULL, // don't set current directory
&rSI, // where we set up the ShowWIndow setting
&ePI // gets populated with handle info
);
If it is more convenient, you can set the first parameter to NULL and put the entire command line in the second parameter. If you do that, and if the program pathname contains any embedded spaces, be sure to enclose that part of the command line in double quotes.
int ReadFromPipeNoWait( HANDLE hPipe, char* pDest, int nMax )
{
DWORD nBytesRead= 0;
DWORD nAvailBytes;
char cTmp;
memset( pDest, 0, nMax );
// -- check for something in the pipe
PeekNamedPipe( hPipe, &cTmp, 1, NULL, &nAvailBytes, NULL );
if ( nAvailBytes == 0 ) {
return( nBytesRead );
}
// OK, something there... read it
ReadFile( hPipe, pDest, nMax-1, &nBytesRead, NULL);
return( nBytesRead );
}
BOOL ExecAndProcessOutput(LPCSTR szCmd, LPCSTR szParms )
{
SECURITY_ATTRIBUTES rSA= {0};
rSA.nLength= sizeof(SECURITY_ATTRIBUTES);
rSA.bInheritHandle= TRUE;
HANDLE hReadPipe, hWritePipe;
CreatePipe( &hReadPipe, &hWritePipe, &rSA, 25000 );
PROCESS_INFORMATION rPI= {0};
STARTUPINFO rSI= {0};
rSI.cb= sizeof(rSI);
rSI.dwFlags= STARTF_USESHOWWINDOW |STARTF_USESTDHANDLES;
rSI.wShowWindow= SW_HIDE; // or SW_SHOWNORMAL or SW_MINIMIZE
rSI.hStdOutput= hWritePipe;
rSI.hStdError= hWritePipe;
CString sCmd; sCmd.Format( "\"%s\" %s", (LPCSTR)szCmd, (LPCSTR)szParms );
BOOL fRet=CreateProcess(NULL,(LPSTR)(LPCSTR)sCmd, NULL,
NULL,TRUE,0,0,0, &rSI, &rPI );
if ( !fRet ) {
return( FALSE );
}
//------------------------- and process its stdout every 100 ms
char dest[1000];
CString sProgress = "";
DWORD dwRetFromWait= WAIT_TIMEOUT;
while ( dwRetFromWait != WAIT_OBJECT_0 ) {
dwRetFromWait= WaitForSingleObject( rPI.hProcess, 100 );
if ( dwRetFromWait == WAIT_ABANDONED ) { // crash?
break;
}
//--- else (WAIT_OBJECT_0 or WAIT_TIMEOUT) process the pipe data
while ( ReadFromPipeNoWait( hReadPipe, dest, sizeof(dest) ) > 0 ) {
// ------------------ Do something with the output.
// ------------------ Eg, insert at the end of an edit box
int iLen= gpEditBox->GetWindowTextLength();
gpEditBox->SetSel( iLen, iLen);
gpEditBox->ReplaceSel( dest );
}
}
CloseHandle( hReadPipe );
CloseHandle( hWritePipe );
CloseHandle( rPI.hThread);
CloseHandle( rPI.hProcess);
// MessageBox("All done!");
return TRUE;
}
And here's an example of starting that whole sequence:
void CMyTestDlg::OnBnClickedButton1()
{
CString sCmd= "c:\\windows\\system32\\Cmd.Exe";
CString sParms=" /c dir c:\\windows\\*.* /s";
gpEditBox= &m_ctlEditBox;
gpEditBox->SetLimitText( 500000 ); // plenty of room
BOOL fRet= ExecAndProcessOutput( sCmd, sParms );
ShellExecute( NULL, "runas",
"c:\\windows\\notepad.exe", // program name
" c:\\temp\\report.txt", // ...and parameters
NULL, // default dir (don't care here)
SW_SHOWNORMAL
);
#include <process.h>
...
system("dir c:\\temp"); // any DOS command
system("notepad"); // execute as from command line
_spawn("dir c:\\temp"); // similar, but there are many options
int nRet= _spawnl( _P_WAIT, "c:\\windows\\notepad.exe", "notepad", 0 );
int nRet= _execl( "c:\\windows\\notepad.exe", "notepad", 0 );
The
system function always opens a DOS window. It appears to to run
Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.
Comments (5)
Commented:
Please continue.
Author
Commented:Commented:
Just a small info:
ShellExecuteEx requires RPC service to be turned on to get the status. It will be nice if you add this also into your article.
Commented:
Open in new window
Commented: