This is G o o g l e's cache of http://www.mindspring.com/~mark_baker/hostrun.htm as retrieved on 4 Mar 2006 08:39:39 GMT.
G o o g l e's cache is the snapshot that we took of the page as we crawled the web.
The page may have changed since that time. Click here for the current page without highlighting.
This cached page may reference images which are no longer available. Click here for the cached text only.
To link to or bookmark this page, use the following url: http://www.google.com/search?q=cache:mTQarRhug6YJ:www.mindspring.com/~mark_baker/hostrun.htm+&hl=en&ct=clnk&cd=1&client=firefox-a


Google is neither affiliated with the authors of this page nor responsible for its content.

AXS_FAQ - Hosting - Running Scripts

Hosting – Running Scripts

How do I execute a script in a given language?

You need to create an instance of the engine you want (say VBScript) and then get its IActiveScript interface. Once that is done, you need to pass the script text to the engine and then move it to the CONNECTED state. This executes the script.

Here are the steps:

If the script engine needs you to create an instance of an object within the script, it will call IActiveScriptSite::GetItemInfo. You need to be able to create and return the appropriate object or type library.

Note: This is one such set of steps to execute a script. There are other possible flags that can be passed to IActiveScriptParse::ParseScriptText, and additional steps that need to be taken if you want to implement ActiveX Script Debugging support.

(Source: mark_baker@mindspring,com, Mark Baker, 11/13/99)

Back to Table of Contents


How can I call a specific function or subroutine within my script?

After executing the script, you can call IActiveScript:: GetScriptDispatch () to get an IDispatch interface for the script. Then you can call IDispatch::GetIDsOfNames() to translate a function/subroutine name into a DISPID. Then you can call IDispatch::Invoke with the DISPID to execute the function. With this technique you can also pass in parameters to the function via the Invoke() method.

(Source: Microsoft’s Knowledge Base article Q222966, 3/31/99)

Back to Table of Contents


How can I determine the correct scripting engine to create from a script’s text?

There is no built-in support that will just select the "right" engine for the text. For example, if you pass VBScript text to a JScript engine, it will report syntax and other errors (obviously). You may be able to discern language by the file extension of the script file if it is stored as an external file. This is how the Microsoft Windows Scripting Host works. If it sees .vbs, it knows its VBScript. If it sees .js, it knows its JScript.

(Source: mark_baker@mindspring,com, Mark Baker, 11/13/99)

Back to Table of Contents


What is the easiest way to re-execute a script?

Don't use SetScriptState(SCRIPTSTATE_INITIALIZED), the global code won't be run again.

The easiest way is to Clone() the script engine, and then reconnect it. Clone()ing allows you to run the global code again. If you clone, make sure you use the SCRIPTITEM_ISPERSISTENT and SCRIPTTEXT_ISPERSISTENT flags so the named items and text you added the first time stick around in the cloned script engine.

(Source: John Crim, WebGecko Software, 7/29/99, microsoft.public.scripting.hosting)

Note that one of the flags to AddNamedItem and ParseScriptText is "ISPERSISTENT". When the script engine is partially reset -- taken back to UNINITIALIZED state and initialized again -- everything that you marked as PERSISTENT stays around. When the script engine is completely reset - that is, closed -- then EVERYTHING is destroyed, even persistent items. So yes, you probably want to close the engine and then call SetScriptSite again to move it back to INITIALIZED state if you really want to throw away everything. Now, if you want to add all the same named items and code that you added before, then it is faster to mark them as persistent and just do a partial reset -- that saves the time required to recompile the code, for instance. ASP uses both techniques -- it maintains a pool of "blank" script engines and also a pool of script engines with compiled source for a particular page. If that page request comes in, then it can just do a partial reset and not recompile. If a new page request comes in, it can use a blank script engine. Engines can be moved from the partially-reset pool to the fully-reset pool by closing them.

(Source: Eric Lippert, Microsoft Scripting Dev, 2/27/1999, microsoft.public.scripting.hosting (Submitted by Andrew Nosenko, 5/27/2000) )

Back to Table of Contents


When I’m done with the scripting engine, how should I release the engine?

IActiveScript::Close will release your interface pointers.

(Source: John Crim, WebGecko Software, 8/6/99, microsoft.public.scripting.hosting)

I did come across some logic a while back that indicated that you should ensure that the engine is _not_ in the initialized state when closing it due to problems with some scripting engines. I do the following as a matter of course in my code so I can't say whether it will fix your problem. Here's the code:

     if ( state == SCRIPTSTATE_INITIALIZED )
          m_engine->SetScriptState(SCRIPTSTATE_CONNECTED); 
     m_engine->SetScriptState(SCRIPTSTATE_DISCONNECTED); // possible overkill 
     m_engine->Close();

(Source: mark_baker@mindspring,com, Mark Baker, 9/8/99, microsoft.public.scripting.hosting)

Back to Table of Contents


How do I trap runtime errors in my script?

