Changes in V9:
1. Added builtin FindFunc()
2. updated addfile(), so when called with 2 as the 3rd parameter.
For ex. addfile("somefile.ahk", 1, 2)
simpleheap memory used by late included files upto this point is freed. Hotkeys, labels, and functions from the first call to addfile are retained.
If you want to create hotkeys in later include files that have already been defined, use a dynamic function call with the Hotkey command:
Hotkey, label, hotkey
2a: I ran a stress test loading 2 client scripts alternately 2000 times, and the total memory usage only increased by 200kb, compared to 2 megabytes with the older version.
2b: This allows me to experiment more seriously with an ahk webserver / app server that can run short independent scripts without launching a separate process.
For example, hosting AutoHotkey.dll in modpython for apache:
Code:
import os, time
from mod_python import apache
from ctypes import *
ahk = cdll.LoadLibrary("AutoHotkey.dll")
ahk.ahkdll(create_string_buffer("..\\htdocs\\test\\pyclient.ahk"), "", "")
def handler(req):
req.content_type = 'text/plain'
req.write("Hello World2!")
return apache.OK
FindFunc code:
Code:
EXPORT unsigned int ahkFindFunc(char *funcname)
{
return (unsigned int)g_script.FindFunc(funcname);
}
void BIF_FindFunc(ExprTokenType &aResultToken, ExprTokenType *aParam[], int aParamCount) // Added in Nv8.
{
// Set default return value in case of early return.
aResultToken.symbol = SYM_INTEGER ;
aResultToken.marker = "";
// Get the first arg, which is the string used as the source of the extraction. Call it "findfunc" for clarity.
char funcname_buf[MAX_NUMBER_SIZE]; // A separate buf because aResultToken.buf is sometimes used to store the result.
char *funcname = TokenToString(*aParam[0], funcname_buf); // Remember that aResultToken.buf is part of a union, though in this case there's no danger of overwriting it since our result will always be of STRING type (not int or float).
int funcname_length = (int)EXPR_TOKEN_LENGTH(aParam[0], funcname);
aResultToken.value_int64 = (__int64)ahkFindFunc(funcname);
return;
}
updated addfile code:
Code:
EXPORT unsigned int addFile(char *fileName, bool aAllowDuplicateInclude, int aIgnoreLoadFailure)
{ // dynamically include a file into a script !!
// labels, hotkeys, functions.
static int filesAdded = 0 ;
Line *oldLastLine = g_script.mLastLine;
if (aIgnoreLoadFailure > 1) // if third param is > 1, reset all functions, labels, remove hotkeys
{
g_script.mFuncCount = 0;
g_script.mFirstLabel = NULL ;
g_script.mLastLabel = NULL ;
g_script.mLastFunc = NULL ;
g_script.mFirstLine = NULL ;
g_script.mLastLine = NULL ;
g_script.mCurrLine = NULL ;
if (filesAdded == 0)
{
SimpleHeap::sBlockCount = 0 ;
SimpleHeap::sFirst = NULL;
SimpleHeap::sLast = NULL;
SimpleHeap::sMostRecentlyAllocated = NULL;
}
if (filesAdded > 0)
{
// Naveen v9 free simpleheap memory for late include files
SimpleHeap *next, *curr;
for (curr = SimpleHeap::sFirst; curr != NULL;)
{
next = curr->mNextBlock; // Save this member's value prior to deleting the object.
curr->~SimpleHeap() ;
curr = next;
}
SimpleHeap::sBlockCount = 0 ;
SimpleHeap::sFirst = NULL;
SimpleHeap::sLast = NULL;
SimpleHeap::sMostRecentlyAllocated = NULL;
/* Naveen: the following is causing a memory leak in the exe version of clearing the simple heap v10
g_script.mVar = NULL ;
g_script.mVarCount = 0 ;
g_script.mVarCountMax = 0 ;
g_script.mLazyVar = NULL ;
g_script.mLazyVarCount = 0 ;
*/
}
g_script.LoadIncludedFile(fileName, aAllowDuplicateInclude, (bool) aIgnoreLoadFailure);
g_script.PreparseBlocks(g_script.mFirstLine); //
// g_script.mFirstLine->ExecUntil(UNTIL_RETURN); // Might never return (e.g. infinite loop or ExitApp).
filesAdded += 1;
}
else
{
g_script.LoadIncludedFile(fileName, aAllowDuplicateInclude, (bool) aIgnoreLoadFailure);
g_script.PreparseBlocks(oldLastLine->mNextLine); //
}
return (unsigned int) oldLastLine->mNextLine; //
}
testscripts: hostscript
Code:
start:
ahkdll := DllCall("LoadLibrary", "str", A_ScriptDir . "\AutoHotkey.dll")
sleep, 500
threadH := DllCall(A_ScriptDir . "\AutoHotkey.dll\ahkdll", "str", "cleanhostdll.ahk", "str"
, "", "str", "parameter1 parameter2", "Cdecl Int")
DllCall(A_ScriptDir . "\AutoHotkey.dll\addFile", "str", "clean.ahk", "uchar", 1
,"uchar" , 2, "Cdecl UInt")
msgbox hostcleanexe
gosub stress
return
stress:
loop, 2
{
loop, 1000
{
DllCall(A_ScriptDir . "\AutoHotkey.dll\addFile", "str", "clean.ahk", "uchar", 1
,"uchar" , 2, "Cdecl UInt")
DllCall(A_ScriptDir . "\AutoHotkey.dll\addFile", "str", "clean2.ahk", "uchar", 1
,"uchar" , 2, "Cdecl UInt")
}
msgbox 1000
}
return
F3::
DllCall(A_ScriptDir . "\AutoHotkey.dll\addFile", "str", "clean.ahk", "uchar", 1
,"uchar" , 2, "Cdecl UInt")
msgbox hostcleanexe clean
return
F4::
DllCall(A_ScriptDir . "\AutoHotkey.dll\addFile", "str", "clean2.ahk", "uchar", 1
,"uchar" , 2, "Cdecl UInt")
msgbox hostcleanexe clean2
return
!r::
Reload
!q::
ExitApp
client scripts:
Code:
#Persistent
return
file1:
x := "second"
x = test
x = another
return
fxclean()
{
msgbox clean
x = 3
}
2nd client script
Code:
#Persistent
return
file1:
x := "second"
x = test
x = another
return
fxclean2()
{
msgbox clean2
x = 3
}