22

I need to get (or pipe) the output from a process that is already running, using the windows api.

Basically my application should allow the user to select a window to pipe the input from, and all input will be displayed in a console. I would also be looking on how to get a pipe on stderr later on.

Important: I did not start the process using CreateProcess() or otherwise. The process is already running, and all I have is the handle to the process (returned from GetWindowThreadProcessId()).

Puppy
  • 144,682
  • 38
  • 256
  • 465
David
  • 15,652
  • 26
  • 115
  • 156
  • As Adam says, almost certainly the wrong thing to do. Can you describe what you are trying to achieve? Are you sure the application even has any output? Most GUI processes don't. – Harry Johnston Sep 30 '11 at 02:29
  • @HarryJohnston It's a Java application which has console output. – David Sep 30 '11 at 06:05
  • In that case, it may be possible to modify the Java runtime to achieve your purpose. I still wouldn't recommend it, but it may be possible. – Harry Johnston Oct 01 '11 at 01:49
  • This answer may be useful to anyone coming across this question: stackoverflow.com/a/54317865/153844 – cmann Jan 27 '20 at 09:22

3 Answers3

4

The cleanest way of doing this without causing any ill effects, such that may occur if you used the method Adam implied of swapping the existing stdout handle with your own, is to use hooking.

If you inject a thread into the existing application and swap calls to WriteFile with an intercepted version that will first give you a copy of what's being written (filtered by handle, source, whatever) then pass it along to the real ::WriteFile with no harm done. Or you can intercept the call higher up by only swapping out printf or whichever call it is that the software is using (some experimentation needed, obviously).

HOWEVER, Adam is spot-on when he says this isn't what you want to do. This is a last resort, so think very, very carefully before going down this line!

Mahmoud Al-Qudsi
  • 28,357
  • 12
  • 85
  • 125
  • Sorry if I am misunderstanding the answer, but what does WriteFile have to do with stdout? The application (In my case) does not write a log file. And even if it did, what if the application is writing to more than one file/s simultaneously? How will you tell which is which? – David Sep 30 '11 at 06:18
  • By checking the handle. At any rate, like I said, you can ignore WriteFile and focus on printf. – Mahmoud Al-Qudsi Sep 30 '11 at 10:02
  • Would it be too much to ask you to provide a code snippet as an example? – David Sep 30 '11 at 10:46
  • What I meant was an example on how can I get the stdOut stream from hooking. I'm new to the windows api and I don't know where to start. Thank you for your help. – David Sep 30 '11 at 10:53
  • 1
    No one here will write that entire code for you. But the basics of what you need are to follow the instructions in the article I linked to replace printf with MyPrintF, send the original output via your preferred IPC means to the application that you want to receive it, then call the native ::printf function with the original parameters. – Mahmoud Al-Qudsi Sep 30 '11 at 10:55
  • Yes, trampolining with Detours is the best way I can think of for this situation. – Mike Kwan Apr 23 '12 at 15:47
  • This should be the accepted answer. It actually answers what was asked and I'm not aware of any other solution. – toster-cx Feb 04 '17 at 07:05
0

Came across this article from MS while searching on the topic. http://support.microsoft.com/kb/190351

The concept of piping input and output on Unix is trivial, there seems no great reason for it to be so complex on Windows. - Karl

Karl
  • 21
  • 1
    Piping output for a process that IS ALREADY RUNNING, without executing it from the application. That's what this question is about. – David Apr 23 '12 at 19:28
-10

Whatever you're trying to do, you're doing it wrong. If you're interacting with a program for which you have the source code, create a defined interface for your IPC: create a socket, a named pipe, windows messaging, shared memory segment, COM server, or whatever your preferred IPC mechanism is. Do not try to graft IPC onto a program that wasn't intending to do IPC.

You have no control over how that process's stdout was set up, and it is not yours to mess with. It was created by its parent process and handed off to the child, and from there on out, it's in control of the child. You don't go in and change the carpets in somebody else's house.

Do not even think of going into that process, trying to CloseHandle its stdout, and CreateFile a new stdout pointing to your pipe. That's a recipe for disaster and will result in quirky behavior and "impossible" crashes.

Even if you could do what you wanted to do, what would happen if two programs did this?

Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
  • 14
    There are many valid reasons for doing this, I don't think a blanket "don't do this" answer is necessarily the way to go. While I do agree that in most cases, it is the wrong option; it is nevertheless a valid solution for certain scenarios. – Mahmoud Al-Qudsi Sep 29 '11 at 22:47
  • @Mahmoud: What are those many valid reasons? If you need to control a process's stdout, you set set it up and create the process yourself (shells are really good at this). Any process for which you'd conceivably want to change where its output goes after startup will have a well-defined interface for doing so. – Adam Rosenfield Sep 29 '11 at 23:10
  • 4
    Never change... just invisibly watch and "monitor." I've had to, on many occasions, make a process interact/work in tandem with another for which the source code was not available. Granted, these were usually not console applications, but I can more than see such a scenario happening. – Mahmoud Al-Qudsi Sep 30 '11 at 03:00
  • @AdamRosenfield Unfortunately, I do not have the source code of the application/s. Given that I start the application, getting the console output is very easy. However, some time ago, I had seen some old vb6 code that, using the windows api, allows you to do exactly what I'm asking. I lost the code though, or I wouldn't be asking here. – David Sep 30 '11 at 06:10
  • 1
    @AdamRosenfield If you are absolutely sure that you need to modify the running process (by creating a thread in that process or otherwise) to achive this, then I think I'm going to give up on this, because it's simply not worth the time and frustration. – David Sep 30 '11 at 06:24
  • @David: I don't know what the old VB6 code was doing, but I'd bet that it was not doing what you thought it was. You really need to be more specific about what you're doing -- who is starting this process that you're interested in? Is there a way to convince it to redirect the child process's stdout in a method of your choosing? Why can't you just start it yourself? – Adam Rosenfield Sep 30 '11 at 15:53
  • @AdamRosenfield Most of the time, the process is already running and I need to do some on-the-spot debugging. I can't write a wrapper for the process which will get the out and save it to a file. Look, it really gets on my nerves that when questions reach a certain level of difficulty, people start to purposely evade the original question. It's really frustrating and it wastes my time. If you can't show me how I can do exactly what I wanted to do in the original question, then you can't help. I appreciate how you are trying to show me that it's a messy job. I already know that, thanks. – David Sep 30 '11 at 16:22
  • 2
    @David: Have you tried using [Process Monitor](http://technet.microsoft.com/en-us/sysinternals/bb896645)? What you want to do simply isn't doable in userspace, there's no public API for anything like it. Kernel mode, on the other hand, is an entirely different beast -- see [this answer](http://stackoverflow.com/questions/4833972/how-does-sysinternals-processmonitor-work/4834010#4834010) for an idea of how Process Monitor works and how you might get started doing it. – Adam Rosenfield Sep 30 '11 at 22:27
  • @AdamRosenfield Wow! I give up on this now. That's definitely beyond me :) I think it will be easier to just ask for the source code of the application and rewrite it. Thanks for your help :) – David Sep 30 '11 at 23:21
  • 3
    I'm getting tired of this negative attitude to hacking and reverse engineering on SO. My reason to do is would be to debug DLL file I'm injecting without creating complicated API as any of those you propose. – Tomáš Zato Mar 05 '15 at 10:52