C++ system function hangs application - c++

I have the following code
void reportResults()
{
wstring env(_wgetenv(L"ProgramFiles"));
env += L"\Internet Explorer\iexplore.exe";
wstringstream url;
url << "\"\"" << env.c_str() << "\" http://yahoo.com\"";
wchar_t arg[BUFSIZE];
url.get(arg, BUFSIZE);
wcout << arg << endl;
_wsystem(arg);
}
Where arg is:
""C:\Program Files\Internet Explorer\iexplore.exe" http://yahoo.com"
The program functions as expected, launching IE and navigating to Yahoo, but the calling function (reportResults) never exits. How do I get the program to exit leaving the browser alive?
Thanks.

You want to use _wspawn() instead of _wsystem(). This will spawn a new process for the browser process. _wsystem() blocks on the command that you create; this is why you're not getting back to your code. _wspawn() creates a new, separate process, which should return to your code immediately.

The _wsystem command will wait for the command in arg to return and returns the return value of the command. If you close the Internet Explorer window it will return command back to your program.

Why not just use ShellExecute to launch the default browser with a given URL?
Synopsis:
LONG r = ShellExecute(NULL, "open", "http://www.microsoft.com", NULL, NULL, SW_SHOWNORMAL);
EDIT:
I suppose since it must be IE, this might work (note, untested code):
LONG r = ShellExecute(NULL, NULL, "iexplore.exe", "http://www.microsoft.com", NULL, SW_SHOWNORMAL);

If you want to use the current implementation, you will have to fork() the process and let a child handle the browser spawning. Thus, the main process will continue and exit the function.

Instead of executing
"C:\Program Files\Internet Explorer\iexplore.exe" "http://yahoo.com"
execute
start "C:\Program Files\Internet Explorer\iexplore.exe" "http://yahoo.com"

Related

Getting the messages back to the same command line from where the MFC application was launched

I am executing an MFC Application from command line which takes four command line arguments.One of the argument is the directory path.
If the path is wrong then I want to show a Message "Bad Path" on the same command line
Note : For showing I don't want to take a new command line .
Basically that's not supported. There is sort of known "workaround" for that, using AttachConsole(-1) to attach parent process console. Has disadvantages of course (like, parent console will not wait for your EXE to terminate, because it's not a "console" app). Anyways, basic idea:
void WriteToParentConsole()
{
if (AttachConsole(-1))
{
char msg[] = "Bad Path!";
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), msg, sizeof(msg), NULL, NULL);
// send ENTER (optional)
// ::SendMessage(GetConsoleWindow(), WM_CHAR, VK_RETURN, 0);
FreeConsole();
}
}
You can check out this article for example, or just google something on AttachConsole/GUI vs Console for more information:
http://www.tillett.info/2013/05/13/how-to-create-a-windows-program-that-works-as-both-as-a-gui-and-console-application/

Waitforsingleobject to detect a system command exit

Hi I want to execute a system command for allegro and wait till it completes, since I need to access the files generated by this command. My code is not working. Can someone please help? Is the command not running? It works if I do system(command.c_str()) but does not wait.
string command = "start allegro -expert -nographic -s " + fileName1 + " " + boardFile1;
bool ret;
bool retwait;
STARTUPINFO startupinfo;
GetStartupInfo (&startupinfo);
PROCESS_INFORMATION pro2info;
LPTSTR cmdL = (LPTSTR)command.c_str();
ret = CreateProcess(NULL, cmdL, NULL, NULL, false, CREATE_NEW_CONSOLE, NULL,NULL, &startupinfo, &pro2info);
cout<<"hProcess: "<<pro2info.hProcess<<endl;
cout<<"dwProcessId: "<<pro2info.dwProcessId <<endl;
//Want to wait till the command executes
while (retwait= WaitForSingleObject (pro2info.hProcess, INFINITE)!=WAIT_OBJECT_0)
cout<<"waitprocess:true"<<endl; //The process is finished;
CloseHandle (pro2info.hProcess);
I think you don't need "start" at the beginning of command, even if you are using the flag CREATE_NEW_CONSOLE. "start" works with system (because system works with batch command), but if you are creating a new process you should only specify the path to the image file. By the way, the only way to know what's going on is to check the return of CreateProcess (and eventually GetLastError()).
Also, that's not the best way to use WaitForSingleObject. You should catch WAIT_FAILED and use GetLastError(), otherwise your next post on SO will be: "Why isn't my program waiting?" :-)
http://msdn.microsoft.com/en-us/library/windows/desktop/ms682425%28v=vs.85%29.aspx

Writing to a process STDIN via Windows pipes

