summaryrefslogtreecommitdiffstats
path: root/Objects/fileobject.c
blob: f4424184d2df1beae58ae7beec0f037cbb3aa59c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
/* File object implementation (what's left of it -- see io.py) */

#define PY_SSIZE_T_CLEAN
#include "Python.h"

#ifdef HAVE_GETC_UNLOCKED
#define GETC(f) getc_unlocked(f)
#define FLOCKFILE(f) flockfile(f)
#define FUNLOCKFILE(f) funlockfile(f)
#else
#define GETC(f) getc(f)
#define FLOCKFILE(f)
#define FUNLOCKFILE(f)
#endif

/* Newline flags */
#define NEWLINE_UNKNOWN 0       /* No newline seen, yet */
#define NEWLINE_CR 1            /* \r newline seen */
#define NEWLINE_LF 2            /* \n newline seen */
#define NEWLINE_CRLF 4          /* \r\n newline seen */

#ifdef __cplusplus
extern "C" {
#endif

/* External C interface */

PyObject *
PyFile_FromFd(int fd, const char *name, const char *mode, int buffering, const char *encoding,
              const char *errors, const char *newline, int closefd)
{
    PyObject *io, *stream;
    _Py_IDENTIFIER(open);

    io = PyImport_ImportModule("io");
    if (io == NULL)
        return NULL;
    stream = _PyObject_CallMethodId(io, &PyId_open, "isisssi", fd, mode,
                                 buffering, encoding, errors,
                                 newline, closefd);
    Py_DECREF(io);
    if (stream == NULL)
        return NULL;
    /* ignore name attribute because the name attribute of _BufferedIOMixin
       and TextIOWrapper is read only */
    return stream;
}

PyObject *
PyFile_GetLine(PyObject *f, int n)
{
    PyObject *result;

    if (f == NULL) {
        PyErr_BadInternalCall();
        return NULL;
    }

    {
        PyObject *reader;
        PyObject *args;
        _Py_IDENTIFIER(readline);

        reader = _PyObject_GetAttrId(f, &PyId_readline);
        if (reader == NULL)
            return NULL;
        if (n <= 0)
            args = PyTuple_New(0);
        else
            args = Py_BuildValue("(i)", n);
        if (args == NULL) {
            Py_DECREF(reader);
            return NULL;
        }
        result = PyEval_CallObject(reader, args);
        Py_DECREF(reader);
        Py_DECREF(args);
        if (result != NULL && !PyBytes_Check(result) &&
            !PyUnicode_Check(result)) {
            Py_DECREF(result);
            result = NULL;
            PyErr_SetString(PyExc_TypeError,
                       "object.readline() returned non-string");
        }
    }

    if (n < 0 && result != NULL && PyBytes_Check(result)) {
        char *s = PyBytes_AS_STRING(result);
        Py_ssize_t len = PyBytes_GET_SIZE(result);
        if (len == 0) {
            Py_DECREF(result);
            result = NULL;
            PyErr_SetString(PyExc_EOFError,
                            "EOF when reading a line");
        }
        else if (s[len-1] == '\n') {
            if (result->ob_refcnt == 1)
                _PyBytes_Resize(&result, len-1);
            else {
                PyObject *v;
                v = PyBytes_FromStringAndSize(s, len-1);
                Py_DECREF(result);
                result = v;
            }
        }
    }
    if (n < 0 && result != NULL && PyUnicode_Check(result)) {
        Py_ssize_t len = PyUnicode_GET_LENGTH(result);
        if (len == 0) {
            Py_DECREF(result);
            result = NULL;
            PyErr_SetString(PyExc_EOFError,
                            "EOF when reading a line");
        }
        else if (PyUnicode_READ_CHAR(result, len-1) == '\n') {
            PyObject *v;
            v = PyUnicode_Substring(result, 0, len-1);
            Py_DECREF(result);
            result = v;
        }
    }
    return result;
}

/* Interfaces to write objects/strings to file-like objects */

int
PyFile_WriteObject(PyObject *v, PyObject *f, int flags)
{
    PyObject *writer, *value, *result;
    _Py_IDENTIFIER(write);

    if (f == NULL) {
        PyErr_SetString(PyExc_TypeError, "writeobject with NULL file");
        return -1;
    }
    writer = _PyObject_GetAttrId(f, &PyId_write);
    if (writer == NULL)
        return -1;
    if (flags & Py_PRINT_RAW) {
        value = PyObject_Str(v);
    }
    else
        value = PyObject_Repr(v);
    if (value == NULL) {
        Py_DECREF(writer);
        return -1;
    }
    result = _PyObject_CallArg1(writer, value);
    Py_DECREF(value);
    Py_DECREF(writer);
    if (result == NULL)
        return -1;
    Py_DECREF(result);
    return 0;
}

int
PyFile_WriteString(const char *s, PyObject *f)
{
    if (f == NULL) {
        /* Should be caused by a pre-existing error */
        if (!PyErr_Occurred())
            PyErr_SetString(PyExc_SystemError,
                            "null file for PyFile_WriteString");
        return -1;
    }
    else if (!PyErr_Occurred()) {
        PyObject *v = PyUnicode_FromString(s);
        int err;
        if (v == NULL)
            return -1;
        err = PyFile_WriteObject(v, f, Py_PRINT_RAW);
        Py_DECREF(v);
        return err;
    }
    else
        return -1;
}

/* Try to get a file-descriptor from a Python object.  If the object
   is an integer, its value is returned.  If not, the
   object's fileno() method is called if it exists; the method must return
   an integer, which is returned as the file descriptor value.
   -1 is returned on failure.
*/

int
PyObject_AsFileDescriptor(PyObject *o)
{
    int fd;
    PyObject *meth;
    _Py_IDENTIFIER(fileno);

    if (PyLong_Check(o)) {
        fd = _PyLong_AsInt(o);
    }
    else if ((meth = _PyObject_GetAttrId(o, &PyId_fileno)) != NULL)
    {
        PyObject *fno = PyEval_CallObject(meth, NULL);
        Py_DECREF(meth);
        if (fno == NULL)
            return -1;

        if (PyLong_Check(fno)) {
            fd = _PyLong_AsInt(fno);
            Py_DECREF(fno);
        }
        else {
            PyErr_SetString(PyExc_TypeError,
                            "fileno() returned a non-integer");
            Py_DECREF(fno);
            return -1;
        }
    }
    else {
        PyErr_SetString(PyExc_TypeError,
                        "argument must be an int, or have a fileno() method.");
        return -1;
    }

    if (fd == -1 && PyErr_Occurred())
        return -1;
    if (fd < 0) {
        PyErr_Format(PyExc_ValueError,
                     "file descriptor cannot be a negative integer (%i)",
                     fd);
        return -1;
    }
    return fd;
}

/*
** Py_UniversalNewlineFgets is an fgets variation that understands
** all of \r, \n and \r\n conventions.
** The stream should be opened in binary mode.
** If fobj is NULL the routine always does newline conversion, and
** it may peek one char ahead to gobble the second char in \r\n.
** If fobj is non-NULL it must be a PyFileObject. In this case there
** is no readahead but in stead a flag is used to skip a following
** \n on the next read. Also, if the file is open in binary mode
** the whole conversion is skipped. Finally, the routine keeps track of
** the different types of newlines seen.
** Note that we need no error handling: fgets() treats error and eof
** identically.
*/
char *
Py_UniversalNewlineFgets(char *buf, int n, FILE *stream, PyObject *fobj)
{
    char *p = buf;
    int c;
    int newlinetypes = 0;
    int skipnextlf = 0;

    if (fobj) {
        errno = ENXIO;          /* What can you do... */
        return NULL;
    }
    FLOCKFILE(stream);
    c = 'x'; /* Shut up gcc warning */
    while (--n > 0 && (c = GETC(stream)) != EOF ) {
        if (skipnextlf ) {
            skipnextlf = 0;
            if (c == '\n') {
                /* Seeing a \n here with skipnextlf true
                ** means we saw a \r before.
                */
                newlinetypes |= NEWLINE_CRLF;
                c = GETC(stream);
                if (c == EOF) break;
            } else {
                /*
                ** Note that c == EOF also brings us here,
                ** so we're okay if the last char in the file
                ** is a CR.
                */
                newlinetypes |= NEWLINE_CR;
            }
        }
        if (c == '\r') {
            /* A \r is translated into a \n, and we skip
            ** an adjacent \n, if any. We don't set the
            ** newlinetypes flag until we've seen the next char.
            */
            skipnextlf = 1;
            c = '\n';
        } else if ( c == '\n') {
            newlinetypes |= NEWLINE_LF;
        }
        *p++ = c;
        if (c == '\n') break;
    }
    /* if ( c == EOF && skipnextlf )
        newlinetypes |= NEWLINE_CR; */
    FUNLOCKFILE(stream);
    *p = '\0';
    if ( skipnextlf ) {
        /* If we have no file object we cannot save the
        ** skipnextlf flag. We have to readahead, which
        ** will cause a pause if we're reading from an
        ** interactive stream, but that is very unlikely
        ** unless we're doing something silly like
        ** exec(open("/dev/tty").read()).
        */
        c = GETC(stream);
        if ( c != '\n' )
            ungetc(c, stream);
    }
    if (p == buf)
        return NULL;
    return buf;
}

/* **************************** std printer ****************************
 * The stdprinter is used during the boot strapping phase as a preliminary
 * file like object for sys.stderr.
 */

typedef struct {
    PyObject_HEAD
    int fd;
} PyStdPrinter_Object;

static PyObject *
stdprinter_new(PyTypeObject *type, PyObject *args, PyObject *kews)
{
    PyStdPrinter_Object *self;

    assert(type != NULL && type->tp_alloc != NULL);

    self = (PyStdPrinter_Object *) type->tp_alloc(type, 0);
    if (self != NULL) {
        self->fd = -1;
    }

    return (PyObject *) self;
}

static int
stdprinter_init(PyObject *self, PyObject *args, PyObject *kwds)
{
    PyErr_SetString(PyExc_TypeError,
                    "cannot create 'stderrprinter' instances");
    return -1;
}

PyObject *
PyFile_NewStdPrinter(int fd)
{
    PyStdPrinter_Object *self;

    if (fd != fileno(stdout) && fd != fileno(stderr)) {
        /* not enough infrastructure for PyErr_BadInternalCall() */
        return NULL;
    }

    self = PyObject_New(PyStdPrinter_Object,
                        &PyStdPrinter_Type);
    if (self != NULL) {
        self->fd = fd;
    }
    return (PyObject*)self;
}

static PyObject *
stdprinter_write(PyStdPrinter_Object *self, PyObject *args)
{
    PyObject *unicode;
    PyObject *bytes = NULL;
    char *str;
    Py_ssize_t n;
    int err;

    if (self->fd < 0) {
        /* fd might be invalid on Windows
         * I can't raise an exception here. It may lead to an
         * unlimited recursion in the case stderr is invalid.
         */
        Py_RETURN_NONE;
    }

    if (!PyArg_ParseTuple(args, "U", &unicode))
        return NULL;

    /* encode Unicode to UTF-8 */
    str = PyUnicode_AsUTF8AndSize(unicode, &n);
    if (str == NULL) {
        PyErr_Clear();
        bytes = _PyUnicode_AsUTF8String(unicode, "backslashreplace");
        if (bytes == NULL)
            return NULL;
        if (PyBytes_AsStringAndSize(bytes, &str, &n) < 0) {
            Py_DECREF(bytes);
            return NULL;
        }
    }

    n = _Py_write(self->fd, str, n);
    /* save errno, it can be modified indirectly by Py_XDECREF() */
    err = errno;

    Py_XDECREF(bytes);

    if (n == -1) {
        if (err == EAGAIN) {
            PyErr_Clear();
            Py_RETURN_NONE;
        }
        return NULL;
    }

    return PyLong_FromSsize_t(n);
}

static PyObject *
stdprinter_fileno(PyStdPrinter_Object *self)
{
    return PyLong_FromLong((long) self->fd);
}

static PyObject *
stdprinter_repr(PyStdPrinter_Object *self)
{
    return PyUnicode_FromFormat("<stdprinter(fd=%d) object at 0x%x>",
                                self->fd, self);
}

static PyObject *
stdprinter_noop(PyStdPrinter_Object *self)
{
    Py_RETURN_NONE;
}

static PyObject *
stdprinter_isatty(PyStdPrinter_Object *self)
{
    long res;
    if (self->fd < 0) {
        Py_RETURN_FALSE;
    }

    Py_BEGIN_ALLOW_THREADS
    res = isatty(self->fd);
    Py_END_ALLOW_THREADS

    return PyBool_FromLong(res);
}

static PyMethodDef stdprinter_methods[] = {
    {"close",           (PyCFunction)stdprinter_noop, METH_NOARGS, ""},
    {"flush",           (PyCFunction)stdprinter_noop, METH_NOARGS, ""},
    {"fileno",          (PyCFunction)stdprinter_fileno, METH_NOARGS, ""},
    {"isatty",          (PyCFunction)stdprinter_isatty, METH_NOARGS, ""},
    {"write",           (PyCFunction)stdprinter_write, METH_VARARGS, ""},
    {NULL,              NULL}  /*sentinel */
};

static PyObject *
get_closed(PyStdPrinter_Object *self, void *closure)
{
    Py_INCREF(Py_False);
    return Py_False;
}

static PyObject *
get_mode(PyStdPrinter_Object *self, void *closure)
{
    return PyUnicode_FromString("w");
}

static PyObject *
get_encoding(PyStdPrinter_Object *self, void *closure)
{
    Py_RETURN_NONE;
}

static PyGetSetDef stdprinter_getsetlist[] = {
    {"closed", (getter)get_closed, NULL, "True if the file is closed"},
    {"encoding", (getter)get_encoding, NULL, "Encoding of the file"},
    {"mode", (getter)get_mode, NULL, "String giving the file mode"},
    {0},
};

PyTypeObject PyStdPrinter_Type = {
    PyVarObject_HEAD_INIT(&PyType_Type, 0)
    "stderrprinter",                            /* tp_name */
    sizeof(PyStdPrinter_Object),                /* tp_basicsize */
    0,                                          /* tp_itemsize */
    /* methods */
    0,                                          /* tp_dealloc */
    0,                                          /* tp_print */
    0,                                          /* tp_getattr */
    0,                                          /* tp_setattr */
    0,                                          /* tp_reserved */
    (reprfunc)stdprinter_repr,                  /* tp_repr */
    0,                                          /* tp_as_number */
    0,                                          /* tp_as_sequence */
    0,                                          /* tp_as_mapping */
    0,                                          /* tp_hash */
    0,                                          /* tp_call */
    0,                                          /* tp_str */
    PyObject_GenericGetAttr,                    /* tp_getattro */
    0,                                          /* tp_setattro */
    0,                                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT,                         /* tp_flags */
    0,                                          /* tp_doc */
    0,                                          /* tp_traverse */
    0,                                          /* tp_clear */
    0,                                          /* tp_richcompare */
    0,                                          /* tp_weaklistoffset */
    0,                                          /* tp_iter */
    0,                                          /* tp_iternext */
    stdprinter_methods,                         /* tp_methods */
    0,                                          /* tp_members */
    stdprinter_getsetlist,                      /* tp_getset */
    0,                                          /* tp_base */
    0,                                          /* tp_dict */
    0,                                          /* tp_descr_get */
    0,                                          /* tp_descr_set */
    0,                                          /* tp_dictoffset */
    stdprinter_init,                            /* tp_init */
    PyType_GenericAlloc,                        /* tp_alloc */
    stdprinter_new,                             /* tp_new */
    PyObject_Del,                               /* tp_free */
};


#ifdef __cplusplus
}
#endif
/span> 0, sizeof(Py_buffer)); /* Manual reset, initially non-signalled */ self->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); return self; } /* -------------------------------------------------------------------- */ /* windows API functions */ PyDoc_STRVAR(CloseHandle_doc, "CloseHandle(handle) -> None\n\ \n\ Close handle."); static PyObject * winapi_CloseHandle(PyObject *self, PyObject *args) { HANDLE hObject; BOOL success; if (!PyArg_ParseTuple(args, F_HANDLE ":CloseHandle", &hObject)) return NULL; Py_BEGIN_ALLOW_THREADS success = CloseHandle(hObject); Py_END_ALLOW_THREADS if (!success) return PyErr_SetFromWindowsErr(0); Py_RETURN_NONE; } static PyObject * winapi_ConnectNamedPipe(PyObject *self, PyObject *args, PyObject *kwds) { HANDLE hNamedPipe; int use_overlapped = 0; BOOL success; OverlappedObject *overlapped = NULL; static char *kwlist[] = {"handle", "overlapped", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, F_HANDLE "|" F_BOOL, kwlist, &hNamedPipe, &use_overlapped)) return NULL; if (use_overlapped) { overlapped = new_overlapped(hNamedPipe); if (!overlapped) return NULL; } Py_BEGIN_ALLOW_THREADS success = ConnectNamedPipe(hNamedPipe, overlapped ? &overlapped->overlapped : NULL); Py_END_ALLOW_THREADS if (overlapped) { int err = GetLastError(); /* Overlapped ConnectNamedPipe never returns a success code */ assert(success == 0); if (err == ERROR_IO_PENDING) overlapped->pending = 1; else if (err == ERROR_PIPE_CONNECTED) SetEvent(overlapped->overlapped.hEvent); else { Py_DECREF(overlapped); return PyErr_SetFromWindowsErr(err); } return (PyObject *) overlapped; } if (!success) return PyErr_SetFromWindowsErr(0); Py_RETURN_NONE; } static PyObject * winapi_CreateFile(PyObject *self, PyObject *args) { LPCTSTR lpFileName; DWORD dwDesiredAccess; DWORD dwShareMode; LPSECURITY_ATTRIBUTES lpSecurityAttributes; DWORD dwCreationDisposition; DWORD dwFlagsAndAttributes; HANDLE hTemplateFile; HANDLE handle; if (!PyArg_ParseTuple(args, "s" F_DWORD F_DWORD F_POINTER F_DWORD F_DWORD F_HANDLE, &lpFileName, &dwDesiredAccess, &dwShareMode, &lpSecurityAttributes, &dwCreationDisposition, &dwFlagsAndAttributes, &hTemplateFile)) return NULL; Py_BEGIN_ALLOW_THREADS handle = CreateFile(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); Py_END_ALLOW_THREADS if (handle == INVALID_HANDLE_VALUE) return PyErr_SetFromWindowsErr(0); return Py_BuildValue(F_HANDLE, handle); } static PyObject * winapi_CreateNamedPipe(PyObject *self, PyObject *args) { LPCTSTR lpName; DWORD dwOpenMode; DWORD dwPipeMode; DWORD nMaxInstances; DWORD nOutBufferSize; DWORD nInBufferSize; DWORD nDefaultTimeOut; LPSECURITY_ATTRIBUTES lpSecurityAttributes; HANDLE handle; if (!PyArg_ParseTuple(args, "s" F_DWORD F_DWORD F_DWORD F_DWORD F_DWORD F_DWORD F_POINTER, &lpName, &dwOpenMode, &dwPipeMode, &nMaxInstances, &nOutBufferSize, &nInBufferSize, &nDefaultTimeOut, &lpSecurityAttributes)) return NULL; Py_BEGIN_ALLOW_THREADS handle = CreateNamedPipe(lpName, dwOpenMode, dwPipeMode, nMaxInstances, nOutBufferSize, nInBufferSize, nDefaultTimeOut, lpSecurityAttributes); Py_END_ALLOW_THREADS if (handle == INVALID_HANDLE_VALUE) return PyErr_SetFromWindowsErr(0); return Py_BuildValue(F_HANDLE, handle); } PyDoc_STRVAR(CreatePipe_doc, "CreatePipe(pipe_attrs, size) -> (read_handle, write_handle)\n\ \n\ Create an anonymous pipe, and return handles to the read and\n\ write ends of the pipe.\n\ \n\ pipe_attrs is ignored internally and can be None."); static PyObject * winapi_CreatePipe(PyObject* self, PyObject* args) { HANDLE read_pipe; HANDLE write_pipe; BOOL result; PyObject* pipe_attributes; /* ignored */ DWORD size; if (! PyArg_ParseTuple(args, "O" F_DWORD ":CreatePipe", &pipe_attributes, &size)) return NULL; Py_BEGIN_ALLOW_THREADS result = CreatePipe(&read_pipe, &write_pipe, NULL, size); Py_END_ALLOW_THREADS if (! result) return PyErr_SetFromWindowsErr(GetLastError()); return Py_BuildValue( "NN", HANDLE_TO_PYNUM(read_pipe), HANDLE_TO_PYNUM(write_pipe)); } /* helpers for createprocess */ static unsigned long getulong(PyObject* obj, char* name) { PyObject* value; unsigned long ret; value = PyObject_GetAttrString(obj, name); if (! value) { PyErr_Clear(); /* FIXME: propagate error? */ return 0; } ret = PyLong_AsUnsignedLong(value); Py_DECREF(value); return ret; } static HANDLE gethandle(PyObject* obj, char* name) { PyObject* value; HANDLE ret; value = PyObject_GetAttrString(obj, name); if (! value) { PyErr_Clear(); /* FIXME: propagate error? */ return NULL; } if (value == Py_None) ret = NULL; else ret = PYNUM_TO_HANDLE(value); Py_DECREF(value); return ret; } static PyObject* getenvironment(PyObject* environment) { Py_ssize_t i, envsize, totalsize; Py_UCS4 *buffer = NULL, *p, *end; PyObject *keys, *values, *res; /* convert environment dictionary to windows enviroment string */ if (! PyMapping_Check(environment)) { PyErr_SetString( PyExc_TypeError, "environment must be dictionary or None"); return NULL; } envsize = PyMapping_Length(environment); keys = PyMapping_Keys(environment); values = PyMapping_Values(environment); if (!keys || !values) goto error; totalsize = 1; /* trailing null character */ for (i = 0; i < envsize; i++) { PyObject* key = PyList_GET_ITEM(keys, i); PyObject* value = PyList_GET_ITEM(values, i); if (! PyUnicode_Check(key) || ! PyUnicode_Check(value)) { PyErr_SetString(PyExc_TypeError, "environment can only contain strings"); goto error; } totalsize += PyUnicode_GET_LENGTH(key) + 1; /* +1 for '=' */ totalsize += PyUnicode_GET_LENGTH(value) + 1; /* +1 for '\0' */ } buffer = PyMem_Malloc(totalsize * sizeof(Py_UCS4)); if (! buffer) goto error; p = buffer; end = buffer + totalsize; for (i = 0; i < envsize; i++) { PyObject* key = PyList_GET_ITEM(keys, i); PyObject* value = PyList_GET_ITEM(values, i); if (!PyUnicode_AsUCS4(key, p, end - p, 0)) goto error; p += PyUnicode_GET_LENGTH(key); *p++ = '='; if (!PyUnicode_AsUCS4(value, p, end - p, 0)) goto error; p += PyUnicode_GET_LENGTH(value); *p++ = '\0'; } /* add trailing null byte */ *p++ = '\0'; assert(p == end); Py_XDECREF(keys); Py_XDECREF(values); res = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buffer, p - buffer); PyMem_Free(buffer); return res; error: PyMem_Free(buffer); Py_XDECREF(keys); Py_XDECREF(values); return NULL; } PyDoc_STRVAR(CreateProcess_doc, "CreateProcess(app_name, cmd_line, proc_attrs, thread_attrs,\n\ inherit, flags, env_mapping, curdir,\n\ startup_info) -> (proc_handle, thread_handle,\n\ pid, tid)\n\ \n\ Create a new process and its primary thread. The return\n\ value is a tuple of the process handle, thread handle,\n\ process ID, and thread ID.\n\ \n\ proc_attrs and thread_attrs are ignored internally and can be None."); static PyObject * winapi_CreateProcess(PyObject* self, PyObject* args) { BOOL result; PROCESS_INFORMATION pi; STARTUPINFOW si; PyObject* environment; wchar_t *wenvironment; wchar_t* application_name; wchar_t* command_line; PyObject* process_attributes; /* ignored */ PyObject* thread_attributes; /* ignored */ BOOL inherit_handles; DWORD creation_flags; PyObject* env_mapping; wchar_t* current_directory; PyObject* startup_info; if (! PyArg_ParseTuple(args, "ZZOO" F_BOOL F_DWORD "OZO:CreateProcess", &application_name, &command_line, &process_attributes, &thread_attributes, &inherit_handles, &creation_flags, &env_mapping, &current_directory, &startup_info)) return NULL; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); /* note: we only support a small subset of all SI attributes */ si.dwFlags = getulong(startup_info, "dwFlags"); si.wShowWindow = (WORD)getulong(startup_info, "wShowWindow"); si.hStdInput = gethandle(startup_info, "hStdInput"); si.hStdOutput = gethandle(startup_info, "hStdOutput"); si.hStdError = gethandle(startup_info, "hStdError"); if (PyErr_Occurred()) return NULL; if (env_mapping != Py_None) { environment = getenvironment(env_mapping); if (! environment) return NULL; wenvironment = PyUnicode_AsUnicode(environment); if (wenvironment == NULL) { Py_XDECREF(environment); return NULL; } } else { environment = NULL; wenvironment = NULL; } Py_BEGIN_ALLOW_THREADS result = CreateProcessW(application_name, command_line, NULL, NULL, inherit_handles, creation_flags | CREATE_UNICODE_ENVIRONMENT, wenvironment, current_directory, &si, &pi); Py_END_ALLOW_THREADS Py_XDECREF(environment); if (! result) return PyErr_SetFromWindowsErr(GetLastError()); return Py_BuildValue("NNkk", HANDLE_TO_PYNUM(pi.hProcess), HANDLE_TO_PYNUM(pi.hThread), pi.dwProcessId, pi.dwThreadId); } PyDoc_STRVAR(DuplicateHandle_doc, "DuplicateHandle(source_proc_handle, source_handle,\n\ target_proc_handle, target_handle, access,\n\ inherit[, options]) -> handle\n\ \n\ Return a duplicate handle object.\n\ \n\ The duplicate handle refers to the same object as the original\n\ handle. Therefore, any changes to the object are reflected\n\ through both handles."); static PyObject * winapi_DuplicateHandle(PyObject* self, PyObject* args) { HANDLE target_handle; BOOL result; HANDLE source_process_handle; HANDLE source_handle; HANDLE target_process_handle; DWORD desired_access; BOOL inherit_handle; DWORD options = 0; if (! PyArg_ParseTuple(args, F_HANDLE F_HANDLE F_HANDLE F_DWORD F_BOOL F_DWORD ":DuplicateHandle", &source_process_handle, &source_handle, &target_process_handle, &desired_access, &inherit_handle, &options)) return NULL; Py_BEGIN_ALLOW_THREADS result = DuplicateHandle( source_process_handle, source_handle, target_process_handle, &target_handle, desired_access, inherit_handle, options ); Py_END_ALLOW_THREADS if (! result) return PyErr_SetFromWindowsErr(GetLastError()); return HANDLE_TO_PYNUM(target_handle); } static PyObject * winapi_ExitProcess(PyObject *self, PyObject *args) { UINT uExitCode; if (!PyArg_ParseTuple(args, F_UINT, &uExitCode)) return NULL; #if defined(Py_DEBUG) SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOALIGNMENTFAULTEXCEPT| SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX); _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG); #endif ExitProcess(uExitCode); return NULL; } PyDoc_STRVAR(GetCurrentProcess_doc, "GetCurrentProcess() -> handle\n\ \n\ Return a handle object for the current process."); static PyObject * winapi_GetCurrentProcess(PyObject* self, PyObject* args) { if (! PyArg_ParseTuple(args, ":GetCurrentProcess")) return NULL; return HANDLE_TO_PYNUM(GetCurrentProcess()); } PyDoc_STRVAR(GetExitCodeProcess_doc, "GetExitCodeProcess(handle) -> Exit code\n\ \n\ Return the termination status of the specified process."); static PyObject * winapi_GetExitCodeProcess(PyObject* self, PyObject* args) { DWORD exit_code; BOOL result; HANDLE process; if (! PyArg_ParseTuple(args, F_HANDLE ":GetExitCodeProcess", &process)) return NULL; result = GetExitCodeProcess(process, &exit_code); if (! result) return PyErr_SetFromWindowsErr(GetLastError()); return PyLong_FromUnsignedLong(exit_code); } static PyObject * winapi_GetLastError(PyObject *self, PyObject *args) { return Py_BuildValue(F_DWORD, GetLastError()); } PyDoc_STRVAR(GetModuleFileName_doc, "GetModuleFileName(module) -> path\n\ \n\ Return the fully-qualified path for the file that contains\n\ the specified module. The module must have been loaded by the\n\ current process.\n\ \n\ The module parameter should be a handle to the loaded module\n\ whose path is being requested. If this parameter is 0, \n\ GetModuleFileName retrieves the path of the executable file\n\ of the current process."); static PyObject * winapi_GetModuleFileName(PyObject* self, PyObject* args) { BOOL result; HMODULE module; WCHAR filename[MAX_PATH]; if (! PyArg_ParseTuple(args, F_HANDLE ":GetModuleFileName", &module)) return NULL; result = GetModuleFileNameW(module, filename, MAX_PATH); filename[MAX_PATH-1] = '\0'; if (! result) return PyErr_SetFromWindowsErr(GetLastError()); return PyUnicode_FromWideChar(filename, wcslen(filename)); } PyDoc_STRVAR(GetStdHandle_doc, "GetStdHandle(handle) -> integer\n\ \n\ Return a handle to the specified standard device\n\ (STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE).\n\ The integer associated with the handle object is returned."); static PyObject * winapi_GetStdHandle(PyObject* self, PyObject* args) { HANDLE handle; DWORD std_handle; if (! PyArg_ParseTuple(args, F_DWORD ":GetStdHandle", &std_handle)) return NULL; Py_BEGIN_ALLOW_THREADS handle = GetStdHandle(std_handle); Py_END_ALLOW_THREADS if (handle == INVALID_HANDLE_VALUE) return PyErr_SetFromWindowsErr(GetLastError()); if (! handle) { Py_INCREF(Py_None); return Py_None; } /* note: returns integer, not handle object */ return HANDLE_TO_PYNUM(handle); } PyDoc_STRVAR(GetVersion_doc, "GetVersion() -> version\n\ \n\ Return the version number of the current operating system."); static PyObject * winapi_GetVersion(PyObject* self, PyObject* args) { if (! PyArg_ParseTuple(args, ":GetVersion")) return NULL; return PyLong_FromUnsignedLong(GetVersion()); } static PyObject * winapi_OpenProcess(PyObject *self, PyObject *args) { DWORD dwDesiredAccess; BOOL bInheritHandle; DWORD dwProcessId; HANDLE handle; if (!PyArg_ParseTuple(args, F_DWORD F_BOOL F_DWORD, &dwDesiredAccess, &bInheritHandle, &dwProcessId)) return NULL; handle = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId); if (handle == NULL) return PyErr_SetFromWindowsErr(0); return Py_BuildValue(F_HANDLE, handle); } static PyObject * winapi_PeekNamedPipe(PyObject *self, PyObject *args) { HANDLE handle; int size = 0; PyObject *buf = NULL; DWORD nread, navail, nleft; BOOL ret; if (!PyArg_ParseTuple(args, F_HANDLE "|i:PeekNamedPipe" , &handle, &size)) return NULL; if (size < 0) { PyErr_SetString(PyExc_ValueError, "negative size"); return NULL; } if (size) { buf = PyBytes_FromStringAndSize(NULL, size); if (!buf) return NULL; Py_BEGIN_ALLOW_THREADS ret = PeekNamedPipe(handle, PyBytes_AS_STRING(buf), size, &nread, &navail, &nleft); Py_END_ALLOW_THREADS if (!ret) { Py_DECREF(buf); return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); } if (_PyBytes_Resize(&buf, nread)) return NULL; return Py_BuildValue("Nii", buf, navail, nleft); } else { Py_BEGIN_ALLOW_THREADS ret = PeekNamedPipe(handle, NULL, 0, NULL, &navail, &nleft); Py_END_ALLOW_THREADS if (!ret) { return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); } return Py_BuildValue("ii", navail, nleft); } } static PyObject * winapi_ReadFile(PyObject *self, PyObject *args, PyObject *kwds) { HANDLE handle; int size; DWORD nread; PyObject *buf; BOOL ret; int use_overlapped = 0; DWORD err; OverlappedObject *overlapped = NULL; static char *kwlist[] = {"handle", "size", "overlapped", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, F_HANDLE "i|i:ReadFile", kwlist, &handle, &size, &use_overlapped)) return NULL; buf = PyBytes_FromStringAndSize(NULL, size); if (!buf) return NULL; if (use_overlapped) { overlapped = new_overlapped(handle); if (!overlapped) { Py_DECREF(buf); return NULL; } /* Steals reference to buf */ overlapped->read_buffer = buf; } Py_BEGIN_ALLOW_THREADS ret = ReadFile(handle, PyBytes_AS_STRING(buf), size, &nread, overlapped ? &overlapped->overlapped : NULL); Py_END_ALLOW_THREADS err = ret ? 0 : GetLastError(); if (overlapped) { if (!ret) { if (err == ERROR_IO_PENDING) overlapped->pending = 1; else if (err != ERROR_MORE_DATA) { Py_DECREF(overlapped); return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); } } return Py_BuildValue("NI", (PyObject *) overlapped, err); } if (!ret && err != ERROR_MORE_DATA) { Py_DECREF(buf); return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); } if (_PyBytes_Resize(&buf, nread)) return NULL; return Py_BuildValue("NI", buf, err); } static PyObject * winapi_SetNamedPipeHandleState(PyObject *self, PyObject *args) { HANDLE hNamedPipe; PyObject *oArgs[3]; DWORD dwArgs[3], *pArgs[3] = {NULL, NULL, NULL}; int i; if (!PyArg_ParseTuple(args, F_HANDLE "OOO", &hNamedPipe, &oArgs[0], &oArgs[1], &oArgs[2])) return NULL; PyErr_Clear(); for (i = 0 ; i < 3 ; i++) { if (oArgs[i] != Py_None) { dwArgs[i] = PyLong_AsUnsignedLongMask(oArgs[i]); if (PyErr_Occurred()) return NULL; pArgs[i] = &dwArgs[i]; } } if (!SetNamedPipeHandleState(hNamedPipe, pArgs[0], pArgs[1], pArgs[2])) return PyErr_SetFromWindowsErr(0); Py_RETURN_NONE; } PyDoc_STRVAR(TerminateProcess_doc, "TerminateProcess(handle, exit_code) -> None\n\ \n\ Terminate the specified process and all of its threads."); static PyObject * winapi_TerminateProcess(PyObject* self, PyObject* args) { BOOL result; HANDLE process; UINT exit_code; if (! PyArg_ParseTuple(args, F_HANDLE F_UINT ":TerminateProcess", &process, &exit_code)) return NULL; result = TerminateProcess(process, exit_code); if (! result) return PyErr_SetFromWindowsErr(GetLastError()); Py_INCREF(Py_None); return Py_None; } static PyObject * winapi_WaitNamedPipe(PyObject *self, PyObject *args) { LPCTSTR lpNamedPipeName; DWORD nTimeOut; BOOL success; if (!PyArg_ParseTuple(args, "s" F_DWORD, &lpNamedPipeName, &nTimeOut)) return NULL; Py_BEGIN_ALLOW_THREADS success = WaitNamedPipe(lpNamedPipeName, nTimeOut); Py_END_ALLOW_THREADS if (!success) return PyErr_SetFromWindowsErr(0); Py_RETURN_NONE; } static PyObject * winapi_WaitForMultipleObjects(PyObject* self, PyObject* args) { DWORD result; PyObject *handle_seq; HANDLE handles[MAXIMUM_WAIT_OBJECTS]; HANDLE sigint_event = NULL; Py_ssize_t nhandles, i; BOOL wait_flag; DWORD milliseconds = INFINITE; if (!PyArg_ParseTuple(args, "O" F_BOOL "|" F_DWORD ":WaitForMultipleObjects", &handle_seq, &wait_flag, &milliseconds)) return NULL; if (!PySequence_Check(handle_seq)) { PyErr_Format(PyExc_TypeError, "sequence type expected, got '%s'", Py_TYPE(handle_seq)->tp_doc); return NULL; } nhandles = PySequence_Length(handle_seq); if (nhandles == -1) return NULL; if (nhandles < 0 || nhandles >= MAXIMUM_WAIT_OBJECTS - 1) { PyErr_Format(PyExc_ValueError, "need at most %zd handles, got a sequence of length %zd", MAXIMUM_WAIT_OBJECTS - 1, nhandles); return NULL; } for (i = 0; i < nhandles; i++) { HANDLE h; PyObject *v = PySequence_GetItem(handle_seq, i); if (v == NULL) return NULL; if (!PyArg_Parse(v, F_HANDLE, &h)) { Py_DECREF(v); return NULL; } handles[i] = h; Py_DECREF(v); } /* If this is the main thread then make the wait interruptible by Ctrl-C unless we are waiting for *all* handles */ if (!wait_flag && _PyOS_IsMainThread()) { sigint_event = _PyOS_SigintEvent(); assert(sigint_event != NULL); handles[nhandles++] = sigint_event; } Py_BEGIN_ALLOW_THREADS if (sigint_event != NULL) ResetEvent(sigint_event); result = WaitForMultipleObjects((DWORD) nhandles, handles, wait_flag, milliseconds); Py_END_ALLOW_THREADS if (result == WAIT_FAILED) return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); else if (sigint_event != NULL && result == WAIT_OBJECT_0 + nhandles - 1) { errno = EINTR; return PyErr_SetFromErrno(PyExc_IOError); } return PyLong_FromLong((int) result); } PyDoc_STRVAR(WaitForSingleObject_doc, "WaitForSingleObject(handle, timeout) -> result\n\ \n\ Wait until the specified object is in the signaled state or\n\ the time-out interval elapses. The timeout value is specified\n\ in milliseconds."); static PyObject * winapi_WaitForSingleObject(PyObject* self, PyObject* args) { DWORD result; HANDLE handle; DWORD milliseconds; if (! PyArg_ParseTuple(args, F_HANDLE F_DWORD ":WaitForSingleObject", &handle, &milliseconds)) return NULL; Py_BEGIN_ALLOW_THREADS result = WaitForSingleObject(handle, milliseconds); Py_END_ALLOW_THREADS if (result == WAIT_FAILED) return PyErr_SetFromWindowsErr(GetLastError()); return PyLong_FromUnsignedLong(result); } static PyObject * winapi_WriteFile(PyObject *self, PyObject *args, PyObject *kwds) { HANDLE handle; Py_buffer _buf, *buf; PyObject *bufobj; DWORD written; BOOL ret; int use_overlapped = 0; DWORD err; OverlappedObject *overlapped = NULL; static char *kwlist[] = {"handle", "buffer", "overlapped", NULL}; /* First get handle and use_overlapped to know which Py_buffer to use */ if (!PyArg_ParseTupleAndKeywords(args, kwds, F_HANDLE "O|i:WriteFile", kwlist, &handle, &bufobj, &use_overlapped)) return NULL; if (use_overlapped) { overlapped = new_overlapped(handle); if (!overlapped) return NULL; buf = &overlapped->write_buffer; } else buf = &_buf; if (!PyArg_Parse(bufobj, "y*", buf)) { Py_XDECREF(overlapped); return NULL; } Py_BEGIN_ALLOW_THREADS ret = WriteFile(handle, buf->buf, buf->len, &written, overlapped ? &overlapped->overlapped : NULL); Py_END_ALLOW_THREADS err = ret ? 0 : GetLastError(); if (overlapped) { if (!ret) { if (err == ERROR_IO_PENDING) overlapped->pending = 1; else { Py_DECREF(overlapped); return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); } } return Py_BuildValue("NI", (PyObject *) overlapped, err); } PyBuffer_Release(buf); if (!ret) return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0); return Py_BuildValue("II", written, err); } static PyMethodDef winapi_functions[] = { {"CloseHandle", winapi_CloseHandle, METH_VARARGS, CloseHandle_doc}, {"ConnectNamedPipe", (PyCFunction)winapi_ConnectNamedPipe, METH_VARARGS | METH_KEYWORDS, ""}, {"CreateFile", winapi_CreateFile, METH_VARARGS, ""}, {"CreateNamedPipe", winapi_CreateNamedPipe, METH_VARARGS, ""}, {"CreatePipe", winapi_CreatePipe, METH_VARARGS, CreatePipe_doc}, {"CreateProcess", winapi_CreateProcess, METH_VARARGS, CreateProcess_doc}, {"DuplicateHandle", winapi_DuplicateHandle, METH_VARARGS, DuplicateHandle_doc}, {"ExitProcess", winapi_ExitProcess, METH_VARARGS, ""}, {"GetCurrentProcess", winapi_GetCurrentProcess, METH_VARARGS, GetCurrentProcess_doc}, {"GetExitCodeProcess", winapi_GetExitCodeProcess, METH_VARARGS, GetExitCodeProcess_doc}, {"GetLastError", winapi_GetLastError, METH_NOARGS, GetCurrentProcess_doc}, {"GetModuleFileName", winapi_GetModuleFileName, METH_VARARGS, GetModuleFileName_doc}, {"GetStdHandle", winapi_GetStdHandle, METH_VARARGS, GetStdHandle_doc}, {"GetVersion", winapi_GetVersion, METH_VARARGS, GetVersion_doc}, {"OpenProcess", winapi_OpenProcess, METH_VARARGS, ""}, {"PeekNamedPipe", winapi_PeekNamedPipe, METH_VARARGS, ""}, {"ReadFile", (PyCFunction)winapi_ReadFile, METH_VARARGS | METH_KEYWORDS, ""}, {"SetNamedPipeHandleState", winapi_SetNamedPipeHandleState, METH_VARARGS, ""}, {"TerminateProcess", winapi_TerminateProcess, METH_VARARGS, TerminateProcess_doc}, {"WaitNamedPipe", winapi_WaitNamedPipe, METH_VARARGS, ""}, {"WaitForMultipleObjects", winapi_WaitForMultipleObjects, METH_VARARGS, ""}, {"WaitForSingleObject", winapi_WaitForSingleObject, METH_VARARGS, WaitForSingleObject_doc}, {"WriteFile", (PyCFunction)winapi_WriteFile, METH_VARARGS | METH_KEYWORDS, ""}, {NULL, NULL} }; static struct PyModuleDef winapi_module = { PyModuleDef_HEAD_INIT, "_winapi", NULL, -1, winapi_functions, NULL, NULL, NULL, NULL }; #define WINAPI_CONSTANT(fmt, con) \ PyDict_SetItemString(d, #con, Py_BuildValue(fmt, con)) PyMODINIT_FUNC PyInit__winapi(void) { PyObject *d; PyObject *m; if (PyType_Ready(&OverlappedType) < 0) return NULL; m = PyModule_Create(&winapi_module); if (m == NULL) return NULL; d = PyModule_GetDict(m); PyDict_SetItemString(d, "Overlapped", (PyObject *) &OverlappedType); /* constants */ WINAPI_CONSTANT(F_DWORD, CREATE_NEW_CONSOLE); WINAPI_CONSTANT(F_DWORD, CREATE_NEW_PROCESS_GROUP); WINAPI_CONSTANT(F_DWORD, DUPLICATE_SAME_ACCESS); WINAPI_CONSTANT(F_DWORD, DUPLICATE_CLOSE_SOURCE); WINAPI_CONSTANT(F_DWORD, ERROR_ALREADY_EXISTS); WINAPI_CONSTANT(F_DWORD, ERROR_BROKEN_PIPE); WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING); WINAPI_CONSTANT(F_DWORD, ERROR_MORE_DATA); WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED); WINAPI_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES); WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED); WINAPI_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES); WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING); WINAPI_CONSTANT(F_DWORD, ERROR_MORE_DATA); WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED); WINAPI_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES); WINAPI_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED); WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY); WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_CONNECTED); WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT); WINAPI_CONSTANT(F_DWORD, FILE_FLAG_FIRST_PIPE_INSTANCE); WINAPI_CONSTANT(F_DWORD, FILE_FLAG_OVERLAPPED); WINAPI_CONSTANT(F_DWORD, FILE_GENERIC_READ); WINAPI_CONSTANT(F_DWORD, FILE_GENERIC_WRITE); WINAPI_CONSTANT(F_DWORD, GENERIC_READ); WINAPI_CONSTANT(F_DWORD, GENERIC_WRITE); WINAPI_CONSTANT(F_DWORD, INFINITE); WINAPI_CONSTANT(F_DWORD, NMPWAIT_WAIT_FOREVER); WINAPI_CONSTANT(F_DWORD, OPEN_EXISTING); WINAPI_CONSTANT(F_DWORD, PIPE_ACCESS_DUPLEX); WINAPI_CONSTANT(F_DWORD, PIPE_ACCESS_INBOUND); WINAPI_CONSTANT(F_DWORD, PIPE_READMODE_MESSAGE); WINAPI_CONSTANT(F_DWORD, PIPE_TYPE_MESSAGE); WINAPI_CONSTANT(F_DWORD, PIPE_UNLIMITED_INSTANCES); WINAPI_CONSTANT(F_DWORD, PIPE_WAIT); WINAPI_CONSTANT(F_DWORD, PROCESS_ALL_ACCESS); WINAPI_CONSTANT(F_DWORD, PROCESS_DUP_HANDLE); WINAPI_CONSTANT(F_DWORD, STARTF_USESHOWWINDOW); WINAPI_CONSTANT(F_DWORD, STARTF_USESTDHANDLES); WINAPI_CONSTANT(F_DWORD, STD_INPUT_HANDLE); WINAPI_CONSTANT(F_DWORD, STD_OUTPUT_HANDLE); WINAPI_CONSTANT(F_DWORD, STD_ERROR_HANDLE); WINAPI_CONSTANT(F_DWORD, STILL_ACTIVE); WINAPI_CONSTANT(F_DWORD, SW_HIDE); WINAPI_CONSTANT(F_DWORD, WAIT_OBJECT_0); WINAPI_CONSTANT(F_DWORD, WAIT_TIMEOUT); WINAPI_CONSTANT("i", NULL); return m; }