Like all programs, scripts running in an Host can throw two kinds of errors, compile-time and run-time. In earlier implementations, the Engines provided by Microsoft (VBScript and JScript), made no distinction between the two types of errors. Both were handled in IActiveScriptSite::OnScriptError(). With more recent versions of the script engines, a distinction was made between run-time and compile-time errors. Compile-time errors, such as syntax errors, are still reported to the Host using the IActiveScriptSite::OnScriptError() method. However, run-time errors, such as passing invalid arguments, are not directly reported to OnScriptError(). Instead, they are reported to a different method, IActiveScriptSiteDebug::OnScriptErrorDebug().

(Source: Knowledge Base, MSDN, Q232394, 6/8/98)

In the newest releases of the script engines, IActiveScriptSiteDebug::OnScriptErrorDebug is called when a run-time error occurs. The IActiveScriptSiteDebug interface gives the Script Host a chance to participate in debugging before the debugger is involved. In order for the Script Host to be notified when a run-time error occurs, a minimal implementation of IActiveScriptSiteDebug is required. When the IActiveScript::SetScriptSite method is called, the script engine will QueryInterface the Host's IActiveScriptSite pointer for the IActiveScriptSiteDebug interface. If this fails, the script engine will attempt to contact the script debugger on its own. However, if the QueryInterface is successful, the script engine will then call IActiveScriptSiteDebug::GetApplication() to establish the debugging facilities for the scripting session. If IActiveScriptSiteDebug::GetApplication() fails, the script engine will conclude that debugging is not available on the machine, and revert to IActiveScriptSite::OnScriptError() for all error handling.

(Source: Knowledge Base, MSDN website, Q23394, 2/4/2000)

Back to Table of Contents


Why does setting the boolean variable "callOnScriptErrorWhenContinuing" in IActiveScriptSiteDebug::OnScriptErrorDebug() not call IActiveScriptSite::OnScriptError?

Probably a bug in the JScript/VBScript engines. Simplest fix is to just propagate the call to OnScriptError yourself within your implementation of OnScriptErrorDebug(). IActiveScriptErrorDebug derives from IActiveScriptError so you can just pass it in as-is

(Source: mark_baker@mindspring.com , Mark Baker, 11/29/99 & 12/9/99, microsoft.public.scripting.hosting)

Back to Table of Contents


How do I signal an error from my host that can be trapped by my script?

How about a failed HRESULT.

(Source: Joe Graf, 11/24/99, microsoft.public.scripting.hosting)

I think you should throw an exception like AfxThrowOleException(YourHRESULT) (or AfxThrowOleDispatchException as noted by Larry Engholm) in msg::GetValueShort() in case you have nothing to return. This exception will be catched further by COleDispatchImpl::Invoke and SCODE will be returned to VB. As far as I know (I may be wrong) there are special operator On Error and object Err in VBScript so you can catch an error there and process it accordingly.

(Source: Alexandr Alexeev, 11/24/99, microsoft.public.scripting.hosting)

Back to Table of Contents


How do I handle script errors without using the script debugger?

To keep the debugger from popping up during an error, have you IActiveScriptSite object also implement IActiveScriptSiteDebug, and in IActiveScriptSiteDebug::OnScriptErrorDebug set *pfEnterDebugger = FALSE.

(Source: John Crim, WebGecko Software, 8/23/99, microsoft.public.scripting.hosting)

Back to Table of Contents


How do I disable the script debugger for my scripts?

