属性プログラミングの FAQ

HRESULT とは

HRESULT は単純なデータ型であり、一般的に属性と ATL によって戻り値としてよく使用されます。 次の表で各種の値について説明します。 ヘッダー ファイル winerror.h には、より多くの値が含まれています。

名前 内容 Value
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 つのパラメーターがあります。

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

属性ブロック内で単一行と複数行の両方のコメントを使用できます。 ただし、パラメーターを属性に保持するかっこ内では、どちらのスタイルのコメントも使用できません。

次は許可されます。

[ 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 属性を適用する必要があります。

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

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