blob: f118436f91523096b0e08f0cfc8dc8fa93442087 [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 }
673 totalsize += PyUnicode_GET_LENGTH(key) + 1; /* +1 for '=' */
674 totalsize += PyUnicode_GET_LENGTH(value) + 1; /* +1 for '\0' */
675 }
676
677 buffer = PyMem_Malloc(totalsize * sizeof(Py_UCS4));
678 if (! buffer)
679 goto error;
680 p = buffer;
681 end = buffer + totalsize;
682
683 for (i = 0; i < envsize; i++) {
684 PyObject* key = PyList_GET_ITEM(keys, i);
685 PyObject* value = PyList_GET_ITEM(values, i);
686 if (!PyUnicode_AsUCS4(key, p, end - p, 0))
687 goto error;
688 p += PyUnicode_GET_LENGTH(key);
689 *p++ = '=';
690 if (!PyUnicode_AsUCS4(value, p, end - p, 0))
691 goto error;
692 p += PyUnicode_GET_LENGTH(value);
693 *p++ = '\0';
694 }
695
696 /* add trailing null byte */
697 *p++ = '\0';
698 assert(p == end);
699
700 Py_XDECREF(keys);
701 Py_XDECREF(values);
702
703 res = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, buffer, p - buffer);
704 PyMem_Free(buffer);
705 return res;
706
707 error:
708 PyMem_Free(buffer);
709 Py_XDECREF(keys);
710 Py_XDECREF(values);
711 return NULL;
712}
713
714PyDoc_STRVAR(CreateProcess_doc,
715"CreateProcess(app_name, cmd_line, proc_attrs, thread_attrs,\n\
716 inherit, flags, env_mapping, curdir,\n\
717 startup_info) -> (proc_handle, thread_handle,\n\
718 pid, tid)\n\
719\n\
720Create a new process and its primary thread. The return\n\
721value is a tuple of the process handle, thread handle,\n\
722process ID, and thread ID.\n\
723\n\
724proc_attrs and thread_attrs are ignored internally and can be None.");
725
726static PyObject *
727winapi_CreateProcess(PyObject* self, PyObject* args)
728{
729 BOOL result;
730 PROCESS_INFORMATION pi;
731 STARTUPINFOW si;
732 PyObject* environment;
733 wchar_t *wenvironment;
734
735 wchar_t* application_name;
736 wchar_t* command_line;
737 PyObject* process_attributes; /* ignored */
738 PyObject* thread_attributes; /* ignored */
739 BOOL inherit_handles;
740 DWORD creation_flags;
741 PyObject* env_mapping;
742 wchar_t* current_directory;
743 PyObject* startup_info;
744
745 if (! PyArg_ParseTuple(args, "ZZOO" F_BOOL F_DWORD "OZO:CreateProcess",
746 &application_name,
747 &command_line,
748 &process_attributes,
749 &thread_attributes,
750 &inherit_handles,
751 &creation_flags,
752 &env_mapping,
753 &current_directory,
754 &startup_info))
755 return NULL;
756
757 ZeroMemory(&si, sizeof(si));
758 si.cb = sizeof(si);
759
760 /* note: we only support a small subset of all SI attributes */
761 si.dwFlags = getulong(startup_info, "dwFlags");
762 si.wShowWindow = (WORD)getulong(startup_info, "wShowWindow");
763 si.hStdInput = gethandle(startup_info, "hStdInput");
764 si.hStdOutput = gethandle(startup_info, "hStdOutput");
765 si.hStdError = gethandle(startup_info, "hStdError");
766 if (PyErr_Occurred())
767 return NULL;
768
769 if (env_mapping != Py_None) {
770 environment = getenvironment(env_mapping);
771 if (! environment)
772 return NULL;
773 wenvironment = PyUnicode_AsUnicode(environment);
774 if (wenvironment == NULL)
775 {
776 Py_XDECREF(environment);
777 return NULL;
778 }
779 }
780 else {
781 environment = NULL;
782 wenvironment = NULL;
783 }
784
785 Py_BEGIN_ALLOW_THREADS
786 result = CreateProcessW(application_name,
787 command_line,
788 NULL,
789 NULL,
790 inherit_handles,
791 creation_flags | CREATE_UNICODE_ENVIRONMENT,
792 wenvironment,
793 current_directory,
794 &si,
795 &pi);
796 Py_END_ALLOW_THREADS
797
798 Py_XDECREF(environment);
799
800 if (! result)
801 return PyErr_SetFromWindowsErr(GetLastError());
802
803 return Py_BuildValue("NNkk",
804 HANDLE_TO_PYNUM(pi.hProcess),
805 HANDLE_TO_PYNUM(pi.hThread),
806 pi.dwProcessId,
807 pi.dwThreadId);
808}
809
810PyDoc_STRVAR(DuplicateHandle_doc,
811"DuplicateHandle(source_proc_handle, source_handle,\n\
812 target_proc_handle, target_handle, access,\n\
813 inherit[, options]) -> handle\n\
814\n\
815Return a duplicate handle object.\n\
816\n\
817The duplicate handle refers to the same object as the original\n\
818handle. Therefore, any changes to the object are reflected\n\
819through both handles.");
820
821static PyObject *
822winapi_DuplicateHandle(PyObject* self, PyObject* args)
823{
824 HANDLE target_handle;
825 BOOL result;
826
827 HANDLE source_process_handle;
828 HANDLE source_handle;
829 HANDLE target_process_handle;
830 DWORD desired_access;
831 BOOL inherit_handle;
832 DWORD options = 0;
833
834 if (! PyArg_ParseTuple(args,
835 F_HANDLE F_HANDLE F_HANDLE F_DWORD F_BOOL F_DWORD
836 ":DuplicateHandle",
837 &source_process_handle,
838 &source_handle,
839 &target_process_handle,
840 &desired_access,
841 &inherit_handle,
842 &options))
843 return NULL;
844
845 Py_BEGIN_ALLOW_THREADS
846 result = DuplicateHandle(
847 source_process_handle,
848 source_handle,
849 target_process_handle,
850 &target_handle,
851 desired_access,
852 inherit_handle,
853 options
854 );
855 Py_END_ALLOW_THREADS
856
857 if (! result)
858 return PyErr_SetFromWindowsErr(GetLastError());
859
860 return HANDLE_TO_PYNUM(target_handle);
861}
862
863static PyObject *
864winapi_ExitProcess(PyObject *self, PyObject *args)
865{
866 UINT uExitCode;
867
868 if (!PyArg_ParseTuple(args, F_UINT, &uExitCode))
869 return NULL;
870
871 #if defined(Py_DEBUG)
872 SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOALIGNMENTFAULTEXCEPT|
873 SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX);
874 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
875 #endif
876
877 ExitProcess(uExitCode);
878
879 return NULL;
880}
881
882PyDoc_STRVAR(GetCurrentProcess_doc,
883"GetCurrentProcess() -> handle\n\
884\n\
885Return a handle object for the current process.");
886
887static PyObject *
888winapi_GetCurrentProcess(PyObject* self, PyObject* args)
889{
890 if (! PyArg_ParseTuple(args, ":GetCurrentProcess"))
891 return NULL;
892
893 return HANDLE_TO_PYNUM(GetCurrentProcess());
894}
895
896PyDoc_STRVAR(GetExitCodeProcess_doc,
897"GetExitCodeProcess(handle) -> Exit code\n\
898\n\
899Return the termination status of the specified process.");
900
901static PyObject *
902winapi_GetExitCodeProcess(PyObject* self, PyObject* args)
903{
904 DWORD exit_code;
905 BOOL result;
906
907 HANDLE process;
908 if (! PyArg_ParseTuple(args, F_HANDLE ":GetExitCodeProcess", &process))
909 return NULL;
910
911 result = GetExitCodeProcess(process, &exit_code);
912
913 if (! result)
914 return PyErr_SetFromWindowsErr(GetLastError());
915
916 return PyLong_FromUnsignedLong(exit_code);
917}
918
919static PyObject *
920winapi_GetLastError(PyObject *self, PyObject *args)
921{
922 return Py_BuildValue(F_DWORD, GetLastError());
923}
924
925PyDoc_STRVAR(GetModuleFileName_doc,
926"GetModuleFileName(module) -> path\n\
927\n\
928Return the fully-qualified path for the file that contains\n\
929the specified module. The module must have been loaded by the\n\
930current process.\n\
931\n\
932The module parameter should be a handle to the loaded module\n\
933whose path is being requested. If this parameter is 0, \n\
934GetModuleFileName retrieves the path of the executable file\n\
935of the current process.");
936
937static PyObject *
938winapi_GetModuleFileName(PyObject* self, PyObject* args)
939{
940 BOOL result;
941 HMODULE module;
942 WCHAR filename[MAX_PATH];
943
944 if (! PyArg_ParseTuple(args, F_HANDLE ":GetModuleFileName",
945 &module))
946 return NULL;
947
948 result = GetModuleFileNameW(module, filename, MAX_PATH);
949 filename[MAX_PATH-1] = '\0';
950
951 if (! result)
952 return PyErr_SetFromWindowsErr(GetLastError());
953
954 return PyUnicode_FromWideChar(filename, wcslen(filename));
955}
956
957PyDoc_STRVAR(GetStdHandle_doc,
958"GetStdHandle(handle) -> integer\n\
959\n\
960Return a handle to the specified standard device\n\
961(STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE).\n\
962The integer associated with the handle object is returned.");
963
964static PyObject *
965winapi_GetStdHandle(PyObject* self, PyObject* args)
966{
967 HANDLE handle;
968 DWORD std_handle;
969
970 if (! PyArg_ParseTuple(args, F_DWORD ":GetStdHandle", &std_handle))
971 return NULL;
972
973 Py_BEGIN_ALLOW_THREADS
974 handle = GetStdHandle(std_handle);
975 Py_END_ALLOW_THREADS
976
977 if (handle == INVALID_HANDLE_VALUE)
978 return PyErr_SetFromWindowsErr(GetLastError());
979
980 if (! handle) {
981 Py_INCREF(Py_None);
982 return Py_None;
983 }
984
985 /* note: returns integer, not handle object */
986 return HANDLE_TO_PYNUM(handle);
987}
988
989PyDoc_STRVAR(GetVersion_doc,
990"GetVersion() -> version\n\
991\n\
992Return the version number of the current operating system.");
993
994static PyObject *
995winapi_GetVersion(PyObject* self, PyObject* args)
996{
997 if (! PyArg_ParseTuple(args, ":GetVersion"))
998 return NULL;
999
1000 return PyLong_FromUnsignedLong(GetVersion());
1001}
1002
1003static PyObject *
1004winapi_OpenProcess(PyObject *self, PyObject *args)
1005{
1006 DWORD dwDesiredAccess;
1007 BOOL bInheritHandle;
1008 DWORD dwProcessId;
1009 HANDLE handle;
1010
1011 if (!PyArg_ParseTuple(args, F_DWORD F_BOOL F_DWORD,
1012 &dwDesiredAccess, &bInheritHandle, &dwProcessId))
1013 return NULL;
1014
1015 handle = OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
1016 if (handle == NULL)
1017 return PyErr_SetFromWindowsErr(0);
1018
1019 return Py_BuildValue(F_HANDLE, handle);
1020}
1021
1022static PyObject *
1023winapi_PeekNamedPipe(PyObject *self, PyObject *args)
1024{
1025 HANDLE handle;
1026 int size = 0;
1027 PyObject *buf = NULL;
1028 DWORD nread, navail, nleft;
1029 BOOL ret;
1030
1031 if (!PyArg_ParseTuple(args, F_HANDLE "|i:PeekNamedPipe" , &handle, &size))
1032 return NULL;
1033
1034 if (size < 0) {
1035 PyErr_SetString(PyExc_ValueError, "negative size");
1036 return NULL;
1037 }
1038
1039 if (size) {
1040 buf = PyBytes_FromStringAndSize(NULL, size);
1041 if (!buf)
1042 return NULL;
1043 Py_BEGIN_ALLOW_THREADS
1044 ret = PeekNamedPipe(handle, PyBytes_AS_STRING(buf), size, &nread,
1045 &navail, &nleft);
1046 Py_END_ALLOW_THREADS
1047 if (!ret) {
1048 Py_DECREF(buf);
1049 return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
1050 }
1051 if (_PyBytes_Resize(&buf, nread))
1052 return NULL;
1053 return Py_BuildValue("Nii", buf, navail, nleft);
1054 }
1055 else {
1056 Py_BEGIN_ALLOW_THREADS
1057 ret = PeekNamedPipe(handle, NULL, 0, NULL, &navail, &nleft);
1058 Py_END_ALLOW_THREADS
1059 if (!ret) {
1060 return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
1061 }
1062 return Py_BuildValue("ii", navail, nleft);
1063 }
1064}
1065
1066static PyObject *
1067winapi_ReadFile(PyObject *self, PyObject *args, PyObject *kwds)
1068{
1069 HANDLE handle;
1070 int size;
1071 DWORD nread;
1072 PyObject *buf;
1073 BOOL ret;
1074 int use_overlapped = 0;
1075 DWORD err;
1076 OverlappedObject *overlapped = NULL;
1077 static char *kwlist[] = {"handle", "size", "overlapped", NULL};
1078
1079 if (!PyArg_ParseTupleAndKeywords(args, kwds,
1080 F_HANDLE "i|i:ReadFile", kwlist,
1081 &handle, &size, &use_overlapped))
1082 return NULL;
1083
1084 buf = PyBytes_FromStringAndSize(NULL, size);
1085 if (!buf)
1086 return NULL;
1087 if (use_overlapped) {
1088 overlapped = new_overlapped(handle);
1089 if (!overlapped) {
1090 Py_DECREF(buf);
1091 return NULL;
1092 }
1093 /* Steals reference to buf */
1094 overlapped->read_buffer = buf;
1095 }
1096
1097 Py_BEGIN_ALLOW_THREADS
1098 ret = ReadFile(handle, PyBytes_AS_STRING(buf), size, &nread,
1099 overlapped ? &overlapped->overlapped : NULL);
1100 Py_END_ALLOW_THREADS
1101
1102 err = ret ? 0 : GetLastError();
1103
1104 if (overlapped) {
1105 if (!ret) {
1106 if (err == ERROR_IO_PENDING)
1107 overlapped->pending = 1;
1108 else if (err != ERROR_MORE_DATA) {
1109 Py_DECREF(overlapped);
1110 return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
1111 }
1112 }
1113 return Py_BuildValue("NI", (PyObject *) overlapped, err);
1114 }
1115
1116 if (!ret && err != ERROR_MORE_DATA) {
1117 Py_DECREF(buf);
1118 return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
1119 }
1120 if (_PyBytes_Resize(&buf, nread))
1121 return NULL;
1122 return Py_BuildValue("NI", buf, err);
1123}
1124
1125static PyObject *
1126winapi_SetNamedPipeHandleState(PyObject *self, PyObject *args)
1127{
1128 HANDLE hNamedPipe;
1129 PyObject *oArgs[3];
1130 DWORD dwArgs[3], *pArgs[3] = {NULL, NULL, NULL};
1131 int i;
1132
1133 if (!PyArg_ParseTuple(args, F_HANDLE "OOO",
1134 &hNamedPipe, &oArgs[0], &oArgs[1], &oArgs[2]))
1135 return NULL;
1136
1137 PyErr_Clear();
1138
1139 for (i = 0 ; i < 3 ; i++) {
1140 if (oArgs[i] != Py_None) {
1141 dwArgs[i] = PyLong_AsUnsignedLongMask(oArgs[i]);
1142 if (PyErr_Occurred())
1143 return NULL;
1144 pArgs[i] = &dwArgs[i];
1145 }
1146 }
1147
1148 if (!SetNamedPipeHandleState(hNamedPipe, pArgs[0], pArgs[1], pArgs[2]))
1149 return PyErr_SetFromWindowsErr(0);
1150
1151 Py_RETURN_NONE;
1152}
1153
1154PyDoc_STRVAR(TerminateProcess_doc,
1155"TerminateProcess(handle, exit_code) -> None\n\
1156\n\
1157Terminate the specified process and all of its threads.");
1158
1159static PyObject *
1160winapi_TerminateProcess(PyObject* self, PyObject* args)
1161{
1162 BOOL result;
1163
1164 HANDLE process;
1165 UINT exit_code;
1166 if (! PyArg_ParseTuple(args, F_HANDLE F_UINT ":TerminateProcess",
1167 &process, &exit_code))
1168 return NULL;
1169
1170 result = TerminateProcess(process, exit_code);
1171
1172 if (! result)
1173 return PyErr_SetFromWindowsErr(GetLastError());
1174
1175 Py_INCREF(Py_None);
1176 return Py_None;
1177}
1178
1179static PyObject *
1180winapi_WaitNamedPipe(PyObject *self, PyObject *args)
1181{
1182 LPCTSTR lpNamedPipeName;
1183 DWORD nTimeOut;
1184 BOOL success;
1185
1186 if (!PyArg_ParseTuple(args, "s" F_DWORD, &lpNamedPipeName, &nTimeOut))
1187 return NULL;
1188
1189 Py_BEGIN_ALLOW_THREADS
1190 success = WaitNamedPipe(lpNamedPipeName, nTimeOut);
1191 Py_END_ALLOW_THREADS
1192
1193 if (!success)
1194 return PyErr_SetFromWindowsErr(0);
1195
1196 Py_RETURN_NONE;
1197}
1198
1199static PyObject *
1200winapi_WaitForMultipleObjects(PyObject* self, PyObject* args)
1201{
1202 DWORD result;
1203 PyObject *handle_seq;
1204 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1205 HANDLE sigint_event = NULL;
1206 Py_ssize_t nhandles, i;
1207 BOOL wait_flag;
1208 DWORD milliseconds = INFINITE;
1209
1210 if (!PyArg_ParseTuple(args, "O" F_BOOL "|" F_DWORD
1211 ":WaitForMultipleObjects",
1212 &handle_seq, &wait_flag, &milliseconds))
1213 return NULL;
1214
1215 if (!PySequence_Check(handle_seq)) {
1216 PyErr_Format(PyExc_TypeError,
1217 "sequence type expected, got '%s'",
Richard Oudkerk67339272012-08-21 14:54:22 +01001218 Py_TYPE(handle_seq)->tp_name);
Antoine Pitrou23bba4c2012-04-18 20:51:15 +02001219 return NULL;
1220 }
1221 nhandles = PySequence_Length(handle_seq);
1222 if (nhandles == -1)
1223 return NULL;
1224 if (nhandles < 0 || nhandles >= MAXIMUM_WAIT_OBJECTS - 1) {
1225 PyErr_Format(PyExc_ValueError,
1226 "need at most %zd handles, got a sequence of length %zd",
1227 MAXIMUM_WAIT_OBJECTS - 1, nhandles);
1228 return NULL;
1229 }
1230 for (i = 0; i < nhandles; i++) {
1231 HANDLE h;
1232 PyObject *v = PySequence_GetItem(handle_seq, i);
1233 if (v == NULL)
1234 return NULL;
1235 if (!PyArg_Parse(v, F_HANDLE, &h)) {
1236 Py_DECREF(v);
1237 return NULL;
1238 }
1239 handles[i] = h;
1240 Py_DECREF(v);
1241 }
1242 /* If this is the main thread then make the wait interruptible
1243 by Ctrl-C unless we are waiting for *all* handles */
1244 if (!wait_flag && _PyOS_IsMainThread()) {
1245 sigint_event = _PyOS_SigintEvent();
1246 assert(sigint_event != NULL);
1247 handles[nhandles++] = sigint_event;
1248 }
1249
1250 Py_BEGIN_ALLOW_THREADS
1251 if (sigint_event != NULL)
1252 ResetEvent(sigint_event);
1253 result = WaitForMultipleObjects((DWORD) nhandles, handles,
1254 wait_flag, milliseconds);
1255 Py_END_ALLOW_THREADS
1256
1257 if (result == WAIT_FAILED)
1258 return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
1259 else if (sigint_event != NULL && result == WAIT_OBJECT_0 + nhandles - 1) {
1260 errno = EINTR;
1261 return PyErr_SetFromErrno(PyExc_IOError);
1262 }
1263
1264 return PyLong_FromLong((int) result);
1265}
1266
1267PyDoc_STRVAR(WaitForSingleObject_doc,
1268"WaitForSingleObject(handle, timeout) -> result\n\
1269\n\
1270Wait until the specified object is in the signaled state or\n\
1271the time-out interval elapses. The timeout value is specified\n\
1272in milliseconds.");
1273
1274static PyObject *
1275winapi_WaitForSingleObject(PyObject* self, PyObject* args)
1276{
1277 DWORD result;
1278
1279 HANDLE handle;
1280 DWORD milliseconds;
1281 if (! PyArg_ParseTuple(args, F_HANDLE F_DWORD ":WaitForSingleObject",
1282 &handle,
1283 &milliseconds))
1284 return NULL;
1285
1286 Py_BEGIN_ALLOW_THREADS
1287 result = WaitForSingleObject(handle, milliseconds);
1288 Py_END_ALLOW_THREADS
1289
1290 if (result == WAIT_FAILED)
1291 return PyErr_SetFromWindowsErr(GetLastError());
1292
1293 return PyLong_FromUnsignedLong(result);
1294}
1295
1296static PyObject *
1297winapi_WriteFile(PyObject *self, PyObject *args, PyObject *kwds)
1298{
1299 HANDLE handle;
1300 Py_buffer _buf, *buf;
1301 PyObject *bufobj;
Victor Stinner71765772013-06-24 23:13:24 +02001302 DWORD len, written;
Antoine Pitrou23bba4c2012-04-18 20:51:15 +02001303 BOOL ret;
1304 int use_overlapped = 0;
1305 DWORD err;
1306 OverlappedObject *overlapped = NULL;
1307 static char *kwlist[] = {"handle", "buffer", "overlapped", NULL};
1308
1309 /* First get handle and use_overlapped to know which Py_buffer to use */
1310 if (!PyArg_ParseTupleAndKeywords(args, kwds,
1311 F_HANDLE "O|i:WriteFile", kwlist,
1312 &handle, &bufobj, &use_overlapped))
1313 return NULL;
1314
1315 if (use_overlapped) {
1316 overlapped = new_overlapped(handle);
1317 if (!overlapped)
1318 return NULL;
1319 buf = &overlapped->write_buffer;
1320 }
1321 else
1322 buf = &_buf;
1323
1324 if (!PyArg_Parse(bufobj, "y*", buf)) {
1325 Py_XDECREF(overlapped);
1326 return NULL;
1327 }
1328
1329 Py_BEGIN_ALLOW_THREADS
Victor Stinner71765772013-06-24 23:13:24 +02001330 len = (DWORD)Py_MIN(buf->len, DWORD_MAX);
1331 ret = WriteFile(handle, buf->buf, len, &written,
Antoine Pitrou23bba4c2012-04-18 20:51:15 +02001332 overlapped ? &overlapped->overlapped : NULL);
1333 Py_END_ALLOW_THREADS
1334
1335 err = ret ? 0 : GetLastError();
1336
1337 if (overlapped) {
1338 if (!ret) {
1339 if (err == ERROR_IO_PENDING)
1340 overlapped->pending = 1;
1341 else {
1342 Py_DECREF(overlapped);
1343 return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
1344 }
1345 }
1346 return Py_BuildValue("NI", (PyObject *) overlapped, err);
1347 }
1348
1349 PyBuffer_Release(buf);
1350 if (!ret)
1351 return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
1352 return Py_BuildValue("II", written, err);
1353}
1354
1355
1356static PyMethodDef winapi_functions[] = {
1357 {"CloseHandle", winapi_CloseHandle, METH_VARARGS,
1358 CloseHandle_doc},
1359 {"ConnectNamedPipe", (PyCFunction)winapi_ConnectNamedPipe,
1360 METH_VARARGS | METH_KEYWORDS, ""},
1361 {"CreateFile", winapi_CreateFile, METH_VARARGS,
1362 ""},
Tim Golden0321cf22014-05-05 19:46:17 +01001363 {"CreateJunction", winapi_CreateJunction, METH_VARARGS,
1364 ""},
Antoine Pitrou23bba4c2012-04-18 20:51:15 +02001365 {"CreateNamedPipe", winapi_CreateNamedPipe, METH_VARARGS,
1366 ""},
1367 {"CreatePipe", winapi_CreatePipe, METH_VARARGS,
1368 CreatePipe_doc},
1369 {"CreateProcess", winapi_CreateProcess, METH_VARARGS,
1370 CreateProcess_doc},
1371 {"DuplicateHandle", winapi_DuplicateHandle, METH_VARARGS,
1372 DuplicateHandle_doc},
1373 {"ExitProcess", winapi_ExitProcess, METH_VARARGS,
1374 ""},
1375 {"GetCurrentProcess", winapi_GetCurrentProcess, METH_VARARGS,
1376 GetCurrentProcess_doc},
1377 {"GetExitCodeProcess", winapi_GetExitCodeProcess, METH_VARARGS,
1378 GetExitCodeProcess_doc},
1379 {"GetLastError", winapi_GetLastError, METH_NOARGS,
1380 GetCurrentProcess_doc},
1381 {"GetModuleFileName", winapi_GetModuleFileName, METH_VARARGS,
1382 GetModuleFileName_doc},
1383 {"GetStdHandle", winapi_GetStdHandle, METH_VARARGS,
1384 GetStdHandle_doc},
1385 {"GetVersion", winapi_GetVersion, METH_VARARGS,
1386 GetVersion_doc},
1387 {"OpenProcess", winapi_OpenProcess, METH_VARARGS,
1388 ""},
1389 {"PeekNamedPipe", winapi_PeekNamedPipe, METH_VARARGS,
1390 ""},
1391 {"ReadFile", (PyCFunction)winapi_ReadFile, METH_VARARGS | METH_KEYWORDS,
1392 ""},
1393 {"SetNamedPipeHandleState", winapi_SetNamedPipeHandleState, METH_VARARGS,
1394 ""},
1395 {"TerminateProcess", winapi_TerminateProcess, METH_VARARGS,
1396 TerminateProcess_doc},
1397 {"WaitNamedPipe", winapi_WaitNamedPipe, METH_VARARGS,
1398 ""},
1399 {"WaitForMultipleObjects", winapi_WaitForMultipleObjects, METH_VARARGS,
1400 ""},
1401 {"WaitForSingleObject", winapi_WaitForSingleObject, METH_VARARGS,
1402 WaitForSingleObject_doc},
1403 {"WriteFile", (PyCFunction)winapi_WriteFile, METH_VARARGS | METH_KEYWORDS,
1404 ""},
1405 {NULL, NULL}
1406};
1407
1408static struct PyModuleDef winapi_module = {
1409 PyModuleDef_HEAD_INIT,
1410 "_winapi",
1411 NULL,
1412 -1,
1413 winapi_functions,
1414 NULL,
1415 NULL,
1416 NULL,
1417 NULL
1418};
1419
1420#define WINAPI_CONSTANT(fmt, con) \
1421 PyDict_SetItemString(d, #con, Py_BuildValue(fmt, con))
1422
1423PyMODINIT_FUNC
1424PyInit__winapi(void)
1425{
1426 PyObject *d;
1427 PyObject *m;
1428
1429 if (PyType_Ready(&OverlappedType) < 0)
1430 return NULL;
1431
1432 m = PyModule_Create(&winapi_module);
1433 if (m == NULL)
1434 return NULL;
1435 d = PyModule_GetDict(m);
1436
1437 PyDict_SetItemString(d, "Overlapped", (PyObject *) &OverlappedType);
1438
1439 /* constants */
1440 WINAPI_CONSTANT(F_DWORD, CREATE_NEW_CONSOLE);
1441 WINAPI_CONSTANT(F_DWORD, CREATE_NEW_PROCESS_GROUP);
1442 WINAPI_CONSTANT(F_DWORD, DUPLICATE_SAME_ACCESS);
Antoine Pitrou5438ed12012-04-24 22:56:57 +02001443 WINAPI_CONSTANT(F_DWORD, DUPLICATE_CLOSE_SOURCE);
Antoine Pitrou23bba4c2012-04-18 20:51:15 +02001444 WINAPI_CONSTANT(F_DWORD, ERROR_ALREADY_EXISTS);
1445 WINAPI_CONSTANT(F_DWORD, ERROR_BROKEN_PIPE);
1446 WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING);
1447 WINAPI_CONSTANT(F_DWORD, ERROR_MORE_DATA);
1448 WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
1449 WINAPI_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES);
Antoine Pitrou23bba4c2012-04-18 20:51:15 +02001450 WINAPI_CONSTANT(F_DWORD, ERROR_MORE_DATA);
1451 WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
Richard Oudkerkfdb8dcf2012-05-05 19:45:37 +01001452 WINAPI_CONSTANT(F_DWORD, ERROR_NO_DATA);
Antoine Pitrou23bba4c2012-04-18 20:51:15 +02001453 WINAPI_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES);
1454 WINAPI_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED);
1455 WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY);
1456 WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_CONNECTED);
1457 WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT);
1458 WINAPI_CONSTANT(F_DWORD, FILE_FLAG_FIRST_PIPE_INSTANCE);
1459 WINAPI_CONSTANT(F_DWORD, FILE_FLAG_OVERLAPPED);
Antoine Pitrou5438ed12012-04-24 22:56:57 +02001460 WINAPI_CONSTANT(F_DWORD, FILE_GENERIC_READ);
1461 WINAPI_CONSTANT(F_DWORD, FILE_GENERIC_WRITE);
Antoine Pitrou23bba4c2012-04-18 20:51:15 +02001462 WINAPI_CONSTANT(F_DWORD, GENERIC_READ);
1463 WINAPI_CONSTANT(F_DWORD, GENERIC_WRITE);
1464 WINAPI_CONSTANT(F_DWORD, INFINITE);
1465 WINAPI_CONSTANT(F_DWORD, NMPWAIT_WAIT_FOREVER);
1466 WINAPI_CONSTANT(F_DWORD, OPEN_EXISTING);
1467 WINAPI_CONSTANT(F_DWORD, PIPE_ACCESS_DUPLEX);
1468 WINAPI_CONSTANT(F_DWORD, PIPE_ACCESS_INBOUND);
1469 WINAPI_CONSTANT(F_DWORD, PIPE_READMODE_MESSAGE);
1470 WINAPI_CONSTANT(F_DWORD, PIPE_TYPE_MESSAGE);
1471 WINAPI_CONSTANT(F_DWORD, PIPE_UNLIMITED_INSTANCES);
1472 WINAPI_CONSTANT(F_DWORD, PIPE_WAIT);
1473 WINAPI_CONSTANT(F_DWORD, PROCESS_ALL_ACCESS);
Antoine Pitrou5438ed12012-04-24 22:56:57 +02001474 WINAPI_CONSTANT(F_DWORD, PROCESS_DUP_HANDLE);
Antoine Pitrou23bba4c2012-04-18 20:51:15 +02001475 WINAPI_CONSTANT(F_DWORD, STARTF_USESHOWWINDOW);
1476 WINAPI_CONSTANT(F_DWORD, STARTF_USESTDHANDLES);
1477 WINAPI_CONSTANT(F_DWORD, STD_INPUT_HANDLE);
1478 WINAPI_CONSTANT(F_DWORD, STD_OUTPUT_HANDLE);
1479 WINAPI_CONSTANT(F_DWORD, STD_ERROR_HANDLE);
1480 WINAPI_CONSTANT(F_DWORD, STILL_ACTIVE);
1481 WINAPI_CONSTANT(F_DWORD, SW_HIDE);
1482 WINAPI_CONSTANT(F_DWORD, WAIT_OBJECT_0);
Victor Stinner373f0a92014-03-20 09:26:55 +01001483 WINAPI_CONSTANT(F_DWORD, WAIT_ABANDONED_0);
Antoine Pitrou23bba4c2012-04-18 20:51:15 +02001484 WINAPI_CONSTANT(F_DWORD, WAIT_TIMEOUT);
1485
1486 WINAPI_CONSTANT("i", NULL);
1487
1488 return m;
1489}