Testing callback from newlisp.dll to newlisp.exe

Started by HPW, September 07, 2011, 02:04:17 PM

Previous topic - Next topic

HPW

Hello,



I try to test the callback from newlisp.dll to newlisp.exe



(import "user32.dll" "MessageBoxA")
(import "newlisp.dll" "newlispEvalStr")
(define (mycallback stext)
(eval-string stext)
)
(setq callbackadr(callback 0 'mycallback))
(MessageBoxA 0 (string "This is callbackadr: " callbackadr) "newLISP EXE" 0)

(setq newlispstr (string "(setq nlmaincallback print)(cpymem(pack "ld" 265)(first(dump nlmaincallback))4)(cpymem(pack "ld" "callbackadr")(+(first(dump nlmaincallback))12)4)(cpymem(pack "ld" "nlmaincallback")(+(first(dump nlmaincallback))8)4)"))
(MessageBoxA 0 (string "This is newlispstr: " newlispstr) "newLISP EXE" 0)
(newlispEvalStr newlispstr)
(MessageBoxA 0 (string "This is next step") "newLISP EXE" 0)

(MessageBoxA 0 (mycallback "(string(symbols))") "newLISP EXE" 0)

(MessageBoxA 0 (newlispEvalStr "(nlmaincallback "(string(symbols))")") "newLISP EXE" 0)


Last line does not work. Show's a -1.

So is it possible to callback newLISP.exe from newlisp.dll ?
Hans-Peter

Lutz

#1
from the other thread:


QuoteAnd does the callback-function support a return value ? Of which type?


The newLISP function assigned in callback will receive all parameters as integers. When a string pointer was passed from the DLL it will be received as an integer. You can then use get-string or unpack to get the string contents.



Similar the return value from the callback is always an integer which must be interpreted by the caller library (DLL) as either a number or a memory address, e.g. a string pointer.


QuoteSo is it possible to callback newLISP.exe from newlisp.dll


You may be on the right track, but try callbackadr instead of the quoted "callbackadr"  in the second cpymem statement. Also all the code after the first MessageBoxA should be happening in the newLISP DLL calling back into newlisp.exe. In newlisp.exe you would do:


(newlispEvalStr (format "(set 'callbackadr %u)" callbackaddr))

... to bring the callback address to newlisp.dll.



Then you would execute all the cpymem stuff via newlispEvalStr to make it happen in newlisp.dll.



The last cpymem for the function name is not really required (only for error messages and when debugging). It also would loose the reference to "nlmaincallback".



See also a recently changes for this in:



http://www.newlisp.org/index.cgi?page=Embedded_Binary">http://www.newlisp.org/index.cgi?page=Embedded_Binary

HPW

#2
Hello Lutz,



Thanks for the explanation about param-type. Should be added to the doc under callback.

I will try your suggestion. I will report any progress.



Hans-Peter
Hans-Peter

HPW

#3
Got it workink so far with one problem remaining:

(import "user32.dll" "MessageBoxA")
(import "newlisp.dll" "newlispEvalStr")
(setq ExeTest1 40 ExeTest2 50 ExeTest3 60)
(define (mycallback stext myresult)
(MessageBoxA 0 (string "Inside MyCallBack") "newLISP EXE" 0)
(setq myresult(eval-string (get-string stext)))
(MessageBoxA 0 (string "Done MyCallBack: " myresult) "newLISP EXE" 0) ;Show coorrect value
(string myresult)
)
(setq callbackadr(callback 0 'mycallback))
(MessageBoxA 0 (string "This is callbackadr: " callbackadr) "newLISP EXE" 0)

;Define and register the callback-function in the DLL
(setq newlispstr (string "(setq nlmaincallback print)(cpymem(pack "ld" 265)(first(dump nlmaincallback))4)(cpymem(pack "ld" "callbackadr")(+(first(dump nlmaincallback))12)4)(cpymem(pack "ld" "nlmaincallback")(+(first(dump nlmaincallback))8)4)"))
;(MessageBoxA 0 (string "This is newlispstr: " newlispstr) "newLISP EXE" 0)
(newlispEvalStr newlispstr)

(setq resultpointer(newlispEvalStr "(get-string(nlmaincallback "(setq ExeTest4 (+ ExeTest1 ExeTest2))"))"))
(setq resultpointer(get-string resultpointer))
(MessageBoxA 0 (string "CallBack-Result: "resultpointer) "newLISP EXE" 0)
(MessageBoxA 0 (string "ExeTest4: "ExeTest4) "newLISP EXE" 0)

The callback is called properly and the testvalue is set in the EXE instance.

Only the content of resultpointer is a strange return "x01>".

Other ideas?



Hans-Peter
Hans-Peter

Lutz

#4
In this scenario, newlisp.dll - doing the cpymem stuff - does a library function call and gets an expired cell-address in return, which is collected by memory management in newlisp.exe.



You would have to store the result in a global variable as shown here:


#!/usr/bin/newlisp
# demo of newlisp library calling back into newlisp parent

(import (if (= ostype "Win32")  "newlisp.dll" "newlisp.dylib") "newlispEvalStr")

(define (mycallback str)
    (set 'result (get-string str))
    (println "mycallback has been called: " result)
)

(set 'dll-code [text][cmd]
(set 'foo print)
(cpymem (pack "ld" (if (= ostype "Win32") 265 264)) (first (dump foo)) 4)
(cpymem (pack "ld" %d) (+ (first (dump foo)) 12) 4)
(set 'foo-name "foo")
(cpymem (pack "ld" foo-name) (+ (first (dump foo)) 8) 4)
[/cmd][/text]
)

(newlispEvalStr (format dll-code (callback 0 'mycallback)))

(newlispEvalStr {(foo "hello from newlisp library")})
(println "global result set to: " result)

(exit)


Note how multi-line text for newlispEvalStr has to be bracketed with [cmd], [/cmd] tags.

HPW

#5
Hello Lutz,



Thanks for the additional explanation.

(The info about the expired cell-address should also go into the doc)

Now all works and make sense.

With the help of the DLL-flavour (newlisp.dll) pdScript is able to do the callbacks into the exe.

Because pdScript is not able to create a function dynamicly on a memory address.

But through the real exported function of newlisp.dll it can do it.

newlisp show again how flexibel it is. And even after a long time I learned something new about newlisp.

;-)



Hans-Peter
Hans-Peter