Remove ScriptingHost initialisation code (share with ScriptInterface instead).

Fix GUI scripts to avoid strict warnings.
Rejig GUI/SpiderMonkey interface to use less custom code, and to work
with JSOPTION_VAROBJFIX.
Add event name to GUI event handler function names (visible in the
profiler).

This was SVN commit r7769.
This commit is contained in:
Ykkrosh 2010-07-19 23:01:58 +00:00
parent ac9412458a
commit 9674c3c0fe
15 changed files with 81 additions and 231 deletions

View file

@ -13,12 +13,12 @@ function startMainMenu()
guiUnHide ("pg");
// Play main 0 A.D. theme when the main menu starts.
curr_music = newRandomSound("music", "menu");
if (curr_music)
curr_music.loop();
global.curr_music = newRandomSound("music", "menu");
if (global.curr_music)
global.curr_music.loop();
// Set starting volume (I'm using a value of zero here for no sound; feel free to comment out these two lines to use defaults).
// curr_music.setGain (0.0);
// global.curr_music.setGain (0.0);
// g_ConfigDB.system["sound.mastergain"] = 0.0;
}

View file

@ -145,7 +145,7 @@ function setCurrItemValue (objectName, string)
return -1; // Return -1 if nothing selected.
var list = getGUIObjectByName(objectName).list;
// Seek through list.
for (ctr = 0; ctr < list.length; ctr++)
for (var ctr = 0; ctr < list.length; ctr++)
{
// If we have found the string in the list,
if (list[ctr] == string)
@ -161,4 +161,4 @@ function setCurrItemValue (objectName, string)
return -2;
}
// ====================================================================
// ====================================================================

View file

@ -47,7 +47,7 @@ function newRandomSound(soundType, soundSubType, soundPrePath)
if (soundArray.length == 0)
{
console.write ("Failed to find sounds matching '*"+soundSubType+"*'");
return;
return undefined;
}
// Get a random number within the sound's range.
var randomSound = getRandom (0, soundArray.length-1);
@ -103,4 +103,4 @@ function crossFade (outHandle, inHandle, fadeDuration)
return true;
}
// ====================================================================
// ====================================================================

View file

@ -38,8 +38,8 @@ function init(data)
function reallyStartGame()
{
// Stop the music
if (typeof curr_music != "undefined" && curr_music)
curr_music.fade(-1, 0.0, 5.0); // fade to 0 over 5 seconds
if (global.curr_music)
global.curr_music.fade(-1, 0.0, 5.0); // fade to 0 over 5 seconds
// This is a reserved function name that is executed by the engine when it is ready
// to start the game (i.e. loading progress has reached 100%).
@ -50,4 +50,3 @@ function reallyStartGame()
// Restore default cursor.
setCursor ("arrow-default");
}

View file

