20
20
ERROR_MORE_DATA = 234
21
21
ERROR_IO_PENDING = 997
22
22
FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000
23
- INVALID_HANDLE_VALUE = wintypes . HANDLE ( - 1 ). value
23
+ INVALID_HANDLE_VALUE = - 1
24
24
25
25
id = 0
26
26
@@ -41,18 +41,8 @@ def _name_pipe():
41
41
42
42
def _win_error (code = None ):
43
43
if not code :
44
- code = ctypes .GetLastError ()
45
- buf = ctypes .create_unicode_buffer (256 )
46
- ctypes .FormatMessageW (
47
- FORMAT_MESSAGE_FROM_SYSTEM ,
48
- None ,
49
- code ,
50
- 0 ,
51
- buf ,
52
- len (buf ),
53
- None
54
- )
55
- return OSError (f"[OS Error { code } ] { buf .value } " )
44
+ code = ctypes .get_last_error ()
45
+ return ctypes .WinError (code )
56
46
57
47
class NPopen :
58
48
def __init__ (
@@ -69,6 +59,7 @@ def __init__(
69
59
if not isinstance (bufsize , int ):
70
60
raise TypeError ("bufsize must be an integer" )
71
61
62
+ self .kernel32 = ctypes .WinDLL ('kernel32' , use_last_error = True )
72
63
self .stream : Union [IO , None ] = None # I/O stream of the pipe
73
64
self ._path = _name_pipe () if name is None else rf"\\.\pipe\{ name } "
74
65
self ._rd = any (c in mode for c in "r+" )
@@ -110,13 +101,12 @@ def __init__(
110
101
111
102
# TODO: assess options: PIPE_WAIT, PIPE_NOWAIT, PIPE_ACCEPT_REMOTE_CLIENTS, PIPE_REJECT_REMOTE_CLIENTS
112
103
113
- max_instances = _wt (PIPE_UNLIMITED_INSTANCES )
114
- buffer_size = _wt (0 )
104
+ max_instances = _wt (1 ) # PIPE_UNLIMITED_INSTANCES returns 'invalid params'. Pipes are point-to-point anyway
105
+ buffer_size = _wt (65536 ) # in all examples online provide 64KB buffer. 0 doesn't fail CreateNamedPipeW, but maybe performance better?
115
106
timeout = _wt (0 )
116
107
117
-
118
108
# "open" named pipe
119
- self . _pipe = ctypes . windll .kernel32 .CreateNamedPipeW (
109
+ h = self .kernel32 .CreateNamedPipeW (
120
110
self ._path ,
121
111
access ,
122
112
pipe_mode ,
@@ -126,8 +116,9 @@ def __init__(
126
116
timeout ,
127
117
None ,
128
118
)
129
- if self . _pipe == INVALID_HANDLE_VALUE :
119
+ if h == INVALID_HANDLE_VALUE :
130
120
raise _win_error ()
121
+ self ._pipe = h
131
122
132
123
@property
133
124
def path (self ):
@@ -146,16 +137,16 @@ def close(self):
146
137
self .stream .close ()
147
138
self .stream = None
148
139
if self ._pipe is not None :
149
- if not ctypes . windll .kernel32 .CloseHandle (self ._pipe ):
140
+ if not self .kernel32 .CloseHandle (self ._pipe ):
150
141
raise _win_error ()
151
142
self ._pipe = None
152
143
153
144
def wait (self ):
154
145
"""Wait for the pipe to open (the other end to be opened) and return file object to read/write."""
155
146
if not self ._pipe :
156
147
raise RuntimeError ("pipe has already been closed." )
157
- if not ctypes . windll .kernel32 .ConnectNamedPipe (self ._pipe , None ):
158
- code = ctypes .GetLastError ()
148
+ if not self .kernel32 .ConnectNamedPipe (self ._pipe , None ):
149
+ code = ctypes .get_last_error ()
159
150
if code != ERROR_PIPE_CONNECTED : # (ok, just indicating that the client has already connected)(Issue#3)
160
151
raise _win_error (code )
161
152
@@ -208,6 +199,7 @@ class Win32RawIO(io.RawIOBase):
208
199
209
200
def __init__ (self , handle : PyHANDLE , rd : bool , wr : bool ) -> None :
210
201
super ().__init__ ()
202
+ self .kernel32 = ctypes .WinDLL ('kernel32' , use_last_error = True )
211
203
self .handle = handle # Underlying Windows handle.
212
204
self ._readable : bool = rd
213
205
self ._writable : bool = wr
@@ -232,7 +224,7 @@ def close(self) -> None:
232
224
if self .closed :
233
225
return
234
226
if self .handle is not None :
235
- ctypes . windll .kernel32 .CloseHandle (self .handle )
227
+ self .kernel32 .CloseHandle (self .handle )
236
228
self .handle = None
237
229
238
230
super ().close ()
@@ -248,9 +240,9 @@ def readinto(self, b: WritableBuffer) -> Union[int, None]:
248
240
nread = _wt (0 )
249
241
buf = (ctypes .c_char * size ).from_buffer (b )
250
242
251
- success = ctypes . windll .kernel32 .ReadFile (self .handle , buf , size , ctypes .byref (nread ), None )
243
+ success = self .kernel32 .ReadFile (self .handle , buf , size , ctypes .byref (nread ), None )
252
244
if not success :
253
- code = ctypes .GetLastError ()
245
+ code = ctypes .get_last_error ()
254
246
if code not in (ERROR_MORE_DATA , ERROR_IO_PENDING ):
255
247
raise _win_error (code )
256
248
@@ -267,8 +259,7 @@ def write(self, b):
267
259
size = len (b )
268
260
nwritten = wintypes .DWORD (0 )
269
261
buf = (ctypes .c_char * size ).from_buffer_copy (b )
270
- if not ctypes .windll .kernel32 .WriteFile (self .handle , buf , size , ctypes .byref (nwritten ), None ):
271
- code = ctypes .GetLastError ()
272
- raise _win_error (code )
262
+ if not self .kernel32 .WriteFile (self .handle , buf , size , ctypes .byref (nwritten ), None ):
263
+ raise _win_error ()
273
264
274
265
return nwritten .value
0 commit comments