I am running Python 3.9, 64bit, and have compiled libharu and some extensions into a DLL, including libpng, with VS 2022. The DLL can load into Python after adding minimal code tweaking to find the VS runtime DLL, which libhpdf.dll depends on, and seems to work (there are only 5 .py files in the bindings) I´ve built the DLL enabling the PTRACE, to follow progress. Have also built the C demos dynamically with that DLL and they all work, generating the PDFs.
I´m trying to run a python demo sample contained in the bindings, arc_demo.py hoping to generate and identical PDF file
I can tell everything works fine till the line adding a document:
pdf = HPDF_New (error_handler, NULL)
Similar output to the trace obtained with the compiled C version of the sample.
But... the var "pdf" is not what HP_AddPage() expects because when issuing the next call, to add a page
page = HPDF_AddPage (pdf)
I run into this:
**ctypes.ArgumentError: argument 1: <class 'OverflowError'>: int too long to convert**
I think it might have to do with the fact that the original bindings were built and tested with 32bit only. The other suspect is the ctypes of the porting.
So now I am modifying the bindings, mainly hpdf.py.
Currently, fighting with the Python to DLL intercommunication, checking if ctypes is handling things as expected. Using byref
, casting *pdf *to a c_void_p
,... no luck. I get rid of the error if the call is done byref(c_void_p(pdf)), but can not access the contents of the HPDF_Doc structure correctly
Any suggestions? Help you might give? A contrasted method for debugging Python with a C-based DLL?
Thanks, Ignacio
PS: Eventually will write classes for the Haru PDF internal structures. But that will come later, after I am able to run a python sample without errors.
The ctypes
interface in if/python/hpdf.py
has no .argtypes
defined for all the functions. It is particularly important for 64-bit handles and pointers to have proper argument types defined for each function. The original developer probably didn't understand that as indicated by converting from WinDLL
to CDLL
interfaces. WinDLL
uses __stdcall
calling convention and needs to know the argument sizes.
For example, HPDF_Doc
is defined as HPDF_HANDLE
which is defined as a ctypes.c_void_p
. That's a 64-bit pointer on a 64-bit OS. HPDF_New
and HPDF_AddPage
are defined as:
#HPDF_Doc HPDF_New (HPDF_Error_Handler user_error_fn, void *user_data)
HPDF_New=haru.HPDF_New
HPDF_New.restype=HPDF_Doc
#HPDF_Page HPDF_AddPage (HPDF_Doc pdf)
HPDF_AddPage=haru.HPDF_AddPage
HPDF_AddPage.restype=HPDF_Page
ctypes
assumes the parameter passed to HPDF_AddPage
is a c_int
since to has no argtypes. The handle value is >32-bit hence the error seen. Ideally, all functions should explicitly declare their argument types so ctypes
can do type checking and properly marshal (convert) parameters from Python objects to C types, e.g.:
HPDF_AddPage.argtypes = HPDF_Doc, # must be a list or tuple...comma makes this a 1-tuple.
HPDF_New.argtypes = HPDF_Error_Handler, c_void_p
Note that argument types must be based on ctypes
types. You'll have to carefully trace the arguments and declare the .argtypes
for each function.