+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Case Insensitive Map of Event names to eventTypes
+// created dynamically at run time in:
+// EVT_ACTIVEX(eventName, id, fn)
+// we map the pointer to them so that:
+// const wxEventType& RegisterActiveXEvent(wxString eventName);
+// can return a const reference, which is neccessary for event tables
+// probably should use a wxWindows hash table here, but I'm lazy ...
+struct less_wxStringI
+{
+ bool operator()(const wxString& x, const wxString& y) const
+ {
+ return x.CmpNoCase(y) < 0;
+ };
+};
+
+typedef map<wxString, wxEventType *, less_wxStringI> ActiveXEventMap;
+static ActiveXEventMap sg_eventMap;
+
+// one off class for automatic freeing of activeX eventtypes
+class ActiveXEventMapFlusher
+{
+public:
+ ~ActiveXEventMapFlusher()
+ {
+ ActiveXEventMap::iterator it = sg_eventMap.end();
+ while (it != sg_eventMap.end())
+ {
+ delete it->second;
+ it++;
+ };
+ };
+};
+
+static ActiveXEventMapFlusher s_dummyActiveXEventMapFlusher;
+
+const wxEventType& RegisterActiveXEvent(wxChar *eventName)
+{
+ wxString ev = eventName;
+ ActiveXEventMap::iterator it = sg_eventMap.find(ev);
+ if (it == sg_eventMap.end())
+ {
+ wxEventType *et = new wxEventType(wxNewEventType());
+ sg_eventMap[ev] = et;
+
+ return *et;
+ };
+
+ return *(it->second);
+};
+
+//////////////////////////////////////////////////////
+bool MSWVariantToVariant(VARIANTARG& va, wxVariant& vx)
+{
+ switch(va.vt)
+ {
+ case VT_VARIANT | VT_BYREF:
+ return MSWVariantToVariant(*va.pvarVal, vx);
+
+ case VT_I2:
+ case VT_I4:
+ vx = (long) va.iVal;
+ return true;
+
+ case VT_I2 | VT_BYREF:
+ case VT_I4 | VT_BYREF:
+ vx = (long) *va.piVal;
+ return true;
+
+ case VT_BSTR:
+ vx = wxString(va.bstrVal);
+ return true;
+
+ case VT_BSTR | VT_BYREF:
+ vx = wxString(*va.pbstrVal);
+ return true;
+
+ case VT_BOOL:
+ vx = (va.boolVal != FALSE);
+ return true;
+
+ case VT_BOOL | VT_BYREF:
+ vx = (*va.pboolVal != FALSE);
+ return true;
+
+ default:
+ vx.MakeNull();
+ return false;
+ };
+};
+
+bool VariantToMSWVariant(wxVariant& vx, VARIANTARG& va)
+{
+ switch(va.vt)
+ {
+ case VT_VARIANT | VT_BYREF:
+ return VariantToMSWVariant(vx, va);
+
+ case VT_I2:
+ case VT_I4:
+ va.iVal = (long) vx;
+ return true;
+
+ case VT_I2 | VT_BYREF:
+ case VT_I4 | VT_BYREF:
+ *va.piVal = (long) vx;
+ return true;
+
+ case VT_BOOL:
+ va.boolVal = ((bool) vx) ? TRUE : FALSE;
+ return true;
+
+ case VT_BOOL | VT_BYREF:
+ *va.pboolVal = ((bool) vx) ? TRUE : FALSE;
+ return true;
+
+ default:
+ return false;
+ };
+};
+
+class wxActiveXEvents : public IDispatch
+{
+private:
+ DECLARE_OLE_UNKNOWN(wxActiveXEvents);
+
+
+ wxActiveX *m_activeX;
+
+public:
+ wxActiveXEvents(wxActiveX *ax) : m_activeX(ax) {}
+ ~wxActiveXEvents()
+ {
+ }
+
+ //IDispatch
+ STDMETHODIMP GetIDsOfNames(REFIID r, OLECHAR** o, unsigned int i, LCID l, DISPID* d)
+ {
+ return E_NOTIMPL;
+ };
+
+ STDMETHODIMP GetTypeInfo(unsigned int i, LCID l, ITypeInfo** t)
+ {
+ return E_NOTIMPL;
+ };
+
+ STDMETHODIMP GetTypeInfoCount(unsigned int* i)
+ {
+ return E_NOTIMPL;
+ };
+
+
+
+ STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
+ WORD wFlags, DISPPARAMS * pDispParams,
+ VARIANT * pVarResult, EXCEPINFO * pExcepInfo,
+ unsigned int * puArgErr)
+ {
+ if (wFlags & (DISPATCH_PROPERTYGET | DISPATCH_PROPERTYPUT | DISPATCH_PROPERTYPUTREF))
+ return E_NOTIMPL;
+
+ // map dispid to name
+ wxActiveX::MemberIdList::iterator mid = m_activeX->m_eventsIdx.find((MEMBERID) dispIdMember);
+ if (mid == m_activeX->m_eventsIdx.end())
+ return S_OK;
+
+ int idx = mid->second;
+
+
+ wxActiveX::FuncX &func = m_activeX->m_events[idx];
+
+ ActiveXEventMap::iterator it = sg_eventMap.find(func.name);
+ if (it == sg_eventMap.end())
+ return S_OK;
+
+ wxActiveXEvent event;
+ event.SetId(m_activeX->GetId());
+ event.SetEventType(*(it->second));
+ event.m_params.NullList();
+
+ // arguments
+ if (pDispParams)
+ {
+ // cdecl call
+ for (int i = pDispParams->cArgs - 1; i >= 0; i--)
+ {
+ VARIANTARG& va = pDispParams->rgvarg[i];
+ wxActiveX::ParamX &px = func.params[pDispParams->cArgs - i - 1];
+ wxVariant vx;
+
+ MSWVariantToVariant(va, vx);
+ vx.SetName(px.name);
+ event.m_params.Append(vx);
+ };
+ };
+
+ if (func.hasOut)
+ {
+ m_activeX->GetParent()->ProcessEvent(event);
+ for (unsigned int i = 0; i < pDispParams->cArgs; i++)
+ {
+ VARIANTARG& va = pDispParams->rgvarg[i];
+ wxActiveX::ParamX &px = func.params[pDispParams->cArgs - i - 1];
+
+ if (px.IsOut())
+ {
+ wxVariant& vx = event.m_params[pDispParams->cArgs - i - 1];
+
+ VariantToMSWVariant(vx, va);
+ };
+ };
+ }
+ else
+ m_activeX->GetParent()->AddPendingEvent(event);
+
+ return S_OK;
+ }
+};
+
+
+DEFINE_OLE_TABLE(wxActiveXEvents)
+ OLE_IINTERFACE(IUnknown)
+ OLE_INTERFACE(IID_IDispatch, IDispatch)
+END_OLE_TABLE;
+
+
+int wxActiveXEvent::ParamCount() const
+{
+ return m_params.GetCount();
+};
+
+static wxVariant nullVar;
+
+wxVariant wxActiveXEvent::operator[] (int idx) const
+{
+ return (wxVariant&) operator[] (idx);
+};
+
+wxVariant& wxActiveXEvent::operator[] (int idx)
+{
+ wxASSERT(idx >= 0 && idx < ParamCount());
+
+ return m_params[idx];
+};
+
+wxVariant wxActiveXEvent::operator[] (wxString name) const
+{
+ return (wxVariant&) operator[] (name);
+};
+
+wxVariant& wxActiveXEvent::operator[] (wxString name)
+{
+ for (int i = 0; i < m_params.GetCount(); i++)
+ {
+ if (name.CmpNoCase(m_params[i].GetName()) == 0)
+ return m_params[i];
+ };
+
+ wxString err = "wxActiveXEvent::operator[] invalid name <" + name + ">";
+ err += "\r\nValid Names = :\r\n";
+ for (i = 0; i < m_params.GetCount(); i++)
+ {
+ err += m_params[i].GetName();
+ err += "\r\n";
+ };
+
+ wxASSERT_MSG(false, err);
+
+ return nullVar;
+};
+
+void wxActiveX::GetTypeInfo()
+{
+ /*
+ We are currently only interested in the IDispatch interface
+ to the control. For dual interfaces (TypeKind = TKIND_INTERFACE)
+ we should drill down through the inheritance
+ (using TYPEATTR->cImplTypes) and GetRefTypeOfImplType(n)
+ and retrieve all the func names etc that way, then generate a C++
+ header file for it.
+
+ But we don't do this and probably never will, so if we have a DUAL
+ interface then we query for the IDispatch
+ via GetRefTypeOfImplType(-1).
+ */
+
+ HRESULT hret = 0;
+
+ // get type info via class info
+ wxAutoOleInterface<IProvideClassInfo> classInfo(IID_IProvideClassInfo, m_ActiveX);
+ if (! classInfo.Ok())
+ return;
+
+ // type info
+ wxAutoOleInterface<ITypeInfo> typeInfo;
+ hret = classInfo->GetClassInfo(typeInfo.GetRef());
+ if (! typeInfo.Ok())
+ return;
+
+ // TYPEATTR
+ TYPEATTR *ta = NULL;
+ hret = typeInfo->GetTypeAttr(&ta);
+ if (! ta)
+ return;
+
+ // this should be a TKIND_COCLASS
+ wxASSERT(ta->typekind == TKIND_COCLASS);
+
+ // iterate contained interfaces
+ for (int i = 0; i < ta->cImplTypes; i++)
+ {
+ HREFTYPE rt = 0;
+
+ // get dispatch type info handle
+ hret = typeInfo->GetRefTypeOfImplType(i, &rt);
+ if (! SUCCEEDED(hret))
+ continue;
+
+ // get dispatch type info interface
+ wxAutoOleInterface<ITypeInfo> ti;
+ hret = typeInfo->GetRefTypeInfo(rt, ti.GetRef());
+ if (! ti.Ok())
+ continue;
+
+ // check if default event sink
+ bool defEventSink = false;
+ int impTypeFlags = 0;
+ typeInfo->GetImplTypeFlags(i, &impTypeFlags);
+
+ if (impTypeFlags & IMPLTYPEFLAG_FDEFAULT)
+ {
+ if (impTypeFlags & IMPLTYPEFLAG_FSOURCE)
+ {
+ WXOLE_TRACEOUT("Default Event Sink");
+ defEventSink = true;
+ }
+ else
+ {
+ WXOLE_TRACEOUT("Default Interface");
+ }
+ };
+
+
+ // process
+ GetTypeInfo(ti, defEventSink);
+ };
+
+
+ // free
+ typeInfo->ReleaseTypeAttr(ta);
+};
+
+void wxActiveX::GetTypeInfo(ITypeInfo *ti, bool defEventSink)
+{
+ ti->AddRef();
+ wxAutoOleInterface<ITypeInfo> typeInfo(ti);
+
+ // TYPEATTR
+ TYPEATTR *ta = NULL;
+ HRESULT hret = typeInfo->GetTypeAttr(&ta);
+ if (! ta)
+ return;
+
+ if (ta->typekind == TKIND_DISPATCH)
+ {
+ WXOLE_TRACEOUT("GUID = " << GetIIDName(ta->guid).c_str());
+
+ if (defEventSink)
+ {
+ wxActiveXEvents *disp = new wxActiveXEvents(this);
+ ConnectAdvise(ta->guid, disp);
+ };
+
+
+ // Get Function Names
+ for (int i = 0; i < ta->cFuncs; i++)
+ {
+ FUNCDESC FAR *fd = NULL;
+
+ hret = typeInfo->GetFuncDesc(i, &fd);
+ if (! fd)
+ continue;
+
+ BSTR anames[1] = {NULL};
+ unsigned int n = 0;
+
+ hret = typeInfo->GetNames(fd->memid, anames, 1, &n);
+
+ if (anames[0])
+ {
+ wxString name = anames[0];
+
+ WXOLE_TRACEOUT("Name " << i << " = " << name.c_str());
+ SysFreeString(anames[0]);
+
+ if (defEventSink)
+ {
+ FuncX func;
+ func.name = name;
+ func.memid = fd->memid;
+ func.hasOut = false;
+
+ // get Param Names
+ unsigned int maxPNames = fd->cParams + 1;
+ unsigned int nPNames = 0;
+ BSTR *pnames = new BSTR[maxPNames];
+
+ hret = typeInfo->GetNames(fd->memid, pnames, maxPNames, &nPNames);
+
+ SysFreeString(pnames[0]);
+ // params
+ for (int p = 0; p < fd->cParams; p++)
+ {
+ ParamX param;
+ param.flags = fd->lprgelemdescParam[p].idldesc.wIDLFlags;
+ param.vt = fd->lprgelemdescParam[p].tdesc.vt;
+ param.name = pnames[p + 1];
+ SysFreeString(pnames[p + 1]);
+
+ func.hasOut |= param.IsOut();
+ func.params.push_back(param);
+ };
+ delete [] pnames;
+
+ m_events.push_back(func);
+ m_eventsIdx[fd->memid] = m_events.size() - 1;
+ };
+ };
+
+ typeInfo->ReleaseFuncDesc(fd);
+ };
+ }
+
+ typeInfo->ReleaseTypeAttr(ta);
+};
+