Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

[AHK_H(+dll) / AHK_L / v2] AhkDllThread+AhkExported


  • Please log in to reply
274 replies to this topic
aSEioT
  • Members
  • 87 posts
  • Last active:
  • Joined: 31 Oct 2010

Thanks for pointing out, I have updated DynaCall Docs

Ok, thank you! but what should i do when the return type is "void", just omit it?

HotKeyIt
  • Moderators
  • 7439 posts
  • Last active: Jun 22 2016 09:14 PM
  • Joined: 18 Jun 2008
If you omit it it will be default = int same as DllCall.

aSEioT
  • Members
  • 87 posts
  • Last active:
  • Joined: 31 Oct 2010

If you omit it it will be default = int same as DllCall.

Should I use "i=p" or just "=p", seems is different?
Thank you for your brilliant invention--'dynacall'! Save a lot of typo!
ahkdll is a great extension of ahk!!

Just a thinking , if we can easily get object from ahkdll(in official ahk_l), then it may possible use it to parse json.

HotKeyIt
  • Moderators
  • 7439 posts
  • Last active: Jun 22 2016 09:14 PM
  • Joined: 18 Jun 2008
ip or i* is equivalent to intP.
When you have no return value you must not use =
Sleep:=DynaCall("Sleep","ui",100) ; default 100
Sleep[]
Sleep[1000]

Using COM Interface you can also receive a COM object.
dll:=ComObjCreate("AutoHotkey.Script")
dll.ahkTextdll("#Persistent`narr:=ComObjArray(VT_VARIANT:=12, 3)`narr[0] := ""Auto""`narr[1] := ""Hot""`narr[2] := ""key""")
Sleep 1000 ; wait for object to be set
obj:=dll.ahkgetvar["arr"]
MsgBox % obj.0 obj.1 obj.2
MsgBox % dll.ahkgetvar["arr"].2
Another way to share objects is Alias() or Object()

Share an object to dll:
dll:=AhkDllThread()
arr:=["a","b","c"]
dll.ahkTextdll("#Persistent`narr:=Object(" &arr ")`nMsgBox % arr.1 arr.2 arr.3")
; dll.ahkTextdll("Alias(arr," getVar(arr) ")`nMsgBox % arr.1 arr.2 arr.3")      ; the Alias way
While % dll.ahkReady()
	Sleep 100
Or get an object from dll:
dll:=AhkDllThread()
dll.ahkTextdll("#Persistent`narr:=[""a"",""b"",""c""]")
Sleep 100 ; wait for object to initialize
Alias(arr,dll.ahkgetvar("arr",1))
MsgBox % arr.1


aSEioT
  • Members
  • 87 posts
  • Last active:
  • Joined: 31 Oct 2010
when I use "AhkDllThread" create a new thread, should I MemoryFreeLibrary after terminate it and how (in AHK_L)? :)

HotKeyIt
  • Moderators
  • 7439 posts
  • Last active: Jun 22 2016 09:14 PM
  • Joined: 18 Jun 2008
Just call AhkDllThread() (same in AHK_L), it will call MemoryFreeLibrary() for all dlls. But I do not think this is necessary, as I understand when exe exits the resources will be free to use anyway.

aSEioT
  • Members
  • 87 posts
  • Last active:
  • Joined: 31 Oct 2010
problem in unload ahkdll!
newThread := AhkDllThread()				; slightly modified to expose the handle of ahkdll
newThread.ahktextdll("#NoTrayIcon`nMsgbox working`n~VKFF::Return")		; test if it is working!
Sleep, 2000
;try to unload the dll
AhkDllThread("")							; MemoryFreeLibrary, need this or not?
newThread.ahkTerminate(1)			; force the thread terminated, need this step or not ?
DllCall("FreeLibrary", "UInt", handleOfAhkdll)			[color=red]; then try to unload it, but this may cause system error (induce the process"WerFault.exe" in win 7) and the main script is abnormally exit.[/color]
~VKFF::Return			; force the main thread persistent



