Editar

Partilhar via


Perguntas frequentes de programação do atributo

O que é um HRESULT?

Um HRESULT é um tipo de dados simples que geralmente é usado como um valor retornado por atributos e ATL em geral. A tabela a seguir descreve os diversos valores. Mais valores fazer parte do arquivo de cabeçalho winerror.h.

Nome Descrição Valor
S_OK Operação concluída com êxito 0x00000000
E_UNEXPECTED Falha inesperada 0x8000FFFF
E_NOTIMPL Não implementado 0x80004001
E_OUTOFMEMORY Falha ao alocar a memória necessária 0x8007000E
E_INVALIDARG Um ou mais argumentos são inválidos 0x80070057
E_NOINTERFACE Não há suporte para essa interface 0x80004002
E_POINTER Ponteiro inválido 0x80004003
E_HANDLE Identificador inválido 0x80070006
E_ABORT Operação anulada 0x80004004
E_FAIL Falha não especificada 0x80004005
E_ACCESSDENIED Erro de acesso geral negado 0x80070005

Quando tenho que especificar o nome do parâmetro para um atributo?

Na maioria dos casos, se o atributo tiver um parâmetro único, esse parâmetro será nomeado. Esse nome não é necessário ao inserir o atributo em seu código. Por exemplo, o seguinte uso do atributo aggregatable:

[coclass, aggregatable(value=allowed)]
class CMyClass
{
// The class declaration
};

é exatamente o mesmo que:

[coclass, aggregatable(allowed)]
class CMyClass
{
// The class declaration
};

No entanto, os seguintes atributos têm parâmetros únicos e sem nome:

Posso usar comentários em um bloco de atributo?

Você pode usar comentários de linha única e de várias linhas em um bloco de atributo. No entanto, você não pode usar nenhum estilo de comentário dentro dos parênteses que contêm os parâmetros de um atributo.

O exemplo a seguir é permitido:

[ coclass, progid("MyClass.CMyClass.1"), /* Multiple-line
                                       comment */
   threading("both") // Single-line comment
]

O exemplo a seguir não é permitido:

[ coclass, progid("MyClass.CMyClass.1" /* Multiple-line comment */ ), threading("both" // Single-line comment)
]

Como os atributos interagem com a herança?

Você pode herdar classes atribuídas e não atribuídas de outras classes e elas podem ser atribuídas ou não. O resultado da derivação de uma classe atribuída é o mesmo que derivar dessa classe depois que o provedor de atributo transformou seu código. Os atributos não são transmitidos para classes derivadas por meio da herança C++. Um provedor de atributos transforma apenas o código nas proximidades de seus atributos.

Como posso usar atributos em um projeto ATL não atribuído?

Você pode ter um projeto ATL não atribuído, que tem um arquivo .idl e talvez você queira começar a adicionar objetos atribuídos. Nesse caso, use o Assistente para Adicionar Classe para fornecer o código.

Como posso usar um arquivo .idl em um projeto atribuído?

Você pode ter um arquivo .idl que deseja usar em seu projeto atribuído à ATL. Nesse caso, você usaria o atributo importidl, compilaria o arquivo .idl em um arquivo .h (consulte as Páginas de Propriedade de MIDL na caixa de diálogo Páginas de Propriedades do projeto) e, em seguida, incluiria o arquivo .h em seu projeto.

Posso modificar o código que é injetado por um atributo?

Alguns atributos injetam código em seu projeto. Você pode ver o código injetado usando a opção do compilador /Fx. Também é possível copiar o código do arquivo injetado e colá-lo no código-fonte. Isso permite que você modifique o comportamento do atributo. No entanto, talvez você também tenha que modificar outras partes do código.

O exemplo a seguir é o resultado da cópia do código injetado em um arquivo de código-fonte:

// 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() {}

Como posso fazer a declaração de encaminhamento de uma interface atribuída?

Se você for fazer uma declaração de encaminhamento de uma interface atribuída, deve aplicar os mesmos atributos à declaração de encaminhamento que você aplica à declaração de interface real. Você também deve aplicar o atributo export à sua declaração de encaminhamento.

Posso usar atributos em uma classe derivada de uma classe que também usa atributos?

Não, não há suporte para o uso de atributos em uma classe derivada de uma classe que também usa atributos.