Solved

redirecting STDOUT/STDERR ???

Posted on 1998-12-02
6
1,526 Views
Last Modified: 2013-12-03
Hi,
I tried redirecting STDOUT to a file using SetStdHandle.
It seems that it does not affect the output result of
printf.
Is there something wrong with what I wrote ???
Isn't this command supposed to send the stdout
to my file ?
If this command only changes a handle which the
does not affect the "printf" command, who need it ?

#include <windows.h>
#include <winbase.h>
#include <stdio.h>

void main()
{
      HANDLE outfile = CreateFile("xxx.dat",
                        GENERIC_WRITE,
                        0,
                        NULL,
                        CREATE_ALWAYS,
                        FILE_ATTRIBUTE_NORMAL,
                        NULL);

      if (outfile == INVALID_HANDLE_VALUE){
            ErrorExit("CreateFile failed.\n");
      }

      //this printf sends the output to the screen!      
        printf("Xxxxxxxxxxxxxxxxxxxxxxxxxxx\n\n\n");
      CloseHandle(outfile);
}

void ErrorExit(char *msg)
{
      fprintf(stderr, "Error: %s, Error code:%d\n",msg, GetLastError());
      exit(1);
}
0
Comment
Question by:kavas
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 2
6 Comments
 

Author Comment

by:kavas
ID: 1416622
I am using WINDOWS NT.
0
 
LVL 27

Expert Comment

by:BigRat
ID: 1416623
Sorry I see no call to SetStdHandle in your code. Forgot to paste the correct version?
0
 
LVL 15

Accepted Solution

by:
NickRepin earned 130 total points
ID: 1416624
It's because printf uses already opened (while the program started) stream. And SetStdHandle has no effect on it.
There is another way to redirect printf to a file by using freopen().

#include <windows.h>
#include <winbase.h>
#include <stdio.h>
#include <io.h>

void main()
{
  HANDLE outfile = CreateFile("xxx.dat",GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);

  HANDLE std;
  DWORD  n;

// Try to write to stdout - will print on screen
  WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),"To screen",10,&n,0);
 
  SetStdHandle(STD_OUTPUT_HANDLE,outfile);

// Try to write to stdout - will print on file
  WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),"To file",10,&n,0);
 
  CloseHandle(outfile);

// Solution for printf:
   freopen("xxx.dat","a",stdout);
   printf("This will go into a file.");
   fclose(stdout);
   return;
}


0
Revamp Your Training Process

Drastically shorten your training time with WalkMe's advanced online training solution that Guides your trainees to action.

 

Author Comment

by:kavas
ID: 1416625
Thanks Nick,
I'll tell you exactly what am I trying to do.
1. master process creates a named pipe, waits for someone
    to connect it, and then reads the input and displays it
    until reading NULL.
2. another seperate process is connecting to the named pipe,
    redirecting its standard output to the pipe and then
    creates a child process using "CreateProcess"
3. My goal is that the standard output of the child process
    will be redirected to the master process (1).

According to what you said, since the redirection is before
the "CreateProcess" it should work.
However, the master receives nothing from the named pipe besides NULL when the child exists.
Could you help me with that one.
Here is the full source:

