IDispatch::Вызов, возвращающий E_INVALIDARG

#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 довольно требовательны к тому, чтобы все было выровнено.