当我在 Delphi 7 中创建基于 TPanel(没有添加代码)的 ActiveX 控件时,我可以将它添加到 MFC C++ 应用程序并让它运行良好。
当我使用完全相同的代码并在 Delphi XE4(和 XE2)中编译它时,MFC 会抛出一个断言。我确认唯一的变化是在 dcu、ocx 和 res 文件中。
断言发生ASSERT(wFlags == DISPATCH_METHOD);
在 occsite.cpp 中(我在其中包含了源代码)。
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;
}
wFlags 的值为 DISPATCH_METHOD | 调度属性获取。
之后一切似乎都正常工作(如果您从 XE4 开始,鼠标事件会导致类似的问题,但 D7 不包括它们)。
我在 Visual Studio 2010 和 Visual Studio 2012 中都试过这个。在 MFC 中,我正在创建一个新的 MFC 对话框应用程序,右键单击并选择添加 ActiveX 控件。我对 MFC 比较陌生,所以我可能做错了。
Win 7 x64 系统中的主机系统。
我不能把断言留在代码中,我真的想让它正常工作,这样我将来可以重用一堆 Delphi 代码。
任何想法正在发生什么,或者谁能指出我比敲击键盘更好的方向?
更新:2013.09.18
雷米在下面的回答是正确的,但这里有更多信息。
从 XE4 开始,主要问题似乎是发送回控制主机的事件(即 OnClickEvent、OnMouseEnter、OnMouseLeave、OnConstrainedResize、OnCanResize 或 OnResizeEvent)。
我找到了 3 个可能的解决方案(如果我找到了,会再次更新):
- 注释掉调用这些事件的代码(我没有说它们是好的解决方案)。
- 注释掉 ComObjs.DispatchInvoke 中导致设置的行。
- 修改 ComObjs 以具有备用 DispatchInvoke 和 DispCallByID
- 备用 DispCallID 需要调用备用 DispatchInvoke。
- 备用 DispatchInvoke 需要删除更改标志的代码
- 全局变量 DispCallByIDProc 在被事件使用时需要设置为备用 DispCallByID 过程。
- DispCallByIDProc 需要在设置为备用之后重新设置(我将其作为备用 DispCallByID 中的第一行)。
我使用了类似下面的东西来包围事件被调用的位置:
FEvents <> nil then
try
SetDispatchByCallID(True);
FEvents.OnClick;
finally
SetDispatchByCallID(False);
end;