How to prototype callbacks in API calls (OpenInsight 32-bit Specific)
At 18 JUN 2003 07:42:29AM Ira Krakow wrote:
To all,
I'm rewriting and adding examples of Win32 API calls for the online help. I was wondering if there was any of prototyping a callback function parameter. Many of the "Enum" type API calls have them.
For example, to find out the characteristics of all the fonts in the system, use EnumFonts, which has the (VB) declaration as follows:
Declare Function EnumFonts Lib "gdi32" Alias "EnumFontsA" (ByVal hDC As Long, ByVal lpsz As String, ByVal lpFontEnumProc As Long, ByVal lParam As Long) As Long
lpFontEnumProc is a pointer to a function that is called as each font is returned.
Can this be prototyped in OI? Can EnumFont call an OI stored procedure? VB has an "AddressOf" operator that does it.
PS: If you have any favorite examples of Windows API calls to include, please email me.
Ira
ikrakow_1999@yahoo.com
At 18 JUN 2003 11:37AM Pat McNerthney wrote:
Ira,
There is not any way to field such callbacks in OpenEngine (nor do I think there is in VB either).
Pat
At 18 JUN 2003 11:37AM [url=http://www.sprezzatura.com]The Sprezzatura Group[/url] wrote:
Ira,
It's not really possible to use Windows API callback functions in OI (except via a DLL, but that's another story as our clients or users of our Utility32 (ironically for EnumFonts and EnumWindows) will testify
)
When you use functions like EnumWindows or EnumFonts you are expected to pass the *memory* address of the function you would like Windows to use when it has some information to pass back to you. This memory address must point to a valid function within a process's code segment as Windows will call it just like any other Windows API call.
This also means that callback functions must be a valid sequence of x86 executable code which of course Basic+ object code is not - it's just a stream of bytes that is interpreted by OE at runtime, rather than executed directly by the processor.
World leaders in all things RevSoft
At 18 JUN 2003 11:39AM [url=http://www.sprezzatura.com]The Sprezzatura Group[/url] wrote:
Hey, beat me by a few seconds - you must have been a gunfighter in a former life :)
World leaders in all things RevSoft
At 18 JUN 2003 11:56AM att sorrell wrote:
At 18 JUN 2003 11:59AM Matt Sorrell wrote:
Erg!! Ignore the empty post, silly return key got in the way.
Not to disagree with you Pat, but you can field callbacks in VB. I do it all the time. As Ira mentioned, you use the AddressOf operator in conjunction with a function name. As Sprezz mentions, they use a custom DLL to handle the Enum functions.
I have written several different programs that utilize EnumWindows and EnumFonts.
msorrel@greyhound.com
At 18 JUN 2003 02:39PM Ira Krakow wrote:
Guess what!
Function pointers are already in OI! You can call a subroutine indirectly using the code below:
SUB_NAME=MSG"
call @SUB_NAME( @window, 'HELLO')
…and you can call a function with the code below…
rv=function(@SUB_NAME( @window, 'HELLO AGAIN'))
The only way this would work is if SUB_NAME contains the address of the MSG function.
By the way, the comparison assumes all upper case. The contents of SUB_NAME *must* be MSG (not Msg, msg, mSg, etc.) in order to get the call to work - at least in 4.1.3a, which is what I used.
It would be great to expose this so that we could use the ENUM_ type API calls.
Ira
At 18 JUN 2003 03:24PM Ira Krakow wrote:
An update. You *can* pass functions as arguments in OI. I tried the following (admittedly a made-up example, but it works for the sake of illustration):
I created 3 functions:
RETURN_ARG1:
function return_arg1(arg)
return arg / 2
RETURN_ARG2:
function return_arg2( arg)
return arg
F_ADD2ARGS:
function f_add2args( arg1, arg2)
return arg1 + arg2
and called all of them with this:
(NOTE: NO FUNCTION DECLARATIONS!!)
var1=RETURN_ARG1'
var2=RETURN_ARG2'
result=F_ADD2ARGS'
rv=function(@Result( function(@var1(8)) , function(@var2(9)) ) )
call msg( @window, rv)
This code displays the result in rv as 13 ( 8 / 2 + 9), tracing through shows the functions were called and returned properly.
This, I think, is powerful stuff, passing arguments that are evaluated as the result of a function call. I believe this capability has been there for a long time…it just hasn't been documented
.
Ira
At 18 JUN 2003 03:38PM Pat McNerthney wrote:
Ira,
Yes, you can do all of that within OpenEngine itself. However, your original question was about having callbacks passed to Win32 APIs, which is a whole different beast, and currently not possible.
Pat
At 18 JUN 2003 03:59PM [url=http://www.sprezzatura.com]The Sprezzatura Group[/url] wrote:
HI Ira,
Function pointers are already in OI! You can call a subroutine indirectly using the code below: SUB_NAME=MSG" call @SUB_NAME( @window, 'HELLO') …and you can call a function with the code below… rv=function(@SUB_NAME( @window, 'HELLO AGAIN')) The only way this would work is if SUB_NAME contains the address of the MSG function.
SUB_NAME contains a string that specifies the literal name of the function to call. The @ operator tells the engine to use the contents of the SUB_NAME variable as the name of the Basic+ function to execute. The program loader in OE (RTP27) looks at the name of the program it has been asked to find and using this as an index, retrieves the object code from a dimensioned array (AKA the program stack) and then begins to interpret it.
Remember that Basic+ functions are *not* x86 machine code. They are just a string variable that's interpreted by OpenEngine as a series of instructions to execute. Currently there is no way for an outside process to execute a Basic+ function UNLESS it uses RevCAPI. If we could call functions via a pointer then we wouldn't need RevCAPI at all :)
World leaders in all things RevSoft
At 18 JUN 2003 05:36PM Ira Krakow wrote:
Dear Sprezz,
Thanks for clearing this up. I understand the difference.
Best wishes.
Ira
At 19 JUN 2003 02:49AM [url=http://www.sprezzatura.com]The Sprezzatura Group[/url] wrote:
Actually, it's more than that. It's how the interpreter resolves the expressions as they are processed.
The same concept is what allows structures such as
X=If V1 ] 100 then Y Else Z
The language is an expression evaluator, in some ways. It's why when doing OR logic, it doesn't matter which is on which side, since everything is evaluated. It doesn't stop when one side is true.
If logic is
IF (Expression=TRUE") then
so expression gets evaluated like
V1 ] 100 OR V2 ] 200
which is simply an expression, that needs to be evaulated.
This is how the calling contstructs work. The expressions are evaluated, so when you find the Call @SVAR(FUNCTION( @VAR(P1,P2))), the function expression must be evaluated before the previous expression.
Knowing that helps explain how the language works as it works and why certain things are possible in Basic+ and other things are not.
World Leaders in all Things RevSoft