1

I am trying to call the following function in a DLL, which (to my limited understanding), takes a callback as a parameter.

C# definitions:

//Error handler
public delegate int FPtrErrorHandler(int ErrorType, int MessageType, int WhomToInform, String ErrorMessage);

//Desired function to call
[ DllImport ( Globals.LibDLLPath, CallingConvention = CallingConvention.Cdecl ) ]
public static extern int OpenLib(String TempDirectory, Bool IfCleanTempDir, FPtrErrorHandler ErrorHandler);

Per this SO entry, I created the Python code below:

import ctypes as c
from ctypes import *

@c.WINFUNCTYPE(c.c_int, c.c_int, c.c_int, c.c_int, c.c_char_p)
def FPtrErrorHandler(ErrorIdentifier, ErrorMessageType, WhomToInform, ErrorMessage):
    print(f'Error ID={ErrorIdentifier}, Type={ErrorMessageType}, WhomToInform={WhomToInform}, msg={ErrorMessage}')
    return 0

lib = windll.LoadLibrary('path_to_dll')

_OpenLib = lib[163]
_OpenLib.restype = c_int
_OpenLib.argtypes = [c_char_p, c_bool, c_void_p]
def OpenLib(TempDirectory,IfCleanTempDir):
    cb1 = FPtrErrorHandler
    return _OpenLib(TempDirectory, IfCleanTempDir, cb1)

n = OpenLib(r:'c:\temp',c_bool(True))

Unfortunately, I get the dreaded message

ArgumentError: argument 1: <class 'TypeError'>: wrong type

Thanks in advance for helping me with this. I'm really happy to learn ctypes and how to use Python to interact with the amazing DLLs that are out there.

Danny Varod
  • 17,324
  • 5
  • 69
  • 111
mherzog
  • 1,085
  • 1
  • 12
  • 24
  • I'm not sure how python interacts with foreign code, but the c# `FPtrErrorHandler` has defined 4 parameters. But your python `FPtrErrorHandler` has only 3 parameter. Isn't that wrong? – Ackdari Jul 28 '20 at 13:49
  • Also it seems like the first argument `c.c_char_p` of `c.WINFUNCTYPE` needs to be the return type. But the c# method return `int` and therfore should be `c.c_int`, right? – Ackdari Jul 28 '20 at 13:53
  • Good questions -- I must say I'm not clear on this myself. I'm assuming that the ErrorMessage in ```FPtrErrorHandler``` is an output parameter, hence the ```c.c_char_p``` as the first argument to ```c.WINFUNCTYPE```. However, I'm open to suggestions regarding what to change. – mherzog Jul 28 '20 at 14:25
  • 1
    `ErrorMessage` is defintly not an outpur parameter, if it would be it would be annoted with the `out` keyword. The sigature shows that the return type is an `int`. – Ackdari Jul 28 '20 at 14:59
  • @Ackdari, Based on your feedback, I changed the code as currently shown. However, I'm still getting the same error. – mherzog Jul 28 '20 at 16:21
  • Maybe the problem comes from `c_void_p` of the `argstypes` – Ackdari Jul 28 '20 at 17:05
  • Yes, very well could be. However, I don't know what to put there. For example, I tried ```POINTER(c_void_p)``` and ```_NOpenNestLib(TempDirectory,IfCleanTempDir,pointer(cb1))``` but the error remains. I wish I knew how to properly handle the delegate. – mherzog Jul 28 '20 at 20:17

1 Answers1

0

OMG, I think this might be an easy one.

If I change the call to the function from

n = OpenLib(r:'c:\temp',c_bool(True))

to

n = OpenLib(rb:'c:\temp',c_bool(True))

it seems to be working. I just added the b modifier in the string prefix.

mherzog
  • 1,085
  • 1
  • 12
  • 24