When I create an ActiveX control based on a TPanel (with no added code) in Delphi 7, I am able to add this to a MFC C++ application and have it run fine.
When I take the exact same code and compile it in Delphi XE4 (and XE2), MFC throws an assertion. I confirmed that the only changes are in the dcu, ocx and res files.
The assertion is happening on ASSERT(wFlags == DISPATCH_METHOD);
in occsite.cpp (I included the source to this).
STDMETHODIMP COleControlSite::XEventSink::Invoke(
DISPID dispid, REFIID, LCID, unsigned short wFlags,
DISPPARAMS* pDispParams, VARIANT* pvarResult,
EXCEPINFO* pExcepInfo, unsigned int* puArgError)
{
UNUSED(wFlags);
METHOD_PROLOGUE_EX(COleControlSite, EventSink)
ASSERT(pThis->m_pCtrlCont != NULL);
ASSERT(pThis->m_pCtrlCont->m_pWnd != NULL);
ASSERT(wFlags == DISPATCH_METHOD);
AFX_EVENT event(AFX_EVENT::event, dispid, pDispParams, pExcepInfo,
puArgError);
pThis->OnEvent(&event);
if (pvarResult != NULL)
::VariantClear(pvarResult);
return event.m_hResult;
}
The value of wFlags is DISPATCH_METHOD | DISPATCHPROPERTYGET.
Everything seems to work correctly after that (mouse events cause similar issues if you start in XE4, but D7 doesn't include them).
I tried this in both Visual Studio 2010 and Visual Studio 2012. In MFC, I am creating a new MFC dialog application, right clicking and selecting add ActiveX control. I am relatively new to MFC so I could be doing it wrong.
The host system in a Win 7 x64 system.
I can't leave the assertions in the code and really want to get this to work correctly so I can reuse a bunch of Delphi code in the future.
Any ideas what is happening or can anyone point me in a slightly better direction than head banging on a keyboard?
Update: 2013.09.18
Remy's answer below is correct, but here is some more information.
As of XE4, it seems the primary issues with this are the events sent back to the control host (i.e. OnClickEvent, OnMouseEnter, OnMouseLeave, OnConstrainedResize, OnCanResize or OnResizeEvent).
I found 3 possible solutions (will update again if I find anymore):
- Comment out the code calling these events (I didn't say they were good solutions).
- Comment out the lines in ComObjs.DispatchInvoke causing this to be set.
- Modify ComObjs to have an alternate DispatchInvoke and DispCallByID
- The alternate DispCallID needs to call the alternate DispatchInvoke.
- The alternate DispatchInvoke needs to have the code changing the flag removed
- The global variable DispCallByIDProc needs to be set to the alternate DispCallByID procedure when being used by an event.
- DispCallByIDProc needs to be set back afterward being set to the alternative (I do it as the first line in the alternate DispCallByID).
I used something like the following to surround where the event was being called:
FEvents <> nil then
try
SetDispatchByCallID(True);
FEvents.OnClick;
finally
SetDispatchByCallID(False);
end;