o = new ActiveXObject("Test.MyControl"); o.OnStateChanged = MyEventHandler;
I figured this would be pretty simple -- just implement an ActiveX control with connection points. Unfortunately, it doesn't work. Internet Explorer complains thus:
1) Implement a property in the ActiveX control that accepts an IDispatch pointer.
STDMETHODIMP CTestCtrl::putref_OnStateChanged(IDispatch* newVal) STDMETHODIMP CTestCtrl::get_OnStateChanged(IDispatch** pVal)
2) Get the DISPID of the "call" method by calling GetIDsOfNames like so:
newVal->GetIDsOfNames(IID_NULL, &szMember, 1, LOCALE_SYSTEM_DEFAULT, pDispId))
3) When you want to invoke the event, construct a VARIANTARG containing the parameters you want to pass to the event in reverse order. Add a pointer to your own IDispatch implementation as the last element in the array.
DISPPARAMS dispParams; VARIANTARG args; VariantInit(&args); args.vt = VT_BSTR; args.bstrVal = ::SysAllocString(L"The event says hello!"); IDispatch* pDisp; HRESULT hRes = this->QueryInterface(IID_IDispatch, (void**)&pDisp); VariantInit(&args); args.vt = VT_DISPATCH; args.pdispVal= pDisp; memset(&dispParams, 0, sizeof(dispParams)); dispParams.rgvarg = args; dispParams.cArgs = sizeof(args)/sizeof(args); EXCEPINFO excepinfo; UINT uArgErr; pEventHandler->Invoke(*pDispId, IID_NULL, LOCALE_SYSTEM_DEFAULT, DISPATCH_METHOD, &dispParams, NULL, &excepinfo, &uArgErr);
4) Clean up when you're done by calling VariantClear on both elements of the args array.