分配更多内存时,Python ctypes结构将被覆盖 [英] Python ctypes structure being overwritten when allocating more memory

查看:136
本文介绍了分配更多内存时,Python ctypes结构将被覆盖的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Python 3.2中,我根据ctypes.windll.kernel32.DeviceIoControl函数返回的数据创建了一个Structure对象。完成此操作后,我可以访问结构字段并返回数据。但是,如果我做某事会使用内存,例如打开文件,则会修改结构内部的数据。在输出的第一部分中,我粘贴的是预期的结果。但是,在打开文件并再次打印结构字段后,值已更改。我不确定为什么要修改数据或如何阻止数据发生。

In Python 3.2 I am creating a Structure object from the data returned by the ctypes.windll.kernel32.DeviceIoControl function. After this is done I can access the Structure fields and return the data. However, if i do something the uses a memory, such as opening a file the data inside the structure is modified. In the first part of the output that I have pasted in the results are what is to be expected. However, after a file is opened and the structures fields printed again values have been changed. I am not sure why the data is being modified or how to stop it from happening.

结构:

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)]

D eviceIoControl:

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


推荐答案

一些观察结果:


  1. DevIoCtl 应该用 byref(BytesReturned)调用。

  2. ctypes.cast 的第一个参数必须是可以解释为指针的对象。
    但是,您要投射的是原始的 bytes 对象(来自 output [:BytesReturned.value] )。

  3. 此时,您从 __ DeviceIoControl 返回的是一个新的Python bytes 对象。对ctypes数组对象的原始引用已超出范围。因此,很有可能已经对其进行了垃圾回收和/或重用。

  1. DevIoCtl should be called with byref(BytesReturned).
  2. ctypes.cast's first argument must be an "object that can be interpreted as a pointer". What you are casting, however, is a raw bytes object (from output[:BytesReturned.value]).
  3. At this point, what you returned from __DeviceIoControl is a new Python bytes object. The original reference to ctypes array object has gone out of scope. So, it's entirely possible that it has been garbage collected and/or reused.

FWIW,我使用ctypes处理Windows IOCTL分派只是为了它。还使用 \\.\PysicalDrive0 IOCTL_DISK_GET_DRIVE_GEOMETRY

FWIW, I played around with Windows IOCTL dispatch using ctypes just for the heck of it. Also using \\.\PysicalDrive0 and IOCTL_DISK_GET_DRIVE_GEOMETRY.

我制作了这个要点

这篇关于分配更多内存时,Python ctypes结构将被覆盖的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