master process:
---------------
void main(void)
{
   HANDLE hPipe;
   DWORD dwRead;
   char c;


   PSECURITY_DESCRIPTOR pSecurityDescriptor = PSECURITY_DESCRIPTOR(new
   BYTE[SECURITY_DESCRIPTOR_MIN_LENGTH]);

   ::InitializeSecurityDescriptor(pSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
   ::SetSecurityDescriptorDacl(pSecurityDescriptor, TRUE, NULL, FALSE);

   SECURITY_ATTRIBUTES SecurityAttributes = { 0 };

   SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
   SecurityAttributes.lpSecurityDescriptor = pSecurityDescriptor;
   SecurityAttributes.bInheritHandle = TRUE;

   hPipe = CreateNamedPipe("\\\\.\\pipe\\stdout",
          PIPE_ACCESS_INBOUND, PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
          256, 256, 1000, &SecurityAttributes);

   fprintf(stderr, "created named pipe :stdout\n");
   ConnectNamedPipe(hPipe, NULL);
   fprintf(stderr, "setting handle to pipe.");
   if (! SetStdHandle(STD_OUTPUT_HANDLE, hPipe)){
            fprintf(stderr, "SetStdHandle failed.\n");
            exit(1);
   }

   while (c != '\0')
   {
       if (! ReadFile(hPipe, &c, 1, &dwRead, NULL))
               break;

       if (dwRead > 0 && c != 0) putchar(c);
   }

   fprintf(stderr, "finished reading\n");
   putchar ('\n');

   DisconnectNamedPipe(hPipe);
   CloseHandle(hPipe);
}



the child process
//---------------------------------------
//demo.exe

#include <stdio.h>
#include <windows.h>
#include <winbase.h>
void main()
{
   if (GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE)
         fprintf(stderr, "bad output handle!!!!!!!!!!!!!!!\n");


      fprintf(stderr, "demo is running.\n");
      for (int i=0; i<100000; i++) {
            fprintf(stdout, "aaaaaaaaaaaaaaaaaaa\n");
            fprintf(stdout, "bbbbbbbbbbbbbbbbbbb\n");
            fprintf(stdout, "ccccccccccccccccccc\n");
            fflush(stdout);
      }

      fprintf(stderr, "finished writing to stdout.\n");
}

the process which connects to the pipe and does "CreateProcess".
----------------------------------------------------------------
#include <windows.h>
#include <string.h>
#include <stdio.h>
#include <winbase.h>

#define APP_NAME "Demo.exe"
void ErrorExit(char *msg);
void RunProc(char *name);

void main(int argc, char *argv[])
{
    HANDLE sChildStdoutWr;
    char *sStdoutPipeName;
      HANDLE hChildStdoutRd, hChildStdoutWr;
      HANDLE hSaveStdout;
      
    if (argc != 2)
    {
        printf("Usage: %s hostname\n", argv[0]);
        exit(1);
    }

    sStdoutPipeName = (char*)malloc(strlen(argv[1]) + 14);
    sprintf(sStdoutPipeName, "\\\\%s\\pipe\\stdout", argv[1]);
      fprintf(stderr, "Waiting to stdout pipe.\n");

      //wait for the pipe to be ready
    if (! WaitNamedPipe(sStdoutPipeName, NMPWAIT_WAIT_FOREVER)){
            free(sStdoutPipeName);
            ErrorExit("WaitNamedPipe failed.");
      }
      fprintf(stderr, "Connecting to stdout pipe.\n");

      //connect to the pipe
   PSECURITY_DESCRIPTOR pSecurityDescriptor = PSECURITY_DESCRIPTOR(new
   BYTE[SECURITY_DESCRIPTOR_MIN_LENGTH]);
   ::InitializeSecurityDescriptor(pSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
   ::SetSecurityDescriptorDacl(pSecurityDescriptor, TRUE, NULL, FALSE);
   SECURITY_ATTRIBUTES SecurityAttributes = { 0 };
   SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
   SecurityAttributes.lpSecurityDescriptor = pSecurityDescriptor;
   SecurityAttributes.bInheritHandle = TRUE;

    sChildStdoutWr = CreateFile(sStdoutPipeName, GENERIC_WRITE, 0,
                                 &SecurityAttributes,
                       OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (sChildStdoutWr == INVALID_HANDLE_VALUE){
            free(sStdoutPipeName);
            ErrorExit("CreateFile failed.");
      }
      fprintf(stderr, "Connected to stdout pipe.\n");

      hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);         //save stdout
      if (! SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr)) //redirect stdout
            ErrorExit("Redirecting STDOUT failed");
      fprintf(stderr, "Redirecting STDOUT\n");
      RunProc (APP_NAME);
      if (! SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout)) //redirect stdout
            ErrorExit("Redirecting STDOUT failed");

      fprintf(stderr, "finished.\n");
    CloseHandle(sChildStdoutWr);
}

void ErrorExit(char *msg)
{
      fprintf(stderr, "Error: %s, Error code:%d\n",msg, GetLastError());
      exit(1);
}

