Solved

Asynchronous I/O to spawned process

Posted on 2003-10-21
10
1,146 Views
Last Modified: 2013-12-03
Hi!

I want to perform asynchronous I/O on stdout/stdin on a spawned process.
So far i have only been able to do synchronous I/O. I have read that
asynchrounous I/O is possible using named pipes, but i haven't been able
to make it work. Does anyone have a clue?

Some code to illustrate my problem
<-- asyncapp.cpp -->
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <stdio.h>

int main(void)
{
      for(int x=10; x--;)
      {
            printf("%d ", x);
            Sleep(1000);
      }
      return 0;
}



<-- redirectedconsole.cpp -->
#define WIN32_LEAN_AND_MEAN
#define BUFSIZE 4096
#include <windows.h>
#include <stdio.h>
#include <conio.h>

HANDLE m_hChildStdoutRd;

DWORD WINAPI readthread(LPVOID lpParameter)
{
      DWORD dwRead;
      TCHAR chBuf[BUFSIZE+1];

      for (;;)
      {
            if(!ReadFile(m_hChildStdoutRd, chBuf, BUFSIZE, &dwRead, NULL) || dwRead==0)
                  break;

            chBuf[dwRead]='\0';
            printf(chBuf);
      }

      return 0;
}

int main(void)
{
      HANDLE hChildStdoutRdTmp, m_hChildStdoutWr, hSaveStdout;
      SECURITY_ATTRIBUTES saAttr;
      PROCESS_INFORMATION piProcInfo;
      STARTUPINFO siStartInfo;
      DWORD id;

      // Set the bInheritHandle flag so pipe handles are inherited.
      saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
      saAttr.bInheritHandle = TRUE;
      saAttr.lpSecurityDescriptor = NULL;

      // Save the handle to the current STDOUT.
      hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);

      // Create a pipe for the child process's STDOUT.
      if(!CreatePipe(&hChildStdoutRdTmp, &m_hChildStdoutWr, &saAttr, 0))
            return FALSE;

      // Set a write handle to the pipe to be STDOUT.
      if(!SetStdHandle(STD_OUTPUT_HANDLE, m_hChildStdoutWr))
            return FALSE;

      // Create noninheritable read handle and close the inheritable read handle.
      if(!DuplicateHandle(GetCurrentProcess(), hChildStdoutRdTmp, GetCurrentProcess(), &m_hChildStdoutRd, 0, TRUE, DUPLICATE_SAME_ACCESS))
            return FALSE;

      // Close original handle
      CloseHandle(hChildStdoutRdTmp);

      // Restore saved handle
      if(!SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout))
            return FALSE;

      // Set up STARTUPINFO
      ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
      siStartInfo.cb = sizeof(STARTUPINFO);
      siStartInfo.dwFlags = STARTF_USESTDHANDLES|STARTF_USESHOWWINDOW;
      siStartInfo.wShowWindow = SW_HIDE;
      siStartInfo.hStdInput = NULL;
      siStartInfo.hStdOutput = m_hChildStdoutWr;
      siStartInfo.hStdError = m_hChildStdoutWr;

      // Create child process
      if(!CreateProcess(NULL, "asyncapp.exe", NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &siStartInfo, &piProcInfo))
            return FALSE;

      // Create read thread
      if(!CreateThread(NULL, 0, readthread, 0, 0, &id))
            return FALSE;

      getch();
      return TRUE;
}
0
Comment
Question by:oskii
  • 4
  • 3
10 Comments
 
LVL 8

Expert Comment

by:mxjijo
Comment Utility

I dont know if I totally understood what u need to achive but..

In general, most of the I/O access could be made asynchronous by setting proper flags during creation time or later, depending up on what u are creating. For example if you specify FILE_FLAG_OVERLAPPED flag, you can perform async operation on that file.

In your case, as far as I know CreatePipe() doesnot support async operations. But, try CreateNamedPipe() with PE_NOWAIT flag. Then you'll be able to do non-blocking IO operations. Take a look at the following links to see more on async IO operations.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ipc/base/synchronous_and_overlapped_input_and_output.asp