AhkDllThread_GetVersion(Query:="FileDescription"){
	static CS := A_IsUnicode ? "W" : "A"
	FSz:=DllCall("Version\GetFileVersionInfoSize" CS, "Str",A_AhkPath, "UInt",0 )
	VarSetCapacity( FVI, FSz, 0 ),VarSetCapacity( Trans,8*(A_IsUnicode?2:1) )
	DllCall("Version\GetFileVersionInfo" CS, "Str",A_AhkPath, "Int",0, "UInt",FSz, "UInt",&FVI )
	DllCall("Version\VerQueryValue" CS, "UInt",&FVI, "Str","\VarFileInfo\Translation", "UIntP",Translation, "UInt",0 )
	DllCall("msvcrt\s" (A_IsUnicode ? "w": "" ) "printf", "Str",Trans, "Str","`%08X", "UInt",NumGet(Translation+0) )
	subBlock := "\StringFileInfo\" SubStr(Trans,-4) SubStr(Trans,1,4) "\" Query
	DllCall("Version\VerQueryValue" CS, "UInt",&FVI, "Str",SubBlock, "UIntP",InfoPtr, "UInt",0 )
	Return StrGet( InfoPtr )
}

AhkDllThread(dll:="AutoHotkey.dll",obj:=0){
	[color=red]global handleOfAhkdll[/color]
	static
	local v,v1,v2
	static init, DynaCall:="DynaCall", MemoryLoadLibrary:="MemoryLoadLibrary",MemoryFreeLibrary:="MemoryFreeLibrary"
			,ResourceLoadLibrary:="ResourceLoadLibrary", MemoryGetProcAddress:="MemoryGetProcAddress"
	static Trans, AHK_H:=(AhkDllThread_GetVersion()=="AutoHotkey_H")
	static functions :="
(Join
ahkKey:s|ahkFunction:s=sssssssssss|ahkPostFunction:i=sssssssssss|
ahkdll:t=ss|ahktextdll:t=ss|ahkReady:|ahkReload:ui=|
ahkTerminate:i|addFile:t=sucuc|addScript:t=si|ahkExec:ui=s|
ahkassign:ui=ss|ahkExecuteLine:t=tuiui|
ahkFindLabel:t=s|ahkgetvar:s=sui|ahkLabel:t=sui|ahkPause:s
)"
  static AhkDllThreadfunc :="
(Join`r`n
#NoTrayIcon
Pause
Return
AhkDllThread(dll:="AutoHotkey.dll",obj:=0,map:=""){
	static
	local v,v1,v2
	static functions := "ahkKey:s|ahkFunction:s=sssssssssss|ahkPostFunction:i=sssssssssss|"
							. "ahkdll:t=ss|ahktextdll:t=ss|ahkReady:|ahkReload:ui=|"
							. "ahkTerminate:i|addFile:t=sucuc|addScript:t=si|ahkExec:ui=s|"
							. "ahkassign:ui=ss|ahkExecuteLine:t=tuiui|"
							. "ahkFindLabel:t=s|ahkgetvar:s=sui|ahkLabel:t=sui|ahkPause:s"
	If !dll {
		Loop `% i
		{
			idx:=A_Index
			`%MemoryFreeLibrary`%(dllmodule`%A_Index`%)
			obj`%A_Index`%:="",dll`%A_Index`%:="",dllmodule`%A_Index`%:=""
		}
		i:=0
		return
	} else if (!FileExist(dll)){
		MsgBox File: `%dll`% does not exist`, provide correct path for AutoHotkey.dll
		ExitApp
	}
	i++
	dllmodule`%i`%:= MemoryLoadLibrary(dll)
	if IsObject(obj)
		object:=obj
	else
		object := Object()
	object[""]:=dllmodule`%i`%
	LoopParse,`%functions`%,|
	{
		StrSplit,v,`%A_LoopField`%,:
		object[map="" ? v.1 ]:=DynaCall(MemoryGetProcAddress(dllmodule`%i`%,v.1),v.2)
	}
  obj`%i`%:=object
	dll`%i`%:=dll
	return &obj`%i`%
}
)"
  If !(dll){
    If !AHK_H {
			return DllCall(dll "\ahkFunction","Str","AhkDllThread","Str","","Str","","Str","","Str","","Str","","Str","","Str","","Str","","Str","","Str","","CDecl Str")
		}
		Loop % i
		{
			idx:=A_Index
			%MemoryFreeLibrary%(dllmodule%A_Index%)
			obj%A_Index%:="",dll%A_Index%:="",dllmodule%A_Index%:=""
		}
		i:=0
		return
	} else if (!FileExist(dll) && !A_IsCompiled){
		MsgBox File: %dll%`ndoes not exist`, provide correct path for AutoHotkey.dll
		ExitApp
	}
	If !AHK_H {
		If (init ||[color=red] handleOfAhkdll := [/color]init:=DllCall("LoadLibrary","Str",dll)){
			If DllCall(dll "\ahktextdll","Str",AhkDllThreadfunc,"Str","","Str","","Cdecl UInt")
				Return Object(0+DllCall(dll "\ahkFunction","Str","AhkDllThread","Str",dll,"Str","","Str","","Str","","Str","","Str","","Str","","Str","","Str","","Str","","CDecl Str"))
			else
				Return 0,ErrorLevel:="Could not load AutoHotkey.dll"
		} else {
			MsgBox Could not load %dll%
			Return 0
		}
	}
	i++
	dllmodule%i%:=A_IsCompiled ? %ResourceLoadLibrary%(dll) : %MemoryLoadLibrary%(dll)
	if IsObject(obj)
    object:=obj
	else
    object := Object()
  object[""]:=dllmodule%i%
	LoopParse,%functions%,|
	{
		StrSplit,v,%A_LoopField%,:
		object[map="" ? v.1 ]:=%DynaCall%(%MemoryGetProcAddress%(dllmodule%i%,v.1),v.2)
	}
  obj%i%:=object
	dll%i%:=dll
	return obj%i%
}
Am I doing sth wrong? :oops:
Thank you for your patient reply for my dull questions!!

