2004-10-12 12:26:28 -03:00
|
|
|
/*
|
|
|
|
* support routines for subprocess module
|
|
|
|
*
|
|
|
|
* Currently, this extension module is only required when using the
|
|
|
|
* subprocess module on Windows, but in the future, stubs for other
|
2004-10-12 18:38:22 -03:00
|
|
|
* platforms might be added here as well.
|
2004-10-12 12:26:28 -03:00
|
|
|
*
|
|
|
|
* Copyright (c) 2004 by Fredrik Lundh <fredrik@pythonware.com>
|
|
|
|
* Copyright (c) 2004 by Secret Labs AB, http://www.pythonware.com
|
|
|
|
* Copyright (c) 2004 by Peter Astrand <astrand@lysator.liu.se>
|
2004-10-12 18:38:22 -03:00
|
|
|
*
|
2004-10-12 12:26:28 -03:00
|
|
|
* By obtaining, using, and/or copying this software and/or its
|
|
|
|
* associated documentation, you agree that you have read, understood,
|
|
|
|
* and will comply with the following terms and conditions:
|
2004-10-12 18:38:22 -03:00
|
|
|
*
|
2004-10-12 12:26:28 -03:00
|
|
|
* Permission to use, copy, modify, and distribute this software and
|
|
|
|
* its associated documentation for any purpose and without fee is
|
|
|
|
* hereby granted, provided that the above copyright notice appears in
|
|
|
|
* all copies, and that both that copyright notice and this permission
|
|
|
|
* notice appear in supporting documentation, and that the name of the
|
|
|
|
* authors not be used in advertising or publicity pertaining to
|
|
|
|
* distribution of the software without specific, written prior
|
|
|
|
* permission.
|
2004-10-12 18:38:22 -03:00
|
|
|
*
|
2004-10-12 12:26:28 -03:00
|
|
|
* THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
|
|
|
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
|
|
|
|
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
|
|
|
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
|
|
|
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
|
|
|
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
|
|
|
|
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
2004-10-12 18:38:22 -03:00
|
|
|
*
|
2004-10-12 12:26:28 -03:00
|
|
|
*/
|
|
|
|
|
2005-12-14 18:29:34 -04:00
|
|
|
/* Licensed to PSF under a Contributor Agreement. */
|
|
|
|
/* See http://www.python.org/2.4/license for licensing details. */
|
|
|
|
|
2004-10-12 12:26:28 -03:00
|
|
|
/* TODO: handle unicode command lines? */
|
|
|
|
/* TODO: handle unicode environment? */
|
|
|
|
|
|
|
|
#include "Python.h"
|
|
|
|
|
|
|
|
#define WINDOWS_LEAN_AND_MEAN
|
|
|
|
#include "windows.h"
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/* handle wrapper. note that this library uses integers when passing
|
|
|
|
handles to a function, and handle wrappers when returning handles.
|
|
|
|
the wrapper is used to provide Detach and Close methods */
|
|
|
|
|
|
|
|
typedef struct {
|
2004-10-12 18:38:22 -03:00
|
|
|
PyObject_HEAD
|
|
|
|
HANDLE handle;
|
2004-10-12 12:26:28 -03:00
|
|
|
} sp_handle_object;
|
|
|
|
|
|
|
|
staticforward PyTypeObject sp_handle_type;
|
|
|
|
|
|
|
|
static PyObject*
|
|
|
|
sp_handle_new(HANDLE handle)
|
|
|
|
{
|
2004-10-12 18:38:22 -03:00
|
|
|
sp_handle_object* self;
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
self = PyObject_NEW(sp_handle_object, &sp_handle_type);
|
|
|
|
if (self == NULL)
|
|
|
|
return NULL;
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
self->handle = handle;
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
return (PyObject*) self;
|
2004-10-12 12:26:28 -03:00
|
|
|
}
|
|
|
|
|
2008-07-19 21:22:08 -03:00
|
|
|
#if defined(MS_WIN32) && !defined(MS_WIN64)
|
|
|
|
#define HANDLE_TO_PYNUM(handle) PyInt_FromLong((long) handle)
|
|
|
|
#define PY_HANDLE_PARAM "l"
|
|
|
|
#else
|
|
|
|
#define HANDLE_TO_PYNUM(handle) PyLong_FromLongLong((long long) handle)
|
|
|
|
#define PY_HANDLE_PARAM "L"
|
|
|
|
#endif
|
|
|
|
|
2004-10-12 12:26:28 -03:00
|
|
|
static PyObject*
|
|
|
|
sp_handle_detach(sp_handle_object* self, PyObject* args)
|
|
|
|
{
|
2004-10-12 18:38:22 -03:00
|
|
|
HANDLE handle;
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
if (! PyArg_ParseTuple(args, ":Detach"))
|
|
|
|
return NULL;
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
handle = self->handle;
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2009-03-03 18:55:00 -04:00
|
|
|
self->handle = INVALID_HANDLE_VALUE;
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
/* note: return the current handle, as an integer */
|
2008-07-19 21:22:08 -03:00
|
|
|
return HANDLE_TO_PYNUM(handle);
|
2004-10-12 12:26:28 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject*
|
|
|
|
sp_handle_close(sp_handle_object* self, PyObject* args)
|
|
|
|
{
|
2004-10-12 18:38:22 -03:00
|
|
|
if (! PyArg_ParseTuple(args, ":Close"))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (self->handle != INVALID_HANDLE_VALUE) {
|
|
|
|
CloseHandle(self->handle);
|
|
|
|
self->handle = INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
2004-10-12 12:26:28 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
sp_handle_dealloc(sp_handle_object* self)
|
|
|
|
{
|
2004-10-12 18:38:22 -03:00
|
|
|
if (self->handle != INVALID_HANDLE_VALUE)
|
|
|
|
CloseHandle(self->handle);
|
Years in the making.
objimpl.h, pymem.h: Stop mapping PyMem_{Del, DEL} and PyMem_{Free, FREE}
to PyObject_{Free, FREE} in a release build. They're aliases for the
system free() now.
_subprocess.c/sp_handle_dealloc(): Since the memory was originally
obtained via PyObject_NEW, it must be released via PyObject_FREE (or
_DEL).
pythonrun.c, tokenizer.c, parsermodule.c: I lost count of the number of
PyObject vs PyMem mismatches in these -- it's like the specific
function called at each site was picked at random, sometimes even with
memory obtained via PyMem getting released via PyObject. Changed most
to use PyObject uniformly, since the blobs allocated are predictably
small in most cases, and obmalloc is generally faster than system
mallocs then.
If extension modules in real life prove as sloppy as Python's front
end, we'll have to revert the objimpl.h + pymem.h part of this patch.
Note that no problems will show up in a debug build (all calls still go
thru obmalloc then). Problems will show up only in a release build, most
likely segfaults.
2006-03-26 19:27:58 -04:00
|
|
|
PyObject_FREE(self);
|
2004-10-12 12:26:28 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
static PyMethodDef sp_handle_methods[] = {
|
2006-05-29 18:58:42 -03:00
|
|
|
{"Detach", (PyCFunction) sp_handle_detach, METH_VARARGS},
|
|
|
|
{"Close", (PyCFunction) sp_handle_close, METH_VARARGS},
|
2004-10-12 18:38:22 -03:00
|
|
|
{NULL, NULL}
|
2004-10-12 12:26:28 -03:00
|
|
|
};
|
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
static PyObject*
|
2004-10-12 12:26:28 -03:00
|
|
|
sp_handle_getattr(sp_handle_object* self, char* name)
|
|
|
|
{
|
2004-10-12 18:38:22 -03:00
|
|
|
return Py_FindMethod(sp_handle_methods, (PyObject*) self, name);
|
2004-10-12 12:26:28 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject*
|
|
|
|
sp_handle_as_int(sp_handle_object* self)
|
|
|
|
{
|
2008-07-19 21:22:08 -03:00
|
|
|
return HANDLE_TO_PYNUM(self->handle);
|
2004-10-12 12:26:28 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
static PyNumberMethods sp_handle_as_number;
|
|
|
|
|
|
|
|
statichere PyTypeObject sp_handle_type = {
|
2004-10-12 18:38:22 -03:00
|
|
|
PyObject_HEAD_INIT(NULL)
|
|
|
|
0, /*ob_size*/
|
|
|
|
"_subprocess_handle", sizeof(sp_handle_object), 0,
|
|
|
|
(destructor) sp_handle_dealloc, /*tp_dealloc*/
|
|
|
|
0, /*tp_print*/
|
|
|
|
(getattrfunc) sp_handle_getattr,/*tp_getattr*/
|
|
|
|
0, /*tp_setattr*/
|
|
|
|
0, /*tp_compare*/
|
|
|
|
0, /*tp_repr*/
|
|
|
|
&sp_handle_as_number, /*tp_as_number */
|
|
|
|
0, /*tp_as_sequence */
|
|
|
|
0, /*tp_as_mapping */
|
|
|
|
0 /*tp_hash*/
|
2004-10-12 12:26:28 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/* windows API functions */
|
|
|
|
|
2010-04-24 12:59:50 -03:00
|
|
|
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.");
|
|
|
|
|
2004-10-12 12:26:28 -03:00
|
|
|
static PyObject *
|
|
|
|
sp_GetStdHandle(PyObject* self, PyObject* args)
|
|
|
|
{
|
2004-10-12 18:38:22 -03:00
|
|
|
HANDLE handle;
|
|
|
|
int std_handle;
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
if (! PyArg_ParseTuple(args, "i:GetStdHandle", &std_handle))
|
|
|
|
return NULL;
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
|
|
handle = GetStdHandle((DWORD) std_handle);
|
|
|
|
Py_END_ALLOW_THREADS
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
if (handle == INVALID_HANDLE_VALUE)
|
|
|
|
return PyErr_SetFromWindowsErr(GetLastError());
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
if (! handle) {
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
/* note: returns integer, not handle object */
|
2008-07-19 21:22:08 -03:00
|
|
|
return HANDLE_TO_PYNUM(handle);
|
2004-10-12 12:26:28 -03:00
|
|
|
}
|
|
|
|
|
2010-04-24 12:59:50 -03:00
|
|
|
PyDoc_STRVAR(GetCurrentProcess_doc,
|
|
|
|
"GetCurrentProcess() -> handle\n\
|
|
|
|
\n\
|
|
|
|
Return a handle object for the current process.");
|
|
|
|
|
2004-10-12 12:26:28 -03:00
|
|
|
static PyObject *
|
|
|
|
sp_GetCurrentProcess(PyObject* self, PyObject* args)
|
|
|
|
{
|
2004-10-12 18:38:22 -03:00
|
|
|
if (! PyArg_ParseTuple(args, ":GetCurrentProcess"))
|
|
|
|
return NULL;
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
return sp_handle_new(GetCurrentProcess());
|
2004-10-12 12:26:28 -03:00
|
|
|
}
|
|
|
|
|
2010-04-24 12:59:50 -03:00
|
|
|
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.");
|
|
|
|
|
2004-10-12 12:26:28 -03:00
|
|
|
static PyObject *
|
|
|
|
sp_DuplicateHandle(PyObject* self, PyObject* args)
|
|
|
|
{
|
2004-10-12 18:38:22 -03:00
|
|
|
HANDLE target_handle;
|
|
|
|
BOOL result;
|
|
|
|
|
2008-07-19 21:22:08 -03:00
|
|
|
HANDLE source_process_handle;
|
|
|
|
HANDLE source_handle;
|
|
|
|
HANDLE target_process_handle;
|
2004-10-12 18:38:22 -03:00
|
|
|
int desired_access;
|
|
|
|
int inherit_handle;
|
|
|
|
int options = 0;
|
|
|
|
|
2008-07-19 21:22:08 -03:00
|
|
|
if (! PyArg_ParseTuple(args,
|
|
|
|
PY_HANDLE_PARAM PY_HANDLE_PARAM PY_HANDLE_PARAM
|
|
|
|
"ii|i:DuplicateHandle",
|
2004-10-12 18:38:22 -03:00
|
|
|
&source_process_handle,
|
|
|
|
&source_handle,
|
|
|
|
&target_process_handle,
|
|
|
|
&desired_access,
|
|
|
|
&inherit_handle,
|
|
|
|
&options))
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
|
|
result = DuplicateHandle(
|
2008-07-19 21:22:08 -03:00
|
|
|
source_process_handle,
|
|
|
|
source_handle,
|
|
|
|
target_process_handle,
|
2004-10-12 18:38:22 -03:00
|
|
|
&target_handle,
|
|
|
|
desired_access,
|
|
|
|
inherit_handle,
|
|
|
|
options
|
|
|
|
);
|
|
|
|
Py_END_ALLOW_THREADS
|
|
|
|
|
|
|
|
if (! result)
|
|
|
|
return PyErr_SetFromWindowsErr(GetLastError());
|
|
|
|
|
|
|
|
return sp_handle_new(target_handle);
|
2004-10-12 12:26:28 -03:00
|
|
|
}
|
|
|
|
|
2010-04-24 12:59:50 -03:00
|
|
|
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.");
|
|
|
|
|
2004-10-12 12:26:28 -03:00
|
|
|
static PyObject *
|
|
|
|
sp_CreatePipe(PyObject* self, PyObject* args)
|
|
|
|
{
|
2004-10-12 18:38:22 -03:00
|
|
|
HANDLE read_pipe;
|
|
|
|
HANDLE write_pipe;
|
|
|
|
BOOL result;
|
|
|
|
|
|
|
|
PyObject* pipe_attributes; /* ignored */
|
|
|
|
int size;
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
if (! PyArg_ParseTuple(args, "Oi:CreatePipe", &pipe_attributes, &size))
|
|
|
|
return NULL;
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
|
|
result = CreatePipe(&read_pipe, &write_pipe, NULL, size);
|
|
|
|
Py_END_ALLOW_THREADS
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
if (! result)
|
|
|
|
return PyErr_SetFromWindowsErr(GetLastError());
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
return Py_BuildValue(
|
|
|
|
"NN", sp_handle_new(read_pipe), sp_handle_new(write_pipe));
|
2004-10-12 12:26:28 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* helpers for createprocess */
|
|
|
|
|
|
|
|
static int
|
|
|
|
getint(PyObject* obj, char* name)
|
|
|
|
{
|
2004-10-12 18:38:22 -03:00
|
|
|
PyObject* value;
|
2006-06-04 19:15:37 -03:00
|
|
|
int ret;
|
2004-10-12 18:38:22 -03:00
|
|
|
|
|
|
|
value = PyObject_GetAttrString(obj, name);
|
|
|
|
if (! value) {
|
|
|
|
PyErr_Clear(); /* FIXME: propagate error? */
|
|
|
|
return 0;
|
|
|
|
}
|
2006-06-04 19:15:37 -03:00
|
|
|
ret = (int) PyInt_AsLong(value);
|
|
|
|
Py_DECREF(value);
|
|
|
|
return ret;
|
2004-10-12 12:26:28 -03:00
|
|
|
}
|
2004-10-12 18:38:22 -03:00
|
|
|
|
2004-10-12 12:26:28 -03:00
|
|
|
static HANDLE
|
|
|
|
gethandle(PyObject* obj, char* name)
|
|
|
|
{
|
2004-10-12 18:38:22 -03:00
|
|
|
sp_handle_object* value;
|
2006-06-04 19:15:37 -03:00
|
|
|
HANDLE ret;
|
2004-10-12 18:38:22 -03:00
|
|
|
|
|
|
|
value = (sp_handle_object*) PyObject_GetAttrString(obj, name);
|
|
|
|
if (! value) {
|
|
|
|
PyErr_Clear(); /* FIXME: propagate error? */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (value->ob_type != &sp_handle_type)
|
2006-06-04 19:15:37 -03:00
|
|
|
ret = NULL;
|
|
|
|
else
|
|
|
|
ret = value->handle;
|
|
|
|
Py_DECREF(value);
|
|
|
|
return ret;
|
2004-10-12 12:26:28 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject*
|
|
|
|
getenvironment(PyObject* environment)
|
|
|
|
{
|
2004-10-12 18:38:22 -03:00
|
|
|
int i, envsize;
|
|
|
|
PyObject* out = NULL;
|
|
|
|
PyObject* keys;
|
|
|
|
PyObject* values;
|
|
|
|
char* p;
|
|
|
|
|
|
|
|
/* 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;
|
|
|
|
|
2008-06-09 01:58:54 -03:00
|
|
|
out = PyString_FromStringAndSize(NULL, 2048);
|
2004-10-12 18:38:22 -03:00
|
|
|
if (! out)
|
|
|
|
goto error;
|
|
|
|
|
2008-06-09 01:58:54 -03:00
|
|
|
p = PyString_AS_STRING(out);
|
2004-10-12 18:38:22 -03:00
|
|
|
|
|
|
|
for (i = 0; i < envsize; i++) {
|
|
|
|
int ksize, vsize, totalsize;
|
|
|
|
PyObject* key = PyList_GET_ITEM(keys, i);
|
|
|
|
PyObject* value = PyList_GET_ITEM(values, i);
|
|
|
|
|
2008-06-09 01:58:54 -03:00
|
|
|
if (! PyString_Check(key) || ! PyString_Check(value)) {
|
2004-10-12 18:38:22 -03:00
|
|
|
PyErr_SetString(PyExc_TypeError,
|
|
|
|
"environment can only contain strings");
|
|
|
|
goto error;
|
|
|
|
}
|
2008-06-09 01:58:54 -03:00
|
|
|
ksize = PyString_GET_SIZE(key);
|
|
|
|
vsize = PyString_GET_SIZE(value);
|
|
|
|
totalsize = (p - PyString_AS_STRING(out)) + ksize + 1 +
|
2004-10-12 18:38:22 -03:00
|
|
|
vsize + 1 + 1;
|
2008-06-09 01:58:54 -03:00
|
|
|
if (totalsize > PyString_GET_SIZE(out)) {
|
|
|
|
int offset = p - PyString_AS_STRING(out);
|
|
|
|
_PyString_Resize(&out, totalsize + 1024);
|
|
|
|
p = PyString_AS_STRING(out) + offset;
|
2004-10-12 18:38:22 -03:00
|
|
|
}
|
2008-06-09 01:58:54 -03:00
|
|
|
memcpy(p, PyString_AS_STRING(key), ksize);
|
2004-10-12 18:38:22 -03:00
|
|
|
p += ksize;
|
|
|
|
*p++ = '=';
|
2008-06-09 01:58:54 -03:00
|
|
|
memcpy(p, PyString_AS_STRING(value), vsize);
|
2004-10-12 18:38:22 -03:00
|
|
|
p += vsize;
|
|
|
|
*p++ = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add trailing null byte */
|
|
|
|
*p++ = '\0';
|
2008-06-09 01:58:54 -03:00
|
|
|
_PyString_Resize(&out, p - PyString_AS_STRING(out));
|
2004-10-12 18:38:22 -03:00
|
|
|
|
|
|
|
/* PyObject_Print(out, stdout, 0); */
|
|
|
|
|
2005-11-12 06:15:03 -04:00
|
|
|
Py_XDECREF(keys);
|
|
|
|
Py_XDECREF(values);
|
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
return out;
|
|
|
|
|
|
|
|
error:
|
|
|
|
Py_XDECREF(out);
|
|
|
|
Py_XDECREF(keys);
|
|
|
|
Py_XDECREF(values);
|
|
|
|
return NULL;
|
2004-10-12 12:26:28 -03:00
|
|
|
}
|
|
|
|
|
2010-04-24 12:59:50 -03:00
|
|
|
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.");
|
|
|
|
|
2004-10-12 12:26:28 -03:00
|
|
|
static PyObject *
|
|
|
|
sp_CreateProcess(PyObject* self, PyObject* args)
|
|
|
|
{
|
2004-10-12 18:38:22 -03:00
|
|
|
BOOL result;
|
|
|
|
PROCESS_INFORMATION pi;
|
|
|
|
STARTUPINFO si;
|
|
|
|
PyObject* environment;
|
|
|
|
|
|
|
|
char* application_name;
|
|
|
|
char* command_line;
|
|
|
|
PyObject* process_attributes; /* ignored */
|
|
|
|
PyObject* thread_attributes; /* ignored */
|
|
|
|
int inherit_handles;
|
|
|
|
int creation_flags;
|
|
|
|
PyObject* env_mapping;
|
|
|
|
char* current_directory;
|
|
|
|
PyObject* startup_info;
|
|
|
|
|
|
|
|
if (! PyArg_ParseTuple(args, "zzOOiiOzO:CreateProcess",
|
|
|
|
&application_name,
|
|
|
|
&command_line,
|
|
|
|
&process_attributes,
|
|
|
|
&thread_attributes,
|
|
|
|
&inherit_handles,
|
|
|
|
&creation_flags,
|
|
|
|
&env_mapping,
|
|
|
|
¤t_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 = getint(startup_info, "dwFlags");
|
2004-11-07 10:30:34 -04:00
|
|
|
si.wShowWindow = getint(startup_info, "wShowWindow");
|
2004-10-12 18:38:22 -03:00
|
|
|
si.hStdInput = gethandle(startup_info, "hStdInput");
|
|
|
|
si.hStdOutput = gethandle(startup_info, "hStdOutput");
|
|
|
|
si.hStdError = gethandle(startup_info, "hStdError");
|
|
|
|
|
2005-11-12 06:15:14 -04:00
|
|
|
if (PyErr_Occurred())
|
|
|
|
return NULL;
|
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
if (env_mapping == Py_None)
|
|
|
|
environment = NULL;
|
|
|
|
else {
|
|
|
|
environment = getenvironment(env_mapping);
|
|
|
|
if (! environment)
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
|
|
result = CreateProcess(application_name,
|
|
|
|
command_line,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
inherit_handles,
|
|
|
|
creation_flags,
|
2008-06-09 01:58:54 -03:00
|
|
|
environment ? PyString_AS_STRING(environment) : NULL,
|
2004-10-12 18:38:22 -03:00
|
|
|
current_directory,
|
|
|
|
&si,
|
|
|
|
&pi);
|
|
|
|
Py_END_ALLOW_THREADS
|
|
|
|
|
|
|
|
Py_XDECREF(environment);
|
|
|
|
|
|
|
|
if (! result)
|
|
|
|
return PyErr_SetFromWindowsErr(GetLastError());
|
|
|
|
|
|
|
|
return Py_BuildValue("NNii",
|
|
|
|
sp_handle_new(pi.hProcess),
|
|
|
|
sp_handle_new(pi.hThread),
|
|
|
|
pi.dwProcessId,
|
|
|
|
pi.dwThreadId);
|
2004-10-12 12:26:28 -03:00
|
|
|
}
|
|
|
|
|
2010-04-24 12:59:50 -03:00
|
|
|
PyDoc_STRVAR(TerminateProcess_doc,
|
|
|
|
"TerminateProcess(handle, exit_code) -> None\n\
|
|
|
|
\n\
|
|
|
|
Terminate the specified process and all of its threads.");
|
|
|
|
|
2005-12-18 17:06:46 -04:00
|
|
|
static PyObject *
|
|
|
|
sp_TerminateProcess(PyObject* self, PyObject* args)
|
|
|
|
{
|
|
|
|
BOOL result;
|
|
|
|
|
2008-07-19 21:22:08 -03:00
|
|
|
HANDLE process;
|
2005-12-18 17:06:46 -04:00
|
|
|
int exit_code;
|
2008-07-19 21:22:08 -03:00
|
|
|
if (! PyArg_ParseTuple(args, PY_HANDLE_PARAM "i:TerminateProcess",
|
|
|
|
&process, &exit_code))
|
2005-12-18 17:06:46 -04:00
|
|
|
return NULL;
|
|
|
|
|
2008-07-19 21:22:08 -03:00
|
|
|
result = TerminateProcess(process, exit_code);
|
2005-12-18 17:06:46 -04:00
|
|
|
|
|
|
|
if (! result)
|
|
|
|
return PyErr_SetFromWindowsErr(GetLastError());
|
|
|
|
|
|
|
|
Py_INCREF(Py_None);
|
|
|
|
return Py_None;
|
|
|
|
}
|
|
|
|
|
2010-04-24 12:59:50 -03:00
|
|
|
PyDoc_STRVAR(GetExitCodeProcess_doc,
|
|
|
|
"GetExitCodeProcess(handle) -> Exit code\n\
|
|
|
|
\n\
|
|
|
|
Return the termination status of the specified process.");
|
|
|
|
|
2004-10-12 12:26:28 -03:00
|
|
|
static PyObject *
|
|
|
|
sp_GetExitCodeProcess(PyObject* self, PyObject* args)
|
|
|
|
{
|
2004-10-12 18:38:22 -03:00
|
|
|
DWORD exit_code;
|
|
|
|
BOOL result;
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2008-07-19 21:22:08 -03:00
|
|
|
HANDLE process;
|
|
|
|
if (! PyArg_ParseTuple(args, PY_HANDLE_PARAM ":GetExitCodeProcess", &process))
|
2004-10-12 18:38:22 -03:00
|
|
|
return NULL;
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2008-07-19 21:22:08 -03:00
|
|
|
result = GetExitCodeProcess(process, &exit_code);
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
if (! result)
|
|
|
|
return PyErr_SetFromWindowsErr(GetLastError());
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
return PyInt_FromLong(exit_code);
|
2004-10-12 12:26:28 -03:00
|
|
|
}
|
|
|
|
|
2010-04-24 12:59:50 -03:00
|
|
|
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.");
|
|
|
|
|
2004-10-12 12:26:28 -03:00
|
|
|
static PyObject *
|
|
|
|
sp_WaitForSingleObject(PyObject* self, PyObject* args)
|
|
|
|
{
|
2004-10-12 18:38:22 -03:00
|
|
|
DWORD result;
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2008-07-19 21:22:08 -03:00
|
|
|
HANDLE handle;
|
2004-10-12 18:38:22 -03:00
|
|
|
int milliseconds;
|
2008-07-19 21:22:08 -03:00
|
|
|
if (! PyArg_ParseTuple(args, PY_HANDLE_PARAM "i:WaitForSingleObject",
|
2004-10-12 18:38:22 -03:00
|
|
|
&handle,
|
|
|
|
&milliseconds))
|
|
|
|
return NULL;
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
Py_BEGIN_ALLOW_THREADS
|
2008-07-19 21:22:08 -03:00
|
|
|
result = WaitForSingleObject(handle, (DWORD) milliseconds);
|
2004-10-12 18:38:22 -03:00
|
|
|
Py_END_ALLOW_THREADS
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
if (result == WAIT_FAILED)
|
|
|
|
return PyErr_SetFromWindowsErr(GetLastError());
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
return PyInt_FromLong((int) result);
|
2004-10-12 12:26:28 -03:00
|
|
|
}
|
|
|
|
|
2010-04-24 12:59:50 -03:00
|
|
|
PyDoc_STRVAR(GetVersion_doc,
|
|
|
|
"GetVersion() -> version\n\
|
|
|
|
\n\
|
|
|
|
Return the version number of the current operating system.");
|
|
|
|
|
2004-10-12 12:26:28 -03:00
|
|
|
static PyObject *
|
|
|
|
sp_GetVersion(PyObject* self, PyObject* args)
|
|
|
|
{
|
2004-10-12 18:38:22 -03:00
|
|
|
if (! PyArg_ParseTuple(args, ":GetVersion"))
|
|
|
|
return NULL;
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
return PyInt_FromLong((int) GetVersion());
|
2004-10-12 12:26:28 -03:00
|
|
|
}
|
|
|
|
|
2010-04-24 12:59:50 -03:00
|
|
|
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.");
|
|
|
|
|
2004-10-12 12:26:28 -03:00
|
|
|
static PyObject *
|
|
|
|
sp_GetModuleFileName(PyObject* self, PyObject* args)
|
|
|
|
{
|
2004-10-12 18:38:22 -03:00
|
|
|
BOOL result;
|
2008-07-19 21:22:08 -03:00
|
|
|
HMODULE module;
|
2004-10-12 18:38:22 -03:00
|
|
|
TCHAR filename[MAX_PATH];
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2008-07-19 21:22:08 -03:00
|
|
|
if (! PyArg_ParseTuple(args, PY_HANDLE_PARAM ":GetModuleFileName",
|
|
|
|
&module))
|
2004-10-12 18:38:22 -03:00
|
|
|
return NULL;
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2008-07-19 21:22:08 -03:00
|
|
|
result = GetModuleFileName(module, filename, MAX_PATH);
|
2004-10-12 18:38:22 -03:00
|
|
|
filename[MAX_PATH-1] = '\0';
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2004-10-12 18:38:22 -03:00
|
|
|
if (! result)
|
|
|
|
return PyErr_SetFromWindowsErr(GetLastError());
|
2004-10-12 12:26:28 -03:00
|
|
|
|
2008-06-09 01:58:54 -03:00
|
|
|
return PyString_FromString(filename);
|
2004-10-12 12:26:28 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
static PyMethodDef sp_functions[] = {
|
2010-04-24 12:59:50 -03:00
|
|
|
{"GetStdHandle", sp_GetStdHandle, METH_VARARGS, GetStdHandle_doc},
|
|
|
|
{"GetCurrentProcess", sp_GetCurrentProcess, METH_VARARGS,
|
|
|
|
GetCurrentProcess_doc},
|
|
|
|
{"DuplicateHandle", sp_DuplicateHandle, METH_VARARGS,
|
|
|
|
DuplicateHandle_doc},
|
|
|
|
{"CreatePipe", sp_CreatePipe, METH_VARARGS, CreatePipe_doc},
|
|
|
|
{"CreateProcess", sp_CreateProcess, METH_VARARGS, CreateProcess_doc},
|
|
|
|
{"TerminateProcess", sp_TerminateProcess, METH_VARARGS,
|
|
|
|
TerminateProcess_doc},
|
|
|
|
{"GetExitCodeProcess", sp_GetExitCodeProcess, METH_VARARGS,
|
|
|
|
GetExitCodeProcess_doc},
|
|
|
|
{"WaitForSingleObject", sp_WaitForSingleObject, METH_VARARGS,
|
|
|
|
WaitForSingleObject_doc},
|
|
|
|
{"GetVersion", sp_GetVersion, METH_VARARGS, GetVersion_doc},
|
|
|
|
{"GetModuleFileName", sp_GetModuleFileName, METH_VARARGS,
|
|
|
|
GetModuleFileName_doc},
|
2004-10-12 18:38:22 -03:00
|
|
|
{NULL, NULL}
|
2004-10-12 12:26:28 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
static void
|
|
|
|
defint(PyObject* d, const char* name, int value)
|
|
|
|
{
|
2004-10-12 18:38:22 -03:00
|
|
|
PyObject* v = PyInt_FromLong((long) value);
|
|
|
|
if (v) {
|
|
|
|
PyDict_SetItemString(d, (char*) name, v);
|
|
|
|
Py_DECREF(v);
|
|
|
|
}
|
2004-10-12 12:26:28 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
#if PY_VERSION_HEX >= 0x02030000
|
|
|
|
PyMODINIT_FUNC
|
|
|
|
#else
|
|
|
|
DL_EXPORT(void)
|
|
|
|
#endif
|
|
|
|
init_subprocess()
|
|
|
|
{
|
2004-10-12 18:38:22 -03:00
|
|
|
PyObject *d;
|
|
|
|
PyObject *m;
|
|
|
|
|
|
|
|
/* patch up object descriptors */
|
|
|
|
sp_handle_type.ob_type = &PyType_Type;
|
|
|
|
sp_handle_as_number.nb_int = (unaryfunc) sp_handle_as_int;
|
|
|
|
|
|
|
|
m = Py_InitModule("_subprocess", sp_functions);
|
2006-01-19 02:09:39 -04:00
|
|
|
if (m == NULL)
|
|
|
|
return;
|
2004-10-12 18:38:22 -03:00
|
|
|
d = PyModule_GetDict(m);
|
|
|
|
|
|
|
|
/* constants */
|
|
|
|
defint(d, "STD_INPUT_HANDLE", STD_INPUT_HANDLE);
|
|
|
|
defint(d, "STD_OUTPUT_HANDLE", STD_OUTPUT_HANDLE);
|
|
|
|
defint(d, "STD_ERROR_HANDLE", STD_ERROR_HANDLE);
|
|
|
|
defint(d, "DUPLICATE_SAME_ACCESS", DUPLICATE_SAME_ACCESS);
|
|
|
|
defint(d, "STARTF_USESTDHANDLES", STARTF_USESTDHANDLES);
|
2004-11-07 10:30:34 -04:00
|
|
|
defint(d, "STARTF_USESHOWWINDOW", STARTF_USESHOWWINDOW);
|
|
|
|
defint(d, "SW_HIDE", SW_HIDE);
|
2004-10-12 18:38:22 -03:00
|
|
|
defint(d, "INFINITE", INFINITE);
|
|
|
|
defint(d, "WAIT_OBJECT_0", WAIT_OBJECT_0);
|
|
|
|
defint(d, "CREATE_NEW_CONSOLE", CREATE_NEW_CONSOLE);
|
2004-10-12 12:26:28 -03:00
|
|
|
}
|