I am trying to create a function that will spawn an instance of a program and then pipe some data into its STDIN and then read the process's output using C++. I have looked at an MSDN example located here which is rather confusing to me and when I try to use the example, I get some nasty error codes and it won't work.
HANDLE hWriteOUT, hReadOUT, hWriteIN, hReadIN;
SECURITY_ATTRIBUTES saPipe = {0};
PROCESS_INFORMATION procInfo = {0};
STARTUPINFO procSi;
DWORD dwWritten, dwRead;
char buf[512];
saPipe.nLength = sizeof(SECURITY_ATTRIBUTES);
saPipe.bInheritHandle = TRUE;
saPipe.lpSecurityDescriptor= NULL;
CreatePipe(&hReadOUT, &hWriteOUT, &saPipe, 0);
SetHandleInformation(hReadOUT, HANDLE_FLAG_INHERIT, 0);
CreatePipe(&hReadIN, &hWriteIN, &saPipe, 0);
SetHandleInformation(hReadIN, HANDLE_FLAG_INHERIT, 0);
ZeroMemory(&procSi, sizeof(STARTUPINFO));
procSi.cb = sizeof(STARTUPINFO);
procSi.hStdError = hWriteOUT;
procSi.hStdOutput = hWriteOUT;
procSi.hStdInput = hReadIN;
procSi.dwFlags |= STARTF_USESTDHANDLES;
CreateProcess(NULL, "cmd", NULL, NULL, TRUE, 0, NULL, NULL, &procSi, &procInfo);
//Gives me an error code of 18 but returns a 1 when a 0 indicates failure.
WriteFile(hWriteIN, "notepad", sizeof("notepad"), &dwWritten, NULL);
cout << GetLastError(); //This gives me error code 18 (ERROR_NO_MORE_FILES)
ReadFile(hReadOUT, buf, 512, &dwRead, NULL);
cout << buf; //This prints "Microsoft Windows [version 6.1.7601]
CloseHandle(hWriteIN);
The code fails to pipe the string "notepad" into cmd.exe but is successful in launching the command shell. If I look in task manager, there are several instances of command prompt spawned but no notepads. In addition, the ReadFile() function is the only one that seemed to have worked, but it's not even reading from the piped process (notepad that was supposed to be spawned) instead, it's reading from CMD. And even worse, it's truncating everything but the first line that it reads! (CMD prints the "Microsoft Windows....\n Copyright...\n C:\Users\Foo>...\n" but the `ReadFile() only grabs the first line)
The code is behaving as expected. There are a number of things you seem to be misunderstanding:
1) You need to send an ENTER ("\n") at the end of a command if you want cmd.exe to run it. Usually it is preferable to specify the command you want to run in CreateProcess, e.g., you could specify "cmd /c notepad" as the command line instead of just "cmd".
2) You've attached your pipes to the standard input and output of the cmd.exe process, so of course you see output from that process. If you don't want to see output from cmd.exe, don't run it; run the application you want directly, e.g., you could specify "notepad" as the command line to run.
3) When reading from a pipe, ReadFile only returns a single block of data at a time, so you need to call it in a loop.
4) Notepad is a GUI process, so it doesn't use stdin or stdout anyway. Presumably this was just a poorly chosen example and you actually want to run a command-line application?
5) Except as specifically documented, the error code (as returned by GetLastError) is only meaningful when a function has failed. None of the functions you are using are exceptions to this case, so there is no point in checking the error code unless the function returns zero to indicate that it has failed.
I know it's kinda too late to answer this question but there is also something else wrong with your code. it seems SetHandleInformation(hReadOUT, HANDLE_FLAG_INHERIT, 0); and SetHandleInformation(hReadIN, HANDLE_FLAG_INHERIT, 0); will break things. I'm not sure why, but after trying t run your code, cmd could not read values from pipe until I remove those two lines.

Trouble restarting exe