The knowledge base article Q232394 - HOWTO: Catch Run-time Errors in an ActiveX Script Host
(http://support.microsoft.com/support/kb/articles/q232/3/94.asp) describes how to disable Active Debugging. Essentially, your host needs to implement the IActiveScriptSiteDebug interface, and return E_FAIL from IActiveScriptSiteDebug::GetApplication() .

(Source: Joel Alley, Microsoft Developer Support, 9/17/99, microsoft.public.scripting.hosting)

Back to Table of Contents


How do I trap syntax errors in a script within my host?

You need to implement support for trapping script errors in general. Then look at the EXCEPINFO.scode value. If it’s anything other than E_ABORT then it’s a script error. Currently, there is no documented error code specifically for syntax errors.

(Source: mark_baker@mindspring.com , Mark Baker, 11/26/99)

Back to Table of Contents


If the engine reports an error in a script, how do I know where the error is located?

You need to implement support for trapping script errors in general. Then call IActiveScriptError::GetSourcePosition() to get the line number and character position (column) of the script text that is causing the problem.

(Source: mark_baker@mindspring.com , Mark Baker, 11/26/99)

Back to Table of Contents


If the engine reports an error in a script, how do I know what kind of error it found?

Implement the IActiveScriptSite interface. Errors are reported by the engine by calling IActiveScriptSite::OnScriptError() and passing in a IActiveScriptError interface. Call IActiveScriptError::GetExceptionInfo() and pass in a zero’d EXCEPINFO structure to hold the exception results.

Note: You must call SysFreeString() on any BSTR’s within the EXCEPINFO structure returned by IActiveScriptError::GetExceptionInfo().

(Source: mark_baker@mindspring.com , Mark Baker, 11/26/99)

Back to Table of Contents


How do I know when a script is finished executing?

If I recall correctly, the call to SetScriptState(CONNECTED) runs the script and blocks until the script is finished running (that is, running the global script code and any functions it may call).

The same holds true when you invoke functions in the script via the Script's IDispatch pointer. The call should block until the function returns.

(Source: Chris Sousa, 9/1/99, microsoft.public.scripting.hosting)

Back to Table of Contents


If I call methods on the scripting engine from a thread other than the one I used to create the engine, I get the HRESULT E_UNEXPECTED. What do I need to do to be able to call the engine from any thread (or multiple threads)?

#1 - Make your host free-threaded (vs apartment threaded). This will allow you to call any method on the engine from any thread. You have to call CoInitialize(COINIT_MULTITHREADED) to make this happen at the COM level. You also have to ensure that your code (ie IActiveScriptSite) is thread safe (ie use critical sections, semaphores, etc

#2 - If #1 is not an option, then you can only call the methods IActiveScript::Clone and IActiveScript::InterruptScriptThread from any thread other than the one you called the method IActiveScript::SetScriptSite from. When the engine is created in apartment mode, it has affinity for the
thread that was running when this method was called.

#3 - If #2 is too restrictive, you can set up a message system between the 2 threads such that any calls that the 2nd thread wishes to make on the engine would be done by sending messages to the 1st thread and have it call the methods on behalf of the 2nd thread. This takes some more work on your part, but it will work just fine.

(Source: mark_baker@mindspring.com, Mark Baker, 9/17/99, microsoft.public.scripting.hosting)

After an engine has received a reference to its host by calling the IActiveScript::SetScriptSite method, the scripting engine can no longer accept calls from non-base threads. This happens because the scripting engine checks the thread that makes each call and rejects any calls from non-base threads.

NOTE: The base thread is the one that called IActiveScript::SetScriptSite.

(Source: Knowledge Base, MSDN, Q222837, 4/1/99)

The thread affinity is not based upon the thread that creates the engine, it is on the thread that sets the engine's site pointer. You can create the engine and pass it around to multiple threads as long as you do not set the site. Once the site is set, it is tied to that thread. Even though the engines are marked as free threaded, the components that are created by the engine are not guaranteed to be free threaded. Since this would cause all kinds of headaches, the engine developers took the stance of enforcing an apartment model approach, once the site is set. You can get around this by creating a thread that marshals all calls to the engine across thread boundaries. This is a non-trivial task. Chris Sousa and I did this for a project, but it took close to 12K lines of code to marshal all of the possible interface calls correctly.

(Source: Joe Graf, 12/7/99, microsoft.public.scripting.hosting)

Back to Table of Contents


In the IActiveScriptParse->ParseScriptText interface/method, what is the definition of the "pszItemName" parameter?

In IActiveScriptParse::ParseScriptText, the pstrItemName parameter is used to give script blocks context. The name you pass in pstrItemName must be a name you've already passed at some point to IActiveScript::AddNamedItem. The pstrItemName parameter works a lot like the 'namespace' keyword in Visual C++. When you pass NULL, the script code

is evaluated in a global context, and when you pass a value, the script code is evaluated with respect to the object you specified.

The most concrete example of its use is probably during a call to IActiveScript::GetScriptDispatch(). By passing the same name in the pstrItemName parameter of GetScriptDispatch as you did to ParseScriptText (and AddNamedItem), you can get an IDispatch pointer to just those methods added with that context.

(Source: Joel Alley, Microsoft Developer Support, 8/11/99, microsoft.public.scripting.hosting)

Back to Table of Contents


In the IActiveScriptParse->AddScriptlet method what is the difference between the pstrDefaultName, pstrItemName and pstrSubItemName arguments?

The pstrDefaultName parameter of AddScriptlet gives the Script Host a chance to name the event handler method. For example, if I wanted an event handler called MyEventHandler that handled Command1_OnClick, this would be the parameter I used to name it. pstrDefaultName differs from pstrEventName because pstrEventName is the name of the actual event (OnClick in the example).

There are a few caveats to pstrDefaultName, of course. If the name is not unique, then the script engine will make its own. If the pstrItemName parameter is NULL, the script engine will make its own. If the script engine doesn't like your name, it will make its own. The name that is actually assigned to the event handler is passed back in the pbstrName parameter of AddScriptlet. If its important to you to know what the name is, you should check this parameter.

The pstrItemName and pstrSubItemName parameters are less subtle. They simply identify the object that will be the source of the event in question. pstrItemName indicates the object, added with AddNamedItem and the SCRIPTITEM_ISSOURCE flag, that will source the event. The engine will ask this object for its IConnectionPointContainer interface to hook up to the event interface. Since any subObjects of an object added with AddNamedItem can also source events, the pstrSubItemName parameter gives the host a chance to indicate that the subitem, and not the main item, will source the event. In this case, the script engine will ask the subitem for its IConnectionPointContainer interface.

(Source: Joel Alley, Microsoft Developer Support, 8/11/99, microsoft.public.scripting.hosting )

Back to Table of Contents


Can the IActiveScriptParse->AddScriptlet method be used to add general functions to a script that are callable by the script passed to the engine via IActiveScriptParse->ParseScriptText?

It's best to use ParseScriptText for general script methods. In the implementations I've seen, including SampleScript, the engine will get confused if the method being added isn't an event of either the pstrItemName or the pstrSubItemName.

(Source: Joel Alley, Microsoft Developer Support, 8/11/99, microsoft.public.scripting.hosting )

Back to Table of Contents


Is there an example of a host using IActiveScriptParse->AddScriptlet?

I am a Script Engine writer and I can tell you the IE for example calls AddScriptlet() with the script to even code that you place in an HTML document. While normal scripts get passed to ParseScriptTExt(), the even scripts get passed to AddScriptlet(). I use this as the indication to my engine that this code is not to be executed immediately but instead added to the engine and only executed if the corresponding events get fired later.

(Source: Rod da Silva, 12/1/99, microsoft.public.scripting.hosting)

Back to Table of Contents


Why does my app crash inside OLEAUT32.DLL after I call IActiveScript::InterruptScriptThread?

The documentation for the IActiveScript::InterruptScriptThread() method indicates that you should pass the address of an EXCEPINFO structure as the second parameter. However, it fails to mention that this structure must be initialized because InterruptScriptThread will try to use information stored in the EXCEPINFO structure.

(Source: Knowledge Base, MSDN, Q182946, 7/23/99)

Back to Table of Contents


What is the state of the script engine after calling IActiveScript::InterruptScriptThread?

When IActiveScript::InterruptScriptThread is called, the script thread it's called on goes into a stopped state. The presumption is that if you interrupted the thread, there's something wrong with it and it shouldn't be run. You can reset this by calling SetScriptState() with the SCRIPTSTATE_STARTED or SCRIPTSTATE_CONNECTED flag again. Of course, this will not restart a script at the point it was interrupted. It will only make it runnable again.

(Source: Joel Alley, Microsoft Developer Support, 11/15/99, microsoft.public.scripting.hosting)

Back to Table of Contents


What are the semantics of IActiveScript::Clone?

It is used to keep from having to parse the script code every time you want to execute. It also lets different threads execute "copies" of an engine. It also has less overhead than creating a new engine each time.

(Source: Joe Graf, 11/14/99, microsoft.public.scripting.hosting )

Back to Table of Contents


How can I add 2 or more sets of script text to the engine via IActiveScript->ParseScriptText and get back an Idispatch pointer for each script?

The ActiveScript object can be QI'd for IDispatch.

To get two seperate IDispatch interfaces, each representing a seperate piece of text, you would need to call CoCreateObject twice to create two script engines, and call IActiveScriptParse once on each.

(Source: Chris Becke, 10/11/99, microsoft.public.scripting.hosting)

Back to Table of Contents


What is error code 0x80020101?

That HRESULT is "SCRIPT_E_REPORTED". It is what is returned by the script engine when an error occurs which has already been reported to the user.

Consider the scenario where VBScript calls JScript calls VBScript and that returns, say, E_FAIL. The VBScript engine will report the error to the user and return E_FAIL to JScript -- which will report the error to the user and return E_FAIL to VBScript, which -- you guessed it -- reports the error to the user and returns E_FAIL.

This is a terrible user scenario. If the script engine successfully calls OnScriptError then it propagates SCRIPT_E_REPORTED back as an indication that something failed but that the user has already been informed, so just fail silently.

So, something IS going wrong, but it should have been reported to the user somehow.

(Source: Eric Lippert, Microsoft Scripting Dev, 11/22/99, microsoft.public.scripting.hosting)

When an ActiveX Script Engine, such as VBScript or JScript, encounters an error it attempts to report the error to its script host by calling the following methods: IActiveScriptSite::OnScriptError -or IActiveScriptSiteDebug::OnScriptErrorDebug.

After one of these methods is called, the script engine must also return an HRESULT from the method that was called when the error occurred. To warn the script host that the error has already been reported, and to ensure that a single error does not result in more than one notification, the script engine returns SCRIPT_E_REPORTED. This indicates that the error has already been handled and the host need not take further action.

(Source: Microsoft Knowledge Base, 2/4/2000)

Back to Table of Contents


How can I run a script using the security credentials of the client?

Look at the CoSetSecurityBlanket() API.

(Source: Joe Graf, 11/22/99, microsoft.public.scripting.hosting)

Back to Table of Contents


I'm getting script error 0x8000FFFF when trying to move to the CONNECTED state after my script was terminated by InterruptScriptThread. What am I doing wrong?

Clone the engine using IActiveScript::Clone(). Then call IActiveScript::SetScriptState(CONNECTED).

(Source: mark_baker@mindspring.com , Mark Baker, 12/16/99, microsoft.public.scripting.host )

Back to Table of Contents


Why would I get a 'Catastrophic Failure' HRESULT back from from either ParseScriptText or from SetScriptState?

We have only encountered this error when a call was issued on the wrong thread.

(Source: Joe Graf, 12/17/99, microsoft.public.scripting.hosting)

I just wanted to mention that I got that error when I failed to call InitNew on IActiveScriptParse before calling ParseScriptText.

(Source: Kyle Palmer, 2/29/2000, FAQ Submission)

Back to Table of Contents


Why does the documentation state that I can call IActiveScript::SetScriptState from a secondary thread, but I get a ‘Catastrophic Failure’ HRESULT back when I try to call it?

The doc is incorrect. MS released a PRB doc (Q222837) on their support site (it's also in the MSDN) that contradicts what the doc says for the method SetScriptState. Here is the pasted text from that PRB doc:

"After the IActiveScript::SetScriptSite method has been called, you cannot call scripting engine methods on non-base thread, however, there are two notable exceptions to this rule:

- You can call the IActiveScript::InterruptScriptThread method from any thread, thus giving the host a chance to stop a script that has become stuck.

- You can call the IActiveScript::Clone method from any thread, thus giving the host the ability to set up a standard scripting engine and then replicate it for multiple job runs. "

(Source: mark_baker@mindspring.com , Mark Baker, 2/11/2000, microsoft.public.scripting.hosting )

Back to Table of Contents


Why would I get a ‘Catastrophic Failure’ HRESULT (0x8000FFFF) back from IActiveScript::GetScriptDispatch?

Three points:

1) The cause of this error is almost ALWAYS calling on the wrong thread. Double check that.
2) You can also call IAS::Clone on any thread.
3) Another possible cause of this error is calling GetScriptDispatch when the script engine has not been initialized CORRECTLY.

