2020ERROR_MORE_DATA = 234
2121ERROR_IO_PENDING = 997
2222FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000
23- INVALID_HANDLE_VALUE = wintypes . HANDLE ( - 1 ). value
23+ INVALID_HANDLE_VALUE = - 1
2424
2525id = 0
2626
@@ -41,18 +41,8 @@ def _name_pipe():
4141
4242def _win_error (code = None ):
4343 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 )
5646
5747class NPopen :
5848 def __init__ (
@@ -69,6 +59,7 @@ def __init__(
6959 if not isinstance (bufsize , int ):
7060 raise TypeError ("bufsize must be an integer" )
7161
62+ self .kernel32 = ctypes .WinDLL ('kernel32' , use_last_error = True )
7263 self .stream : Union [IO , None ] = None # I/O stream of the pipe
7364 self ._path = _name_pipe () if name is None else rf"\\.\pipe\{ name } "
7465 self ._rd = any (c in mode for c in "r+" )
@@ -110,13 +101,12 @@ def __init__(
110101
111102 # TODO: assess options: PIPE_WAIT, PIPE_NOWAIT, PIPE_ACCEPT_REMOTE_CLIENTS, PIPE_REJECT_REMOTE_CLIENTS
112103
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?
115106 timeout = _wt (0 )
116107
117-
118108 # "open" named pipe
119- self . _pipe = ctypes . windll .kernel32 .CreateNamedPipeW (
109+ h = self .kernel32 .CreateNamedPipeW (
120110 self ._path ,
121111 access ,
122112 pipe_mode ,
@@ -126,8 +116,9 @@ def __init__(
126116 timeout ,
127117 None ,
128118 )
129- if self . _pipe == INVALID_HANDLE_VALUE :
119+ if h == INVALID_HANDLE_VALUE :
130120 raise _win_error ()
121+ self ._pipe = h
131122
132123 @property
133124 def path (self ):
@@ -146,16 +137,16 @@ def close(self):
146137 self .stream .close ()
147138 self .stream = None
148139 if self ._pipe is not None :
149- if not ctypes . windll .kernel32 .CloseHandle (self ._pipe ):
140+ if not self .kernel32 .CloseHandle (self ._pipe ):
150141 raise _win_error ()
151142 self ._pipe = None
152143
153144 def wait (self ):
154145 """Wait for the pipe to open (the other end to be opened) and return file object to read/write."""
155146 if not self ._pipe :
156147 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 ()
159150 if code != ERROR_PIPE_CONNECTED : # (ok, just indicating that the client has already connected)(Issue#3)
160151 raise _win_error (code )
161152
@@ -208,6 +199,7 @@ class Win32RawIO(io.RawIOBase):
208199
209200 def __init__ (self , handle : PyHANDLE , rd : bool , wr : bool ) -> None :
210201 super ().__init__ ()
202+ self .kernel32 = ctypes .WinDLL ('kernel32' , use_last_error = True )
211203 self .handle = handle # Underlying Windows handle.
212204 self ._readable : bool = rd
213205 self ._writable : bool = wr
@@ -232,7 +224,7 @@ def close(self) -> None:
232224 if self .closed :
233225 return
234226 if self .handle is not None :
235- ctypes . windll .kernel32 .CloseHandle (self .handle )
227+ self .kernel32 .CloseHandle (self .handle )
236228 self .handle = None
237229
238230 super ().close ()
@@ -248,9 +240,9 @@ def readinto(self, b: WritableBuffer) -> Union[int, None]:
248240 nread = _wt (0 )
249241 buf = (ctypes .c_char * size ).from_buffer (b )
250242
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 )
252244 if not success :
253- code = ctypes .GetLastError ()
245+ code = ctypes .get_last_error ()
254246 if code not in (ERROR_MORE_DATA , ERROR_IO_PENDING ):
255247 raise _win_error (code )
256248
@@ -267,8 +259,7 @@ def write(self, b):
267259 size = len (b )
268260 nwritten = wintypes .DWORD (0 )
269261 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 ()
273264
274265 return nwritten .value
0 commit comments