HotKeyIt
  • Moderators
  • 7439 posts
  • Last active: Jun 22 2016 09:14 PM
  • Joined: 18 Jun 2008
AhkDllThread() uses MemoryLoadLibrary, MemoryGetProcAddress and MemoryFreeLibrary.
Calling AhkDllThread("") is enough, newThread.ahkTerminate(1) needs to be called before freeing library.

If you want to unload the dll that starts the threads in AHK_L you better replace init with handleOfAhkdll completely and also set it empty once unloaded (handleOfAhkdll:="").

aSEioT
  • Members
  • 87 posts
  • Last active:
  • Joined: 31 Oct 2010

AhkDllThread() uses MemoryLoadLibrary, MemoryGetProcAddress and MemoryFreeLibrary.
Calling AhkDllThread("") is enough, newThread.ahkTerminate(1) needs to be called before freeing library.

If you want to unload the dll that starts the threads in AHK_L you better replace init with handleOfAhkdll completely and also set it empty once unloaded (handleOfAhkdll:="").


If I don't misunderstand, then I just do it in the right sequence! but how about the crash? in my demo code, there was just one calling, then "init" and "handleOfAhkdll" are not mess in this situation.

HotKeyIt
  • Moderators
  • 7439 posts
  • Last active: Jun 22 2016 09:14 PM
  • Joined: 18 Jun 2008
