Func.Bind()/ObjBindMethod() tricks - extended functions

Post your working scripts, libraries and tools for AHK v1.1 and older
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
Contact:

Func.Bind()/ObjBindMethod() tricks - extended functions

08 Mar 2015, 05:18

Just some useful/convenient BoundFunc objects(there are many more of course) :D :

Code: Select all

WshShell := ComObjCreate("WScript.Shell")

Exec := ObjBindMethod(WshShell, "Exec")
%Exec%("calc.exe")

; alternative MsgBox
Popup := ObjBindMethod(WshShell, "Popup")
%Popup%("Hello World",, A_ScriptName)

; current process ID
A_ScriptPid := Func("DllCall").Bind("GetCurrentProcessId", "Ptr", 0)
%Popup%( "A_ScriptPid = " . %A_ScriptPid%() )

; count of key-value pairs
ObjCount := Func("NumGet").Bind(4 * A_PtrSize)
obj := {a:"Auto", h:"Hot", k:"key"}
%Popup%( "ObjCount = " . %ObjCount%(&obj) ) ; must pass address

StrUpper := Func("Format").Bind("{:Us}")
%Popup%( %StrUpper%("autohotkey") )

StrLower := Func("Format").Bind("{:Ls}")
%Popup%( %StrLower%("AUTOHOTKEY") )

StrTitle := Func("Format").Bind("{:Ts}")
%Popup%( %StrTitle%("the quick brown fox") )

DecToHex := Func("Format").Bind("0x{:X}")
%Popup%( "57007 = " . %DecToHex%(57007) )

IsWinVisible := Func("DllCall").Bind("IsWindowVisible", "Ptr")
%Popup%( %IsWinVisible%(A_ScriptHwnd + 0) ) ; must pass hWnd

IsWindow := Func("DllCall").Bind("IsWindow", "Ptr")
%Popup%( %IsWindow%(A_ScriptHwnd + 0) )

sc := ComObjCreate("ScriptControl")
sc.Language := "JScript"
JsEval := ObjBindMethod(sc, "Eval")
%Popup%( "1 + 1 = " . %JsEval%("1 + 1") )

; Readable OnMessage(es)
OnWinDestroy := Func("OnMessage").Bind(0x02)
%OnWinDestroy%("WM_DESTROY")
ExitApp
toralf
Posts: 868
Joined: 27 Apr 2014, 21:08
Location: Germany

Re: Func.Bind()/ObjBindMethod() tricks - extended functions

08 Mar 2015, 15:42

Did you test if a bound function is faster or slower than the normal call? E.g. Inside of a loop with multiple cycles.
ciao
toralf
geek
Posts: 1052
Joined: 02 Oct 2013, 22:13
Location: GeekDude
Contact:

Re: Func.Bind()/ObjBindMethod() tricks - extended functions

09 Mar 2015, 10:59

I was halfway expecting to be able to do this

Code: Select all

Shell := ComObjCreate("WScript.Shell")
Exec := ObjBindMethod(Shell, "Exec", A_AhkPath " *")
Dyna := ObjBindMethod(Exec, "StdIn.Write")
; Or
Dyna := ObjBindMethod(ObjBindMethod(Exec, "StdIn"), "Write")
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
Contact:

Re: Func.Bind()/ObjBindMethod() tricks - extended functions

09 Mar 2015, 11:16

@toralf, nope I haven't benchmarked it yet. Performance should be similar to Func(function references).
@GeekDude, have you tried StdinWrite := ObjBindMethod(Exec.Stdin, "Write")? Since Exec.StdIn is a TextStream object.
geek
Posts: 1052
Joined: 02 Oct 2013, 22:13
Location: GeekDude
Contact:

Re: Func.Bind()/ObjBindMethod() tricks - extended functions

09 Mar 2015, 11:18

Exec.Stdin is a non-existent property on the Exec BoundFunc object
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
Contact:

Re: Func.Bind()/ObjBindMethod() tricks - extended functions

09 Mar 2015, 11:37

