-
Notifications
You must be signed in to change notification settings - Fork 72
/
Copy pathclass_xcall.ahk
97 lines (90 loc) · 3.96 KB
/
class_xcall.ahk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
class xcall extends xlib.callback {
__new(fn, decl*){
base.__new(fn, decl*) ; initialises this.bin
this.handler := new xlib.threadHandler() ;
this.autoCleanUp( true )
this.checkIfParamsNeedsToBeSaved ; operates on this.decl.
}
paramsToSaveList := ''
checkIfParamsNeedsToBeSaved(){
; parameters which have type such as 'str' or 'int*' needs to be internally allocated and saved.
; This method checks which params needs to be saved
local
global xlib
static str_type := 0
static ptr_type := 1
for k, type in this.decl
if instr(type, 'str')
saveParam( [k, str_type, type = 'astr' ? 'cp0' : 'utf-16' ] )
else if (c := substr(type, -1)) == '*' || c = 'p'
saveParam( [k, ptr_type, rtrim(type, '*Pp')] )
saveParam(o){
; help function
if this.paramsToSaveList == ''
this.paramsToSaveList := [] ; only create object if needed
this.paramsToSaveList.push o
}
}
autoCleanUp(bool := true){
this.autoRelease := bool
return this.handler.autoReleaseAllCallbackStructs( bool ) ; automatic clean up if bool is true.
}
outstandingCallbacks := []
nCallbacksRunning := 0
call(callback, p*){
; callback, udf script callback. (Free variable, see callbackRouter below)
; p, parameters for the worker function.
;
local
global xlib
static str_type := 0
static ptr_type := 1
; Save parameters if needed. That is parameter types such as 'str', 'int*' etc...
if this.paramsToSaveList !== '' {
savedParams := []
for k, item in this.paramsToSaveList { ; item is an array: [parameter_index, ptr_type or str_type, type or encoding]
index := item.1
if item.2 == str_type {
savedParam := new xlib[ 'strbuf' ](strlen(p[ index ]), item.3)
savedParam.str := p[ index ] ; copy the string
} else {
savedParam := new xlib[ item.3 ]( p[ index ] ) ; copy the value
}
p[ index ] := savedParam.pointer ; set the pointer to the copied value or string as parameter to be passed to the function.
savedParams[ index ] := savedParam ; save the parameters to ensure they exist when for the duration of the thread and script callback.
}
}
; Note, multi-expression line(s)
pvid := this.setupCall(p*) ; pvid: [pv, callId], pv is of type 'struct'
, pv := pvid.1 ; free variable
, callId := pvid.2 ; -- '' --
; setup callback free variables for callbackRouter (closure)
; Avoids bindnig 'this'
rt := this.rt ; return type
, o := this.o ; offset array, offsets for each parameter
, npp := this.numputParams ; numputParams, from declaration array
scriptCallback := func('callbackRouter') ; Script callback, calls udf callback function.
callbackNumber := this.handler.registerTaskCallback( ; Register the task
;
this.bin, ; Work function
pv.pointer, ; Parameters
scriptCallback,
false ; Do not start
)
this.outstandingCallbacks[ callbackNumber ] := this.autoRelease ? true : pv
, this.nCallbacksRunning++
, this.handler.startTask( callbackNumber ) ; Start
return callbackNumber
;
; Callback closure
;
callbackRouter( callbackNumber, task ){ ; callbackNumber and task is passed by the thread handler. task == this.handler
; This function is the scriptCallback called by threadHandler.callbackReciever, when it returns it releases the callback struct
; which has the last reference to this closure, hence 'pv' is released and its clean up function is called. It releases the return address and the parameter list.
; Note, one line
pRet := pv.get('ret') ; get the pointer to the return value. If desired, it will be dereferenced according to the declared return type, as stored in rt.
, resObj := xlib.callback.createResObj( pv.get('params'), savedParams, o, npp, pRet, rt, p.length() ) ; Create a result object.
, callback.call(resObj) ; callback is a parameter of the outer function.
}
}
}