-1

I can call functions in my dll from python. When I call a dll function that does a callback to my python code it fails. It there some sort of mutex blocking my callback?

from ctypes import *
import _ctypes

@CFUNCTYPE(None)
def Test():
    print ("Test here")
    return

def SetUpDll():
    print ("Setting read / write callback functions...")
    windll.ClaRUN.AttachThreadToClarion(1)
    MyDll = CDLL('IC2_CommsServer.dll')

    SetTestFunc = getattr(MyDll, "SETTESTFUNC@Fl")
    SetTestFunc (Test)

    CallTestFunc = getattr(MyDll, "CALLTESTFUNC@F")
    CallTestFunc()

    _ctypes.FreeLibrary(MyDll._handle)
    _ctypes.FreeLibrary(windll.ClaRUN._handle)

    print ("Done.")


SetUpDll()

C:\Users\Derek\anaconda3_32\python.exe Z:/ps_IC2_dll/ps_IC2_dll.py
Setting read / write callback functions...
Traceback (most recent call last):
  File "Z:/ps_IC2_dll/ps_IC2_dll.py", line 48, in <module>
    SetUpDll()
  File "Z:/ps_IC2_dll/ps_IC2_dll.py", line 40, in SetUpDll
    CallTestFunc()
OSError: exception: access violation writing 0x009EF77C

Process finished with exit code 1
Derek
  • 23
  • 6
  • I think I have located the problem. SetTestFunc (Test) <<< this does not pass the callback address. This passes a handle to the Test object. How do I get the actual funtion address? – Derek May 07 '20 at 09:11
  • It's *Undefined Behavior*. Most likely, it's a dupe of [\[SO\]: C function called from Python via ctypes returns incorrect value (@CristiFati's answer)](https://stackoverflow.com/questions/58610333/c-function-called-from-python-via-ctypes-returns-incorrect-value/58611011#58611011), but there might be other issues as well. – CristiFati May 07 '20 at 11:11
  • Yes! :-) added from your other answer: SetTestFunc.restype = None SetTestFunc.argtypes = [CFUNCTYPE(None)] Now it works – Derek May 07 '20 at 13:23
  • Then please mark the question as a duplicate of the other one (by pressing the *close* button, and pasting the other question *URL*). – CristiFati May 07 '20 at 13:26
  • There is another issue. :-( Native clarion functions use a C calling convention but... parameters are not compatible. I have changed all my DLL functions to be C functions and now the code works correctly. – Derek May 07 '20 at 13:57
  • What do you mean by "*C calling convention*". If it's *cdecl*, then all you have to change is `cdll.ClaRUN.AttachThreadToClarion(1)`. – CristiFati May 07 '20 at 15:01
  • Clarion uses its own proprietary Topspeed C register passing format. So it is C but 100% NOT cdecl compatible. – Derek May 08 '20 at 14:31

2 Answers2

0

First, on Windows, the ctypes uses win32 structured exception handling to prevent crashes from general protection faults when functions are called with invalid argument values.

You have a bad call for this line of code:

CallTestFunc = getattr(MyDll, "CALLTESTFUNC@F")

Try to review your code, then see if the problem is from ps_IC2_dll.py build area.

  • Thanks Catalin, The failure is actually after the next line. CallTestFunc(). It calls a simple test function in my dll which outputs a debug message and then executes the callback to python. I see the debug message so the CallTestFunc() works. It is the callback to the python Test() that fails. – Derek May 07 '20 at 06:56
0

Thanks to CristiFati who provided half of the answer.

This code now works, note that the clarion dll functions are now prototyped as ,C A nice side effect is that the function names loose the "@F" suffix and so the code is simpler.

from ctypes import *
import _ctypes

@CFUNCTYPE(None)
def Test():
    print ("Test here")
    return

def SetUpDll():
    print ("Setting read / write callback functions...  Ptr=", sizeof(c_void_p), "bytes")
    assert sizeof(c_void_p) == 4

    ClaRTL = CDLL('./ClaRUN.dll')
    MyDll = CDLL('./IC2_CommsServer.dll')

    ClaRTL.AttachThreadToClarion.restype = None
    ClaRTL.AttachThreadToClarion.argtypes = [c_int32]
    ClaRTL.AttachThreadToClarion(1)

    MyDll.SETTESTFUNC.restype = None
    MyDll.SETTESTFUNC.argtypes = [CFUNCTYPE(None)]
    MyDll.SETTESTFUNC (Test)

    MyDll.CALLTESTFUNC.restype = None
    MyDll.CALLTESTFUNC ()

    _ctypes.FreeLibrary(MyDll._handle)
    _ctypes.FreeLibrary(ClaRTL._handle)

    print ("Done.")


SetUpDll()

Output is now:

C:\Users\Derek\AppData\Local\Programs\Python\Python38-32\python.exe Z:/ps_IC2_dll/ps_IC2_dll.py
Setting read / write callback functions...  Ptr= 4 bytes
Test here
Done.

Process finished with exit code 0
Derek
  • 23
  • 6