【发布时间】:2014-08-21 13:15:39
【问题描述】:
我有一个 ATL COM 组件,它引发了一些由托管(C# 和 VB.NET)代码处理的事件。该组件当前由 VS2005 VB.NET 项目(作为 ActiveX 控件)使用,所有事件都被引发并且一切正常。
但是,在将一些代码移植到 C# 时,我注意到除了其中一个事件之外的所有事件都不会引发。引发的唯一事件不将任何参数传递回处理程序。所有其他人都这样做。
// this function is auto-generated
HRESULT Fire_SomeEvent(VARIANT_BOOL inOriginated, IUserType * inUserType)
{
CComVariant varResult;
T* pT = static_cast<T*>(this);
int nConnectionIndex;
CComVariant* pvars = new CComVariant[2];
int nConnections = m_vec.GetSize();
for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++)
{
pT->Lock();
CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
pT->Unlock();
IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);
if (pDispatch != NULL)
{
VariantClear(&varResult);
pvars[1] = inOriginated;
pvars[0] = inUserType;
DISPPARAMS disp = { pvars, NULL, 2, 0 };
pDispatch->Invoke(0x7, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL);
}
}
delete[] pvars;
return varResult.scode;
}
Invoke 正在返回 0x80070057 (E_INVALIDARG)。然而,在 VB 领域,当通过 ActiveX 包装器使用时,它可以工作。现在,无论如何,我都不是 COM 向导,我只是不明白。我无法在任何地方找到任何适用的东西。
我认为这可能与传递 UDT 有关,但不是;一个几乎相同的版本,将IUserType 替换为LONG 也返回E_INVALIDARG。同样,不传递参数的单个事件有效。
托管代码如何使用它的简短示例。这里没有什么疯狂的。
class Program
{
private ComType _c;
static void Main(string[] args)
{
_c = new ComType();
_c.SomeEvent += _c_SomeEvent;
_c.DoSomethingWhichRaisesSomeEvent();
}
static void _c_SomeEvent(bool b, IUserType udt)
{
// never called
}
}
在联系这里之前,我通常会花更多时间进行调试,但我必须尽快给这里打个电话。我要么必须解决这个问题,要么放弃这个界面并使用另一个(这对我的目的来说不是最佳的)。所以,希望你们中的一些 COM 专业人士以前遇到过这种情况。
【问题讨论】:
-
Reintepret_cast 而不是 QI for IDispatch 是错误的。
-
我还要仔细检查 dispparams 的 vt 值。第一个参数应该是 IDispatch 吗?我希望索引以递增的顺序排列,而不是递减。
-
"UDT" 是一个危险信号,它需要在类型库中定义才能在来自 VT_RECORD 的转换中存活。
-
@EricBrown:我可以在其中扔一个
QueryInterface,尝试一下不会有什么坏处,但我认为这不是手头的问题(此代码也是自动生成的)。我会检查 vt,但索引实际上是按降序排列的。请参阅msdn.microsoft.com/en-us/library/windows/desktop/… 和puArgErr [out]部分。 -
@EricBrown:天哪!我将 VARIANT_BOOL 参数的 vt 更改为 11(VT_BOOL,duh),它起作用了!是的。感谢您的帮助,我真的很感激。发布答案以便我接受。