• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 http://www.python.org/2.4/license for licensing details. */
36 
37 #include "Python.h"
38 #include "structmember.h"
39 
40 #define WINDOWS_LEAN_AND_MEAN
41 #include "windows.h"
42 #include <crtdbg.h>
43 #include "winreparse.h"
44 
45 #if defined(MS_WIN32) && !defined(MS_WIN64)
46 #define HANDLE_TO_PYNUM(handle) \
47     PyLong_FromUnsignedLong((unsigned long) handle)
48 #define PYNUM_TO_HANDLE(obj) ((HANDLE)PyLong_AsUnsignedLong(obj))
49 #define F_POINTER "k"
50 #define T_POINTER T_ULONG
51 #else
52 #define HANDLE_TO_PYNUM(handle) \
53     PyLong_FromUnsignedLongLong((unsigned long long) handle)
54 #define PYNUM_TO_HANDLE(obj) ((HANDLE)PyLong_AsUnsignedLongLong(obj))
55 #define F_POINTER "K"
56 #define T_POINTER T_ULONGLONG
57 #endif
58 
59 #define F_HANDLE F_POINTER
60 #define F_DWORD "k"
61 
62 #define T_HANDLE T_POINTER
63 
64 /* Grab CancelIoEx dynamically from kernel32 */
65 static int has_CancelIoEx = -1;
66 static BOOL (CALLBACK *Py_CancelIoEx)(HANDLE, LPOVERLAPPED);
67 
68 static int
check_CancelIoEx()69 check_CancelIoEx()
70 {
71     if (has_CancelIoEx == -1)
72     {
73         HINSTANCE hKernel32 = GetModuleHandle("KERNEL32");
74         * (FARPROC *) &Py_CancelIoEx = GetProcAddress(hKernel32,
75                                                       "CancelIoEx");
76         has_CancelIoEx = (Py_CancelIoEx != NULL);
77     }
78     return has_CancelIoEx;
79 }
80 
81 
82 /*
83  * A Python object wrapping an OVERLAPPED structure and other useful data
84  * for overlapped I/O
85  */
86 
87 typedef struct {
88     PyObject_HEAD
89     OVERLAPPED overlapped;
90     /* For convenience, we store the file handle too */
91     HANDLE handle;
92     /* Whether there's I/O in flight */
93     int pending;
94     /* Whether I/O completed successfully */
95     int completed;
96     /* Buffer used for reading (optional) */
97     PyObject *read_buffer;
98     /* Buffer used for writing (optional) */
99     Py_buffer write_buffer;
100 } OverlappedObject;
101 
102 static void
overlapped_dealloc(OverlappedObject * self)103 overlapped_dealloc(OverlappedObject *self)
104 {
105     DWORD bytes;
106     int err = GetLastError();
107 
108     if (self->pending) {
109         if (check_CancelIoEx() &&
110             Py_CancelIoEx(self->handle, &self->overlapped) &&
111             GetOverlappedResult(self->handle, &self->overlapped, &bytes, TRUE))
112         {
113             /* The operation is no longer pending -- nothing to do. */
114         }
115         else if (_Py_IsFinalizing())
116         {
117             /* The operation is still pending -- give a warning.  This
118                will probably only happen on Windows XP. */
119             PyErr_SetString(PyExc_RuntimeError,
120                             "I/O operations still in flight while destroying "
121                             "Overlapped object, the process may crash");
122             PyErr_WriteUnraisable(NULL);
123         }
124         else
125         {
126             /* The operation is still pending, but the process is
127                probably about to exit, so we need not worry too much
128                about memory leaks.  Leaking self prevents a potential
129                crash.  This can happen when a daemon thread is cleaned
130                up at exit -- see #19565.  We only expect to get here
131                on Windows XP. */
132             CloseHandle(self->overlapped.hEvent);
133             SetLastError(err);
134             return;
135         }
136     }
137 
138     CloseHandle(self->overlapped.hEvent);
139     SetLastError(err);
140     if (self->write_buffer.obj)
141         PyBuffer_Release(&self->write_buffer);
142     Py_CLEAR(self->read_buffer);
143     PyObject_Del(self);
144 }
145 
146 /*[clinic input]
147 module _winapi
148 class _winapi.Overlapped "OverlappedObject *" "&OverlappedType"
149 [clinic start generated code]*/
150 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=c13d3f5fd1dabb84]*/
151 
152 /*[python input]
153 def create_converter(type_, format_unit):
154     name = type_ + '_converter'
155     # registered upon creation by CConverter's metaclass
156     type(name, (CConverter,), {'type': type_, 'format_unit': format_unit})
157 
158 # format unit differs between platforms for these
159 create_converter('HANDLE', '" F_HANDLE "')
160 create_converter('HMODULE', '" F_HANDLE "')
161 create_converter('LPSECURITY_ATTRIBUTES', '" F_POINTER "')
162 create_converter('LPCVOID', '" F_POINTER "')
163 
164 create_converter('BOOL', 'i') # F_BOOL used previously (always 'i')
165 create_converter('DWORD', 'k') # F_DWORD is always "k" (which is much shorter)
166 create_converter('LPCTSTR', 's')
167 create_converter('LPCWSTR', 'u')
168 create_converter('LPWSTR', 'u')
169 create_converter('UINT', 'I') # F_UINT used previously (always 'I')
170 
171 class HANDLE_return_converter(CReturnConverter):
172     type = 'HANDLE'
173 
174     def render(self, function, data):
175         self.declare(data)
176         self.err_occurred_if("_return_value == INVALID_HANDLE_VALUE", data)
177         data.return_conversion.append(
178             'if (_return_value == NULL) {\n    Py_RETURN_NONE;\n}\n')
179         data.return_conversion.append(
180             'return_value = HANDLE_TO_PYNUM(_return_value);\n')
181 
182 class DWORD_return_converter(CReturnConverter):
183     type = 'DWORD'
184 
185     def render(self, function, data):
186         self.declare(data)
187         self.err_occurred_if("_return_value == PY_DWORD_MAX", data)
188         data.return_conversion.append(
189             'return_value = Py_BuildValue("k", _return_value);\n')
190 
191 class LPVOID_return_converter(CReturnConverter):
192     type = 'LPVOID'
193 
194     def render(self, function, data):
195         self.declare(data)
196         self.err_occurred_if("_return_value == NULL", data)
197         data.return_conversion.append(
198             'return_value = HANDLE_TO_PYNUM(_return_value);\n')
199 [python start generated code]*/
200 /*[python end generated code: output=da39a3ee5e6b4b0d input=79464c61a31ae932]*/
201 
202 #include "clinic/_winapi.c.h"
203 
204 /*[clinic input]
205 _winapi.Overlapped.GetOverlappedResult
206 
207     wait: bool
208     /
209 [clinic start generated code]*/
210 
211 static PyObject *
_winapi_Overlapped_GetOverlappedResult_impl(OverlappedObject * self,int wait)212 _winapi_Overlapped_GetOverlappedResult_impl(OverlappedObject *self, int wait)
213 /*[clinic end generated code: output=bdd0c1ed6518cd03 input=194505ee8e0e3565]*/
214 {
215     BOOL res;
216     DWORD transferred = 0;
217     DWORD err;
218 
219     Py_BEGIN_ALLOW_THREADS
220     res = GetOverlappedResult(self->handle, &self->overlapped, &transferred,
221                               wait != 0);
222     Py_END_ALLOW_THREADS
223 
224     err = res ? ERROR_SUCCESS : GetLastError();
225     switch (err) {
226         case ERROR_SUCCESS:
227         case ERROR_MORE_DATA:
228         case ERROR_OPERATION_ABORTED:
229             self->completed = 1;
230             self->pending = 0;
231             break;
232         case ERROR_IO_INCOMPLETE:
233             break;
234         default:
235             self->pending = 0;
236             return PyErr_SetExcFromWindowsErr(PyExc_OSError, err);
237     }
238     if (self->completed && self->read_buffer != NULL) {
239         assert(PyBytes_CheckExact(self->read_buffer));
240         if (transferred != PyBytes_GET_SIZE(self->read_buffer) &&
241             _PyBytes_Resize(&self->read_buffer, transferred))
242             return NULL;
243     }
244     return Py_BuildValue("II", (unsigned) transferred, (unsigned) err);
245 }
246 
247 /*[clinic input]
248 _winapi.Overlapped.getbuffer
249 [clinic start generated code]*/
250 
251 static PyObject *
_winapi_Overlapped_getbuffer_impl(OverlappedObject * self)252 _winapi_Overlapped_getbuffer_impl(OverlappedObject *self)
253 /*[clinic end generated code: output=95a3eceefae0f748 input=347fcfd56b4ceabd]*/
254 {
255     PyObject *res;
256     if (!self->completed) {
257         PyErr_SetString(PyExc_ValueError,
258                         "can't get read buffer before GetOverlappedResult() "
259                         "signals the operation completed");
260         return NULL;
261     }
262     res = self->read_buffer ? self->read_buffer : Py_None;
263     Py_INCREF(res);
264     return res;
265 }
266 
267 /*[clinic input]
268 _winapi.Overlapped.cancel
269 [clinic start generated code]*/
270 
271 static PyObject *
_winapi_Overlapped_cancel_impl(OverlappedObject * self)272 _winapi_Overlapped_cancel_impl(OverlappedObject *self)
273 /*[clinic end generated code: output=fcb9ab5df4ebdae5 input=cbf3da142290039f]*/
274 {
275     BOOL res = TRUE;
276 
277     if (self->pending) {
278         Py_BEGIN_ALLOW_THREADS
279         if (check_CancelIoEx())
280             res = Py_CancelIoEx(self->handle, &self->overlapped);
281         else
282             res = CancelIo(self->handle);
283         Py_END_ALLOW_THREADS
284     }
285 
286     /* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */
287     if (!res && GetLastError() != ERROR_NOT_FOUND)
288         return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
289     self->pending = 0;
290     Py_RETURN_NONE;
291 }
292 
293 static PyMethodDef overlapped_methods[] = {
294     _WINAPI_OVERLAPPED_GETOVERLAPPEDRESULT_METHODDEF
295     _WINAPI_OVERLAPPED_GETBUFFER_METHODDEF
296     _WINAPI_OVERLAPPED_CANCEL_METHODDEF
297     {NULL}
298 };
299 
300 static PyMemberDef overlapped_members[] = {
301     {"event", T_HANDLE,
302      offsetof(OverlappedObject, overlapped) + offsetof(OVERLAPPED, hEvent),
303      READONLY, "overlapped event handle"},
304     {NULL}
305 };
306 
307 PyTypeObject OverlappedType = {
308     PyVarObject_HEAD_INIT(NULL, 0)
309     /* tp_name           */ "_winapi.Overlapped",
310     /* tp_basicsize      */ sizeof(OverlappedObject),
311     /* tp_itemsize       */ 0,
312     /* tp_dealloc        */ (destructor) overlapped_dealloc,
313     /* tp_vectorcall_offset */ 0,
314     /* tp_getattr        */ 0,
315     /* tp_setattr        */ 0,
316     /* tp_as_async       */ 0,
317     /* tp_repr           */ 0,
318     /* tp_as_number      */ 0,
319     /* tp_as_sequence    */ 0,
320     /* tp_as_mapping     */ 0,
321     /* tp_hash           */ 0,
322     /* tp_call           */ 0,
323     /* tp_str            */ 0,
324     /* tp_getattro       */ 0,
325     /* tp_setattro       */ 0,
326     /* tp_as_buffer      */ 0,
327     /* tp_flags          */ Py_TPFLAGS_DEFAULT,
328     /* tp_doc            */ "OVERLAPPED structure wrapper",
329     /* tp_traverse       */ 0,
330     /* tp_clear          */ 0,
331     /* tp_richcompare    */ 0,
332     /* tp_weaklistoffset */ 0,
333     /* tp_iter           */ 0,
334     /* tp_iternext       */ 0,
335     /* tp_methods        */ overlapped_methods,
336     /* tp_members        */ overlapped_members,
337     /* tp_getset         */ 0,
338     /* tp_base           */ 0,
339     /* tp_dict           */ 0,
340     /* tp_descr_get      */ 0,
341     /* tp_descr_set      */ 0,
342     /* tp_dictoffset     */ 0,
343     /* tp_init           */ 0,
344     /* tp_alloc          */ 0,
345     /* tp_new            */ 0,
346 };
347 
348 static OverlappedObject *
new_overlapped(HANDLE handle)349 new_overlapped(HANDLE handle)
350 {
351     OverlappedObject *self;
352 
353     self = PyObject_New(OverlappedObject, &OverlappedType);
354     if (!self)
355         return NULL;
356     self->handle = handle;
357     self->read_buffer = NULL;
358     self->pending = 0;
359     self->completed = 0;
360     memset(&self->overlapped, 0, sizeof(OVERLAPPED));
361     memset(&self->write_buffer, 0, sizeof(Py_buffer));
362     /* Manual reset, initially non-signalled */
363     self->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
364     return self;
365 }
366 
367 /* -------------------------------------------------------------------- */
368 /* windows API functions */
369 
370 /*[clinic input]
371 _winapi.CloseHandle
372 
373     handle: HANDLE
374     /
375 
376 Close handle.
377 [clinic start generated code]*/
378 
379 static PyObject *
_winapi_CloseHandle_impl(PyObject * module,HANDLE handle)380 _winapi_CloseHandle_impl(PyObject *module, HANDLE handle)
381 /*[clinic end generated code: output=7ad37345f07bd782 input=7f0e4ac36e0352b8]*/
382 {
383     BOOL success;
384 
385     Py_BEGIN_ALLOW_THREADS
386     success = CloseHandle(handle);
387     Py_END_ALLOW_THREADS
388 
389     if (!success)
390         return PyErr_SetFromWindowsErr(0);
391 
392     Py_RETURN_NONE;
393 }
394 
395 /*[clinic input]
396 _winapi.ConnectNamedPipe
397 
398     handle: HANDLE
399     overlapped as use_overlapped: bool(accept={int}) = False
400 [clinic start generated code]*/
401 
402 static PyObject *
_winapi_ConnectNamedPipe_impl(PyObject * module,HANDLE handle,int use_overlapped)403 _winapi_ConnectNamedPipe_impl(PyObject *module, HANDLE handle,
404                               int use_overlapped)
405 /*[clinic end generated code: output=335a0e7086800671 input=34f937c1c86e5e68]*/
406 {
407     BOOL success;
408     OverlappedObject *overlapped = NULL;
409 
410     if (use_overlapped) {
411         overlapped = new_overlapped(handle);
412         if (!overlapped)
413             return NULL;
414     }
415 
416     Py_BEGIN_ALLOW_THREADS
417     success = ConnectNamedPipe(handle,
418                                overlapped ? &overlapped->overlapped : NULL);
419     Py_END_ALLOW_THREADS
420 
421     if (overlapped) {
422         int err = GetLastError();
423         /* Overlapped ConnectNamedPipe never returns a success code */
424         assert(success == 0);
425         if (err == ERROR_IO_PENDING)
426             overlapped->pending = 1;
427         else if (err == ERROR_PIPE_CONNECTED)
428             SetEvent(overlapped->overlapped.hEvent);
429         else {
430             Py_DECREF(overlapped);
431             return PyErr_SetFromWindowsErr(err);
432         }
433         return (PyObject *) overlapped;
434     }
435     if (!success)
436         return PyErr_SetFromWindowsErr(0);
437 
438     Py_RETURN_NONE;
439 }
440 
441 /*[clinic input]
442 _winapi.CreateFile -> HANDLE
443 
444     file_name: LPCTSTR
445     desired_access: DWORD
446     share_mode: DWORD
447     security_attributes: LPSECURITY_ATTRIBUTES
448     creation_disposition: DWORD
449     flags_and_attributes: DWORD
450     template_file: HANDLE
451     /
452 [clinic start generated code]*/
453 
454 static HANDLE
_winapi_CreateFile_impl(PyObject * module,LPCTSTR file_name,DWORD desired_access,DWORD share_mode,LPSECURITY_ATTRIBUTES security_attributes,DWORD creation_disposition,DWORD flags_and_attributes,HANDLE template_file)455 _winapi_CreateFile_impl(PyObject *module, LPCTSTR file_name,
456                         DWORD desired_access, DWORD share_mode,
457                         LPSECURITY_ATTRIBUTES security_attributes,
458                         DWORD creation_disposition,
459                         DWORD flags_and_attributes, HANDLE template_file)
460 /*[clinic end generated code: output=417ddcebfc5a3d53 input=6423c3e40372dbd5]*/
461 {
462     HANDLE handle;
463 
464     if (PySys_Audit("_winapi.CreateFile", "uIIII",
465                     file_name, desired_access, share_mode,
466                     creation_disposition, flags_and_attributes) < 0) {
467         return INVALID_HANDLE_VALUE;
468     }
469 
470     Py_BEGIN_ALLOW_THREADS
471     handle = CreateFile(file_name, desired_access,
472                         share_mode, security_attributes,
473                         creation_disposition,
474                         flags_and_attributes, template_file);
475     Py_END_ALLOW_THREADS
476 
477     if (handle == INVALID_HANDLE_VALUE)
478         PyErr_SetFromWindowsErr(0);
479 
480     return handle;
481 }
482 
483 /*[clinic input]
484 _winapi.CreateFileMapping -> HANDLE
485 
486     file_handle: HANDLE
487     security_attributes: LPSECURITY_ATTRIBUTES
488     protect: DWORD
489     max_size_high: DWORD
490     max_size_low: DWORD
491     name: LPCWSTR
492     /
493 [clinic start generated code]*/
494 
495 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)496 _winapi_CreateFileMapping_impl(PyObject *module, HANDLE file_handle,
497                                LPSECURITY_ATTRIBUTES security_attributes,
498                                DWORD protect, DWORD max_size_high,
499                                DWORD max_size_low, LPCWSTR name)
500 /*[clinic end generated code: output=6c0a4d5cf7f6fcc6 input=3dc5cf762a74dee8]*/
501 {
502     HANDLE handle;
503 
504     Py_BEGIN_ALLOW_THREADS
505     handle = CreateFileMappingW(file_handle, security_attributes,
506                                 protect, max_size_high, max_size_low,
507                                 name);
508     Py_END_ALLOW_THREADS
509 
510     if (handle == NULL) {
511         PyObject *temp = PyUnicode_FromWideChar(name, -1);
512         PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, 0, temp);
513         Py_XDECREF(temp);
514         handle = INVALID_HANDLE_VALUE;
515     }
516 
517     return handle;
518 }
519 
520 /*[clinic input]
521 _winapi.CreateJunction
522 
523     src_path: LPWSTR
524     dst_path: LPWSTR
525     /
526 [clinic start generated code]*/
527 
528 static PyObject *
_winapi_CreateJunction_impl(PyObject * module,LPWSTR src_path,LPWSTR dst_path)529 _winapi_CreateJunction_impl(PyObject *module, LPWSTR src_path,
530                             LPWSTR dst_path)
531 /*[clinic end generated code: output=66b7eb746e1dfa25 input=8cd1f9964b6e3d36]*/
532 {
533     /* Privilege adjustment */
534     HANDLE token = NULL;
535     TOKEN_PRIVILEGES tp;
536 
537     /* Reparse data buffer */
538     const USHORT prefix_len = 4;
539     USHORT print_len = 0;
540     USHORT rdb_size = 0;
541     _Py_PREPARSE_DATA_BUFFER rdb = NULL;
542 
543     /* Junction point creation */
544     HANDLE junction = NULL;
545     DWORD ret = 0;
546 
547     if (src_path == NULL || dst_path == NULL)
548         return PyErr_SetFromWindowsErr(ERROR_INVALID_PARAMETER);
549 
550     if (wcsncmp(src_path, L"\\??\\", prefix_len) == 0)
551         return PyErr_SetFromWindowsErr(ERROR_INVALID_PARAMETER);
552 
553     if (PySys_Audit("_winapi.CreateJunction", "uu", src_path, dst_path) < 0) {
554         return NULL;
555     }
556 
557     /* Adjust privileges to allow rewriting directory entry as a
558        junction point. */
559     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token))
560         goto cleanup;
561 
562     if (!LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &tp.Privileges[0].Luid))
563         goto cleanup;
564 
565     tp.PrivilegeCount = 1;
566     tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
567     if (!AdjustTokenPrivileges(token, FALSE, &tp, sizeof(TOKEN_PRIVILEGES),
568                                NULL, NULL))
569         goto cleanup;
570 
571     if (GetFileAttributesW(src_path) == INVALID_FILE_ATTRIBUTES)
572         goto cleanup;
573 
574     /* Store the absolute link target path length in print_len. */
575     print_len = (USHORT)GetFullPathNameW(src_path, 0, NULL, NULL);
576     if (print_len == 0)
577         goto cleanup;
578 
579     /* NUL terminator should not be part of print_len. */
580     --print_len;
581 
582     /* REPARSE_DATA_BUFFER usage is heavily under-documented, especially for
583        junction points. Here's what I've learned along the way:
584        - A junction point has two components: a print name and a substitute
585          name. They both describe the link target, but the substitute name is
586          the physical target and the print name is shown in directory listings.
587        - The print name must be a native name, prefixed with "\??\".
588        - Both names are stored after each other in the same buffer (the
589          PathBuffer) and both must be NUL-terminated.
590        - There are four members defining their respective offset and length
591          inside PathBuffer: SubstituteNameOffset, SubstituteNameLength,
592          PrintNameOffset and PrintNameLength.
593        - The total size we need to allocate for the REPARSE_DATA_BUFFER, thus,
594          is the sum of:
595          - the fixed header size (REPARSE_DATA_BUFFER_HEADER_SIZE)
596          - the size of the MountPointReparseBuffer member without the PathBuffer
597          - the size of the prefix ("\??\") in bytes
598          - the size of the print name in bytes
599          - the size of the substitute name in bytes
600          - the size of two NUL terminators in bytes */
601     rdb_size = _Py_REPARSE_DATA_BUFFER_HEADER_SIZE +
602         sizeof(rdb->MountPointReparseBuffer) -
603         sizeof(rdb->MountPointReparseBuffer.PathBuffer) +
604         /* Two +1's for NUL terminators. */
605         (prefix_len + print_len + 1 + print_len + 1) * sizeof(WCHAR);
606     rdb = (_Py_PREPARSE_DATA_BUFFER)PyMem_RawMalloc(rdb_size);
607     if (rdb == NULL)
608         goto cleanup;
609 
610     memset(rdb, 0, rdb_size);
611     rdb->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
612     rdb->ReparseDataLength = rdb_size - _Py_REPARSE_DATA_BUFFER_HEADER_SIZE;
613     rdb->MountPointReparseBuffer.SubstituteNameOffset = 0;
614     rdb->MountPointReparseBuffer.SubstituteNameLength =
615         (prefix_len + print_len) * sizeof(WCHAR);
616     rdb->MountPointReparseBuffer.PrintNameOffset =
617         rdb->MountPointReparseBuffer.SubstituteNameLength + sizeof(WCHAR);
618     rdb->MountPointReparseBuffer.PrintNameLength = print_len * sizeof(WCHAR);
619 
620     /* Store the full native path of link target at the substitute name
621        offset (0). */
622     wcscpy(rdb->MountPointReparseBuffer.PathBuffer, L"\\??\\");
623     if (GetFullPathNameW(src_path, print_len + 1,
624                          rdb->MountPointReparseBuffer.PathBuffer + prefix_len,
625                          NULL) == 0)
626         goto cleanup;
627 
628     /* Copy everything but the native prefix to the print name offset. */
629     wcscpy(rdb->MountPointReparseBuffer.PathBuffer +
630              prefix_len + print_len + 1,
631              rdb->MountPointReparseBuffer.PathBuffer + prefix_len);
632 
633     /* Create a directory for the junction point. */
634     if (!CreateDirectoryW(dst_path, NULL))
635         goto cleanup;
636 
637     junction = CreateFileW(dst_path, GENERIC_READ | GENERIC_WRITE, 0, NULL,
638         OPEN_EXISTING,
639         FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
640     if (junction == INVALID_HANDLE_VALUE)
641         goto cleanup;
642 
643     /* Make the directory entry a junction point. */
644     if (!DeviceIoControl(junction, FSCTL_SET_REPARSE_POINT, rdb, rdb_size,
645                          NULL, 0, &ret, NULL))
646         goto cleanup;
647 
648 cleanup:
649     ret = GetLastError();
650 
651     CloseHandle(token);
652     CloseHandle(junction);
653     PyMem_RawFree(rdb);
654 
655     if (ret != 0)
656         return PyErr_SetFromWindowsErr(ret);
657 
658     Py_RETURN_NONE;
659 }
660 
661 /*[clinic input]
662 _winapi.CreateNamedPipe -> HANDLE
663 
664     name: LPCTSTR
665     open_mode: DWORD
666     pipe_mode: DWORD
667     max_instances: DWORD
668     out_buffer_size: DWORD
669     in_buffer_size: DWORD
670     default_timeout: DWORD
671     security_attributes: LPSECURITY_ATTRIBUTES
672     /
673 [clinic start generated code]*/
674 
675 static HANDLE
_winapi_CreateNamedPipe_impl(PyObject * module,LPCTSTR 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)676 _winapi_CreateNamedPipe_impl(PyObject *module, LPCTSTR name, DWORD open_mode,
677                              DWORD pipe_mode, DWORD max_instances,
678                              DWORD out_buffer_size, DWORD in_buffer_size,
679                              DWORD default_timeout,
680                              LPSECURITY_ATTRIBUTES security_attributes)
681 /*[clinic end generated code: output=80f8c07346a94fbc input=5a73530b84d8bc37]*/
682 {
683     HANDLE handle;
684 
685     if (PySys_Audit("_winapi.CreateNamedPipe", "uII",
686                     name, open_mode, pipe_mode) < 0) {
687         return INVALID_HANDLE_VALUE;
688     }
689 
690     Py_BEGIN_ALLOW_THREADS
691     handle = CreateNamedPipe(name, open_mode, pipe_mode,
692                              max_instances, out_buffer_size,
693                              in_buffer_size, default_timeout,
694                              security_attributes);
695     Py_END_ALLOW_THREADS
696 
697     if (handle == INVALID_HANDLE_VALUE)
698         PyErr_SetFromWindowsErr(0);
699 
700     return handle;
701 }
702 
703 /*[clinic input]
704 _winapi.CreatePipe
705 
706     pipe_attrs: object
707         Ignored internally, can be None.
708     size: DWORD
709     /
710 
711 Create an anonymous pipe.
712 
713 Returns a 2-tuple of handles, to the read and write ends of the pipe.
714 [clinic start generated code]*/
715 
716 static PyObject *
_winapi_CreatePipe_impl(PyObject * module,PyObject * pipe_attrs,DWORD size)717 _winapi_CreatePipe_impl(PyObject *module, PyObject *pipe_attrs, DWORD size)
718 /*[clinic end generated code: output=1c4411d8699f0925 input=c4f2cfa56ef68d90]*/
719 {
720     HANDLE read_pipe;
721     HANDLE write_pipe;
722     BOOL result;
723 
724     if (PySys_Audit("_winapi.CreatePipe", NULL) < 0) {
725         return NULL;
726     }
727 
728     Py_BEGIN_ALLOW_THREADS
729     result = CreatePipe(&read_pipe, &write_pipe, NULL, size);
730     Py_END_ALLOW_THREADS
731 
732     if (! result)
733         return PyErr_SetFromWindowsErr(GetLastError());
734 
735     return Py_BuildValue(
736         "NN", HANDLE_TO_PYNUM(read_pipe), HANDLE_TO_PYNUM(write_pipe));
737 }
738 
739 /* helpers for createprocess */
740 
741 static unsigned long
getulong(PyObject * obj,const char * name)742 getulong(PyObject* obj, const char* name)
743 {
744     PyObject* value;
745     unsigned long ret;
746 
747     value = PyObject_GetAttrString(obj, name);
748     if (! value) {
749         PyErr_Clear(); /* FIXME: propagate error? */
750         return 0;
751     }
752     ret = PyLong_AsUnsignedLong(value);
753     Py_DECREF(value);
754     return ret;
755 }
756 
757 static HANDLE
gethandle(PyObject * obj,const char * name)758 gethandle(PyObject* obj, const char* name)
759 {
760     PyObject* value;
761     HANDLE ret;
762 
763     value = PyObject_GetAttrString(obj, name);
764     if (! value) {
765         PyErr_Clear(); /* FIXME: propagate error? */
766         return NULL;
767     }
768     if (value == Py_None)
769         ret = NULL;
770     else
771         ret = PYNUM_TO_HANDLE(value);
772     Py_DECREF(value);
773     return ret;
774 }
775 
776 static wchar_t *
getenvironment(PyObject * environment)777 getenvironment(PyObject* environment)
778 {
779     Py_ssize_t i, envsize, totalsize;
780     wchar_t *buffer = NULL, *p, *end;
781     PyObject *keys, *values;
782 
783     /* convert environment dictionary to windows environment string */
784     if (! PyMapping_Check(environment)) {
785         PyErr_SetString(
786             PyExc_TypeError, "environment must be dictionary or None");
787         return NULL;
788     }
789 
790     keys = PyMapping_Keys(environment);
791     if (!keys) {
792         return NULL;
793     }
794     values = PyMapping_Values(environment);
795     if (!values) {
796         goto error;
797     }
798 
799     envsize = PyList_GET_SIZE(keys);
800     if (PyList_GET_SIZE(values) != envsize) {
801         PyErr_SetString(PyExc_RuntimeError,
802             "environment changed size during iteration");
803         goto error;
804     }
805 
806     totalsize = 1; /* trailing null character */
807     for (i = 0; i < envsize; i++) {
808         PyObject* key = PyList_GET_ITEM(keys, i);
809         PyObject* value = PyList_GET_ITEM(values, i);
810         Py_ssize_t size;
811 
812         if (! PyUnicode_Check(key) || ! PyUnicode_Check(value)) {
813             PyErr_SetString(PyExc_TypeError,
814                 "environment can only contain strings");
815             goto error;
816         }
817         if (PyUnicode_FindChar(key, '\0', 0, PyUnicode_GET_LENGTH(key), 1) != -1 ||
818             PyUnicode_FindChar(value, '\0', 0, PyUnicode_GET_LENGTH(value), 1) != -1)
819         {
820             PyErr_SetString(PyExc_ValueError, "embedded null character");
821             goto error;
822         }
823         /* Search from index 1 because on Windows starting '=' is allowed for
824            defining hidden environment variables. */
825         if (PyUnicode_GET_LENGTH(key) == 0 ||
826             PyUnicode_FindChar(key, '=', 1, PyUnicode_GET_LENGTH(key), 1) != -1)
827         {
828             PyErr_SetString(PyExc_ValueError, "illegal environment variable name");
829             goto error;
830         }
831 
832         size = PyUnicode_AsWideChar(key, NULL, 0);
833         assert(size > 1);
834         if (totalsize > PY_SSIZE_T_MAX - size) {
835             PyErr_SetString(PyExc_OverflowError, "environment too long");
836             goto error;
837         }
838         totalsize += size;    /* including '=' */
839 
840         size = PyUnicode_AsWideChar(value, NULL, 0);
841         assert(size > 0);
842         if (totalsize > PY_SSIZE_T_MAX - size) {
843             PyErr_SetString(PyExc_OverflowError, "environment too long");
844             goto error;
845         }
846         totalsize += size;  /* including trailing '\0' */
847     }
848 
849     buffer = PyMem_NEW(wchar_t, totalsize);
850     if (! buffer) {
851         PyErr_NoMemory();
852         goto error;
853     }
854     p = buffer;
855     end = buffer + totalsize;
856 
857     for (i = 0; i < envsize; i++) {
858         PyObject* key = PyList_GET_ITEM(keys, i);
859         PyObject* value = PyList_GET_ITEM(values, i);
860         Py_ssize_t size = PyUnicode_AsWideChar(key, p, end - p);
861         assert(1 <= size && size < end - p);
862         p += size;
863         *p++ = L'=';
864         size = PyUnicode_AsWideChar(value, p, end - p);
865         assert(0 <= size && size < end - p);
866         p += size + 1;
867     }
868 
869     /* add trailing null character */
870     *p++ = L'\0';
871     assert(p == end);
872 
873  error:
874     Py_XDECREF(keys);
875     Py_XDECREF(values);
876     return buffer;
877 }
878 
879 static LPHANDLE
gethandlelist(PyObject * mapping,const char * name,Py_ssize_t * size)880 gethandlelist(PyObject *mapping, const char *name, Py_ssize_t *size)
881 {
882     LPHANDLE ret = NULL;
883     PyObject *value_fast = NULL;
884     PyObject *value;
885     Py_ssize_t i;
886 
887     value = PyMapping_GetItemString(mapping, name);
888     if (!value) {
889         PyErr_Clear();
890         return NULL;
891     }
892 
893     if (value == Py_None) {
894         goto cleanup;
895     }
896 
897     value_fast = PySequence_Fast(value, "handle_list must be a sequence or None");
898     if (value_fast == NULL)
899         goto cleanup;
900 
901     *size = PySequence_Fast_GET_SIZE(value_fast) * sizeof(HANDLE);
902 
903     /* Passing an empty array causes CreateProcess to fail so just don't set it */
904     if (*size == 0) {
905         goto cleanup;
906     }
907 
908     ret = PyMem_Malloc(*size);
909     if (ret == NULL)
910         goto cleanup;
911 
912     for (i = 0; i < PySequence_Fast_GET_SIZE(value_fast); i++) {
913         ret[i] = PYNUM_TO_HANDLE(PySequence_Fast_GET_ITEM(value_fast, i));
914         if (ret[i] == (HANDLE)-1 && PyErr_Occurred()) {
915             PyMem_Free(ret);
916             ret = NULL;
917             goto cleanup;
918         }
919     }
920 
921 cleanup:
922     Py_DECREF(value);
923     Py_XDECREF(value_fast);
924     return ret;
925 }
926 
927 typedef struct {
928     LPPROC_THREAD_ATTRIBUTE_LIST attribute_list;
929     LPHANDLE handle_list;
930 } AttributeList;
931 
932 static void
freeattributelist(AttributeList * attribute_list)933 freeattributelist(AttributeList *attribute_list)
934 {
935     if (attribute_list->attribute_list != NULL) {
936         DeleteProcThreadAttributeList(attribute_list->attribute_list);
937         PyMem_Free(attribute_list->attribute_list);
938     }
939 
940     PyMem_Free(attribute_list->handle_list);
941 
942     memset(attribute_list, 0, sizeof(*attribute_list));
943 }
944 
945 static int
getattributelist(PyObject * obj,const char * name,AttributeList * attribute_list)946 getattributelist(PyObject *obj, const char *name, AttributeList *attribute_list)
947 {
948     int ret = 0;
949     DWORD err;
950     BOOL result;
951     PyObject *value;
952     Py_ssize_t handle_list_size;
953     DWORD attribute_count = 0;
954     SIZE_T attribute_list_size = 0;
955 
956     value = PyObject_GetAttrString(obj, name);
957     if (!value) {
958         PyErr_Clear(); /* FIXME: propagate error? */
959         return 0;
960     }
961 
962     if (value == Py_None) {
963         ret = 0;
964         goto cleanup;
965     }
966 
967     if (!PyMapping_Check(value)) {
968         ret = -1;
969         PyErr_Format(PyExc_TypeError, "%s must be a mapping or None", name);
970         goto cleanup;
971     }
972 
973     attribute_list->handle_list = gethandlelist(value, "handle_list", &handle_list_size);
974     if (attribute_list->handle_list == NULL && PyErr_Occurred()) {
975         ret = -1;
976         goto cleanup;
977     }
978 
979     if (attribute_list->handle_list != NULL)
980         ++attribute_count;
981 
982     /* Get how many bytes we need for the attribute list */
983     result = InitializeProcThreadAttributeList(NULL, attribute_count, 0, &attribute_list_size);
984     if (result || GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
985         ret = -1;
986         PyErr_SetFromWindowsErr(GetLastError());
987         goto cleanup;
988     }
989 
990     attribute_list->attribute_list = PyMem_Malloc(attribute_list_size);
991     if (attribute_list->attribute_list == NULL) {
992         ret = -1;
993         goto cleanup;
994     }
995 
996     result = InitializeProcThreadAttributeList(
997         attribute_list->attribute_list,
998         attribute_count,
999         0,
1000         &attribute_list_size);
1001     if (!result) {
1002         err = GetLastError();
1003 
1004         /* So that we won't call DeleteProcThreadAttributeList */
1005         PyMem_Free(attribute_list->attribute_list);
1006         attribute_list->attribute_list = NULL;
1007 
1008         ret = -1;
1009         PyErr_SetFromWindowsErr(err);
1010         goto cleanup;
1011     }
1012 
1013     if (attribute_list->handle_list != NULL) {
1014         result = UpdateProcThreadAttribute(
1015             attribute_list->attribute_list,
1016             0,
1017             PROC_THREAD_ATTRIBUTE_HANDLE_LIST,
1018             attribute_list->handle_list,
1019             handle_list_size,
1020             NULL,
1021             NULL);
1022         if (!result) {
1023             ret = -1;
1024             PyErr_SetFromWindowsErr(GetLastError());
1025             goto cleanup;
1026         }
1027     }
1028 
1029 cleanup:
1030     Py_DECREF(value);
1031 
1032     if (ret < 0)
1033         freeattributelist(attribute_list);
1034 
1035     return ret;
1036 }
1037 
1038 /*[clinic input]
1039 _winapi.CreateProcess
1040 
1041     application_name: Py_UNICODE(accept={str, NoneType})
1042     command_line: object
1043         Can be str or None
1044     proc_attrs: object
1045         Ignored internally, can be None.
1046     thread_attrs: object
1047         Ignored internally, can be None.
1048     inherit_handles: BOOL
1049     creation_flags: DWORD
1050     env_mapping: object
1051     current_directory: Py_UNICODE(accept={str, NoneType})
1052     startup_info: object
1053     /
1054 
1055 Create a new process and its primary thread.
1056 
1057 The return value is a tuple of the process handle, thread handle,
1058 process ID, and thread ID.
1059 [clinic start generated code]*/
1060 
1061 static PyObject *
_winapi_CreateProcess_impl(PyObject * module,const Py_UNICODE * application_name,PyObject * command_line,PyObject * proc_attrs,PyObject * thread_attrs,BOOL inherit_handles,DWORD creation_flags,PyObject * env_mapping,const Py_UNICODE * current_directory,PyObject * startup_info)1062 _winapi_CreateProcess_impl(PyObject *module,
1063                            const Py_UNICODE *application_name,
1064                            PyObject *command_line, PyObject *proc_attrs,
1065                            PyObject *thread_attrs, BOOL inherit_handles,
1066                            DWORD creation_flags, PyObject *env_mapping,
1067                            const Py_UNICODE *current_directory,
1068                            PyObject *startup_info)
1069 /*[clinic end generated code: output=9b2423a609230132 input=42ac293eaea03fc4]*/
1070 {
1071     PyObject *ret = NULL;
1072     BOOL result;
1073     PROCESS_INFORMATION pi;
1074     STARTUPINFOEXW si;
1075     wchar_t *wenvironment = NULL;
1076     wchar_t *command_line_copy = NULL;
1077     AttributeList attribute_list = {0};
1078 
1079     if (PySys_Audit("_winapi.CreateProcess", "uuu", application_name,
1080                     command_line, current_directory) < 0) {
1081         return NULL;
1082     }
1083 
1084     ZeroMemory(&si, sizeof(si));
1085     si.StartupInfo.cb = sizeof(si);
1086 
1087     /* note: we only support a small subset of all SI attributes */
1088     si.StartupInfo.dwFlags = getulong(startup_info, "dwFlags");
1089     si.StartupInfo.wShowWindow = (WORD)getulong(startup_info, "wShowWindow");
1090     si.StartupInfo.hStdInput = gethandle(startup_info, "hStdInput");
1091     si.StartupInfo.hStdOutput = gethandle(startup_info, "hStdOutput");
1092     si.StartupInfo.hStdError = gethandle(startup_info, "hStdError");
1093     if (PyErr_Occurred())
1094         goto cleanup;
1095 
1096     if (env_mapping != Py_None) {
1097         wenvironment = getenvironment(env_mapping);
1098         if (wenvironment == NULL) {
1099             goto cleanup;
1100         }
1101     }
1102 
1103     if (getattributelist(startup_info, "lpAttributeList", &attribute_list) < 0)
1104         goto cleanup;
1105 
1106     si.lpAttributeList = attribute_list.attribute_list;
1107     if (PyUnicode_Check(command_line)) {
1108         command_line_copy = PyUnicode_AsWideCharString(command_line, NULL);
1109         if (command_line_copy == NULL) {
1110             goto cleanup;
1111         }
1112     }
1113     else if (command_line != Py_None) {
1114         PyErr_Format(PyExc_TypeError,
1115                      "CreateProcess() argument 2 must be str or None, not %s",
1116                      Py_TYPE(command_line)->tp_name);
1117         goto cleanup;
1118     }
1119 
1120 
1121     Py_BEGIN_ALLOW_THREADS
1122     result = CreateProcessW(application_name,
1123                            command_line_copy,
1124                            NULL,
1125                            NULL,
1126                            inherit_handles,
1127                            creation_flags | EXTENDED_STARTUPINFO_PRESENT |
1128                            CREATE_UNICODE_ENVIRONMENT,
1129                            wenvironment,
1130                            current_directory,
1131                            (LPSTARTUPINFOW)&si,
1132                            &pi);
1133     Py_END_ALLOW_THREADS
1134 
1135     if (!result) {
1136         PyErr_SetFromWindowsErr(GetLastError());
1137         goto cleanup;
1138     }
1139 
1140     ret = Py_BuildValue("NNkk",
1141                         HANDLE_TO_PYNUM(pi.hProcess),
1142                         HANDLE_TO_PYNUM(pi.hThread),
1143                         pi.dwProcessId,
1144                         pi.dwThreadId);
1145 
1146 cleanup:
1147     PyMem_Free(command_line_copy);
1148     PyMem_Free(wenvironment);
1149     freeattributelist(&attribute_list);
1150 
1151     return ret;
1152 }
1153 
1154 /*[clinic input]
1155 _winapi.DuplicateHandle -> HANDLE
1156 
1157     source_process_handle: HANDLE
1158     source_handle: HANDLE
1159     target_process_handle: HANDLE
1160     desired_access: DWORD
1161     inherit_handle: BOOL
1162     options: DWORD = 0
1163     /
1164 
1165 Return a duplicate handle object.
1166 
1167 The duplicate handle refers to the same object as the original
1168 handle. Therefore, any changes to the object are reflected
1169 through both handles.
1170 [clinic start generated code]*/
1171 
1172 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)1173 _winapi_DuplicateHandle_impl(PyObject *module, HANDLE source_process_handle,
1174                              HANDLE source_handle,
1175                              HANDLE target_process_handle,
1176                              DWORD desired_access, BOOL inherit_handle,
1177                              DWORD options)
1178 /*[clinic end generated code: output=ad9711397b5dcd4e input=b933e3f2356a8c12]*/
1179 {
1180     HANDLE target_handle;
1181     BOOL result;
1182 
1183     Py_BEGIN_ALLOW_THREADS
1184     result = DuplicateHandle(
1185         source_process_handle,
1186         source_handle,
1187         target_process_handle,
1188         &target_handle,
1189         desired_access,
1190         inherit_handle,
1191         options
1192     );
1193     Py_END_ALLOW_THREADS
1194 
1195     if (! result) {
1196         PyErr_SetFromWindowsErr(GetLastError());
1197         return INVALID_HANDLE_VALUE;
1198     }
1199 
1200     return target_handle;
1201 }
1202 
1203 /*[clinic input]
1204 _winapi.ExitProcess
1205 
1206     ExitCode: UINT
1207     /
1208 
1209 [clinic start generated code]*/
1210 
1211 static PyObject *
_winapi_ExitProcess_impl(PyObject * module,UINT ExitCode)1212 _winapi_ExitProcess_impl(PyObject *module, UINT ExitCode)
1213 /*[clinic end generated code: output=a387deb651175301 input=4f05466a9406c558]*/
1214 {
1215     #if defined(Py_DEBUG)
1216         SetErrorMode(SEM_FAILCRITICALERRORS|SEM_NOALIGNMENTFAULTEXCEPT|
1217                      SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX);
1218         _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
1219     #endif
1220 
1221     ExitProcess(ExitCode);
1222 
1223     return NULL;
1224 }
1225 
1226 /*[clinic input]
1227 _winapi.GetCurrentProcess -> HANDLE
1228 
1229 Return a handle object for the current process.
1230 [clinic start generated code]*/
1231 
1232 static HANDLE
_winapi_GetCurrentProcess_impl(PyObject * module)1233 _winapi_GetCurrentProcess_impl(PyObject *module)
1234 /*[clinic end generated code: output=ddeb4dd2ffadf344 input=b213403fd4b96b41]*/
1235 {
1236     return GetCurrentProcess();
1237 }
1238 
1239 /*[clinic input]
1240 _winapi.GetExitCodeProcess -> DWORD
1241 
1242     process: HANDLE
1243     /
1244 
1245 Return the termination status of the specified process.
1246 [clinic start generated code]*/
1247 
1248 static DWORD
_winapi_GetExitCodeProcess_impl(PyObject * module,HANDLE process)1249 _winapi_GetExitCodeProcess_impl(PyObject *module, HANDLE process)
1250 /*[clinic end generated code: output=b4620bdf2bccf36b input=61b6bfc7dc2ee374]*/
1251 {
1252     DWORD exit_code;
1253     BOOL result;
1254 
1255     result = GetExitCodeProcess(process, &exit_code);
1256 
1257     if (! result) {
1258         PyErr_SetFromWindowsErr(GetLastError());
1259         exit_code = PY_DWORD_MAX;
1260     }
1261 
1262     return exit_code;
1263 }
1264 
1265 /*[clinic input]
1266 _winapi.GetLastError -> DWORD
1267 [clinic start generated code]*/
1268 
1269 static DWORD
_winapi_GetLastError_impl(PyObject * module)1270 _winapi_GetLastError_impl(PyObject *module)
1271 /*[clinic end generated code: output=8585b827cb1a92c5 input=62d47fb9bce038ba]*/
1272 {
1273     return GetLastError();
1274 }
1275 
1276 /*[clinic input]
1277 _winapi.GetModuleFileName
1278 
1279     module_handle: HMODULE
1280     /
1281 
1282 Return the fully-qualified path for the file that contains module.
1283 
1284 The module must have been loaded by the current process.
1285 
1286 The module parameter should be a handle to the loaded module
1287 whose path is being requested. If this parameter is 0,
1288 GetModuleFileName retrieves the path of the executable file
1289 of the current process.
1290 [clinic start generated code]*/
1291 
1292 static PyObject *
_winapi_GetModuleFileName_impl(PyObject * module,HMODULE module_handle)1293 _winapi_GetModuleFileName_impl(PyObject *module, HMODULE module_handle)
1294 /*[clinic end generated code: output=85b4b728c5160306 input=6d66ff7deca5d11f]*/
1295 {
1296     BOOL result;
1297     WCHAR filename[MAX_PATH];
1298 
1299     Py_BEGIN_ALLOW_THREADS
1300     result = GetModuleFileNameW(module_handle, filename, MAX_PATH);
1301     filename[MAX_PATH-1] = '\0';
1302     Py_END_ALLOW_THREADS
1303 
1304     if (! result)
1305         return PyErr_SetFromWindowsErr(GetLastError());
1306 
1307     return PyUnicode_FromWideChar(filename, wcslen(filename));
1308 }
1309 
1310 /*[clinic input]
1311 _winapi.GetStdHandle -> HANDLE
1312 
1313     std_handle: DWORD
1314         One of STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, or STD_ERROR_HANDLE.
1315     /
1316 
1317 Return a handle to the specified standard device.
1318 
1319 The integer associated with the handle object is returned.
1320 [clinic start generated code]*/
1321 
1322 static HANDLE
_winapi_GetStdHandle_impl(PyObject * module,DWORD std_handle)1323 _winapi_GetStdHandle_impl(PyObject *module, DWORD std_handle)
1324 /*[clinic end generated code: output=0e613001e73ab614 input=07016b06a2fc8826]*/
1325 {
1326     HANDLE handle;
1327 
1328     Py_BEGIN_ALLOW_THREADS
1329     handle = GetStdHandle(std_handle);
1330     Py_END_ALLOW_THREADS
1331 
1332     if (handle == INVALID_HANDLE_VALUE)
1333         PyErr_SetFromWindowsErr(GetLastError());
1334 
1335     return handle;
1336 }
1337 
1338 /*[clinic input]
1339 _winapi.GetVersion -> long
1340 
1341 Return the version number of the current operating system.
1342 [clinic start generated code]*/
1343 
1344 static long
_winapi_GetVersion_impl(PyObject * module)1345 _winapi_GetVersion_impl(PyObject *module)
1346 /*[clinic end generated code: output=e41f0db5a3b82682 input=e21dff8d0baeded2]*/
1347 /* Disable deprecation warnings about GetVersionEx as the result is
1348    being passed straight through to the caller, who is responsible for
1349    using it correctly. */
1350 #pragma warning(push)
1351 #pragma warning(disable:4996)
1352 
1353 {
1354     return GetVersion();
1355 }
1356 
1357 #pragma warning(pop)
1358 
1359 /*[clinic input]
1360 _winapi.MapViewOfFile -> LPVOID
1361 
1362     file_map: HANDLE
1363     desired_access: DWORD
1364     file_offset_high: DWORD
1365     file_offset_low: DWORD
1366     number_bytes: size_t
1367     /
1368 [clinic start generated code]*/
1369 
1370 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)1371 _winapi_MapViewOfFile_impl(PyObject *module, HANDLE file_map,
1372                            DWORD desired_access, DWORD file_offset_high,
1373                            DWORD file_offset_low, size_t number_bytes)
1374 /*[clinic end generated code: output=f23b1ee4823663e3 input=177471073be1a103]*/
1375 {
1376     LPVOID address;
1377 
1378     Py_BEGIN_ALLOW_THREADS
1379     address = MapViewOfFile(file_map, desired_access, file_offset_high,
1380                             file_offset_low, number_bytes);
1381     Py_END_ALLOW_THREADS
1382 
1383     if (address == NULL)
1384         PyErr_SetFromWindowsErr(0);
1385 
1386     return address;
1387 }
1388 
1389 /*[clinic input]
1390 _winapi.OpenFileMapping -> HANDLE
1391 
1392     desired_access: DWORD
1393     inherit_handle: BOOL
1394     name: LPCWSTR
1395     /
1396 [clinic start generated code]*/
1397 
1398 static HANDLE
_winapi_OpenFileMapping_impl(PyObject * module,DWORD desired_access,BOOL inherit_handle,LPCWSTR name)1399 _winapi_OpenFileMapping_impl(PyObject *module, DWORD desired_access,
1400                              BOOL inherit_handle, LPCWSTR name)
1401 /*[clinic end generated code: output=08cc44def1cb11f1 input=131f2a405359de7f]*/
1402 {
1403     HANDLE handle;
1404 
1405     Py_BEGIN_ALLOW_THREADS
1406     handle = OpenFileMappingW(desired_access, inherit_handle, name);
1407     Py_END_ALLOW_THREADS
1408 
1409     if (handle == NULL) {
1410         PyObject *temp = PyUnicode_FromWideChar(name, -1);
1411         PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, 0, temp);
1412         Py_XDECREF(temp);
1413         handle = INVALID_HANDLE_VALUE;
1414     }
1415 
1416     return handle;
1417 }
1418 
1419 /*[clinic input]
1420 _winapi.OpenProcess -> HANDLE
1421 
1422     desired_access: DWORD
1423     inherit_handle: BOOL
1424     process_id: DWORD
1425     /
1426 [clinic start generated code]*/
1427 
1428 static HANDLE
_winapi_OpenProcess_impl(PyObject * module,DWORD desired_access,BOOL inherit_handle,DWORD process_id)1429 _winapi_OpenProcess_impl(PyObject *module, DWORD desired_access,
1430                          BOOL inherit_handle, DWORD process_id)
1431 /*[clinic end generated code: output=b42b6b81ea5a0fc3 input=ec98c4cf4ea2ec36]*/
1432 {
1433     HANDLE handle;
1434 
1435     if (PySys_Audit("_winapi.OpenProcess", "II",
1436                     process_id, desired_access) < 0) {
1437         return INVALID_HANDLE_VALUE;
1438     }
1439 
1440     Py_BEGIN_ALLOW_THREADS
1441     handle = OpenProcess(desired_access, inherit_handle, process_id);
1442     Py_END_ALLOW_THREADS
1443     if (handle == NULL) {
1444         PyErr_SetFromWindowsErr(GetLastError());
1445         handle = INVALID_HANDLE_VALUE;
1446     }
1447 
1448     return handle;
1449 }
1450 
1451 /*[clinic input]
1452 _winapi.PeekNamedPipe
1453 
1454     handle: HANDLE
1455     size: int = 0
1456     /
1457 [clinic start generated code]*/
1458 
1459 static PyObject *
_winapi_PeekNamedPipe_impl(PyObject * module,HANDLE handle,int size)1460 _winapi_PeekNamedPipe_impl(PyObject *module, HANDLE handle, int size)
1461 /*[clinic end generated code: output=d0c3e29e49d323dd input=c7aa53bfbce69d70]*/
1462 {
1463     PyObject *buf = NULL;
1464     DWORD nread, navail, nleft;
1465     BOOL ret;
1466 
1467     if (size < 0) {
1468         PyErr_SetString(PyExc_ValueError, "negative size");
1469         return NULL;
1470     }
1471 
1472     if (size) {
1473         buf = PyBytes_FromStringAndSize(NULL, size);
1474         if (!buf)
1475             return NULL;
1476         Py_BEGIN_ALLOW_THREADS
1477         ret = PeekNamedPipe(handle, PyBytes_AS_STRING(buf), size, &nread,
1478                             &navail, &nleft);
1479         Py_END_ALLOW_THREADS
1480         if (!ret) {
1481             Py_DECREF(buf);
1482             return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1483         }
1484         if (_PyBytes_Resize(&buf, nread))
1485             return NULL;
1486         return Py_BuildValue("NII", buf, navail, nleft);
1487     }
1488     else {
1489         Py_BEGIN_ALLOW_THREADS
1490         ret = PeekNamedPipe(handle, NULL, 0, NULL, &navail, &nleft);
1491         Py_END_ALLOW_THREADS
1492         if (!ret) {
1493             return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1494         }
1495         return Py_BuildValue("II", navail, nleft);
1496     }
1497 }
1498 
1499 /*[clinic input]
1500 _winapi.ReadFile
1501 
1502     handle: HANDLE
1503     size: DWORD
1504     overlapped as use_overlapped: bool(accept={int}) = False
1505 [clinic start generated code]*/
1506 
1507 static PyObject *
_winapi_ReadFile_impl(PyObject * module,HANDLE handle,DWORD size,int use_overlapped)1508 _winapi_ReadFile_impl(PyObject *module, HANDLE handle, DWORD size,
1509                       int use_overlapped)
1510 /*[clinic end generated code: output=d3d5b44a8201b944 input=08c439d03a11aac5]*/
1511 {
1512     DWORD nread;
1513     PyObject *buf;
1514     BOOL ret;
1515     DWORD err;
1516     OverlappedObject *overlapped = NULL;
1517 
1518     buf = PyBytes_FromStringAndSize(NULL, size);
1519     if (!buf)
1520         return NULL;
1521     if (use_overlapped) {
1522         overlapped = new_overlapped(handle);
1523         if (!overlapped) {
1524             Py_DECREF(buf);
1525             return NULL;
1526         }
1527         /* Steals reference to buf */
1528         overlapped->read_buffer = buf;
1529     }
1530 
1531     Py_BEGIN_ALLOW_THREADS
1532     ret = ReadFile(handle, PyBytes_AS_STRING(buf), size, &nread,
1533                    overlapped ? &overlapped->overlapped : NULL);
1534     Py_END_ALLOW_THREADS
1535 
1536     err = ret ? 0 : GetLastError();
1537 
1538     if (overlapped) {
1539         if (!ret) {
1540             if (err == ERROR_IO_PENDING)
1541                 overlapped->pending = 1;
1542             else if (err != ERROR_MORE_DATA) {
1543                 Py_DECREF(overlapped);
1544                 return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1545             }
1546         }
1547         return Py_BuildValue("NI", (PyObject *) overlapped, err);
1548     }
1549 
1550     if (!ret && err != ERROR_MORE_DATA) {
1551         Py_DECREF(buf);
1552         return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1553     }
1554     if (_PyBytes_Resize(&buf, nread))
1555         return NULL;
1556     return Py_BuildValue("NI", buf, err);
1557 }
1558 
1559 /*[clinic input]
1560 _winapi.SetNamedPipeHandleState
1561 
1562     named_pipe: HANDLE
1563     mode: object
1564     max_collection_count: object
1565     collect_data_timeout: object
1566     /
1567 [clinic start generated code]*/
1568 
1569 static PyObject *
_winapi_SetNamedPipeHandleState_impl(PyObject * module,HANDLE named_pipe,PyObject * mode,PyObject * max_collection_count,PyObject * collect_data_timeout)1570 _winapi_SetNamedPipeHandleState_impl(PyObject *module, HANDLE named_pipe,
1571                                      PyObject *mode,
1572                                      PyObject *max_collection_count,
1573                                      PyObject *collect_data_timeout)
1574 /*[clinic end generated code: output=f2129d222cbfa095 input=9142d72163d0faa6]*/
1575 {
1576     PyObject *oArgs[3] = {mode, max_collection_count, collect_data_timeout};
1577     DWORD dwArgs[3], *pArgs[3] = {NULL, NULL, NULL};
1578     int i;
1579     BOOL b;
1580 
1581     for (i = 0 ; i < 3 ; i++) {
1582         if (oArgs[i] != Py_None) {
1583             dwArgs[i] = PyLong_AsUnsignedLongMask(oArgs[i]);
1584             if (PyErr_Occurred())
1585                 return NULL;
1586             pArgs[i] = &dwArgs[i];
1587         }
1588     }
1589 
1590     Py_BEGIN_ALLOW_THREADS
1591     b = SetNamedPipeHandleState(named_pipe, pArgs[0], pArgs[1], pArgs[2]);
1592     Py_END_ALLOW_THREADS
1593 
1594     if (!b)
1595         return PyErr_SetFromWindowsErr(0);
1596 
1597     Py_RETURN_NONE;
1598 }
1599 
1600 
1601 /*[clinic input]
1602 _winapi.TerminateProcess
1603 
1604     handle: HANDLE
1605     exit_code: UINT
1606     /
1607 
1608 Terminate the specified process and all of its threads.
1609 [clinic start generated code]*/
1610 
1611 static PyObject *
_winapi_TerminateProcess_impl(PyObject * module,HANDLE handle,UINT exit_code)1612 _winapi_TerminateProcess_impl(PyObject *module, HANDLE handle,
1613                               UINT exit_code)
1614 /*[clinic end generated code: output=f4e99ac3f0b1f34a input=d6bc0aa1ee3bb4df]*/
1615 {
1616     BOOL result;
1617 
1618     if (PySys_Audit("_winapi.TerminateProcess", "nI",
1619                     (Py_ssize_t)handle, exit_code) < 0) {
1620         return NULL;
1621     }
1622 
1623     result = TerminateProcess(handle, exit_code);
1624 
1625     if (! result)
1626         return PyErr_SetFromWindowsErr(GetLastError());
1627 
1628     Py_RETURN_NONE;
1629 }
1630 
1631 /*[clinic input]
1632 _winapi.VirtualQuerySize -> size_t
1633 
1634     address: LPCVOID
1635     /
1636 [clinic start generated code]*/
1637 
1638 static size_t
_winapi_VirtualQuerySize_impl(PyObject * module,LPCVOID address)1639 _winapi_VirtualQuerySize_impl(PyObject *module, LPCVOID address)
1640 /*[clinic end generated code: output=40c8e0ff5ec964df input=6b784a69755d0bb6]*/
1641 {
1642     SIZE_T size_of_buf;
1643     MEMORY_BASIC_INFORMATION mem_basic_info;
1644     SIZE_T region_size;
1645 
1646     Py_BEGIN_ALLOW_THREADS
1647     size_of_buf = VirtualQuery(address, &mem_basic_info, sizeof(mem_basic_info));
1648     Py_END_ALLOW_THREADS
1649 
1650     if (size_of_buf == 0)
1651         PyErr_SetFromWindowsErr(0);
1652 
1653     region_size = mem_basic_info.RegionSize;
1654     return region_size;
1655 }
1656 
1657 /*[clinic input]
1658 _winapi.WaitNamedPipe
1659 
1660     name: LPCTSTR
1661     timeout: DWORD
1662     /
1663 [clinic start generated code]*/
1664 
1665 static PyObject *
_winapi_WaitNamedPipe_impl(PyObject * module,LPCTSTR name,DWORD timeout)1666 _winapi_WaitNamedPipe_impl(PyObject *module, LPCTSTR name, DWORD timeout)
1667 /*[clinic end generated code: output=c2866f4439b1fe38 input=36fc781291b1862c]*/
1668 {
1669     BOOL success;
1670 
1671     Py_BEGIN_ALLOW_THREADS
1672     success = WaitNamedPipe(name, timeout);
1673     Py_END_ALLOW_THREADS
1674 
1675     if (!success)
1676         return PyErr_SetFromWindowsErr(0);
1677 
1678     Py_RETURN_NONE;
1679 }
1680 
1681 /*[clinic input]
1682 _winapi.WaitForMultipleObjects
1683 
1684     handle_seq: object
1685     wait_flag: BOOL
1686     milliseconds: DWORD(c_default='INFINITE') = _winapi.INFINITE
1687     /
1688 [clinic start generated code]*/
1689 
1690 static PyObject *
_winapi_WaitForMultipleObjects_impl(PyObject * module,PyObject * handle_seq,BOOL wait_flag,DWORD milliseconds)1691 _winapi_WaitForMultipleObjects_impl(PyObject *module, PyObject *handle_seq,
1692                                     BOOL wait_flag, DWORD milliseconds)
1693 /*[clinic end generated code: output=295e3f00b8e45899 input=36f76ca057cd28a0]*/
1694 {
1695     DWORD result;
1696     HANDLE handles[MAXIMUM_WAIT_OBJECTS];
1697     HANDLE sigint_event = NULL;
1698     Py_ssize_t nhandles, i;
1699 
1700     if (!PySequence_Check(handle_seq)) {
1701         PyErr_Format(PyExc_TypeError,
1702                      "sequence type expected, got '%s'",
1703                      Py_TYPE(handle_seq)->tp_name);
1704         return NULL;
1705     }
1706     nhandles = PySequence_Length(handle_seq);
1707     if (nhandles == -1)
1708         return NULL;
1709     if (nhandles < 0 || nhandles >= MAXIMUM_WAIT_OBJECTS - 1) {
1710         PyErr_Format(PyExc_ValueError,
1711                      "need at most %zd handles, got a sequence of length %zd",
1712                      MAXIMUM_WAIT_OBJECTS - 1, nhandles);
1713         return NULL;
1714     }
1715     for (i = 0; i < nhandles; i++) {
1716         HANDLE h;
1717         PyObject *v = PySequence_GetItem(handle_seq, i);
1718         if (v == NULL)
1719             return NULL;
1720         if (!PyArg_Parse(v, F_HANDLE, &h)) {
1721             Py_DECREF(v);
1722             return NULL;
1723         }
1724         handles[i] = h;
1725         Py_DECREF(v);
1726     }
1727     /* If this is the main thread then make the wait interruptible
1728        by Ctrl-C unless we are waiting for *all* handles */
1729     if (!wait_flag && _PyOS_IsMainThread()) {
1730         sigint_event = _PyOS_SigintEvent();
1731         assert(sigint_event != NULL);
1732         handles[nhandles++] = sigint_event;
1733     }
1734 
1735     Py_BEGIN_ALLOW_THREADS
1736     if (sigint_event != NULL)
1737         ResetEvent(sigint_event);
1738     result = WaitForMultipleObjects((DWORD) nhandles, handles,
1739                                     wait_flag, milliseconds);
1740     Py_END_ALLOW_THREADS
1741 
1742     if (result == WAIT_FAILED)
1743         return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1744     else if (sigint_event != NULL && result == WAIT_OBJECT_0 + nhandles - 1) {
1745         errno = EINTR;
1746         return PyErr_SetFromErrno(PyExc_OSError);
1747     }
1748 
1749     return PyLong_FromLong((int) result);
1750 }
1751 
1752 /*[clinic input]
1753 _winapi.WaitForSingleObject -> long
1754 
1755     handle: HANDLE
1756     milliseconds: DWORD
1757     /
1758 
1759 Wait for a single object.
1760 
1761 Wait until the specified object is in the signaled state or
1762 the time-out interval elapses. The timeout value is specified
1763 in milliseconds.
1764 [clinic start generated code]*/
1765 
1766 static long
_winapi_WaitForSingleObject_impl(PyObject * module,HANDLE handle,DWORD milliseconds)1767 _winapi_WaitForSingleObject_impl(PyObject *module, HANDLE handle,
1768                                  DWORD milliseconds)
1769 /*[clinic end generated code: output=3c4715d8f1b39859 input=443d1ab076edc7b1]*/
1770 {
1771     DWORD result;
1772 
1773     Py_BEGIN_ALLOW_THREADS
1774     result = WaitForSingleObject(handle, milliseconds);
1775     Py_END_ALLOW_THREADS
1776 
1777     if (result == WAIT_FAILED) {
1778         PyErr_SetFromWindowsErr(GetLastError());
1779         return -1;
1780     }
1781 
1782     return result;
1783 }
1784 
1785 /*[clinic input]
1786 _winapi.WriteFile
1787 
1788     handle: HANDLE
1789     buffer: object
1790     overlapped as use_overlapped: bool(accept={int}) = False
1791 [clinic start generated code]*/
1792 
1793 static PyObject *
_winapi_WriteFile_impl(PyObject * module,HANDLE handle,PyObject * buffer,int use_overlapped)1794 _winapi_WriteFile_impl(PyObject *module, HANDLE handle, PyObject *buffer,
1795                        int use_overlapped)
1796 /*[clinic end generated code: output=2ca80f6bf3fa92e3 input=11eae2a03aa32731]*/
1797 {
1798     Py_buffer _buf, *buf;
1799     DWORD len, written;
1800     BOOL ret;
1801     DWORD err;
1802     OverlappedObject *overlapped = NULL;
1803 
1804     if (use_overlapped) {
1805         overlapped = new_overlapped(handle);
1806         if (!overlapped)
1807             return NULL;
1808         buf = &overlapped->write_buffer;
1809     }
1810     else
1811         buf = &_buf;
1812 
1813     if (!PyArg_Parse(buffer, "y*", buf)) {
1814         Py_XDECREF(overlapped);
1815         return NULL;
1816     }
1817 
1818     Py_BEGIN_ALLOW_THREADS
1819     len = (DWORD)Py_MIN(buf->len, PY_DWORD_MAX);
1820     ret = WriteFile(handle, buf->buf, len, &written,
1821                     overlapped ? &overlapped->overlapped : NULL);
1822     Py_END_ALLOW_THREADS
1823 
1824     err = ret ? 0 : GetLastError();
1825 
1826     if (overlapped) {
1827         if (!ret) {
1828             if (err == ERROR_IO_PENDING)
1829                 overlapped->pending = 1;
1830             else {
1831                 Py_DECREF(overlapped);
1832                 return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1833             }
1834         }
1835         return Py_BuildValue("NI", (PyObject *) overlapped, err);
1836     }
1837 
1838     PyBuffer_Release(buf);
1839     if (!ret)
1840         return PyErr_SetExcFromWindowsErr(PyExc_OSError, 0);
1841     return Py_BuildValue("II", written, err);
1842 }
1843 
1844 /*[clinic input]
1845 _winapi.GetACP
1846 
1847 Get the current Windows ANSI code page identifier.
1848 [clinic start generated code]*/
1849 
1850 static PyObject *
_winapi_GetACP_impl(PyObject * module)1851 _winapi_GetACP_impl(PyObject *module)
1852 /*[clinic end generated code: output=f7ee24bf705dbb88 input=1433c96d03a05229]*/
1853 {
1854     return PyLong_FromUnsignedLong(GetACP());
1855 }
1856 
1857 /*[clinic input]
1858 _winapi.GetFileType -> DWORD
1859 
1860     handle: HANDLE
1861 [clinic start generated code]*/
1862 
1863 static DWORD
_winapi_GetFileType_impl(PyObject * module,HANDLE handle)1864 _winapi_GetFileType_impl(PyObject *module, HANDLE handle)
1865 /*[clinic end generated code: output=92b8466ac76ecc17 input=0058366bc40bbfbf]*/
1866 {
1867     DWORD result;
1868 
1869     Py_BEGIN_ALLOW_THREADS
1870     result = GetFileType(handle);
1871     Py_END_ALLOW_THREADS
1872 
1873     if (result == FILE_TYPE_UNKNOWN && GetLastError() != NO_ERROR) {
1874         PyErr_SetFromWindowsErr(0);
1875         return -1;
1876     }
1877 
1878     return result;
1879 }
1880 
1881 
1882 static PyMethodDef winapi_functions[] = {
1883     _WINAPI_CLOSEHANDLE_METHODDEF
1884     _WINAPI_CONNECTNAMEDPIPE_METHODDEF
1885     _WINAPI_CREATEFILE_METHODDEF
1886     _WINAPI_CREATEFILEMAPPING_METHODDEF
1887     _WINAPI_CREATENAMEDPIPE_METHODDEF
1888     _WINAPI_CREATEPIPE_METHODDEF
1889     _WINAPI_CREATEPROCESS_METHODDEF
1890     _WINAPI_CREATEJUNCTION_METHODDEF
1891     _WINAPI_DUPLICATEHANDLE_METHODDEF
1892     _WINAPI_EXITPROCESS_METHODDEF
1893     _WINAPI_GETCURRENTPROCESS_METHODDEF
1894     _WINAPI_GETEXITCODEPROCESS_METHODDEF
1895     _WINAPI_GETLASTERROR_METHODDEF
1896     _WINAPI_GETMODULEFILENAME_METHODDEF
1897     _WINAPI_GETSTDHANDLE_METHODDEF
1898     _WINAPI_GETVERSION_METHODDEF
1899     _WINAPI_MAPVIEWOFFILE_METHODDEF
1900     _WINAPI_OPENFILEMAPPING_METHODDEF
1901     _WINAPI_OPENPROCESS_METHODDEF
1902     _WINAPI_PEEKNAMEDPIPE_METHODDEF
1903     _WINAPI_READFILE_METHODDEF
1904     _WINAPI_SETNAMEDPIPEHANDLESTATE_METHODDEF
1905     _WINAPI_TERMINATEPROCESS_METHODDEF
1906     _WINAPI_VIRTUALQUERYSIZE_METHODDEF
1907     _WINAPI_WAITNAMEDPIPE_METHODDEF
1908     _WINAPI_WAITFORMULTIPLEOBJECTS_METHODDEF
1909     _WINAPI_WAITFORSINGLEOBJECT_METHODDEF
1910     _WINAPI_WRITEFILE_METHODDEF
1911     _WINAPI_GETACP_METHODDEF
1912     _WINAPI_GETFILETYPE_METHODDEF
1913     {NULL, NULL}
1914 };
1915 
1916 static struct PyModuleDef winapi_module = {
1917     PyModuleDef_HEAD_INIT,
1918     "_winapi",
1919     NULL,
1920     -1,
1921     winapi_functions,
1922     NULL,
1923     NULL,
1924     NULL,
1925     NULL
1926 };
1927 
1928 #define WINAPI_CONSTANT(fmt, con) \
1929     PyDict_SetItemString(d, #con, Py_BuildValue(fmt, con))
1930 
1931 PyMODINIT_FUNC
PyInit__winapi(void)1932 PyInit__winapi(void)
1933 {
1934     PyObject *d;
1935     PyObject *m;
1936 
1937     if (PyType_Ready(&OverlappedType) < 0)
1938         return NULL;
1939 
1940     m = PyModule_Create(&winapi_module);
1941     if (m == NULL)
1942         return NULL;
1943     d = PyModule_GetDict(m);
1944 
1945     PyDict_SetItemString(d, "Overlapped", (PyObject *) &OverlappedType);
1946 
1947     /* constants */
1948     WINAPI_CONSTANT(F_DWORD, CREATE_NEW_CONSOLE);
1949     WINAPI_CONSTANT(F_DWORD, CREATE_NEW_PROCESS_GROUP);
1950     WINAPI_CONSTANT(F_DWORD, DUPLICATE_SAME_ACCESS);
1951     WINAPI_CONSTANT(F_DWORD, DUPLICATE_CLOSE_SOURCE);
1952     WINAPI_CONSTANT(F_DWORD, ERROR_ALREADY_EXISTS);
1953     WINAPI_CONSTANT(F_DWORD, ERROR_BROKEN_PIPE);
1954     WINAPI_CONSTANT(F_DWORD, ERROR_IO_PENDING);
1955     WINAPI_CONSTANT(F_DWORD, ERROR_MORE_DATA);
1956     WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
1957     WINAPI_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES);
1958     WINAPI_CONSTANT(F_DWORD, ERROR_MORE_DATA);
1959     WINAPI_CONSTANT(F_DWORD, ERROR_NETNAME_DELETED);
1960     WINAPI_CONSTANT(F_DWORD, ERROR_NO_DATA);
1961     WINAPI_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES);
1962     WINAPI_CONSTANT(F_DWORD, ERROR_OPERATION_ABORTED);
1963     WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_BUSY);
1964     WINAPI_CONSTANT(F_DWORD, ERROR_PIPE_CONNECTED);
1965     WINAPI_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT);
1966     WINAPI_CONSTANT(F_DWORD, FILE_FLAG_FIRST_PIPE_INSTANCE);
1967     WINAPI_CONSTANT(F_DWORD, FILE_FLAG_OVERLAPPED);
1968     WINAPI_CONSTANT(F_DWORD, FILE_GENERIC_READ);
1969     WINAPI_CONSTANT(F_DWORD, FILE_GENERIC_WRITE);
1970     WINAPI_CONSTANT(F_DWORD, FILE_MAP_ALL_ACCESS);
1971     WINAPI_CONSTANT(F_DWORD, FILE_MAP_COPY);
1972     WINAPI_CONSTANT(F_DWORD, FILE_MAP_EXECUTE);
1973     WINAPI_CONSTANT(F_DWORD, FILE_MAP_READ);
1974     WINAPI_CONSTANT(F_DWORD, FILE_MAP_WRITE);
1975     WINAPI_CONSTANT(F_DWORD, GENERIC_READ);
1976     WINAPI_CONSTANT(F_DWORD, GENERIC_WRITE);
1977     WINAPI_CONSTANT(F_DWORD, INFINITE);
1978     WINAPI_CONSTANT(F_HANDLE, INVALID_HANDLE_VALUE);
1979     WINAPI_CONSTANT(F_DWORD, MEM_COMMIT);
1980     WINAPI_CONSTANT(F_DWORD, MEM_FREE);
1981     WINAPI_CONSTANT(F_DWORD, MEM_IMAGE);
1982     WINAPI_CONSTANT(F_DWORD, MEM_MAPPED);
1983     WINAPI_CONSTANT(F_DWORD, MEM_PRIVATE);
1984     WINAPI_CONSTANT(F_DWORD, MEM_RESERVE);
1985     WINAPI_CONSTANT(F_DWORD, NMPWAIT_WAIT_FOREVER);
1986     WINAPI_CONSTANT(F_DWORD, OPEN_EXISTING);
1987     WINAPI_CONSTANT(F_DWORD, PAGE_EXECUTE);
1988     WINAPI_CONSTANT(F_DWORD, PAGE_EXECUTE_READ);
1989     WINAPI_CONSTANT(F_DWORD, PAGE_EXECUTE_READWRITE);
1990     WINAPI_CONSTANT(F_DWORD, PAGE_EXECUTE_WRITECOPY);
1991     WINAPI_CONSTANT(F_DWORD, PAGE_GUARD);
1992     WINAPI_CONSTANT(F_DWORD, PAGE_NOACCESS);
1993     WINAPI_CONSTANT(F_DWORD, PAGE_NOCACHE);
1994     WINAPI_CONSTANT(F_DWORD, PAGE_READONLY);
1995     WINAPI_CONSTANT(F_DWORD, PAGE_READWRITE);
1996     WINAPI_CONSTANT(F_DWORD, PAGE_WRITECOMBINE);
1997     WINAPI_CONSTANT(F_DWORD, PAGE_WRITECOPY);
1998     WINAPI_CONSTANT(F_DWORD, PIPE_ACCESS_DUPLEX);
1999     WINAPI_CONSTANT(F_DWORD, PIPE_ACCESS_INBOUND);
2000     WINAPI_CONSTANT(F_DWORD, PIPE_READMODE_MESSAGE);
2001     WINAPI_CONSTANT(F_DWORD, PIPE_TYPE_MESSAGE);
2002     WINAPI_CONSTANT(F_DWORD, PIPE_UNLIMITED_INSTANCES);
2003     WINAPI_CONSTANT(F_DWORD, PIPE_WAIT);
2004     WINAPI_CONSTANT(F_DWORD, PROCESS_ALL_ACCESS);
2005     WINAPI_CONSTANT(F_DWORD, SYNCHRONIZE);
2006     WINAPI_CONSTANT(F_DWORD, PROCESS_DUP_HANDLE);
2007     WINAPI_CONSTANT(F_DWORD, SEC_COMMIT);
2008     WINAPI_CONSTANT(F_DWORD, SEC_IMAGE);
2009     WINAPI_CONSTANT(F_DWORD, SEC_LARGE_PAGES);
2010     WINAPI_CONSTANT(F_DWORD, SEC_NOCACHE);
2011     WINAPI_CONSTANT(F_DWORD, SEC_RESERVE);
2012     WINAPI_CONSTANT(F_DWORD, SEC_WRITECOMBINE);
2013     WINAPI_CONSTANT(F_DWORD, STARTF_USESHOWWINDOW);
2014     WINAPI_CONSTANT(F_DWORD, STARTF_USESTDHANDLES);
2015     WINAPI_CONSTANT(F_DWORD, STD_INPUT_HANDLE);
2016     WINAPI_CONSTANT(F_DWORD, STD_OUTPUT_HANDLE);
2017     WINAPI_CONSTANT(F_DWORD, STD_ERROR_HANDLE);
2018     WINAPI_CONSTANT(F_DWORD, STILL_ACTIVE);
2019     WINAPI_CONSTANT(F_DWORD, SW_HIDE);
2020     WINAPI_CONSTANT(F_DWORD, WAIT_OBJECT_0);
2021     WINAPI_CONSTANT(F_DWORD, WAIT_ABANDONED_0);
2022     WINAPI_CONSTANT(F_DWORD, WAIT_TIMEOUT);
2023 
2024     WINAPI_CONSTANT(F_DWORD, ABOVE_NORMAL_PRIORITY_CLASS);
2025     WINAPI_CONSTANT(F_DWORD, BELOW_NORMAL_PRIORITY_CLASS);
2026     WINAPI_CONSTANT(F_DWORD, HIGH_PRIORITY_CLASS);
2027     WINAPI_CONSTANT(F_DWORD, IDLE_PRIORITY_CLASS);
2028     WINAPI_CONSTANT(F_DWORD, NORMAL_PRIORITY_CLASS);
2029     WINAPI_CONSTANT(F_DWORD, REALTIME_PRIORITY_CLASS);
2030 
2031     WINAPI_CONSTANT(F_DWORD, CREATE_NO_WINDOW);
2032     WINAPI_CONSTANT(F_DWORD, DETACHED_PROCESS);
2033     WINAPI_CONSTANT(F_DWORD, CREATE_DEFAULT_ERROR_MODE);
2034     WINAPI_CONSTANT(F_DWORD, CREATE_BREAKAWAY_FROM_JOB);
2035 
2036     WINAPI_CONSTANT(F_DWORD, FILE_TYPE_UNKNOWN);
2037     WINAPI_CONSTANT(F_DWORD, FILE_TYPE_DISK);
2038     WINAPI_CONSTANT(F_DWORD, FILE_TYPE_CHAR);
2039     WINAPI_CONSTANT(F_DWORD, FILE_TYPE_PIPE);
2040     WINAPI_CONSTANT(F_DWORD, FILE_TYPE_REMOTE);
2041 
2042     WINAPI_CONSTANT("i", NULL);
2043 
2044     return m;
2045 }
2046