## ActiveX Scripting Engine

To write an ActiveX Scripting engine, write an OLE COM object that supports the following interfaces.

Interface | Required? | Description
IActiveScript | Yes | Basic scripting ability.
IPersist* | Yes. At least one of the following (see note below). | Persistence support.
| IPersistStorage | DATA={url} syntax for OBJECT tag.
| IPersistStreamInit | Same as above, as well as DATA="string-encoded byte stream" syntax for OBJECT tag.
| IPersistPropertyBag | PARAM= syntax for OBJECT tag.
IActiveScriptParse | No | Ability to add script text, evaluate expressions, and so on.

Support for the IActiveScriptParse interface is optional; however, if it is not supported, the script engine must implement one of the IPersist* interfaces in order to load a given script.

Note: Certain interpreted script languages (for example, VBScript) running in specific host environments (for example, Internet Explorer) may rarely (or never) be called upon to save or restore a script state through IPersist*. Instead, IActiveScriptParse is used by calling IActiveScriptParse::InitNew to create a blank script, then scriptlets are added and connected to events with IActiveScriptParse::AddScriptlet and general code is added via IActiveScriptParse::ParseScriptText. Nonetheless, a scripting engine should fully implement at least one IPersist* scheme (preferably IPersistStreamInit), because other host applications may try to make use of them.

### Registry Standard

An ActiveX Scripting engine can identify itself using component categories. ActiveX Scripting currently defines two component categories:

Category | Description
CATID_ActiveScript | Indicates that the class identifiers (CLSIDs) are ActiveX Scripting engines that support, at a minimum, IActiveScript and a persistence mechanism (IPersistStorage, IPersistStreamInit, or IPersistPropertyBag).
CATID_ActiveScriptParse | Indicates that the CLSIDs are ActiveX Scripting engines that support, at a minimum, IActiveScript and IActiveScriptParse.

Although IActiveScriptParse is not a true persistence mechanism, it does support an InitNew method that is functionally equivalent to IPersist*::InitNew.

### Script Engine States

At any given time, an ActiveX Scripting engine can be in one of several states.

State | Description
uninitialized | The script has not been initialized or loaded using an IPersist* interface, or does not have an IActiveScriptSite set. The scripting engine is generally not usable from this state until the host takes steps to initialize the engine.
initialized | The script has been initialized with an IPersist* interface and has an IActiveScriptSite set, but is not connected to host objects and sinking events. Note that this state simply means that IPersist*::Load, IPersist*::InitNew, or IActiveScriptParse::InitNew has been completed, and IActiveScript::SetScriptSite has been called. The engine cannot run code in this mode. The engine queues code that the host passes to it through IActiveScriptParse::ParseScriptText, and executes the code after transitioning to the started state.
started | The transition from the initialized state to started state causes the engine to execute any code that was queued in the initialized state. The engine can execute code while in the started state, but it is not connected to events of the objects added through IActiveScript::AddNamedItem. The engine can execute code by calling the IDispatch interface obtained from IActiveScript::GetScriptDispatch, or by calling IActiveScriptParse::ParseScriptText. It is possible that further background initialization (progressive loading) is still ongoing, and that calling SetScriptState with the SCRIPTSTATE_CONNECTED value may cause the script to block until initialization is complete.
connected | The script is loaded and connected for sinking events from host objects.
disconnected | The script is loaded and has a run-time state, but is temporarily disconnected from sinking events from host objects. This state is distinguished from the initialized state in that the transition to this state does not cause the script to reset, the run-time state of the script is not reset, and a script initialization procedure is not executed.
closed | The script has been closed. The scripting engine no longer works and returns errors for most methods.

The following illustration shows the relationships between the various scripting engine states, and shows the methods that cause transitions from one state to another.

The following illustration shows the actions that the scripting engine performs during the various state transitions.

### A Word About Threading

Because an ActiveX Scripting engine can be used in many environments, it is important to keep its execution model as flexible as possible. For example, a server-based host may have a multithreaded design that it needs to preserve while using ActiveX Scripting in an efficient manner. At the same time, a host that does not use threading, such as a typical application, should not be burdened with threading management. ActiveX Scripting achieves this balance by restricting the ways a free-threaded scripting engine can call back to the host, freeing hosts from this burden.

#### For Scripting Engine Implementers

Scripting engines used on servers are typically implemented as free-threading COM objects. This means that methods on IActiveScript and its associated interfaces can be called from any thread in the process, without marshaling. (Unfortunately, this also means that the scripting engine must be implemented as an in-process server, because OLE does not currently support interprocess marshaling of free-threaded objects.) Synchronization is the responsibility of the scripting engine. For scripting engines that are not internally reentrant, or for language models that are not multithreaded, synchronization could be as simple as serializing access to the scripting engine with a mutex. Of course certain methods, such as InterruptScriptThread, should not be serialized in this way, so that a stuck script can be terminated from another thread.

The fact that IActiveScript is free-threaded generally implies that IActiveScriptSite and the host's object model should be free-threaded as well. This would make implementation of the host quite difficult, particularly in the common case where the host is a single-threaded Windows®-based application with single-threaded or apartment-model ActiveX controls in its object model. For this reason, the following constraints are placed on the scripting engine's use of IActiveScriptSite:

- The script site is always called in the context of a host thread. That is, the scripting engine never calls the script site in the context of a thread that it created, but only from within a scripting engine method that was called from the host (directly through IActiveScript and its derivatives, through the exposed scripting engine's dispatch object, or through a Windows message; indirectly from an event source in the host's object model).
- The script site is never called from within the context of a simple thread state control method (for example, InterruptScriptThread) or from the Clone method.

#### For Scripting Host Implementers

A host can safely assume that an engine will call IActiveScriptSite only in the context of the base thread, as long as the host obeys the following rules:

- Choose a base thread (generally the thread that contains the message loop).
- Instantiate the scripting engine in the base thread.
- Call scripting engine methods only from the base thread, except where specifically allowed, as in the cases of InterruptScriptThread and Clone.
- Call the scripting engine's dispatch object only in the base thread.
- Ensure that the message loop runs in the base thread if a window handle is provided.
- Ensure that objects in the host's object model only source events in the base thread.

Note that these rules are automatically followed by all single-threaded hosts. The restricted model described above is intentionally loose enough to allow a host to abort a stuck script by calling InterruptScriptThread from another thread (initiated by a CTRL+BREAK handler or the like), or to duplicate a script in a new thread using Clone.

Also note that none of these restrictions apply to a host that chooses to implement a free-threaded IActiveScriptSite and a free-threaded object model. Such a host can use IActiveScript from any thread, without restriction.

#### Script Thread Execution States

Each script thread can be in one of the following execution states:

State | Description
NotInScript | The thread is not currently running in a script (sinking a scripted event, processing ParseScriptText, or being called through a global script function published through GetScriptDispatch).
Running | The thread is currently executing script code.

© 1996 Microsoft Corporation