void RunProc(char *name)
{
   PROCESS_INFORMATION piProcInfo;
   STARTUPINFO si;
 
   fprintf(stderr, "Running process %s\n",name);
   // Set up members of STARTUPINFO structure.
   ZeroMemory( &si, sizeof(STARTUPINFO) );
   si.cb = sizeof(STARTUPINFO);
   si.lpDesktop = "WinSta0\\Default";

   // Create the child process.
   int ret_val = CreateProcess(
        name,
      NULL,          // 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
      &si,  // STARTUPINFO pointer
      &piProcInfo);  // receives PROCESS_INFORMATION

      if (! ret_val)
            ErrorExit("CreateProcess failed.");
}


0
 
LVL 15

Expert Comment

by:NickRepin
ID: 1416626
kavas, that's an another question. It has a few relations to redirecting stdout, but much to pipes and security.

Neverthless, you made fatal errors in your code:
1) You are not initialized 'c' var in server app.
2) in child app hChildStdoutWr is not initialized.
hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);         //save stdout
if (! SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr)) //redirect stdout
                                       ^^^^^^^ error
ErrorExit("Redirecting STDOUT failed");

Now all works fine!

SERVER
------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <iostream.h>
void main(void)
{
   HANDLE hPipe;
   DWORD dwRead;
   char c;


   PSECURITY_DESCRIPTOR pSecurityDescriptor = PSECURITY_DESCRIPTOR(new
   BYTE[SECURITY_DESCRIPTOR_MIN_LENGTH]);

   ::InitializeSecurityDescriptor(pSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
   ::SetSecurityDescriptorDacl(pSecurityDescriptor, TRUE, NULL, FALSE);

   SECURITY_ATTRIBUTES SecurityAttributes = { 0 };

   SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
   SecurityAttributes.lpSecurityDescriptor = pSecurityDescriptor;
   SecurityAttributes.bInheritHandle = TRUE;

   hPipe = CreateNamedPipe("\\\\.\\pipe\\stdout",
          PIPE_ACCESS_INBOUND, PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
          256, 256, 1000, &SecurityAttributes);

   fprintf(stderr, "created named pipe :stdout\n");
   ConnectNamedPipe(hPipe, NULL);
   fprintf(stderr, "setting handle to pipe.");
   if (! SetStdHandle(STD_OUTPUT_HANDLE, hPipe)){
fprintf(stderr, "SetStdHandle failed.\n");
exit(1);
   }

c=1;
   while (c != '\0')
   {
       if (! ReadFile(hPipe, &c, 1, &dwRead, NULL))  {
  fprintf(stderr,"FALSE from ReadFile\n");
   break;
}
//fprintf(stderr,"Char=%d, dwRead=%d",int(c),dwRead);
       if (dwRead > 0 && c != 0) putchar(c);
   }

   fprintf(stderr, "finished reading\n");
   putchar ('\n');

   DisconnectNamedPipe(hPipe);
   CloseHandle(hPipe);
}

CLIENT
-----------------------------------------------------------------------
#include <windows.h>
#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <iostream.h>

#define APP_NAME "Demo.exe"
void ErrorExit(char *msg);
void RunProc(char *name);

void main(int argc, char *argv[])
{
    HANDLE sChildStdoutWr;
    char *sStdoutPipeName;
HANDLE hChildStdoutRd, hChildStdoutWr;
HANDLE hSaveStdout;

    if (argc != 2)
    {
        printf("Usage: %s hostname\n", argv[0]);
        exit(1);
    }

    sStdoutPipeName = (char*)malloc(strlen(argv[1]) + 14);
    sprintf(sStdoutPipeName, "\\\\%s\\pipe\\stdout", argv[1]);
fprintf(stderr, "Waiting to stdout pipe.\n");

//wait for the pipe to be ready
    if (! WaitNamedPipe(sStdoutPipeName, NMPWAIT_WAIT_FOREVER)){
free(sStdoutPipeName);
ErrorExit("WaitNamedPipe failed.");
}
fprintf(stderr, "Connecting to stdout pipe.\n");

//connect to the pipe
   PSECURITY_DESCRIPTOR pSecurityDescriptor = PSECURITY_DESCRIPTOR(new
   BYTE[SECURITY_DESCRIPTOR_MIN_LENGTH]);
   ::InitializeSecurityDescriptor(pSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
   ::SetSecurityDescriptorDacl(pSecurityDescriptor, TRUE, NULL, FALSE);
   SECURITY_ATTRIBUTES SecurityAttributes = { 0 };
   SecurityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
   SecurityAttributes.lpSecurityDescriptor = pSecurityDescriptor;
   SecurityAttributes.bInheritHandle = TRUE;

    sChildStdoutWr = CreateFile(sStdoutPipeName, GENERIC_WRITE, 0,
   &SecurityAttributes,
                       OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (sChildStdoutWr == INVALID_HANDLE_VALUE){
free(sStdoutPipeName);
ErrorExit("CreateFile failed.");
}
fprintf(stderr, "Connected to stdout pipe.\n");

hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);         //save stdout
if (! SetStdHandle(STD_OUTPUT_HANDLE, sChildStdoutWr)) //redirect stdout
ErrorExit("Redirecting STDOUT failed");

DWORD wr;
cout<<"Write="<<WriteFile(sChildStdoutWr,"Test write",10,&wr,0)<<endl;
cout<<wr<<GetLastError()<<endl;

fprintf(stderr, "Redirecting STDOUT\n");
RunProc (APP_NAME);
//getch();
if (! SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout)) //redirect stdout
ErrorExit("Redirecting STDOUT failed");

fprintf(stderr, "finished.\n");
    CloseHandle(sChildStdoutWr);
}

void ErrorExit(char *msg)
{
fprintf(stderr, "Error: %s, Error code:%d\n",msg, GetLastError());
exit(1);
}

void RunProc(char *name)
{
   PROCESS_INFORMATION piProcInfo;
   STARTUPINFO si;
 
   fprintf(stderr, "Running process %s\n",name);
   // Set up members of STARTUPINFO structure.
   ZeroMemory( &si, sizeof(STARTUPINFO) );
   si.cb = sizeof(STARTUPINFO);
   si.lpDesktop = "WinSta0\\Default";

   // Create the child process.
   int ret_val = CreateProcess(
  name,
      NULL,          // 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
      &si,  // STARTUPINFO pointer
      &piProcInfo);  // receives PROCESS_INFORMATION

if (! ret_val)
ErrorExit("CreateProcess failed.");
}


DEMO
---------------------------------------------------------
#include <stdio.h>
#include <windows.h>
#include <winbase.h>
#include <conio.h>
#include <iostream.h>
void main()
{
   HANDLE h;
   if ((h=GetStdHandle(STD_OUTPUT_HANDLE)) == INVALID_HANDLE_VALUE)
   fprintf(stderr, "bad output handle!!!!!!!!!!!!!!!\n");

fprintf(stderr, "demo is running\n");

DWORD wr;
char* str="\r\nFrom demo Test write\r\n"   ;
cerr<<"Write="<<WriteFile(h,str,strlen(str),&wr,0)<<endl;
cerr<<wr<<GetLastError()<<endl;

for (int i=0; i<10; i++) {
fprintf(stdout, "aaaaaaaaaaaaaaaaaaa\n");
fprintf(stdout, "bbbbbbbbbbbbbbbbbbb\n");
fprintf(stdout, "ccccccccccccccccccc\n");
fflush(stdout);
}

fprintf(stderr, "finished writing to stdout.\n");
}

0
 

Author Comment

by:kavas
ID: 1416627
Thanks Nick,
It was my stupid mistake.

Avi.

0

Featured Post

Get free NFR key for Veeam Availability Suite 9.5

Veeam is happy to provide a free NFR license (1 year, 2 sockets) to all certified IT Pros. The license allows for the non-production use of Veeam Availability Suite v9.5 in your home lab, without any feature limitations. It works for both VMware and Hyper-V environments

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article shows a few slightly more advanced techniques for Windows 7 gadget programming, including how to save and restore user settings for your gadget and how to populate the "details" panel that is displayed in the Windows 7 gadget gallery.  …
This article describes how to add a user-defined command button to the Windows 7 Explorer toolbar.  In the previous article (http://www.experts-exchange.com/A_2172.html), we saw how to put the Delete button back there where it belongs.  "Delete" is …
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
Michael from AdRem Software outlines event notifications and Automatic Corrective Actions in network monitoring. Automatic Corrective Actions are scripts, which can automatically run upon discovery of a certain undesirable condition in your network.…

617 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question