Python and C

P Boy prettyboy988-google at yahoo.com
Fri Mar 10 22:49:49 CET 2006


I have written some C extension before but it was pretty tedious. I
have recently found another approach by using ctypes
(http://starship.python.net/crew/theller/ctypes/). Which you develop
your C module in dynamic library (DLL in Windows world), the from
Python, you can call the C functions in the DLL using ctypes.

I have a library from Microsoft, ewfapi.dll, ewfapi.lib (not required),
and ewfapi.h (see download) which I want to program the EWF capability
in Windows XP Embedded. I was thinking about writing a Python C
extension for it, but using ctypes is much easier. I only need to
redefine some data structures from the header file, and not worry about
common C tasks such as memory management, reference counting, etc.

Ewfapi files can be downloaded from
http://www.microsoft.com/downloads/details.aspx?FamilyID=eb3b3d35-ae95-4864-ba3c-d488d3980972&displaylang=en

I have some sample usage in Python shown below, which I can
interactively control the EWF feature using Python shell (in an XP
embedded machine).


# ewf.py

import ctypes
import string

# These are the functions from the EWF API
##EwfMgrGetDriveLetterFromVolumeName(volumeName)
##
##EwfMgrVolumeNameListIsEmpty(volumeEntry)
##
##EwfMgrVolumeNameEntryPop(volumeEntry)
##
##EwfMgrVolumeNameListDelete
##
##EwfMgrOpenProtected
##
##EwfMgrClose = _ewfapiPy.EwfMgrClose
##
##EwfMgrClearCommand = _ewfapiPy.EwfMgrClearCommand
##
##EwfMgrSetPersistentData = _ewfapiPy.EwfMgrSetPersistentData
##
##EwfMgrGetPersistentData = _ewfapiPy.EwfMgrGetPersistentData
##
##EwfMgrCheckpoint = _ewfapiPy.EwfMgrCheckpoint
##
##EwfMgrRestore = _ewfapiPy.EwfMgrRestore
##
##EwfMgrDisable = _ewfapiPy.EwfMgrDisable
##
##EwfMgrEnable = _ewfapiPy.EwfMgrEnable
##
##EwfMgrCommit = _ewfapiPy.EwfMgrCommit
##
##EwfMgrCommitAndDisableLive = _ewfapiPy.EwfMgrCommitAndDisableLive
##
##EwfMgrCommitFile = _ewfapiPy.EwfMgrCommitFile
##
##EwfMgrSetLevel = _ewfapiPy.EwfMgrSetLevel
##
##EwfMgrGetProtectedVolumeConfig =
_ewfapiPy.EwfMgrGetProtectedVolumeConfig
##
##EwfMgrGetProtectedVolumeList = _ewfapiPy.EwfMgrGetProtectedVolumeList
##
##EwfMgrOpenOverlayStore = _ewfapiPy.EwfMgrOpenOverlayStore
##
##EwfMgrGetOverlayStoreConfig = _ewfapiPy.EwfMgrGetOverlayStoreConfig
##
##EwfMgrRegisterLowSpaceNotification =
_ewfapiPy.EwfMgrRegisterLowSpaceNotification

# Short handle to the API
ewfapi = ctypes.windll.ewfapi

# Data structure from EWFAPI.h translated into Python

# Map these enumerations to string
EWF_CMD = { 0 : 'NO Command',
            1 : 'Enable',
            2 : 'Disable',
            3 : 'Set Level',
            4 : 'Commit',
            }

EWF_STATE = { 0 : 'Enabled',
              1 : 'Disabled',
              }

EWF_TYPE = { 0 : 'Disk',
             1 : 'RAM',
             2 : 'RAM Reg',
             }

# Forward Declaration
pVolumeNameEntry = ctypes.POINTER('VolumeNameEntry')

# Structure of a linked-list
class VolumeNameEntry(ctypes.Structure):
    _fields_ = [('Next', ctypes.POINTER(pVolumeNameEntry)),
                ('Name', ctypes.c_wchar * 256),
                ]

# Set the pointer to the structure
ctypes.SetPointerType(pVolumeNameEntry, VolumeNameEntry)


# Volume descriptor
class VolumeDesc(ctypes.Structure):
    _fields_ = [('DeviceName',  ctypes.c_wchar * 256),
                ('VolumeID',    ctypes.c_ubyte * 16),
                ]

pVolumeDesc = ctypes.POINTER(VolumeDesc)


# Overlay configuration
class OverlayStoreConfig(ctypes.Structure):
    _fields_ = [('FormatVersion',   ctypes.c_ulong),
                ('VolumeSize',      ctypes.c_longlong),
                ('NumSegments',     ctypes.c_ulong),
                ('FreeSegments',    ctypes.c_ulong),
                ('SegmentSize',     ctypes.c_ulong),
                ('MaxVolumes',      ctypes.c_ulong),
                ('NumVolumes',      ctypes.c_ulong),
                ('MaxLevels',       ctypes.c_ushort),
                ('VolumeDescArray', pVolumeDesc),
                ]

pOverlayStoreConfig = ctypes.POINTER(OverlayStoreConfig)

class Command(ctypes.Structure):
    _fields_ = [('Command', ctypes.c_int),
                ('Param1',  ctypes.c_ulong),
                ('Param2',  ctypes.c_ulong),
                ]

pCommand = ctypes.POINTER(Command)

class FileTime(ctypes.Structure):
    _fields_ = [('LowDateTime', ctypes.c_ulong),
                ('HighDateTime', ctypes.c_ulong),
                ]

pFileTime = ctypes.POINTER(FileTime)

class LevelDesc(ctypes.Structure):
    _fields_ = [('LevelName', ctypes.c_wchar * 64),
                ('LevelEndTime', FileTime),
                ('LevelDataSize', ctypes.c_longlong),
                ]

pLevelDesc = ctypes.POINTER(LevelDesc)


class VolumeConfig(ctypes.Structure):
    _fields_ = [('Type',                ctypes.c_int),
                ('State',               ctypes.c_int),
                ('BootCommand',         Command),
                ('PersistentData',      ctypes.c_ubyte * 32),
                ('MaxLevels',           ctypes.c_ushort),
                ('ClumpSize',           ctypes.c_ulong),
                ('CurrentLevel',        ctypes.c_ushort),
                ('DiskMap_RamDataSize', ctypes.c_longlong),
                ('DiskDataSize',        ctypes.c_longlong),
                ('MemMapSize',          ctypes.c_ulong),
                ('VolumeDesc',          VolumeDesc),
                ('LevelDescArray',      pLevelDesc),
                ]

def formatUnsigned(u):
    return '%02X' % u

def unsignedArrayToHex(array):
    return string.join(map(formatUnsigned, array)).replace(' ','')

def displayVolumeConfiguration(config, drive):
    config_type = EWF_TYPE[config.Type]
    print 'Type     : %s' % config_type
    print 'State    : %s' % EWF_STATE[config.State]
    print 'Boot Cmd : %s' % EWF_CMD[config.BootCommand.Command]
    print 'Param 1  : %u' % config.BootCommand.Param1
    print 'Param 2  : %u' % config.BootCommand.Param2
    print 'Persistent Data: %s' %
unsignedArrayToHex(config.PersistentData)
    print
    print 'Maximum Levels   : %u' % config.MaxLevels
    print 'Clump Size       : %u Bytes' % config.ClumpSize
    print 'Current Level    : %u' % config.CurrentLevel
    if config_type == 'Disk':
        print 'Disk Map Size    : %u Bytes' %
config.DiskMap_RamDataSize
        print 'Disk Data Size   : %u Bytes' % config.DiskDataSize
    else:
        print 'RAM Data Size    : %u Bytes' %
config.DiskMap_RamDataSize

    print 'Memory Map Size  : %u Bytes' % config.MemMapSize
    print 'Device Name      : %s' % config.VolumeDesc.DeviceName
    print 'Volume ID        : %s' %
unsignedArrayToHex(config.VolumeDesc.VolumeID)
    print 'Drive            : %s' % drive

def information():
    # Get the pointer and convert to linked-list node
    volume_list =
VolumeNameEntry.from_address(ewfapi.EwfMgrGetProtectedVolumeList())
    while 1:
        drive =
chr(ewfapi.EwfMgrGetDriveLetterFromVolumeName(volume_list.Name))
        print '%s: = %s' % (drive, volume_list.Name)
        handle = ewfapi.EwfMgrOpenProtected(volume_list.Name)
        config =
VolumeConfig.from_address(ewfapi.EwfMgrGetProtectedVolumeConfig(handle))
        displayVolumeConfiguration(config, drive)
        if
ewfapi.EwfMgrVolumeNameListIsEmpty(ctypes.c_void_p.from_address(ctypes.addressof(volume_list))):
            break


if __name__ == "__main__ ":
    print 'Running'
    information()




More information about the Python-list mailing list