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

Post your working scripts, libraries and tools
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
GitHub: cocobelgica

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: 691
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
User avatar
joedf
Posts: 7457
Joined: 29 Sep 2013, 17:08
Facebook: J0EDF
Google: +joedf
GitHub: joedf
Location: Canada
Contact:

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

09 Mar 2015, 02:44

Hmmm interesting
Image Image Image Image Image
Windows 10 x64 Professional, Intel i5-8500, NVIDIA GTX 1060 6GB, 2x8GB G.Skill RipJaws V - DDR4 3280 MHz | [About Me] | [ASPDM - StdLib Distribution]
[Populate the AHK MiniCity!] | [Qonsole - Quake-like console emulator] | [LibCon - Autohotkey Console Library] | [About the AHK Foundation]
GeekDude
Posts: 855
Joined: 02 Oct 2013, 22:13

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
GitHub: cocobelgica

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.
Coco
Posts: 771
Joined: 29 Sep 2013, 20:37
GitHub: cocobelgica

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.
HotKeyIt
Posts: 2039
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: 6682
Joined: 30 Sep 2013, 04:07
GitHub: Lexikos

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: 2039
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”

Who is online

Users browsing this forum: Chunjee, MSN [Bot] and 84 guests