1 /*
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 https://www.python.org/2.4/license for licensing details. */
36
37 #include "Python.h"
38 #include "pycore_moduleobject.h" // _PyModule_GetState()
39 #include "pycore_pylifecycle.h" // _Py_IsInterpreterFinalizing()
40 #include "pycore_pystate.h" // _PyInterpreterState_GET
41
42
43
44 #ifndef WINDOWS_LEAN_AND_MEAN
45 #define WINDOWS_LEAN_AND_MEAN
46 #endif
47 #include "windows.h"
48 #include <winioctl.h>
49 #include <crtdbg.h>
50 #include "winreparse.h"
51
52 #if defined(MS_WIN32) && !defined(MS_WIN64)
53 #define HANDLE_TO_PYNUM(handle) \
54 PyLong_FromUnsignedLong((unsigned long) handle)
55 #define PYNUM_TO_HANDLE(obj) ((HANDLE)PyLong_AsUnsignedLong(obj))
56 #define F_POINTER "k"
57 #define T_POINTER Py_T_ULONG
58 #else
59 #define HANDLE_TO_PYNUM(handle) \
60 PyLong_FromUnsignedLongLong((unsigned long long) handle)
61 #define PYNUM_TO_HANDLE(obj) ((HANDLE)PyLong_AsUnsignedLongLong(obj))
62 #define F_POINTER "K"
63 #define T_POINTER Py_T_ULONGLONG
64 #endif
65
66 #define F_HANDLE F_POINTER
67 #define F_DWORD "k"
68
69 #define T_HANDLE T_POINTER
70
71 // winbase.h limits the STARTF_* flags to the desktop API as of 10.0.19041.
72 #ifndef STARTF_USESHOWWINDOW
73 #define STARTF_USESHOWWINDOW 0x00000001
74 #endif
75 #ifndef STARTF_USESIZE
76 #define STARTF_USESIZE 0x00000002
77 #endif
78 #ifndef STARTF_USEPOSITION
79 #define STARTF_USEPOSITION 0x00000004
80 #endif
81 #ifndef STARTF_USECOUNTCHARS
82 #define STARTF_USECOUNTCHARS 0x00000008
83 #endif
84 #ifndef STARTF_USEFILLATTRIBUTE
85 #define STARTF_USEFILLATTRIBUTE 0x00000010
86 #endif
87 #ifndef STARTF_RUNFULLSCREEN
88 #define STARTF_RUNFULLSCREEN 0x00000020
89 #endif
90 #ifndef STARTF_FORCEONFEEDBACK
91 #define STARTF_FORCEONFEEDBACK 0x00000040
92 #endif
93 #ifndef STARTF_FORCEOFFFEEDBACK
94 #define STARTF_FORCEOFFFEEDBACK 0x00000080
95 #endif
96 #ifndef STARTF_USESTDHANDLES
97 #define STARTF_USESTDHANDLES 0x00000100
98 #endif
99 #ifndef STARTF_USEHOTKEY
100 #define STARTF_USEHOTKEY 0x00000200
101 #endif
102 #ifndef STARTF_TITLEISLINKNAME
103 #define STARTF_TITLEISLINKNAME 0x00000800
104 #endif
105 #ifndef STARTF_TITLEISAPPID
106 #define STARTF_TITLEISAPPID 0x00001000
107 #endif
108 #ifndef STARTF_PREVENTPINNING
109 #define STARTF_PREVENTPINNING 0x00002000
110 #endif
111 #ifndef STARTF_UNTRUSTEDSOURCE
112 #define STARTF_UNTRUSTEDSOURCE 0x00008000
113 #endif
114
115 typedef struct {
116 PyTypeObject *overlapped_type;
117 } WinApiState;
118
119 static inline WinApiState*
winapi_get_state(PyObject * module)120 winapi_get_state(PyObject *module)
121 {
122 void *state = _PyModule_GetState(module);
123 assert(state != NULL);
124 return (WinApiState *)state;
125 }
126
127 /*
128 * A Python object wrapping an OVERLAPPED structure and other useful data
129 * for overlapped I/O
130 */
131
132 typedef struct {
133 PyObject_HEAD
134 OVERLAPPED overlapped;
135 /* For convenience, we store the file handle too */
136 HANDLE handle;
137 /* Whether there's I/O in flight */
138 int pending;
139 /* Whether I/O completed successfully */
140 int completed;
141 /* Buffer used for reading (optional) */
142 PyObject *read_buffer;
143 /* Buffer used for writing (optional) */
144 Py_buffer write_buffer;
145 } OverlappedObject;
146
147 /*
148 Note: tp_clear (overlapped_clear) is not implemented because it
149 requires cancelling the IO operation if it's pending and the cancellation is
150 quite complex and can fail (see: overlapped_dealloc).
151 */
152 static int
overlapped_traverse(OverlappedObject * self,visitproc visit,void * arg)153 overlapped_traverse(OverlappedObject *self, visitproc visit, void *arg)
154 {
155 Py_VISIT(self->read_buffer);
156 Py_VISIT(self->write_buffer.obj);
157 Py_VISIT(Py_TYPE(self));
158 return 0;
159 }
160
161 static void
overlapped_dealloc(OverlappedObject * self)162 overlapped_dealloc(OverlappedObject *self)
163 {
164 DWORD bytes;
165 int err = GetLastError();
166
167 PyObject_GC_UnTrack(self);
168 if (self->pending) {
169 if (CancelIoEx(self->handle, &self->overlapped) &&
170 GetOverlappedResult(self->handle, &self->overlapped, &bytes, TRUE))
171 {
172 /* The operation is no longer pending -- nothing to do. */
173 }
174 else if (_Py_IsInterpreterFinalizing(_PyInterpreterState_GET()))
175 {
176 /* The operation is still pending -- give a warning. This
177 will probably only happen on Windows XP. */
178 PyErr_SetString(PyExc_PythonFinalizationError,
179 "I/O operations still in flight while destroying "
180 "Overlapped object, the process may crash");
181 PyErr_WriteUnraisable(NULL);
182 }
183 else
184 {
185 /* The operation is still pending, but the process is
186 probably about to exit, so we need not worry too much
187 about memory leaks. Leaking self prevents a potential
188 crash. This can happen when a daemon thread is cleaned
189 up at exit -- see #19565. We only expect to get here
190 on Windows XP. */
191 CloseHandle(self->overlapped.hEvent);
192 SetLastError(err);
193 return;
194 }
195 }
196
197 CloseHandle(self->overlapped.hEvent);
198 SetLastError(err);
199 if (self->write_buffer.obj)
200 PyBuffer_Release(&self->write_buffer);
201 Py_CLEAR(self->read_buffer);
202 PyTypeObject *tp = Py_TYPE(self);
203 tp->tp_free(self);
204 Py_DECREF(tp);
205 }
206
207 /*[clinic input]
208 module _winapi
209 class _winapi.Overlapped "OverlappedObject *" "&OverlappedType"
210 [clinic start generated code]*/
211 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=c13d3f5fd1dabb84]*/
212
213 /*[python input]
214 def create_converter(type_, format_unit):
215 name = type_ + '_converter'
216 # registered upon creation by CConverter's metaclass
217 type(name, (CConverter,), {'type': type_, 'format_unit': format_unit})
218
219 # format unit differs between platforms for these
220 create_converter('HANDLE', '" F_HANDLE "')
221 create_converter('HMODULE', '" F_HANDLE "')
222 create_converter('LPSECURITY_ATTRIBUTES', '" F_POINTER "')
223 create_converter('LPCVOID', '" F_POINTER "')
224
225 create_converter('BOOL', 'i') # F_BOOL used previously (always 'i')
226 create_converter('DWORD', 'k') # F_DWORD is always "k" (which is much shorter)
227 create_converter('UINT', 'I') # F_UINT used previously (always 'I')
228
229 class LPCWSTR_converter(Py_UNICODE_converter):
230 type = 'LPCWSTR'
231
232 class HANDLE_return_converter(CReturnConverter):
233 type = 'HANDLE'
234
235 def render(self, function, data):
236 self.declare(data)
237 self.err_occurred_if("_return_value == INVALID_HANDLE_VALUE", data)
238 data.return_conversion.append(
239 'if (_return_value == NULL) {\n Py_RETURN_NONE;\n}\n')
240 data.return_conversion.append(
241 'return_value = HANDLE_TO_PYNUM(_return_value);\n')
242
243 class DWORD_return_converter(CReturnConverter):
244 type = 'DWORD'
245
246 def render(self, function, data):
247 self.declare(data)
248 self.err_occurred_if("_return_value == PY_DWORD_MAX", data)
249 data.return_conversion.append(
250 'return_value = PyLong_FromUnsignedLong(_return_value);\n')
251
252 class LPVOID_return_converter(CReturnConverter):
253 type = 'LPVOID'
254
255 def render(self, function, data):
256 self.declare(data)
257 self.err_occurred_if("_return_value == NULL", data)
258 data.return_conversion.append(
259 'return_value = HANDLE_TO_PYNUM(_return_value);\n')
260 [python start generated code]*/
261 /*[python end generated code: output=da39a3ee5e6b4b0d input=da0a4db751936ee7]*/
262
263 #include "clinic/_winapi.c.h"
264
265 /*[clinic input]
266 _winapi.Overlapped.GetOverlappedResult
267
268 wait: bool
269 /
270 [clinic start generated code]*/
271
272 static PyObject *
_winapi_Overlapped_GetOverlappedResult_impl(OverlappedObject * self,int wait)273 _winapi_Overlapped_GetOverlappedResult_impl(OverlappedObject *self, int wait)
274 /*[clinic end generated code: output=bdd0c1ed6518cd03 input=194505ee8e0e3565]*/
275 {
276 BOOL res;
277 DWORD transferred = 0;
278 DWORD err;
279
280 Py_BEGIN_ALLOW_THREADS
281 res = GetOverlappedResult(self->handle, &self->overlapped, &transferred,
282 wait != 0);
283 Py_END_ALLOW_THREADS
284
285 err = res ? ERROR_SUCCESS : GetLastError();
286 switch (err) {
287 case ERROR_SUCCESS:
288 case ERROR_MORE_DATA:
289 case ERROR_OPERATION_ABORTED:
290 self->completed = 1;
291 self->pending = 0;
292 break;
293 case ERROR_IO_INCOMPLETE:
294 break;
295 default:
296 self->pending = 0;
297 return PyErr_SetExcFromWindowsErr(PyExc_OSError, err);
298 }
299 if (self->completed && self->read_buffer != NULL) {
300 assert(PyBytes_CheckExact(self->read_buffer));
301 if (transferred != PyBytes_GET_SIZE(self->read_buffer) &&
302 _PyBytes_Resize(&self->read_buffer, transferred))
303 return NULL;
304 }
305 return Py_BuildValue("II", (unsigned) transferred, (unsigned) err);
306 }
307
308 /*[clinic input]
309 _winapi.Overlapped.getbuffer
310 [clinic start generated code]*/
311
312 static PyObject *
_winapi_Overlapped_getbuffer_impl(OverlappedObject * self)313 _winapi_Overlapped_getbuffer_impl(OverlappedObject *self)
314 /*[clinic end generated code: output=95a3eceefae0f748 input=347fcfd56b4ceabd]*/
315 {
316 PyObject *res;
317 if (!self->completed) {
318 PyErr_SetString(PyExc_ValueError,
319 "can't get read buffer before GetOverlappedResult() "
320 "signals the operation completed");
321 return NULL;
322 }
323 res = self->read_buffer ? self->read_buffer : Py_None;
324 return Py_NewRef(res);
325 }
326
327 /*[clinic input]
328 _winapi.Overlapped.cancel
329 [clinic start generated code]*/
330
331 static PyObject *
_winapi_Overlapped_cancel_impl(OverlappedObject * self)332 _winapi_Overlapped_cancel_impl(OverlappedObject *self)
333 /*[clinic end generated code: output=fcb9ab5df4ebdae5 input=cbf3da142290039f]*/
334 {
335 BOOL res = TRUE;
336
337 if (self->pending) {
338 Py_BEGIN_ALLOW_THREADS
339 res = CancelIoEx(self->handle, &self->overlapped);
340 Py_END_ALLOW_THREADS
341 }
342
343 /* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */
344 if (!res && GetLastError() != ERROR_NOT_FOUND)
345 return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
346 self->pending = 0;
347 Py_RETURN_NONE;
348 }
349
350 static PyMethodDef overlapped_methods[] = {
351 _WINAPI_OVERLAPPED_GETOVERLAPPEDRESULT_METHODDEF
352 _WINAPI_OVERLAPPED_GETBUFFER_METHODDEF
353 _WINAPI_OVERLAPPED_CANCEL_METHODDEF
354 {NULL}
355 };
356
357 static PyMemberDef overlapped_members[] = {
358 {"event", T_HANDLE,
359 offsetof(OverlappedObject, overlapped) + offsetof(OVERLAPPED, hEvent),
360 Py_READONLY, "overlapped event handle"},
361 {NULL}
362 };
363
364 static PyType_Slot winapi_overlapped_type_slots[] = {
365 {Py_tp_traverse, overlapped_traverse},
366 {Py_tp_dealloc, overlapped_dealloc},
367 {Py_tp_doc, "OVERLAPPED structure wrapper"},
368 {Py_tp_methods, overlapped_methods},
369 {Py_tp_members, overlapped_members},
370 {0,0}
371 };
372
373 static PyType_Spec winapi_overlapped_type_spec = {
374 .name = "_winapi.Overlapped",
375 .basicsize = sizeof(OverlappedObject),
376 .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION |
377 Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE),
378 .slots = winapi_overlapped_type_slots,
379 };
380
381 static OverlappedObject *
new_overlapped(PyObject * module,HANDLE handle)382 new_overlapped(PyObject *module, HANDLE handle)
383 {
384 WinApiState *st = winapi_get_state(module);
385 OverlappedObject *self = PyObject_GC_New(OverlappedObject, st->overlapped_type);
386 if (!self)
387 return NULL;
388
389 self->handle = handle;
390 self->read_buffer = NULL;
391 self->pending = 0;
392 self->completed = 0;
393 memset(&self->overlapped, 0, sizeof(OVERLAPPED));
394 memset(&self->write_buffer, 0, sizeof(Py_buffer));
395 /* Manual reset, initially non-signalled */
396 self->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
397
398 PyObject_GC_Track(self);
399 return self;
400 }
401
402 /* -------------------------------------------------------------------- */
403 /* windows API functions */
404
405 /*[clinic input]
406 _winapi.CloseHandle
407
408 handle: HANDLE
409 /
410
411 Close handle.
412 [clinic start generated code]*/
413
414 static PyObject *
_winapi_CloseHandle_impl(PyObject * module,HANDLE handle)415 _winapi_CloseHandle_impl(PyObject *module, HANDLE handle)
416 /*[clinic end generated code: output=7ad37345f07bd782 input=7f0e4ac36e0352b8]*/
417 {
418 BOOL success;
419
420 Py_BEGIN_ALLOW_THREADS
421 success = CloseHandle(handle);
422 Py_END_ALLOW_THREADS
423
424 if (!success)
425 return PyErr_SetFromWindowsErr(0);
426
427 Py_RETURN_NONE;
428 }
429
430 /*[clinic input]
431 _winapi.ConnectNamedPipe
432
433 handle: HANDLE
434 overlapped as use_overlapped: bool = False
435 [clinic start generated code]*/
436
437 static PyObject *
_winapi_ConnectNamedPipe_impl(PyObject * module,HANDLE handle,int use_overlapped)438 _winapi_ConnectNamedPipe_impl(PyObject *module, HANDLE handle,
439 int use_overlapped)
440 /*[clinic end generated code: output=335a0e7086800671 input=a80e56e8bd370e31]*/
441 {
442 BOOL success;
443 OverlappedObject *overlapped = NULL;
444
445 if (use_overlapped) {
446 overlapped = new_overlapped(module, handle);
447 if (!overlapped)
448 return NULL;
449 }
450
451 Py_BEGIN_ALLOW_THREADS
452 success = ConnectNamedPipe(handle,
453 overlapped ? &overlapped->overlapped : NULL);
454 Py_END_ALLOW_THREADS
455
456 if (overlapped) {
457 int err = GetLastError();
458 /* Overlapped ConnectNamedPipe never returns a success code */
459 assert(success == 0);
460 if (err == ERROR_IO_PENDING)
461 overlapped->pending = 1;
462 else if (err == ERROR_PIPE_CONNECTED)
463 SetEvent(overlapped->overlapped.hEvent);
464 else {
465 Py_DECREF(overlapped);
466 return PyErr_SetFromWindowsErr(err);
467 }
468 return (PyObject *) overlapped;
469 }
470 if (!success)
471 return PyErr_SetFromWindowsErr(0);
472
473 Py_RETURN_NONE;
474 }
475
476 /*[clinic input]
477 _winapi.CreateEventW -> HANDLE
478
479 security_attributes: LPSECURITY_ATTRIBUTES
480 manual_reset: BOOL
481 initial_state: BOOL
482 name: LPCWSTR(accept={str, NoneType})
483 [clinic start generated code]*/
484
485 static HANDLE
_winapi_CreateEventW_impl(PyObject * module,LPSECURITY_ATTRIBUTES security_attributes,BOOL manual_reset,BOOL initial_state,LPCWSTR name)486 _winapi_CreateEventW_impl(PyObject *module,
487 LPSECURITY_ATTRIBUTES security_attributes,
488 BOOL manual_reset, BOOL initial_state,
489 LPCWSTR name)
490 /*[clinic end generated code: output=2d4c7d5852ecb298 input=4187cee28ac763f8]*/
491 {
492 HANDLE handle;
493
494 if (PySys_Audit("_winapi.CreateEventW", "bbu", manual_reset, initial_state, name) < 0) {
495 return INVALID_HANDLE_VALUE;
496 }
497
498 Py_BEGIN_ALLOW_THREADS
499 handle = CreateEventW(security_attributes, manual_reset, initial_state, name);
500 Py_END_ALLOW_THREADS
501
502 if (handle == INVALID_HANDLE_VALUE) {
503 PyErr_SetFromWindowsErr(0);
504 }
505
506 return handle;
507 }
508
509 /*[clinic input]
510 _winapi.CreateFile -> HANDLE
511
512 file_name: LPCWSTR
513 desired_access: DWORD
514 share_mode: DWORD
515 security_attributes: LPSECURITY_ATTRIBUTES
516 creation_disposition: DWORD
517 flags_and_attributes: DWORD
518 template_file: HANDLE
519 /
520 [clinic start generated code]*/
521
522 static HANDLE
_winapi_CreateFile_impl(PyObject * module,LPCWSTR file_name,DWORD desired_access,DWORD share_mode,LPSECURITY_ATTRIBUTES security_attributes,DWORD creation_disposition,DWORD flags_and_attributes,HANDLE template_file)523 _winapi_CreateFile_impl(PyObject *module, LPCWSTR file_name,
524 DWORD desired_access, DWORD share_mode,
525 LPSECURITY_ATTRIBUTES security_attributes,
526 DWORD creation_disposition,
527 DWORD flags_and_attributes, HANDLE template_file)
528 /*[clinic end generated code: output=818c811e5e04d550 input=1fa870ed1c2e3d69]*/
529 {
530 HANDLE handle;
531
532 if (PySys_Audit("_winapi.CreateFile", "ukkkk",
533 file_name, desired_access, share_mode,
534 creation_disposition, flags_and_attributes) < 0) {
535 return INVALID_HANDLE_VALUE;
536 }
537
538 Py_BEGIN_ALLOW_THREADS
539 handle = CreateFileW(file_name, desired_access,
540 share_mode, security_attributes,
541 creation_disposition,
542 flags_and_attributes, template_file);
543 Py_END_ALLOW_THREADS
544
545 if (handle == INVALID_HANDLE_VALUE) {
546 PyErr_SetFromWindowsErr(0);
547 }
548
549 return handle;
550 }
551
552 /*[clinic input]
553 _winapi.CreateFileMapping -> HANDLE
554
555 file_handle: HANDLE
556 security_attributes: LPSECURITY_ATTRIBUTES
557 protect: DWORD
558 max_size_high: DWORD
559 max_size_low: DWORD
560 name: LPCWSTR
561 /
562 [clinic start generated code]*/
563
564 static HANDLE
_winapi_CreateFileMapping_impl(PyObject * module,HANDLE file_handle,LPSECURITY_ATTRIBUTES security_attributes,DWORD protect,DWORD max_size_high,DWORD max_size_low,LPCWSTR name)565 _winapi_CreateFileMapping_impl(PyObject *module, HANDLE file_handle,
566 LPSECURITY_ATTRIBUTES security_attributes,
567 DWORD protect, DWORD max_size_high,
568 DWORD max_size_low, LPCWSTR name)
569 /*[clinic end generated code: output=6c0a4d5cf7f6fcc6 input=3dc5cf762a74dee8]*/
570 {
571 HANDLE handle;
572
573 Py_BEGIN_ALLOW_THREADS
574 handle = CreateFileMappingW(file_handle, security_attributes,
575 protect, max_size_high, max_size_low,
576 name);
577 Py_END_ALLOW_THREADS
578
579 if (handle == NULL) {
580 PyObject *temp = PyUnicode_FromWideChar(name, -1);
581 PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, 0, temp);
582 Py_XDECREF(temp);
583 handle = INVALID_HANDLE_VALUE;
584 }
585
586 return handle;
587 }
588
589 /*[clinic input]
590 _winapi.CreateJunction
591
592 src_path: LPCWSTR
593 dst_path: LPCWSTR
594 /
595 [clinic start generated code]*/
596
597 static PyObject *
_winapi_CreateJunction_impl(PyObject * module,LPCWSTR src_path,LPCWSTR dst_path)598 _winapi_CreateJunction_impl(PyObject *module, LPCWSTR src_path,
599 LPCWSTR dst_path)
600 /*[clinic end generated code: output=44b3f5e9bbcc4271 input=963d29b44b9384a7]*/
601 {
602 /* Privilege adjustment */
603 HANDLE token = NULL;
604 struct {
605 TOKEN_PRIVILEGES base;
606 /* overallocate by a few array elements */
607 LUID_AND_ATTRIBUTES privs[4];
608 } tp, previousTp;
609 int previousTpSize = 0;
610
611 /* Reparse data buffer */
612 const USHORT prefix_len = 4;
613 USHORT print_len = 0;
614 USHORT rdb_size = 0;
615 _Py_PREPARSE_DATA_BUFFER rdb = NULL;
616
617 /* Junction point creation */
618 HANDLE junction = NULL;
619 DWORD ret = 0;
620
621 if (src_path == NULL || dst_path == NULL)
622 return PyErr_SetFromWindowsErr(ERROR_INVALID_PARAMETER);
623
624 if (wcsncmp(src_path, L"\\??\\", prefix_len) == 0)
625 return PyErr_SetFromWindowsErr(ERROR_INVALID_PARAMETER);
626
627 if (PySys_Audit("_winapi.CreateJunction", "uu", src_path, dst_path) < 0) {
628 return NULL;
629 }
630
631 /* Adjust privileges to allow rewriting directory entry as a
632 junction point. */
633 if (!OpenProcessToken(GetCurrentProcess(),
634 TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) {
635 goto cleanup;
636 }
637
638 if (!LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &tp.base.Privileges[0].Luid)) {
639 goto cleanup;
640 }
641
642 tp.base.PrivilegeCount = 1;
643 tp.base.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
644 if (!AdjustTokenPrivileges(token, FALSE, &tp.base, sizeof(previousTp),
645 &previousTp.base, &previousTpSize)) {
646 goto cleanup;
647 }
648
649 if (GetFileAttributesW(src_path) == INVALID_FILE_ATTRIBUTES)
650 goto cleanup;
651
652 /* Store the absolute link target path length in print_len. */
653 print_len = (USHORT)GetFullPathNameW(src_path, 0, NULL, NULL);
654 if (print_len == 0)
655 goto cleanup;
656
657 /* NUL terminator should not be part of print_len. */
658 --print_len;
659
660 /* REPARSE_DATA_BUFFER usage is heavily under-documented, especially for
661 junction points. Here's what I've learned along the way:
662 - A junction point has two components: a print name and a substitute
663 name. They both describe the link target, but the substitute name is
664 the physical target and the print name is shown in directory listings.
665 - The print name must be a native name, prefixed with "\??\".
666 - Both names are stored after each other in the same buffer (the
667 PathBuffer) and both must be NUL-terminated.
668 - There are four members defining their respective offset and length
669 inside PathBuffer: SubstituteNameOffset, SubstituteNameLength,
670 PrintNameOffset and PrintNameLength.
671 - The total size we need to allocate for the REPARSE_DATA_BUFFER, thus,
672 is the sum of:
673 - the fixed header size (REPARSE_DATA_BUFFER_HEADER_SIZE)
674 - the size of the MountPointReparseBuffer member without the PathBuffer
675 - the size of the prefix ("\??\") in bytes
676 - the size of the print name in bytes
677 - the size of the substitute name in bytes
678 - the size of two NUL terminators in bytes */
679 rdb_size = _Py_REPARSE_DATA_BUFFER_HEADER_SIZE +
680 sizeof(rdb->MountPointReparseBuffer) -
681 sizeof(rdb->MountPointReparseBuffer.PathBuffer) +
682 /* Two +1's for NUL terminators. */
683 (prefix_len + print_len + 1 + print_len + 1) * sizeof(WCHAR);
684 rdb = (_Py_PREPARSE_DATA_BUFFER)PyMem_RawCalloc(1, rdb_size);
685 if (rdb == NULL)
686 goto cleanup;
687
688 rdb->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
689 rdb->ReparseDataLength = rdb_size - _Py_REPARSE_DATA_BUFFER_HEADER_SIZE;
690 rdb->MountPointReparseBuffer.SubstituteNameOffset = 0;
691 rdb->MountPointReparseBuffer.SubstituteNameLength =
692 (prefix_len + print_len) * sizeof(WCHAR);
693 rdb->MountPointReparseBuffer.PrintNameOffset =
694 rdb->MountPointReparseBuffer.SubstituteNameLength + sizeof(WCHAR);
695 rdb->MountPointReparseBuffer.PrintNameLength = print_len * sizeof(WCHAR);
696
697 /* Store the full native path of link target at the substitute name
698 offset (0). */
699 wcscpy(rdb->MountPointReparseBuffer.PathBuffer, L"\\??\\");
700 if (GetFullPathNameW(src_path, print_len + 1,
701 rdb->MountPointReparseBuffer.PathBuffer + prefix_len,
702 NULL) == 0)
703 goto cleanup;
704
705 /* Copy everything but the native prefix to the print name offset. */
706 wcscpy(rdb->MountPointReparseBuffer.PathBuffer +
707 prefix_len + print_len + 1,
708 rdb->MountPointReparseBuffer.PathBuffer + prefix_len);
709
710 /* Create a directory for the junction point. */
711 if (!CreateDirectoryW(dst_path, NULL))
712 goto cleanup;
713
714 junction = CreateFileW(dst_path, GENERIC_READ | GENERIC_WRITE, 0, NULL,
715 OPEN_EXISTING,
716 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
717 if (junction == INVALID_HANDLE_VALUE)
718 goto cleanup;
719
720 /* Make the directory entry a junction point. */
721 if (!DeviceIoControl(junction, FSCTL_SET_REPARSE_POINT, rdb, rdb_size,
722 NULL, 0, &ret, NULL))
723 goto cleanup;
724
725 cleanup:
726 ret = GetLastError();
727
728 if (previousTpSize) {
729 AdjustTokenPrivileges(token, FALSE, &previousTp.base, previousTpSize,
730 NULL, NULL);
731 }
732
733 if (token != NULL)
734 CloseHandle(token);
735 if (junction != NULL)
736 CloseHandle(junction);
737 PyMem_RawFree(rdb);
738
739 if (ret != 0)
740 return PyErr_SetFromWindowsErr(ret);
741
742 Py_RETURN_NONE;
743 }
744
745 /*[clinic input]
746 _winapi.CreateMutexW -> HANDLE
747
748 security_attributes: LPSECURITY_ATTRIBUTES
749 initial_owner: BOOL
750 name: LPCWSTR(accept={str, NoneType})
751 [clinic start generated code]*/
752
753 static HANDLE
_winapi_CreateMutexW_impl(PyObject * module,LPSECURITY_ATTRIBUTES security_attributes,BOOL initial_owner,LPCWSTR name)754 _winapi_CreateMutexW_impl(PyObject *module,
755 LPSECURITY_ATTRIBUTES security_attributes,
756 BOOL initial_owner, LPCWSTR name)
757 /*[clinic end generated code: output=31b9ee8fc37e49a5 input=7d54b921e723254a]*/
758 {
759 HANDLE handle;
760
761 if (PySys_Audit("_winapi.CreateMutexW", "bu", initial_owner, name) < 0) {
762 return INVALID_HANDLE_VALUE;
763 }
764
765 Py_BEGIN_ALLOW_THREADS
766 handle = CreateMutexW(security_attributes, initial_owner, name);
767 Py_END_ALLOW_THREADS
768
769 if (handle == INVALID_HANDLE_VALUE) {
770 PyErr_SetFromWindowsErr(0);
771 }
772
773 return handle;
774 }
775
776 /*[clinic input]
777 _winapi.CreateNamedPipe -> HANDLE
778
779 name: LPCWSTR
780 open_mode: DWORD
781 pipe_mode: DWORD
782 max_instances: DWORD
783 out_buffer_size: DWORD
784 in_buffer_size: DWORD
785 default_timeout: DWORD
786 security_attributes: LPSECURITY_ATTRIBUTES
787 /
788 [clinic start generated code]*/
789
790 static HANDLE
_winapi_CreateNamedPipe_impl(PyObject * module,LPCWSTR name,DWORD open_mode,DWORD pipe_mode,DWORD max_instances,DWORD out_buffer_size,DWORD in_buffer_size,DWORD default_timeout,LPSECURITY_ATTRIBUTES security_attributes)791 _winapi_CreateNamedPipe_impl(PyObject *module, LPCWSTR name, DWORD open_mode,
792 DWORD pipe_mode, DWORD max_instances,
793 DWORD out_buffer_size, DWORD in_buffer_size,
794 DWORD default_timeout,
795 LPSECURITY_ATTRIBUTES security_attributes)
796 /*[clinic end generated code: output=7d6fde93227680ba input=5bd4e4a55639ee02]*/
797 {
798 HANDLE handle;
799
800 if (PySys_Audit("_winapi.CreateNamedPipe", "ukk",
801 name, open_mode, pipe_mode) < 0) {
802 return INVALID_HANDLE_VALUE;
803 }
804
805 Py_BEGIN_ALLOW_THREADS
806 handle = CreateNamedPipeW(name, open_mode, pipe_mode,
807 max_instances, out_buffer_size,
808 in_buffer_size, default_timeout,
809 security_attributes);
810 Py_END_ALLOW_THREADS
811
812 if (handle == INVALID_HANDLE_VALUE)
813 PyErr_SetFromWindowsErr(0);
814
815 return handle;
816 }
817
818 /*[clinic input]
819 _winapi.CreatePipe
820
821 pipe_attrs: object
822 Ignored internally, can be None.
823 size: DWORD
824 /
825
826 Create an anonymous pipe.
827
828 Returns a 2-tuple of handles, to the read and write ends of the pipe.
829 [clinic start generated code]*/
830
831 static PyObject *
_winapi_CreatePipe_impl(PyObject * module,PyObject * pipe_attrs,DWORD size)832 _winapi_CreatePipe_impl(PyObject *module, PyObject *pipe_attrs, DWORD size)
833 /*[clinic end generated code: output=1c4411d8699f0925 input=c4f2cfa56ef68d90]*/
834 {
835 HANDLE read_pipe;
836 HANDLE write_pipe;
837 BOOL result;
838
839 if (PySys_Audit("_winapi.CreatePipe", NULL) < 0) {
840 return NULL;
841 }
842
843 Py_BEGIN_ALLOW_THREADS
844 result = CreatePipe(&read_pipe, &write_pipe, NULL, size);
845 Py_END_ALLOW_THREADS
846
847 if (! result)
848 return PyErr_SetFromWindowsErr(GetLastError());
849
850 return Py_BuildValue(
851 "NN", HANDLE_TO_PYNUM(read_pipe), HANDLE_TO_PYNUM(write_pipe));
852 }
853
854 /* helpers for createprocess */
855
856 static unsigned long
getulong(PyObject * obj,const char * name)857 getulong(PyObject* obj, const char* name)
858 {
859 PyObject* value;
860 unsigned long ret;
861
862 value = PyObject_GetAttrString(obj, name);
863 if (! value) {
864 PyErr_Clear(); /* FIXME: propagate error? */
865 return 0;
866 }
867 ret = PyLong_AsUnsignedLong(value);
868 Py_DECREF(value);
869 return ret;
870 }
871
872 static HANDLE
gethandle(PyObject * obj,const char * name)873 gethandle(PyObject* obj, const char* name)
874 {
875 PyObject* value;
876 HANDLE ret;
877
878 value = PyObject_GetAttrString(obj, name);
879 if (! value) {
880 PyErr_Clear(); /* FIXME: propagate error? */
881 return NULL;
882 }
883 if (value == Py_None)
884 ret = NULL;
885 else
886 ret = PYNUM_TO_HANDLE(value);
887 Py_DECREF(value);
888 return ret;
889 }
890
891 static PyObject *
sortenvironmentkey(PyObject * module,PyObject * item)892 sortenvironmentkey(PyObject *module, PyObject *item)
893 {
894 return _winapi_LCMapStringEx_impl(NULL, LOCALE_NAME_INVARIANT,
895 LCMAP_UPPERCASE, item);
896 }
897
898 static PyMethodDef sortenvironmentkey_def = {
899 "sortenvironmentkey", _PyCFunction_CAST(sortenvironmentkey), METH_O, "",
900 };
901
902 static int
sort_environment_keys(PyObject * keys)903 sort_environment_keys(PyObject *keys)
904 {
905 PyObject *keyfunc = PyCFunction_New(&sortenvironmentkey_def, NULL);
906 if (keyfunc == NULL) {
907 return -1;
908 }
909 PyObject *kwnames = Py_BuildValue("(s)", "key");
910 if (kwnames == NULL) {
911 Py_DECREF(keyfunc);
912 return -1;
913 }
914 PyObject *args[] = { keys, keyfunc };
915 PyObject *ret = PyObject_VectorcallMethod(&_Py_ID(sort), args, 1, kwnames);
916 Py_DECREF(keyfunc);
917 Py_DECREF(kwnames);
918 if (ret == NULL) {
919 return -1;
920 }
921 Py_DECREF(ret);
922
923 return 0;
924 }
925
926 static int
compare_string_ordinal(PyObject * str1,PyObject * str2,int * result)927 compare_string_ordinal(PyObject *str1, PyObject *str2, int *result)
928 {
929 wchar_t *s1 = PyUnicode_AsWideCharString(str1, NULL);
930 if (s1 == NULL) {
931 return -1;
932 }
933 wchar_t *s2 = PyUnicode_AsWideCharString(str2, NULL);
934 if (s2 == NULL) {
935 PyMem_Free(s1);
936 return -1;
937 }
938 *result = CompareStringOrdinal(s1, -1, s2, -1, TRUE);
939 PyMem_Free(s1);
940 PyMem_Free(s2);
941 return 0;
942 }
943
944 static PyObject *
dedup_environment_keys(PyObject * keys)945 dedup_environment_keys(PyObject *keys)
946 {
947 PyObject *result = PyList_New(0);
948 if (result == NULL) {
949 return NULL;
950 }
951
952 // Iterate over the pre-ordered keys, check whether the current key is equal
953 // to the next key (ignoring case), if different, insert the current value
954 // into the result list. If they are equal, do nothing because we always
955 // want to keep the last inserted one.
956 for (Py_ssize_t i = 0; i < PyList_GET_SIZE(keys); i++) {
957 PyObject *key = PyList_GET_ITEM(keys, i);
958
959 // The last key will always be kept.
960 if (i + 1 == PyList_GET_SIZE(keys)) {
961 if (PyList_Append(result, key) < 0) {
962 Py_DECREF(result);
963 return NULL;
964 }
965 continue;
966 }
967
968 PyObject *next_key = PyList_GET_ITEM(keys, i + 1);
969 int compare_result;
970 if (compare_string_ordinal(key, next_key, &compare_result) < 0) {
971 Py_DECREF(result);
972 return NULL;
973 }
974 if (compare_result == CSTR_EQUAL) {
975 continue;
976 }
977 if (PyList_Append(result, key) < 0) {
978 Py_DECREF(result);
979 return NULL;
980 }
981 }
982
983 return result;
984 }
985
986 static PyObject *
normalize_environment(PyObject * environment)987 normalize_environment(PyObject *environment)
988 {
989 PyObject *keys = PyMapping_Keys(environment);
990 if (keys == NULL) {
991 return NULL;
992 }
993
994 if (sort_environment_keys(keys) < 0) {
995 Py_DECREF(keys);
996 return NULL;
997 }
998
999 PyObject *normalized_keys = dedup_environment_keys(keys);
1000 Py_DECREF(keys);
1001 if (normalized_keys == NULL) {
1002 return NULL;
1003 }
1004
1005 PyObject *result = PyDict_New();
1006 if (result == NULL) {
1007 Py_DECREF(normalized_keys);
1008 return NULL;
1009 }
1010
1011 for (int i = 0; i < PyList_GET_SIZE(normalized_keys); i++) {
1012 PyObject *key = PyList_GET_ITEM(normalized_keys, i);
1013 PyObject *value = PyObject_GetItem(environment, key);
1014 if (value == NULL) {
1015 Py_DECREF(normalized_keys);
1016 Py_DECREF(result);
1017 return NULL;
1018 }
1019
1020 int ret = PyObject_SetItem(result, key, value);
1021 Py_DECREF(value);
1022 if (ret < 0) {
1023 Py_DECREF(normalized_keys);
1024 Py_DECREF(result);
1025 return NULL;
1026 }
1027 }
1028
1029 Py_DECREF(normalized_keys);
1030
1031 return result;
1032 }
1033
1034 static wchar_t *
getenvironment(PyObject * environment)1035 getenvironment(PyObject* environment)
1036 {
1037 Py_ssize_t i, envsize, totalsize;
1038 wchar_t *buffer = NULL, *p, *end;
1039 PyObject *normalized_environment = NULL;
1040 PyObject *keys = NULL;
1041 PyObject *values = NULL;
1042
1043 /* convert environment dictionary to windows environment string */
1044 if (! PyMapping_Check(environment)) {
1045 PyErr_SetString(
1046 PyExc_TypeError, "environment must be dictionary or None");
1047 return NULL;
1048 }
1049
1050 normalized_environment = normalize_environment(environment);
1051 if (normalize_environment == NULL) {
1052 return NULL;
1053 }
1054
1055 keys = PyMapping_Keys(normalized_environment);
1056 if (!keys) {
1057 goto error;
1058 }
1059 values = PyMapping_Values(normalized_environment);
1060 if (!values) {
1061 goto error;
1062 }
1063
1064 envsize = PyList_GET_SIZE(keys);
1065
1066 if (envsize == 0) {
1067 // A environment block must be terminated by two null characters --
1068 // one for the last string and one for the block.
1069 buffer = PyMem_Calloc(2, sizeof(wchar_t));
1070 if (!buffer) {
1071 PyErr_NoMemory();
1072 }
1073 goto cleanup;
1074 }
1075
1076 if (PyList_GET_SIZE(values) != envsize) {
1077 PyErr_SetString(PyExc_RuntimeError,
1078 "environment changed size during iteration");
1079 goto error;
1080 }
1081
1082 totalsize = 1; /* trailing null character */
1083 for (i = 0; i < envsize; i++) {
1084 PyObject* key = PyList_GET_ITEM(keys, i);
1085 PyObject* value = PyList_GET_ITEM(values, i);
1086 Py_ssize_t size;
1087
1088 if (! PyUnicode_Check(key) || ! PyUnicode_Check(value)) {
1089 PyErr_SetString(PyExc_TypeError,
1090 "environment can only contain strings");
1091 goto error;
1092 }
1093 if (PyUnicode_FindChar(key, '\0', 0, PyUnicode_GET_LENGTH(key), 1) != -1 ||
1094 PyUnicode_FindChar(value, '\0', 0, PyUnicode_GET_LENGTH(value), 1) != -1)
1095 {
1096 PyErr_SetString(PyExc_ValueError, "embedded null character");
1097 goto error;
1098 }
1099 /* Search from index 1 because on Windows starting '=' is allowed for
1100 defining hidden environment variables. */
1101 if (PyUnicode_GET_LENGTH(key) == 0 ||
1102 PyUnicode_FindChar(key, '=', 1, PyUnicode_GET_LENGTH(key), 1) != -1)
1103 {
1104 PyErr_SetString(PyExc_ValueError, "illegal environment variable name");
1105 goto error;
1106 }
1107
1108 size = PyUnicode_AsWideChar(key, NULL, 0);
1109 assert(size > 1);
1110 if (totalsize > PY_SSIZE_T_MAX - size) {
1111 PyErr_SetString(PyExc_OverflowError, "environment too long");
1112 goto error;
1113 }
1114 totalsize += size; /* including '=' */
1115
1116 size = PyUnicode_AsWideChar(value, NULL, 0);
1117 assert(size > 0);
1118 if (totalsize > PY_SSIZE_T_MAX - size) {
1119 PyErr_SetString(PyExc_OverflowError, "environment too long");
1120 goto error;
1121 }
1122 totalsize += size; /* including trailing '\0' */
1123 }
1124
1125 buffer = PyMem_NEW(wchar_t, totalsize);
1126 if (! buffer) {
1127 PyErr_NoMemory();
1128 goto error;
1129 }
1130 p = buffer;
1131 end = buffer + totalsize;
1132
1133 for (i = 0; i < envsize; i++) {
1134 PyObject* key = PyList_GET_ITEM(keys, i);
1135 PyObject* value = PyList_GET_ITEM(values, i);
1136 Py_ssize_t size = PyUnicode_AsWideChar(key, p, end - p);
1137 assert(1 <= size && size < end - p);
1138 p += size;
1139 *p++ = L'=';
1140 size = PyUnicode_AsWideChar(value, p, end - p);
1141 assert(0 <= size && size < end - p);
1142 p += size + 1;
1143 }
1144
1145 /* add trailing null character */
1146 *p++ = L'\0';
1147 assert(p == end);
1148
1149 cleanup:
1150 error:
1151 Py_XDECREF(normalized_environment);
1152 Py_XDECREF(keys);
1153 Py_XDECREF(values);
1154 return buffer;
1155 }
1156
1157 static LPHANDLE
gethandlelist(PyObject * mapping,const char * name,Py_ssize_t * size)1158 gethandlelist(PyObject *mapping, const char *name, Py_ssize_t *size)
1159 {
1160 LPHANDLE ret = NULL;
1161 PyObject *value_fast = NULL;
1162 PyObject *value;
1163 Py_ssize_t i;
1164
1165 value = PyMapping_GetItemString(mapping, name);
1166 if (!value) {
1167 PyErr_Clear();
1168 return NULL;
1169 }
1170
1171 if (value == Py_None) {
1172 goto cleanup;
1173 }
1174
1175 value_fast = PySequence_Fast(value, "handle_list must be a sequence or None");
1176 if (value_fast == NULL)
1177 goto cleanup;
1178
1179 *size = PySequence_Fast_GET_SIZE(value_fast) * sizeof(HANDLE);
1180
1181 /* Passing an empty array causes CreateProcess to fail so just don't set it */
1182 if (*size == 0) {
1183 goto cleanup;
1184 }
1185
1186 ret = PyMem_Malloc(*size);
1187 if (ret == NULL)
1188 goto cleanup;
1189
1190 for (i = 0; i < PySequence_Fast_GET_SIZE(value_fast); i++) {
1191 ret[i] = PYNUM_TO_HANDLE(PySequence_Fast_GET_ITEM(value_fast, i));
1192 if (ret[i] == (HANDLE)-1 && PyErr_Occurred()) {
1193 PyMem_Free(ret);
1194 ret = NULL;
1195 goto cleanup;
1196 }
1197 }
1198
1199 cleanup:
1200 Py_DECREF(value);
1201 Py_XDECREF(value_fast);
1202 return ret;
1203 }
1204
1205 typedef struct {
1206 LPPROC_THREAD_ATTRIBUTE_LIST attribute_list;
1207 LPHANDLE handle_list;
1208 } AttributeList;
1209
1210 static void
freeattributelist(AttributeList * attribute_list)1211 freeattributelist(AttributeList *attribute_list)
1212 {
1213 if (attribute_list->attribute_list != NULL) {
1214 DeleteProcThreadAttributeList(attribute_list->attribute_list);
1215 PyMem_Free(attribute_list->attribute_list);
1216 }
1217
1218 PyMem_Free(attribute_list->handle_list);
1219
1220 memset(attribute_list, 0, sizeof(*attribute_list));
1221 }
1222
1223 static int
getattributelist(PyObject * obj,const char * name,AttributeList * attribute_list)1224 getattributelist(PyObject *obj, const char *name, AttributeList *attribute_list)
1225 {
1226 int ret = 0;
1227 DWORD err;
1228 BOOL result;
1229 PyObject *value;
1230 Py_ssize_t handle_list_size;
1231 DWORD attribute_count = 0;
1232 SIZE_T attribute_list_size = 0;
1233
1234 value = PyObject_GetAttrString(obj, name);
1235 if (!value) {
1236 PyErr_Clear(); /* FIXME: propagate error? */
1237 return 0;
1238 }
1239
1240 if (value == Py_None) {
1241 ret = 0;
1242 goto cleanup;
1243 }
1244
1245 if (!PyMapping_Check(value)) {
1246 ret = -1;
1247 PyErr_Format(PyExc_TypeError, "%s must be a mapping or None", name);
1248 goto cleanup;
1249 }
1250
1251 attribute_list->handle_list = gethandlelist(value, "handle_list", &handle_list_size);
1252 if (attribute_list->handle_list == NULL && PyErr_Occurred()) {
1253 ret = -1;
1254 goto cleanup;
1255 }
1256
1257 if (attribute_list->handle_list != NULL)
1258 ++attribute_count;
1259
1260 /* Get how many bytes we need for the attribute list */
1261 result = InitializeProcThreadAttributeList(NULL, attribute_count, 0, &attribute_list_size);
1262 if (result || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
1263 ret = -1;
1264 PyErr_SetFromWindowsErr(GetLastError());
1265 goto cleanup;
1266 }
1267
1268 attribute_list->attribute_list = PyMem_Malloc(attribute_list_size);
1269 if (attribute_list->attribute_list == NULL) {
1270 ret = -1;
1271 goto cleanup;
1272 }
1273
1274 result = InitializeProcThreadAttributeList(
1275 attribute_list->attribute_list,
1276 attribute_count,
1277 0,
1278 &attribute_list_size);
1279 if (!result) {
1280 err = GetLastError();
1281
1282 /* So that we won't call DeleteProcThreadAttributeList */
1283 PyMem_Free(attribute_list->attribute_list);
1284 attribute_list->attribute_list = NULL;
1285
1286 ret = -1;
1287 PyErr_SetFromWindowsErr(err);
1288 goto cleanup;
1289 }
1290
1291 if (attribute_list->handle_list != NULL) {
1292 result = UpdateProcThreadAttribute(
1293 attribute_list->attribute_list,
1294 0,
1295 PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
1296 attribute_list->handle_list,
1297 handle_list_size,
1298 NULL,
1299 NULL);
1300 if (!result) {
1301 ret = -1;
1302 PyErr_SetFromWindowsErr(GetLastError());
1303 goto cleanup;
1304 }
1305 }
1306
1307 cleanup:
1308 Py_DECREF(value);
1309
1310 if (ret < 0)
1311 freeattributelist(attribute_list);
1312
1313 return ret;
1314 }
1315
1316 /*[clinic input]
1317 _winapi.CreateProcess
1318
1319 application_name: Py_UNICODE(accept={str, NoneType})
1320 command_line: object
1321 Can be str or None
1322 proc_attrs: object
1323 Ignored internally, can be None.
1324 thread_attrs: object
1325 Ignored internally, can be None.
1326 inherit_handles: BOOL
1327 creation_flags: DWORD
1328 env_mapping: object
1329 current_directory: Py_UNICODE(accept={str, NoneType})
1330 startup_info: object
1331 /
1332
1333 Create a new process and its primary thread.
1334
1335 The return value is a tuple of the process handle, thread handle,
1336 process ID, and thread ID.
1337 [clinic start generated code]*/
1338
1339 static PyObject *
_winapi_CreateProcess_impl(PyObject * module,const wchar_t * application_name,PyObject * command_line,PyObject * proc_attrs,PyObject * thread_attrs,BOOL inherit_handles,DWORD creation_flags,PyObject * env_mapping,const wchar_t * current_directory,PyObject * startup_info)1340 _winapi_CreateProcess_impl(PyObject *module, const wchar_t *application_name,
1341 PyObject *command_line, PyObject *proc_attrs,
1342 PyObject *thread_attrs, BOOL inherit_handles,
1343 DWORD creation_flags, PyObject *env_mapping,
1344 const wchar_t *current_directory,
1345 PyObject *startup_info)
1346 /*[clinic end generated code: output=a25c8e49ea1d6427 input=42ac293eaea03fc4]*/
1347 {
1348 PyObject *ret = NULL;
1349 BOOL result;
1350 PROCESS_INFORMATION pi;
1351 STARTUPINFOEXW si;
1352 wchar_t *wenvironment = NULL;
1353 wchar_t *command_line_copy = NULL;
1354 AttributeList attribute_list = {0};
1355
1356 if (PySys_Audit("_winapi.CreateProcess", "uuu", application_name,
1357 command_line, current_directory) < 0) {
1358 return NULL;
1359 }
1360
1361 ZeroMemory(&si, sizeof(si));
1362 si.StartupInfo.cb = sizeof(si);
1363
1364 /* note: we only support a small subset of all SI attributes */
1365 si.StartupInfo.dwFlags = getulong(startup_info, "dwFlags");
1366 si.StartupInfo.wShowWindow = (WORD)getulong(startup_info, "wShowWindow");
1367 si.StartupInfo.hStdInput = gethandle(startup_info, "hStdInput");
1368 si.StartupInfo.hStdOutput = gethandle(startup_info, "hStdOutput");
1369 si.StartupInfo.hStdError = gethandle(startup_info, "hStdError");
1370 if (PyErr_Occurred())
1371 goto cleanup;
1372
1373 if (env_mapping != Py_None) {
1374 wenvironment = getenvironment(env_mapping);
1375 if (wenvironment == NULL) {
1376 goto cleanup;
1377 }
1378 }
1379
1380 if (getattributelist(startup_info, "lpAttributeList", &attribute_list) < 0)
1381 goto cleanup;
1382
1383 si.lpAttributeList = attribute_list.attribute_list;
1384 if (PyUnicode_Check(command_line)) {
1385 command_line_copy = PyUnicode_AsWideCharString(command_line, NULL);
1386 if (command_line_copy == NULL) {
1387 goto cleanup;
1388 }
1389 }
1390 else if (command_line != Py_None) {
1391 PyErr_Format(PyExc_TypeError,
1392 "CreateProcess() argument 2 must be str or None, not %s",
1393 Py_TYPE(command_line)->tp_name);
1394 goto cleanup;
1395 }
1396
1397
1398 Py_BEGIN_ALLOW_THREADS
1399 result = CreateProcessW(application_name,
1400 command_line_copy,
1401 NULL,
1402 NULL,
1403 inherit_handles,
1404 creation_flags | EXTENDED_STARTUPINFO_PRESENT |
1405 CREATE_UNICODE_ENVIRONMENT,
1406 wenvironment,
1407 current_directory,
1408 (LPSTARTUPINFOW)&si,
1409 &pi);
1410 Py_END_ALLOW_THREADS
1411
1412 if (!result) {
1413 PyErr_SetFromWindowsErr(GetLastError());
1414 goto cleanup;
1415 }
1416
1417 ret = Py_BuildValue("NNkk",
1418 HANDLE_TO_PYNUM(pi.hProcess),
1419 HANDLE_TO_PYNUM(pi.hThread),
1420 pi.dwProcessId,
1421 pi.dwThreadId);
1422
1423 cleanup:
1424 PyMem_Free(command_line_copy);
1425 PyMem_Free(wenvironment);
1426 freeattributelist(&attribute_list);
1427
1428 return ret;
1429 }
1430
1431 /*[clinic input]
1432 _winapi.DuplicateHandle -> HANDLE
1433
1434 source_process_handle: HANDLE
1435 source_handle: HANDLE
1436 target_process_handle: HANDLE
1437 desired_access: DWORD
1438 inherit_handle: BOOL
1439 options: DWORD = 0
1440 /
1441
1442 Return a duplicate handle object.
1443
1444 The duplicate handle refers to the same object as the original
1445 handle. Therefore, any changes to the object are reflected
1446 through both handles.
1447 [clinic start generated code]*/
1448
1449 static HANDLE
_winapi_DuplicateHandle_impl(PyObject * module,HANDLE source_process_handle,HANDLE source_handle,HANDLE target_process_handle,DWORD desired_access,BOOL inherit_handle,DWORD options)1450 _winapi_DuplicateHandle_impl(PyObject *module, HANDLE source_process_handle,
1451 HANDLE source_handle,
1452 HANDLE target_process_handle,
1453 DWORD desired_access, BOOL inherit_handle,
1454 DWORD options)
1455 /*[clinic end generated code: output=ad9711397b5dcd4e input=b933e3f2356a8c12]*/
1456 {
1457 HANDLE target_handle;
1458 BOOL result;
1459
1460 Py_BEGIN_ALLOW_THREADS
1461 result = DuplicateHandle(
1462 source_process_handle,
1463 source_handle,
1464 target_process_handle,
1465 &target_handle,
1466 desired_access,
1467 inherit_handle,
1468 options
1469 );
1470 Py_END_ALLOW_THREADS
1471
1472 if (! result) {
1473 PyErr_SetFromWindowsErr(GetLastError());
1474 return INVALID_HANDLE_VALUE;
1475 }
1476
1477 return target_handle;
1478 }
1479
1480 /*[clinic input]
1481 _winapi.ExitProcess
1482
1483 ExitCode: UINT
1484 /
1485
1486 [clinic start generated code]*/
1487
1488 static PyObject *
_winapi_ExitProcess_impl(PyObject * module,UINT ExitCode)1489 _winapi_ExitProcess_impl(PyObject *module, UINT ExitCode)
1490 /*[clinic end generated code: output=a387deb651175301 input=4f05466a9406c558]*/
1491 {
1492 #if defined(Py_DEBUG)
1493 #ifdef MS_WINDOWS_DESKTOP
1494 SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOALIGNMENTFAULTEXCEPT|
1495 SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX);
1496 #endif
1497 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
1498 #endif
1499
1500 ExitProcess(ExitCode);
1501
1502 return NULL;
1503 }
1504
1505 /*[clinic input]
1506 _winapi.GetCurrentProcess -> HANDLE
1507
1508 Return a handle object for the current process.
1509 [clinic start generated code]*/
1510
1511 static HANDLE
_winapi_GetCurrentProcess_impl(PyObject * module)1512 _winapi_GetCurrentProcess_impl(PyObject *module)
1513 /*[clinic end generated code: output=ddeb4dd2ffadf344 input=b213403fd4b96b41]*/
1514 {
1515 return GetCurrentProcess();
1516 }
1517
1518 /*[clinic input]
1519 _winapi.GetExitCodeProcess -> DWORD
1520
1521 process: HANDLE
1522 /
1523
1524 Return the termination status of the specified process.
1525 [clinic start generated code]*/
1526
1527 static DWORD
_winapi_GetExitCodeProcess_impl(PyObject * module,HANDLE process)1528 _winapi_GetExitCodeProcess_impl(PyObject *module, HANDLE process)
1529 /*[clinic end generated code: output=b4620bdf2bccf36b input=61b6bfc7dc2ee374]*/
1530 {
1531 DWORD exit_code;
1532 BOOL result;
1533
1534 result = GetExitCodeProcess(process, &exit_code);
1535
1536 if (! result) {
1537 PyErr_SetFromWindowsErr(GetLastError());
1538 exit_code = PY_DWORD_MAX;
1539 }
1540
1541 return exit_code;
1542 }
1543
1544 /*[clinic input]
1545 _winapi.GetLastError -> DWORD
1546 [clinic start generated code]*/
1547
1548 static DWORD
_winapi_GetLastError_impl(PyObject * module)1549 _winapi_GetLastError_impl(PyObject *module)
1550 /*[clinic end generated code: output=8585b827cb1a92c5 input=62d47fb9bce038ba]*/
1551 {
1552 return GetLastError();
1553 }
1554
1555
1556 /*[clinic input]
1557 _winapi.GetLongPathName
1558
1559 path: LPCWSTR
1560
1561 Return the long version of the provided path.
1562
1563 If the path is already in its long form, returns the same value.
1564
1565 The path must already be a 'str'. If the type is not known, use
1566 os.fsdecode before calling this function.
1567 [clinic start generated code]*/
1568
1569 static PyObject *
_winapi_GetLongPathName_impl(PyObject * module,LPCWSTR path)1570 _winapi_GetLongPathName_impl(PyObject *module, LPCWSTR path)
1571 /*[clinic end generated code: output=c4774b080275a2d0 input=9872e211e3a4a88f]*/
1572 {
1573 DWORD cchBuffer;
1574 PyObject *result = NULL;
1575
1576 Py_BEGIN_ALLOW_THREADS
1577 cchBuffer = GetLongPathNameW(path, NULL, 0);
1578 Py_END_ALLOW_THREADS
1579 if (cchBuffer) {
1580 WCHAR *buffer = (WCHAR *)PyMem_Malloc(cchBuffer * sizeof(WCHAR));
1581 if (buffer) {
1582 Py_BEGIN_ALLOW_THREADS
1583 cchBuffer = GetLongPathNameW(path, buffer, cchBuffer);
1584 Py_END_ALLOW_THREADS
1585 if (cchBuffer) {
1586 result = PyUnicode_FromWideChar(buffer, cchBuffer);
1587 } else {
1588 PyErr_SetFromWindowsErr(0);
1589 }
1590 PyMem_Free((void *)buffer);
1591 }
1592 } else {
1593 PyErr_SetFromWindowsErr(0);
1594 }
1595 return result;
1596 }
1597
1598 /*[clinic input]
1599 _winapi.GetModuleFileName
1600
1601 module_handle: HMODULE
1602 /
1603
1604 Return the fully-qualified path for the file that contains module.
1605
1606 The module must have been loaded by the current process.
1607
1608 The module parameter should be a handle to the loaded module
1609 whose path is being requested. If this parameter is 0,
1610 GetModuleFileName retrieves the path of the executable file
1611 of the current process.
1612 [clinic start generated code]*/
1613
1614 static PyObject *
_winapi_GetModuleFileName_impl(PyObject * module,HMODULE module_handle)1615 _winapi_GetModuleFileName_impl(PyObject *module, HMODULE module_handle)
1616 /*[clinic end generated code: output=85b4b728c5160306 input=6d66ff7deca5d11f]*/
1617 {
1618 BOOL result;
1619 WCHAR filename[MAX_PATH];
1620
1621 Py_BEGIN_ALLOW_THREADS
1622 result = GetModuleFileNameW(module_handle, filename, MAX_PATH);
1623 filename[MAX_PATH-1] = '\0';
1624 Py_END_ALLOW_THREADS
1625
1626 if (! result)
1627 return PyErr_SetFromWindowsErr(GetLastError());
1628
1629 return PyUnicode_FromWideChar(filename, wcslen(filename));
1630 }
1631
1632 /*[clinic input]
1633 _winapi.GetShortPathName
1634
1635 path: LPCWSTR
1636
1637 Return the short version of the provided path.
1638
1639 If the path is already in its short form, returns the same value.
1640
1641 The path must already be a 'str'. If the type is not known, use
1642 os.fsdecode before calling this function.
1643 [clinic start generated code]*/
1644
1645 static PyObject *
_winapi_GetShortPathName_impl(PyObject * module,LPCWSTR path)1646 _winapi_GetShortPathName_impl(PyObject *module, LPCWSTR path)
1647 /*[clinic end generated code: output=dab6ae494c621e81 input=43fa349aaf2ac718]*/
1648 {
1649 DWORD cchBuffer;
1650 PyObject *result = NULL;
1651
1652 Py_BEGIN_ALLOW_THREADS
1653 cchBuffer = GetShortPathNameW(path, NULL, 0);
1654 Py_END_ALLOW_THREADS
1655 if (cchBuffer) {
1656 WCHAR *buffer = (WCHAR *)PyMem_Malloc(cchBuffer * sizeof(WCHAR));
1657 if (buffer) {
1658 Py_BEGIN_ALLOW_THREADS
1659 cchBuffer = GetShortPathNameW(path, buffer, cchBuffer);
1660 Py_END_ALLOW_THREADS
1661 if (cchBuffer) {
1662 result = PyUnicode_FromWideChar(buffer, cchBuffer);
1663 } else {
1664 PyErr_SetFromWindowsErr(0);
1665 }
1666 PyMem_Free((void *)buffer);
1667 }
1668 } else {
1669 PyErr_SetFromWindowsErr(0);
1670 }
1671 return result;
1672 }
1673
1674 /*[clinic input]
1675 _winapi.GetStdHandle -> HANDLE
1676
1677 std_handle: DWORD
1678 One of STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, or STD_ERROR_HANDLE.
1679 /
1680
1681 Return a handle to the specified standard device.
1682
1683 The integer associated with the handle object is returned.
1684 [clinic start generated code]*/
1685
1686 static HANDLE
_winapi_GetStdHandle_impl(PyObject * module,DWORD std_handle)1687 _winapi_GetStdHandle_impl(PyObject *module, DWORD std_handle)
1688 /*[clinic end generated code: output=0e613001e73ab614 input=07016b06a2fc8826]*/
1689 {
1690 HANDLE handle;
1691
1692 Py_BEGIN_ALLOW_THREADS
1693 handle = GetStdHandle(std_handle);
1694 Py_END_ALLOW_THREADS
1695
1696 if (handle == INVALID_HANDLE_VALUE)
1697 PyErr_SetFromWindowsErr(GetLastError());
1698
1699 return handle;
1700 }
1701
1702 /*[clinic input]
1703 _winapi.GetVersion -> long
1704
1705 Return the version number of the current operating system.
1706 [clinic start generated code]*/
1707
1708 static long
_winapi_GetVersion_impl(PyObject * module)1709 _winapi_GetVersion_impl(PyObject *module)
1710 /*[clinic end generated code: output=e41f0db5a3b82682 input=e21dff8d0baeded2]*/
1711 /* Disable deprecation warnings about GetVersionEx as the result is
1712 being passed straight through to the caller, who is responsible for
1713 using it correctly. */
1714 #pragma warning(push)
1715 #pragma warning(disable:4996)
1716
1717 {
1718 return GetVersion();
1719 }
1720
1721 #pragma warning(pop)
1722
1723 /*[clinic input]
1724 _winapi.MapViewOfFile -> LPVOID
1725
1726 file_map: HANDLE
1727 desired_access: DWORD
1728 file_offset_high: DWORD
1729 file_offset_low: DWORD
1730 number_bytes: size_t
1731 /
1732 [clinic start generated code]*/
1733
1734 static LPVOID
_winapi_MapViewOfFile_impl(PyObject * module,HANDLE file_map,DWORD desired_access,DWORD file_offset_high,DWORD file_offset_low,size_t number_bytes)1735 _winapi_MapViewOfFile_impl(PyObject *module, HANDLE file_map,
1736 DWORD desired_access, DWORD file_offset_high,
1737 DWORD file_offset_low, size_t number_bytes)
1738 /*[clinic end generated code: output=f23b1ee4823663e3 input=177471073be1a103]*/
1739 {
1740 LPVOID address;
1741
1742 Py_BEGIN_ALLOW_THREADS
1743 address = MapViewOfFile(file_map, desired_access, file_offset_high,
1744 file_offset_low, number_bytes);
1745 Py_END_ALLOW_THREADS
1746
1747 if (address == NULL)
1748 PyErr_SetFromWindowsErr(0);
1749
1750 return address;
1751 }
1752
1753 /*[clinic input]
1754 _winapi.UnmapViewOfFile
1755
1756 address: LPCVOID
1757 /
1758 [clinic start generated code]*/
1759
1760 static PyObject *
_winapi_UnmapViewOfFile_impl(PyObject * module,LPCVOID address)1761 _winapi_UnmapViewOfFile_impl(PyObject *module, LPCVOID address)
1762 /*[clinic end generated code: output=4f7e18ac75d19744 input=8c4b6119ad9288a3]*/
1763 {
1764 BOOL success;
1765
1766 Py_BEGIN_ALLOW_THREADS
1767 success = UnmapViewOfFile(address);
1768 Py_END_ALLOW_THREADS
1769
1770 if (!success) {
1771 return PyErr_SetFromWindowsErr(0);
1772 }
1773
1774 Py_RETURN_NONE;
1775 }
1776
1777 /*[clinic input]
1778 _winapi.OpenEventW -> HANDLE
1779
1780 desired_access: DWORD
1781 inherit_handle: BOOL
1782 name: LPCWSTR
1783 [clinic start generated code]*/
1784
1785 static HANDLE
_winapi_OpenEventW_impl(PyObject * module,DWORD desired_access,BOOL inherit_handle,LPCWSTR name)1786 _winapi_OpenEventW_impl(PyObject *module, DWORD desired_access,
1787 BOOL inherit_handle, LPCWSTR name)
1788 /*[clinic end generated code: output=c4a45e95545a4bd2 input=dec26598748d35aa]*/
1789 {
1790 HANDLE handle;
1791
1792 if (PySys_Audit("_winapi.OpenEventW", "ku", desired_access, name) < 0) {
1793 return INVALID_HANDLE_VALUE;
1794 }
1795
1796 Py_BEGIN_ALLOW_THREADS
1797 handle = OpenEventW(desired_access, inherit_handle, name);
1798 Py_END_ALLOW_THREADS
1799
1800 if (handle == INVALID_HANDLE_VALUE) {
1801 PyErr_SetFromWindowsErr(0);
1802 }
1803
1804 return handle;
1805 }
1806
1807
1808 /*[clinic input]
1809 _winapi.OpenMutexW -> HANDLE
1810
1811 desired_access: DWORD
1812 inherit_handle: BOOL
1813 name: LPCWSTR
1814 [clinic start generated code]*/
1815
1816 static HANDLE
_winapi_OpenMutexW_impl(PyObject * module,DWORD desired_access,BOOL inherit_handle,LPCWSTR name)1817 _winapi_OpenMutexW_impl(PyObject *module, DWORD desired_access,
1818 BOOL inherit_handle, LPCWSTR name)
1819 /*[clinic end generated code: output=dda39d7844397bf0 input=f3a7b466c5307712]*/
1820 {
1821 HANDLE handle;
1822
1823 if (PySys_Audit("_winapi.OpenMutexW", "ku", desired_access, name) < 0) {
1824 return INVALID_HANDLE_VALUE;
1825 }
1826
1827 Py_BEGIN_ALLOW_THREADS
1828 handle = OpenMutexW(desired_access, inherit_handle, name);
1829 Py_END_ALLOW_THREADS
1830
1831 if (handle == INVALID_HANDLE_VALUE) {
1832 PyErr_SetFromWindowsErr(0);
1833 }
1834
1835 return handle;
1836 }
1837
1838 /*[clinic input]
1839 _winapi.OpenFileMapping -> HANDLE
1840
1841 desired_access: DWORD
1842 inherit_handle: BOOL
1843 name: LPCWSTR
1844 /
1845 [clinic start generated code]*/
1846
1847 static HANDLE
_winapi_OpenFileMapping_impl(PyObject * module,DWORD desired_access,BOOL inherit_handle,LPCWSTR name)1848 _winapi_OpenFileMapping_impl(PyObject *module, DWORD desired_access,
1849 BOOL inherit_handle, LPCWSTR name)
1850 /*[clinic end generated code: output=08cc44def1cb11f1 input=131f2a405359de7f]*/
1851 {
1852 HANDLE handle;
1853
1854 Py_BEGIN_ALLOW_THREADS
1855 handle = OpenFileMappingW(desired_access, inherit_handle, name);
1856 Py_END_ALLOW_THREADS
1857
1858 if (handle == NULL) {
1859 PyObject *temp = PyUnicode_FromWideChar(name, -1);
1860 PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, 0, temp);
1861 Py_XDECREF(temp);
1862 handle = INVALID_HANDLE_VALUE;
1863 }
1864
1865 return handle;
1866 }
1867
1868 /*[clinic input]
1869 _winapi.OpenProcess -> HANDLE
1870
1871 desired_access: DWORD
1872 inherit_handle: BOOL
1873 process_id: DWORD
1874 /
1875 [clinic start generated code]*/
1876
1877 static HANDLE
_winapi_OpenProcess_impl(PyObject * module,DWORD desired_access,BOOL inherit_handle,DWORD process_id)1878 _winapi_OpenProcess_impl(PyObject *module, DWORD desired_access,
1879 BOOL inherit_handle, DWORD process_id)
1880 /*[clinic end generated code: output=b42b6b81ea5a0fc3 input=ec98c4cf4ea2ec36]*/
1881 {
1882 HANDLE handle;
1883
1884 if (PySys_Audit("_winapi.OpenProcess", "kk",
1885 process_id, desired_access) < 0) {
1886 return INVALID_HANDLE_VALUE;
1887 }
1888
1889 Py_BEGIN_ALLOW_THREADS
1890 handle = OpenProcess(desired_access, inherit_handle, process_id);
1891 Py_END_ALLOW_THREADS
1892 if (handle == NULL) {
1893 PyErr_SetFromWindowsErr(GetLastError());
1894 handle = INVALID_HANDLE_VALUE;
1895 }
1896
1897 return handle;
1898 }
1899
1900 /*[clinic input]
1901 _winapi.PeekNamedPipe
1902
1903 handle: HANDLE
1904 size: int = 0
1905 /
1906 [clinic start generated code]*/
1907
1908 static PyObject *
_winapi_PeekNamedPipe_impl(PyObject * module,HANDLE handle,int size)1909 _winapi_PeekNamedPipe_impl(PyObject *module, HANDLE handle, int size)
1910 /*[clinic end generated code: output=d0c3e29e49d323dd input=c7aa53bfbce69d70]*/
1911 {
1912 PyObject *buf = NULL;
1913 DWORD nread, navail, nleft;
1914 BOOL ret;
1915
1916 if (size < 0) {
1917 PyErr_SetString(PyExc_ValueError, "negative size");
1918 return NULL;
1919 }
1920
1921 if (size) {
1922 buf = PyBytes_FromStringAndSize(NULL, size);
1923 if (!buf)
1924 return NULL;
1925 Py_BEGIN_ALLOW_THREADS
1926 ret = PeekNamedPipe(handle, PyBytes_AS_STRING(buf), size, &nread,
1927 &navail, &nleft);
1928 Py_END_ALLOW_THREADS
1929 if (!ret) {
1930 Py_DECREF(buf);
1931 return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1932 }
1933 if (_PyBytes_Resize(&buf, nread))
1934 return NULL;
1935 return Py_BuildValue("NII", buf, navail, nleft);
1936 }
1937 else {
1938 Py_BEGIN_ALLOW_THREADS
1939 ret = PeekNamedPipe(handle, NULL, 0, NULL, &navail, &nleft);
1940 Py_END_ALLOW_THREADS
1941 if (!ret) {
1942 return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1943 }
1944 return Py_BuildValue("II", navail, nleft);
1945 }
1946 }
1947
1948 /*[clinic input]
1949 _winapi.LCMapStringEx
1950
1951 locale: LPCWSTR
1952 flags: DWORD
1953 src: unicode
1954
1955 [clinic start generated code]*/
1956
1957 static PyObject *
_winapi_LCMapStringEx_impl(PyObject * module,LPCWSTR locale,DWORD flags,PyObject * src)1958 _winapi_LCMapStringEx_impl(PyObject *module, LPCWSTR locale, DWORD flags,
1959 PyObject *src)
1960 /*[clinic end generated code: output=b90e6b26e028ff0a input=3e3dcd9b8164012f]*/
1961 {
1962 if (flags & (LCMAP_SORTHANDLE | LCMAP_HASH | LCMAP_BYTEREV |
1963 LCMAP_SORTKEY)) {
1964 return PyErr_Format(PyExc_ValueError, "unsupported flags");
1965 }
1966
1967 Py_ssize_t src_size;
1968 wchar_t *src_ = PyUnicode_AsWideCharString(src, &src_size);
1969 if (!src_) {
1970 return NULL;
1971 }
1972 if (src_size > INT_MAX) {
1973 PyMem_Free(src_);
1974 PyErr_SetString(PyExc_OverflowError, "input string is too long");
1975 return NULL;
1976 }
1977
1978 int dest_size = LCMapStringEx(locale, flags, src_, (int)src_size, NULL, 0,
1979 NULL, NULL, 0);
1980 if (dest_size <= 0) {
1981 DWORD error = GetLastError();
1982 PyMem_Free(src_);
1983 return PyErr_SetFromWindowsErr(error);
1984 }
1985
1986 wchar_t* dest = PyMem_NEW(wchar_t, dest_size);
1987 if (dest == NULL) {
1988 PyMem_Free(src_);
1989 return PyErr_NoMemory();
1990 }
1991
1992 int nmapped = LCMapStringEx(locale, flags, src_, (int)src_size, dest, dest_size,
1993 NULL, NULL, 0);
1994 if (nmapped <= 0) {
1995 DWORD error = GetLastError();
1996 PyMem_Free(src_);
1997 PyMem_DEL(dest);
1998 return PyErr_SetFromWindowsErr(error);
1999 }
2000
2001 PyMem_Free(src_);
2002 PyObject *ret = PyUnicode_FromWideChar(dest, nmapped);
2003 PyMem_DEL(dest);
2004
2005 return ret;
2006 }
2007
2008 /*[clinic input]
2009 _winapi.ReadFile
2010
2011 handle: HANDLE
2012 size: DWORD
2013 overlapped as use_overlapped: bool = False
2014 [clinic start generated code]*/
2015
2016 static PyObject *
_winapi_ReadFile_impl(PyObject * module,HANDLE handle,DWORD size,int use_overlapped)2017 _winapi_ReadFile_impl(PyObject *module, HANDLE handle, DWORD size,
2018 int use_overlapped)
2019 /*[clinic end generated code: output=d3d5b44a8201b944 input=4f82f8e909ad91ad]*/
2020 {
2021 DWORD nread;
2022 PyObject *buf;
2023 BOOL ret;
2024 DWORD err;
2025 OverlappedObject *overlapped = NULL;
2026
2027 buf = PyBytes_FromStringAndSize(NULL, size);
2028 if (!buf)
2029 return NULL;
2030 if (use_overlapped) {
2031 overlapped = new_overlapped(module, handle);
2032 if (!overlapped) {
2033 Py_DECREF(buf);
2034 return NULL;
2035 }
2036 /* Steals reference to buf */
2037 overlapped->read_buffer = buf;
2038 }
2039
2040 Py_BEGIN_ALLOW_THREADS
2041 ret = ReadFile(handle, PyBytes_AS_STRING(buf), size, &nread,
2042 overlapped ? &overlapped->overlapped : NULL);
2043 Py_END_ALLOW_THREADS
2044
2045 err = ret ? 0 : GetLastError();
2046
2047 if (overlapped) {
2048 if (!ret) {
2049 if (err == ERROR_IO_PENDING)
2050 overlapped->pending = 1;
2051 else if (err != ERROR_MORE_DATA) {
2052 Py_DECREF(overlapped);
2053 return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
2054 }
2055 }
2056 return Py_BuildValue("NI", (PyObject *) overlapped, err);
2057 }
2058
2059 if (!ret && err != ERROR_MORE_DATA) {
2060 Py_DECREF(buf);
2061 return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
2062 }
2063 if (_PyBytes_Resize(&buf, nread))
2064 return NULL;
2065 return Py_BuildValue("NI", buf, err);
2066 }
2067
2068 /*[clinic input]
2069 _winapi.ReleaseMutex
2070
2071 mutex: HANDLE
2072 [clinic start generated code]*/
2073
2074 static PyObject *
_winapi_ReleaseMutex_impl(PyObject * module,HANDLE mutex)2075 _winapi_ReleaseMutex_impl(PyObject *module, HANDLE mutex)
2076 /*[clinic end generated code: output=5b9001a72dd8af37 input=49e9d20de3559d84]*/
2077 {
2078 int err = 0;
2079
2080 Py_BEGIN_ALLOW_THREADS
2081 if (!ReleaseMutex(mutex)) {
2082 err = GetLastError();
2083 }
2084 Py_END_ALLOW_THREADS
2085 if (err) {
2086 return PyErr_SetFromWindowsErr(err);
2087 }
2088 Py_RETURN_NONE;
2089 }
2090
2091 /*[clinic input]
2092 _winapi.ResetEvent
2093
2094 event: HANDLE
2095 [clinic start generated code]*/
2096
2097 static PyObject *
_winapi_ResetEvent_impl(PyObject * module,HANDLE event)2098 _winapi_ResetEvent_impl(PyObject *module, HANDLE event)
2099 /*[clinic end generated code: output=81c8501d57c0530d input=e2d42d990322e87a]*/
2100 {
2101 int err = 0;
2102
2103 Py_BEGIN_ALLOW_THREADS
2104 if (!ResetEvent(event)) {
2105 err = GetLastError();
2106 }
2107 Py_END_ALLOW_THREADS
2108 if (err) {
2109 return PyErr_SetFromWindowsErr(err);
2110 }
2111 Py_RETURN_NONE;
2112 }
2113
2114 /*[clinic input]
2115 _winapi.SetEvent
2116
2117 event: HANDLE
2118 [clinic start generated code]*/
2119
2120 static PyObject *
_winapi_SetEvent_impl(PyObject * module,HANDLE event)2121 _winapi_SetEvent_impl(PyObject *module, HANDLE event)
2122 /*[clinic end generated code: output=c18ba09eb9aa774d input=e660e830a37c09f8]*/
2123 {
2124 int err = 0;
2125
2126 Py_BEGIN_ALLOW_THREADS
2127 if (!SetEvent(event)) {
2128 err = GetLastError();
2129 }
2130 Py_END_ALLOW_THREADS
2131 if (err) {
2132 return PyErr_SetFromWindowsErr(err);
2133 }
2134 Py_RETURN_NONE;
2135 }
2136
2137 /*[clinic input]
2138 _winapi.SetNamedPipeHandleState
2139
2140 named_pipe: HANDLE
2141 mode: object
2142 max_collection_count: object
2143 collect_data_timeout: object
2144 /
2145 [clinic start generated code]*/
2146
2147 static PyObject *
_winapi_SetNamedPipeHandleState_impl(PyObject * module,HANDLE named_pipe,PyObject * mode,PyObject * max_collection_count,PyObject * collect_data_timeout)2148 _winapi_SetNamedPipeHandleState_impl(PyObject *module, HANDLE named_pipe,
2149 PyObject *mode,
2150 PyObject *max_collection_count,
2151 PyObject *collect_data_timeout)
2152 /*[clinic end generated code: output=f2129d222cbfa095 input=9142d72163d0faa6]*/
2153 {
2154 PyObject *oArgs[3] = {mode, max_collection_count, collect_data_timeout};
2155 DWORD dwArgs[3], *pArgs[3] = {NULL, NULL, NULL};
2156 int i;
2157 BOOL b;
2158
2159 for (i = 0 ; i < 3 ; i++) {
2160 if (oArgs[i] != Py_None) {
2161 dwArgs[i] = PyLong_AsUnsignedLongMask(oArgs[i]);
2162 if (PyErr_Occurred())
2163 return NULL;
2164 pArgs[i] = &dwArgs[i];
2165 }
2166 }
2167
2168 Py_BEGIN_ALLOW_THREADS
2169 b = SetNamedPipeHandleState(named_pipe, pArgs[0], pArgs[1], pArgs[2]);
2170 Py_END_ALLOW_THREADS
2171
2172 if (!b)
2173 return PyErr_SetFromWindowsErr(0);
2174
2175 Py_RETURN_NONE;
2176 }
2177
2178
2179 /*[clinic input]
2180 _winapi.TerminateProcess
2181
2182 handle: HANDLE
2183 exit_code: UINT
2184 /
2185
2186 Terminate the specified process and all of its threads.
2187 [clinic start generated code]*/
2188
2189 static PyObject *
_winapi_TerminateProcess_impl(PyObject * module,HANDLE handle,UINT exit_code)2190 _winapi_TerminateProcess_impl(PyObject *module, HANDLE handle,
2191 UINT exit_code)
2192 /*[clinic end generated code: output=f4e99ac3f0b1f34a input=d6bc0aa1ee3bb4df]*/
2193 {
2194 BOOL result;
2195
2196 if (PySys_Audit("_winapi.TerminateProcess", "nI",
2197 (Py_ssize_t)handle, exit_code) < 0) {
2198 return NULL;
2199 }
2200
2201 result = TerminateProcess(handle, exit_code);
2202
2203 if (! result)
2204 return PyErr_SetFromWindowsErr(GetLastError());
2205
2206 Py_RETURN_NONE;
2207 }
2208
2209 /*[clinic input]
2210 _winapi.VirtualQuerySize -> size_t
2211
2212 address: LPCVOID
2213 /
2214 [clinic start generated code]*/
2215
2216 static size_t
_winapi_VirtualQuerySize_impl(PyObject * module,LPCVOID address)2217 _winapi_VirtualQuerySize_impl(PyObject *module, LPCVOID address)
2218 /*[clinic end generated code: output=40c8e0ff5ec964df input=6b784a69755d0bb6]*/
2219 {
2220 SIZE_T size_of_buf;
2221 MEMORY_BASIC_INFORMATION mem_basic_info;
2222 SIZE_T region_size;
2223
2224 Py_BEGIN_ALLOW_THREADS
2225 size_of_buf = VirtualQuery(address, &mem_basic_info, sizeof(mem_basic_info));
2226 Py_END_ALLOW_THREADS
2227
2228 if (size_of_buf == 0)
2229 PyErr_SetFromWindowsErr(0);
2230
2231 region_size = mem_basic_info.RegionSize;
2232 return region_size;
2233 }
2234
2235 /*[clinic input]
2236 _winapi.WaitNamedPipe
2237
2238 name: LPCWSTR
2239 timeout: DWORD
2240 /
2241 [clinic start generated code]*/
2242
2243 static PyObject *
_winapi_WaitNamedPipe_impl(PyObject * module,LPCWSTR name,DWORD timeout)2244 _winapi_WaitNamedPipe_impl(PyObject *module, LPCWSTR name, DWORD timeout)
2245 /*[clinic end generated code: output=e161e2e630b3e9c2 input=099a4746544488fa]*/
2246 {
2247 BOOL success;
2248
2249 Py_BEGIN_ALLOW_THREADS
2250 success = WaitNamedPipeW(name, timeout);
2251 Py_END_ALLOW_THREADS
2252
2253 if (!success)
2254 return PyErr_SetFromWindowsErr(0);
2255
2256 Py_RETURN_NONE;
2257 }
2258
2259
2260 typedef struct {
2261 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2262 HANDLE cancel_event;
2263 DWORD handle_base;
2264 DWORD handle_count;
2265 HANDLE thread;
2266 volatile DWORD result;
2267 } BatchedWaitData;
2268
2269 static DWORD WINAPI
_batched_WaitForMultipleObjects_thread(LPVOID param)2270 _batched_WaitForMultipleObjects_thread(LPVOID param)
2271 {
2272 BatchedWaitData *data = (BatchedWaitData *)param;
2273 data->result = WaitForMultipleObjects(
2274 data->handle_count,
2275 data->handles,
2276 FALSE,
2277 INFINITE
2278 );
2279 if (data->result == WAIT_FAILED) {
2280 DWORD err = GetLastError();
2281 SetEvent(data->cancel_event);
2282 return err;
2283 } else if (data->result >= WAIT_ABANDONED_0 && data->result < WAIT_ABANDONED_0 + MAXIMUM_WAIT_OBJECTS) {
2284 data->result = WAIT_FAILED;
2285 SetEvent(data->cancel_event);
2286 return ERROR_ABANDONED_WAIT_0;
2287 }
2288 return 0;
2289 }
2290
2291 /*[clinic input]
2292 _winapi.BatchedWaitForMultipleObjects
2293
2294 handle_seq: object
2295 wait_all: BOOL
2296 milliseconds: DWORD(c_default='INFINITE') = _winapi.INFINITE
2297
2298 Supports a larger number of handles than WaitForMultipleObjects
2299
2300 Note that the handles may be waited on other threads, which could cause
2301 issues for objects like mutexes that become associated with the thread
2302 that was waiting for them. Objects may also be left signalled, even if
2303 the wait fails.
2304
2305 It is recommended to use WaitForMultipleObjects whenever possible, and
2306 only switch to BatchedWaitForMultipleObjects for scenarios where you
2307 control all the handles involved, such as your own thread pool or
2308 files, and all wait objects are left unmodified by a wait (for example,
2309 manual reset events, threads, and files/pipes).
2310
2311 Overlapped handles returned from this module use manual reset events.
2312 [clinic start generated code]*/
2313
2314 static PyObject *
_winapi_BatchedWaitForMultipleObjects_impl(PyObject * module,PyObject * handle_seq,BOOL wait_all,DWORD milliseconds)2315 _winapi_BatchedWaitForMultipleObjects_impl(PyObject *module,
2316 PyObject *handle_seq,
2317 BOOL wait_all, DWORD milliseconds)
2318 /*[clinic end generated code: output=d21c1a4ad0a252fd input=7e196f29005dc77b]*/
2319 {
2320 Py_ssize_t thread_count = 0, handle_count = 0, i;
2321 Py_ssize_t nhandles;
2322 BatchedWaitData *thread_data[MAXIMUM_WAIT_OBJECTS];
2323 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2324 HANDLE sigint_event = NULL;
2325 HANDLE cancel_event = NULL;
2326 DWORD result;
2327
2328 const Py_ssize_t _MAXIMUM_TOTAL_OBJECTS = (MAXIMUM_WAIT_OBJECTS - 1) * (MAXIMUM_WAIT_OBJECTS - 1);
2329
2330 if (!PySequence_Check(handle_seq)) {
2331 PyErr_Format(PyExc_TypeError,
2332 "sequence type expected, got '%s'",
2333 Py_TYPE(handle_seq)->tp_name);
2334 return NULL;
2335 }
2336 nhandles = PySequence_Length(handle_seq);
2337 if (nhandles == -1) {
2338 return NULL;
2339 }
2340 if (nhandles == 0) {
2341 return wait_all ? Py_NewRef(Py_None) : PyList_New(0);
2342 }
2343
2344 /* If this is the main thread then make the wait interruptible
2345 by Ctrl-C. When waiting for *all* handles, it is only checked
2346 in between batches. */
2347 if (_PyOS_IsMainThread()) {
2348 sigint_event = _PyOS_SigintEvent();
2349 assert(sigint_event != NULL);
2350 }
2351
2352 if (nhandles < 0 || nhandles > _MAXIMUM_TOTAL_OBJECTS) {
2353 PyErr_Format(PyExc_ValueError,
2354 "need at most %zd handles, got a sequence of length %zd",
2355 _MAXIMUM_TOTAL_OBJECTS, nhandles);
2356 return NULL;
2357 }
2358
2359 if (!wait_all) {
2360 cancel_event = CreateEventW(NULL, TRUE, FALSE, NULL);
2361 if (!cancel_event) {
2362 PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
2363 return NULL;
2364 }
2365 }
2366
2367 i = 0;
2368 while (i < nhandles) {
2369 BatchedWaitData *data = (BatchedWaitData*)PyMem_Malloc(sizeof(BatchedWaitData));
2370 if (!data) {
2371 goto error;
2372 }
2373 thread_data[thread_count++] = data;
2374 data->thread = NULL;
2375 data->cancel_event = cancel_event;
2376 data->handle_base = Py_SAFE_DOWNCAST(i, Py_ssize_t, DWORD);
2377 data->handle_count = Py_SAFE_DOWNCAST(nhandles - i, Py_ssize_t, DWORD);
2378 if (data->handle_count > MAXIMUM_WAIT_OBJECTS - 1) {
2379 data->handle_count = MAXIMUM_WAIT_OBJECTS - 1;
2380 }
2381 for (DWORD j = 0; j < data->handle_count; ++i, ++j) {
2382 PyObject *v = PySequence_GetItem(handle_seq, i);
2383 if (!v || !PyArg_Parse(v, F_HANDLE, &data->handles[j])) {
2384 Py_XDECREF(v);
2385 goto error;
2386 }
2387 Py_DECREF(v);
2388 }
2389 if (!wait_all) {
2390 data->handles[data->handle_count++] = cancel_event;
2391 }
2392 }
2393
2394 DWORD err = 0;
2395
2396 /* We need to use different strategies when waiting for ALL handles
2397 as opposed to ANY handle. This is because there is no way to
2398 (safely) interrupt a thread that is waiting for all handles in a
2399 group. So for ALL handles, we loop over each set and wait. For
2400 ANY handle, we use threads and wait on them. */
2401 if (wait_all) {
2402 Py_BEGIN_ALLOW_THREADS
2403 long long deadline = 0;
2404 if (milliseconds != INFINITE) {
2405 deadline = (long long)GetTickCount64() + milliseconds;
2406 }
2407
2408 for (i = 0; !err && i < thread_count; ++i) {
2409 DWORD timeout = milliseconds;
2410 if (deadline) {
2411 long long time_to_deadline = deadline - GetTickCount64();
2412 if (time_to_deadline <= 0) {
2413 err = WAIT_TIMEOUT;
2414 break;
2415 } else if (time_to_deadline < UINT_MAX) {
2416 timeout = (DWORD)time_to_deadline;
2417 }
2418 }
2419 result = WaitForMultipleObjects(thread_data[i]->handle_count,
2420 thread_data[i]->handles, TRUE, timeout);
2421 // ABANDONED is not possible here because we own all the handles
2422 if (result == WAIT_FAILED) {
2423 err = GetLastError();
2424 } else if (result == WAIT_TIMEOUT) {
2425 err = WAIT_TIMEOUT;
2426 }
2427
2428 if (!err && sigint_event) {
2429 result = WaitForSingleObject(sigint_event, 0);
2430 if (result == WAIT_OBJECT_0) {
2431 err = ERROR_CONTROL_C_EXIT;
2432 } else if (result == WAIT_FAILED) {
2433 err = GetLastError();
2434 }
2435 }
2436 }
2437
2438 CloseHandle(cancel_event);
2439
2440 Py_END_ALLOW_THREADS
2441 } else {
2442 Py_BEGIN_ALLOW_THREADS
2443
2444 for (i = 0; i < thread_count; ++i) {
2445 BatchedWaitData *data = thread_data[i];
2446 data->thread = CreateThread(
2447 NULL,
2448 1, // smallest possible initial stack
2449 _batched_WaitForMultipleObjects_thread,
2450 (LPVOID)data,
2451 CREATE_SUSPENDED,
2452 NULL
2453 );
2454 if (!data->thread) {
2455 err = GetLastError();
2456 break;
2457 }
2458 handles[handle_count++] = data->thread;
2459 }
2460 Py_END_ALLOW_THREADS
2461
2462 if (err) {
2463 PyErr_SetExcFromWindowsErr(PyExc_OSError, err);
2464 goto error;
2465 }
2466 if (handle_count > MAXIMUM_WAIT_OBJECTS - 1) {
2467 // basically an assert, but stronger
2468 PyErr_SetString(PyExc_SystemError, "allocated too many wait objects");
2469 goto error;
2470 }
2471
2472 Py_BEGIN_ALLOW_THREADS
2473
2474 // Once we start resuming threads, can no longer "goto error"
2475 for (i = 0; i < thread_count; ++i) {
2476 ResumeThread(thread_data[i]->thread);
2477 }
2478 if (sigint_event) {
2479 handles[handle_count++] = sigint_event;
2480 }
2481 result = WaitForMultipleObjects((DWORD)handle_count, handles, wait_all, milliseconds);
2482 // ABANDONED is not possible here because we own all the handles
2483 if (result == WAIT_FAILED) {
2484 err = GetLastError();
2485 } else if (result == WAIT_TIMEOUT) {
2486 err = WAIT_TIMEOUT;
2487 } else if (sigint_event && result == WAIT_OBJECT_0 + handle_count) {
2488 err = ERROR_CONTROL_C_EXIT;
2489 }
2490
2491 SetEvent(cancel_event);
2492
2493 // Wait for all threads to finish before we start freeing their memory
2494 if (sigint_event) {
2495 handle_count -= 1;
2496 }
2497 WaitForMultipleObjects((DWORD)handle_count, handles, TRUE, INFINITE);
2498
2499 for (i = 0; i < thread_count; ++i) {
2500 if (!err && thread_data[i]->result == WAIT_FAILED) {
2501 if (!GetExitCodeThread(thread_data[i]->thread, &err)) {
2502 err = GetLastError();
2503 }
2504 }
2505 CloseHandle(thread_data[i]->thread);
2506 }
2507
2508 CloseHandle(cancel_event);
2509
2510 Py_END_ALLOW_THREADS
2511
2512 }
2513
2514 PyObject *triggered_indices;
2515 if (sigint_event != NULL && err == ERROR_CONTROL_C_EXIT) {
2516 errno = EINTR;
2517 PyErr_SetFromErrno(PyExc_OSError);
2518 triggered_indices = NULL;
2519 } else if (err) {
2520 PyErr_SetExcFromWindowsErr(PyExc_OSError, err);
2521 triggered_indices = NULL;
2522 } else if (wait_all) {
2523 triggered_indices = Py_NewRef(Py_None);
2524 } else {
2525 triggered_indices = PyList_New(0);
2526 if (triggered_indices) {
2527 for (i = 0; i < thread_count; ++i) {
2528 Py_ssize_t triggered = (Py_ssize_t)thread_data[i]->result - WAIT_OBJECT_0;
2529 if (triggered >= 0 && (size_t)triggered < thread_data[i]->handle_count - 1) {
2530 PyObject *v = PyLong_FromSsize_t(thread_data[i]->handle_base + triggered);
2531 if (!v || PyList_Append(triggered_indices, v) < 0) {
2532 Py_XDECREF(v);
2533 Py_CLEAR(triggered_indices);
2534 break;
2535 }
2536 Py_DECREF(v);
2537 }
2538 }
2539 }
2540 }
2541
2542 for (i = 0; i < thread_count; ++i) {
2543 PyMem_Free((void *)thread_data[i]);
2544 }
2545
2546 return triggered_indices;
2547
2548 error:
2549 // We should only enter here before any threads start running.
2550 // Once we start resuming threads, different cleanup is required
2551 CloseHandle(cancel_event);
2552 while (--thread_count >= 0) {
2553 HANDLE t = thread_data[thread_count]->thread;
2554 if (t) {
2555 TerminateThread(t, WAIT_ABANDONED_0);
2556 CloseHandle(t);
2557 }
2558 PyMem_Free((void *)thread_data[thread_count]);
2559 }
2560 return NULL;
2561 }
2562
2563 /*[clinic input]
2564 _winapi.WaitForMultipleObjects
2565
2566 handle_seq: object
2567 wait_flag: BOOL
2568 milliseconds: DWORD(c_default='INFINITE') = _winapi.INFINITE
2569 /
2570 [clinic start generated code]*/
2571
2572 static PyObject *
_winapi_WaitForMultipleObjects_impl(PyObject * module,PyObject * handle_seq,BOOL wait_flag,DWORD milliseconds)2573 _winapi_WaitForMultipleObjects_impl(PyObject *module, PyObject *handle_seq,
2574 BOOL wait_flag, DWORD milliseconds)
2575 /*[clinic end generated code: output=295e3f00b8e45899 input=36f76ca057cd28a0]*/
2576 {
2577 DWORD result;
2578 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
2579 HANDLE sigint_event = NULL;
2580 Py_ssize_t nhandles, i;
2581
2582 if (!PySequence_Check(handle_seq)) {
2583 PyErr_Format(PyExc_TypeError,
2584 "sequence type expected, got '%s'",
2585 Py_TYPE(handle_seq)->tp_name);
2586 return NULL;
2587 }
2588 nhandles = PySequence_Length(handle_seq);
2589 if (nhandles == -1)
2590 return NULL;
2591 if (nhandles < 0 || nhandles > MAXIMUM_WAIT_OBJECTS - 1) {
2592 PyErr_Format(PyExc_ValueError,
2593 "need at most %zd handles, got a sequence of length %zd",
2594 MAXIMUM_WAIT_OBJECTS - 1, nhandles);
2595 return NULL;
2596 }
2597 for (i = 0; i < nhandles; i++) {
2598 HANDLE h;
2599 PyObject *v = PySequence_GetItem(handle_seq, i);
2600 if (v == NULL)
2601 return NULL;
2602 if (!PyArg_Parse(v, F_HANDLE, &h)) {
2603 Py_DECREF(v);
2604 return NULL;
2605 }
2606 handles[i] = h;
2607 Py_DECREF(v);
2608 }
2609 /* If this is the main thread then make the wait interruptible
2610 by Ctrl-C unless we are waiting for *all* handles */
2611 if (!wait_flag && _PyOS_IsMainThread()) {
2612 sigint_event = _PyOS_SigintEvent();
2613 assert(sigint_event != NULL);
2614 handles[nhandles++] = sigint_event;
2615 }
2616
2617 Py_BEGIN_ALLOW_THREADS
2618 if (sigint_event != NULL)
2619 ResetEvent(sigint_event);
2620 result = WaitForMultipleObjects((DWORD) nhandles, handles,
2621 wait_flag, milliseconds);
2622 Py_END_ALLOW_THREADS
2623
2624 if (result == WAIT_FAILED)
2625 return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
2626 else if (sigint_event != NULL && result == WAIT_OBJECT_0 + nhandles - 1) {
2627 errno = EINTR;
2628 return PyErr_SetFromErrno(PyExc_OSError);
2629 }
2630
2631 return PyLong_FromLong((int) result);
2632 }
2633
2634 /*[clinic input]
2635 _winapi.WaitForSingleObject -> long
2636
2637 handle: HANDLE
2638 milliseconds: DWORD
2639 /
2640
2641 Wait for a single object.
2642
2643 Wait until the specified object is in the signaled state or
2644 the time-out interval elapses. The timeout value is specified
2645 in milliseconds.
2646 [clinic start generated code]*/
2647
2648 static long
_winapi_WaitForSingleObject_impl(PyObject * module,HANDLE handle,DWORD milliseconds)2649 _winapi_WaitForSingleObject_impl(PyObject *module, HANDLE handle,
2650 DWORD milliseconds)
2651 /*[clinic end generated code: output=3c4715d8f1b39859 input=443d1ab076edc7b1]*/
2652 {
2653 DWORD result;
2654
2655 Py_BEGIN_ALLOW_THREADS
2656 result = WaitForSingleObject(handle, milliseconds);
2657 Py_END_ALLOW_THREADS
2658
2659 if (result == WAIT_FAILED) {
2660 PyErr_SetFromWindowsErr(GetLastError());
2661 return -1;
2662 }
2663
2664 return result;
2665 }
2666
2667 /*[clinic input]
2668 _winapi.WriteFile
2669
2670 handle: HANDLE
2671 buffer: object
2672 overlapped as use_overlapped: bool = False
2673 [clinic start generated code]*/
2674
2675 static PyObject *
_winapi_WriteFile_impl(PyObject * module,HANDLE handle,PyObject * buffer,int use_overlapped)2676 _winapi_WriteFile_impl(PyObject *module, HANDLE handle, PyObject *buffer,
2677 int use_overlapped)
2678 /*[clinic end generated code: output=2ca80f6bf3fa92e3 input=2badb008c8a2e2a0]*/
2679 {
2680 Py_buffer _buf, *buf;
2681 DWORD len, written;
2682 BOOL ret;
2683 DWORD err;
2684 OverlappedObject *overlapped = NULL;
2685
2686 if (use_overlapped) {
2687 overlapped = new_overlapped(module, handle);
2688 if (!overlapped)
2689 return NULL;
2690 buf = &overlapped->write_buffer;
2691 }
2692 else
2693 buf = &_buf;
2694
2695 if (!PyArg_Parse(buffer, "y*", buf)) {
2696 Py_XDECREF(overlapped);
2697 return NULL;
2698 }
2699
2700 Py_BEGIN_ALLOW_THREADS
2701 len = (DWORD)Py_MIN(buf->len, PY_DWORD_MAX);
2702 ret = WriteFile(handle, buf->buf, len, &written,
2703 overlapped ? &overlapped->overlapped : NULL);
2704 Py_END_ALLOW_THREADS
2705
2706 err = ret ? 0 : GetLastError();
2707
2708 if (overlapped) {
2709 if (!ret) {
2710 if (err == ERROR_IO_PENDING)
2711 overlapped->pending = 1;
2712 else {
2713 Py_DECREF(overlapped);
2714 return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
2715 }
2716 }
2717 return Py_BuildValue("NI", (PyObject *) overlapped, err);
2718 }
2719
2720 PyBuffer_Release(buf);
2721 if (!ret)
2722 return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
2723 return Py_BuildValue("II", written, err);
2724 }
2725
2726 /*[clinic input]
2727 _winapi.GetACP
2728
2729 Get the current Windows ANSI code page identifier.
2730 [clinic start generated code]*/
2731
2732 static PyObject *
_winapi_GetACP_impl(PyObject * module)2733 _winapi_GetACP_impl(PyObject *module)
2734 /*[clinic end generated code: output=f7ee24bf705dbb88 input=1433c96d03a05229]*/
2735 {
2736 return PyLong_FromUnsignedLong(GetACP());
2737 }
2738
2739 /*[clinic input]
2740 _winapi.GetFileType -> DWORD
2741
2742 handle: HANDLE
2743 [clinic start generated code]*/
2744
2745 static DWORD
_winapi_GetFileType_impl(PyObject * module,HANDLE handle)2746 _winapi_GetFileType_impl(PyObject *module, HANDLE handle)
2747 /*[clinic end generated code: output=92b8466ac76ecc17 input=0058366bc40bbfbf]*/
2748 {
2749 DWORD result;
2750
2751 Py_BEGIN_ALLOW_THREADS
2752 result = GetFileType(handle);
2753 Py_END_ALLOW_THREADS
2754
2755 if (result == FILE_TYPE_UNKNOWN && GetLastError() != NO_ERROR) {
2756 PyErr_SetFromWindowsErr(0);
2757 return -1;
2758 }
2759
2760 return result;
2761 }
2762
2763
2764 /*[clinic input]
2765 _winapi._mimetypes_read_windows_registry
2766
2767 on_type_read: object
2768
2769 Optimized function for reading all known MIME types from the registry.
2770
2771 *on_type_read* is a callable taking *type* and *ext* arguments, as for
2772 MimeTypes.add_type.
2773 [clinic start generated code]*/
2774
2775 static PyObject *
_winapi__mimetypes_read_windows_registry_impl(PyObject * module,PyObject * on_type_read)2776 _winapi__mimetypes_read_windows_registry_impl(PyObject *module,
2777 PyObject *on_type_read)
2778 /*[clinic end generated code: output=20829f00bebce55b input=cd357896d6501f68]*/
2779 {
2780 #define CCH_EXT 128
2781 #define CB_TYPE 510
2782 struct {
2783 wchar_t ext[CCH_EXT];
2784 wchar_t type[CB_TYPE / sizeof(wchar_t) + 1];
2785 } entries[64];
2786 int entry = 0;
2787 HKEY hkcr = NULL;
2788 LRESULT err;
2789
2790 Py_BEGIN_ALLOW_THREADS
2791 err = RegOpenKeyExW(HKEY_CLASSES_ROOT, NULL, 0, KEY_READ, &hkcr);
2792 for (DWORD i = 0; err == ERROR_SUCCESS || err == ERROR_MORE_DATA; ++i) {
2793 LPWSTR ext = entries[entry].ext;
2794 LPWSTR type = entries[entry].type;
2795 DWORD cchExt = CCH_EXT;
2796 DWORD cbType = CB_TYPE;
2797 HKEY subkey;
2798 DWORD regType;
2799
2800 err = RegEnumKeyExW(hkcr, i, ext, &cchExt, NULL, NULL, NULL, NULL);
2801 if (err != ERROR_SUCCESS || (cchExt && ext[0] != L'.')) {
2802 continue;
2803 }
2804
2805 err = RegOpenKeyExW(hkcr, ext, 0, KEY_READ, &subkey);
2806 if (err == ERROR_FILE_NOT_FOUND || err == ERROR_ACCESS_DENIED) {
2807 err = ERROR_SUCCESS;
2808 continue;
2809 } else if (err != ERROR_SUCCESS) {
2810 continue;
2811 }
2812
2813 err = RegQueryValueExW(subkey, L"Content Type", NULL,
2814 ®Type, (LPBYTE)type, &cbType);
2815 RegCloseKey(subkey);
2816 if (err == ERROR_FILE_NOT_FOUND) {
2817 err = ERROR_SUCCESS;
2818 continue;
2819 } else if (err != ERROR_SUCCESS) {
2820 continue;
2821 } else if (regType != REG_SZ || !cbType) {
2822 continue;
2823 }
2824 type[cbType / sizeof(wchar_t)] = L'\0';
2825
2826 entry += 1;
2827
2828 /* Flush our cached entries if we are full */
2829 if (entry == sizeof(entries) / sizeof(entries[0])) {
2830 Py_BLOCK_THREADS
2831 for (int j = 0; j < entry; ++j) {
2832 PyObject *r = PyObject_CallFunction(
2833 on_type_read, "uu", entries[j].type, entries[j].ext
2834 );
2835 if (!r) {
2836 /* We blocked threads, so safe to return from here */
2837 RegCloseKey(hkcr);
2838 return NULL;
2839 }
2840 Py_DECREF(r);
2841 }
2842 Py_UNBLOCK_THREADS
2843 entry = 0;
2844 }
2845 }
2846 if (hkcr) {
2847 RegCloseKey(hkcr);
2848 }
2849 Py_END_ALLOW_THREADS
2850
2851 if (err != ERROR_SUCCESS && err != ERROR_NO_MORE_ITEMS) {
2852 PyErr_SetFromWindowsErr((int)err);
2853 return NULL;
2854 }
2855
2856 for (int j = 0; j < entry; ++j) {
2857 PyObject *r = PyObject_CallFunction(
2858 on_type_read, "uu", entries[j].type, entries[j].ext
2859 );
2860 if (!r) {
2861 return NULL;
2862 }
2863 Py_DECREF(r);
2864 }
2865
2866 Py_RETURN_NONE;
2867 #undef CCH_EXT
2868 #undef CB_TYPE
2869 }
2870
2871 /*[clinic input]
2872 _winapi.NeedCurrentDirectoryForExePath -> bool
2873
2874 exe_name: LPCWSTR
2875 /
2876 [clinic start generated code]*/
2877
2878 static int
_winapi_NeedCurrentDirectoryForExePath_impl(PyObject * module,LPCWSTR exe_name)2879 _winapi_NeedCurrentDirectoryForExePath_impl(PyObject *module,
2880 LPCWSTR exe_name)
2881 /*[clinic end generated code: output=a65ec879502b58fc input=972aac88a1ec2f00]*/
2882 {
2883 BOOL result;
2884
2885 Py_BEGIN_ALLOW_THREADS
2886 result = NeedCurrentDirectoryForExePathW(exe_name);
2887 Py_END_ALLOW_THREADS
2888
2889 return result;
2890 }
2891
2892
2893 /*[clinic input]
2894 _winapi.CopyFile2
2895
2896 existing_file_name: LPCWSTR
2897 new_file_name: LPCWSTR
2898 flags: DWORD
2899 progress_routine: object = None
2900
2901 Copies a file from one name to a new name.
2902
2903 This is implemented using the CopyFile2 API, which preserves all stat
2904 and metadata information apart from security attributes.
2905
2906 progress_routine is reserved for future use, but is currently not
2907 implemented. Its value is ignored.
2908 [clinic start generated code]*/
2909
2910 static PyObject *
_winapi_CopyFile2_impl(PyObject * module,LPCWSTR existing_file_name,LPCWSTR new_file_name,DWORD flags,PyObject * progress_routine)2911 _winapi_CopyFile2_impl(PyObject *module, LPCWSTR existing_file_name,
2912 LPCWSTR new_file_name, DWORD flags,
2913 PyObject *progress_routine)
2914 /*[clinic end generated code: output=43d960d9df73d984 input=fb976b8d1492d130]*/
2915 {
2916 HRESULT hr;
2917 COPYFILE2_EXTENDED_PARAMETERS params = { sizeof(COPYFILE2_EXTENDED_PARAMETERS) };
2918
2919 if (PySys_Audit("_winapi.CopyFile2", "uuk",
2920 existing_file_name, new_file_name, flags) < 0) {
2921 return NULL;
2922 }
2923
2924 params.dwCopyFlags = flags;
2925 /* For future implementation. We ignore the value for now so that
2926 users only have to test for 'CopyFile2' existing and not whether
2927 the additional parameter exists.
2928 if (progress_routine != Py_None) {
2929 params.pProgressRoutine = _winapi_CopyFile2ProgressRoutine;
2930 params.pvCallbackContext = Py_NewRef(progress_routine);
2931 }
2932 */
2933 Py_BEGIN_ALLOW_THREADS;
2934 hr = CopyFile2(existing_file_name, new_file_name, ¶ms);
2935 Py_END_ALLOW_THREADS;
2936 /* For future implementation.
2937 if (progress_routine != Py_None) {
2938 Py_DECREF(progress_routine);
2939 }
2940 */
2941 if (FAILED(hr)) {
2942 if ((hr & 0xFFFF0000) == 0x80070000) {
2943 PyErr_SetFromWindowsErr(hr & 0xFFFF);
2944 } else {
2945 PyErr_SetFromWindowsErr(hr);
2946 }
2947 return NULL;
2948 }
2949 Py_RETURN_NONE;
2950 }
2951
2952
2953 static PyMethodDef winapi_functions[] = {
2954 _WINAPI_CLOSEHANDLE_METHODDEF
2955 _WINAPI_CONNECTNAMEDPIPE_METHODDEF
2956 _WINAPI_CREATEEVENTW_METHODDEF
2957 _WINAPI_CREATEFILE_METHODDEF
2958 _WINAPI_CREATEFILEMAPPING_METHODDEF
2959 _WINAPI_CREATEMUTEXW_METHODDEF
2960 _WINAPI_CREATENAMEDPIPE_METHODDEF
2961 _WINAPI_CREATEPIPE_METHODDEF
2962 _WINAPI_CREATEPROCESS_METHODDEF
2963 _WINAPI_CREATEJUNCTION_METHODDEF
2964 _WINAPI_DUPLICATEHANDLE_METHODDEF
2965 _WINAPI_EXITPROCESS_METHODDEF
2966 _WINAPI_GETCURRENTPROCESS_METHODDEF
2967 _WINAPI_GETEXITCODEPROCESS_METHODDEF
2968 _WINAPI_GETLASTERROR_METHODDEF
2969 _WINAPI_GETLONGPATHNAME_METHODDEF
2970 _WINAPI_GETMODULEFILENAME_METHODDEF
2971 _WINAPI_GETSHORTPATHNAME_METHODDEF
2972 _WINAPI_GETSTDHANDLE_METHODDEF
2973 _WINAPI_GETVERSION_METHODDEF
2974 _WINAPI_MAPVIEWOFFILE_METHODDEF
2975 _WINAPI_OPENEVENTW_METHODDEF
2976 _WINAPI_OPENFILEMAPPING_METHODDEF
2977 _WINAPI_OPENMUTEXW_METHODDEF
2978 _WINAPI_OPENPROCESS_METHODDEF
2979 _WINAPI_PEEKNAMEDPIPE_METHODDEF
2980 _WINAPI_LCMAPSTRINGEX_METHODDEF
2981 _WINAPI_READFILE_METHODDEF
2982 _WINAPI_RELEASEMUTEX_METHODDEF
2983 _WINAPI_RESETEVENT_METHODDEF
2984 _WINAPI_SETEVENT_METHODDEF
2985 _WINAPI_SETNAMEDPIPEHANDLESTATE_METHODDEF
2986 _WINAPI_TERMINATEPROCESS_METHODDEF
2987 _WINAPI_UNMAPVIEWOFFILE_METHODDEF
2988 _WINAPI_VIRTUALQUERYSIZE_METHODDEF
2989 _WINAPI_WAITNAMEDPIPE_METHODDEF
2990 _WINAPI_WAITFORMULTIPLEOBJECTS_METHODDEF
2991 _WINAPI_BATCHEDWAITFORMULTIPLEOBJECTS_METHODDEF
2992 _WINAPI_WAITFORSINGLEOBJECT_METHODDEF
2993 _WINAPI_WRITEFILE_METHODDEF
2994 _WINAPI_GETACP_METHODDEF
2995 _WINAPI_GETFILETYPE_METHODDEF
2996 _WINAPI__MIMETYPES_READ_WINDOWS_REGISTRY_METHODDEF
2997 _WINAPI_NEEDCURRENTDIRECTORYFOREXEPATH_METHODDEF
2998 _WINAPI_COPYFILE2_METHODDEF
2999 {NULL, NULL}
3000 };
3001
3002 #define WINAPI_CONSTANT(fmt, con) \
3003 do { \
3004 PyObject *value = Py_BuildValue(fmt, con); \
3005 if (value == NULL) { \
3006 return -1; \
3007 } \
3008 if (PyDict_SetItemString(d, #con, value) < 0) { \
3009 Py_DECREF(value); \
3010 return -1; \
3011 } \
3012 Py_DECREF(value); \
3013 } while (0)
3014
winapi_exec(PyObject * m)3015 static int winapi_exec(PyObject *m)
3016 {
3017 WinApiState *st = winapi_get_state(m);
3018
3019 st->overlapped_type = (PyTypeObject *)PyType_FromModuleAndSpec(m, &winapi_overlapped_type_spec, NULL);
3020 if (st->overlapped_type == NULL) {
3021 return -1;
3022 }
3023
3024 if (PyModule_AddType(m, st->overlapped_type) < 0) {
3025 return -1;
3026 }
3027
3028 PyObject *d = PyModule_GetDict(m);
3029
3030 /* constants */
3031 WINAPI_CONSTANT(F_DWORD, CREATE_NEW_CONSOLE);
3032 WINAPI_CONSTANT(F_DWORD, CREATE_NEW_PROCESS_GROUP);
3033 WINAPI_CONSTANT(F_DWORD, DUPLICATE_SAME_ACCESS);
3034 WINAPI_CONSTANT(F_DWORD, DUPLICATE_CLOSE_SOURCE);
3035 WINAPI_CONSTANT(F_DWORD, ERROR_ACCESS_DENIED);
3036 WINAPI_CONSTANT(F_DWORD, ERROR_ALREADY_EXISTS);
3037 WINAPI_CONSTANT(F_DWORD, ERROR_BROKEN_PIPE);
3038 WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING);
3039 WINAPI_CONSTANT(F_DWORD, ERROR_MORE_DATA);
3040 WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
3041 WINAPI_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES);
3042 WINAPI_CONSTANT(F_DWORD, ERROR_MORE_DATA);
3043 WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
3044 WINAPI_CONSTANT(F_DWORD, ERROR_NO_DATA);
3045 WINAPI_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES);
3046 WINAPI_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED);
3047 WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY);
3048 WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_CONNECTED);
3049 WINAPI_CONSTANT(F_DWORD, ERROR_PRIVILEGE_NOT_HELD);
3050 WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT);
3051 WINAPI_CONSTANT(F_DWORD, FILE_FLAG_FIRST_PIPE_INSTANCE);
3052 WINAPI_CONSTANT(F_DWORD, FILE_FLAG_OVERLAPPED);
3053 WINAPI_CONSTANT(F_DWORD, FILE_GENERIC_READ);
3054 WINAPI_CONSTANT(F_DWORD, FILE_GENERIC_WRITE);
3055 WINAPI_CONSTANT(F_DWORD, FILE_MAP_ALL_ACCESS);
3056 WINAPI_CONSTANT(F_DWORD, FILE_MAP_COPY);
3057 WINAPI_CONSTANT(F_DWORD, FILE_MAP_EXECUTE);
3058 WINAPI_CONSTANT(F_DWORD, FILE_MAP_READ);
3059 WINAPI_CONSTANT(F_DWORD, FILE_MAP_WRITE);
3060 WINAPI_CONSTANT(F_DWORD, GENERIC_READ);
3061 WINAPI_CONSTANT(F_DWORD, GENERIC_WRITE);
3062 WINAPI_CONSTANT(F_DWORD, INFINITE);
3063 WINAPI_CONSTANT(F_HANDLE, INVALID_HANDLE_VALUE);
3064 WINAPI_CONSTANT(F_DWORD, MEM_COMMIT);
3065 WINAPI_CONSTANT(F_DWORD, MEM_FREE);
3066 WINAPI_CONSTANT(F_DWORD, MEM_IMAGE);
3067 WINAPI_CONSTANT(F_DWORD, MEM_MAPPED);
3068 WINAPI_CONSTANT(F_DWORD, MEM_PRIVATE);
3069 WINAPI_CONSTANT(F_DWORD, MEM_RESERVE);
3070 WINAPI_CONSTANT(F_DWORD, NMPWAIT_WAIT_FOREVER);
3071 WINAPI_CONSTANT(F_DWORD, OPEN_EXISTING);
3072 WINAPI_CONSTANT(F_DWORD, PAGE_EXECUTE);
3073 WINAPI_CONSTANT(F_DWORD, PAGE_EXECUTE_READ);
3074 WINAPI_CONSTANT(F_DWORD, PAGE_EXECUTE_READWRITE);
3075 WINAPI_CONSTANT(F_DWORD, PAGE_EXECUTE_WRITECOPY);
3076 WINAPI_CONSTANT(F_DWORD, PAGE_GUARD);
3077 WINAPI_CONSTANT(F_DWORD, PAGE_NOACCESS);
3078 WINAPI_CONSTANT(F_DWORD, PAGE_NOCACHE);
3079 WINAPI_CONSTANT(F_DWORD, PAGE_READONLY);
3080 WINAPI_CONSTANT(F_DWORD, PAGE_READWRITE);
3081 WINAPI_CONSTANT(F_DWORD, PAGE_WRITECOMBINE);
3082 WINAPI_CONSTANT(F_DWORD, PAGE_WRITECOPY);
3083 WINAPI_CONSTANT(F_DWORD, PIPE_ACCESS_DUPLEX);
3084 WINAPI_CONSTANT(F_DWORD, PIPE_ACCESS_INBOUND);
3085 WINAPI_CONSTANT(F_DWORD, PIPE_READMODE_MESSAGE);
3086 WINAPI_CONSTANT(F_DWORD, PIPE_TYPE_MESSAGE);
3087 WINAPI_CONSTANT(F_DWORD, PIPE_UNLIMITED_INSTANCES);
3088 WINAPI_CONSTANT(F_DWORD, PIPE_WAIT);
3089 WINAPI_CONSTANT(F_DWORD, PROCESS_ALL_ACCESS);
3090 WINAPI_CONSTANT(F_DWORD, SYNCHRONIZE);
3091 WINAPI_CONSTANT(F_DWORD, PROCESS_DUP_HANDLE);
3092 WINAPI_CONSTANT(F_DWORD, SEC_COMMIT);
3093 WINAPI_CONSTANT(F_DWORD, SEC_IMAGE);
3094 WINAPI_CONSTANT(F_DWORD, SEC_LARGE_PAGES);
3095 WINAPI_CONSTANT(F_DWORD, SEC_NOCACHE);
3096 WINAPI_CONSTANT(F_DWORD, SEC_RESERVE);
3097 WINAPI_CONSTANT(F_DWORD, SEC_WRITECOMBINE);
3098 WINAPI_CONSTANT(F_DWORD, STARTF_USESHOWWINDOW);
3099 WINAPI_CONSTANT(F_DWORD, STARTF_USESIZE);
3100 WINAPI_CONSTANT(F_DWORD, STARTF_USEPOSITION);
3101 WINAPI_CONSTANT(F_DWORD, STARTF_USECOUNTCHARS);
3102 WINAPI_CONSTANT(F_DWORD, STARTF_USEFILLATTRIBUTE);
3103 WINAPI_CONSTANT(F_DWORD, STARTF_RUNFULLSCREEN);
3104 WINAPI_CONSTANT(F_DWORD, STARTF_FORCEONFEEDBACK);
3105 WINAPI_CONSTANT(F_DWORD, STARTF_FORCEOFFFEEDBACK);
3106 WINAPI_CONSTANT(F_DWORD, STARTF_USESTDHANDLES);
3107 WINAPI_CONSTANT(F_DWORD, STARTF_USEHOTKEY);
3108 WINAPI_CONSTANT(F_DWORD, STARTF_TITLEISLINKNAME);
3109 WINAPI_CONSTANT(F_DWORD, STARTF_TITLEISAPPID);
3110 WINAPI_CONSTANT(F_DWORD, STARTF_PREVENTPINNING);
3111 WINAPI_CONSTANT(F_DWORD, STARTF_UNTRUSTEDSOURCE);
3112 WINAPI_CONSTANT(F_DWORD, STD_INPUT_HANDLE);
3113 WINAPI_CONSTANT(F_DWORD, STD_OUTPUT_HANDLE);
3114 WINAPI_CONSTANT(F_DWORD, STD_ERROR_HANDLE);
3115 WINAPI_CONSTANT(F_DWORD, STILL_ACTIVE);
3116 WINAPI_CONSTANT(F_DWORD, SW_HIDE);
3117 WINAPI_CONSTANT(F_DWORD, WAIT_OBJECT_0);
3118 WINAPI_CONSTANT(F_DWORD, WAIT_ABANDONED_0);
3119 WINAPI_CONSTANT(F_DWORD, WAIT_TIMEOUT);
3120
3121 WINAPI_CONSTANT(F_DWORD, ABOVE_NORMAL_PRIORITY_CLASS);
3122 WINAPI_CONSTANT(F_DWORD, BELOW_NORMAL_PRIORITY_CLASS);
3123 WINAPI_CONSTANT(F_DWORD, HIGH_PRIORITY_CLASS);
3124 WINAPI_CONSTANT(F_DWORD, IDLE_PRIORITY_CLASS);
3125 WINAPI_CONSTANT(F_DWORD, NORMAL_PRIORITY_CLASS);
3126 WINAPI_CONSTANT(F_DWORD, REALTIME_PRIORITY_CLASS);
3127
3128 WINAPI_CONSTANT(F_DWORD, CREATE_NO_WINDOW);
3129 WINAPI_CONSTANT(F_DWORD, DETACHED_PROCESS);
3130 WINAPI_CONSTANT(F_DWORD, CREATE_DEFAULT_ERROR_MODE);
3131 WINAPI_CONSTANT(F_DWORD, CREATE_BREAKAWAY_FROM_JOB);
3132
3133 WINAPI_CONSTANT(F_DWORD, FILE_TYPE_UNKNOWN);
3134 WINAPI_CONSTANT(F_DWORD, FILE_TYPE_DISK);
3135 WINAPI_CONSTANT(F_DWORD, FILE_TYPE_CHAR);
3136 WINAPI_CONSTANT(F_DWORD, FILE_TYPE_PIPE);
3137 WINAPI_CONSTANT(F_DWORD, FILE_TYPE_REMOTE);
3138
3139 WINAPI_CONSTANT("u", LOCALE_NAME_INVARIANT);
3140 WINAPI_CONSTANT(F_DWORD, LOCALE_NAME_MAX_LENGTH);
3141 WINAPI_CONSTANT("u", LOCALE_NAME_SYSTEM_DEFAULT);
3142 WINAPI_CONSTANT("u", LOCALE_NAME_USER_DEFAULT);
3143
3144 WINAPI_CONSTANT(F_DWORD, LCMAP_FULLWIDTH);
3145 WINAPI_CONSTANT(F_DWORD, LCMAP_HALFWIDTH);
3146 WINAPI_CONSTANT(F_DWORD, LCMAP_HIRAGANA);
3147 WINAPI_CONSTANT(F_DWORD, LCMAP_KATAKANA);
3148 WINAPI_CONSTANT(F_DWORD, LCMAP_LINGUISTIC_CASING);
3149 WINAPI_CONSTANT(F_DWORD, LCMAP_LOWERCASE);
3150 WINAPI_CONSTANT(F_DWORD, LCMAP_SIMPLIFIED_CHINESE);
3151 WINAPI_CONSTANT(F_DWORD, LCMAP_TITLECASE);
3152 WINAPI_CONSTANT(F_DWORD, LCMAP_TRADITIONAL_CHINESE);
3153 WINAPI_CONSTANT(F_DWORD, LCMAP_UPPERCASE);
3154
3155 WINAPI_CONSTANT(F_DWORD, COPY_FILE_ALLOW_DECRYPTED_DESTINATION);
3156 WINAPI_CONSTANT(F_DWORD, COPY_FILE_COPY_SYMLINK);
3157 WINAPI_CONSTANT(F_DWORD, COPY_FILE_FAIL_IF_EXISTS);
3158 WINAPI_CONSTANT(F_DWORD, COPY_FILE_NO_BUFFERING);
3159 WINAPI_CONSTANT(F_DWORD, COPY_FILE_NO_OFFLOAD);
3160 WINAPI_CONSTANT(F_DWORD, COPY_FILE_OPEN_SOURCE_FOR_WRITE);
3161 WINAPI_CONSTANT(F_DWORD, COPY_FILE_RESTARTABLE);
3162 WINAPI_CONSTANT(F_DWORD, COPY_FILE_REQUEST_SECURITY_PRIVILEGES);
3163 WINAPI_CONSTANT(F_DWORD, COPY_FILE_RESUME_FROM_PAUSE);
3164 #ifndef COPY_FILE_REQUEST_COMPRESSED_TRAFFIC
3165 // Only defined in newer WinSDKs
3166 #define COPY_FILE_REQUEST_COMPRESSED_TRAFFIC 0x10000000
3167 #endif
3168 WINAPI_CONSTANT(F_DWORD, COPY_FILE_REQUEST_COMPRESSED_TRAFFIC);
3169
3170 WINAPI_CONSTANT(F_DWORD, COPYFILE2_CALLBACK_CHUNK_STARTED);
3171 WINAPI_CONSTANT(F_DWORD, COPYFILE2_CALLBACK_CHUNK_FINISHED);
3172 WINAPI_CONSTANT(F_DWORD, COPYFILE2_CALLBACK_STREAM_STARTED);
3173 WINAPI_CONSTANT(F_DWORD, COPYFILE2_CALLBACK_STREAM_FINISHED);
3174 WINAPI_CONSTANT(F_DWORD, COPYFILE2_CALLBACK_POLL_CONTINUE);
3175 WINAPI_CONSTANT(F_DWORD, COPYFILE2_CALLBACK_ERROR);
3176
3177 WINAPI_CONSTANT(F_DWORD, COPYFILE2_PROGRESS_CONTINUE);
3178 WINAPI_CONSTANT(F_DWORD, COPYFILE2_PROGRESS_CANCEL);
3179 WINAPI_CONSTANT(F_DWORD, COPYFILE2_PROGRESS_STOP);
3180 WINAPI_CONSTANT(F_DWORD, COPYFILE2_PROGRESS_QUIET);
3181 WINAPI_CONSTANT(F_DWORD, COPYFILE2_PROGRESS_PAUSE);
3182
3183 WINAPI_CONSTANT("i", NULL);
3184
3185 return 0;
3186 }
3187
3188 static PyModuleDef_Slot winapi_slots[] = {
3189 {Py_mod_exec, winapi_exec},
3190 {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
3191 {Py_mod_gil, Py_MOD_GIL_NOT_USED},
3192 {0, NULL}
3193 };
3194
3195 static int
winapi_traverse(PyObject * module,visitproc visit,void * arg)3196 winapi_traverse(PyObject *module, visitproc visit, void *arg)
3197 {
3198 WinApiState *st = winapi_get_state(module);
3199 Py_VISIT(st->overlapped_type);
3200 return 0;
3201 }
3202
3203 static int
winapi_clear(PyObject * module)3204 winapi_clear(PyObject *module)
3205 {
3206 WinApiState *st = winapi_get_state(module);
3207 Py_CLEAR(st->overlapped_type);
3208 return 0;
3209 }
3210
3211 static void
winapi_free(void * module)3212 winapi_free(void *module)
3213 {
3214 winapi_clear((PyObject *)module);
3215 }
3216
3217 static struct PyModuleDef winapi_module = {
3218 PyModuleDef_HEAD_INIT,
3219 .m_name = "_winapi",
3220 .m_size = sizeof(WinApiState),
3221 .m_methods = winapi_functions,
3222 .m_slots = winapi_slots,
3223 .m_traverse = winapi_traverse,
3224 .m_clear = winapi_clear,
3225 .m_free = winapi_free,
3226 };
3227
3228 PyMODINIT_FUNC
PyInit__winapi(void)3229 PyInit__winapi(void)
3230 {
3231 return PyModuleDef_Init(&winapi_module);
3232 }
3233