#c #com #interop
#c #com #взаимодействие
Вопрос:
У меня есть компонент ATL COM, который вызывает несколько событий, которые обрабатываются управляемыми (C # и VB.NET ) код. Компонент в настоящее время используется VS2005 VB.NET проект (как элемент управления ActiveX) и все события инициируются, и все работает.
Однако при переносе части кода на C # я заметил, что все события, кроме одного, никогда не вызываются. Единственное вызванное событие не передает никаких аргументов обратно обработчику. Все остальные делают.
// this function is auto-generated
HRESULT Fire_SomeEvent(VARIANT_BOOL inOriginated, IUserType * inUserType)
{
CComVariant varResu<
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(amp;varResult);
pvars[1] = inOriginated;
pvars[0] = inUserType;
DISPPARAMS disp = { pvars, NULL, 2, 0 };
pDispatch->Invoke(0x7, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, amp;disp, amp;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
}
}
Обычно я бы потратил больше времени на отладку, прежде чем обращаться сюда, но мне скоро нужно позвонить сюда. Я должен либо исправить это, либо отказаться от этого интерфейса и использовать другой (который неоптимален для моих целей). Итак, надеюсь, что некоторые из вас, КОМ-профессионалы, сталкивались с этим раньше.
Комментарии:
1. Повторная передача вместо QI для IDispatch неверна.
2. Я бы также дважды проверил значения vt в dispparams. Должен ли 1-й аргумент быть IDispatch? Я бы ожидал, что индексы будут идти в порядке возрастания, а не уменьшения.
3. «UDT» — это красный флаг, он должен быть определен в библиотеке типов, чтобы пережить преобразование из VT_RECORD.
4. @EricBrown: Я могу добавить туда
QueryInterface
, попробовать не помешает, но я не думаю, что это проблема (этот код также генерируется автоматически). Я проверю vt, но индексы на самом деле идут в порядке убывания. Смотрите msdn.microsoft.com/en-us/library/windows/desktop /… и раздел дляpuArgErr [out]
.5. @EricBrown: Ну, черт возьми; я изменил значение vt для аргумента VARIANT_BOOL на 11 (VT_BOOL, да), и это сработало! Да. Спасибо за помощь, я действительно ценю это. Отправьте ответ, чтобы я мог его принять.
Ответ №1:
Дважды проверьте свои значения vt в ваших вариантах dispparam; многие реализации IDispatch довольно требовательны к тому, чтобы все было выровнено.