(Source: Eric Lippert, Microsoft Scripting Dev, 12/28/99, microsoft.public.scripting.hosting )

Back to Table of Contents


How can I implement "modules" functionality in my host similar to what the Microsoft Script Control offers?

The idea of a "module" is taken from Visual Basic. Other languages have a notion of a "class" or a "namespace". Some languages may not have any such notion if they are more pure function based. However, to create a "module" of related code you need 2 things: (1) the name of the module (2) the functions/methods for the module. To create a module programmatically, you call IActiveScript::AddNamedItem() with the name of the module and pass through the flag SCRIPTITEM_CODEONLY. This indicates to the engine that this named item is a "module" and _not_ a COM automation object. Then to add the functions for the module, you call IActiveScriptParse::ParseScriptText as many times as need be (to add the method code) and pass in the name of the module in the 2nd parm (pstrItemName). This will then add the functions under that module name. If you then want to execute functions in a module, call IActiveScript::GetScriptDispatch() and pass in the module name as the [in] parm. You will get back a normal IDispatch* and can call GetIDsOfNames() on it to translate a specific function name to an id. Then call IDispatch::Invoke() with that id and any parms you want to send through. If you pass NULL through as the pstrItemName parm instead, then the code gets added to the global namespace. This can then be accessed by passing NULL to GetScriptDispatch.

