Что такое HRESULT?
HRESULT — это простой тип данных, который часто используется в качестве возвращаемого значения атрибутами и ATL в целом. В следующей таблице описаны различные значения. Дополнительные значения содержатся в файле заголовка winerror.h.
Имя | Описание | Значение |
---|---|---|
S_OK | Операция выполнена успешно | 0x00000000 |
E_UNEXPECTED | Непредвиденный сбой | 0x8000FFFF |
E_NOTIMPL | Не реализовано | 0x80004001 |
E_OUTOFMEMORY | Не удалось выделить необходимую память | 0x8007000E |
E_INVALIDARG | Один или несколько аргументов недопустимы | 0x80070057 |
E_NOINTERFACE | Такой интерфейс не поддерживается | 0x80004002 |
E_POINTER | Недопустимый указатель | 0x80004003 |
E_HANDLE | Недопустимый дескриптор | 0x80070006 |
E_ABORT | Операция прервана | 0x80004004 |
E_FAIL | Неуказанный сбой | 0x80004005 |
E_ACCESSDENIED | Общая ошибка отказа в доступе | 0x80070005 |
Когда нужно указать имя параметра для атрибута?
В большинстве случаев, если атрибут имеет один параметр, этот параметр называется. Это имя не требуется при вставке атрибута в код. Например, следующее использование агрегируемого атрибута:
[coclass, aggregatable(value=allowed)]
class CMyClass
{
// The class declaration
};
точно так же, как:
[coclass, aggregatable(allowed)]
class CMyClass
{
// The class declaration
};
Однако следующие атрибуты имеют одинарные неименованные параметры:
Можно ли использовать комментарии в блоке атрибутов?
В блоке атрибутов можно использовать как однострочные, так и несколько строковый комментарий. Однако нельзя использовать любой стиль комментариев в скобках, где параметры заданы атрибуту.
Допускается следующее:
[ coclass, progid("MyClass.CMyClass.1"), /* Multiple-line
comment */
threading("both") // Single-line comment
]
Ниже запрещено:
[ coclass, progid("MyClass.CMyClass.1" /* Multiple-line comment */ ), threading("both" // Single-line comment)
]
Как атрибуты взаимодействуют с наследованием?
Можно наследовать как атрибуты, так и неуправляемые классы от других классов, которые могут быть атрибутами или нет. Результатом производных от класса атрибутов является то же самое, что и производный от этого класса после преобразования своего кода поставщиком атрибутов. Атрибуты не передаются производным классам через наследование C++. Поставщик атрибутов преобразует код только в непосредственной близости от его атрибутов.
Как использовать атрибуты в неатрибуционном проекте ATL?
Возможно, у вас есть неатрибуционный проект ATL, имеющий IDL-файл, и вы можете начать добавлять объекты с атрибутами. В этом случае используйте мастер добавления классов для предоставления кода.
Как использовать IDL-файл в проекте с атрибутами?
У вас может быть IDL-файл, который вы хотите использовать в проекте атрибутов ATL. В этом случае вы будете использовать атрибут importidl, скомпилируйте IDL-файл в H-файл (см. страницы свойств MIDL в диалоговом окне страниц свойств проекта), а затем включите H-файл в проект.
Можно ли изменить код, который внедряется атрибутом?
Некоторые атрибуты внедряют код в проект. Вы можете просмотреть внедренный код с помощью параметра компилятора /Fx . Также можно скопировать код из внедренного файла и вставить его в исходный код. Это позволяет изменить поведение атрибута. Однако может потребоваться изменить другие части кода.
Следующий пример является результатом копирования внедренного кода в файл исходного кода:
// attr_injected.cpp
// compile with: comsupp.lib
#define _ATL_ATTRIBUTES 1
#include <atlbase.h>
#include <atlcom.h>
[ module(name="MyLibrary") ];
// ITestTest
[
object, uuid("DADECE00-0FD2-46F1-BFD3-6A0579CA1BC4"), dual, helpstring("ITestTest Interface"), pointer_default(unique)
]
__interface ITestTest : IDispatch {
[id(1), helpstring("method DoTest")]
HRESULT DoTest([in] BSTR str);
};
// _ITestTestEvents
[
uuid("12753B9F-DEF4-49b0-9D52-A79C371F2909"), dispinterface, helpstring("_ITestTestEvents Interface")
]
__interface _ITestTestEvents {
[id(1), helpstring("method BeforeChange")] HRESULT BeforeChange([in] BSTR str, [in,out] VARIANT_BOOL* bCancel);
};
// CTestTest
[
coclass, threading(apartment), vi_progid("TestATL1.TestTest"), progid("TestATL1.TestTest.1"), version(1.0), uuid("D9632007-14FA-4679-9E1C-28C9A949E784"), // this line would be commented out from original file
// event_source("com"), // this line would be added to support injected code
source(_ITestTestEvents), helpstring("TestTest Class")
]
class ATL_NO_VTABLE CTestTest : public ITestTest,
// the following base classes support added injected code
public IConnectionPointContainerImpl<CTestTest>,
public IConnectionPointImpl<CTestTest, &__uuidof(::_ITestTestEvents), CComDynamicUnkArray>
{
public:
CTestTest() {
}
// this line would be commented out from original file
// __event __interface _ITestTestEvents;
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct() {
return S_OK;
}
void FinalRelease() {}
public:
CComBSTR m_value;
STDMETHOD(DoTest)(BSTR str) {
VARIANT_BOOL bCancel = FALSE;
BeforeChange(str,&bCancel);
if (bCancel) {
return Error("Error : Someone don't want us to change the value");
}
m_value =str;
return S_OK;
}
// the following was copied in from the injected code.
HRESULT BeforeChange(::BSTR i1,::VARIANT_BOOL* i2) {
HRESULT hr = S_OK;
IConnectionPointImpl<CTestTest, &__uuidof(_ITestTestEvents), CComDynamicUnkArray>* p = this;
VARIANT rgvars[2];
Lock();
IUnknown** pp = p->m_vec.begin();
Unlock();
while (pp < p->m_vec.end()) {
if (*pp != NULL) {
IDispatch* pDispatch = (IDispatch*) *pp;
::VariantInit(&rgvars[1]);
rgvars[1].vt = VT_BSTR;
V_BSTR(&rgvars[1])= (BSTR) i1;
::VariantInit(&rgvars[0]);
rgvars[0].vt = (VT_BOOL | VT_BYREF);
V_BOOLREF(&rgvars[0])= (VARIANT_BOOL*) i2;
DISPPARAMS disp = { rgvars, NULL, 2, 0 };
VARIANT ret_val;
hr = __ComInvokeEventHandler(pDispatch, 1, 1, &disp, &ret_val);
if (FAILED(hr))
break;
}
pp++;
}
return hr;
}
BEGIN_CONNECTION_POINT_MAP(CTestTest)
CONNECTION_POINT_ENTRY(__uuidof(::_ITestTestEvents))
END_CONNECTION_POINT_MAP()
// end added code section
// _ITestCtrlEvents Methods
public:
};
int main() {}
Как перенаправить объявление интерфейса атрибута?
Если вы собираетесь сделать перенаправленное объявление интерфейса с атрибутами, необходимо применить те же атрибуты к объявлению пересылки, которое применяется к фактическому объявлению интерфейса. Кроме того, необходимо применить атрибут экспорта к объявлению пересылки.
Можно ли использовать атрибуты для класса, производного от класса, который также использует атрибуты?
Нет, использование атрибутов в классе, производном от класса, который также использует атрибуты, не поддерживается.