@ -3,7 +3,7 @@
<objects>
<script>
function init () { }
function init() { }
</script>
<!--
@ -328,8 +328,8 @@ Watch for updates or get involved in the development: http://wildfiregames.com/0
tooltip="Tired of 0 A.D. ? Click here to leave and reenter the real world."
>
<action on="Press"><![CDATA[
btCaptions = ["Yes, let me out!", "Nooooo!"];
btCode = [exit, null];
var btCaptions = ["Yes, let me out!", "Nooooo!"];
var btCode = [exit, null];
messageBox (400, 200, "Do you really want to quit [icon=iconProduct] A.D.? This will cause a sudden return to reality.", "Confirmation", 0, btCaptions, btCode);
]]></action>
</object>
@ -434,12 +434,12 @@ Watch for updates or get involved in the development: http://wildfiregames.com/0
// either. Maybe this control isn't finished yet?)
if(this.checked)
{
curr_music.setGain (0.0);
global.curr_music.setGain (0.0);
g_ConfigDB.system["sound.mastergain"] = 0.0;
}
if(!this.checked)
{
curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
global.curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
g_ConfigDB.system["sound.mastergain"] = getGUIObjectByName ("pgOptionsAudioMusicGain").caption;
}
]]></action>
@ -485,7 +485,7 @@ Watch for updates or get involved in the development: http://wildfiregames.com/0
if (getGUIObjectByName ("pgOptionsAudioMusicGain").caption > 0.0)
guiModifyCaption ("pgOptionsAudioMusicGain", -.1, 1);
curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
global.curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
g_ConfigDB.system["sound.mastergain"] = getGUIObjectByName ("pgOptionsAudioMusicGain").caption;
]]></action>
</object>
@ -499,7 +499,7 @@ Watch for updates or get involved in the development: http://wildfiregames.com/0
if (getGUIObjectByName ("pgOptionsAudioMusicGain").caption < 1.0)
guiModifyCaption ("pgOptionsAudioMusicGain", .1, 1);
curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
global.curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
g_ConfigDB.system["sound.mastergain"] = getGUIObjectByName ("pgOptionsAudioMusicGain").caption;
]]></action>
</object>
@ -514,12 +514,12 @@ Watch for updates or get involved in the development: http://wildfiregames.com/0
if(this.checked)
{
curr_music.setGain (0.0);
global.curr_music.setGain (0.0);
g_ConfigDB.system["sound.mastergain"] = 0.0;
}
if(!this.checked)
{
curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
global.curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
g_ConfigDB.system["sound.mastergain"] = getGUIObjectByName ("pgOptionsAudioMusicGain").caption;
}
]]></action>
@ -590,12 +590,12 @@ Watch for updates or get involved in the development: http://wildfiregames.com/0
if(this.checked)
{
// curr_music.setGain (0.0);
// global.curr_music.setGain (0.0);
// g_ConfigDB.system["sound.mastergain"] = 0.0;
}
if(!this.checked)
{
// curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
// global.curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
// g_ConfigDB.system["sound.mastergain"] = getGUIObjectByName ("pgOptionsAudioMusicGain").caption;
}
]]></action>
@ -666,12 +666,12 @@ Watch for updates or get involved in the development: http://wildfiregames.com/0
if(this.checked)
{
// curr_music.setGain (0.0);
// global.curr_music.setGain (0.0);
// g_ConfigDB.system["sound.mastergain"] = 0.0;
}
if(!this.checked)
{
// curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
// global.curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
// g_ConfigDB.system["sound.mastergain"] = getGUIObjectByName ("pgOptionsAudioMusicGain").caption;
}
]]></action>
@ -741,12 +741,12 @@ Watch for updates or get involved in the development: http://wildfiregames.com/0
if(this.checked)
{
// curr_music.setGain (0.0);
// global.curr_music.setGain (0.0);
// g_ConfigDB.system["sound.mastergain"] = 0.0;
}
if(!this.checked)
{
// curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
// global.curr_music.setGain (getGUIObjectByName ("pgOptionsAudioMusicGain").caption);
// g_ConfigDB.system["sound.mastergain"] = getGUIObjectByName ("pgOptionsAudioMusicGain").caption;
}
]]></action>

View file