(Source: mark_baker@mindspring.com , Mark Baker, 2/7/2000, microsoft.public.scripting.hosting)

Back to Table of Contents


What is the expected behavior of the flags that can be passed to IActiveScript::InterruptScriptThread?

The flags for IActiveScript::InterruptScriptThread are currently ignored by both VBScript and JScript. The flags are included for possible additional functionality in the future, and to give other engines the opportunity for custom behavior.

Source: Joel Alley, Microsoft Developer Support, 2/24/2000, microsoft.public.scripting.hosting

Back to Table of Contents


How can I programatically access the global variables & functions in a script?

Always watch your contexts. A script must be added with a pstrItemName of NULL to have its variables and functions added in the global context. When this is done the GetScriptDispatch() process of obtaining variable and function references works just fine. And the event function is part of the context and not part of the object sourcing the event.

Source: Curtis Clauson, 3/6/2000, microsoft.public.scripting.hosting

Back to Table of Contents


Why does IActiveScriptError::GetSourceLineText return E_FAIL when called after a runtime error occurs?

I was under the impression that once the script code was compiled the script engine no longer reported the source line during errors. From what I have seen, the source is only reported upon a compilation error.

Source: Joe Graf, 3/8/2000, microsoft.public.scripting.hosting

Back to Table of Contents


Are there any special flags I need to pass to IActiveScript::AddNamedItem() in order to parse a script in a named context?

The SCRIPTITEM_NOCODE flag indicates that you don't want a script context for the named item. If you want to parse script text in a named context, don't pass the SCRIPTITEM_NOCODE flag.

Source: Joel Alley, Microsoft Developer Support, 3/13/2000, microsoft.public.scripting.hosting

I believe this was an answer to a question I recently posted. The answer tells you what flags not to set. In fact, I found that the only flag you need to set in this case is SCRIPTITEM_CODEONLY.

(Source: Larry Baer, FAQ Submission, 3/29/2000)

