1 (изменено: Dworkin, 2017-11-10 21:44:43)

Тема: AHK: работа с потоками autohotkey.dll

Добрый вечер. Помогите пожалуйста. Все никак не получается запустить несколько поток одновременно или почти одновременно.

Сам autohotkey.dll скачал отсюда:
https://raw.githubusercontent.com/HotKe … Hotkey.dll
Библиотеки отсюда:
https://github.com/HotKeyIt/ahkdll-v2-r … ported.ahk
https://github.com/zhamlin/Macro/blob/m … Thread.ahk

НО их я закинул в папку lib где установлен autohotkey иначе через #include почему-то не работает.


Если так то из-за подгрузки еще одного AutoHotkey.dll выдается ошибка.

#Persistent
#NoEnv

codefromvar1 =
(
#Persistent
CoordMode, ToolTip, Screen 
var := 1
msgbox, 1
Loop {
	sleep 100
	var++
	ToolTip, var, 1024, 768, 1 
}
)

codefromvar2 =
(
#Persistent
CoordMode, ToolTip, Screen 
var2 := 1
msgbox, 2
Loop {
	sleep 100
	var2++
	ToolTip, var2, 1024, 780, 2 
}
)

AhkThread1 := AhkDllThread("AutoHotkey.dll")
AhkThread1.ahktextdll(codefromvar1)
AhkThread2 := AhkDllThread("AutoHotkey.dll")
AhkThread2.ahktextdll(codefromvar2)
return

Если же скопирую и переименную на AutoHotkey2.dll то теперь почему то не работает второй поток

#Persistent
#NoEnv

codefromvar1 =
(
#Persistent
CoordMode, ToolTip, Screen 
var := 1
msgbox, 1
Loop {
	sleep 100
	var++
	ToolTip, var, 1024, 768, 1 
}
)

codefromvar2 =
(
#Persistent
CoordMode, ToolTip, Screen 
var2 := 1
msgbox, 2
Loop {
	sleep 100
	var2++
	ToolTip, var2, 1024, 780, 2 
}
)

AhkThread1 := AhkDllThread("AutoHotkey.dll")
AhkThread1.ahktextdll(codefromvar1)
AhkThread2 := AhkDllThread("AutoHotkey2.dll")
AhkThread2.ahktextdll(codefromvar2)
return

Скажите пожалуйста как правильно?

2

Re: AHK: работа с потоками autohotkey.dll

Удалось запустить одновременно два потока таким образом:

#Persistent
codefromvar1 =
(
#Persistent
CoordMode, ToolTip, Screen 
var := 1
msgbox, 1
Loop {
	sleep 100
	var++
	ToolTip, var, 1024, 768, 1 
}
)

codefromvar2 =
(
#Persistent
CoordMode, ToolTip, Screen 
var2 := 1
msgbox, 2
Loop {
	sleep 100
	var2++
	ToolTip, var2, 1024, 780, 2 
}
)

dllpath1 := "AutoHotkey.dll"
dllpath2 := "AutoHotkey2.dll"
DllCall("LoadLibrary","Str",dllpath1) ; Load the AutoHotkey module.
DllCall("LoadLibrary","Str",dllpath2) ; Load the AutoHotkey module.
DllCall(dllpath1 "\ahktextdll","Str",codefromvar1,"Str","","CDecl")
DllCall(dllpath2 "\ahktextdll","Str",codefromvar2,"Str","","CDecl")

но копировать каждый раз файл это время. Может есть другие идеи?

3 (изменено: YMP, 2017-11-11 12:03:39)

Re: AHK: работа с потоками autohotkey.dll

Вариант, указанный в справке, — это использование MemoryModule. Он позволяет загружать одну и ту же DLL несколько раз. Но в AutoHotkey.dll оно не встроено, насколько я понимаю, надо скачивать соответствующую DLL'ку.

Хотя ниже написано вот что:

Internally AutoHotkey.dll COM Interface always uses MemoryModule to create a new thread

Не ясно, в общем.

4

Re: AHK: работа с потоками autohotkey.dll

Dworkin пишет:

Может есть другие идеи?

Есть. Написать автору, почему его же код с последней длл выдаёт ошибку:

Loop 3
dll%A_Index%:=AhkDllThread(A_ScriptDir "\autohotkey.dll"),dll%A_Index%.ahkdll()

