First of all, thank you, thank you, thank you!
WS4AHK is the probably best thing to happen to AHK since the invention of sliced bread and DLLCALL...
I've been toying with ahk for 2 days and I asked myself, do we really need to use WS_Initialize() explicitly in AHK?
What if we incorporate it in the WS_Exec() function and do a little check if WS was already initialized, so that it won't reinitialize at encountering every WS_Exec(VBsnippet) in AHK ? After all a WS_Exec implies that you wan't to have a scripting host initialized, but you don't want to have it initialized over and over again...
Modified WS4AHKExec here:
Code:
WS_Exec(sCode)
{
if NOT WS_Initialized ; MODIFIED
WS_Initialize()
global __WS_iScriptControlObj__, __WS_iScriptErrorObj__
IfEqual __WS_iScriptControlObj__,
{
Msgbox % "Windows Scripting has not been initialized!`nExiting application."
ExitApp
}
; Run the code
Critical, On ; For thread safty
iErr := __WS_IScriptControl_ExecuteStatement(__WS_iScriptControlObj__, sCode)
If (iErr = "")
{
Critical, Off
; ErrorLevel has already been set to whatever error occured
Return False
}
Else
{
ErrLvl := ErrorLevel ; save ErrorLevel
blnIsErr := __WS_IsComError("IScriptControl::ExecuteStatement", iErr)
If (ErrorLevel = 0)
ErrorLevel := ErrLvl ; restore ErrorLevel
Else
ErrorLevel := ErrLvl "`n" ErrorLevel ; append ErrorLevel
If (blnIsErr)
{
; Probably an exception. Get the deatils.
; TODO: Find out what HRESULT code(s) mean there is an exception.
; FIXME: This call destroys whatever ErrorLevel is
__WS_HandleScriptError()
Critical, Off
Return False
}
Else ; success
{
Critical, Off
Return True
}
}
WS_Initialized := TRUE ; MODIFIED
}
This will do an implicit WS_Initialize at encountering your first WS_Exec
and remember that the WS was initialized..
Finally, WS_Initialized is reset when WS_Uninitialized is called:
Code:
WS_Uninitialize()
{
global __WS_iScriptControlObj__, __WS_iScriptErrorObj__
If __WS_iScriptErrorObj__ is Integer
If (__WS_iScriptErrorObj__ <> 0)
__WS_IUnknown_Release(__WS_iScriptErrorObj__)
If __WS_iScriptControlObj__ is Integer
If (__WS_iScriptControlObj__ <> 0)
__WS_IUnknown_Release(__WS_iScriptControlObj__)
ErrLvl := ErrorLevel ; save ErrorLevel
DllCall("ole32\CoUninitialize")
ErrorLevel := ErrLvl ; restore ErrorLevel
__WS_iScriptControlObj__ := ""
__WS_iScriptErrorObj__ := ""
WS_Initialized := FALSE ; MODIFIED
}
A bit quickndirty, but it seems to work...
I think your scriping client is such a valuable extension to AHK that it deserves to be incorporated as a function in AHK itselve, for instance as a block like:
Code:
Ahkvar = Hello World
[WSEXEC]
msgbox "%Ahkvar%"
[/WSEXEC]
Note that special care has to be taken by AHK to evaluate %Ahkvar% first before actually passing control to the scripting host, the current solution is to assign the vbscript to a ahkvariable first and then execute the ahkvariable:
Code:
Ws_Initialize()
Ahkvar = Hello World
vbscript =
(
msgbox "%Ahkvar%"
)
WS_Exec(vbscript)
It works, but a WS start/end block looks much cleaner and could potentially be
used as common placeholders for other future AHK scriptingclients for perl/python etc, like:
Code:
...ahkcode
...ahkcode
...some more
[PYTHON] ; Block of inline code, using HTML style
put your python code here....
some more...
[/PYTHON]
Anyway, I am really pleased with the way you extended the functionallity of AHK, here is a little testscript I made, demonstrating how WS4AHK can be a tool to prevent circular reference errors in excel when using iterations in cells.
Code:
A1 = 1 ; AHK Vars to be copied to Excel Cells
A2 = =A1*2
A3 = =A2*3
;
;
startexcel =
(
Dim Excel
Set Excel = CreateObject ("excel.application")
excel.visible = True
)
WS_Exec(startexcel)
;
;
AddWorkbookSheet =
(
Dim workbook
set workbook = excel.workbooks.add
Dim worksheet
set worksheet = excel.Sheets(1) 'The first worksheet
)
WS_Exec(AddWorkbookSheet)
;
;
;
CopyAHKvars2XL =
(
Worksheet.Cells(1, 1).Value = "%A1%"
Worksheet.Cells(2, 1).Value = "%A2%"
Worksheet.Cells(3, 1).Value = "%A3%"
)
WS_Exec(CopyAHKvars2XL)
;
;
;
; Do some math operations and have the cells outputresult returned to the cells input,
; (this would normally cause a circular reference error in Excel, but we can bypass it nicely by reading/writing from AHK using WS_Eval)
;
loop 10
{
WS_Eval(multiplier, "Worksheet.Cells(2, 1).Value")
pipe_output2input =
(
Worksheet.Cells(1, 1).Value = "%multiplier%"
)
WS_Exec(pipe_output2input)
sleep 500
}
WS_Uninitialize()
Note: There is no WS_Initialize in the script as it relies on the modiefied WS4AHK as posted above, you might want to add a WS_Initialize if running with the original WS4AHK.
Code: