Skip navigation

Tag Archives: C++

Today We’ll implement a javascript callback interface in C++.

We’re targetting a browser plugin (Which already has a “one way” js interface).
The idea : we want the plugin to trigger javascript methods, and ultimately we want to be able to link any js code to our plugin events loop.

Note:This article requires some c++/Win32 api/netscape api skills as well as a tiny clue of what is discussed here…

When coding cross platform software , you’ll often have to write some parts of your plugin twice. (sometimes more than twice)
In this case, MS activex com objects aren’t handled the way nsi controls are, so we need to split the code.

our method(s) should have an input parameter, “name” that we will use to store our javascript function name we want to trigger.

so something like : return Our_JS_CallBack(const char * name)

when called from the plugin, this method will send client’s browser a js event that will spawn our function which name is has been inputed at call.

Please be carefull here : ClientSite and ClientInstance are declared and initialised out of this 2 functions.
both of these pointers should have a correct value before using ::Our_JS_CallBack

MicroSoft CODE: m_spClientSite is a pointer to oleclientsite of your plugin ( type : ComPtr )
NetScape CODE: ClientInstance is the netscape NPP object pointer for your plugin (type : NPP);

Microsoft style:

//————————————————————————–
HRESULT Plugin::Our_JS_CallBack(const char * name)
{
IOleClientSite *m_spClientSite = (IOleClientSite *)GetCClientSite();

IServiceProvider* isp;
IWebBrowser2* ppBrowser;

HRESULT hr = m_spClientSite->QueryInterface(IID_IServiceProvider, reinterpret_cast(&isp));
if(FAILED(hr)) return FALSE;

hr = isp->QueryService(IID_IWebBrowserApp, IID_IWebBrowser2, reinterpret_cast(&ppBrowser));
if(NULL==ppBrowser) return S_FALSE;

IDispatch *m_ppDispDoc;
hr = ppBrowser->get_Document(&m_ppDispDoc);
if(FAILED(hr)) return S_FALSE;

IHTMLDocument2 *ppDocument2;
hr = m_ppDispDoc->QueryInterface(IID_IHTMLDocument2 ,reinterpret_cast(&ppDocument2));
if(FAILED(hr)) return S_FALSE;

CComPtr scriptEngine;
ppDocument2->get_Script(&scriptEngine);

DISPID callid;
USES_CONVERSION;
OLECHAR FAR* szCallMember = T2OLE(name);
HRESULT hr3 = scriptEngine->GetIDsOfNames(IID_NULL, &szCallMember, 1, LOCALE_USER_DEFAULT, &callid);
DISPPARAMS callParameters = { 0 };
int nargs = 0;
callParameters.cArgs = nargs + 1;

CComPtr win;
ppDocument2->get_parentWindow(&win);

VARIANT *vargs= new VARIANT[nargs + 1];
VARIANT result;

vargs[nargs] = CComVariant(win);
long index;
callParameters.rgvarg = vargs;
EXCEPINFO exception;

HRESULT hr4 = scriptEngine->Invoke(callid, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &callParameters, &result, &exception, 0);

return S_OK;
}

NetScape Style:

NPBool NSPlugin::Our_JS_CallBack(const char *name)
{
NPObject *window;
NPN_GetValue(ClientInstance, NPNVWindowNPObject, &window);
NPIdentifier methodName;
methodName= NPN_GetStringIdentifier(name);
uint32_t argCount=0;
NPVariant result;
NPN_Invoke( NsInstance,
window,
methodName,
NULL,
argCount,
&result);
return TRUE;
}

You ‘ll have to declare both methods in your plugin class and be carefull not to call Our_JS_CallBack in a loop !

ie (c++ code): instance->Our_JS_CallBack(“JSEvent”);

you can then go to your HTML code after plugin’s instanciation, and write down the body of your callback

function JSEvent()
{
alert(“well done!”)
}

when the plugin executes instance->Our_JS_CallBack(“JSEvent”), a nice alert box should appear on client side, validating the javascript callback.

The hard part was understanding the concept and digging msdn 🙂