https://autohotkey.com/board/topic/5614 … hkexported

5 (изменено: Dworkin, 2017-11-12 04:47:15)

Re: AHK: работа с потоками autohotkey.dll

Решил проблему конфликта загрузки несколько раз одного autohotkey.dll.
Нашел пост где был обновленный AhkDllThread который работает с x64 и он использовал #include <_MemoryLibrary>.
Короче нужны еще 3 библиотеки _MemoryLibrary, _Struct, sizeof.

Распишу для всех.
Все это в папку lib где установлен autohotkey:
https://github.com/HotKeyIt/ahkdll-v1-r … ibrary.ahk
https://github.com/HotKeyIt/ahkdll-v1-r … Struct.ahk
https://github.com/HotKeyIt/ahkdll-v1-r … sizeof.ahk
https://github.com/HotKeyIt/ahkdll-v2-r … ported.ahk

Обновленый AhkDllThread.ahk тоже в папку lib. Если папки нет, создайте ее:


#include <_MemoryLibrary>
AhkDllThread_IsH(){ ; FileGetVersionInfo Written by SKAN modified by HotKeyIt www.autohotkey.com/forum/viewtopic.php?p=233188#233188
 Static HexVal:="msvcrt\s" (A_IsUnicode?"w":"") "printf",AHK:=A_AhkPath?A_AhkPath:A_ScriptFullPath
 If ((FSz:=DllCall("Version\GetFileVersionInfoSize","Str",AHK,"UInt",0)) && VarSetCapacity(FVI,FSz,0) && VarSetCapacity(Trans,8*(A_IsUnicode?2:1)))
  && DllCall("Version\GetFileVersionInfo","Str",AHK,"Int",0,"UInt",FSz,"PTR",&FVI) 
  && DllCall("Version\VerQueryValue","PTR",&FVI,"Str","\VarFileInfo\Translation","PTR*",Translation,"UInt",0)
  && DllCall(HexVal,"Str",Trans,"Str","`%08X","UInt",NumGet(Translation+0))
  && DllCall("Version\VerQueryValue","PTR",&FVI,"Str","\StringFileInfo\" SubStr(Trans,-3) SubStr(Trans,1,4) "\InternalName","PTR*",InfoPtr,"UInt",0)
    Return StrGet(InfoPtr+0,DllCall("lstrlen" (A_IsUnicode?"W":"A"),"PTR",InfoPtr)) = "AutoHotkey_H"
				|| StrGet(InfoPtr+0,DllCall("lstrlen" (A_IsUnicode?"W":"A"),"PTR",InfoPtr)) = " "
}
AhkDllThread(dll="AutoHotkey.dll",obj=0){
  static init,ahkfunction,hLib,dllptr,libScript,ahkexec,DynaCall:="DynaCall", MemoryLoadLibrary:="MemoryLoadLibrary",MemoryFreeLibrary:="MemoryFreeLibrary"
      ,ResourceLoadLibrary:="ResourceLoadLibrary", MemoryGetProcAddress:="MemoryGetProcAddress"
  static AHK_H:=AhkDllThread_IsH()
  static base:={__Delete:"AhkDllThread"}
  static functions :="
(Join
ahkFunction:s=ssssssssss|ahkPostFunction:i=ssssssssss|
ahkdll:ut=sss|ahktextdll:ut=sss|ahkReady:|ahkReload:i|
ahkTerminate:i|addFile:ut=sucuc|addScript:ut=si|ahkExec:ui=s|
ahkassign:ui=ss|ahkExecuteLine:ut=utuiui|ahkFindFunc:ut=s|
ahkFindLabel:ut=s|ahkgetvar:s=sui|ahkLabel:ui=sui|ahkPause:s|ahkIsUnicode:
)"
  static AhkDllThreadfunc :="
(Join`r`n
" (!A_IsCompiled ? "#include <_MemoryLibrary>" : "") "
#Persistent
SetBatchLines,-1
#NoTrayIcon
Return
AhkDllThreadDLL(dll=""AutoHotkey.dll"",obj=0){
  static functions := ""ahkFunction:s=ssssssssss|ahkPostFunction:i=ssssssssss|""
              . ""ahkdll:ut=sss|ahktextdll:ut=sss|ahkReady:|ahkReload:i|""
              . ""ahkTerminate:i|addFile:ut=sucuc|addScript:ut=si|ahkExec:ui=s|""
              . ""ahkassign:ui=ss|ahkExecuteLine:ut=utuiui|ahkFindFunc:ui=s|""
              . ""ahkFindLabel:ui=s|ahkgetvar:s=sui|ahkLabel:ui=sui|ahkPause:s""
  static object
  If (dll=""0""){
    object:=""""
    return
  } else If (!FileExist(dll) && obj=0){
    MsgBox File: `%dll`% does not exist`, provide correct path for AutoHotkey.dll
    ExitApp
  }
  object:={"""":new _MemoryLibrary(obj?obj:dll)}
  Loop,Parse,functions,|
  {
    StringSplit,v,A_LoopField,:
    object[map="""" ? v1 : !InStr(map,v1) ? v1 : SubStr(map,InStr(map,v1)+StrLen(v1)+1,InStr(map,A_Space,0,InStr(map,v1)))]:=DynaCall(object[""""].GetProcAddress(v1),v2)
  }
  object.base:=Object(" (&base) ")
  return &object
}
)"
  If IsObject(dll){
    dll.ahkterminate()
    If !AHK_H {
      dll[""].Free(),dll:=""
    } else %MemoryFreeLibrary%(dll[""])
    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 || ((hLib:=new _MemoryLibrary(A_IsCompiled?(dllptr:=DllCall("LockResource","ptr",DllCall("LoadResource","ptr",lib,"ptr",DllCall("FindResource","ptr",lib:=DllCall("GetModuleHandle","ptr",0,"ptr"),"str",dll,"ptr",10,"ptr"),"ptr"),"ptr")):dll)) && (Init:=hLib.GetProcAddress("ahktextdll")) && (!A_IsCompiled||LibScript:=(!(res:=DllCall("FindResource","ptr",lib:=DllCall("GetModuleHandle","ptr",0,"ptr"),"str",">AUTOHOTKEY SCRIPT<","ptr",10,"ptr"))?(res:=DllCall("FindResource","ptr",lib,"str",">AHK WITH ICON<","ptr",10,"ptr")):res)?StrGet(DllCall("LockResource","ptr",DllCall("LoadResource","ptr",lib,"ptr",res,"ptr"),"ptr"),DllCall("SizeofResource","ptr",lib,"ptr",res,"uint"),"UTF-8"):""))){
      If (ahkfunction || (DllCall(init,"Str",AhkDllThreadfunc "`n" LibScript,"Str","","Str","","Cdecl UInt") && (ahkfunction:=hLib.GetProcAddress("ahkFunction")) && (ahkExec:=hLib.GetProcAddress("ahkExec")))){
        return Object(0+DllCall(ahkfunction,"Str","AhkDllThreadDLL","Str",dll,"Str",A_IsCompiled?dllptr:"","Str","","Str","","Str","","Str","","Str","","Str","","Str","","Str","","CDecl Str"))
        ;reset internal return memory in autoHotkey.dll and release object
        ,DllCall(ahkfunction,"Str","AhkDllThreadDLL","Str","0","Str","","Str","","Str","","Str","","Str","","Str","","Str","","Str","","Str","","CDecl Str")
      } else {
        MsgBox Could not load script in %dll%
        Return 0
      }
    } else {
      MsgBox Could not load %dll%
      Return 0
    }
  }
  object:=IsObject(obj)?obj:{},object[""]:= A_IsCompiled ? %ResourceLoadLibrary%(dll) : %MemoryLoadLibrary%(dll)
  Loop,Parse,functions,|
  {
    StringSplit,v,A_LoopField,:
    object[map="" ? v1 : !InStr(map,v1) ? v1 : SubStr(map,InStr(map,v1)+StrLen(v1)+1,InStr(map,A_Space,0,InStr(map,v1)))]:=%DynaCall%(%MemoryGetProcAddress%(object[""],v1),v2)
  }
  return object,object.base:=base
}

И autohotkey.dll:
https://raw.githubusercontent.com/HotKe … Hotkey.dll

Очень важно! Что бы скомпилированный скрипт заработал надо:

FileInstall, AutoHotkey.dll,AutoHotkey.dll

И тогда этот код работает:

#Persistent
#NoEnv

codefromvar1 =
(
#Persistent
CoordMode, ToolTip, Screen 
var := 1
msgbox, 1
Loop {
	sleep 100
	var++
	ToolTip, var, 1024, 768, 1 
}
)

codefromvar2 =
(
#Persistent
CoordMode, ToolTip, Screen 
var2 := 1
msgbox, 2
Loop {
	sleep 100
	var2++
	ToolTip, var2, 1024, 780, 2 
}
)

AhkThread1 := AhkDllThread("AutoHotkey.dll")
AhkThread1.ahktextdll(codefromvar1)
AhkThread2 := AhkDllThread("AutoHotkey.dll")
AhkThread2.ahktextdll(codefromvar2)
return

6 (изменено: svoboden, 2017-11-12 04:05:25)

Re: AHK: работа с потоками autohotkey.dll

А для чего эти два потока надо. Разве от многопоточности ума больше прибавится или в этом есть какая-то польза?

7

Re: AHK: работа с потоками autohotkey.dll

svoboden пишет:

А для чего эти два потока надо. Разве от многопоточности ума больше прибавится или в этом есть какая-то польза?

Можно использовать функцию закачки и она не будет тормозить выполнение кода.
Например у меня скрипт обращается на сервер и пока ждет ответа, тупо висит. А с многоопытностью я могу посылать запросы на сервер подряд.

8 (изменено: KusochekDobra, 2017-11-12 04:28:20)

Re: AHK: работа с потоками autohotkey.dll

А как например, закрыть поток, или обменяться данными? И где у Вас в основном примере, код получает доступ к папке "Lib", ведь нет ни одного инклуда? Или это какая-то хитрая сборка Autohotkey?

9 (изменено: Dworkin, 2017-11-12 04:35:40)

Re: AHK: работа с потоками autohotkey.dll

KusochekDobra пишет:

А как например, закрыть поток? И где у Вас в основном примере, код получает доступ к папке "Lib", ведь нет ни одного инклуда?

Поток сам завершится после отработки кода, но есть свои нюансы.
Например


#Persistent
#NoEnv

codefromvar1 =
(
#Persistent
CoordMode, ToolTip, Screen 
var := 1
msgbox, 1
Loop 5 {
	sleep 1000
	var++
	ToolTip, var, 1024, 768, 1 
}

)

codefromvar2 =
(

CoordMode, ToolTip, Screen 
var2 := 1
msgbox, 2
Loop 5 {
	sleep 1000
	var2++
	ToolTip, var2, 1024, 780, 2 
}

)

AhkThread1 := AhkDllThread("AutoHotkey.dll")
AhkThread1.ahktextdll(codefromvar1)
AhkThread2 := AhkDllThread("AutoHotkey.dll")
AhkThread2.ahktextdll(codefromvar2)
return

Первый поток после отработки останется висеть так как #Persistent, а второй завершится. Либо если в коде потока есть #Persistent, вы можете после отработки кода написать exitapp.

codefromvar1 =
(
#Persistent
CoordMode, ToolTip, Screen 
var := 1
msgbox, 1
Loop 5 {
	sleep 1000
	var++
	ToolTip, var, 1024, 768, 1 
}
exitapp
)

тогда первый поток тоже завершится.

Создаете папку lib куда установлен autohotkey, закидываете туда инклуды(библиотеки) и autohotkey их автоматом использует. А файл autohotkey.dll я папку где скрипт или указываете путь.
А вот как обмениваться данными я не знаю. Знаю что например функции создания общей переменной или объекта для всех потоков и основного скрипта в ahk_l нет, но есть в ahk_h

10 (изменено: Malcev, 2017-11-12 06:10:23)

Re: AHK: работа с потоками autohotkey.dll

Dworkin пишет:

Можно использовать функцию закачки и она не будет тормозить выполнение кода.
Например у меня скрипт обращается на сервер и пока ждет ответа, тупо висит. А с многоопытностью я могу посылать запросы на сервер подряд.

1) А почему не посылаете запросы асинхронно?
2) Зачем мучиться с многопоточностью, если можно создать несколько скриптов и между ними обениваться полученной информацией.

