Здравствуйте, Щербатов Евгений, Вы писали:
ЩЕ>Подскажите плиз, где я прокололся? Ведь не может быть, что в МС добавили поддержку атрибутов, а генерация ошибок у них работать перестала?
Нигде не прокололся. Таки перестала работать генерация ошибок.
Что собственно происходит?
При компиляции "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,
а там он правильный
Здравствуйте, lkurts, Вы писали:
ЩЕ>>Подскажите плиз, где я прокололся? Ведь не может быть, что в МС добавили поддержку атрибутов, а генерация ошибок у них работать перестала?
L>Нигде не прокололся. Таки перестала работать генерация ошибок.
<-------skipped-------->
L>Обрати внимание на кусок которыый я пометил курсивом — в нем и есть ошибка. Для того
L>чтобы в VB пришла твоя ошибка должна быть заполнена EXCEPINFO *pExcepInfo, а она нигде
L>не заполняется — поэтому ошибка и не проходит. Там должно было бы быть что-то вроде
<-------skipped-------->
Хотел обновить информацию. В VS 2005 описанная проблема исправлена. Теперь в Injected код
компилятор вставляет следующее (в самый конец сгенерированного Invoke):
if (FAILED(hr) && pExcepInfo != NULL)
{
AtlExcepInfoFromErrorInfo(hr, pExcepInfo);
}
Как видно, здесь вызывается новая функция (вроде бы ранее не существовашая) : AtlExcepInfoFromErrorInfo.
Она находится в файле: atlevent.h и выглядит так:
inline HRESULT AtlExcepInfoFromErrorInfo(HRESULT hrInvoke, EXCEPINFO *pExcepInfo)
{
if (pExcepInfo == NULL)
{
return E_POINTER;
}
pExcepInfo->pfnDeferredFillIn = NULL;
pExcepInfo->scode = hrInvoke;
CComPtr<IErrorInfo> spErrInfo;
HRESULT hr = GetErrorInfo(0, &spErrInfo);
if (SUCCEEDED(hr))
{
// Set up ErrInfo object
// Ignore any errors. If additional error information is not
// available then corresponding pointer will be NULL or 0
spErrInfo->GetSource(&pExcepInfo->bstrSource);
spErrInfo->GetDescription(&pExcepInfo->bstrDescription);
spErrInfo->GetHelpFile(&pExcepInfo->bstrHelpFile);
spErrInfo->GetHelpContext(&pExcepInfo->dwHelpContext);
}
return hr;
}
Заметим что в двух выделенных строчках ошибка, поскольку GetErrorInfo может выдавать S_FALSE,
и тогда случится обращение к нулевому указателю. Об этом существует соответствующая KB artice:
http://support.microsoft.com/default.aspx?scid=kb;en-us;913940
Вот такие дела. Будьте бдительны!
да...
может, всё же стоит вынести диагноз "в морг" для attributed ATL?

... << RSDN@Home 1.1.4 stable SR1 rev. 568>>