Try this, I have done some fixes:
AhkDllThread_GetVersion(Query:="FileDescription"){

   static CS := A_IsUnicode ? "W" : "A"

   FSz:=DllCall("Version\GetFileVersionInfoSize" CS, "Str",A_AhkPath, "UInt",0 )

   VarSetCapacity( FVI, FSz, 0 ),VarSetCapacity( Trans,8*(A_IsUnicode?2:1) )

   DllCall("Version\GetFileVersionInfo" CS, "Str",A_AhkPath, "Int",0, "UInt",FSz, "UInt",&FVI )

   DllCall("Version\VerQueryValue" CS, "UInt",&FVI, "Str","\VarFileInfo\Translation", "UIntP",Translation, "UInt",0 )

   DllCall("msvcrt\s" (A_IsUnicode ? "w": "" ) "printf", "Str",Trans, "Str","`%08X", "UInt",NumGet(Translation+0) )

   subBlock := "\StringFileInfo\" SubStr(Trans,-4) SubStr(Trans,1,4) "\" Query

   DllCall("Version\VerQueryValue" CS, "UInt",&FVI, "Str",SubBlock, "UIntP",InfoPtr, "UInt",0 )

   Return StrGet( InfoPtr )

}



AhkDllThread(dll:="AutoHotkey.dll",obj:=0){

   static

   local v,v1,v2

   static handleOfAhkdll,DynaCall:="DynaCall", MemoryLoadLibrary:="MemoryLoadLibrary",MemoryFreeLibrary:="MemoryFreeLibrary"

         ,ResourceLoadLibrary:="ResourceLoadLibrary", MemoryGetProcAddress:="MemoryGetProcAddress"

   static Trans, AHK_H:=(AhkDllThread_GetVersion()=="AutoHotkey_H")

   static functions :="

(Join

ahkKey:s|ahkFunction:s=sssssssssss|ahkPostFunction:i=sssssssssss|

ahkdll:t=ss|ahktextdll:t=ss|ahkReady:|ahkReload:ui=|

ahkTerminate:i|addFile:t=sucuc|addScript:t=si|ahkExec:ui=s|

ahkassign:ui=ss|ahkExecuteLine:t=tuiui|

ahkFindLabel:t=s|ahkgetvar:s=sui|ahkLabel:t=sui|ahkPause:s

)"

  static AhkDllThreadfunc :="

(Join`r`n

#NoTrayIcon

Pause

Return

AhkDllThread(dll:="AutoHotkey.dll",obj:=0,map:=""){

   static

   local v,v1,v2

   static functions := "ahkKey:s|ahkFunction:s=sssssssssss|ahkPostFunction:i=sssssssssss|"

                     . "ahkdll:t=ss|ahktextdll:t=ss|ahkReady:|ahkReload:ui=|"

                     . "ahkTerminate:i|addFile:t=sucuc|addScript:t=si|ahkExec:ui=s|"

                     . "ahkassign:ui=ss|ahkExecuteLine:t=tuiui|"

                     . "ahkFindLabel:t=s|ahkgetvar:s=sui|ahkLabel:t=sui|ahkPause:s"

   If !dll {

	  Loop `% i

      {

         idx:=A_Index

         `%MemoryFreeLibrary`%(dllmodule`%A_Index`%)

         obj`%A_Index`%:="",dll`%A_Index`%:="",dllmodule`%A_Index`%:=""

      }

      i:=0

      return

   } else if (!FileExist(dll)){

      MsgBox File: `%dll`% does not exist`, provide correct path for AutoHotkey.dll

      ExitApp

   }

   i++

   dllmodule`%i`%:= MemoryLoadLibrary(dll)

   if IsObject(obj)

      object:=obj

   else

      object := Object()

   object[""]:=dllmodule`%i`%

   LoopParse,`%functions`%,|

   {

      StrSplit,v,`%A_LoopField`%,:

      object[map="" ? v.1 ]:=DynaCall(MemoryGetProcAddress(dllmodule`%i`%,v.1),v.2)

   }

  obj`%i`%:=object

   dll`%i`%:=dll

   return &obj`%i`%

}

)"

  If !(dll){

    If !AHK_H {

         DllCall(_dll "\ahkFunction","Str","AhkDllThread","Str","","Str","","Str","","Str","","Str","","Str","","Str","","Str","","Str","","Str","","CDecl Str")

		 DllCall(_dll "\ahkTerminate")

		 DllCall("FreeLibrary","PTR",handleOfAhkdll)

		 handleOfAhkdll:="",_dll:=""

		 Return

      }

      Loop % i

      {

         idx:=A_Index

         %MemoryFreeLibrary%(dllmodule%A_Index%)

         obj%A_Index%:="",dll%A_Index%:="",dllmodule%A_Index%:=""

      }

      i:=0

      return

   } else if (!FileExist(dll) && !A_IsCompiled){

      MsgBox File: %dll%`ndoes not exist`, provide correct path for AutoHotkey.dll

      ExitApp

   }

   If !AHK_H {

      If (init || init := DllCall("LoadLibrary","Str",_dll := dll)){

         If DllCall(dll "\ahktextdll","Str",AhkDllThreadfunc,"Str","","Str","","Cdecl UInt")

            Return Object(0+DllCall(dll "\ahkFunction","Str","AhkDllThread","Str",dll,"Str","","Str","","Str","","Str","","Str","","Str","","Str","","Str","","Str","","CDecl Str"))

         else

            Return 0,ErrorLevel:="Could not load AutoHotkey.dll"

      } else {

         MsgBox Could not load %dll%

         Return 0

      }

   }

   i++

   dllmodule%i%:=A_IsCompiled ? %ResourceLoadLibrary%(dll) : %MemoryLoadLibrary%(dll)

   if IsObject(obj)

    object:=obj

   else

    object := Object()

  object[""]:=dllmodule%i%

   LoopParse,%functions%,|

   {

      StrSplit,v,%A_LoopField%,:

      object[map="" ? v.1 ]:=%DynaCall%(%MemoryGetProcAddress%(dllmodule%i%,v.1),v.2)

   }

  obj%i%:=object

   dll%i%:=dll

   return obj%i%

}


