Solved

redirecting STDOUT/STDERR ???

Posted on 1998-12-02
6
1,494 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
  • 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
Gigs: Get Your Project Delivered by an Expert

Select from freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely and get projects done right.

 

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

Live: Real-Time Solutions, Start Here

Receive instant 1:1 support from technology experts, using our real-time conversation and whiteboard interface. Your first 5 minutes are always free.

Question has a verified solution.

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

Suggested Solutions

This article shows how to make a Windows 7 gadget that accepts files dropped from the Windows Explorer.  It also illustrates how to give your gadget a non-rectangular shape and how to add some nifty visual effects to text displayed in a your gadget.…
This article describes how to programmatically preset the "Pages per Sheet" option that's available with most printer drivers.   This setting lets you do "n-Up" printing, where two, four, or more pages are printed on each sheet of paper. If your …
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…
Windows 10 is mostly good. However the one thing that annoys me is how many clicks you have to do to dial a VPN connection. You have to go to settings from the start menu, (2 clicks), Network and Internet (1 click), Click VPN (another click) then fi…

776 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