Named items can have code associated with them -- for instance, in IE a form might be a named item with some code (event handlers for the elements of the form) associated with it. If a named item is marked as CODEONLY then we do not attempt to actually get a pointer to the item -- the name represents "code only", not an object with some code associated with it. If a named item is marked as NOCODE then we do the opposite -- get a pointer to the object, but do not attempt to get code associated with it, because there is "no code" associated with this object. (If you then attempt to set that object as the default dispatch of a code block, that's an error.)

(Source: Eric Lippert, Microsoft Scripting Dev, 2/15/1999, microsoft.public.scripting.hosting (Submitted by Andrew Nosenko, 5/27/2000) )

Back to Table of Contents


Is there any way to save parsed code into a binary format to eleviate having to re-parse the code at a later time?

You're not the first to ask for this feature. We wanted to serialize the pcode to a database....the feature doesn't work. The active scripting supports the correct interface but I think you get back E_NOTIMPL or E_FAIL I don't remember which.

(Source: Joe Graf, 3/31/2000, microsoft.public.scripting.hosting)

I tried: IPersist, IPersistFile, IPersistStorage, IPersistStreamInit, IPersistStream, IPersistPropertyBag

JScript supports none.

(Source: Pavel Gusak, 4/5/2000, microsoft.public.scripting.hosting)

Back to Table of Contents


How can I pause and then resume the execution of a script from where it was paused?

IActiveScript::GetScriptThreadID(); SuspendThread(); ResumeThread();

(Source: Pavel Gusak, 4/12/2000, microsoft.public.scripting.hosting)

Note: you can't use IActiveScript::InterruptScriptThread to interrupt the script if you want to resume it from where it was interrupted.

(Source: Mark Baker, 5/12/2000)

Back to Table of Contents


Which IPersistXXX interface should I use to load source code (script) into an engine?

We've (this newsgroup) found that the engines don't support any of them.

(Source: Joe Graf, 6/16/2000, microsoft.public.scripting.hosting)

Back to Table of Contents


What would be the proper way to terminate a script from an automation object method that was added using AddNamedItem? I've tried InterruptScriptThread, then SetScriptState(SCRIPTSTATE_DISCONNECTED), doing this this fires an error on the next line of code following the method that quits the script. Also tried calling OnScriptTerminate directly, somewhere in this mixture has to be a clean way to exit.

I'm not sure that it is legal to call InterruptScriptThread from an automation object. It is usually called by the host in response to some condition. I can see 2 ways to solve the problem: (1) have the automation object use a Win32 event to signal the host to interrupt the script (2) have the automation object just return an error code of some type and process the error in the script using the VBScript On Error statemenet or Jscript try/catch statements. Since the MS doc is silent on whether InterruptScriptThread can be called from an automation object, it is probably better not to try to get this to work - you may run into problems with other non-MS engines such as Perl or Python that didn't implement the behavior since it wasn't clearly documented. The 2 solutions I mention should work fine in any engine, though.

(Source: Mark Baker, 5/24/2000, microsoft.public.scripting.hosting)

Back to Table of Contents


How can I support multiple scripting languages such that scripts written in one language can call scripts written in another language (ie. VBScript calls Jscript, etc)?

Have you tried passing the dispatch pointer of each engine to each other via AddNamedItem/GetItemInfo? This should work as long as they are on the same threads (otherwise you'll see E_CATASTROPHIC). I haven't tried this so don't hold me to it.

(Source: Joe Graf, 5/31/2000, microsoft.public.scripting.hosting)

Back to Table of Contents


Can the Dispatch pointer retrieved with GetScriptDispatch() be passed between threads?

All calls to the scripting engine must come from the same thread (except InterruptScriptThread). This includes the script engine's dispatch pointer.

(Source: Joe Graf, 6/1/2000, microsoft.public.scripting.hosting)

Back to Table of Contents


How can I safely use a script interface (like an IDispatch pointer) in a secondary thread if that thread doesn't own the interface?

You might try having thread B perform the call for thread A and then just pass the results to thread A via some internal data structure. You could also create a series of "services" that thread B could support on behalf of thread A - these services would be initiated using Win32 Events to signal thread B to do its stuff - thread B would then signal thread A when it is finished and the results are ready. This requires calling WaitOnSingleObject() (or one of its companions) to shift back and forth between the threads. But it gets around the limitation that the script engines only support a couple of specific methods on alternate threads.

(Source: Mark Baker, 6/1/2000, microsoft.public.scripting.hosting)

Back to Table of Contents


What is the best way to reset the scripting engine between uses?

There's been some confusion as to how exactly one resets a script engine. Here's what I said on the subject the other day:

Note that one of the flags to AddNamedItem and ParseScriptText is "ISPERSISTENT". When the script engine is partially reset -- taken back to UNINITIALIZED state and initialized again -- everything that you marked as PERSISTENT stays around. When the script engine is completely reset -- that is, closed -- then EVERYTHING is destroyed, even persistent items.

This is correct, but I think it's worth describing _exactly_ what happens for the a few state transitions, just to clear up any confusion:

1) If the script engine is in CLOSED or UNINITIALIZED state, it is illegal to transition to anything but CLOSED or UNINITIALIZED. To get to INITIALIZED state from CLOSED or UNINITIALIZED, you must call SetScriptSite -- in CLOSED/UNINITIALIZED state, the script engine does not have a reference to the site, and hence cannot do anything.

2) If the script engine is STARTED, CONNECTED or DISCONNECTED and you move it to INITIALIZED, the following happens:

- any event sinks are disconnected and freed
- any non-persistent named items are thrown away
- any non-persistent code blocks are thrown away
- any persistent code blocks are marked as "has not yet run"
- the existing script session (the runtime context) is thrown away
- a new script session is created and the remaining named items are added to the global name space -- we are ready to run code.

3) If the script engine is STARTED, CONNECTED, DISCONNECTED or INITIALIZED and you move it to UNINITIALIZED, the following happens:

