pythonctypes

File Handler created using ctypes is invalid


I was trying to create a new file using ctypes in python. The file gets created and I am able to write in to it. The problem starts when I try to read from this file. It gives me an invalid file handle error. Anyone might know why this is the case.

The following is the code I used:

from ctypes import *

def CreateFile(file_name='',data=''):

    file_handler=windll.Kernel32.CreateFileA(file_name,0x10000000,0,None,4,0x80,None)

    pointer_to_written_data=c_int(0)
    windll.Kernel32.WriteFile(file_handler,data,len(data),byref(pointer_to_written_data),None)
    windll.Kernel32.CloseHandle(file_handler)
    return

def ReadAFile(file_name=''):

    file_handler=windll.Kernel32.CreateFileA(file_name,0x10000000,0,None,4,0x80,None)
    data=create_string_buffer(4096)
    pointer_to_read_data=c_int(0)
    if(windll.Kernel32.ReadFile(file_handler,byref(data),1024,byref(pointer_to_read_data),None)==0):
            print "Failed"
    print windll.Kernel32.GetLastError()
    windll.Kernel32.CloseHandle(file_handler)
    print data.value
    return

CreateFile("sample.txt","This is a test file!!")
ReadAFile("sample.txt")

Solution

  • Your code works as is after the CloseHandle edit.

    When you weren't closing the file handle in CreateFile(), the file open in ReadAFile failed because the file was already open. You didn't check the error so your call to ReadFile failed. Now that the code is edited to have the CloseHandle in CreateFile, it works. Note you may need to close and re-open your IDE as it may keep a handle open to the file until you kill the process since it was a handle leak (I had that issue).

    I also find in ctypes that being explicit and defining argtypes, restype, and errcheck is useful. errcheck especially, since code will throw an error and you don't have to check return values for failure.

    Note: Original Python 2 code edited for Python 3 and updated to use Unicode Win32 APIs. See edit history for original.

    import ctypes as ct
    import ctypes.wintypes as w
    
    INVALID_HANDLE_VALUE = w.HANDLE(-1).value
    GENERIC_ALL = 0x10000000
    OPEN_ALWAYS = 4
    FILE_ATTRIBUTE_NORMAL = 0x80
    
    kernel32 = ct.WinDLL('kernel32', use_last_error=True)
    CreateFileW = kernel32.CreateFileW
    WriteFile = kernel32.WriteFile
    ReadFile = kernel32.ReadFile
    CloseHandle = kernel32.CloseHandle
    
    def validate_handle(result, func, args):
        if result == INVALID_HANDLE_VALUE:
            raise ct.WinError(get_last_error())
        return result
    
    def validate_bool(result, func, args):
        if not result:
            raise ct.WinError(get_last_error())
    
    CreateFileW.argtypes = w.LPCWSTR, w.DWORD, w.DWORD, ct.c_void_p, w.DWORD, w.DWORD, w.HANDLE
    CreateFileW.restype = w.HANDLE
    CreateFileW.errcheck = validate_handle
    WriteFile.argtypes = w.HANDLE, ct.c_void_p, w.DWORD, w.LPDWORD, ct.c_void_p
    WriteFile.restype = w.BOOL
    WriteFile.errcheck = validate_bool
    ReadFile.argtypes = w.HANDLE, w.LPVOID, w.DWORD, w.LPDWORD, ct.c_void_p
    ReadFile.restype = w.BOOL
    ReadFile.errcheck = validate_bool
    CloseHandle.argtypes = w.HANDLE,
    CloseHandle.restype = w.BOOL
    CloseHandle.errcheck = validate_bool
    
    def CreateFile(file_name='', data=''):
        file_handler = CreateFileW(file_name, GENERIC_ALL, 0, None, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, None)
        written = w.DWORD()
        try:
            WriteFile(file_handler, data, len(data) * ct.sizeof(w.WCHAR), ct.byref(written), None)
        finally:
            CloseHandle(file_handler)
    
    def ReadAFile(file_name=''):
        file_handler = CreateFileW(file_name, GENERIC_ALL, 0, None, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, None)
        data = ct.create_unicode_buffer(4096)
        read = w.DWORD()
        try:
            ReadFile(file_handler, ct.byref(data), 1024, ct.byref(read), None)
        finally:
            CloseHandle(file_handler)
        print(data.value)
    
    CreateFile('sample.txt', 'This is a test file!!')
    ReadAFile('sample.txt')