编程常见问题的属性

本主题回答以下常见问题:

  • 什么是 HRESULT?

  • 我当必须为特性指定参数名称?

  • 我是否能将注释在特性块?

  • 属性与继承交互?

  • 如何使用属性在一个非 ATL 项目?

  • 如何使用 .idl 文件在一个特性化项目中?

  • 我是否能修改属性插入的代码?

  • 如何前向声明特性化的界面?

  • 我是否能将在从还可以使用属性的类派生的类的属性?

什么是 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
};

但是,下面的特性具有唯一,未命名参数:

call_as

case

cpp_quote

default

defaultvalue

defaultvtable

emitidl

first_is

helpcontext

helpfile

helpstring

helpstringcontext

helpstringdll

id

iid_is

import

importlib

包含

includelib

last_is

length_is

max_is

no_injected_text

pointer_default

说明

restricted

size_is

source

switch_is

switch_type

transmit_as

wire_marshal

我是否能将注释在特性块?

可以使用单行,并在属性中的多行注释块。 但是,不能使用注释任何一个样式位于备用参数的括号内于属性。

下面这样:

[ 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 文件在一个特性化项目中?

您可能会在该 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() {}

如何前向声明特性化的界面?

如果您使用前向声明特性化的接口,必须将同一特性应用于接口实际声明的前向声明。 您还必须将 导出 特性应用于该前向声明。

我是否能将在从还可以使用属性的类派生的类的属性?

不,在从还可以使用属性的类派生的类的属性不受支持。

请参见

其他资源

特性化编程的概念