- the connection to the host's site is thrown away
- any event sinks are disconnected and freed
- any non-persistent named items are thrown away
- any non-persistent code blocks are thrown away, any persistent code blocks are marked as "has not yet run"
- if in IE, the IE security manager is reset
- if in the debugger, all debugger connections are reset, and all actively debugged documents are destroyed - the existing script session is thrown away
- no session is created -- without a connection to the host, we cannot run code.

4) If you move the engine to CLOSED from any state:

- everything in (3) happens
- persistent named items are thrown away
- persistent code blocks are thrown away

(Source: Eric Lippert, Microsoft Scripting Dev, 2/4/1999, microsoft.public.scripting.hosting (Submitted by Andrew Nosenko, 5/27/2000))

Back to Table of Contents


What is the purpose of the IActiveScriptParseProcedure interface?

The IActiveScriptParseProcedure interface is used by Internet Explorer to more easily handle button clicks and other events. Essentially, it the equivalent of combining a call to IActiveScriptParse::ParseScriptText and IActiveScript::GetScriptDispatch.

From the SamScrpt sample script engine, here's a brief write-up on ParseProcedureText, IActiveScriptParseProcedure's only method.

/******************************************************************************
*  ParseProcedureText -- This method allows an Active Script Host to use
*  IDispatch-style function pointers to fire methods instead of using the more
*  difficult method of Connection Points.  It parses a scriplet and wraps it in
*  an anonymous IDispatch interface, which the host can use in lieu of
*  Connection Points to handle events.
*
*  Parameters: pstrCode -- Address of the script code to evaluate
*              pstrFormalParams -- Address of any formal parameters to the
*                                  scriptlet. (ignored)
*              pstrProcedureName -- Name of the event
*              pstrItemName --  The named item that gives this scriptlet its context.
*              punkContext -- Address of the context object.  This item is
*                             reserved for the debugger.
*              pstrDelimiter -- Address of the delimiter the host used to detect
*                               the end of the scriptlet.
*              dwSourceContextCookie -- Application defined value for debugging
*              ulStartingLineNumber -- zero-based number defining where parsing
*                                      began.
*              dwFlags -- SCRIPTPROC_HOSTMANAGESSOURCE
*                         SCRIPTPROC_IMPLICIT_THIS
*                         SCRIPTPROC_IMPLICIT_PARENTS
*                         SCRIPTPROC_ALL_FLAGS
*              ppdisp -- Address of the pointer that receives the IDispatch
*                        pointer the host uses to call this event.
*  Returns: S_OK
*           DISP_E_EXCEPTION
*           E_INVALIDARG
*           E_POINTER
*           E_NOTIMPL
*           E_UNEXPECTED
*           OLESCRIPT_E_SYNTAX
******************************************************************************/

(Source: Joel Alley (MS), 6/10/1999, microsoft.public.scripting.hosting (Submitted by Andrew Nosenko, 5/27/2000))

Back to Table of Contents


What is the purpose of the IActiveScriptStats interface and methods?

IActiveScriptStats is used by IE4 to handle script timeouts (prevent "denial of service"). Pass in one of the flags for the first param (stid). Currently, only SCRIPTSTAT_STATEMENT_COUNT is supported -- it returns the number of statements executed since the script started.

cpp_quote(     "/* IActiveScriptStats::GetStat() values */")
cpp_quote(     "")
cpp_quote(     "#define SCRIPTSTAT_STATEMENT_COUNT       1")
cpp_quote(     "#define SCRIPTSTAT_INSTRUCTION_COUNT     2")
cpp_quote(     "#define SCRIPTSTAT_INTSTRUCTION_TIME     3")
cpp_quote(     "#define SCRIPTSTAT_TOTAL_TIME            4")

[
        object,
        uuid(B8DA6310-E19B-11d0-933C-00A0C90DCAA9),
        pointer_default(unique)
]
interface IActiveScriptStats : IUnknown
{
        HRESULT GetStat(
                [in] DWORD stid,
                [out] ULONG *pluHi,
                [out] ULONG *pluLo
        );

        HRESULT GetStatEx(
                [in]  REFGUID guid,
                [out] ULONG *pluHi,
                [out] ULONG *pluLo
        );

        HRESULT ResetStats(void);
}

(Source: Chris Weight, Microsoft Scripting Dev, 3/11/1998, microsoft.public.scripting.hosting (Submtted by Andrew Nosenko, 5/27/2000))

Back to Table of Contents


Is there a complete description of the multithreading support within Active Scripting?

There are several threading models -- threading models are contracts between a caller and a callee regarding what the responsibilities of each are with respect to threading. The threading models in common usage are:

- Single threaded -- calls to an object must always be on the same thread. There are no synchronization issues because there is always only one thread no matter how many object instances there are.

- Free threaded -- calls to an object can be on any thread at any time, including multiple threads at the same time. The object is responsible for all synchronization issues.

- Apartment threaded -- calls to an object must always be on the same thread, but different instantiations of the object can be called on different threads at the same time. The object is responsible for synchronizing access to global (that is, not-per-instance) data.

