[Webinar] Streamline your web hosting managementRegister Today

x
?
Solved

redirecting STDOUT/STDERR ???

Posted on 1998-12-02
6
Medium Priority
?
1,576 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 520 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
Hire Technology Freelancers with Gigs

Work with 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

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

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 …
For most people, the WrapPanel seems like a magic when they switch from WinForms to WPF. Most of us will think that the code that is used to write a control like that would be difficult. However, most of the work is done by the WPF engine, and the W…
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…
Is your organization moving toward a cloud and mobile-first environment? In this transition, your IT department will encounter many challenges, such as navigating how to: Deploy new applications and services to a growing team Accommodate employee…

613 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