Link to home
Start Free TrialLog in
Avatar of kavas
kavas

asked on

redirecting STDOUT/STDERR ???

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);
}
Avatar of kavas
kavas

ASKER

I am using WINDOWS NT.
Sorry I see no call to SetStdHandle in your code. Forgot to paste the correct version?
ASKER CERTIFIED SOLUTION
Avatar of NickRepin
NickRepin

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of kavas

ASKER

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.");
}


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");
}

Avatar of kavas

ASKER

Thanks Nick,
It was my stupid mistake.

Avi.