eimhym Posted September 22, 2013 Share Posted September 22, 2013 (edited) Since IE9, Microsoft use new JScript engine which powering HTML5 content - JScript9 aka Chakra that is ECMA-262 5th edition compliant and also JIT-ed! Alas, they decide that the powerfull engine to be unreachable through ScriptControl. Though some hacks can re-enable this engine, there's more elegant way - The amazing AutoItObject to the rescue! expandcollapse popup#include "AutoItObject.au3" _AutoItObject_Startup() $sCLSID_ScriptEngine = "{16D51579-A30B-4C8B-A276-0FF4DC41E755}" ; JScript9 'Chakra' CLSID ; $sCLSID_ScriptEngine = "{F414C260-6AC0-11CF-B6D1-00AA00BBBB58}" ; Old JScript CLSID Global $engine_path ; ; You may specify the DLL path to make it run in portable way! $engine_path = @ScriptDir & "\JScript9.DLL" ; $engine_path = @ScriptDir & "\JScript.DLL" ; Old JScript ; Initialization Script, for other script engine like VBScript or LuaScript the init script would be different. $sInitScript = "AutoIt.SetRootObject(this);function Hello(){AutoIt.MsgBox(0, 'Script Says:', 'Hello World!'); return 'You are running ' + ScriptEngine() + ' ' + [ScriptEngineMajorVersion(), ScriptEngineMinorVersion(), ScriptEngineBuildVersion()].join('.')}" Func GoNuts ( ) ; Execute script's function and fetch return value MsgBox(0, "Script Return Value:", $_Script.Hello()) ; Add new function $_Script.eval("function add(x, y){return x+y}") MsgBox(0, "Script function call", "Awesome," & @CRLF & @CRLF & "1 + 2 = " & $_Script.add(1, 2) & " !") ; etc ... Have Fun! EndFunc #Region >>> ActiveScript Constants Global Const _ ; IActiveScript $sIID_IActiveScript = "{BB1A2AE1-A4F9-11CF-8F20-00805F2CD064}", _ $tagIActiveScript = "QueryInterface hresult(ptr;ptr*);" & _ "AddRef ulong();" & _ "Release ulong();" & _ "SetScriptSite hresult(ptr);" & _ "GetScriptSite hresult(ptr;ptr*);" & _ "SetScriptState hresult(dword);" & _ "GetScriptState hresult(dword*);" & _ "Close hresult();" & _ "AddNamedItem hresult(wstr;dword);" & _ "AddTypeLib hresult(ptr;dword;dword;dword);" & _ "GetScriptDispatch hresult(wstr;ptr);" & _ "GetCurrentScriptThreadID hresult(dword*);" & _ "GetScriptThreadID hresult(dword;dword*);" & _ "GetScriptThreadState hresult(dword;dword*);" & _ "InterruptScriptThread hresult(dword;ptr;dword);" & _ "Clone hresult(int);" ; Credits to trancexx If @AutoItX64 Then ; IActiveScriptParse Global Const $sIID_IActiveScriptParse = "{C7EF7658-E1EE-480E-97EA-D52CB4D76D17}" Else ; 32 bit Global Const $sIID_IActiveScriptParse = "{BB1A2AE2-A4F9-11CF-8F20-00805F2CD064}" EndIf Global Const _ $tIID_IActiveScriptParse = _AutoItObject_CLSIDFromString($sIID_IActiveScriptParse), _ $tagActiveScriptParse = "QueryInterface hresult(ptr;ptr*);" & _ "AddRef ulong();" & _ "Release ulong();" & _ "InitNew long();" & _ "AddScriptlet long(wstr;wstr;wstr;wstr;wstr;wstr;dword*;ulong;dword;ptr;ptr);" & _ "ParseScriptText long(wstr;ptr;ptr;ptr;dword*;ulong;dword;ptr;ptr);" ; NOTE: ; The ptr in ParseScriptText (pstrItemName, pstrDelimiter) is used ; instead of wstr because there's no other way to pass NULL parameter. ; Change it back to wstr if you ever need to pass string. Global Const _ ; IActiveScriptSite $sIID_IActiveScriptSite = "{DB01A1E3-A42B-11CF-8F20-00805F2CD064}", _ $tagActiveScriptSite = "QueryInterface hresult(ptr;ptr*);" & _ "AddRef ulong();" & _ "Release ulong();" & _ "GetLCID hresult(dword*);" & _ "GetItemInfo hresult(wstr;dword;ptr;ptr);" & _ "GetDocVersionString hresult(ptr);" & _ "OnScriptTerminate hresult(ptr;ptr);" & _ "OnStateChange hresult(uint);" & _ "OnScriptError hresult(ptr);" & _ "OnEnterScript hresult();" & _ "OnLeaveScript hresult();" Global Const _ ; IActiveScriptError $sIID_IActiveScriptError = "{EAE1BA61-A4ED-11CF-8F20-00805F2CD064}", _ $tagActiveScriptError = "QueryInterface hresult(ptr;ptr*);" & _ "AddRef ulong();" & _ "Release ulong();" & _ "GetExceptionInfo hresult(ptr);" & _ "GetSourcePosition hresult(ptr;ptr;ptr);" & _ "GetSourceLineText hresult(ptr);", _ $tagEXCEPINFO = "word wCode;" & _ "word wReserved;" & _ "ptr bstrSource;" & _ "ptr bstrDescription;" & _ "ptr bstrHelpFile;" & _ "dword dwHelpContext;" & _ "ptr pvReserved;" & _ "ptr pfnDeferredFillIn;" & _ "long scode;" Enum _ ; SCRIPTSTATE $SCRIPTSTATE_UNINITIALIZED, _ $SCRIPTSTATE_STARTED, _ $SCRIPTSTATE_CONNECTED, _ $SCRIPTSTATE_DISCONNECTED, _ $SCRIPTSTATE_CLOSED, _ $SCRIPTSTATE_INITIALIZED Global Const _ ; SCRIPTITEM $SCRIPTITEM_ISVISIBLE = 0x00000002, _ $SCRIPTITEM_ISSOURCE = 0x00000004, _ $SCRIPTITEM_GLOBALMEMBERS = 0x00000008, _ $SCRIPTITEM_ISPERSISTENT = 0x00000040, _ $SCRIPTITEM_CODEONLY = 0x00000200, _ $SCRIPTITEM_NOCODE = 0x00000400, _ $SCRIPTITEM_ALL = BitOR( $SCRIPTITEM_ISSOURCE, $SCRIPTITEM_ISVISIBLE, $SCRIPTITEM_ISPERSISTENT, $SCRIPTITEM_GLOBALMEMBERS, $SCRIPTITEM_NOCODE, $SCRIPTITEM_CODEONLY ) #EndRegion <<< ActiveScript Constants #Region >>> Scriptable Object Global $_AutoIt = _AutoItObject_Create() Global $pAutoIt = _AutoItObject_IDispatchToPtr($_AutoIt) ; see GetItemInfo handler Global $_Script ; will hold ScriptEngine's root object, where we can access script's global function _AutoItObject_AddMethod($_AutoIt, "SetRootObject", "_AutoIt_SetRootObject") _AutoItObject_AddMethod($_AutoIt, "MsgBox", "_AutoIt_MsgBox") Func _AutoIt_SetRootObject ( $_Self, $_Root ) Dim $_Script = $_Root ; the legit way is through IDispatchEx, but oh well EndFunc ;==> _AutoIt_SetRootObject Func _AutoIt_MsgBox ( $_Self, $iFlags, $sTitle, $sMessage ) Return MsgBox($iFlags, $sTitle, $sMessage) EndFunc ;==> _AutoIt_MsgBox #EndRegion <<< Scriptable Object ; Look in registry if file not found If NOT FileExists($engine_path) Then $engine_path = RegRead("HKCR\CLSID\" & $sCLSID_ScriptEngine & "\InprocServer32", "") If NOT FileExists($engine_path) Then Exit 1 ; Engine's DLL not found EndIf ; Boilerplate Global $_ActiveScript = _AutoItObject_ObjCreateEx($engine_path, $sCLSID_ScriptEngine, $sIID_IActiveScript, $tagIActiveScript, False) If NOT IsObj($_ActiveScript) Then Exit 2 ; Could not instantiate engine, wrong CLSID ? _AutoItObject_IUnknownAddRef($_ActiveScript) $aCall = $_ActiveScript.QueryInterface(DllStructGetPtr($tIID_IActiveScriptParse), 0) Global $_ActiveScriptParse = _AutoItObject_WrapperCreate($aCall[2], $tagActiveScriptParse) If NOT IsObj($_ActiveScriptParse) Then Exit 3 ; Could not acquire ActiveScriptParse, check for 32/64 IID Global $_ActiveScriptSite = _AutoItObject_ObjectFromDtag("_ASS_", $tagActiveScriptSite) If @error Then Exit 4 ; Failed implementing ActiveScriptSite $_ActiveScript.SetScriptSite(Number($_ActiveScriptSite.__ptr__)) $_ActiveScript.AddNamedItem("AutoIt", BitOR($SCRIPTITEM_ISVISIBLE, $SCRIPTITEM_NOCODE)) Global $fScriptInitialized = 0 $_ActiveScriptParse.InitNew() $tActiveScriptParseError = DllStructCreate ($tagEXCEPINFO) $_ActiveScriptParse.ParseScriptText($sInitScript, 0, 0, 0, 0, 0, 0, 0, DllStructGetPtr($tActiveScriptParseError)) $_ActiveScript.SetScriptState($SCRIPTSTATE_CONNECTED) OnAutoItExitRegister("Cleanup") If NOT IsObj($_Script) Then Exit 5 ; Initialization script error GoNuts() Func Cleanup ( ) $_Script = 0 $_ActiveScript.Close() _AutoItObject_IUnknownRelease($_ActiveScript) $_ActiveScriptParse = 0 $_ActiveScript = 0 $_ActiveScriptSite = 0 EndFunc ;==> Cleanup #Region >>> ActiveScriptSite Implementation Func _ASS_QueryInterface ( $_Self, $pRIID, $pObj ) #forceref $_Self, $pRIID, $pObj _Trace("_ASS_QueryInterface") Return 0x80004002 ; E_NOINTERFACE EndFunc ;==> _ASS_QueryInterface Func _ASS_AddRef ( $_Self ) #forceref $_Self Return 1 EndFunc ;==> _ASS_AddRef Func _ASS_Release ( $_Self ) #forceref $_Self Return 1 EndFunc ;==> _ASS_Release Func _ASS_GetLCID ( $_Self, $iLCID ) #forceref $_Self $iLCID = 0x0400 ; LOCALE_USER_DEFAULT _Trace(StringFormat( '_ASS_GetLCID: 0x%X', $iLCID )) Return 0 ; S_OK EndFunc ;==> _ASS_GetLCID Func _ASS_GetItemInfo ( $_Self, $sName, $iMask, $pObj, $pTypeInfo ) #forceref $_Self, $pObj, $pTypeInfo Static Local _ $SCRIPTINFO_IUNKNOWN = 1, _ $SCRIPTINFO_ITYPEINFO = 2 _Trace(StringFormat( '_ASS_GetItemInfo: %s', $sName )) If $sName = "AutoIt" AND BitAND($iMask, $SCRIPTINFO_IUNKNOWN) Then _AutoItObject_IUnknownAddRef($pAutoIt) DllStructSetData(DllStructCreate("ptr", $pObj), 1, $pAutoIt) Return 0 ; S_OK EndIf If BitAND($iMask, $SCRIPTINFO_IUNKNOWN) Then DllStructSetData(DllStructCreate("ptr", $pObj), 1, 0) If BitAND($iMask, $SCRIPTINFO_ITYPEINFO) Then DllStructSetData(DllStructCreate("ptr", $pTypeInfo), 1, 0) Return 0x80004005 ; E_FAIL EndFunc ;==> _ASS_GetItemInfo Func _ASS_GetDocVersionString ( $_Self, $pbstrVersionString ) #forceref $_Self, $pbstrVersionString DllStructSetData(DllStructCreate("byte", $pbstrVersionString), 1, 0) _Trace(StringFormat( '_ASS_GetDocVersionString: %s', "OK" )) Return 0 ; S_OK EndFunc ;==> _ASS_GetDocVersionString Func _ASS_OnScriptTerminate ( $_Self, $pResult, $pExceptionInfo ) #forceref $_Self, $pResult, $pExceptionInfo _Trace(StringFormat( '_ASS_OnScriptTerminate: %s', "OK" )) Return 0 ; S_OK EndFunc ;==> _ASS_OnScriptTerminate Func _ASS_OnStateChange ( $_Self, $iState ) #forceref $_Self _Trace(StringFormat( '_ASS_OnStateChange: State = %d', $iState )) Return 0 ; S_OK EndFunc ;==> _ASS_OnStateChange Func _ASS_OnScriptError ( $_Self, $pActiveScriptError ) #forceref $_Self, $pActiveScriptError Static Local _ $tEXCEPINFO = DllStructCreate ($tagEXCEPINFO), _ $pEXCEPINFO = DllStructGetPtr($tEXCEPINFO) Local $_Error = _AutoItObject_WrapperCreate($pActiveScriptError, $tagActiveScriptError) _AutoItObject_IUnknownAddRef($pActiveScriptError) $aCall = $_Error.GetExceptionInfo($pEXCEPINFO) If NOT $aCall[0] Then MsgBox(16, __Au3Obj_SysReadString(DllStructGetData($tEXCEPINFO, "bstrSource")), StringFormat ( _ "Error 0x%X\r\n\r\n%s", _ DllStructGetData($tEXCEPINFO, "scode"), _ __Au3Obj_SysReadString(DllStructGetData($tEXCEPINFO, "bstrDescription")) _ )) $_Error = 0 Return 0 ; S_OK EndFunc ;==> _ASS_OnScriptError Func _ASS_OnEnterScript ( $_Self ) #forceref $_Self _Trace(StringFormat( '_ASS_OnEnterScript: %s', "OK" )) Return 0 ; S_OK EndFunc ;==> _ASS_OnEnterScript Func _ASS_OnLeaveScript ( $_Self ) #forceref $_Self _Trace(StringFormat( '_ASS_OnLeaveScript: %s', "OK" )) Return 0 ; S_OK EndFunc ;==> _ASS_OnLeaveScript #EndRegion <<< ActiveScriptSite Implementation Func _Trace ( $msg, $ln = @ScriptLineNumber ) ConsoleWrite( @ScriptName & "(" & $ln & "): " & $msg & @CRLF) EndFunc ;==> _Trace Minimum Requirements (JScript9): IE9 (for the JScript9.dll only, can be portable) Win7 (works in WinPE too), x64 still untested NOTE: Through IActiveScriptSite we can host not only JScript engine, but any other ActiveScripting engine like VBScript, LuaScript(JIT), ActivePerl etc. NOTE: If you don't know the DLL path ( Specifiying dll path is now optional )Please uncomment the first method of specifiying the dll path, ; ; Either get DLL path from registry $engine_path = RegRead("HKCR\CLSID\" & $sCLSID_ScriptEngine & "\InprocServer32", "") ; ObjCreateInterface like ; ; Or bring along the DLL in portable way! ; $engine_path = @ScriptDir & "\JScript9.DLL" ; $engine_path = @ScriptDir & "\JScript.DLL" ; Old JScript Thanks to trancexx for mentioning this Update 23/09/13 Fixed ParseScriptText parameter, credits to trancexx Added x64 support, untested Edited September 24, 2013 by eimhym KLM and trancexx 2 Link to comment Share on other sites More sharing options...
trancexx Posted September 23, 2013 Share Posted September 23, 2013 Excellent!You should really pass pointer to EXCEPINFO structure as last argument for ParseScriptText. And to get it working for x64 you should define $sIID_IActiveScriptParse64. Maybe like this:Global Const $sIID_IActiveScriptParse64 = "{c7ef7658-e1ee-480e-97ea-d52cb4d76d17}" Global Const $sIID_IActiveScriptParse32 = "{BB1A2AE2-A4F9-11cf-8F20-00805F2CD064}" Global Const $sIID_IActiveScriptParse = @AutoItX64 ? $sIID_IActiveScriptParse64 : $sIID_IActiveScriptParse32... and dwSourceContextCookie parameter for $tagIActiveScriptParse should be "dword_ptr".ParseScriptText shows that AutoIt lacks processing of Null keyword for aliased pointer types. That's why you specify "ptr" for "wstr" Null, right? I wrote the same thing few days ago but without AutoItObject. Try it, it's much nicer. ♡♡♡ . eMyvnE Link to comment Share on other sites More sharing options...
eimhym Posted September 23, 2013 Author Share Posted September 23, 2013 You should really pass pointer to EXCEPINFO structure as last argument for ParseScriptText. And to get it working for x64 you should define $sIID_IActiveScriptParse64 and dwSourceContextCookie parameter for $tagIActiveScriptParse should be "dword_ptr" Fixed, thank you for the hint! After re-read the doc, EXCEPINFO is indeed not optional. Though it is scriptlet related, not the script parsing error. We still have to watch IActiveScriptSite.OnScriptError for that purpose. Null, right? Yea, would be awesome if we can pass Null to wstr. I've added comment to ParseScriptText if someone ever need to pass string. I wrote the same thing few days ago but without AutoItObject. If you mean by that is Delphi's like interface and inheritance, oh well you just hit me with an idea PS I have no access to Win x64, so I'd be grateful if someone can confirm that it works in x64 too. The script hasn't tested thoroughly so I believe theres something left here and there. Any feedback welcomed Link to comment Share on other sites More sharing options...
JohnOne Posted September 23, 2013 Share Posted September 23, 2013 (edited) Out of mt depth here, but can you not pass '0' to emulate Null. Or maybe AutoIt deals with that internally. Edited September 23, 2013 by JohnOne AutoIt Absolute Beginners Require a serial Pause Script Video Tutorials by Morthawt ipify Monkey's are, like, natures humans. Link to comment Share on other sites More sharing options...
eimhym Posted September 23, 2013 Author Share Posted September 23, 2013 (edited) "0" would be an empty string, while the pointer to that string is still not NULL. If AutoIt does convert it to NULL pointer (psz) automatically that would be great (or disaster?) trancexx mentioned about keyword for NULL, IMHO that would be better. Edited September 23, 2013 by eimhym Link to comment Share on other sites More sharing options...
trancexx Posted September 23, 2013 Share Posted September 23, 2013 (edited) If you mean by that is Delphi's like interface and inheritance, oh well you just hit me with an idea I meant by using built-in ObjCreateInterface function.I needed to execute some online javascript code because converting it to AutoIt was too complicated. It was much easier to use IActiveScript to do it for me.You would have troubles finding anyone to test your code because you're making it hard to do that. First of all you shouldn't be using dll directly when Windows offers easier ways for creating this object. For example this is preferred way:ObjCreateInterface($sCLSID_ScriptEngine, $sIID_IActiveScript, $tagIActiveScript)... or even better this:ObjCreateInterface("JScript", $sIID_IActiveScript, $tagIActiveScript) Edited September 23, 2013 by trancexx ♡♡♡ . eMyvnE Link to comment Share on other sites More sharing options...
eimhym Posted September 24, 2013 Author Share Posted September 24, 2013 (edited) you shouldn't be using dll directly That's why Chakra is by default inaccessible - it does have CLSID but no ProgID. The hack I mentioned in first post is about assigning ProgID manually, but that require editing the registry. ObjCreateInterface is cool, and if anyone prefer that, please uncomment the first method of obtaining dll path from registry and comment the later (specify it directly). E.g: ; ; Either get DLL path from registry $engine_path = RegRead("HKCR\CLSID\" & $sCLSID_ScriptEngine & "\InprocServer32", "") ; ObjCreateInterface like, autopath ; ; Or bring along the DLL in portable way! ; $engine_path = @ScriptDir & "\JScript9.DLL" ; comment this! ; $engine_path = @ScriptDir & "\JScript.DLL" ; Old JScript For anyone courious, thats what ObjCreateInterface would do anyway; find ProgID/CLSID entry in registry, look for dll path entry. After InprocServer path found, we instantiate class by invoking dll's exported DllGetClassObject and then CreateInstance from the class factory - and I think thats also what _AutoItObject_ObjCreateEx do. I haven't look at AutoItObject source though, trancexx you know better lol To note again, JScript9.dll can be used even without having IE browser installed. This would be extremely usefull in WinPE environment. A portable Windows Scripting Host if I may say. Again, if anyone not sure where the hell the dll is, please uncomment the first method like shown above Updated: now trying to find path in registry automatically when specified dll not found Edited September 24, 2013 by eimhym Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now