Python 3.2では、ctypes.windll.kernel32.DeviceIoControl関数によって返されたデータからStructureオブジェクトを作成しています。これが完了したら、Structureフィールドにアクセスしてデータを返すことができます。しかし、私が何かをすると、ファイルを開くなどのメモリを使用すると、構造内のデータが変更されます。私が結果に貼り付けた出力の最初の部分では、予想されることがあります。ただし、ファイルが開かれ、構造体のフィールドが再度印刷された後、値が変更されています。なぜデータが変更されているのか、それが起こるのを止める方法はわかりません。さらに多くのメモリを割り当てると、Pythonのctypes構造が上書きされる
構造:
class DISK_GEOMETRY(ctypes.Structure):
'''
Disk Geometry Data Structure
http://msdn.microsoft.com/en-us/library/aa363972(v=vs.85).aspx
'''
_fields_ = [("Cylinders", wintypes.LARGE_INTEGER),
("MediaType", wintypes.BYTE), #MEDIA_TYPE
("TracksPerCylinder", wintypes.DWORD),
("SectorsPerTrack", wintypes.DWORD),
("BytesPerSector", wintypes.DWORD)]
class DISK_GEOMETRY_EX(ctypes.Structure):
'''
Disk Geometry EX Data Structure
http://msdn.microsoft.com/en-us/library/aa363970(v=vs.85).aspx
'''
_fields_ = [("Geometry", DISK_GEOMETRY),
("DiskSize", wintypes.LARGE_INTEGER),
("Data[1]", wintypes.BYTE)]
のDeviceIoControl:
class DeviceIoControl:
def __init__(self, path):
self.path = path
def __DeviceIoControl(self, devicehandle, IoControlCode, input, output):
'''
DeviceIoControl Function
http://msdn.microsoft.com/en-us/library/aa363216(v=vs.85).aspx
'''
DevIoCtl = ctypes.windll.kernel32.DeviceIoControl
DevIoCtl.argtypes = [
wintypes.HANDLE, #HANDLE hDevice
wintypes.DWORD, #DWORD dwIoControlCode
wintypes.LPVOID, #LPVOID lpInBuffer
wintypes.DWORD, #DWORD nInBufferSize
wintypes.LPVOID, #LPVOID lpOutBuffer
wintypes.DWORD, #DWORD nOutBufferSize
ctypes.POINTER(wintypes.DWORD), #LPDWORD lpBytesReturned
wintypes.LPVOID] #LPOVERLAPPED lpOverlapped
DevIoCtl.restype = wintypes.BOOL
if isinstance(output, int):
output = ctypes.create_string_buffer(output)
input_size = len(input) if input is not None else 0
output_size = len(output)
assert isinstance(output, ctypes.Array)
BytesReturned = wintypes.DWORD()
status = DevIoCtl(devicehandle, IoControlCode, input, input_size, output, output_size, BytesReturned, None)
return output[:BytesReturned.value] if status is not 0 else -1
def GetDriveGeometry(self):
diskhandle = winapi.CreateHandle(
self.path,
winapi.NULL,
winapi.FILE_SHARE_READ|winapi.FILE_SHARE_WRITE,
winapi.LPSECURITY_ATTRIBUTES(),
winapi.OPEN_EXISTING,
winapi.FILE_ATTRIBUTE_NORMAL,
winapi.NULL)
if diskhandle == winapi.INVALID_HANDLE_VALUE:
return -1
temp = ctypes.cast(self.__DeviceIoControl(diskhandle, winioctl.IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, None, 1024), ctypes.POINTER(winioctl.DISK_GEOMETRY_EX)).contents
winapi.CloseHandle(diskhandle)
return temp
メイン:
device = DeviceIoControl(r"\\.\PhysicalDrive0")
devicegeo = device.GetDriveGeometry()
print("Disk Size: " +str(devicegeo.DiskSize))
print("BytesPerSector: "+str(devicegeo.Geometry.BytesPerSector))
print("Cylinders: "+str(devicegeo.Geometry.Cylinders))
print("MediaType: "+str(hex(devicegeo.Geometry.MediaType)))
print("CtypesAddressOf: "+str(ctypes.addressof(devicegeo)))
with open(r"\\.\PhysicalDrive0", 'rb') as f:
f.seek(0)
MBRdata = f.read(512)
print("\nOpened a file\n")
print("Disk Size: "+str(devicegeo.DiskSize))
print("BytesPerSector: "+str(devicegeo.Geometry.BytesPerSector))
print("Cylinders: "+str(devicegeo.Geometry.Cylinders))
print("MediaType: "+str(hex(devicegeo.Geometry.MediaType)))
print("CtypesAddressOf: "+str(ctypes.addressof(devicegeo)))
出力:
Disk Size: 80000000000
BytesPerSector: 512
Cylinders: 9726
MediaType: 0xc
CtypesAddressOf: 12322040
Opened a file
Disk Size: 0
BytesPerSector: 1
Cylinders: 2170477562872987649
MediaType: -0x40
CtypesAddressOf: 12322040
'device'が何であるか、その' GetDriveGeometry'が何をするか(正確には、 'ctypes'がその戻り値を容易にするもの)に依存します。基本的なネイティブ実装が管理するメモリのビューを返すことができ、それらを所有することは意図していない可能性があります。 – Santa
@Santaこれらの機能の背後にあるコードを質問に追加しました。 – Shawn
@Shawn 'winapi'インポートはどこから来ますか?インポートされたパッケージのエイリアスですか? – swdev