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