I need to restart the program that im working on after an update has been downloaded except im running into some issues.
If i use CreateProcess nothing happens, if i use ShellExecute i get an 0xC0150002 error and if i use ShellExecute with the command "runas" it works fine. I can start the command prompt fine using CreateProcess and ShellExecute just not the same exe again and dont want to use runas as this will elevate the exe.
Any Ideas?
Windows 7, visual studio 2008 c++
alt text http://lodle.net/shell_error.jpg
CreateProcess:
char exePath[255];
GetModuleFileName(NULL, exePath, 255);
size_t exePathLen = strlen(exePath);
for (size_t x=exePathLen; x>0; x--)
{
if (exePath[x] == '\\')
break;
else
exePath[x] = '\0';
}
char name[255];
GetModuleFileName(NULL, name, 255);
PROCESS_INFORMATION ProcInfo = {0};
STARTUPINFO StartupInfo = {0};
BOOL res = CreateProcess(name, "-wait", NULL, NULL, false, 0, NULL, exePath, &StartupInfo, &ProcInfo );
ShellExecute:
char exePath[255];
GetModuleFileName(NULL, exePath, 255);
size_t exePathLen = strlen(exePath);
for (size_t x=exePathLen; x>0; x--)
{
if (exePath[x] == '\\')
break;
else
exePath[x] = '\0';
}
char name[255];
GetModuleFileName(NULL, name, 255);
INT_PTR r = (INT_PTR)ShellExecute(NULL, "runas", name, "-wait", exePath, SW_SHOW);
CreateProcess() is an arcane beast. I remember unfondly my first frustrations with it. You should look at the Microsoft CreateProcess Example and the CreateProcess Page. (those links likely have a short lifetime, Googling CreateProcess should work just as well).
I can see 3 problems in your code.
StartupInfo must have "cb" set to the structure size:
STARTUPINFO StartupInfo = {0};
StartupInfo.cb = sizeof(StartupInfo);
The second argument requires both the command and the arguments to form the command line. Your program will see "-wait" as argv[0] and ignore it or pay it no mind.
char command[512];
sprintf(command, "%s -wait", name);
BOOL res = CreateProcess(name, command, // and as you had before
You don't look at GetLastError() if CreateProcess() fails (by returning a zero). It may have helped you but I suspect it would just say "invalid argument" or somesuch. Hey, there's only 10 of them to check, don't be lazy :-)
Another bug I committed is not closing the hProcess and/or hThread handles return in PROCESS_INFORMATION when I was done. I did do hProcess, but not hThread.
Looks like a manifest or registry question judging from the error code. If you can't get the actual error message string for more details, you might try:
moving every possible manifest file (Microsoft.VC80.CRT.manifest and the like) into your exe's directory, to ensure accessibility
cleanly and completely uninstall/wipe out old versions of DLL you may have installer newer versions of (I suggest: uninstall EVERY version, clean the registry with a sweep-clean tool such as Norton's, reinstall the new stuff from scratch)
What happens if you run the process using system()? It gives you less control, but you'll be running it from the same context you're running in. Also, Try monitoring the launch of your second process using ProcMon, it might give you the hint you need about the source of the failure.
Ok worked it all out in the end.
The first time my exe ran it used the default paths and as such loaded vld (a leak detector dll) from the default path. However in the exe i modified the dll path to be the bin folder ([app]\bin) when i restarted the exe using CreateProcess it picked up on a different vld dll (this was my mistake) that had incorrect side by side linkage and it was only after looking at event viewer that i worked it out.
Thanks for all your help.

How can I start explorer.exe via C++?

I'm trying to programmatically start explorer.exe but I'm not having any luck.
This is my code:
cout << pName << "died, lets restart it." << endl;
STARTUPINFO startupInfo = {0};
startupInfo.cb = sizeof(startupInfo);
PROCESS_INFORMATION processInformation;
if(CreateProcess(pName, NULL, NULL, NULL, false, NORMAL_PRIORITY_CLASS, NULL, NULL, &startupInfo, &processInformation) == 0){
cout << "Error starting " << pName << ": " << GetLastError() << endl;
}
and pName is explorer.exe
Can someone tell me what I'm doing wrong? I get the error code '2' which is ERROR_FILE_NOT_FOUND
The first parameter is the application name; the second is the command line. Try specifying "explorer.exe" as the second parameter.
See this MSDN article:
lpApplicationName [in, optional]
The name of the module to be executed.
This module can be a Windows-based
application. It can be some other type
of module (for example, MS-DOS or
OS/2) if the appropriate subsystem is
available on the local computer.
The string can specify the full path
and file name of the module to execute
or it can specify a partial name. In
the case of a partial name, the
function uses the current drive and
current directory to complete the
specification. The function will not
use the search path. This parameter
must include the file name extension;
no default extension is assumed.
You probably should give "ShellExecuteEx" a try. This function lets you specify a file or folder and a verb that describes what to do with it. If you use "explore" as the verb, it will open Windows Explorer with the given folder.
It's surprisingly hard to find relevant information on how to reliably restart windows explorer. On 64-bit Windows 7/8, the ShellExecute method does not work properly and leads to things such as file copying and icon overlays being completely broken.
The most reliable way seems to use stdlib.h system call:
system("start explorer");
If you are trying to shutdown and restart explorer, you might want to programmatically disable AutoRestartShell registry key, which prevents you from controlling when explorer is restarted.