Bearbeiten

Share via


Häufig gestellte Fragen zur Programmierung von Attributen

Was ist ein HRESULT?

Ein HRESULT ist ein einfacher Datentyp, der häufig als Rückgabewert von Attributen und ATL im Allgemeinen verwendet wird. In der folgenden Tabelle werden die verschiedenen Werte beschrieben. Weitere Werte sind in der Headerdatei winerror.h enthalten.

Name Beschreibung Wert
S_OK Vorgang erfolgreich 0x00000000
E_UNEXPECTED Unerwarteter Fehler 0x8000FFFF
E_NOTIMPL Nicht implementiert 0x80004001
E_OUTOFMEMORY Fehler beim Zuordnen des erforderlichen Arbeitsspeichers. 0x8007000E
E_INVALIDARG Mindestens ein Argument ist ungültig. 0x80070057
E_NOINTERFACE Schnittstelle nicht unterstützt. 0x80004002
E_POINTER Ungültiger Zeiger 0x80004003
E_HANDLE Ungültiger Handle 0x80070006
E_ABORT Vorgang abgebrochen 0x80004004
E_FAIL Nicht angegebener Fehler 0x80004005
E_ACCESSDENIED Fehler "Allgemeiner Zugriff verweigert" 0x80070005

Wann muss ich den Parameternamen für ein Attribut angeben?

Wenn das Attribut in den meisten Fällen über einen einzelnen Parameter verfügt, wird dieser Parameter benannt. Dieser Name ist beim Einfügen des Attributs in Den Code nicht erforderlich. Beispielsweise die folgende Verwendung des aggregatierbaren Attributs:

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

ist genau dasselbe wie:

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

Die folgenden Attribute weisen jedoch einzelne, unbenannte Parameter auf:

Kann ich Kommentare in einem Attributblock verwenden?

Sie können sowohl einzeilige als auch mehrere Zeilenkommentar innerhalb eines Attributblocks verwenden. Sie können jedoch keines der Kommentararten innerhalb der Klammern verwenden, die die Parameter für ein Attribut enthalten.

Folgendes ist zulässig:

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

Folgendes ist unzulässig:

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

Wie interagieren Attribute mit der Vererbung?

Sie können attributierte und nicht zugeordnete Klassen von anderen Klassen erben, die selbst zugeschrieben werden können oder nicht. Das Ergebnis der Ableitung von einer attributierten Klasse ist identisch mit der Ableitung von dieser Klasse, nachdem der Attributanbieter seinen Code transformiert hat. Attribute werden nicht über die C++-Vererbung an abgeleitete Klassen übertragen. Ein Attributanbieter transformiert code nur in der Nähe seiner Attribute.

Wie kann ich Attribute in einem nicht attributierten ATL-Projekt verwenden?

Möglicherweise verfügen Sie über ein nicht attributiertes ATL-Projekt, das über eine IDL-Datei verfügt, und Sie können mit dem Hinzufügen von attributierten Objekten beginnen. Verwenden Sie in diesem Fall den Assistenten zum Hinzufügen von Klassen, um den Code bereitzustellen.

Wie kann ich eine IDL-Datei in einem zugeordneten Projekt verwenden?

Möglicherweise verfügen Sie über eine IDL-Datei, die Sie in Ihrem ATL-Attributprojekt verwenden möchten. In diesem Fall würden Sie das Importidl-Attribut verwenden, die IDL-Datei in eine H-Datei kompilieren (siehe die MIDL-Eigenschaftenseiten im Dialogfeld "Eigenschaftenseiten" des Projekts), und fügen Sie dann die H-Datei in Ihr Projekt ein.

Kann ich Code ändern, der von einem Attribut eingefügt wird?

Einige Attribute enthalten Code in Ihr Projekt. Sie können den eingefügten Code mithilfe der /Fx-Compileroption sehen. Es ist auch möglich, Code aus der eingefügten Datei zu kopieren und in Ihren Quellcode einzufügen. Auf diese Weise können Sie das Verhalten des Attributs ändern. Möglicherweise müssen Sie jedoch auch andere Teile des Codes ändern.

Das folgende Beispiel ist das Ergebnis des Kopierens von eingefügtem Code in eine Quellcodedatei:

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

Wie kann ich eine attributbasierte Schnittstelle weiterleiten?

Wenn Sie eine Forward-Deklaration einer zugeordneten Schnittstelle vornehmen möchten, müssen Sie dieselben Attribute auf die Weiterleitungsdeklaration anwenden, die Sie auf die tatsächliche Schnittstellendeklaration anwenden. Sie müssen auch das Export-Attribut auf Die Weiterleitungsdeklaration anwenden.

Kann ich Attribute für eine von einer Klasse abgeleitete Klasse verwenden, die auch Attribute verwendet?

Nein, die Verwendung von Attributen für eine von einer Klasse abgeleitete Klasse, die auch Attribute verwendet, wird nicht unterstützt.