2 * support routines for subprocess module
4 * Currently, this extension module is only required when using the
5 * subprocess module on Windows, but in the future, stubs for other
6 * platforms might be added here as well.
8 * Copyright (c) 2004 by Fredrik Lundh <fredrik@pythonware.com>
9 * Copyright (c) 2004 by Secret Labs AB, http://www.pythonware.com
10 * Copyright (c) 2004 by Peter Astrand <astrand@lysator.liu.se>
12 * By obtaining, using, and/or copying this software and/or its
13 * associated documentation, you agree that you have read, understood,
14 * and will comply with the following terms and conditions:
16 * Permission to use, copy, modify, and distribute this software and
17 * its associated documentation for any purpose and without fee is
18 * hereby granted, provided that the above copyright notice appears in
19 * all copies, and that both that copyright notice and this permission
20 * notice appear in supporting documentation, and that the name of the
21 * authors not be used in advertising or publicity pertaining to
22 * distribution of the software without specific, written prior
25 * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
26 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
27 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
28 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
29 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
30 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
31 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
35 /* Licensed to PSF under a Contributor Agreement. */
36 /* See http://www.python.org/2.4/license for licensing details. */
38 /* TODO: handle unicode command lines? */
39 /* TODO: handle unicode environment? */
43 #define WINDOWS_LEAN_AND_MEAN
46 /* -------------------------------------------------------------------- */
47 /* handle wrapper. note that this library uses integers when passing
48 handles to a function, and handle wrappers when returning handles.
49 the wrapper is used to provide Detach and Close methods */
56 staticforward PyTypeObject sp_handle_type
;
59 sp_handle_new(HANDLE handle
)
61 sp_handle_object
* self
;
63 self
= PyObject_NEW(sp_handle_object
, &sp_handle_type
);
67 self
->handle
= handle
;
69 return (PyObject
*) self
;
72 #if defined(MS_WIN32) && !defined(MS_WIN64)
73 #define HANDLE_TO_PYNUM(handle) PyInt_FromLong((long) handle)
74 #define PY_HANDLE_PARAM "l"
76 #define HANDLE_TO_PYNUM(handle) PyLong_FromLongLong((long long) handle)
77 #define PY_HANDLE_PARAM "L"
81 sp_handle_detach(sp_handle_object
* self
, PyObject
* args
)
85 if (! PyArg_ParseTuple(args
, ":Detach"))
88 handle
= self
->handle
;
90 self
->handle
= INVALID_HANDLE_VALUE
;
92 /* note: return the current handle, as an integer */
93 return HANDLE_TO_PYNUM(handle
);
97 sp_handle_close(sp_handle_object
* self
, PyObject
* args
)
99 if (! PyArg_ParseTuple(args
, ":Close"))
102 if (self
->handle
!= INVALID_HANDLE_VALUE
) {
103 CloseHandle(self
->handle
);
104 self
->handle
= INVALID_HANDLE_VALUE
;
111 sp_handle_dealloc(sp_handle_object
* self
)
113 if (self
->handle
!= INVALID_HANDLE_VALUE
)
114 CloseHandle(self
->handle
);
118 static PyMethodDef sp_handle_methods
[] = {
119 {"Detach", (PyCFunction
) sp_handle_detach
, METH_VARARGS
},
120 {"Close", (PyCFunction
) sp_handle_close
, METH_VARARGS
},
125 sp_handle_getattr(sp_handle_object
* self
, char* name
)
127 return Py_FindMethod(sp_handle_methods
, (PyObject
*) self
, name
);
131 sp_handle_as_int(sp_handle_object
* self
)
133 return HANDLE_TO_PYNUM(self
->handle
);
136 static PyNumberMethods sp_handle_as_number
;
138 statichere PyTypeObject sp_handle_type
= {
139 PyObject_HEAD_INIT(NULL
)
141 "_subprocess_handle", sizeof(sp_handle_object
), 0,
142 (destructor
) sp_handle_dealloc
, /*tp_dealloc*/
144 (getattrfunc
) sp_handle_getattr
,/*tp_getattr*/
148 &sp_handle_as_number
, /*tp_as_number */
149 0, /*tp_as_sequence */
150 0, /*tp_as_mapping */
154 /* -------------------------------------------------------------------- */
155 /* windows API functions */
157 PyDoc_STRVAR(GetStdHandle_doc
,
158 "GetStdHandle(handle) -> integer\n\
160 Return a handle to the specified standard device\n\
161 (STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE).\n\
162 The integer associated with the handle object is returned.");
165 sp_GetStdHandle(PyObject
* self
, PyObject
* args
)
170 if (! PyArg_ParseTuple(args
, "i:GetStdHandle", &std_handle
))
173 Py_BEGIN_ALLOW_THREADS
174 handle
= GetStdHandle((DWORD
) std_handle
);
177 if (handle
== INVALID_HANDLE_VALUE
)
178 return PyErr_SetFromWindowsErr(GetLastError());
185 /* note: returns integer, not handle object */
186 return HANDLE_TO_PYNUM(handle
);
189 PyDoc_STRVAR(GetCurrentProcess_doc
,
190 "GetCurrentProcess() -> handle\n\
192 Return a handle object for the current process.");
195 sp_GetCurrentProcess(PyObject
* self
, PyObject
* args
)
197 if (! PyArg_ParseTuple(args
, ":GetCurrentProcess"))
200 return sp_handle_new(GetCurrentProcess());
203 PyDoc_STRVAR(DuplicateHandle_doc
,
204 "DuplicateHandle(source_proc_handle, source_handle,\n\
205 target_proc_handle, target_handle, access,\n\
206 inherit[, options]) -> handle\n\
208 Return a duplicate handle object.\n\
210 The duplicate handle refers to the same object as the original\n\
211 handle. Therefore, any changes to the object are reflected\n\
212 through both handles.");
215 sp_DuplicateHandle(PyObject
* self
, PyObject
* args
)
217 HANDLE target_handle
;
220 HANDLE source_process_handle
;
221 HANDLE source_handle
;
222 HANDLE target_process_handle
;
227 if (! PyArg_ParseTuple(args
,
228 PY_HANDLE_PARAM PY_HANDLE_PARAM PY_HANDLE_PARAM
229 "ii|i:DuplicateHandle",
230 &source_process_handle
,
232 &target_process_handle
,
238 Py_BEGIN_ALLOW_THREADS
239 result
= DuplicateHandle(
240 source_process_handle
,
242 target_process_handle
,
251 return PyErr_SetFromWindowsErr(GetLastError());
253 return sp_handle_new(target_handle
);
256 PyDoc_STRVAR(CreatePipe_doc
,
257 "CreatePipe(pipe_attrs, size) -> (read_handle, write_handle)\n\
259 Create an anonymous pipe, and return handles to the read and\n\
260 write ends of the pipe.\n\
262 pipe_attrs is ignored internally and can be None.");
265 sp_CreatePipe(PyObject
* self
, PyObject
* args
)
271 PyObject
* pipe_attributes
; /* ignored */
274 if (! PyArg_ParseTuple(args
, "Oi:CreatePipe", &pipe_attributes
, &size
))
277 Py_BEGIN_ALLOW_THREADS
278 result
= CreatePipe(&read_pipe
, &write_pipe
, NULL
, size
);
282 return PyErr_SetFromWindowsErr(GetLastError());
284 return Py_BuildValue(
285 "NN", sp_handle_new(read_pipe
), sp_handle_new(write_pipe
));
288 /* helpers for createprocess */
291 getint(PyObject
* obj
, char* name
)
296 value
= PyObject_GetAttrString(obj
, name
);
298 PyErr_Clear(); /* FIXME: propagate error? */
301 ret
= (int) PyInt_AsLong(value
);
307 gethandle(PyObject
* obj
, char* name
)
309 sp_handle_object
* value
;
312 value
= (sp_handle_object
*) PyObject_GetAttrString(obj
, name
);
314 PyErr_Clear(); /* FIXME: propagate error? */
317 if (value
->ob_type
!= &sp_handle_type
)
326 getenvironment(PyObject
* environment
)
329 PyObject
* out
= NULL
;
334 /* convert environment dictionary to windows enviroment string */
335 if (! PyMapping_Check(environment
)) {
337 PyExc_TypeError
, "environment must be dictionary or None");
341 envsize
= PyMapping_Length(environment
);
343 keys
= PyMapping_Keys(environment
);
344 values
= PyMapping_Values(environment
);
345 if (!keys
|| !values
)
348 out
= PyString_FromStringAndSize(NULL
, 2048);
352 p
= PyString_AS_STRING(out
);
354 for (i
= 0; i
< envsize
; i
++) {
355 int ksize
, vsize
, totalsize
;
356 PyObject
* key
= PyList_GET_ITEM(keys
, i
);
357 PyObject
* value
= PyList_GET_ITEM(values
, i
);
359 if (! PyString_Check(key
) || ! PyString_Check(value
)) {
360 PyErr_SetString(PyExc_TypeError
,
361 "environment can only contain strings");
364 ksize
= PyString_GET_SIZE(key
);
365 vsize
= PyString_GET_SIZE(value
);
366 totalsize
= (p
- PyString_AS_STRING(out
)) + ksize
+ 1 +
368 if (totalsize
> PyString_GET_SIZE(out
)) {
369 int offset
= p
- PyString_AS_STRING(out
);
370 _PyString_Resize(&out
, totalsize
+ 1024);
371 p
= PyString_AS_STRING(out
) + offset
;
373 memcpy(p
, PyString_AS_STRING(key
), ksize
);
376 memcpy(p
, PyString_AS_STRING(value
), vsize
);
381 /* add trailing null byte */
383 _PyString_Resize(&out
, p
- PyString_AS_STRING(out
));
385 /* PyObject_Print(out, stdout, 0); */
399 PyDoc_STRVAR(CreateProcess_doc
,
400 "CreateProcess(app_name, cmd_line, proc_attrs, thread_attrs,\n\
401 inherit, flags, env_mapping, curdir,\n\
402 startup_info) -> (proc_handle, thread_handle,\n\
405 Create a new process and its primary thread. The return\n\
406 value is a tuple of the process handle, thread handle,\n\
407 process ID, and thread ID.\n\
409 proc_attrs and thread_attrs are ignored internally and can be None.");
412 sp_CreateProcess(PyObject
* self
, PyObject
* args
)
415 PROCESS_INFORMATION pi
;
417 PyObject
* environment
;
419 char* application_name
;
421 PyObject
* process_attributes
; /* ignored */
422 PyObject
* thread_attributes
; /* ignored */
425 PyObject
* env_mapping
;
426 char* current_directory
;
427 PyObject
* startup_info
;
429 if (! PyArg_ParseTuple(args
, "zzOOiiOzO:CreateProcess",
441 ZeroMemory(&si
, sizeof(si
));
444 /* note: we only support a small subset of all SI attributes */
445 si
.dwFlags
= getint(startup_info
, "dwFlags");
446 si
.wShowWindow
= getint(startup_info
, "wShowWindow");
447 si
.hStdInput
= gethandle(startup_info
, "hStdInput");
448 si
.hStdOutput
= gethandle(startup_info
, "hStdOutput");
449 si
.hStdError
= gethandle(startup_info
, "hStdError");
451 if (PyErr_Occurred())
454 if (env_mapping
== Py_None
)
457 environment
= getenvironment(env_mapping
);
462 Py_BEGIN_ALLOW_THREADS
463 result
= CreateProcess(application_name
,
469 environment
? PyString_AS_STRING(environment
) : NULL
,
475 Py_XDECREF(environment
);
478 return PyErr_SetFromWindowsErr(GetLastError());
480 return Py_BuildValue("NNii",
481 sp_handle_new(pi
.hProcess
),
482 sp_handle_new(pi
.hThread
),
487 PyDoc_STRVAR(TerminateProcess_doc
,
488 "TerminateProcess(handle, exit_code) -> None\n\
490 Terminate the specified process and all of its threads.");
493 sp_TerminateProcess(PyObject
* self
, PyObject
* args
)
499 if (! PyArg_ParseTuple(args
, PY_HANDLE_PARAM
"i:TerminateProcess",
500 &process
, &exit_code
))
503 result
= TerminateProcess(process
, exit_code
);
506 return PyErr_SetFromWindowsErr(GetLastError());
512 PyDoc_STRVAR(GetExitCodeProcess_doc
,
513 "GetExitCodeProcess(handle) -> Exit code\n\
515 Return the termination status of the specified process.");
518 sp_GetExitCodeProcess(PyObject
* self
, PyObject
* args
)
524 if (! PyArg_ParseTuple(args
, PY_HANDLE_PARAM
":GetExitCodeProcess", &process
))
527 result
= GetExitCodeProcess(process
, &exit_code
);
530 return PyErr_SetFromWindowsErr(GetLastError());
532 return PyInt_FromLong(exit_code
);
535 PyDoc_STRVAR(WaitForSingleObject_doc
,
536 "WaitForSingleObject(handle, timeout) -> result\n\
538 Wait until the specified object is in the signaled state or\n\
539 the time-out interval elapses. The timeout value is specified\n\
543 sp_WaitForSingleObject(PyObject
* self
, PyObject
* args
)
549 if (! PyArg_ParseTuple(args
, PY_HANDLE_PARAM
"i:WaitForSingleObject",
554 Py_BEGIN_ALLOW_THREADS
555 result
= WaitForSingleObject(handle
, (DWORD
) milliseconds
);
558 if (result
== WAIT_FAILED
)
559 return PyErr_SetFromWindowsErr(GetLastError());
561 return PyInt_FromLong((int) result
);
564 PyDoc_STRVAR(GetVersion_doc
,
565 "GetVersion() -> version\n\
567 Return the version number of the current operating system.");
570 sp_GetVersion(PyObject
* self
, PyObject
* args
)
572 if (! PyArg_ParseTuple(args
, ":GetVersion"))
575 return PyInt_FromLong((int) GetVersion());
578 PyDoc_STRVAR(GetModuleFileName_doc
,
579 "GetModuleFileName(module) -> path\n\
581 Return the fully-qualified path for the file that contains\n\
582 the specified module. The module must have been loaded by the\n\
585 The module parameter should be a handle to the loaded module\n\
586 whose path is being requested. If this parameter is 0, \n\
587 GetModuleFileName retrieves the path of the executable file\n\
588 of the current process.");
591 sp_GetModuleFileName(PyObject
* self
, PyObject
* args
)
595 TCHAR filename
[MAX_PATH
];
597 if (! PyArg_ParseTuple(args
, PY_HANDLE_PARAM
":GetModuleFileName",
601 result
= GetModuleFileName(module
, filename
, MAX_PATH
);
602 filename
[MAX_PATH
-1] = '\0';
605 return PyErr_SetFromWindowsErr(GetLastError());
607 return PyString_FromString(filename
);
610 static PyMethodDef sp_functions
[] = {
611 {"GetStdHandle", sp_GetStdHandle
, METH_VARARGS
, GetStdHandle_doc
},
612 {"GetCurrentProcess", sp_GetCurrentProcess
, METH_VARARGS
,
613 GetCurrentProcess_doc
},
614 {"DuplicateHandle", sp_DuplicateHandle
, METH_VARARGS
,
615 DuplicateHandle_doc
},
616 {"CreatePipe", sp_CreatePipe
, METH_VARARGS
, CreatePipe_doc
},
617 {"CreateProcess", sp_CreateProcess
, METH_VARARGS
, CreateProcess_doc
},
618 {"TerminateProcess", sp_TerminateProcess
, METH_VARARGS
,
619 TerminateProcess_doc
},
620 {"GetExitCodeProcess", sp_GetExitCodeProcess
, METH_VARARGS
,
621 GetExitCodeProcess_doc
},
622 {"WaitForSingleObject", sp_WaitForSingleObject
, METH_VARARGS
,
623 WaitForSingleObject_doc
},
624 {"GetVersion", sp_GetVersion
, METH_VARARGS
, GetVersion_doc
},
625 {"GetModuleFileName", sp_GetModuleFileName
, METH_VARARGS
,
626 GetModuleFileName_doc
},
630 /* -------------------------------------------------------------------- */
633 defint(PyObject
* d
, const char* name
, int value
)
635 PyObject
* v
= PyInt_FromLong((long) value
);
637 PyDict_SetItemString(d
, (char*) name
, v
);
642 #if PY_VERSION_HEX >= 0x02030000
652 /* patch up object descriptors */
653 sp_handle_type
.ob_type
= &PyType_Type
;
654 sp_handle_as_number
.nb_int
= (unaryfunc
) sp_handle_as_int
;
656 m
= Py_InitModule("_subprocess", sp_functions
);
659 d
= PyModule_GetDict(m
);
662 defint(d
, "STD_INPUT_HANDLE", STD_INPUT_HANDLE
);
663 defint(d
, "STD_OUTPUT_HANDLE", STD_OUTPUT_HANDLE
);
664 defint(d
, "STD_ERROR_HANDLE", STD_ERROR_HANDLE
);
665 defint(d
, "DUPLICATE_SAME_ACCESS", DUPLICATE_SAME_ACCESS
);
666 defint(d
, "STARTF_USESTDHANDLES", STARTF_USESTDHANDLES
);
667 defint(d
, "STARTF_USESHOWWINDOW", STARTF_USESHOWWINDOW
);
668 defint(d
, "SW_HIDE", SW_HIDE
);
669 defint(d
, "INFINITE", INFINITE
);
670 defint(d
, "WAIT_OBJECT_0", WAIT_OBJECT_0
);
671 defint(d
, "CREATE_NEW_CONSOLE", CREATE_NEW_CONSOLE
);
672 defint(d
, "CREATE_NEW_PROCESS_GROUP", CREATE_NEW_PROCESS_GROUP
);