bool JsObjectWrapper::invokeDefault(const NPVariant* args, unsigned argCount, NPVariant* result) { if(argCount < 1) { Debug::println("JsObjectWrapper::invokeDefault> argCount < 1: %d", argCount); return false; } if(!NPVARIANT_IS_OBJECT(args[0])) { Debug::println("JsObjectWrapper::invokeDefault> args[0] not an object"); return false; } NPObject* pArray = NPVARIANT_TO_OBJECT(args[0]); Variant varRet; if(!NPN_GetProperty(getNPP(), pArray, m_agent->methods.length, varRet.ptr())) { Debug::println("JsObjectWrapper::invokeDefault> get length failed"); return false; } if(!NPVARIANT_IS_INT32(varRet.get())) { Debug::println("JsObjectWrapper::invokeDefault> length did not return an int"); return false; } int len = NPVARIANT_TO_INT32(varRet.get()); VariantArray varArgs(len); for(int i = 0; i < len; i++) { NPIdentifier id = NPN_GetIntIdentifier(i); Variant varItem; if(!NPN_GetProperty(getNPP(), pArray, id, varArgs[i].ptr())) { Debug::println("JsObjectWrapper::invokeDefault> get [%d] failed", i); return false; } } Debug::println("JsObjectWrapper::invokeDefault"); if(!m_agent->invokeRemoteDelegate(m_targetId, varArgs.get(), len, result)) { Debug::println("JsObjectWrapper::invokeDefault> invokeRemoteDelegate() failed"); return false; } return true; }
STDMETHODIMP CJavaObject::InvokeEx(DISPID dispidMember, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, IServiceProvider* pspCaller) { Debug::log(Debug::Debugging) << "Invoking " << dispidMember << " on Java object " << objId << Debug::flush; if (!sessionData) { // Prevent errors if the object is retained post-disconnect Debug::log(Debug::Warning) << "JavaObject retained beyound session shutdown" << Debug::flush; return DISP_E_MEMBERNOTFOUND; } HostChannel* channel = sessionData->getHostChannel(); Value thisRef = Value(); thisRef.setJavaObject(objId); if ((wFlags & DISPATCH_PROPERTYGET) && dispidMember == DISPID_VALUE && pdispparams->cArgs - pdispparams->cNamedArgs == 0) { // This is an expression like ('' + obj) // raw toString(); wFlags = DISPATCH_METHOD; dispidMember = DISPID_TOSTRING; } if (wFlags & DISPATCH_METHOD) { Debug::log(Debug::Spam) << "Dispatching method " << dispidMember << " on " << objId << Debug::flush; if (!(dispidMember == DISPID_VALUE || dispidMember == DISPID_TOSTRING)) { Debug::log(Debug::Error) << "Cannot dispatch for non-default id: " << dispidMember << Debug::flush; return E_FAIL; } scoped_array<Value> args; Value javaDispatchId; int numArgs; if (dispidMember == DISPID_VALUE) { numArgs = pdispparams->cArgs - pdispparams->cNamedArgs - 2; if (numArgs < 0) { // Indicates an error in JSNI rewriting or dispatch code Debug::log(Debug::Error) << "Insufficient number of arguments" << Debug::flush; return E_FAIL; } args.reset(new Value[numArgs]); // The dispatch parameters are backwards sessionData->makeValue(javaDispatchId, pdispparams->rgvarg[pdispparams->cArgs - 1]); sessionData->makeValue(thisRef, pdispparams->rgvarg[pdispparams->cArgs - 2]); for (int i = 0; i < numArgs; i++) { int index = pdispparams->cArgs - 3 - i; VARIANTARG element = pdispparams->rgvarg[index]; sessionData->makeValue(args[i], element); } } else if (dispidMember == DISPID_TOSTRING) { // raw toString(); numArgs = 0; javaDispatchId.setInt(0); } bool isException = false; Value returnValue; if (!InvokeMessage::send(*channel, thisRef, javaDispatchId.getInt(), numArgs, args.get())) { Debug::log(Debug::Error) << "Unable to send method invocation" << Debug::flush; } else { scoped_ptr<ReturnMessage> m(channel->reactToMessagesWhileWaitingForReturn( sessionData->getSessionHandler())); if (!m.get()) { Debug::log(Debug::Error) << "Did not receive ReturnMessage" << Debug::flush; } else { if (dispidMember == DISPID_TOSTRING) { // raw toString(); if (pvarResult) { // This will be NULL when the caller doesn't care about the return value _variant_t returnVariant; sessionData->makeValueRef(returnVariant, m->getReturnValue()); *pvarResult = returnVariant.Detach(); } return m->isException() ? E_FAIL : S_OK; } isException = m->isException(); returnValue = m->getReturnValue(); } } DISPID dispId; HRESULT hr = IEUtils::resolveName(sessionData->getWindow(), Constants::__gwt_makeResult, &dispId); if (FAILED(hr)) { Debug::log(Debug::Error) << "Unable to get dispId for __gwt_makeResult" << Debug::flush; return E_FAIL; } // Call __gwt_makeResult(isException, returnValue) scoped_array<_variant_t> varArgs(new _variant_t[2]); // Args go backwards. varArgs[1] = (isException ? 1 : 0); sessionData->makeValueRef(varArgs[0], returnValue); DISPPARAMS dispParams = {varArgs.get(), NULL, 2, 0}; CComPtr<IDispatchEx> dispEx; sessionData->getWindow()->QueryInterface(&dispEx); return dispEx->InvokeEx(dispId, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispParams, pvarResult, pexcepinfo, pspCaller); } else if (wFlags & DISPATCH_PROPERTYGET) { Debug::log(Debug::Spam) << "Getting property " << dispidMember << " on " << objId << Debug::flush; if (dispidMember == DISPID_VALUE) { this->QueryInterface(IID_IDispatch, (void**)&pvarResult->pdispVal); pvarResult->vt = VT_DISPATCH; } else if (dispidMember == DISPID_TOSTRING) { // Asking for a tear-off of the .toString function Debug::log(Debug::Spam) << "Making .toString tearoff" << Debug::flush; // Get a reference to __gwt_makeTearOff DISPID tearOffDispid; HRESULT hr = IEUtils::resolveName(sessionData->getWindow(), Constants::__gwt_makeTearOff, &tearOffDispid); if (FAILED(hr)) { Debug::log(Debug::Error) << "Unable to find __gwt_makeTearOff" << Debug::flush; return E_FAIL; } scoped_array<_variant_t> tearOffArgs(new _variant_t[3]); // Parameters are backwards: // __gwt_makeTearOff(proxy, dispId, argCount); tearOffArgs[2] = this; // proxy tearOffArgs[1] = 0; // dispId tearOffArgs[0] = 0; // argCount DISPPARAMS tearOffParams = {tearOffArgs.get(), NULL, 3, 0}; // Invoke __gwt_makeTearOff hr = IEUtils::Invoke(sessionData->getWindow(), tearOffDispid,DISPATCH_METHOD, &tearOffParams, pvarResult, NULL, 0); if (FAILED(hr)) { Debug::log(Debug::Error) << "Unable to invoke __gwt_makeTearOff" << Debug::flush; return E_FAIL; } } else { Value ret = ServerMethods::getProperty(*channel, sessionData->getSessionHandler(), objId, dispidMember); if (ret.isUndefined()) { Debug::log(Debug::Error) << "Undefined get from Java object" << Debug::flush; return E_FAIL; } _variant_t returnVariant; sessionData->makeValueRef(returnVariant, ret); *pvarResult = returnVariant.Detach(); } } else if (wFlags & (DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF)) { Debug::log(Debug::Spam) << "Setting property " << dispidMember << " on " << objId << Debug::flush; Value value; sessionData->makeValue(value, pdispparams->rgvarg[0]); ServerMethods::setProperty(*channel, sessionData->getSessionHandler(), objId, dispidMember, value); } else { Debug::log(Debug::Error) << "Unsupported invocation " << wFlags << Debug::flush; return DISP_E_MEMBERNOTFOUND; } return S_OK; }