属性プログラミングの FAQ
ここでは、次のよく寄せられる質問に回答します。
HRESULT とは何ですか
どのような場合に属性のパラメータ名を指定する必要がありますか
属性ブロックでコメントを使用できますか
属性と継承の間にはどのような関係がありますか
属性なしの ATL プロジェクトで属性を使用するにはどのようにしますか
属性付きプロジェクトで .idl ファイルを使用するにはどのようにしますか
属性によって挿入されたコードは変更できますか
属性付きインターフェイスの事前宣言を行うにはどのようにしますか
属性を使用するクラスから派生したクラスでさらに属性を使用できますか
HRESULT とは何ですか
HRESULT とは単純なデータ型で、普通、属性および ATL の戻り値としてよく使われます。次の表は、さまざまな値についての説明です。winerror.h ファイルではこれ以外の値も定義されています。
名前 |
説明 |
値 |
---|---|---|
S_OK |
操作が正常終了 |
0x00000000 |
E_UNEXPECTED |
予測不可能なエラー |
0x8000FFFF |
E_NOTIMPL |
実装されていない |
0x80004001 |
E_OUTOFMEMORY |
必要なメモリの割り当てに失敗 |
0x8007000E |
E_INVALIDARG |
1 つ以上の引数が無効 |
0x80070057 |
E_NOINTERFACE |
サポートされていないインターフェイス |
0x80004002 |
E_POINTER |
無効なポインタ |
0x80004003 |
E_HANDLE |
無効なハンドル |
0x80070006 |
E_ABORT |
操作が中止された |
0x80004004 |
E_FAIL |
規定されていないエラー |
0x80004005 |
E_ACCESSDENIED |
一般的なアクセス拒否エラー |
0x80070005 |
どのような場合に属性のパラメータ名を指定する必要がありますか
通常、属性のパラメータが 1 つだけの場合、そのパラメータは名前付きです。属性をコードに追加する場合、この名前は必要ありません。aggregatable 属性の使用例は、次のとおりです。
[coclass, aggregatable(value=allowed)]
class CMyClass
{
// The class declaration
};
上の例とまったく同じものを次に示します。
[coclass, aggregatable(allowed)]
class CMyClass
{
// The class declaration
};
ただし、次に示す属性のパラメータは 1 つだけですが、名前付きではありません。
属性ブロックでコメントを使用できますか
属性ブロックには、1 行または複数行のコメントを記述できます。ただし、属性に対するパラメータを指定するかっこの中では、どちらの形式のコメントも使用できません。
使用できる形式のコメントを次に示します。
[ 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 プロジェクトで属性を使用するにはどのようにしますか
.idl ファイルを持つ属性なしの ATL プロジェクトがあり、属性付きオブジェクトの追加を開始する場合があります。この場合は、クラスの追加ウィザードを使用してコードを指定します。
属性付きプロジェクトで .idl ファイルを使用するにはどのようにしますか
ATL 属性付きプロジェクトで .idl ファイルを使用する場合があります。この場合は、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() {}
属性付きインターフェイスの事前宣言を行うにはどのようにしますか
属性付きインターフェイスの事前宣言を行う場合は、実際のインターフェイス宣言に適用する事前宣言に同じ属性を適用する必要があります。事前宣言には export 属性も適用する必要があります。
属性を使用するクラスから派生したクラスでさらに属性を使用できますか
いいえ。属性を使用するクラスから派生したクラスでの属性の使用はサポートされていません。