Page 1 of 1

[H2] AhkRun() 加载动态代码

Posted: 23 Feb 2016, 06:05
by arcticir
解决了很多问题,重启和传递对象作为参数等等.



增加的全局变量:
h_history 即使重启也不会损毁的记录对象
h_Caller 调用者的名字
h_CallerPid
h_CallerId
h_CallerHwnd

Code: Select all

f:=[]
loop 100
s.="asdfsafsafsafsafsafasfsaf"

loop 1000
f.Push(l:=[s])

AhkRun("ObjTree(h_history)`nMsgBox `% `"Reload `" `nReload()",,[f,f,f])

Code: Select all

AhkRun(Script,Title:="",Args:="",Tray:="",Path:=""){
	static fox:=[]
	if Type(Script)="Integer"
	Return c:=Struct("ULONG_PTR dwData,DWORD cbData,PVOID lpData"),Script=1
		?(c[]:=Title,VarSetCapacity(h_history,c.cbData),DllCall("RtlMoveMemory",PTR,&h_history,PTR,c.lpData,PTR,c.cbData),Struct(_AHKVar := "{Int64 ContentsInt64,Double ContentsDouble,PTR object},{char *mByteContents,LPTSTR CharContents},{UINT_PTR Length,_AHKVar *AliasFor},{UINT_PTR Capacity,UINT_PTR BIV},BYTE HowAllocated,BYTE Attrib,BYTE IsLocal,BYTE Type,LPTSTR Name",getvar(h_history),{Attrib:1,Length:c.cbData}),h_history:=ObjLoad(&h_history), h_history.A_Args?A_Args:=h_history.A_Args:0)
		:(c.lpData:=fox.GetAddress(Script),c.cbData:=fox.GetCapacity(Script),SendMessage_(StrGet(NumGet(Title + 2*A_PtrSize)),0x4a,1,c[]),OnMessage(0x4a,A_ScriptHwnd,"AhkRun",0),fox.Delete(Script)),0

	Thread:=IsObject(Script)?Script:{Script:Script},Args?Thread.A_Args:=IsObject(Args)?Args:[Args]:""
		,IsObject(Script)?Thread.Reload?Thread.Reload++:Thread.Reload:=1:"",Thread.Tick:=A_TickCount


        if (-1=p1:=DllCall("CreateNamedPipe","str",Pipe:="\\.\pipe\" (Title=""?Thread.name?Thread.name:"AHK - ":Thread.name:=Title) "(" A_TickCount ")","uint",2,"uint",0,"uint",255,"uint",0,"uint",0,"Ptr",0,"Ptr",0))
                or (-1=p2:=DllCall("CreateNamedPipe","str",Pipe,"uint",2,"uint",0,"uint",255,"uint",0,"uint",0,"Ptr",0,"Ptr",0))
        Return 0
        Run, % (Path?Path:A_AhkPath) " `"" Pipe "`"" ,,UseErrorLevel HIDE,P

        If ErrorLevel
                return DllCall("CloseHandle","Ptr",p1),DllCall("CloseHandle","Ptr",p2),0

	Script:=chr(0xfeff) "#Include <ScriptStruct>`nGlobal h_Caller,h_CallerPid,h_CallerId,h_CallerHwnd,h_history`nAhkRun__Global(w:=`"`",l:=`"`"){`nstatic A__ScriptDir := `"" A_ScriptDir "`",r:=AhkRun__Global()`n"
        . (Tray?"":"#NoTrayIcon") "`nSetWorkingDir," A_WorkingDir "`nScriptStruct().mFileDir[`"`"] := &A__ScriptDir"
        . "`nh_Caller:=`"" A_ScriptName "`",h_CallerPid:=" (Thread.Reload?h_CallerPid:ProcessExist()) ",h_CallerHwnd:=" A_ScriptHwnd ",h_CallerId:=`"" h_id "`""
        . ",VarSetCapacity(Struct, 3*A_PtrSize, 0),NumPut((StrLen(Hwnd:=A_ScriptHwnd) + 1) * 2, Struct, A_PtrSize),NumPut(&Hwnd, Struct, 2*A_PtrSize),onmessage(0x4a,A_ScriptHwnd,`"AhkRun`",-1)"
        . ",SendMessage_(" A_ScriptHwnd ",0x4a," P ",&Struct)`nonmessage(0x4a,A_ScriptHwnd,`"AhkRun`",0)`n}`nReload(){`nAhkRun(h_history)`nExitApp`n}`n" Thread.Script
	,len:=ObjDump(Thread,data2)
	,DllCall("ConnectNamedPipe","Ptr",p1,"Ptr",0),DllCall("CloseHandle","Ptr",p1),DllCall("ConnectNamedPipe","Ptr",p2,"Ptr",0)
	if s:=DllCall("WriteFile","Ptr",p2,"Wstr",Script,"UInt",StrLen(Script)*2+4,"uint*",0,"Ptr",0)
	{
		fox.SetCapacity(P,len),RtlMoveMemory(fox.GetAddress(P),&data2,len)
		,OnMessage(0x4a,A_ScriptHwnd,"AhkRun",-1),DllCall("CloseHandle","Ptr",p2),t:=A_TickCount
		Sleep, 30
		while fox.HasKey(P) and ((A_TickCount-t)<10000)
			Sleep, -1
		if fox.HasKey(P)
		OnMessage(0x4a,A_ScriptHwnd,"AhkRun",0),fox.Delete(P)
	}
	Return s?P:(DllCall("CloseHandle","Ptr",p2),0)
}



记略:

Pipe的管道名称会触发#Singleinstance的作用机制,即使使用了#Singleinstance OFF, 存在重名时加载新进程也会多使用一倍的时间.
所以直接在名字后面加上 A_TickCount 变量,以杜绝重名.

使用了大量H2的内置函数,故代码较简单. 大部分代码来自 HotKeyIt.