我正在嘗試從管道中讀取。我成功地打開了管道并寫信給它,但由于某種原因,我無法讀取它。沒有錯誤,但 bytes_read 物件指示讀取了 368 個位元組,而緩沖區僅包含一個位元組。我查看了其他在 Python 中使用該函式的示例并嘗試了各種更改,但無論如何,我無法修復它。代碼的適用部分如下。代碼的運行部分呼叫 open_file,然后 write_file 發送握手,然后在回圈中呼叫 read_all_file_contents。
import ctypes as ct
from ctypes.wintypes import *
from .exceptions import WinapiException
__all__ = (
"open_file", "read_file", "write_file", "read_all_file_contents",
)
# Winapi constants
GENERIC_READ = -0x80000000
GENERIC_WRITE = 0x40000000
OPEN_EXISTING = 0x3
INVALID_HANDLE_VALUE = -0x1
ERROR_IO_PENDING = 0x3E5
# Winapi structures
class SecurityAttributes(ct.Structure):
_fields_ = (
("nLength", DWORD),
("lpSecurityDescriptor", LPVOID),
("bInheritHandle", BOOL)
)
class OverlappedUnionStruct(ct.Structure):
_fields_ = (
("Offset", DWORD),
("OffsetHigh", DWORD)
)
class OverlappedUnion(ct.Union):
_fields_ = (
("Offset", OverlappedUnionStruct),
("Pointer", LPVOID)
)
class Overlapped(ct.Structure):
_fields_ = (
("Internal", PULONG),
("InternalHigh", PULONG),
("Data", OverlappedUnion),
("hEvent", HANDLE)
)
# Winapi functions
k32 = ct.WinDLL("kernel32")
GetLastError = k32.GetLastError
GetLastError.restype = DWORD
CreateFile = k32.CreateFileA
CreateFile.argtypes = LPCSTR, DWORD, DWORD, SecurityAttributes, DWORD, DWORD, HANDLE
CreateFile.restype = HANDLE
ReadFile = k32.ReadFile
ReadFile.argtypes = HANDLE, LPVOID, DWORD, LPDWORD, ct.POINTER(Overlapped)
ReadFile.restype = BOOL
WriteFile = k32.WriteFile
WriteFile.argtypes = HANDLE, LPCVOID, DWORD, LPDWORD, ct.POINTER(Overlapped)
WriteFile.restype = BOOL
PeekNamedPipe = k32.PeekNamedPipe
PeekNamedPipe.argtypes = HANDLE, LPVOID, DWORD, LPDWORD, LPDWORD, LPDWORD
PeekNamedPipe.restype = BOOL
# Wrapper functions
def _peek_pipe(handle):
bytes_available = ct.c_ulong()
if not PeekNamedPipe(handle, None, 0, None, ct.byref(bytes_available), None):
raise WinapiException(f"PeekNamedPipe failed with error code {GetLastError()}")
print(f"Bytes available {bytes_available.value}")
return bytes_available.value
def open_file(file_name, access=GENERIC_READ | GENERIC_WRITE, share_mode=0, security_attribute=None,
creation_disposition=OPEN_EXISTING, flags=0, template_file=None):
file_name = ct.c_char_p(file_name.encode())
if security_attribute is None:
security_attribute = SecurityAttributes()
handle = CreateFile(file_name, access, share_mode, security_attribute, creation_disposition,
flags, template_file)
if handle == INVALID_HANDLE_VALUE:
raise WinapiException(f"CreateFile failed with error code {GetLastError()}")
return handle
def read_file(handle, size):
buf = (ct.c_char * size)()
bytes_read = DWORD(0)
print(f"reading {size}")
if ReadFile(handle, ct.byref(buf), size, ct.byref(bytes_read), None):
print(f"return data read {bytes_read.value}")
return bytes_read.value, buf.value
elif error_code := GetLastError() != ERROR_IO_PENDING:
raise WinapiException(f"ReadFile failed with error code {error_code}")
def read_all_file_contents(handle):
data = bytes()
total_bytes_read = 0
while bytes_available := _peek_pipe(handle):
print("calling read_file")
result = read_file(handle, bytes_available)
if result is None:
break
print(result)
total_bytes_read = result[0]
data = result[1]
return total_bytes_read, data
def write_file(handle, data):
bytes_written = ct.c_ulong()
print("writing time")
if WriteFile(handle, data, len(data), ct.byref(bytes_written), Overlapped()):
print("return bytes read")
return bytes_written.value
else:
raise WinapiException(f"WriteFile failed with error code {GetLastError()}")
運行程式時的輸出是這樣的:
Bytes available 0
...
Bytes available 368
calling read_file
reading 368
return data read 368
(368, b'\x01')
Bytes available 0
[Error from the main loop caused by only one byte being returned]
編輯:如果您有不和諧,這是一個可重現的示例(它必須是打開的):
from winapi import open_file, read_all_file_contents, write_file
import json
import struct
def payload_to_bytes(opcode, payload):
payload_bytes = json.dumps(payload).encode()
header = struct.pack("BL", opcode, len(payload_bytes))
return header payload_bytes
handle = open_file("\\\\?\\pipe\\discord-ipc-0")
# handshake
write_file(handle, payload_to_bytes(0, {
"v": 1,
"client_id": "1032756213445836801"
}))
while True:
bytes_read, raw = read_all_file_contents(handle)
if bytes_read == 0:
continue
opcode, length, _ = struct.unpack_from("BLh", raw, 0)
payload = json.loads(raw[8:8 length].decode())
print(payload)
break
uj5u.com熱心網友回復:
在讀取位元組緩沖區時 使用.raw而不是。只讀取以空字符結尾的字串。您看到的是一個位元組,因為下一個位元組為空。這是一個修復:.value.value
def read_file(handle, size):
buf = ct.create_string_buffer(size) # also works
bytes_read = DWORD() # 0 is the default
print(f"reading {size}")
if ReadFile(handle, ct.byref(buf), size, ct.byref(bytes_read), None):
data = bytes_read.raw[:bytes_read.value] # truncated to bytes read
print(f"return data read {data}")
return bytes_read.value, data
elif error_code := GetLastError() != ERROR_IO_PENDING:
raise WinapiException(f"ReadFile failed with error code {error_code}")
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/525634.html
標籤:Python温纳皮类型
