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