'
' ------------------------------------------------------------------------
' MULTIPLE CALLBACK UNDER RAPIDQ      Text  Documentation       by Jacques
' 
' September 25rd, 2005
' August 13th, 2006
' This turn around was a group work. Thanks to John, Paul and Warriant
' ------------------------------------------------------------------------
'
' ------------------------------------------------------------------------
' A Short Example is Better than a long Theory for a Four Arguments CallBack
' The Extra Argument not counted 
' ------------------------------------------------------------------------
' $Include "CallBack_4.Inc"        ' _4 may be _0, _1, ..., _8   = Nbr of arguments of Your CallBack
'
' Function UserCallBackFunctionName (A1 As Long, A2 As Long, A3 as Long , A4 As Long) As Long
'     ' nice efficient code
' End Function
'
' DefInt iAnyName     
' Bind iAnyName To UserCallBackFunctionName            ' iAnyName maybe reused but in some case not
' DefInt lpfnCallBack = SetNewCallBack_4 (iAnyName)    ' _4 = Nbr of arguments of your CallBack
'
' ------------------------------------------------------------------------
' That's it
'
' CallBack_x.Inc automatically include CallBackForwarder.Inc if not yet included.
' LIMITATIONS :
'   - _4 Can be _1, _2, _3, _4, _5, _6, _7, _8  for  1,2,3,4,4,6,7,8 Arguments
'   - There is no maximum number of callback anymore
'   - Any Use of the RapidQ CodePtr Word will DEEPLY harm this
'     !!!!!!!!!!  YOU CANNOT USE CODEPTR ANYMORE  !!!!!!!!!!!!!
'     RapidQ allows only one CodePtr for Each Function Prototype, if
'     two CodePtr are used to point 4 arguments functions, the latter
'     will overwrite the former (See CallBackBugDemo.Bas).
' ----------------------------------------------------------------------------------
' ----------------------------------------------------------------------------------
' HOW IT WORKS :
' ----------------------------------------------------------------------------------
'  - the external process calls the CallBack Forwarder
'  - the callback forwarder forwards the Caller to the master callback function
'    (i.e MasterCallBack_4 in CallBack_4.Inc). It adds a first argument which is an
'    the RapidQ handle of the RqFunction to forward to (Bind RqFuncHandle To YourCallBackFunc).
'  - the master callback use CallFunc to Call the User CallBack. The Master Callback
'    is built in the callback_X Include file.
'
'  The Programmer Must (example for a 4 arguments CallBack):
'    1 - Get the RapidQ Function Handle of his CallBack Function
'          DefInt hRqFunction
'          Bind hRqFunction To RqCallBackFunction
'    2 - Create a CallBack Forwarder for his CallBack by calling
'      lpfnCallBackForwarder = SetNewCallBack_4 (hRqFunction)
'      lpfnCallBackForwarder returned by SetNewCallBack_4 is the address/lpfn
'      you have to pass to the external process.
' **********************************************************************************
' ---- CallBack Forwader Documentation ---------------------------------------------
' The CallBack Forwarder Code (14 bytes) will be Generated in an allocated memory space,
' the pointer to that space is returned by the function.
' ForwardTo : a function pointer to our callback funtion (+ one one : first = CallBack
'             Index you choose)
' CBIndex   : a user choosen number to identify this CallBack forwarder
' --- CallBack Forwarder Nasm Assembler code ---- Nasm List ------------------------
' ----------------------------------------------------------------------------------
'  Offset   Hexadecimal   Cycles  Memory     Mnemonic                Comments
' decimal   Code         486 CPU
' ----------------------------------------------------------------------------------
'    0000   58                 1       1     pop    eax              ; eax = return address
'    0001   68DDCCBBAA         4       2     push   dword CBIndex    ; CBIndex 5th Argument
'    0005   50                 1       1     push   eax              ; return address back on the stack
'    0007   B8DDCCBBAA         1       1     mov    eax, ForwardTo   ; eax = lpfnForwardTo
'    0012   FFE0               5       0     jmp    eax              ; Goto lpfnForwardTo
' ----------------------------------------------------------------------------------
' tot: 14                     12       5        
' ----------------------------------------------------------------------------------
' The job is done in 12 processor cycles and 5 memory access ! For a 2GHz processor 
' it will take 6 billionth of a second + 5 memory access whose duration are unpredictable.
' ----------------------------------------------------------------------------------
' **********************************************************************************
'