ThisIsEd
Pilgrim

Capturing stdOutput and stdError from LaunchApplication

I'm attempting to capture the output from an executable launched from LaunchApplication, but all I'm getting is a blank file created. I've put together a sample project to try to get anything outputting to a text file, but no luck. All I get is the file created but with no contents. Here's my current Setup.rul:


#include "ifx.h"
export prototype MyFunction(HWND);
prototype Kernel32.CloseHandle(HWND);
prototype HWND Kernel32.CreateFileA(STRING, NUMBER, NUMBER, NUMBER, NUMBER, NUMBER, NUMBER);

///////////////////////////////////////////////////////////////////////////////
// Function: MyFunction
///////////////////////////////////////////////////////////////////////////////
function MyFunction(hMSI)
HWND stdOutput;
STRING szDir, szProgram, szCmdLine;
begin
LAAW_PARAMETERS.bInheritHandles = TRUE;
stdOutput = Kernel32.CreateFileA("C:\\temp\\log.log", GENERIC_WRITE, 2, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
LAAW_STARTUPINFO.dwFlags = LAAW_STARTUPINFO.dwFlags | STARTF_USESTDHANDLES;
LAAW_STARTUPINFO.hStdOutput = stdOutput;
LAAW_STARTUPINFO.hStdError = stdOutput;
szProgram = "c:\\windows\\system32\\getmac.exe";
szCmdLine = "";
LaunchApplication(szProgram, szCmdLine, "c:\\temp", SW_SHOWNORMAL, 1000, LAAW_OPTION_WAIT);
Kernel32.CloseHandle(stdOutput);
MessageBox("Check file", INFORMATION);
end;


Anyone have any luck capturing the stdout and stderr from InstallScript? I'm able to get the return code just fine, but I need more info than that.

Thanks
Labels (1)
0 Kudos
5 Replies
Christopher_Pai
Pilgrim

I really don't reccomend screen scraping the output of out of process exe's in an installer. If you really need the MAC address ( I'm guessing on your requirements here ) it's far easier to just query WMI and get it back as a string.
0 Kudos
ThisIsEd
Pilgrim

sorry, forgot to mention that it's our own .exe that we're launching and wanting to get the output from. I just picked getmac.exe for the example above that I'm trying to at least get working since it's simple.

I'm mainly looking to use this for troubleshooting installs. I can grab the error code that we return, but the output (both stdoutput and stderror) gives some extra info that would be handy.
0 Kudos
Cary_R
Pilgrim

Hi Ed,

I've not yet been able to work out how to get this going without an intermediate file. But, the "Easy Way" methods you can probably use:

1. Passing an output redirect on the commandline:

getmac.exe > c:\myfile.txt

Then reading in from the file after it's done. This looks like it's what you're already trying by redirecting STDOUT via setting handles and such.

2. Using C#, which is much simpler. Here's an except from something I have working, reading from a child process's STDOUT and writing to the parent process's console window:

string tmpFolder, stdOut;
tmpFolder = System.Environment.GetEnvironmentVariable("TEMP");

string AppPath = Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName;

AppPath = System.IO.Path.GetDirectoryName(AppPath);


System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.FileName = AppPath + "\\sftinfo.exe";
p.StartInfo.Arguments = "\"" + manifest + "\" -M \"" + tmpFolder + "\\sftinfo.xml.nfo\"";

p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.UseShellExecute = false;
p.Start();

stdOut = p.StandardOutput.ReadToEnd();
Console.Write(stdOut);
0 Kudos
Anonymous
Not applicable

I was able to get this working by calling cmd.exe and passing the target program as parameters to cmd.exe using the /K or /C switches. I saw this implicitly referenced in another post. It made sense after I pondered it for a second. I/O redirection is a service provided by the shell, while the various LaunchApplication() functions directly spawn the processes via the Windows API. No screen output and hence the need to wrap the target CLI program... That is unless there's some undocumented LaunchApp() variant that attaches to the stdin/stdout pipes...

-Russ
0 Kudos

Here's how I got it to work:

	NUMBER stdOutHandle;
	NUMBER stdErrHandle;
	SECURITY_ATTRIBUTES securityAttributes;
begin
	// redirect stdout and stderror.  need to use the win32 CreateFile
	// because the installshield functions return non-win32 handles
	securityAttributes.nLength = SizeOf(securityAttributes);
	securityAttributes.bInheritHandle = TRUE;
	
	stdOutHandle = KERNEL32.CreateFileA(stdOutFile, (GENERIC_READ | GENERIC_WRITE), FILE_SHARE_READ,
										&securityAttributes, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	stdErrHandle = KERNEL32.CreateFileA(stdErrFile, (GENERIC_READ | GENERIC_WRITE), FILE_SHARE_READ,
										&securityAttributes, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
										
	LAAW_STARTUPINFO.hStdInput = NULL;
	LAAW_STARTUPINFO.hStdOutput = stdOutHandle;
	LAAW_STARTUPINFO.hStdError = stdErrHandle;
	LAAW_STARTUPINFO.dwFlags = LAAW_STARTUPINFO.dwFlags | STARTF_USESTDHANDLES;
	LAAW_PARAMETERS.bInheritHandles = TRUE;
	
	launchAppResult = LaunchAppAndWait(app, args, LAAW_OPTION_WAIT | LAAW_OPTION_HIDDEN);

	CloseFile(stdOutHandle);
	CloseFile(stdErrHandle);
0 Kudos