11 (изменено: Dworkin, 2017-11-12 06:14:22)

Re: AHK: работа с потоками autohotkey.dll

Malcev пишет:

1) А почему не посылаете запросы асинхронно?
2) Зачем мучиться с многопоточностью, если можно создать несколько скриптов и между ними обмениваться полученной информацией.

Потому что я об этом не знал)) Можете пожалуйста показать пример посылки нескольких пост запросов?
Многопоточность интересна, может еще понадобиться)

12

Re: AHK: работа с потоками autohotkey.dll

https://autohotkey.com/docs/commands/UR … ToFile.htm
Когда мне понадобилась многопоточность я пробовал использовать autohotkey.dll, но мне показалось это неудобным.
В итоге с помощью teadrinkera создал следящий скрипт и кучу дочерних, которые передают информацию следящему.
http://forum.script-coding.com/viewtopic.php?id=10765

KusochekDobra пишет:

И где у Вас в основном примере, код получает доступ к папке "Lib", ведь нет ни одного инклуда?

Если скрипт находится в папке Lib с таким же названием, что и функция, то инклуд не нужен.

13 (изменено: Dworkin, 2017-11-12 07:10:32)

Re: AHK: работа с потоками autohotkey.dll

Malcev пишет:

Когда мне понадобилась многопоточность я пробовал использовать autohotkey.dll, но мне показалось это неудобным.

