ATL attributed проект и генерация ошибок
От: lkurts Россия http://lktalks.blogspot.com
Дата: 31.12.04 00:12
Оценка: 37 (8)
#Имя: FAQ.atl.attributed.errgen
Здравствуйте, Щербатов Евгений, Вы писали:

ЩЕ>Подскажите плиз, где я прокололся? Ведь не может быть, что в МС добавили поддержку атрибутов, а генерация ошибок у них работать перестала?


Нигде не прокололся. Таки перестала работать генерация ошибок.

Что собственно происходит?

При компиляции "attributed" проекта на компилятор вставляет в твой код некоторые вставки
на основании тех атрибутов которые ты ему прописал. Эти вставки можно просмотреть,
если указать опцию /Fx. При указанииэтой опции тебе компилятор для каждого файла f.x в который
он вставлял код сгенерирует файл f.mrg.x (то есть между именем и расширением файла добавляется mrg), в котором будут аккуратно помечены все вставки которые он за тебя сделал. Так вот — посмотрим что же он там нагенерил. Заметим что поскольку твой выызов идет из VB, то ты неявно пользуешься функцией Invoke интерфейса IDispatch, поскольку больше ничем бейсик пользоваться не умеет. Как раз Invoke и вставляет
тебе компилятор (помимо всего прочего). Вот прирмерно как она выглядит:

    //+++ Start Injected Code For Attribute 'support_error_info'
#injected_line 32 "l:\\work\\projects\\coding\\attributedtest\\errtest.h"
    virtual HRESULT STDMETHODCALLTYPE IErrTest::Invoke(
                /* [in] */ DISPID dispIdMember,
                /* [in] */ REFIID riid,
                /* [in] */ LCID lcid,
                /* [in] */ WORD wFlags,
                /* [out][in] */ DISPPARAMS *pDispParams,
                /* [out] */ VARIANT *pVarResult,
                /* [out] */ EXCEPINFO *pExcepInfo,
                /* [out] */ UINT *puArgErr) 
    {
        (void) riid;
        (void) dispIdMember;
        (void) lcid;
        (void) wFlags;
        (void) pExcepInfo;
        (void) puArgErr;
        HRESULT hr = S_OK;
        if (pDispParams == 0) {
            return DISP_E_BADVARTYPE;
        }
        if (pDispParams->cArgs > 0) {
            return DISP_E_BADPARAMCOUNT;
        }
        if (pVarResult != 0) {
            ::VariantInit(pVarResult);
        }
        switch (dispIdMember) {
        case 1:
            {
                if (pDispParams->cArgs != 0) {
                    return DISP_E_BADPARAMCOUNT;
                }
                hr = ((::IErrTest*) this)->MakeError();
                break;
            }
        default:
            return DISP_E_MEMBERNOTFOUND;
        }
        return hr;
    }


Обрати внимание на кусок которыый я пометил курсивом — в нем и есть ошибка. Для того
чтобы в VB пришла твоя ошибка должна быть заполнена EXCEPINFO *pExcepInfo, а она нигде
не заполняется — поэтому ошибка и не проходит. Там должно было бы быть что-то вроде

IErrorInfo* ErrorInfo; 
GetErrorInfo(0, &ErrorInfo);
ErrorInfo->GetDescription(&pExcepInfo->bstrDescription);
pExcepInfo->wCode = hr;



Как же с этим бороться?
Самый простой способ борьбы вглядит примерно так:
у тебя в .h файле где-то написано примерно так:

class  CErrTest : public IErrTest


вместо этого надо написать так:
class  CErrTest : public IDispatchImpl<IErrTest>


В этом случае код для Invoke вставляться не будет, а будет взят из IDispatchImpl,
а там он правильный
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.