35

Is there a rough equivalent to the Linux/Unix stdio.h popen() function in the Win32 API? If so, where can I find it?

Edit: I need to know this to patch an omission in the D standard library. Any answer must use only standard Win32 API, no MSVC-specific functions. Also, I'd prefer something that's not horribly low-level, if it exists.

dsimcha
  • 67,514
  • 53
  • 213
  • 334
  • 2
    _popen is part of the standard C library on Windows and is available to anyone linking against/using the standard C library. – Jason Coco Jan 16 '09 at 17:10
  • Ok, well I couldn't seem to get it working from D, which supports the C ABI, but that's probably beyond the scope of this question. – dsimcha Jan 16 '09 at 17:11
  • 6
    Windows is not Linux; there is no standard C library in the OS. KERNEL32.DLL does not have printf() – MSalters Jan 23 '09 at 13:08

5 Answers5

27

MSDN explains how you do what popen does using the Windows API in Pipe Handle Inheritance . Here it provides a well-documented example. It's way more low-level than the _popen function found in the runtime library linked by Jason, but uses the Win32 API exclusively.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 5
    Oh, I like this answer much better than mine :) – Jason Coco Jan 16 '09 at 16:22
  • 1
    It looks very interesting, and had I not been 2 days late on my delivery deadline, I might be interested in implementing this solution :-) . But for my needs (I just want to capture stdout), `_popen` is more than enough. – Guss Oct 01 '13 at 15:17
  • did you forget to post a link to the MSDN page? Where is this well-documented example? – Gregor Leban Apr 21 '15 at 12:21
22

You can call _popen if you're writing a console application. For more information, see the documentation on the MSDN site: http://msdn.microsoft.com/en-us/library/96ayss4b(VS.80).aspx

Jason Coco
  • 77,985
  • 20
  • 184
  • 180
3

Digging up an old thread ...

Reacting to Jason Coco's reply above, and contrary to what the linked MSDN page claims, it is apparently possible nowadays to call _popen() from non-console apps. I call it from a QuickTime importer component, basically a DLL in disguise. It opens a console window but otherwise shows the expected behaviour. Compiling a standard console tool with mingw32's -mwindows option to make it a GUI app, _popen continues to work correctly (but a console window opens even when running the tool from another console.

RJVB
  • 698
  • 8
  • 18
3

Sadly it's not particularly easy.

You need to create a pipe using the win32 function (CreatePipe), then typically you need to duplicate the end of the pipe (DuplicateHandle) that you're giving to the subprocess to allow it to be inherited, otherwise it won't be and hence can't be used.

Then you need to create a process using CreateProcess (which takes lots of structure pointers, including a STARTUPINFO), and pass in the STARTUPINFO the handle that you've duplicated as its stdout.

Then you can read from the reading end of the pipe (ReadFile etc) until you reach eof, then you need to clean up by closing all the various win32 handles.

MarkR
  • 62,604
  • 14
  • 116
  • 151
1

This is an old post, but I also had a need several years ago to use a popen() like call in a Windows environment. As several of the comments in the answer here have noted, using the Windows API to implement anything close to the classic POSIX popen() is interesting.

I created an implementation which I submitted to Code Review . This implementation uses pipes to stdin and from stdout, as well as Windows methods for CreateProcess(...).

The linked code is designed to be built into a dll with a very small API.

int __declspec(dllexport) cmd_rsp(const char *command, char **chunk, unsigned int size); 

Simple example of usage:

#include "cmd_rsp.h"
int main(void)
{
    char *buf = {0};
    buf = calloc(100, 1);
    if(!buf)return 0;
    cmd_rsp("dir /s", &buf, 100);
    printf("%s", buf);
    free(buf);
    //or a custom exe
    char *buf2 = {0};
    buf2 = calloc(100, 1);
    cmd_rsp("some_custom_program.exe arg_1 arg_2 arg_n", &buf2, 100);
    printf("%s", buf2);
    free(buf2);
    
    return 0;
}

It takes any command that can be for example issued from stdin, creates a separate process to execute the command, then returns all response content (If there is any) to a buffer, and does this without displaying the CMD window popup. The buffer grows as needed to accommodate size of response.

ryyker
  • 22,849
  • 3
  • 43
  • 87