Если вы пробывали многопоточность может у вас есть такие фукнции для AHK_L?
objShare
CriticalObject
CriticalSection
Может есть LowLevel.ahk? А то тот что я нашел почему-то крашит.

14

Re: AHK: работа с потоками autohotkey.dll

Не, так далеко я не заходил.

15

Re: AHK: работа с потоками autohotkey.dll

Поскольку тут для каждого потока загружается отдельный экземпляр интерпретатора, то экономия ресурсов по сравнению с запуском отдельных процессов сомнительна. А необходимость кучи дополнительных библиотек, морока с их версиями и т.д. и вовсе сводит привлекательность этого пути к нулю.

Выгода процессов ещё в том, что крах одного не влечёт за собой крах других, а в случае с потоками достаточно одному навернуться и весь процесс накроется.

16 (изменено: Dworkin, 2017-11-12 18:04:25)

Re: AHK: работа с потоками autohotkey.dll

YMP пишет:

морока с их версиями и т.д

Этим я уже заморочился и все что надо выложил сюда

Вот нашел функцию ObjShare.
https://hotkeyit.github.io/v2/docs/comm … jShare.htm

Пример:

LresultFromObject(obj){
	static IDispatch
	, set := VarSetCapacity(IDispatch, 16)
	, init := NumPut(0x46000000000000c0, NumPut(0x20400, IDispatch, "int64"), "int64")
	
	return DllCall("Oleacc.dll\LresultFromObject", ptr,&IDispatch, ptr,0, ptr,&obj, ptr)
}

