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