I see, you would have to do ObjBindMethod(Exec.Call().StdIn, "Write") which I assume is not what you really wanted.
geek
Posts: 1052
Joined: 02 Oct 2013, 22:13
Location: GeekDude
Contact:

Re: Func.Bind()/ObjBindMethod() tricks - extended functions

11 Mar 2015, 21:20

I could just actually write the function
HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

Re: Func.Bind()/ObjBindMethod() tricks - extended functions

13 Mar 2015, 16:08

I've done a bit testing in AHK_H using GetCurrentProcessId: (for reference: #DllImport, DynaCall)

Code: Select all

Method		  Result		Duration
#DllImport:	0x1F1C		1 (125)
DynaCall:     0x1F1C		1.36
DllCall:      0x1F1C		2.23
Bind:		   0x1F1C		3.39
So Bind is obviously much slower than direct DllCall and should be only used where speed does not matter or Bind is required.

Following the test script used for above results. (requires AutoHotkey_H v2)

Code: Select all

GetCurrentProcessIdBind := Func("DllCall").Bind(GetProcAddress(LoadLibrary("kernel32.dll"),"GetCurrentProcessId"), "Ptr", 0,"Cdecl")
GetCurrentProcessIdDynaCall := DynaCall("GetCurrentProcessId","ui==t")
ProcessSetPriority,High
loop:=1000000
QueryPerformanceCounter(getvar(v1:=0))
Loop loop
    var1:=GetCurrentProcessId() ; #DllImport
QueryPerformanceCounter(getvar(v2:=0))
Loop loop
    var2:=GetCurrentProcessIdDynaCall[] ; DynaCall
QueryPerformanceCounter(getvar(v3:=0))
Loop loop
    var3:=DllCall("GetCurrentProcessId","PTR",0,"Cdecl") ; DllCall
QueryPerformanceCounter(getvar(v4:=0))
Loop loop
    var4:=%GetCurrentProcessIdBind%() ; Bind call
QueryPerformanceCounter(getvar(v5:=0)),QueryPerformanceFrequency(getvar(p:=0))
MsgBox % format("Method`t`tResult`t`tDuration`n#DllImport:`t0x{1:X}`t`t1 ({2})`nDynaCall:`t`t0x{3:X}`t`t{4:.2f}`nDllCall:`t`t0x{5:X}`t`t{6:.2f}`nBind:`t`t0x{7:X}`t`t{8:.2f}`n",var1,Round((v2-v1)/p*1000,0),var2,(v3-v2)/(v2-v1),var3,(v4-v3)/(v2-v1),var4,(v5-v4)/(v2-v1))
EDIT:
Thanks Lexikos, example corrected above to use a pointer to GetCurrentProcessId to have proper comparison.
So the difference is not really big which is great :D
lexikos
Posts: 9583
Joined: 30 Sep 2013, 04:07
Contact:

Re: Func.Bind()/ObjBindMethod() tricks - extended functions

13 Mar 2015, 23:04

You are comparing apples with oranges.

The main reason for the difference in performance is LoadLibrary/GetProcAddress. When you call DllCall directly or use #DllImport, "GetCurrentProcessId" is automatically resolved to a pointer at load-time. If you perform the same optimization manually, the bound function takes only about twice as long as a direct call (it's still < 1µs). A variadic call is partway between the two.

It should also be noted that GetCurrentProcessId is just a placeholder in this case. It does not normally take parameters, and is not Cdecl.

Most functions will take longer than GetCurrentProcessId, so the relative difference between the two methods of calling it will be lesser. For example, when I used the parameter list PointerToIsWindow, "ptr", A_ScriptHwnd, "int", the difference was less than one percent. In that test, a variadic call was actually faster than a normal call; probably due to differences in CPU cache utilization or other magic.
HotKeyIt
Posts: 2364
Joined: 29 Sep 2013, 18:35
Contact:

Re: Func.Bind()/ObjBindMethod() tricks - extended functions

14 Mar 2015, 06:59

Many thanks Lexikos, I have updated example above to use a pointer for Bind Call, I totally missed that :oops:

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 256 guests