aSEioT
  • Members
  • 87 posts
  • Last active:
  • Joined: 31 Oct 2010
Thank you! it is working now! :lol:
I just realize we don't even need to manually "FreeLibrary" after terminate it. (Cause in your code, "handleOfAhkdll" is not setted at all.)
btw:
object[map="" ? v.1 ]v.1[/color]) ? v.1 : SubStr(map,InStr(map,v.1)+StrLen(v.1)+1,InStr(map,A_Space,0,InStr(map,v.1)))] :wink:
Thank you!

HotKeyIt
  • Moderators
  • 7439 posts
  • Last active: Jun 22 2016 09:14 PM
  • Joined: 18 Jun 2008
Thanks ;)

aSEioT
  • Members
  • 87 posts
  • Last active:
  • Joined: 31 Oct 2010
@HotKeyIt
could you tell me the different between ahkaddscript("some statements",1) and ahkexec("some statements"). How to choose correct one(performance etc).
thank you!

HotKeyIt
  • Moderators
  • 7439 posts
  • Last active: Jun 22 2016 09:14 PM
  • Joined: 18 Jun 2008
In terms of performance, if you will need to reuse the script then addScript is better choice.
ahkExec is just there to execude some code snipets and have more control over the dll script, the script will be deleted after run.

addFile also allows you to use ahkExecuteLine and it has more options than ahkExec.

aSEioT
  • Members
  • 87 posts
  • Last active:
  • Joined: 31 Oct 2010
what means it would be deleted later? It doesn't add to the script? So I can create some functions several times(cause it can not do normally).
btw: I can each call a function use "ahkfunction("funcName", params)" or just ahkexec("funcName(params)").

Just little mess!
(post by mobile phone)