global var := 0
class Test{
	Call(var){
		var++
		tooltip % var
	}
}

obj := new Test
lresult := LresultFromObject(obj)
threadCode =
(
	ObjectFromLresult(lresult){
		static IDispatch
		, set := VarSetCapacity(IDispatch, 16)
		, init := NumPut(0x46000000000000c0, NumPut(0x20400, IDispatch, "int64"), "int64")
		
		if DllCall("Oleacc.dll\ObjectFromLresult", ptr,lresult, ptr,&IDispatch, ptr,0, ptr,getvar(com:=0))
			throw "LResult Object could not be created"
		return ComObject(9,com,1)
	}

	obj := ObjectFromLresult(%lresult%)
	loop 5 {
		obj.call(A_Index)
		sleep 1000
	}
	msgbox, end thread.
	exitapp
)

ahkDll := "AutoHotkey.dll"
DllCall("LoadLibrary", str,ahkDll)
DllCall(ahkDll "\ahktextdll", str,threadCode, str,"", "CDecl")
sleep 7000
obj.call(999)

17

Re: AHK: работа с потоками autohotkey.dll

Вообще, странная тема про эти потоки. Не показан пример, для чего оно надо и т.д.

18

Re: AHK: работа с потоками autohotkey.dll

Так а разве вам не ответили в 7 посте?

19 (изменено: svoboden, 2017-11-15 21:08:07)

Re: AHK: работа с потоками autohotkey.dll

Ответили, но тс говорил про какую-то многоопытность.

20

Re: AHK: работа с потоками autohotkey.dll

Думаю, имелось в виду многопоточность.