Edytuj

Udostępnij za pośrednictwem


Programowanie oparte na atrybutach — często zadawane pytania

Co to jest HRESULT?

HRESULT to prosty typ danych, który jest często używany jako wartość zwracana przez atrybuty i ATL ogólnie. W poniższej tabeli opisano różne wartości. Więcej wartości znajduje się w pliku nagłówka winerror.h.

Nazwa/nazwisko Opis Wartość
S_OK Operacja powiodła się 0x00000000
E_UNEXPECTED Nieoczekiwany błąd 0x8000FFFF
E_NOTIMPL Nie zaimplementowano 0x80004001
E_OUTOFMEMORY Nie można przydzielić wymaganej pamięci 0x8007000E
E_INVALIDARG Co najmniej jeden argument jest nieprawidłowy 0x80070057
E_NOINTERFACE Nie jest obsługiwany taki interfejs 0x80004002
E_POINTER Nieprawidłowy wskaźnik 0x80004003
E_HANDLE Nieprawidłowy uchwyt 0x80070006
E_ABORT Operacja przerwana 0x80004004
E_FAIL Nieokreślony błąd 0x80004005
E_ACCESSDENIED Błąd odmowy dostępu ogólnego 0x80070005

Kiedy muszę określić nazwę parametru dla atrybutu?

W większości przypadków, jeśli atrybut ma jeden parametr, ten parametr ma nazwę. Ta nazwa nie jest wymagana podczas wstawiania atrybutu w kodzie. Na przykład następujące użycie atrybutu aggregatable :

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

jest dokładnie taki sam jak:

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

Jednak następujące atrybuty mają pojedyncze, nienazwane parametry:

Czy mogę używać komentarzy w bloku atrybutów?

W bloku atrybutów można używać komentarzy jednowierszowych i wielowierszowych. Nie można jednak użyć dowolnego stylu komentarza w nawiasach trzymających parametry do atrybutu.

Dozwolone są następujące elementy:

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

Następujące warunki są niedozwolone:

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

Jak atrybuty współdziałają z dziedziczeniem?

Można dziedziczyć zarówno klasy przypisywane, jak i nieprzydatne z innych klas, które same mogą być przypisywane. Wynik wyprowadzania z klasy przypisanej jest taki sam jak wyprowadzanie z tej klasy po tym, jak dostawca atrybutów przekształcił swój kod. Atrybuty nie są przesyłane do klas pochodnych za pośrednictwem dziedziczenia języka C++. Dostawca atrybutów przekształca kod tylko w pobliżu jego atrybutów.

Jak mogę używać atrybutów w projekcie ATL bez atrybutów?

Być może masz nieprzydatowany projekt ATL, który zawiera plik idl, i może być konieczne rozpoczęcie dodawania obiektów przypisanych. W tym przypadku użyj Kreatora dodawania klas, aby podać kod.

Jak mogę użyć pliku idl w projekcie przypisanym?

Być może masz plik idl, którego chcesz użyć w projekcie przypisanym ATL. W takim przypadku należy użyć atrybutu importidl, skompilować plik idl do pliku h (zobacz strony właściwości MIDL w oknie dialogowym Strony właściwości projektu), a następnie dołączyć plik .h w projekcie.

Czy mogę zmodyfikować kod wstrzykiwany przez atrybut?

Niektóre atrybuty wprowadzają kod do projektu. Możesz zobaczyć wstrzyknięty kod przy użyciu opcji /Fx kompilatora. Istnieje również możliwość skopiowania kodu z wprowadzonego pliku i wklejania go do kodu źródłowego. Dzięki temu można modyfikować zachowanie atrybutu. Może być jednak konieczne zmodyfikowanie innych części kodu.

Poniższy przykład jest wynikiem kopiowania wprowadzonego kodu do pliku kodu źródłowego:

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

Jak mogę przekazać dalej deklarowanie interfejsu przypisanego?

Jeśli zamierzasz przesłać deklarację do przodu interfejsu przypisanego, należy zastosować te same atrybuty do deklaracji przesyłania dalej, która ma zastosowanie do rzeczywistej deklaracji interfejsu. Należy również zastosować atrybut eksportu do deklaracji przesyłania dalej.

Czy mogę używać atrybutów w klasie pochodzącej z klasy, która również używa atrybutów?

Nie, używanie atrybutów w klasie pochodzącej z klasy, która również używa atrybutów, nie jest obsługiwane.