Modifier

Forum aux questions sur la programmation par attributs

Qu’est-ce qu’un HRESULT ?

Un HRESULT est un type de données simple qui est souvent utilisé comme valeur de retour par attributs et ATL en général. Le tableau suivant décrit les différentes valeurs. D’autres valeurs sont contenues dans le fichier d’en-tête winerror.h.

Nom Description active
S_OK L’opération a réussi 0x00000000
E_UNEXPECTED Échec inattendu 0x8000FFFF
E_NOTIMPL Non implémenté 0x80004001
E_OUTOFMEMORY Échec de l’allocation de la mémoire nécessaire 0x8007000E
E_INVALIDARG Un ou plusieurs arguments ne sont pas valides 0x80070057
E_NOINTERFACE Interface non prise en charge 0x80004002
E_POINTER Pointeur non valide 0x80004003
E_HANDLE Handle non valide 0x80070006
E_ABORT Opération abandonnée 0x80004004
E_FAIL Échec non spécifié 0x80004005
E_ACCESSDENIED Erreur d’accès général refusée 0x80070005

Quand dois-je spécifier le nom du paramètre d’un attribut ?

Dans la plupart des cas, si l’attribut a un paramètre unique, ce paramètre est nommé. Ce nom n’est pas obligatoire lors de l’insertion de l’attribut dans votre code. Par exemple, l’utilisation suivante de l’attribut aggregatable :

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

est exactement le même que :

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

Toutefois, les attributs suivants ont des paramètres uniques et sans nom :

Puis-je utiliser des commentaires dans un bloc d’attributs ?

Vous pouvez utiliser à la fois des lignes uniques et plusieurs commentaire de ligne au sein d’un bloc d’attributs. Toutefois, vous ne pouvez pas utiliser l’un ou l’autre style de commentaire entre parenthèses contenant les paramètres sur un attribut.

Les éléments suivants sont autorisés :

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

Les éléments suivants ne sont pas autorisés :

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

Comment les attributs interagissent-ils avec l’héritage ?

Vous pouvez hériter des classes attribuées et non attribuées à partir d’autres classes, qui peuvent elles-mêmes être attribuées ou non. Le résultat de la dérivation d’une classe attributée est identique à celui de cette classe après que le fournisseur d’attributs a transformé son code. Les attributs ne sont pas transmis aux classes dérivées via l’héritage C++. Un fournisseur d’attributs transforme uniquement le code à proximité de ses attributs.

Comment puis-je utiliser des attributs dans un projet ATL non attribué ?

Vous pouvez avoir un projet ATL non attribué, qui a un fichier .idl et que vous souhaiterez peut-être commencer à ajouter des objets attributs. Dans ce cas, utilisez l’Assistant Ajouter une classe pour fournir le code.

Comment puis-je utiliser un fichier .idl dans un projet attribué ?

Vous pouvez avoir un fichier .idl que vous souhaitez utiliser dans votre projet attribut ATL. Dans ce cas, vous allez utiliser l’attribut importidl, compiler le fichier .idl dans un fichier .h (voir les pages de propriétés MIDL dans la boîte de dialogue Pages de propriétés du projet), puis inclure le fichier .h dans votre projet.

Puis-je modifier le code injecté par un attribut ?

Certains attributs injectent du code dans votre projet. Vous pouvez voir le code injecté à l’aide de l’option du compilateur /Fx . Il est également possible de copier du code à partir du fichier injecté et de le coller dans votre code source. Cela vous permet de modifier le comportement de l’attribut. Toutefois, vous devrez peut-être également modifier d’autres parties de votre code.

L’exemple suivant est le résultat de la copie du code injecté dans un fichier de code source :

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

Comment transférer une interface attribuée ?

Si vous envisagez d’effectuer une déclaration de transfert d’une interface attributée, vous devez appliquer les mêmes attributs à la déclaration de transfert que vous appliquez à la déclaration d’interface réelle. Vous devez également appliquer l’attribut d’exportation à votre déclaration de transfert.

Puis-je utiliser des attributs sur une classe dérivée d’une classe qui utilise également des attributs ?

Non, l’utilisation d’attributs sur une classe dérivée d’une classe qui utilise également des attributs n’est pas prise en charge.