blob: 0274874ddae8461b7b4ffd7c22920215bdac9f15 [file] [log] [blame]
Antoine Pitrou23bba4c2012-04-18 20:51:15 +02001/*
2 * Support routines from the Windows API
3 *
4 * This module was originally created by merging PC/_subprocess.c with
5 * Modules/_multiprocessing/win32_functions.c.
6 *
7 * Copyright (c) 2004 by Fredrik Lundh <fredrik@pythonware.com>
8 * Copyright (c) 2004 by Secret Labs AB, http://www.pythonware.com
9 * Copyright (c) 2004 by Peter Astrand <astrand@lysator.liu.se>
10 *
11 * By obtaining, using, and/or copying this software and/or its
12 * associated documentation, you agree that you have read, understood,
13 * and will comply with the following terms and conditions:
14 *
15 * Permission to use, copy, modify, and distribute this software and
16 * its associated documentation for any purpose and without fee is
17 * hereby granted, provided that the above copyright notice appears in
18 * all copies, and that both that copyright notice and this permission
19 * notice appear in supporting documentation, and that the name of the
20 * authors not be used in advertising or publicity pertaining to
21 * distribution of the software without specific, written prior
22 * permission.
23 *
24 * THE AUTHORS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
25 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
26 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
27 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
28 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
29 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
30 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
31 *
32 */
33
34/* Licensed to PSF under a Contributor Agreement. */
35/* See http://www.python.org/2.4/license for licensing details. */
36
37#include "Python.h"
38#include "structmember.h"
39
40#define WINDOWS_LEAN_AND_MEAN
41#include "windows.h"
42#include <crtdbg.h>
Tim Golden0321cf22014-05-05 19:46:17 +010043#include "winreparse.h"
Antoine Pitrou23bba4c2012-04-18 20:51:15 +020044
45#if defined(MS_WIN32) && !defined(MS_WIN64)
46#define HANDLE_TO_PYNUM(handle) \
47 PyLong_FromUnsignedLong((unsigned long) handle)
48#define PYNUM_TO_HANDLE(obj) ((HANDLE)PyLong_AsUnsignedLong(obj))
49#define F_POINTER "k"
50#define T_POINTER T_ULONG
51#else
52#define HANDLE_TO_PYNUM(handle) \
53 PyLong_FromUnsignedLongLong((unsigned long long) handle)
54#define PYNUM_TO_HANDLE(obj) ((HANDLE)PyLong_AsUnsignedLongLong(obj))
55#define F_POINTER "K"
56#define T_POINTER T_ULONGLONG
57#endif
58
59#define F_HANDLE F_POINTER
60#define F_DWORD "k"
61#define F_BOOL "i"
62#define F_UINT "I"
63
64#define T_HANDLE T_POINTER
65
Victor Stinner71765772013-06-24 23:13:24 +020066#define DWORD_MAX 4294967295U
67
Antoine Pitrou23bba4c2012-04-18 20:51:15 +020068/* Grab CancelIoEx dynamically from kernel32 */
69static int has_CancelIoEx = -1;
70static BOOL (CALLBACK *Py_CancelIoEx)(HANDLE, LPOVERLAPPED);
71
72static int
73check_CancelIoEx()
74{
75 if (has_CancelIoEx == -1)
76 {
77 HINSTANCE hKernel32 = GetModuleHandle("KERNEL32");
78 * (FARPROC *) &Py_CancelIoEx = GetProcAddress(hKernel32,
79 "CancelIoEx");
80 has_CancelIoEx = (Py_CancelIoEx != NULL);
81 }
82 return has_CancelIoEx;
83}
84
85
86/*
87 * A Python object wrapping an OVERLAPPED structure and other useful data
88 * for overlapped I/O
89 */
90
91typedef struct {
92 PyObject_HEAD
93 OVERLAPPED overlapped;
94 /* For convenience, we store the file handle too */
95 HANDLE handle;
96 /* Whether there's I/O in flight */
97 int pending;
98 /* Whether I/O completed successfully */
99 int completed;
100 /* Buffer used for reading (optional) */
101 PyObject *read_buffer;
102 /* Buffer used for writing (optional) */
103 Py_buffer write_buffer;
104} OverlappedObject;
105
106static void
107overlapped_dealloc(OverlappedObject *self)
108{
109 DWORD bytes;
110 int err = GetLastError();
Richard Oudkerk633db6f2013-11-17 13:15:51 +0000111
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200112 if (self->pending) {
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200113 if (check_CancelIoEx() &&
Richard Oudkerk633db6f2013-11-17 13:15:51 +0000114 Py_CancelIoEx(self->handle, &self->overlapped) &&
115 GetOverlappedResult(self->handle, &self->overlapped, &bytes, TRUE))
116 {
117 /* The operation is no longer pending -- nothing to do. */
118 }
119 else if (_Py_Finalizing == NULL)
120 {
121 /* The operation is still pending -- give a warning. This
122 will probably only happen on Windows XP. */
123 PyErr_SetString(PyExc_RuntimeError,
124 "I/O operations still in flight while destroying "
125 "Overlapped object, the process may crash");
126 PyErr_WriteUnraisable(NULL);
127 }
128 else
129 {
130 /* The operation is still pending, but the process is
131 probably about to exit, so we need not worry too much
132 about memory leaks. Leaking self prevents a potential
133 crash. This can happen when a daemon thread is cleaned
134 up at exit -- see #19565. We only expect to get here
135 on Windows XP. */
136 CloseHandle(self->overlapped.hEvent);
137 SetLastError(err);
138 return;
139 }
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200140 }
Richard Oudkerk633db6f2013-11-17 13:15:51 +0000141
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200142 CloseHandle(self->overlapped.hEvent);
143 SetLastError(err);
144 if (self->write_buffer.obj)
145 PyBuffer_Release(&self->write_buffer);
146 Py_CLEAR(self->read_buffer);
147 PyObject_Del(self);
148}
149
150static PyObject *
151overlapped_GetOverlappedResult(OverlappedObject *self, PyObject *waitobj)
152{
153 int wait;
154 BOOL res;
155 DWORD transferred = 0;
156 DWORD err;
157
158 wait = PyObject_IsTrue(waitobj);
159 if (wait < 0)
160 return NULL;
161 Py_BEGIN_ALLOW_THREADS
162 res = GetOverlappedResult(self->handle, &self->overlapped, &transferred,
163 wait != 0);
164 Py_END_ALLOW_THREADS
165
166 err = res ? ERROR_SUCCESS : GetLastError();
167 switch (err) {
168 case ERROR_SUCCESS:
169 case ERROR_MORE_DATA:
170 case ERROR_OPERATION_ABORTED:
171 self->completed = 1;
172 self->pending = 0;
173 break;
174 case ERROR_IO_INCOMPLETE:
175 break;
176 default:
177 self->pending = 0;
178 return PyErr_SetExcFromWindowsErr(PyExc_IOError, err);
179 }
180 if (self->completed && self->read_buffer != NULL) {
181 assert(PyBytes_CheckExact(self->read_buffer));
182 if (transferred != PyBytes_GET_SIZE(self->read_buffer) &&
183 _PyBytes_Resize(&self->read_buffer, transferred))
184 return NULL;
185 }
186 return Py_BuildValue("II", (unsigned) transferred, (unsigned) err);
187}
188
189static PyObject *
190overlapped_getbuffer(OverlappedObject *self)
191{
192 PyObject *res;
193 if (!self->completed) {
194 PyErr_SetString(PyExc_ValueError,
195 "can't get read buffer before GetOverlappedResult() "
196 "signals the operation completed");
197 return NULL;
198 }
199 res = self->read_buffer ? self->read_buffer : Py_None;
200 Py_INCREF(res);
201 return res;
202}
203
204static PyObject *
205overlapped_cancel(OverlappedObject *self)
206{
207 BOOL res = TRUE;
208
209 if (self->pending) {
210 Py_BEGIN_ALLOW_THREADS
211 if (check_CancelIoEx())
212 res = Py_CancelIoEx(self->handle, &self->overlapped);
213 else
214 res = CancelIo(self->handle);
215 Py_END_ALLOW_THREADS
216 }
217
218 /* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */
219 if (!res && GetLastError() != ERROR_NOT_FOUND)
220 return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
221 self->pending = 0;
222 Py_RETURN_NONE;
223}
224
225static PyMethodDef overlapped_methods[] = {
226 {"GetOverlappedResult", (PyCFunction) overlapped_GetOverlappedResult,
227 METH_O, NULL},
228 {"getbuffer", (PyCFunction) overlapped_getbuffer, METH_NOARGS, NULL},
229 {"cancel", (PyCFunction) overlapped_cancel, METH_NOARGS, NULL},
230 {NULL}
231};
232
233static PyMemberDef overlapped_members[] = {
234 {"event", T_HANDLE,
235 offsetof(OverlappedObject, overlapped) + offsetof(OVERLAPPED, hEvent),
236 READONLY, "overlapped event handle"},
237 {NULL}
238};
239
240PyTypeObject OverlappedType = {
241 PyVarObject_HEAD_INIT(NULL, 0)
242 /* tp_name */ "_winapi.Overlapped",
243 /* tp_basicsize */ sizeof(OverlappedObject),
244 /* tp_itemsize */ 0,
245 /* tp_dealloc */ (destructor) overlapped_dealloc,
246 /* tp_print */ 0,
247 /* tp_getattr */ 0,
248 /* tp_setattr */ 0,
249 /* tp_reserved */ 0,
250 /* tp_repr */ 0,
251 /* tp_as_number */ 0,
252 /* tp_as_sequence */ 0,
253 /* tp_as_mapping */ 0,
254 /* tp_hash */ 0,
255 /* tp_call */ 0,
256 /* tp_str */ 0,
257 /* tp_getattro */ 0,
258 /* tp_setattro */ 0,
259 /* tp_as_buffer */ 0,
260 /* tp_flags */ Py_TPFLAGS_DEFAULT,
261 /* tp_doc */ "OVERLAPPED structure wrapper",
262 /* tp_traverse */ 0,
263 /* tp_clear */ 0,
264 /* tp_richcompare */ 0,
265 /* tp_weaklistoffset */ 0,
266 /* tp_iter */ 0,
267 /* tp_iternext */ 0,
268 /* tp_methods */ overlapped_methods,
269 /* tp_members */ overlapped_members,
270 /* tp_getset */ 0,
271 /* tp_base */ 0,
272 /* tp_dict */ 0,
273 /* tp_descr_get */ 0,
274 /* tp_descr_set */ 0,
275 /* tp_dictoffset */ 0,
276 /* tp_init */ 0,
277 /* tp_alloc */ 0,
278 /* tp_new */ 0,
279};
280
281static OverlappedObject *
282new_overlapped(HANDLE handle)
283{
284 OverlappedObject *self;
285
286 self = PyObject_New(OverlappedObject, &OverlappedType);
287 if (!self)
288 return NULL;
289 self->handle = handle;
290 self->read_buffer = NULL;
291 self->pending = 0;
292 self->completed = 0;
293 memset(&self->overlapped, 0, sizeof(OVERLAPPED));
294 memset(&self->write_buffer, 0, sizeof(Py_buffer));
295 /* Manual reset, initially non-signalled */
296 self->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
297 return self;
298}
299
300/* -------------------------------------------------------------------- */
301/* windows API functions */
302
303PyDoc_STRVAR(CloseHandle_doc,
304"CloseHandle(handle) -> None\n\
305\n\
306Close handle.");
307
308static PyObject *
309winapi_CloseHandle(PyObject *self, PyObject *args)
310{
311 HANDLE hObject;
312 BOOL success;
313
314 if (!PyArg_ParseTuple(args, F_HANDLE ":CloseHandle", &hObject))
315 return NULL;
316
317 Py_BEGIN_ALLOW_THREADS
318 success = CloseHandle(hObject);
319 Py_END_ALLOW_THREADS
320
321 if (!success)
322 return PyErr_SetFromWindowsErr(0);
323
324 Py_RETURN_NONE;
325}
326
327static PyObject *
328winapi_ConnectNamedPipe(PyObject *self, PyObject *args, PyObject *kwds)
329{
330 HANDLE hNamedPipe;
331 int use_overlapped = 0;
332 BOOL success;
333 OverlappedObject *overlapped = NULL;
334 static char *kwlist[] = {"handle", "overlapped", NULL};
335
336 if (!PyArg_ParseTupleAndKeywords(args, kwds,
337 F_HANDLE "|" F_BOOL, kwlist,
338 &hNamedPipe, &use_overlapped))
339 return NULL;
340
341 if (use_overlapped) {
342 overlapped = new_overlapped(hNamedPipe);
343 if (!overlapped)
344 return NULL;
345 }
346
347 Py_BEGIN_ALLOW_THREADS
348 success = ConnectNamedPipe(hNamedPipe,
349 overlapped ? &overlapped->overlapped : NULL);
350 Py_END_ALLOW_THREADS
351
352 if (overlapped) {
353 int err = GetLastError();
354 /* Overlapped ConnectNamedPipe never returns a success code */
355 assert(success == 0);
356 if (err == ERROR_IO_PENDING)
357 overlapped->pending = 1;
358 else if (err == ERROR_PIPE_CONNECTED)
359 SetEvent(overlapped->overlapped.hEvent);
360 else {
361 Py_DECREF(overlapped);
362 return PyErr_SetFromWindowsErr(err);
363 }
364 return (PyObject *) overlapped;
365 }
366 if (!success)
367 return PyErr_SetFromWindowsErr(0);
368
369 Py_RETURN_NONE;
370}
371
372static PyObject *
373winapi_CreateFile(PyObject *self, PyObject *args)
374{
375 LPCTSTR lpFileName;
376 DWORD dwDesiredAccess;
377 DWORD dwShareMode;
378 LPSECURITY_ATTRIBUTES lpSecurityAttributes;
379 DWORD dwCreationDisposition;
380 DWORD dwFlagsAndAttributes;
381 HANDLE hTemplateFile;
382 HANDLE handle;
383
384 if (!PyArg_ParseTuple(args, "s" F_DWORD F_DWORD F_POINTER
385 F_DWORD F_DWORD F_HANDLE,
386 &lpFileName, &dwDesiredAccess, &dwShareMode,
387 &lpSecurityAttributes, &dwCreationDisposition,
388 &dwFlagsAndAttributes, &hTemplateFile))
389 return NULL;
390
391 Py_BEGIN_ALLOW_THREADS
392 handle = CreateFile(lpFileName, dwDesiredAccess,
393 dwShareMode, lpSecurityAttributes,
394 dwCreationDisposition,
395 dwFlagsAndAttributes, hTemplateFile);
396 Py_END_ALLOW_THREADS
397
398 if (handle == INVALID_HANDLE_VALUE)
399 return PyErr_SetFromWindowsErr(0);
400
401 return Py_BuildValue(F_HANDLE, handle);
402}
403
404static PyObject *
Tim Golden0321cf22014-05-05 19:46:17 +0100405winapi_CreateJunction(PyObject *self, PyObject *args)
406{
407 /* Input arguments */
408 LPWSTR src_path = NULL;
409 LPWSTR dst_path = NULL;
410
411 /* Privilege adjustment */
412 HANDLE token = NULL;
413 TOKEN_PRIVILEGES tp;
414
415 /* Reparse data buffer */
416 const USHORT prefix_len = 4;
417 USHORT print_len = 0;
418 USHORT rdb_size = 0;
419 PREPARSE_DATA_BUFFER rdb = NULL;
420
421 /* Junction point creation */
422 HANDLE junction = NULL;
423 DWORD ret = 0;
424
425 if (!PyArg_ParseTuple(args, "uu", &src_path, &dst_path))
426 return NULL;
427
428 if (src_path == NULL || dst_path == NULL)
429 return PyErr_SetFromWindowsErr(ERROR_INVALID_PARAMETER);
430
431 if (wcsncmp(src_path, L"\\??\\", prefix_len) == 0)
432 return PyErr_SetFromWindowsErr(ERROR_INVALID_PARAMETER);
433
434 /* Adjust privileges to allow rewriting directory entry as a
435 junction point. */
436 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token))
437 goto cleanup;
438
439 if (!LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &tp.Privileges[0].Luid))
440 goto cleanup;
441
442 tp.PrivilegeCount = 1;
443 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
444 if (!AdjustTokenPrivileges(token, FALSE, &tp, sizeof(TOKEN_PRIVILEGES),
445 NULL, NULL))
446 goto cleanup;
447
448 if (GetFileAttributesW(src_path) == INVALID_FILE_ATTRIBUTES)
449 goto cleanup;
450
451 /* Store the absolute link target path length in print_len. */
452 print_len = (USHORT)GetFullPathNameW(src_path, 0, NULL, NULL);
453 if (print_len == 0)
454 goto cleanup;
455
456 /* NUL terminator should not be part of print_len. */
457 --print_len;
458
459 /* REPARSE_DATA_BUFFER usage is heavily under-documented, especially for
460 junction points. Here's what I've learned along the way:
461 - A junction point has two components: a print name and a substitute
462 name. They both describe the link target, but the substitute name is
463 the physical target and the print name is shown in directory listings.
464 - The print name must be a native name, prefixed with "\??\".
465 - Both names are stored after each other in the same buffer (the
466 PathBuffer) and both must be NUL-terminated.
467 - There are four members defining their respective offset and length
468 inside PathBuffer: SubstituteNameOffset, SubstituteNameLength,
469 PrintNameOffset and PrintNameLength.
470 - The total size we need to allocate for the REPARSE_DATA_BUFFER, thus,
471 is the sum of:
472 - the fixed header size (REPARSE_DATA_BUFFER_HEADER_SIZE)
473 - the size of the MountPointReparseBuffer member without the PathBuffer
474 - the size of the prefix ("\??\") in bytes
475 - the size of the print name in bytes
476 - the size of the substitute name in bytes
477 - the size of two NUL terminators in bytes */
478 rdb_size = REPARSE_DATA_BUFFER_HEADER_SIZE +
479 sizeof(rdb->MountPointReparseBuffer) -
480 sizeof(rdb->MountPointReparseBuffer.PathBuffer) +
481 /* Two +1's for NUL terminators. */
482 (prefix_len + print_len + 1 + print_len + 1) * sizeof(WCHAR);
483 rdb = (PREPARSE_DATA_BUFFER)PyMem_RawMalloc(rdb_size);
484 if (rdb == NULL)
485 goto cleanup;
486
487 memset(rdb, 0, rdb_size);
488 rdb->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
489 rdb->ReparseDataLength = rdb_size - REPARSE_DATA_BUFFER_HEADER_SIZE;
490 rdb->MountPointReparseBuffer.SubstituteNameOffset = 0;
491 rdb->MountPointReparseBuffer.SubstituteNameLength =
492 (prefix_len + print_len) * sizeof(WCHAR);
493 rdb->MountPointReparseBuffer.PrintNameOffset =
494 rdb->MountPointReparseBuffer.SubstituteNameLength + sizeof(WCHAR);
495 rdb->MountPointReparseBuffer.PrintNameLength = print_len * sizeof(WCHAR);
496
497 /* Store the full native path of link target at the substitute name
498 offset (0). */
499 wcscpy(rdb->MountPointReparseBuffer.PathBuffer, L"\\??\\");
500 if (GetFullPathNameW(src_path, print_len + 1,
501 rdb->MountPointReparseBuffer.PathBuffer + prefix_len,
502 NULL) == 0)
503 goto cleanup;
504
505 /* Copy everything but the native prefix to the print name offset. */
506 wcscpy(rdb->MountPointReparseBuffer.PathBuffer +
507 prefix_len + print_len + 1,
508 rdb->MountPointReparseBuffer.PathBuffer + prefix_len);
509
510 /* Create a directory for the junction point. */
511 if (!CreateDirectoryW(dst_path, NULL))
512 goto cleanup;
513
514 junction = CreateFileW(dst_path, GENERIC_READ | GENERIC_WRITE, 0, NULL,
515 OPEN_EXISTING,
516 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
517 if (junction == INVALID_HANDLE_VALUE)
518 goto cleanup;
519
520 /* Make the directory entry a junction point. */
521 if (!DeviceIoControl(junction, FSCTL_SET_REPARSE_POINT, rdb, rdb_size,
522 NULL, 0, &ret, NULL))
523 goto cleanup;
524
525cleanup:
526 ret = GetLastError();
527
528 CloseHandle(token);
529 CloseHandle(junction);
530 PyMem_RawFree(rdb);
531
532 if (ret != 0)
533 return PyErr_SetFromWindowsErr(ret);
534
535 Py_RETURN_NONE;
536}
537
538static PyObject *
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200539winapi_CreateNamedPipe(PyObject *self, PyObject *args)
540{
541 LPCTSTR lpName;
542 DWORD dwOpenMode;
543 DWORD dwPipeMode;
544 DWORD nMaxInstances;
545 DWORD nOutBufferSize;
546 DWORD nInBufferSize;
547 DWORD nDefaultTimeOut;
548 LPSECURITY_ATTRIBUTES lpSecurityAttributes;
549 HANDLE handle;
550
551 if (!PyArg_ParseTuple(args, "s" F_DWORD F_DWORD F_DWORD
552 F_DWORD F_DWORD F_DWORD F_POINTER,
553 &lpName, &dwOpenMode, &dwPipeMode,
554 &nMaxInstances, &nOutBufferSize,
555 &nInBufferSize, &nDefaultTimeOut,
556 &lpSecurityAttributes))
557 return NULL;
558
559 Py_BEGIN_ALLOW_THREADS
560 handle = CreateNamedPipe(lpName, dwOpenMode, dwPipeMode,
561 nMaxInstances, nOutBufferSize,
562 nInBufferSize, nDefaultTimeOut,
563 lpSecurityAttributes);
564 Py_END_ALLOW_THREADS
565
566 if (handle == INVALID_HANDLE_VALUE)
567 return PyErr_SetFromWindowsErr(0);
568
569 return Py_BuildValue(F_HANDLE, handle);
570}
571
572PyDoc_STRVAR(CreatePipe_doc,
573"CreatePipe(pipe_attrs, size) -> (read_handle, write_handle)\n\
574\n\
575Create an anonymous pipe, and return handles to the read and\n\
576write ends of the pipe.\n\
577\n\
578pipe_attrs is ignored internally and can be None.");
579
580static PyObject *
581winapi_CreatePipe(PyObject* self, PyObject* args)
582{
583 HANDLE read_pipe;
584 HANDLE write_pipe;
585 BOOL result;
586
587 PyObject* pipe_attributes; /* ignored */
588 DWORD size;
589
590 if (! PyArg_ParseTuple(args, "O" F_DWORD ":CreatePipe",
591 &pipe_attributes, &size))
592 return NULL;
593
594 Py_BEGIN_ALLOW_THREADS
595 result = CreatePipe(&read_pipe, &write_pipe, NULL, size);
596 Py_END_ALLOW_THREADS
597
598 if (! result)
599 return PyErr_SetFromWindowsErr(GetLastError());
600
601 return Py_BuildValue(
602 "NN", HANDLE_TO_PYNUM(read_pipe), HANDLE_TO_PYNUM(write_pipe));
603}
604
605/* helpers for createprocess */
606
607static unsigned long
608getulong(PyObject* obj, char* name)
609{
610 PyObject* value;
611 unsigned long ret;
612
613 value = PyObject_GetAttrString(obj, name);
614 if (! value) {
615 PyErr_Clear(); /* FIXME: propagate error? */
616 return 0;
617 }
618 ret = PyLong_AsUnsignedLong(value);
619 Py_DECREF(value);
620 return ret;
621}
622
623static HANDLE
624gethandle(PyObject* obj, char* name)
625{
626 PyObject* value;
627 HANDLE ret;
628
629 value = PyObject_GetAttrString(obj, name);
630 if (! value) {
631 PyErr_Clear(); /* FIXME: propagate error? */
632 return NULL;
633 }
634 if (value == Py_None)
635 ret = NULL;
636 else
637 ret = PYNUM_TO_HANDLE(value);
638 Py_DECREF(value);
639 return ret;
640}
641
642static PyObject*
643getenvironment(PyObject* environment)
644{
645 Py_ssize_t i, envsize, totalsize;
646 Py_UCS4 *buffer = NULL, *p, *end;
647 PyObject *keys, *values, *res;
648
Ezio Melotti85a86292013-08-17 16:57:41 +0300649 /* convert environment dictionary to windows environment string */
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200650 if (! PyMapping_Check(environment)) {
651 PyErr_SetString(
652 PyExc_TypeError, "environment must be dictionary or None");
653 return NULL;
654 }
655
656 envsize = PyMapping_Length(environment);
657
658 keys = PyMapping_Keys(environment);
659 values = PyMapping_Values(environment);
660 if (!keys || !values)
661 goto error;
662
663 totalsize = 1; /* trailing null character */
664 for (i = 0; i < envsize; i++) {
665 PyObject* key = PyList_GET_ITEM(keys, i);
666 PyObject* value = PyList_GET_ITEM(values, i);
667
668 if (! PyUnicode_Check(key) || ! PyUnicode_Check(value)) {
669 PyErr_SetString(PyExc_TypeError,
670 "environment can only contain strings");
671 goto error;
672 }
Benjamin Peterson8ce68062015-02-09 20:58:12 -0500673 if (totalsize > PY_SSIZE_T_MAX - PyUnicode_GET_LENGTH(key) - 1) {
674 PyErr_SetString(PyExc_OverflowError, "environment too long");
675 goto error;
676 }
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200677 totalsize += PyUnicode_GET_LENGTH(key) + 1; /* +1 for '=' */
Benjamin Peterson8ce68062015-02-09 20:58:12 -0500678 if (totalsize > PY_SSIZE_T_MAX - PyUnicode_GET_LENGTH(value) - 1) {
679 PyErr_SetString(PyExc_OverflowError, "environment too long");
680 goto error;
681 }
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200682 totalsize += PyUnicode_GET_LENGTH(value) + 1; /* +1 for '\0' */
683 }
684
Benjamin Peterson8ce68062015-02-09 20:58:12 -0500685 buffer = PyMem_NEW(Py_UCS4, totalsize);
686 if (! buffer) {
687 PyErr_NoMemory();
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200688 goto error;
Benjamin Peterson8ce68062015-02-09 20:58:12 -0500689 }
Antoine Pitrou23bba4c2012-04-18 20:51:15 +0200690 p = buffer;
691 end = buffer + totalsize;
692
693 for (i = 0; i < envsize; i++) {
694 PyObject* key = PyList_GET_ITEM(keys, i);
695 PyObject* value = PyList_GET_ITEM(values, i);
696 if (!PyUnicode_AsUCS4(key, p, end - p, 0))
697 goto error;
698 p += PyUnicode_GET_LENGTH(key);
699 *p++ = '=';
700 if (!PyUnicode_AsUCS4(value, p, end - p, 0))
701 goto error;
702 p += PyUnicode_GET_LENGTH(value);
703 *p++ = '\0';
704 }
705
706 /* add trailing null byte */
707 *p++ = '\0';
708 assert(p == end);
709
710 Py_XDECREF(keys);
711 Py_XDECREF(values);
712
713 res = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buffer, p - buffer);
714 PyMem_Free(buffer);
715 return res;
716
717 error:
718 PyMem_Free(buffer);
719 Py_XDECREF(keys);
720 Py_XDECREF(values);
721 return NULL;
722}
723
724PyDoc_STRVAR(CreateProcess_doc,
725"CreateProcess(app_name, cmd_line, proc_attrs, thread_attrs,\n\
726 inherit, flags, env_mapping, curdir,\n\
727 startup_info) -> (proc_handle, thread_handle,\n\
728 pid, tid)\n\
729\n\
730Create a new process and its primary thread. The return\n\
731value is a tuple of the process handle, thread handle,\n\
732process ID, and thread ID.\n\
733\n\
734proc_attrs and thread_attrs are ignored internally and can be None.");
735
736static PyObject *
737winapi_CreateProcess(PyObject* self, PyObject* args)
738{
739 BOOL result;
740 PROCESS_INFORMATION pi;
741 STARTUPINFOW si;
742 PyObject* environment;
743 wchar_t *wenvironment;
744
745 wchar_t* application_name;
746 wchar_t* command_line;
747 PyObject* process_attributes; /* ignored */
748 PyObject* thread_attributes; /* ignored */
749 BOOL inherit_handles;
750 DWORD creation_flags;
751 PyObject* env_mapping;
752 wchar_t* current_directory;
753 PyObject* startup_info;
754
755 if (! PyArg_ParseTuple(args, "ZZOO" F_BOOL F_DWORD "OZO:CreateProcess",
756 &application_name,
757 &command_line,
758 &process_attributes,
759 &thread_attributes,
760 &inherit_handles,
761 &creation_flags,
762 &env_mapping,
763 &current_directory,
764 &startup_info))
765 return NULL;
766
767 ZeroMemory(&si, sizeof(si));
768 si.cb = sizeof(si);
769
770 /* note: we only support a small subset of all SI attributes */
771 si.dwFlags = getulong(startup_info, "dwFlags");
772 si.wShowWindow = (WORD)getulong(startup_info, "wShowWindow");
773 si.hStdInput = gethandle(startup_info, "hStdInput");
774 si.hStdOutput = gethandle(startup_info, "hStdOutput");
775 si.hStdError = gethandle(startup_info, "hStdError");
776 if (PyErr_Occurred())
777 return NULL;
778
779 if (env_mapping != Py_None) {
780 environment = getenvironment(env_mapping);
781 if (! environment)
782 return NULL;
783 wenvironment = PyUnicode_AsUnicode(environment);
784 if (wenvironment == NULL)
785 {
786 Py_XDECREF(environment);
787 return NULL;
788 }
789 }
790 else {
791 environment = NULL;
792 wenvironment = NULL;
793 }
794
795 Py_BEGIN_ALLOW_THREADS
796 result = CreateProcessW(application_name,
797 command_line,
798 NULL,
799 NULL,
800 inherit_handles,
801 creation_flags | CREATE_UNICODE_ENVIRONMENT,
802 wenvironment,
803 current_directory,
804 &si,
805 &pi);
806 Py_END_ALLOW_THREADS
807
808 Py_XDECREF(environment);
809
810 if (! result)
811 return PyErr_SetFromWindowsErr(GetLastError());
812
813 return Py_BuildValue("NNkk",
814 HANDLE_TO_PYNUM(pi.hProcess),
815 HANDLE_TO_PYNUM(pi.hThread),
816 pi.dwProcessId,
817 pi.dwThreadId);
818}
819
820PyDoc_STRVAR(DuplicateHandle_doc,
821"DuplicateHandle(source_proc_handle, source_handle,\n\
822 target_proc_handle, target_handle, access,\n\
823 inherit[, options]) -> handle\n\
824\n\
825Return a duplicate handle object.\n\
826\n\
827The duplicate handle refers to the same object as the original\n\
828handle. Therefore, any changes to the object are reflected\n\
829through both handles.");
830
831static PyObject *
832winapi_DuplicateHandle(PyObject* self, PyObject* args)
833{
834 HANDLE target_handle;
835 BOOL result;
836
837 HANDLE source_process_handle;
838 HANDLE source_handle;
839 HANDLE target_process_handle;
840 DWORD desired_access;
841 BOOL inherit_handle;
842 DWORD options = 0;
843
844 if (! PyArg_ParseTuple(args,
845 F_HANDLE F_HANDLE F_HANDLE F_DWORD F_BOOL F_DWORD
846 ":DuplicateHandle",
847 &source_process_handle,
848 &source_handle,
849 &target_process_handle,
850 &desired_access,
851 &inherit_handle,
852 &options))
853 return NULL;
854
855 Py_BEGIN_ALLOW_THREADS
856 result = DuplicateHandle(
857 source_process_handle,
858 source_handle,
859 target_process_handle,
860 &target_handle,
861 desired_access,
862 inherit_handle,
863 options
864 );
865 Py_END_ALLOW_THREADS
866
867 if (! result)
868 return PyErr_SetFromWindowsErr(GetLastError());
869
870 return HANDLE_TO_PYNUM(target_handle);
871}
872
873static PyObject *
874winapi_ExitProcess(PyObject *self, PyObject *args)
875{
876 UINT uExitCode;
877
878 if (!PyArg_ParseTuple(args, F_UINT, &uExitCode))
879 return NULL;
880
881 #if defined(Py_DEBUG)
882 SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOALIGNMENTFAULTEXCEPT|
883 SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX);
884 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
885 #endif
886
887 ExitProcess(uExitCode);
888
889 return NULL;
890}
891
892PyDoc_STRVAR(GetCurrentProcess_doc,
893"GetCurrentProcess() -> handle\n\
894\n\
895Return a handle object for the current process.");
896
897static PyObject *
898winapi_GetCurrentProcess(PyObject* self, PyObject* args)
899{
900 if (! PyArg_ParseTuple(args, ":GetCurrentProcess"))
901 return NULL;
902
903 return HANDLE_TO_PYNUM(GetCurrentProcess());
904}
905
906PyDoc_STRVAR(GetExitCodeProcess_doc,
907"GetExitCodeProcess(handle) -> Exit code\n\
908\n\
909Return the termination status of the specified process.");
910
911static PyObject *
912winapi_GetExitCodeProcess(PyObject* self, PyObject* args)
913{
914 DWORD exit_code;
915 BOOL result;
916
917 HANDLE process;
918 if (! PyArg_ParseTuple(args, F_HANDLE ":GetExitCodeProcess", &process))
919 return NULL;
920
921 result = GetExitCodeProcess(process, &exit_code);
922
923 if (! result)
924 return PyErr_SetFromWindowsErr(GetLastError());
925
926 return PyLong_FromUnsignedLong(exit_code);
927}
928
929static PyObject *
930winapi_GetLastError(PyObject *self, PyObject *args)
931{
932 return Py_BuildValue(F_DWORD, GetLastError());
933}
934
935PyDoc_STRVAR(GetModuleFileName_doc,
936"GetModuleFileName(module) -> path\n\
937\n\
938Return the fully-qualified path for the file that contains\n\
939the specified module. The module must have been loaded by the\n\
940current process.\n\
941\n\
942The module parameter should be a handle to the loaded module\n\
943whose path is being requested. If this parameter is 0, \n\
944GetModuleFileName retrieves the path of the executable file\n\
945of the current process.");
946
947static PyObject *
948winapi_GetModuleFileName(PyObject* self, PyObject* args)
949{
950 BOOL result;
951 HMODULE module;
952 WCHAR filename[MAX_PATH];
953
954 if (! PyArg_ParseTuple(args, F_HANDLE ":GetModuleFileName",
955 &module))
956 return NULL;
957
958 result = GetModuleFileNameW(module, filename, MAX_PATH);
959 filename[MAX_PATH-1] = '\0';
960
961 if (! result)
962 return PyErr_SetFromWindowsErr(GetLastError());
963
964 return PyUnicode_FromWideChar(filename, wcslen(filename));
965}
966
967PyDoc_STRVAR(GetStdHandle_doc,
968"GetStdHandle(handle) -> integer\n\
969\n\
970Return a handle to the specified standard device\n\
971(STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE).\n\
972The integer associated with the handle object is returned.");
973
974static PyObject *
975winapi_GetStdHandle(PyObject* self, PyObject* args)
976{
977 HANDLE handle;
978 DWORD std_handle;
979
980 if (! PyArg_ParseTuple(args, F_DWORD ":GetStdHandle", &std_handle))
981 return NULL;
982
983 Py_BEGIN_ALLOW_THREADS
984 handle = GetStdHandle(std_handle);
985 Py_END_ALLOW_THREADS
986
987 if (handle == INVALID_HANDLE_VALUE)
988 return PyErr_SetFromWindowsErr(GetLastError());
989
990 if (! handle) {
991 Py_INCREF(Py_None);
992 return Py_None;
993 }
994
995 /* note: returns integer, not handle object */
996 return HANDLE_TO_PYNUM(handle);
997}
998
999PyDoc_STRVAR(GetVersion_doc,
1000"GetVersion() -> version\n\
1001\n\
1002Return the version number of the current operating system.");
1003
Steve Dower3e96f322015-03-02 08:01:10 -08001004/* Disable deprecation warnings about GetVersionEx as the result is
1005 being passed straight through to the caller, who is responsible for
1006 using it correctly. */
1007#pragma warning(push)
1008#pragma warning(disable:4996)
1009
Antoine Pitrou23bba4c2012-04-18 20:51:15 +02001010static PyObject *
1011winapi_GetVersion(PyObject* self, PyObject* args)
1012{
1013 if (! PyArg_ParseTuple(args, ":GetVersion"))
1014 return NULL;
1015
1016 return PyLong_FromUnsignedLong(GetVersion());
1017}
1018
Steve Dower3e96f322015-03-02 08:01:10 -08001019#pragma warning(pop)
1020
Antoine Pitrou23bba4c2012-04-18 20:51:15 +02001021static PyObject *
1022winapi_OpenProcess(PyObject *self, PyObject *args)
1023{
1024 DWORD dwDesiredAccess;
1025 BOOL bInheritHandle;
1026 DWORD dwProcessId;
1027 HANDLE handle;
1028
1029 if (!PyArg_ParseTuple(args, F_DWORD F_BOOL F_DWORD,
1030 &dwDesiredAccess, &bInheritHandle, &dwProcessId))
1031 return NULL;
1032
1033 handle = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
1034 if (handle == NULL)
1035 return PyErr_SetFromWindowsErr(0);
1036
1037 return Py_BuildValue(F_HANDLE, handle);
1038}
1039
1040static PyObject *
1041winapi_PeekNamedPipe(PyObject *self, PyObject *args)
1042{
1043 HANDLE handle;
1044 int size = 0;
1045 PyObject *buf = NULL;
1046 DWORD nread, navail, nleft;
1047 BOOL ret;
1048
1049 if (!PyArg_ParseTuple(args, F_HANDLE "|i:PeekNamedPipe" , &handle, &size))
1050 return NULL;
1051
1052 if (size < 0) {
1053 PyErr_SetString(PyExc_ValueError, "negative size");
1054 return NULL;
1055 }
1056
1057 if (size) {
1058 buf = PyBytes_FromStringAndSize(NULL, size);
1059 if (!buf)
1060 return NULL;
1061 Py_BEGIN_ALLOW_THREADS
1062 ret = PeekNamedPipe(handle, PyBytes_AS_STRING(buf), size, &nread,
1063 &navail, &nleft);
1064 Py_END_ALLOW_THREADS
1065 if (!ret) {
1066 Py_DECREF(buf);
1067 return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
1068 }
1069 if (_PyBytes_Resize(&buf, nread))
1070 return NULL;
1071 return Py_BuildValue("Nii", buf, navail, nleft);
1072 }
1073 else {
1074 Py_BEGIN_ALLOW_THREADS
1075 ret = PeekNamedPipe(handle, NULL, 0, NULL, &navail, &nleft);
1076 Py_END_ALLOW_THREADS
1077 if (!ret) {
1078 return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
1079 }
1080 return Py_BuildValue("ii", navail, nleft);
1081 }
1082}
1083
1084static PyObject *
1085winapi_ReadFile(PyObject *self, PyObject *args, PyObject *kwds)
1086{
1087 HANDLE handle;
1088 int size;
1089 DWORD nread;
1090 PyObject *buf;
1091 BOOL ret;
1092 int use_overlapped = 0;
1093 DWORD err;
1094 OverlappedObject *overlapped = NULL;
1095 static char *kwlist[] = {"handle", "size", "overlapped", NULL};
1096
1097 if (!PyArg_ParseTupleAndKeywords(args, kwds,
1098 F_HANDLE "i|i:ReadFile", kwlist,
1099 &handle, &size, &use_overlapped))
1100 return NULL;
1101
1102 buf = PyBytes_FromStringAndSize(NULL, size);
1103 if (!buf)
1104 return NULL;
1105 if (use_overlapped) {
1106 overlapped = new_overlapped(handle);
1107 if (!overlapped) {
1108 Py_DECREF(buf);
1109 return NULL;
1110 }
1111 /* Steals reference to buf */
1112 overlapped->read_buffer = buf;
1113 }
1114
1115 Py_BEGIN_ALLOW_THREADS
1116 ret = ReadFile(handle, PyBytes_AS_STRING(buf), size, &nread,
1117 overlapped ? &overlapped->overlapped : NULL);
1118 Py_END_ALLOW_THREADS
1119
1120 err = ret ? 0 : GetLastError();
1121
1122 if (overlapped) {
1123 if (!ret) {
1124 if (err == ERROR_IO_PENDING)
1125 overlapped->pending = 1;
1126 else if (err != ERROR_MORE_DATA) {
1127 Py_DECREF(overlapped);
1128 return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
1129 }
1130 }
1131 return Py_BuildValue("NI", (PyObject *) overlapped, err);
1132 }
1133
1134 if (!ret && err != ERROR_MORE_DATA) {
1135 Py_DECREF(buf);
1136 return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
1137 }
1138 if (_PyBytes_Resize(&buf, nread))
1139 return NULL;
1140 return Py_BuildValue("NI", buf, err);
1141}
1142
1143static PyObject *
1144winapi_SetNamedPipeHandleState(PyObject *self, PyObject *args)
1145{
1146 HANDLE hNamedPipe;
1147 PyObject *oArgs[3];
1148 DWORD dwArgs[3], *pArgs[3] = {NULL, NULL, NULL};
1149 int i;
1150
1151 if (!PyArg_ParseTuple(args, F_HANDLE "OOO",
1152 &hNamedPipe, &oArgs[0], &oArgs[1], &oArgs[2]))
1153 return NULL;
1154
1155 PyErr_Clear();
1156
1157 for (i = 0 ; i < 3 ; i++) {
1158 if (oArgs[i] != Py_None) {
1159 dwArgs[i] = PyLong_AsUnsignedLongMask(oArgs[i]);
1160 if (PyErr_Occurred())
1161 return NULL;
1162 pArgs[i] = &dwArgs[i];
1163 }
1164 }
1165
1166 if (!SetNamedPipeHandleState(hNamedPipe, pArgs[0], pArgs[1], pArgs[2]))
1167 return PyErr_SetFromWindowsErr(0);
1168
1169 Py_RETURN_NONE;
1170}
1171
1172PyDoc_STRVAR(TerminateProcess_doc,
1173"TerminateProcess(handle, exit_code) -> None\n\
1174\n\
1175Terminate the specified process and all of its threads.");
1176
1177static PyObject *
1178winapi_TerminateProcess(PyObject* self, PyObject* args)
1179{
1180 BOOL result;
1181
1182 HANDLE process;
1183 UINT exit_code;
1184 if (! PyArg_ParseTuple(args, F_HANDLE F_UINT ":TerminateProcess",
1185 &process, &exit_code))
1186 return NULL;
1187
1188 result = TerminateProcess(process, exit_code);
1189
1190 if (! result)
1191 return PyErr_SetFromWindowsErr(GetLastError());
1192
1193 Py_INCREF(Py_None);
1194 return Py_None;
1195}
1196
1197static PyObject *
1198winapi_WaitNamedPipe(PyObject *self, PyObject *args)
1199{
1200 LPCTSTR lpNamedPipeName;
1201 DWORD nTimeOut;
1202 BOOL success;
1203
1204 if (!PyArg_ParseTuple(args, "s" F_DWORD, &lpNamedPipeName, &nTimeOut))
1205 return NULL;
1206
1207 Py_BEGIN_ALLOW_THREADS
1208 success = WaitNamedPipe(lpNamedPipeName, nTimeOut);
1209 Py_END_ALLOW_THREADS
1210
1211 if (!success)
1212 return PyErr_SetFromWindowsErr(0);
1213
1214 Py_RETURN_NONE;
1215}
1216
1217static PyObject *
1218winapi_WaitForMultipleObjects(PyObject* self, PyObject* args)
1219{
1220 DWORD result;
1221 PyObject *handle_seq;
1222 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1223 HANDLE sigint_event = NULL;
1224 Py_ssize_t nhandles, i;
1225 BOOL wait_flag;
1226 DWORD milliseconds = INFINITE;
1227
1228 if (!PyArg_ParseTuple(args, "O" F_BOOL "|" F_DWORD
1229 ":WaitForMultipleObjects",
1230 &handle_seq, &wait_flag, &milliseconds))
1231 return NULL;
1232
1233 if (!PySequence_Check(handle_seq)) {
1234 PyErr_Format(PyExc_TypeError,
1235 "sequence type expected, got '%s'",
Richard Oudkerk67339272012-08-21 14:54:22 +01001236 Py_TYPE(handle_seq)->tp_name);
Antoine Pitrou23bba4c2012-04-18 20:51:15 +02001237 return NULL;
1238 }
1239 nhandles = PySequence_Length(handle_seq);
1240 if (nhandles == -1)
1241 return NULL;
1242 if (nhandles < 0 || nhandles >= MAXIMUM_WAIT_OBJECTS - 1) {
1243 PyErr_Format(PyExc_ValueError,
1244 "need at most %zd handles, got a sequence of length %zd",
1245 MAXIMUM_WAIT_OBJECTS - 1, nhandles);
1246 return NULL;
1247 }
1248 for (i = 0; i < nhandles; i++) {
1249 HANDLE h;
1250 PyObject *v = PySequence_GetItem(handle_seq, i);
1251 if (v == NULL)
1252 return NULL;
1253 if (!PyArg_Parse(v, F_HANDLE, &h)) {
1254 Py_DECREF(v);
1255 return NULL;
1256 }
1257 handles[i] = h;
1258 Py_DECREF(v);
1259 }
1260 /* If this is the main thread then make the wait interruptible
1261 by Ctrl-C unless we are waiting for *all* handles */
1262 if (!wait_flag && _PyOS_IsMainThread()) {
1263 sigint_event = _PyOS_SigintEvent();
1264 assert(sigint_event != NULL);
1265 handles[nhandles++] = sigint_event;
1266 }
1267
1268 Py_BEGIN_ALLOW_THREADS
1269 if (sigint_event != NULL)
1270 ResetEvent(sigint_event);
1271 result = WaitForMultipleObjects((DWORD) nhandles, handles,
1272 wait_flag, milliseconds);
1273 Py_END_ALLOW_THREADS
1274
1275 if (result == WAIT_FAILED)
1276 return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
1277 else if (sigint_event != NULL && result == WAIT_OBJECT_0 + nhandles - 1) {
1278 errno = EINTR;
1279 return PyErr_SetFromErrno(PyExc_IOError);
1280 }
1281
1282 return PyLong_FromLong((int) result);
1283}
1284
1285PyDoc_STRVAR(WaitForSingleObject_doc,
1286"WaitForSingleObject(handle, timeout) -> result\n\
1287\n\
1288Wait until the specified object is in the signaled state or\n\
1289the time-out interval elapses. The timeout value is specified\n\
1290in milliseconds.");
1291
1292static PyObject *
1293winapi_WaitForSingleObject(PyObject* self, PyObject* args)
1294{
1295 DWORD result;
1296
1297 HANDLE handle;
1298 DWORD milliseconds;
1299 if (! PyArg_ParseTuple(args, F_HANDLE F_DWORD ":WaitForSingleObject",
1300 &handle,
1301 &milliseconds))
1302 return NULL;
1303
1304 Py_BEGIN_ALLOW_THREADS
1305 result = WaitForSingleObject(handle, milliseconds);
1306 Py_END_ALLOW_THREADS
1307
1308 if (result == WAIT_FAILED)
1309 return PyErr_SetFromWindowsErr(GetLastError());
1310
1311 return PyLong_FromUnsignedLong(result);
1312}
1313
1314static PyObject *
1315winapi_WriteFile(PyObject *self, PyObject *args, PyObject *kwds)
1316{
1317 HANDLE handle;
1318 Py_buffer _buf, *buf;
1319 PyObject *bufobj;
Victor Stinner71765772013-06-24 23:13:24 +02001320 DWORD len, written;
Antoine Pitrou23bba4c2012-04-18 20:51:15 +02001321 BOOL ret;
1322 int use_overlapped = 0;
1323 DWORD err;
1324 OverlappedObject *overlapped = NULL;
1325 static char *kwlist[] = {"handle", "buffer", "overlapped", NULL};
1326
1327 /* First get handle and use_overlapped to know which Py_buffer to use */
1328 if (!PyArg_ParseTupleAndKeywords(args, kwds,
1329 F_HANDLE "O|i:WriteFile", kwlist,
1330 &handle, &bufobj, &use_overlapped))
1331 return NULL;
1332
1333 if (use_overlapped) {
1334 overlapped = new_overlapped(handle);
1335 if (!overlapped)
1336 return NULL;
1337 buf = &overlapped->write_buffer;
1338 }
1339 else
1340 buf = &_buf;
1341
1342 if (!PyArg_Parse(bufobj, "y*", buf)) {
1343 Py_XDECREF(overlapped);
1344 return NULL;
1345 }
1346
1347 Py_BEGIN_ALLOW_THREADS
Victor Stinner71765772013-06-24 23:13:24 +02001348 len = (DWORD)Py_MIN(buf->len, DWORD_MAX);
1349 ret = WriteFile(handle, buf->buf, len, &written,
Antoine Pitrou23bba4c2012-04-18 20:51:15 +02001350 overlapped ? &overlapped->overlapped : NULL);
1351 Py_END_ALLOW_THREADS
1352
1353 err = ret ? 0 : GetLastError();
1354
1355 if (overlapped) {
1356 if (!ret) {
1357 if (err == ERROR_IO_PENDING)
1358 overlapped->pending = 1;
1359 else {
1360 Py_DECREF(overlapped);
1361 return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
1362 }
1363 }
1364 return Py_BuildValue("NI", (PyObject *) overlapped, err);
1365 }
1366
1367 PyBuffer_Release(buf);
1368 if (!ret)
1369 return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
1370 return Py_BuildValue("II", written, err);
1371}
1372
1373
1374static PyMethodDef winapi_functions[] = {
1375 {"CloseHandle", winapi_CloseHandle, METH_VARARGS,
1376 CloseHandle_doc},
1377 {"ConnectNamedPipe", (PyCFunction)winapi_ConnectNamedPipe,
1378 METH_VARARGS | METH_KEYWORDS, ""},
1379 {"CreateFile", winapi_CreateFile, METH_VARARGS,
1380 ""},
Tim Golden0321cf22014-05-05 19:46:17 +01001381 {"CreateJunction", winapi_CreateJunction, METH_VARARGS,
1382 ""},
Antoine Pitrou23bba4c2012-04-18 20:51:15 +02001383 {"CreateNamedPipe", winapi_CreateNamedPipe, METH_VARARGS,
1384 ""},
1385 {"CreatePipe", winapi_CreatePipe, METH_VARARGS,
1386 CreatePipe_doc},
1387 {"CreateProcess", winapi_CreateProcess, METH_VARARGS,
1388 CreateProcess_doc},
1389 {"DuplicateHandle", winapi_DuplicateHandle, METH_VARARGS,
1390 DuplicateHandle_doc},
1391 {"ExitProcess", winapi_ExitProcess, METH_VARARGS,
1392 ""},
1393 {"GetCurrentProcess", winapi_GetCurrentProcess, METH_VARARGS,
1394 GetCurrentProcess_doc},
1395 {"GetExitCodeProcess", winapi_GetExitCodeProcess, METH_VARARGS,
1396 GetExitCodeProcess_doc},
1397 {"GetLastError", winapi_GetLastError, METH_NOARGS,
1398 GetCurrentProcess_doc},
1399 {"GetModuleFileName", winapi_GetModuleFileName, METH_VARARGS,
1400 GetModuleFileName_doc},
1401 {"GetStdHandle", winapi_GetStdHandle, METH_VARARGS,
1402 GetStdHandle_doc},
1403 {"GetVersion", winapi_GetVersion, METH_VARARGS,
1404 GetVersion_doc},
1405 {"OpenProcess", winapi_OpenProcess, METH_VARARGS,
1406 ""},
1407 {"PeekNamedPipe", winapi_PeekNamedPipe, METH_VARARGS,
1408 ""},
1409 {"ReadFile", (PyCFunction)winapi_ReadFile, METH_VARARGS | METH_KEYWORDS,
1410 ""},
1411 {"SetNamedPipeHandleState", winapi_SetNamedPipeHandleState, METH_VARARGS,
1412 ""},
1413 {"TerminateProcess", winapi_TerminateProcess, METH_VARARGS,
1414 TerminateProcess_doc},
1415 {"WaitNamedPipe", winapi_WaitNamedPipe, METH_VARARGS,
1416 ""},
1417 {"WaitForMultipleObjects", winapi_WaitForMultipleObjects, METH_VARARGS,
1418 ""},
1419 {"WaitForSingleObject", winapi_WaitForSingleObject, METH_VARARGS,
1420 WaitForSingleObject_doc},
1421 {"WriteFile", (PyCFunction)winapi_WriteFile, METH_VARARGS | METH_KEYWORDS,
1422 ""},
1423 {NULL, NULL}
1424};
1425
1426static struct PyModuleDef winapi_module = {
1427 PyModuleDef_HEAD_INIT,
1428 "_winapi",
1429 NULL,
1430 -1,
1431 winapi_functions,
1432 NULL,
1433 NULL,
1434 NULL,
1435 NULL
1436};
1437
1438#define WINAPI_CONSTANT(fmt, con) \
1439 PyDict_SetItemString(d, #con, Py_BuildValue(fmt, con))
1440
1441PyMODINIT_FUNC
1442PyInit__winapi(void)
1443{
1444 PyObject *d;
1445 PyObject *m;
1446
1447 if (PyType_Ready(&OverlappedType) < 0)
1448 return NULL;
1449
1450 m = PyModule_Create(&winapi_module);
1451 if (m == NULL)
1452 return NULL;
1453 d = PyModule_GetDict(m);
1454
1455 PyDict_SetItemString(d, "Overlapped", (PyObject *) &OverlappedType);
1456
1457 /* constants */
1458 WINAPI_CONSTANT(F_DWORD, CREATE_NEW_CONSOLE);
1459 WINAPI_CONSTANT(F_DWORD, CREATE_NEW_PROCESS_GROUP);
1460 WINAPI_CONSTANT(F_DWORD, DUPLICATE_SAME_ACCESS);
Antoine Pitrou5438ed12012-04-24 22:56:57 +02001461 WINAPI_CONSTANT(F_DWORD, DUPLICATE_CLOSE_SOURCE);
Antoine Pitrou23bba4c2012-04-18 20:51:15 +02001462 WINAPI_CONSTANT(F_DWORD, ERROR_ALREADY_EXISTS);
1463 WINAPI_CONSTANT(F_DWORD, ERROR_BROKEN_PIPE);
1464 WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING);
1465 WINAPI_CONSTANT(F_DWORD, ERROR_MORE_DATA);
1466 WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
1467 WINAPI_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES);
Antoine Pitrou23bba4c2012-04-18 20:51:15 +02001468 WINAPI_CONSTANT(F_DWORD, ERROR_MORE_DATA);
1469 WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
Richard Oudkerkfdb8dcf2012-05-05 19:45:37 +01001470 WINAPI_CONSTANT(F_DWORD, ERROR_NO_DATA);
Antoine Pitrou23bba4c2012-04-18 20:51:15 +02001471 WINAPI_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES);
1472 WINAPI_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED);
1473 WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY);
1474 WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_CONNECTED);
1475 WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT);
1476 WINAPI_CONSTANT(F_DWORD, FILE_FLAG_FIRST_PIPE_INSTANCE);
1477 WINAPI_CONSTANT(F_DWORD, FILE_FLAG_OVERLAPPED);
Antoine Pitrou5438ed12012-04-24 22:56:57 +02001478 WINAPI_CONSTANT(F_DWORD, FILE_GENERIC_READ);
1479 WINAPI_CONSTANT(F_DWORD, FILE_GENERIC_WRITE);
Antoine Pitrou23bba4c2012-04-18 20:51:15 +02001480 WINAPI_CONSTANT(F_DWORD, GENERIC_READ);
1481 WINAPI_CONSTANT(F_DWORD, GENERIC_WRITE);
1482 WINAPI_CONSTANT(F_DWORD, INFINITE);
1483 WINAPI_CONSTANT(F_DWORD, NMPWAIT_WAIT_FOREVER);
1484 WINAPI_CONSTANT(F_DWORD, OPEN_EXISTING);
1485 WINAPI_CONSTANT(F_DWORD, PIPE_ACCESS_DUPLEX);
1486 WINAPI_CONSTANT(F_DWORD, PIPE_ACCESS_INBOUND);
1487 WINAPI_CONSTANT(F_DWORD, PIPE_READMODE_MESSAGE);
1488 WINAPI_CONSTANT(F_DWORD, PIPE_TYPE_MESSAGE);
1489 WINAPI_CONSTANT(F_DWORD, PIPE_UNLIMITED_INSTANCES);
1490 WINAPI_CONSTANT(F_DWORD, PIPE_WAIT);
1491 WINAPI_CONSTANT(F_DWORD, PROCESS_ALL_ACCESS);
Antoine Pitrou5438ed12012-04-24 22:56:57 +02001492 WINAPI_CONSTANT(F_DWORD, PROCESS_DUP_HANDLE);
Antoine Pitrou23bba4c2012-04-18 20:51:15 +02001493 WINAPI_CONSTANT(F_DWORD, STARTF_USESHOWWINDOW);
1494 WINAPI_CONSTANT(F_DWORD, STARTF_USESTDHANDLES);
1495 WINAPI_CONSTANT(F_DWORD, STD_INPUT_HANDLE);
1496 WINAPI_CONSTANT(F_DWORD, STD_OUTPUT_HANDLE);
1497 WINAPI_CONSTANT(F_DWORD, STD_ERROR_HANDLE);
1498 WINAPI_CONSTANT(F_DWORD, STILL_ACTIVE);
1499 WINAPI_CONSTANT(F_DWORD, SW_HIDE);
1500 WINAPI_CONSTANT(F_DWORD, WAIT_OBJECT_0);
Victor Stinner373f0a92014-03-20 09:26:55 +01001501 WINAPI_CONSTANT(F_DWORD, WAIT_ABANDONED_0);
Antoine Pitrou23bba4c2012-04-18 20:51:15 +02001502 WINAPI_CONSTANT(F_DWORD, WAIT_TIMEOUT);
1503
1504 WINAPI_CONSTANT("i", NULL);
1505
1506 return m;
1507}