blah
blah

Reputation: 103

How do I redirect the output of a system() function to a variable?

I have this code:

system("echo %username%");

I want to redirect its result to a variable, say uname.

How can I do it?

I am aware of the WinAPI but I want to do it this way.

Upvotes: 3

Views: 3065

Answers (2)

Rogério Ramos
Rogério Ramos

Reputation: 286

The quick, ugly and dirty way is to redirect the output to a file and then read that file.

system("echo %username% > someFile.txt");

A more elaborated way is to use the CreateProcess API with the following command line: cmd.exe /c echo %username%

That API allows you to specify custom standard input and standard output. You can create a pipe for the standard output like this:

HANDLE g_hChildStd_OUT_Wr = NULL;

SECURITY_ATTRIBUTES saAttr;

saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
saAttr.bInheritHandle = TRUE; 
saAttr.lpSecurityDescriptor = NULL; 

// Create a pipe for the child process's STDOUT. 
// 
if ( !CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0) ) return -1;

And then use this pipe in the CreateProcess API. Something like this:

TCHAR szCmdline[]=TEXT("cmd.exe /c echo %username%");
PROCESS_INFORMATION piProcInfo; 
STARTUPINFO siStartInfo;

// Set up members of the PROCESS_INFORMATION structure. 
// 
memset( &piProcInfo, 0, sizeof(PROCESS_INFORMATION) );

// Set up members of the STARTUPINFO structure. 
// This structure specifies the STDIN and STDOUT handles for redirection.
//
memset( &siStartInfo, 0, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO); 
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;

// Create the child process. 
//    
bSuccess = CreateProcess(NULL, 
      szCmdline,     // command line 
      NULL,          // process security attributes 
      NULL,          // primary thread security attributes 
      TRUE,          // handles are inherited 
      0,             // creation flags 
      NULL,          // use parent's environment 
      NULL,          // use parent's current directory 
      &siStartInfo,  // STARTUPINFO pointer 
      &piProcInfo);  // receives PROCESS_INFORMATION 

And then reads from the pipe with something like this:

DWORD dwRead, dwWritten; 
CHAR chBuf[BUFSIZE]; 
BOOL bSuccess = FALSE;
HANDLE hParentStdOut = GetStdHandle(STD_OUTPUT_HANDLE);

for (;;) 
{ 
      bSuccess = ReadFile( g_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
      if( ! bSuccess || dwRead == 0 ) break; 
}

The process will be running asynchronously so you need to know when the process is terminated and do the proper cleanup. Therefore there is a bunch of details to learn here in order to make this work.

A complete example can be found here: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx

Upvotes: 3

James Kanze
James Kanze

Reputation: 153909

If the goal is only to get the user name, have you considered getenv; getenv( "username" ) will return it directly.

Otherwise, if you have more that you want to do, and want the results in a file... The string you pass to system is passed to a command interpreter, so anything you could do in a command line in cmd.exe will work in system: file redirection, pipe to another process, etc.

Upvotes: 0

Related Questions