- Rental threaded -- calls to an object can be on any thread, but the caller guarantees that only one thread is calling into the object at any time. That is, the caller is responsible for synchronizing calls to the object.

The active scripting engines provided by Microsoft (VBScript, JScript) are free threaded. However, ActiveX controls are typically apartment threaded. That means that the script engines must guarantee that they do not call into controls on a different thread than the thread that the control was created on.

Therefore, the script engines seriously restrict their callers - though technically the script engines are free threaded, for practical purposes you can treat them as apartment threaded.

Just to make sure I've described this model, let me re-iterate. Suppose you have an object of class Foo and you create three objects, Bar1, Bar2 and Bar3. Bar1 you create on ThreadA, Bar2 and Bar3 you create on ThreadB. Now, all calls to methods of Bar1 must be on ThreadA and all calls to Bar2 and Bar3 must be on ThreadB, to not break the apartment model. You can have multiple objects per thread -- Bar2 and Bar3 are both on ThreadB. If Bar1, Bar2 and Bar3 need access to some global data associated with class Foo then it is the responsibility of the object to synchronize thread access.

Anyway, the script engines enforce the apartment model in the following manner: Before the script engine is brought to INITIALIZED state, it is free threaded. Now suppose you call SetScriptSite on ThreadA -- this brings the script engine to INITIALIZED state. From this point on, until the script engine is reset to UNINITIALIZED state, all calls must be on ThreadA. Why? Because bringing the engine to INITIALIZED state does event sinks and other calls on ActiveX controls, and those controls must always be called on the same thread. Of course, there are a few exceptions -- InterruptScriptThread obviously cannot be called on ThreadA if ThreadA is the thread being interrupted!

(Source: Eric Lippert, Microsoft Scripting Dev, 2/19/1998, microsoft.public.scripting.hosting (Submitted by Andrew Nosenko, 5/27/2000))

Back to Table of Contents


Why would IActiveScript::InterruptScriptThread return E_INVALIDARG if I know the parameters passed to InterruptScriptThread are valid?

IActiveScript::InterruptScriptThread will return E_INVALIDARG if an interrupt is already pending in the script thread (ie. waiting for the next statement to be executed), or if the script thread is not running.

(Source: Joel Alley, Microsoft Developer Support, 8/14/2000, microsoft.public.scripting.hosting)

Back to Table of Contents


Why does IActiveScript::InterruptScriptThread not terminate a running script immediately when I'm trying to kill the script engine?

InterruptScriptThread only instructs the script engine to stop executing code at the next opportunity. The call sets a flag that the script engine only checks when executing code. If there isn't currently any code running (such as when the script engine is sitting idle waiting for events to fire), InterruptScriptThread will appear to not work.

To work around this, you might try adding a trivial method to your script, so that when you're ready to stop the engine, you could call InterruptScriptThread, and then call this method so the script engine would recognize the interrupt flag and stop.

(Source: Joel Alley, Microsoft Developer Support, 9/25/2000, microsoft.public.scripting.hosting)

Back to Table of Contents


How can I save/restore the values of script variables between runs?

Get the LPDISPATCH from the script engine.
Call GetIDsOfNames() with the name of the variable you are trying to read
Call Invoke() with "property get" passed in.
The variable's contents will be stored in the result variant

You have to convert JScript arrays to SAFEARRAYs and back. There is sample code out there (somewhere) to do this. I found it once..

(Source: Joe Graf, 9/28/2000-9/29/2000, microsoft.public.scripting.hosting)

Back to Table of Contents


What is the difference between the IActiveScript interface and the IScriptControl interface?

The IActiveScript interface doesn't use the script control - it is there so that you can access the features of a scripting engine directly. The MS Script OCX is there to make accessing script engines more easy, e.g. for those people who don't want to implement COM interfaces directly or prefer to use OLE Automation (a much more familiar technique for many programmers, and the only one easily available in some programming languages).

(Source: Peter Jamieson, 9/29/2000, microsoft.public.scripting..hosting)

Back to Table of Contents


Is there a way I can access the parameters of an event within a script added via IActiveScriptParse::AddScriptlet?

In VBScript, you could use 'auto-magic' events to declare the parameters for the event. Unfortunately, the only way to get events into JScript is through the AddScriptlet method. Since AddScriptlet creates a wrapper method around the script that takes no parameters and returns no values, there's no way to refer to the arguments that are passed in.

(Source: Joel Alley, Microsoft Developer Support, 2/12/2001, microsoft.public.scripting.hosting)

Back to Table of Contents


What are the correct HRESULT values to return when using the interface IActiveScriptSiteInterruptPoll?

The script engine is calling IActiveScriptSiteInterruptPoll::QueryContinue() to make sure the host still wants the script to continue running. This might be useful in a long running script. As long as QueryContinue() returns S_OK, the script will continue to run to completion. If QueryContinue() returns any error code or S_FALSE, script execution will stop and the error handler will be called.

The S_CODE 16388 is the HRESULT 0x80004004 (E_ABORT).

(Source: Joel Alley, Microsoft Developer Support, 2/12/2001, microsoft.public.scripting.hosting)

Back to Table of Contents




Copyright © 1999-2001  Mark M. Baker