On Sun, Mar 5, 2017 at 12:16 AM, Kurt Eilander <web...@totalrewind.com> wrote:
>
> I'm having another problem.  I'm wanting to get the size of a dll resource,
> but...
>
> When I do:
>     try:
>         hLib=win32api.GetModuleHandle(fileName)
>     except:
>         hLib=win32api.LoadLibrary(fileName)
>     if hLib==None:
>         raise WindowsError('File not found, '+fileName)
>     hResInfo=ctypes.windll.kernel32.FindResourceW(hLib,index,type)
>     size=ctypes.windll.kernel32.SizeofResource(hLib,hResInfo)
>
> It throws:
>     hResInfo=ctypes.windll.kernel32.FindResourceW(hLib,index,type)
>     ctypes.ArgumentError: argument 1: <type 'exceptions.OverflowError'>:
> long int too long to convert
>
> Almost like ctypes doesn't like the win32api handle.
>
> My machine is 64 bit.  Is that what ctypes is not liking?  Is there a way
> around it?

The default conversion for integer arguments is to a 32-bit C int. The
implementation calls PyLong_AsLong, for which a 64-bit address can
raise an overflow exception on Windows since a C long is always 32-bit
on this platform. You're lucky to get an exception. The problem is
worse on Unix systems that have a 64-bit C long. The conversion
doesn't overflow, but ctypes itself silently casts the address to a
32-bit int. Invariably this causes a segfault, either directly or
indirectly due to stack or heap corruption.

It looks like you're also not setting restype to a pointer type for
FindResourceW. Like with parameters, the default integer conversion
type for a function result is a 32-bit C int. A 64-bit result will be
silently truncated on Windows as well. Kernel and User handles never
exceed 32-bit values, but don't assume that's true of all handles.
HMODULE handles break this rule, as do others. Always assume a handle
type requires the full range of a pointer.

Here are some general suggestions. Use ctypes.WinDLL instead of
ctypes.windll (the latter was a bad design for multiple reasons). Load
the library with the option use_last_error=True, unless you're working
with NT or COM libraries that return NTSTATUS or HRESULT values.
Always set the function prototype -- at least argtypes; restype if the
function returns a pointer type; and preferably an errcheck function
that raises idiomatic exceptions.

For example:

    import winerror
    import win32api
    import ctypes
    from ctypes import wintypes

    kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

    def _check_zero(result, func, args):
        if not result:
            raise ctypes.WinError(ctypes.get_last_error())
        return args

    kernel32.FindResourceW.errcheck = _check_zero
    kernel32.FindResourceW.restype = wintypes.HRSRC
    kernel32.FindResourceW.argtypes = (
        wintypes.HMODULE, # _In_opt_ hModule
        wintypes.LPCWSTR, # _In_     lpName
        wintypes.LPCWSTR) # _In_     lpType

    kernel32.LoadResource.errcheck = _check_zero
    kernel32.LoadResource.restype = wintypes.HGLOBAL
    kernel32.LoadResource.argtypes = (
        wintypes.HMODULE, # _In_opt_ hModule
        wintypes.HRSRC)   # _In_     hResInfo

    kernel32.SizeofResource.errcheck = _check_zero
    kernel32.SizeofResource.restype = wintypes.DWORD
    kernel32.SizeofResource.argtypes = (
        wintypes.HMODULE, # _In_opt_ hModule
        wintypes.HRSRC)   # _In_     hResInfo

    kernel32.LockResource.restype = wintypes.LPVOID
    kernel32.LockResource.argtypes = (
        wintypes.HGLOBAL,) # _In_ hResData

    def get_resource(filename, index, rtype):
        try:
            hLib = win32api.GetModuleHandle(filename)
        except win32api.error as e:
            if e.winerror != winerror.ERROR_MOD_NOT_FOUND:
                raise
            hLib = win32api.LoadLibrary(filename)
        index = wintypes.LPCWSTR(index) # MAKEINTRESOURCE
        rtype = wintypes.LPCWSTR(rtype)
        hResInfo = kernel32.FindResourceW(hLib, index, rtype)
        hRes = kernel32.LoadResource(hLib, hResInfo)
        size = kernel32.SizeofResource(hLib, hResInfo)
        addr = kernel32.LockResource(hRes)
        return ctypes.string_at(addr, size)

    if __name__ == '__main__':
        RT_MANIFEST = 24
        manifest = get_resource(None, 1, RT_MANIFEST).decode('utf-8')
        print(manifest)

The above demo prints the embedded manifest from python.exe. Of
course, it would be a lot simpler to use win32api.LoadResource [1]:

    manifest = win32api.LoadResource(None, RT_MANIFEST, 1).decode('utf-8')

[1]: 
http://docs.activestate.com/activepython/3.4/pywin32/win32api__LoadResource_meth.html
_______________________________________________
python-win32 mailing list
python-win32@python.org
https://mail.python.org/mailman/listinfo/python-win32

Reply via email to