Solved

redirecting STDOUT/STDERR ???

Posted on 1998-12-02
6
1,523 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
PeopleSoft Has Never Been Easier

PeopleSoft Adoption Made Smooth & Simple!

On-The-Job Training Is made Intuitive & Easy With WalkMe's On-Screen Guidance Tool.  Claim Your Free WalkMe Account Now

 

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

SharePoint Admin?

Enable Your Employees To Focus On The Core With Intuitive Onscreen Guidance That is With You At The Moment of Need.

Question has a verified solution.

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

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.…
After several hours of googling I could not gather any information on this topic. There are several ways of controlling the USB port connected to any storage device. The best example of that is by changing the registry value of "HKEY_LOCAL_MACHINE\S…
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…
There are cases when e.g. an IT administrator wants to have full access and view into selected mailboxes on Exchange server, directly from his own email account in Outlook or Outlook Web Access. This proves useful when for example administrator want…

728 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