次の方法で共有


属性プログラミングの 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 つだけですが、名前付きではありません。

call_as

case

cpp_quote

default

defaultvalue

defaultvtable

emitidl

entry

first_is

helpcontext

helpfile

helpstring

helpstringcontext

helpstringdll

id

iid_is

import

importlib

include

includelib

last_is

length_is

max_is

no_injected_text

pointer_default

pragma

restricted

size_is

source

switch_is

switch_type

transmit_as

wire_marshal

属性ブロックでコメントを使用できますか

属性ブロックには、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 属性も適用する必要があります。

属性を使用するクラスから派生したクラスでさらに属性を使用できますか

いいえ。属性を使用するクラスから派生したクラスでの属性の使用はサポートされていません。

参照

概念

属性付きプログラミングの概念