Jump to content

Autoit DllCallbackRegister have a bug?


Recommended Posts

I'm sorry my english...

i try DllCallbackRegister($func, "ptr:cdecl", "ptr; ptr") but it's raise error when callback called.

only use can DllCallbackRegister($func, "ptr:cdecl", "ptr") but no idea how get param from python...

help please.

output:

E:\Users\EcmaXp\Desktop>python32 ./module1.py
<module 'spam' (built-in)>
['__doc__', '__name__', '__package__', 'hello'
<built-in function hello>
hello
3 <module 'spam' (built-in)>
E:\Users\EcmaXp\Desktop>rem after compile change to DllCallbackRegister($func, "ptr:cdecl", "ptr; ptr")

E:\Users\EcmaXp\Desktop>python32 ./module1.py
<module 'spam' (built-in)>
['__doc__', '__name__', '__package__', 'hello'
<built-in function hello>
E:\Users\EcmaXp\Desktop>rem error!

E:\Users\EcmaXp\Desktop>

code:

; Python 3.1 <=> Autoit 3

#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Change2CUI=y
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
#NoTrayIcon
#include <misc.au3>
#include <string.au3>

Global $_NON_FREE_STRUCT[1]
Global $_current_line = -1
Global $_Py_AutoitDebug = False
Global $_Py_AutoitMaxiumArgmentCount = 4

Global Const $PYTHON_API_VERSION = 1013

Global Const $tagPyObject = _
    "long_ptr ob_refcnt;" & _ ; long_ptr is a ssize_t is a Py_ssize_t
    "ptr ob_type;"

Global Const $tagPyCFunctionObject = _
    $tagPyObject & _ ; PyObject_HEAD
    "ptr m_ml;" & _ ; PyObject /* Description of the C function to call */
    "ptr m_self;" & _ ; PyObject /* Passed as 'self' arg to the C func, can be NULL */
    "ptr m_module;" ; PyObject /* The __module__ attribute, can be anything */

Global Const $tagPyModuleDef_Base = _
    $tagPyObject & _ ; PyObject_HEAD
    "ptr m_init;" & _ ; PyObject* (*m_init)(void)
    "long_ptr m_index;" & _ ; PyObject
    "ptr m_copy;" ; PyObject

Global Const $tagPyModuleDef = _
    $tagPyModuleDef_Base & _ ; PyObject_HEAD
    "ptr m_name;" & _ ; const char*
    "ptr m_doc;" & _ ; const char*
    "long_ptr m_size;" & _ ; Py_ssize_t
    "ptr m_methods;" & _ ; PyMethodDef
    "ptr m_reload;" & _ ; inquiry
    "ptr m_traverse;" & _ ; traverseproc
    "ptr m_clear;" & _ ; inquiry
    "ptr m_free;" ; freefunc

Global Const $tagPyMethodDef = _
    "ptr ml_name;" & _ ; char[] /* The name of the built-in function/method */
    "ptr ml_meth;" & _ ; PyCFunction /* The C function that implements it */
    "int ml_flags;" & _ ; /* Combination of METH_xxx flags, which mostly describe the args expected by the C func */
    "ptr ml_doc;" ; /* The __doc__ attribute, or NULL */

Global Const $Py_NULL = Ptr(0)
Global Const $METH_VARARGS  = 0x0001
Global Const $METH_KEYWORDS = 0x0002
Global Const $METH_NOARGS   = 0x0004
Global Const $METH_O        = 0x0008
Global Const $METH_CLASS    = 0x0010
Global Const $METH_STATIC   = 0x0020
Global Const $METH_COEXIST  = 0x0040

Func PyAu_MakePyMethodDef($funcname, $pycfunction, $doc="");, $flag=$METH_VARARGS, $doc="")
    $assign_data = True

    If Not StringLen($funcname) And Not StringLen($pycfunction) Then
        $assign_data = False
    EndIf

    If $assign_data Then
        #cs
        $callbackarg = ""

        If BitAnd($flag, $METH_VARARGS) Then
            $callbackarg = "ptr; ptr"
        EndIf

        If BitAnd($flag, $METH_KEYWORDS) Then
            $callbackarg = "ptr; ptr; ptr;"
        EndIf

        If BitAnd($flag, $METH_NOARGS) Then
            $callbackarg = "ptr; ptr; ptr;"
        EndIf
        #ce

        $flag = $METH_VARARGS
        $callbackfunc = DllCallbackRegister($pycfunction, "ptr:cdecl", "ptr") ; THIS LINE
        ; I went get two param but Autoit raise error!
        ; how can i work?
    EndIf

    $pymethod = DllStructCreate($tagPyMethodDef)

    If $assign_data Then
        DllStructSetData($pymethod, "ml_name", MakeStringBuffer($funcname))
        DllStructSetData($pymethod, "ml_meth", DllCallbackGetPtr($callbackfunc))
        DllStructSetData($pymethod, "ml_flags", $flag)
        DllStructSetData($pymethod, "ml_doc", _Iif(StringLen($doc), MakeUnicodeBuffer($doc), $Py_NULL))
    EndIf

    NonFreeStruct($pymethod)

    Return $pymethod
EndFunc

#cs
Func PyAu_MakeCFunctionObject($func, $self=$Py_NULL, $module=$Py_NULL)
    $pycfunctionobj = DllStructCreate($tagPyCFunctionObject)
    DllStructSetData($pycfunctionobj, "m_ml", DllCallbackGetPtr($callbackfunc))
    DllStructSetData($pycfunctionobj, "m_self", $self)
    DllStructSetData($pycfunctionobj, "m_module", $module)
    NonFreeStruct($pycfunctionobj)

    Return DllStructGetPtr($pycfunctionobj)
EndFunc
#ce

#Region user code
$PyDLL = DllOpen("python31")

Func TestFunction($mod, $args)
    print("hello")
    Return $mod

    #cs
    $result = PyArg_ParseTuple($args, "ii", "int", "int")
    If Not IsArray($result) Then Return

    print("called testfuncion!")
    Return Py_BuildValue("i", "int", $result[1] + $result[2])
    #ce
EndFunc

Func PyInit_spam()
    $a = PyAu_MakePyMethodDef("hello", "TestFunction")
    $b = PyAu_MakePyMethodDef("", "")
    $pymethods = ConcatStruct($a, $b)

    $pymodule = DllStructCreate($tagPyModuleDef)
    DllStructSetData($pymodule, "m_name", MakeStringBuffer("spam"))
    DllStructSetData($pymodule, "m_size", -1)
    DllStructSetData($pymodule, "m_methods", GetFreezeStructPtr($pymethods))

    Return PyModule_Create(GetFreezeStructPtr($pymodule))
EndFunc

$initfunc = DllCallbackRegister("PyInit_spam", "ptr", "")

Py("Import_AppendInittab", "none", "ptr", MakeStringBuffer("spam"), "ptr", DllCallbackGetPtr($initfunc))

Py_Initialize()
Global Const $Py_None = Py_GetNone()
Py_Main()
Py_Finalize()
#EndRegion user code

#Region python functions
Func Py_Initialize()
    Py("_Initialize", "none")
EndFunc   ;==>Py_Initialize

Func Py_GetNone()
    Local Static $Py_None = -1
    If $Py_None == -1 Then
        $module = PyImport_ImportModule("builtins")
        $moduledict = PyModule_GetDict($module)
        $Py_None = PyDict_GetItem($moduledict, Py_BuildString("None"))
    EndIf

    Py_INCREF($Py_None)
    Return $Py_None
EndFunc

Func PyImport_ImportModule($name)
    Return Py("Import_ImportModule", "ptr", "ptr", MakeStringBuffer(String($name)))
EndFunc

Func Py_IsInitialized()
    Return Py("_IsInitialized", "int")
EndFunc   ;==>Py_IsInitialized

Func Py_Finalize()
    Return Py("_Finalize", "none")
EndFunc   ;==>Py_Finalize

Func Py_Module_New($name)
    Return Py("Module_New", "ptr", "ptr", MakeStringBuffer(String($name)))
EndFunc   ;==>Py_Module_New

Func PyModule_GetDict($module)
    Return Py("Module_GetDict", "ptr", "ptr", $module)
EndFunc   ;==>PyModule_GetDict

Func Py_BuildString($string)
    Return Py_BuildValue("s", "ptr", MakeStringBuffer($string))
EndFunc   ;==>Py_BuildString

Func PyImport_GetModuleDict()
    Return Py("Import_GetModuleDict", "ptr")
EndFunc   ;==>PyImport_GetModuleDict

Func PyDict_SetItem($dict, $key, $value)
    Return Py("Dict_SetItem", "int", "ptr", $dict, "ptr", $key, "ptr", $value)
EndFunc   ;==>PyDict_SetItem

Func PyDict_GetItem($dict, $key)
    Return Py("Dict_GetItem", "ptr", "ptr", $dict, "ptr", $key)
EndFunc   ;==>PyDict_SetItem

Func PyModule_Create($module)
    Return PyModule_Create2($module, $PYTHON_API_VERSION)
EndFunc

Func PyModule_Create2($moduledef, $apiver)
    Return Py("Module_Create2", "ptr", "ptr", $moduledef, "int", $apiver)
EndFunc

Func Py_INCREF($objptr)
    $obj = DllStructCreate($tagPyObject, $objptr)
    DllStructSetData($obj, "ob_refcnt", DllStructGetData($obj, "ob_refcnt") + 1)

    If $_Py_AutoitDebug Then
        print("current(irc) : " & DllStructGetData($obj, "ob_refcnt"))
    EndIf
EndFunc   ;==>Py_INCREF

Func Py_DECREF($objptr)
    $obj = DllStructCreate($tagPyObject, $objptr)
    DllStructSetData($obj, "ob_refcnt", DllStructGetData($obj, "ob_refcnt") - 1)

    If $_Py_AutoitDebug Then
        print("current(dec) : " & DllStructGetData($obj, "ob_refcnt"))
    EndIf
EndFunc   ;==>Py_DECREF

Func Py_BuildValue($valueformat, _
        $T1 = "", $P1 = "", _
        $T2 = "", $P2 = "", _
        $T3 = "", $P3 = "", _
        $T4 = "", $P4 = "", _
        $line = @ScriptLineNumber)

    If Not Mod(@NumParams, 2) Then
        _Py_AutoitInteralError("Wrong Argment Given")
        Return
    EndIf

    $paramtempformat = ""

    For $i = 1 To Int(@NumParams / 2)
        $paramformat = Eval("T" & $i)
        $param = Eval("P" & $i)

        $paramtempformat &= $paramformat & ";"
    Next

    $va_list = DllStructCreate($paramtempformat)

    For $i = 1 To Int(@NumParams / 2)
        $param = Eval("P" & $i)
        DllStructSetData($va_list, $i, $param)
    Next

    $result = Py("_VaBuildValue", "ptr", "str", $valueformat, "ptr", DllStructGetPtr($va_list))
    $va_list = 0

    Return $result
EndFunc   ;==>Py_BuildValue

Func PyArg_ParseTuple($valueformat, _
        $T1 = "", _
        $T2 = "", _
        $T3 = "", _
        $T4 = "", _
        $line = @ScriptLineNumber)

    For $i = 1 to $_Py_AutoitMaxiumArgmentCount
        If Not IsDeclared("T" & $i) Then
            If @NumParams > ($i + 1)  Then
                _Py_AutoitInteralError("Wrong Argment Given")
                Return
            EndIf
        EndIf
    Next

    Local $resultvalue[@NumParams]
    $resultvalue[0] = @NumParams - 1

    $paramtempformat = ""

    For $i = 1 To $resultvalue[0]
        $paramformat = Eval("T" & $i)
        $paramtempformat &= $paramformat & ";"
    Next

    $va_list = DllStructCreate($paramtempformat)

    $result = Py("Arg_VaParse", "int", "str", $valueformat, "ptr", DllStructGetPtr($va_list))
    If Not $result Then
        Return False
    EndIf

    $va_list = 0

    For $i = 1 To $resultvalue[0]
        $param = Eval("P" & $i)
        $resultvalue[$i] = DllStructGetData($va_list, $i)
    Next

    Return $resultvalue
EndFunc

Func Py_Main()
    $argc = $CmdLine[0] + 1
    $argv = DllStructCreate(StringTrimRight(_StringRepeat("ptr;", $argc), 1))

    DllStructSetData($argv, 1, MakeUnicodeBuffer(@ScriptFullPath))

    For $i = 2 To $argc
        DllStructSetData($argv, $i, MakeUnicodeBuffer($CmdLine[$i - 1]))
    Next

    Py("_Main", "none", "int", $argc, "ptr", DllStructGetPtr($argv))

    $argv = 0
EndFunc   ;==>Py_Main
#EndRegion python functions

#Region help functions
Func print($arg)
    ConsoleWrite($arg & @CRLF)
EndFunc   ;==>print

Func NonFreeStruct(ByRef $x)
    Global $_NON_FREE_STRUCT
    $size = UBound($_NON_FREE_STRUCT)
    ReDim $_NON_FREE_STRUCT[$size + 1]
    $_NON_FREE_STRUCT[$size] = $x
EndFunc   ;==>NonFreeStruct

Func CleanLastStruct($number = 1)
    Global $_NON_FREE_STRUCT
    $size = UBound($_NON_FREE_STRUCT)
    For $i = 1 To $number
        $_NON_FREE_STRUCT[$size] = 0
        ReDim $_NON_FREE_STRUCT[$size - 1]
        $size -= 1
    Next
EndFunc   ;==>CleanLastStruct

Func GetStructAsByte($a)
    $tmp = DllStructCreate("byte [" & DllStructGetSize($a) & "]", DllStructGetPtr($a))
    Return DllStructGetData($tmp, 1)
EndFunc   ;==>GetStructAsByte

Func ConcatStruct(ByRef $a, ByRef $b)
    $tmp = DllStructCreate("byte a[" & DllStructGetSize($a) & "]; byte b[" & DllStructGetSize($b) & "]")

    DllStructSetData($tmp, 1, GetStructAsByte($a))
    DllStructSetData($tmp, 2, GetStructAsByte($b))
    NonFreeStruct($tmp)
    Return $tmp
EndFunc   ;==>ConcatStruct

Func GetFreezeStructPtr($a)
    NonFreeStruct($a)
    Return DllStructGetPtr($a)
EndFunc

Func MakeStringBuffer($msg)
    $tmp = DllStructCreate("char[" & StringLen($msg) + 1 & "]")
    DllStructSetData($tmp, 1, $msg)
    NonFreeStruct($tmp)
    Return DllStructGetPtr($tmp)
EndFunc   ;==>MakeStringBuffer

Func MakeUnicodeBuffer($msg)
    $tmp = DllStructCreate("wchar[" & StringLen($msg) + 1 & "]")
    DllStructSetData($tmp, 1, $msg)
    NonFreeStruct($tmp)
    Return DllStructGetPtr($tmp)
EndFunc   ;==>MakeUnicodeBuffer

Func _Py_AutoitInteralError($msg, $line = $_current_line)
    print("Internal Error:" & $line & ": " & $msg)
    Exit 1
EndFunc   ;==>_Py_AutoitInteralError

Func _Py_AutoitInteralWarning($msg, $line = $_current_line)
    print("Internal Warning:" & $line & ": " & $msg)
EndFunc   ;==>_Py_AutoitInteralWarning

Func Py($funcname, $typeret, _
        $T1 = "", $P1 = "", _
        $T2 = "", $P2 = "", _
        $T3 = "", $P3 = "", _
        $T4 = "", $P4 = "", _
        $T5 = "", $P5 = "", _
        $T6 = "", $P6 = "", _
        $T7 = "", $P7 = "", _
        $T8 = "", $P8 = "", _
        $T9 = "", $P9 = "", _
        $T10 = "", $P10 = "", _
        $T11 = "", $P11 = "", _
        $T12 = "", $P12 = "", _
        $line = @ScriptLineNumber)

    Global $PyDLL
    Global $_current_line = $line

    $ERROR_POINTER_NULL = False

    If StringLen(StringStripWS($typeret, 1 + 2 + 4 + 8)) <> StringLen($typeret) Then
        _Py_AutoitInteralError("Return Type are have space")
    EndIf

    If $typeret == "ptr" Then
        $ERROR_POINTER_NULL = True
    EndIf

    $typeret &= ":cdecl"
    $funcname = "Py" & $funcname

    If @NumParams == 2 Then
        $ret = DllCall($PyDLL, $typeret, $funcname)
    ElseIf @NumParams == 4 Then
        $ret = DllCall($PyDLL, $typeret, $funcname, $T1, $P1)
    ElseIf @NumParams == 6 Then
        $ret = DllCall($PyDLL, $typeret, $funcname, $T1, $P1, $T2, $P2)
    ElseIf @NumParams == 8 Then
        $ret = DllCall($PyDLL, $typeret, $funcname, $T1, $P1, $T2, $P2, $T3, $P3)
    ElseIf @NumParams == 10 Then
        $ret = DllCall($PyDLL, $typeret, $funcname, $T1, $P1, $T2, $P2, $T3, $P3, $T4, $P4)
    ElseIf Mod(@NumParams - 3, 2) Then
        $ExecuteString = "DllCall($PyDLL, $typeret, $funcname"
        For $i = 1 To Int((@NumParams - 2) / 2)
            $ExecuteString &= ", $T" & $i & ", $P" & $i
        Next

        $ExecuteString &= ")"

        $ret = Execute($ExecuteString)
    Else
        _Py_AutoitInteralError("Wrong Argment Given")
        Return
    EndIf

    $err = @error
    $ext = @extended

    If $err Then
        Local $err_table[5] = [ _
                '0 no error (unknown!)', _
                '1 unable to use the DLL file', _
                '2 unknown "return type"', _
                '3 "function" not found in the DLL file', _
                '4 bad number of parameters' _
                ]

        _Py_AutoitInteralError("Fail Call Function (" & $funcname & ", " & $typeret & ", '" & $err_table[$err] & "', " & $ext & ")")
        Return
    EndIf

    If IsArray($ret) Then
        $ret = $ret[0]
    EndIf

    If $ERROR_POINTER_NULL And Not $ret Then
        _Py_AutoitInteralError("The Pointer are Null")
        Return
    EndIf

    If $_Py_AutoitDebug Then
        print("Return " & _Iif(StringLen($ret), $ret, "None") & @TAB & "From " & $_current_line & " line")
    EndIf

    Return $ret
EndFunc   ;==>Py
#EndRegion help functions

python code

import spam
print(spam)
print(dir(spam))
print(spam.hello)
print(3, spam.hello(3, 3))
Edited by GreenBox
Link to comment
Share on other sites

  • 2 weeks later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...