Print Article
Add to your CodeProject bookmarks
Comment on this article
Report this article as inappropriate
Creating Javascript Arrays and other objects from C++How to create Javascript Arrays and other objects from C++ code and pass them to the script.
IntroductionJavascript has some built-in classes like How does it work?To create new instances you would usually write Javascript code like: var o = new Array();
If you host JScript in a C++ application (by using the scripting host directly or by using the WebBrowser-control to display a website with Javascript code embedded) you can't simply call The following happens when you use the
After these steps you will have your Obtain the scripting objectThere are usually two situations, where you have to deal with Javascript from your C++ application. One is, that you host a WebBrowser-control to display HTML pages, the second is that you use the JScript scripting host directly. In the second case you will have some // pScriptEngine is of type IActiveScript
// SCRIPT_ITEMNAME is the name you specified in IActiveScript::AddNamedItem
// can be NULL to retreive the the object containing all global members
CComPtr<IDispatch> pScriptDisp;
HRESULT hr = pScriptEngine->GetScriptDispatch(SCRIPT_ITEMNAME, &pScriptDisp);
if (FAILED(hr))
return hr;
// pScriptDisp is now the scripting object
If you host a WebBrowser-control you will have a // spBrowser is of type IHTMLWindow2
CComPtr<IDispatch> spDoc;
hr = spBrowser->get_Document(&spDoc);
if (FAILED(hr))
return hr;
CComQIPtr<IHTMLDocument2> spHTMLDoc(spDoc);
if (!spHTMLDoc)
return E_NOINTERFACE;
CComPtr<IHTMLWindow2> spWindow;
hr = spHTMLDoc->get_parentWindow(&spWindow);
if (FAILED(hr))
return hr;
CComQIPtr<IDispatch> pScriptDisp(spWindow);
if (!pScriptDisp)
return E_NOINTERFACE;
// pScriptDisp should now be scripting object
Obtaining the object constructorUsing the function doSomething()
{
// ...
}
you add a property of type If you then construct a new instance by saying // get DISPID for "Array"
DISPID did = 0;
LPOLESTR lpNames = {L"Array"};
hr = pScriptDisp->GetIDsOfNames(IID_NULL, lpNames, 1, LOCALE_USER_DEFAULT, &did);
if (FAILED(hr))
return hr;
// invoke pScriptDisp with DISPATCH_PROPERTYGET for "Array"
CComVariant vtRet;
DISPPARAMS params = {0};
CComVariant vtResult;
hr = pScriptDisp->Invoke(did, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, ¶ms
, &vtResult, NULL, NULL);
if (FAILED(hr))
return hr;
// vtResult should be of type VT_DISPATCH and contain the creator for Array
Now we have something like a creator for // get IDispatchEx on returned IDispatch
CComQIPtr<IDispatchEx> creator(vtResult.pdispVal);
if (!creator)
return E_NOINTERFACE;
The HRESULT InvokeEx(
DISPID id,
LCID lcid,
WORD wFlags,
DISPARAMS *pdp,
VARIANT *pVarRes,
EXCEPINFO *pei,
IServiceProvider *pspCaller
);
Using // creator is of type IDispatchEx
DISPPARAMS params = {0};
CComVariant vtResult;
HRESULT hr = creator->InvokeEx(DISPID_VALUE, LOCALE_USER_DEFAULT, DISPATCH_CONSTRUCT
, ¶ms, &vtResult, NULL, NULL);
// vtResult should contain the newly created object
If everything went well you have the newly created object now, weather it is a built-in-object or some object you defined in Javascript. Yes, of course you can also construct objects you defined in your js-code function MyObject()
{
this.foo = "bar";
}
by asking for a property named "MyObject". And that's more ore less all. Oh, yes, you might want to pass some parameters to your constructor. Use the Adding valuesIf you created a new HRESULT GetDispID(
BSTR bstrName,
DWORD grfdex,
DISPID *pid
);
This property doesn't exist yet. To create it pass the flag // theObject is of type IDispatchEx and is the js-Array
DISPID did = 0;
hr = theObject->GetDispID(CComBSTR(L"0"), fdexNameEnsure, &did);
if (FAILED(hr))
return hr;
CComVariant data(_T("bar"));
DISPID namedArgs = {DISPID_PROPERTYPUT};
DISPPARAMS params = {&data, namedArgs, 1, 1};
hr = theObject->InvokeEx(did, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, ¶ms,
NULL, NULL, NULL);
As you can see the Putting it all together our HRESULT CJsArrayView::PutJsArray(LPOLESTR lpsName, CAtlVariantArray& data)
{
// get script dispatch
CComPtr<IDispatch> scriptDispatch;
HRESULT hr = GetScriptDispatch(&scriptDispatch);
if (FAILED(hr))
return hr;
ATLASSERT(scriptDispatch);
// get DISPID for "Array"
DISPID did = 0;
LPOLESTR lpNames = {L"Array"};
hr = scriptDispatch->GetIDsOfNames(IID_NULL, lpNames, 1, LOCALE_USER_DEFAULT, &did);
if (FAILED(hr))
return hr;
// invoke scriptdispatch with DISPATCH_PROPERTYGET for "Array"
CComVariant vtRet;
DISPPARAMS params = {0};
CComVariant vtResult;
hr = scriptDispatch->Invoke(did, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYGET, ¶ms, &vtResult, NULL, NULL);
if (FAILED(hr))
return hr;
// check result: should be a VT_DISPATCH
if ((VT_DISPATCH != vtResult.vt) (NULL == vtResult.pdispVal))
return DISP_E_TYPEMISMATCH;
// get IDispatchEx on returned IDispatch
CComQIPtr<IDispatchEx> prototype(vtResult.pdispVal);
if (!prototype)
return E_NOINTERFACE;
// call InvokeEx with DISPID_VALUE and DISPATCH_CONSTRUCT to construct new array
vtResult.Clear();
hr = prototype->InvokeEx(DISPID_VALUE, LOCALE_USER_DEFAULT, DISPATCH_CONSTRUCT, ¶ms, &vtResult, NULL, NULL);
if (FAILED(hr))
return hr;
// vtresult should contain the new array now.
if ((VT_DISPATCH != vtResult.vt) (NULL == vtResult.pdispVal))
return DISP_E_TYPEMISMATCH;
// get IDispatchEx on returned IDispatch
CComQIPtr<IDispatchEx> theObject(vtResult.pdispVal);
if (!theObject)
return E_NOINTERFACE;
// add values by invoking InvokeEx
CString sName;
for(size_t n = 0; n < data.GetCount(); n++)
{
sName.Format(_T("%i"), n);
hr = theObject->GetDispID(CComBSTR(sName), fdexNameEnsure, &did);
if (FAILED(hr))
break;
DISPID namedArgs = {DISPID_PROPERTYPUT};
DISPPARAMS p = {&data[n], namedArgs, 1, 1};
hr = theObject->InvokeEx(did, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, &p, NULL, NULL, NULL);
if (FAILED(hr))
break;
}
// now call the js-function in lpsName with the array as parameter
params.cArgs = 1;
params.rgvarg = &vtResult;
hr = CallJs(scriptDispatch, lpsName, ¶ms);
return hr;
}
The sample codeThe ZIP contains a sample project based on WTL and ATL. All the important code is contained in the view class LicenseThis article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL) About the Author
Comments and Discussions
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||