~ J
0
 

Author Comment

by:oskii
Comment Utility
Instead of create pipe I have tried to create a named pipe with:

OVERLAPPED OverlapObj;
hChildStdoutRdTmp=CreateNamedPipe("\\\\.\\pipe\\apipe", PIPE_ACCESS_INBOUND|FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, 1, 4096, 4096, 500, NULL);
m_hChildStdoutWr=CreateFile("\\\\.\\pipe\\apipe", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
ZeroMemory(&OverlapObj, sizeof(OverlapObj));
ConnectNamedPipe(hChildStdoutRdTmp, &OverlapObj);

If I then put WaitForSingleObject() in the read thread, it will never return, i suppose something is wrong...
0
 
LVL 8

Expert Comment

by:mxjijo
Comment Utility

Explain me a little more... how did you do it ?

Did you setup the OVERLAPPED structure properly ?
What id the return value of ReadFile() ??
What hande are you passing to WaitForSingleObject() ?

~ J


0
 

Author Comment

by:oskii
Comment Utility
I have not done any setup of the overlapped structure (other than ZeroMemory). I dont really know what i shoud fill it with, this might be the problem.
I passed the m_hChildStdoutRd handle to WaitForSingleObject. ReadFile returns nonzero and sets last error to 997 (Overlapped I/O operation is in progress)

Thank you mxjijo for your interest in this question!
0
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 8

Expert Comment

by:mxjijo
Comment Utility

Its not the way Async IO works.

Its fine that u're passing Zero'd OV structure to ConnectPipe().

But you have to prepare another one for ReadFile too, which in your case should not be Zero'd.

As you mentioned, your ReadFile() will return immediately with IN_PROGRESS error. Now, you have to wait for that IO operation to compleate. This could be done as follows

* Prepare an OVERLAPPED structure and pass it to ReadFile() with an Event, created prior to this. System will set that event once the IO operation is compleated. Infact this is the handle that you should pass to your WaitForSingleObject().

   Wait - Not ovet yet. Now, once the Event is triggered, you can assume the io operation is over, but there could be an error. So you should check the status of this operation using GetOverlappedResult(), passing the OV structure and Pipe handle above. Now, you have more clear idea how many bytes has been transferred, what eas the result etc.

   You should read up on the link I gave you before. It explains the typical Async IO operation.

~ J
0
 

Author Comment

by:oskii
Comment Utility
Thank you for your reply, i have not been able to make overlapped I/O work yet, but i am confused weither overlapped communication really solves the main problem, if you compile and run the asyncapp.cpp (you can probably do it mentaly), you will se that it displays 9 <one sec delay> 8 ... and so on when the same program is being executed with redirected stdout it will be a 10 second delay, and after that all numbers are displayed. If i put fflush(stdout) in the loop in asyncapp the application will work as it is supposed to do even when spawned with redirected handles. The problem is that i am trying to redirect a third-party application for which i dont have the sources.

Will overlapped I/O solve this problem, or should i seek answers elsewhere?

Thanks in advice,
Oskar Sjöberg
0
 
LVL 8

Expert Comment

by:mxjijo
Comment Utility

I have not compiled your code, but as a first impression, I dont think Overlapped IO will NOT solve your problem. I have not tried io redirection my myself yet. However I had a similar problem on Unix I remember, and fflush() was the method I used there either:) Yes there is some buffering assiciated with stdio's. I dont know if there is a way to get aroung this..  I'll let u know if I find something..

~ J
0
 

Accepted Solution

by:
CetusMOD earned 0 total points
Comment Utility
PAQed, with points refunded (50)

CetusMOD
Community Support Moderator
0

Featured Post

Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

Join & Write a Comment

If you have ever found yourself doing a repetitive action with the mouse and keyboard, and if you have even a little programming experience, there is a good chance that you can use a text editor to whip together a sort of macro to automate the proce…
As more and more people are shifting to the latest .Net frameworks, the windows presentation framework is gaining importance by the day. Many people are now turning to WPF controls to provide a rich user experience. I have been using WPF controls fo…
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…
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…

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

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now