@ -53,11 +53,12 @@ function updateCursor()
function findGatherType(gatherer, supply)
{
if (!gatherer || !supply)
return;
return undefined;
if (gatherer[supply.type.generic+"."+supply.type.specific])
return supply.type.specific;
if (gatherer[supply.type.generic])
return supply.type.generic;
return undefined;
}
/**
@ -69,17 +70,17 @@ function determineAction(x, y)
// No action if there's no selection
if (!selection.length)
return;
return undefined;
// If the selection doesn't exist, no action
var entState = Engine.GuiInterfaceCall("GetEntityState", selection[0]);
if (!entState)
return;
return undefined;
// If the selection isn't friendly units, no action
var player = Engine.GetPlayerID();
if (entState.player != player && !g_DevSettings.controlAll)
return;
return undefined;
var targets = Engine.PickEntitiesAtPoint(x, y);

View file

@ -12,7 +12,7 @@ function layoutButtonRow(rowNumber, guiName, buttonSideLength, buttonSpacer, sta
{
var colNumber = 0;
for (i = startIndex; i < endIndex; i++)
for (var i = startIndex; i < endIndex; i++)
{
var button = getGUIObjectByName("unit"+guiName+"Button["+i+"]");
var size = button.size;

View file

@ -57,7 +57,6 @@ CGUI
#include "ps/Profile.h"
#include "scripting/ScriptingHost.h"
#include "scripting/JSConversions.h"
#include "ps/Hotkey.h"
#include "ps/Globals.h"
#include "ps/Filesystem.h"
@ -66,45 +65,10 @@ const double SELECT_DBLCLICK_RATE = 0.5;
#include "ps/CLogger.h"
#define LOG_CATEGORY L"gui"
// Class for global JavaScript object
JSClass GUIClass = {
"GUIClass", JSCLASS_HAS_PRIVATE,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
};
static JSBool GetGUIObjectByName(JSContext* cx, JSObject* obj, uintN UNUSED(argc), jsval* argv, jsval* rval)
{
CGUI* gui = (CGUI*)JS_GetInstancePrivate(cx, obj, &GUIClass, argv);
if (! gui)
return JS_FALSE;
try
{
CStr name = ToPrimitive<CStr>(cx, argv[0]);
IGUIObject* guiObj = gui->FindObjectByName(name);
if (guiObj)
*rval = OBJECT_TO_JSVAL(guiObj->GetJSObject());
else
*rval = JSVAL_NULL;
return JS_TRUE;
}
catch (PSERROR_Scripting&)
{
return JS_FALSE;
}
}
JSFunctionSpec GUIClassFunctions[] = {
{ "getGUIObjectByName", GetGUIObjectByName, 1, 0, 0 },
{ NULL }
};
void CGUI::ScriptingInit()
{
JSI_IGUIObject::init();
JSI_GUITypes::init();
g_ScriptingHost.DefineCustomObjectType(&GUIClass, NULL, 0, NULL, GUIClassFunctions, NULL, NULL);
}
InReaction CGUI::HandleEvent(const SDL_Event_* ev)
@ -383,10 +347,9 @@ CGUI::CGUI() : m_MouseButtons(0), m_FocusedObject(NULL), m_InternalNameNumber(0)
m_BaseObject->SetGUI(this);
// Construct the parent object for all GUI JavaScript things
m_ScriptObject = JS_NewObject(g_ScriptingHost.getContext(), &GUIClass, NULL, NULL);
m_ScriptObject = JS_NewObject(g_ScriptingHost.getContext(), NULL, g_ScriptingHost.GetGlobalObject(), NULL);
debug_assert(m_ScriptObject != NULL); // How should it handle errors?
JS_AddRoot(g_ScriptingHost.getContext(), &m_ScriptObject);
JS_SetPrivate(g_ScriptingHost.getContext(), m_ScriptObject, this);
}
CGUI::~CGUI()
@ -398,8 +361,6 @@ CGUI::~CGUI()
if (m_ScriptObject)
{
// Make sure it doesn't have dangling references to this CGUI
JS_SetPrivate(g_ScriptingHost.getContext(), m_ScriptObject, NULL);
// Let it be garbage-collected
JS_RemoveRoot(g_ScriptingHost.getContext(), &m_ScriptObject);
}

View file

@ -166,6 +166,10 @@ void CGUIManager::LoadPage(SGUIPage& page)
page.gui->LoadXmlFile(path, page.inputs);
}
// Remember this GUI page, in case the scripts call FindObjectByName
shared_ptr<CGUI> oldGUI = m_CurrentGUI;
m_CurrentGUI = page.gui;
page.gui->SendEventToAll("load");
// Call the init() function
@ -173,6 +177,8 @@ void CGUIManager::LoadPage(SGUIPage& page)
{
LOGERROR(L"GUI page '%ls': Failed to call init() function", page.name.c_str());
}
m_CurrentGUI = oldGUI;
}
LibError CGUIManager::ReloadChangedFiles(const VfsPath& path)
@ -243,7 +249,12 @@ SGUIIcon CGUIManager::GetIcon(const CStr& str) const
IGUIObject* CGUIManager::FindObjectByName(const CStr& name) const
{
return top()->FindObjectByName(name);
// This can be called from scripts run by TickObjects,
// and we want to return it the same GUI page as is being ticked
if (m_CurrentGUI)
return m_CurrentGUI->FindObjectByName(name);
else
return top()->FindObjectByName(name);
}
void CGUIManager::SendEventToAll(const CStr& eventName)
@ -257,7 +268,11 @@ void CGUIManager::TickObjects()
PageStackType pageStack = m_PageStack;
for (PageStackType::iterator it = pageStack.begin(); it != pageStack.end(); ++it)
{
m_CurrentGUI = it->gui;
it->gui->TickObjects();
}
m_CurrentGUI.reset();
}
void CGUIManager::Draw()

View file

@ -122,6 +122,8 @@ private:
typedef std::vector<SGUIPage> PageStackType;
PageStackType m_PageStack;
shared_ptr<CGUI> m_CurrentGUI; // used to latch state during TickObjects/LoadPage (this is kind of ugly)
ScriptInterface& m_ScriptInterface;
};

View file

@ -445,7 +445,7 @@ void IGUIObject::RegisterScriptHandler(const CStr& Action, const CStr& Code, CGU
// Generate a unique name
static int x=0;
char buf[64];
sprintf_s(buf, ARRAY_SIZE(buf), "__eventhandler%d", x++);
sprintf_s(buf, ARRAY_SIZE(buf), "__eventhandler%d (%s)", x++, Action.c_str());
JSFunction* func = JS_CompileFunction(g_ScriptingHost.getContext(), pGUI->m_ScriptObject,
buf, paramCount, paramNames, Code.c_str(), Code.length(), CodeName, 0);
@ -484,7 +484,7 @@ void IGUIObject::ScriptEvent(const CStr& Action)
jsval guiObject = PRIVATE_TO_JSVAL(this);
// Make a 'this', allowing access to the IGUIObject
JSObject* jsGuiObject = JS_ConstructObjectWithArguments(g_ScriptingHost.getContext(), &JSI_IGUIObject::JSI_class, NULL, m_pGUI->m_ScriptObject, 1, &guiObject);
JSObject* jsGuiObject = JS_ConstructObjectWithArguments(g_ScriptingHost.getContext(), &JSI_IGUIObject::JSI_class, m_pGUI->m_ScriptObject, NULL, 1, &guiObject);
debug_assert(jsGuiObject); // TODO: Handle errors
// Prevent it from being garbage-collected before it's passed into the function
@ -495,7 +495,7 @@ void IGUIObject::ScriptEvent(const CStr& Action)
mouseParams[0] = INT_TO_JSVAL(m_pGUI->m_MousePos.x);
mouseParams[1] = INT_TO_JSVAL(m_pGUI->m_MousePos.y);
mouseParams[2] = INT_TO_JSVAL(m_pGUI->m_MouseButtons);
JSObject* mouseObj = JS_ConstructObjectWithArguments(g_ScriptingHost.getContext(), &JSI_GUIMouse::JSI_class, NULL, m_pGUI->m_ScriptObject, 3, mouseParams);
JSObject* mouseObj = JS_ConstructObjectWithArguments(g_ScriptingHost.getContext(), &JSI_GUIMouse::JSI_class, m_pGUI->m_ScriptObject, NULL, 3, mouseParams);
debug_assert(mouseObj); // TODO: Handle errors
// Don't garbage collect the mouse

View file

@ -336,14 +336,6 @@ static void InitScripting()
new ScriptingHost;
RegisterJavascriptInterfaces();
#define REG_JS_CONSTANT(_name) g_ScriptingHost.DefineConstant(#_name, _name)
REG_JS_CONSTANT(SDL_BUTTON_LEFT);
REG_JS_CONSTANT(SDL_BUTTON_MIDDLE);
REG_JS_CONSTANT(SDL_BUTTON_RIGHT);
REG_JS_CONSTANT(SDL_BUTTON_WHEELUP);
REG_JS_CONSTANT(SDL_BUTTON_WHEELDOWN);
#undef REG_JS_CONSTANT
}

View file

@ -35,6 +35,8 @@
#include "graphics/UnitManager.h"
#include "graphics/scripting/JSInterface_Camera.h"
#include "graphics/scripting/JSInterface_LightEnv.h"
#include "gui/GUIManager.h"
#include "gui/IGUIObject.h"
#include "lib/timer.h"
#include "lib/svn_revision.h"
#include "lib/frequency_filter.h"
@ -61,7 +63,6 @@
#define LOG_CATEGORY L"script"
extern bool g_TerrainModified;
// rationale: the function table is now at the end of the source file to
// avoid the need for forward declarations for every function.
@ -404,6 +405,23 @@ JSBool SetCameraTarget( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval*
return( JS_TRUE );
}
JSBool GetGUIObjectByName(JSContext* cx, JSObject* UNUSED(obj), uintN UNUSED(argc), jsval* argv, jsval* rval)
{
try
{
CStr name = ToPrimitive<CStr>(cx, argv[0]);
IGUIObject* guiObj = g_GUI->FindObjectByName(name);
if (guiObj)
*rval = OBJECT_TO_JSVAL(guiObj->GetJSObject());
else
*rval = JSVAL_NULL;
return JS_TRUE;
}
catch (PSERROR_Scripting&)
{
return JS_FALSE;
}
}
//-----------------------------------------------------------------------------
// Miscellany
@ -645,6 +663,7 @@ JSFunctionSpec ScriptFunctionTable[] =
JS_FUNC("getCursorName", GetCursorName, 0)
JS_FUNC("getFPS", GetFps, 0)
JS_FUNC("isGameRunning", isGameRunning, 0)
JS_FUNC("getGUIObjectByName", GetGUIObjectByName, 1)
// Miscellany
JS_FUNC("v3dist", ComputeDistanceBetweenTwoPoints, 2)

View file

@ -29,79 +29,24 @@
#define LOG_CATEGORY L"scriptinghost"
namespace
{
const int RUNTIME_MEMORY_ALLOWANCE = 16 * 1024 * 1024;
const int STACK_CHUNK_SIZE = 16 * 1024;
JSClass GlobalClass =
{
"global", JSCLASS_GLOBAL_FLAGS,
JS_PropertyStub, JS_PropertyStub,
JS_PropertyStub, JS_PropertyStub,
JS_EnumerateStub, JS_ResolveStub,
JS_ConvertStub, JS_FinalizeStub
};
}
ScriptingHost::ScriptingHost()
: m_RunTime(NULL), m_Context(NULL), m_GlobalObject(NULL)
{
m_RunTime = JS_NewRuntime(RUNTIME_MEMORY_ALLOWANCE);
if(!m_RunTime)
m_ScriptInterface = new ScriptInterface("Engine");
m_Context = m_ScriptInterface->GetContext();
m_GlobalObject = JS_GetGlobalObject(m_Context);
if (!JS_DefineFunctions(m_Context, m_GlobalObject, ScriptFunctionTable))
throw PSERROR_Scripting_SetupFailed();
m_Context = JS_NewContext(m_RunTime, STACK_CHUNK_SIZE);
if(!m_Context)
if (!JS_DefineProperties(m_Context, m_GlobalObject, ScriptGlobalTable))
throw PSERROR_Scripting_SetupFailed();
// JS_SetGCZeal(m_Context, 2);
JS_SetErrorReporter(m_Context, ScriptingHost::ErrorReporter);
JS_SetVersion(m_Context, JSVERSION_LATEST);
JS_BeginRequest(m_Context);
m_GlobalObject = JS_NewObject(m_Context, &GlobalClass, NULL, NULL);
if(!m_GlobalObject)
throw PSERROR_Scripting_SetupFailed();
#ifndef NDEBUG
// Register our script and function handlers - note: docs say they don't like
// nulls passed as closures, nor should they return nulls.
JS_SetExecuteHook( m_RunTime, jshook_script, this );
JS_SetCallHook( m_RunTime, jshook_function, this );
#endif
if (JS_InitStandardClasses(m_Context, m_GlobalObject) == JSVAL_FALSE)
throw PSERROR_Scripting_SetupFailed();
if (JS_DefineFunctions(m_Context, m_GlobalObject, ScriptFunctionTable) == JS_FALSE)
throw PSERROR_Scripting_SetupFailed();
if( JS_DefineProperties( m_Context, m_GlobalObject, ScriptGlobalTable ) == JS_FALSE )
throw PSERROR_Scripting_SetupFailed();
m_ScriptInterface = new ScriptInterface("Engine", m_Context);
}
ScriptingHost::~ScriptingHost()
{
delete m_ScriptInterface;
if (m_Context != NULL)
{
JS_EndRequest(m_Context);
JS_DestroyContext(m_Context);
m_Context = NULL;
}
if (m_RunTime != NULL)
{
JS_DestroyRuntime(m_RunTime);
m_RunTime = NULL;
}
}
ScriptInterface& ScriptingHost::GetScriptInterface()
@ -306,77 +251,3 @@ jsval ScriptingHost::UCStringToValue( const CStrW& str )
{
return STRING_TO_JSVAL(JS_NewUCStringCopyZ(m_Context, str.utf16().c_str()));
}
//----------------------------------------------------------------------------
// called by SpiderMonkey whenever someone does JS_ReportError.
// prints that message as well as locus to log, debug output and console.
void ScriptingHost::ErrorReporter(JSContext* UNUSED(cx), const char* pmessage, JSErrorReport* report)
{
const char* file = report->filename? report->filename : "(current document)";
int line = report->lineno;
const char* message = pmessage? pmessage : "No error message available";
// apparently there is no further information in this struct we can use
// because linebuf/tokenptr require a buffer to have been allocated.
// that doesn't look possible since we are a callback and there is
// no mention in the docs about where this would happen (typical).
// for developer convenience: write to output window so they can
// double-click on that line and be taken to the error locus.
debug_printf(L"%hs(%d): %hs\n", file, line, message);
// note: CLogger's LOG already takes care of writing to the console,
// so don't do that here.
LOG(CLogger::Error, LOG_CATEGORY, L"JavaScript Error (%hs, line %d): %hs", file, line, message);
}
#ifndef NDEBUG
void* ScriptingHost::jshook_script( JSContext* UNUSED(cx), JSStackFrame* UNUSED(fp),
JSBool before, JSBool* UNUSED(ok), void* closure )
{
if (!CProfileManager::IsInitialised())
return closure;
if( before )
{
g_Profiler.StartScript( "script invocation" );
}
else
g_Profiler.Stop();
return( closure );
}
void* ScriptingHost::jshook_function( JSContext* cx, JSStackFrame* fp, JSBool before, JSBool* UNUSED(ok), void* closure )
{
if (!CProfileManager::IsInitialised())
return closure;
JSFunction* fn = JS_GetFrameFunction( cx, fp );
if( before )
{
if( fn )
{
g_Profiler.StartScript( JS_GetFunctionName( fn ) );
}
else
g_Profiler.StartScript( "function invocation" );
}
else
g_Profiler.Stop();
return( closure );
}
#endif

View file

@ -65,7 +65,6 @@ private:
JSClass * m_Class;
};
JSRuntime * m_RunTime;
JSContext * m_Context;
JSObject * m_GlobalObject;
@ -73,13 +72,6 @@ private:
std::map < std::string, CustomType > m_CustomObjectTypes;
#ifndef NDEBUG
// A hook to capture script calls
static void* jshook_script( JSContext* cx, JSStackFrame* fp, JSBool before, JSBool* ok, void* closure );
// A hook to capture function calls
static void* jshook_function( JSContext* cx, JSStackFrame* fp, JSBool before, JSBool* ok, void* closure );
#endif
// The long-term plan is to migrate from ScriptingHost to the newer shinier ScriptInterface.
// For now, just have a ScriptInterface that hooks onto the ScriptingHost's context so they
// can both be used.
@ -126,8 +118,6 @@ public:
std::string ValueToString(const jsval value);
CStrW ValueToUCString(const jsval value);
jsval UCStringToValue(const CStrW& str);
static void ErrorReporter(JSContext * context, const char * message, JSErrorReport * report);
};
#define g_ScriptingHost ScriptingHost::GetSingleton()