編輯

分享方式:


屬性程式設計常見問題集

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

不過,下列屬性具有單一且未命名的參數:

我可以在屬性區塊中使用批註嗎?

您可以在屬性區塊內同時使用單行和多行批註。 不過,您無法在括弧內使用任一樣式的批註,將參數套用至屬性。

允許下列專案:

[ 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 專案中使用屬性?

您可能有具有 .idl 檔案的非attributed ATL 專案,而且您可能想要開始新增屬性化物件。 在此情況下,請使用 [ 新增類別精靈 ] 來提供程式碼。

如何在屬性化專案中使用 .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() {}

如何轉送宣告屬性化介面?

如果您要對屬性化介面進行轉送宣告,您必須將相同的屬性套用至您套用至實際介面宣告的轉送宣告。 您也必須將 export 屬性套用至轉送宣告。

我可以在衍生自也使用屬性的類別上使用屬性嗎?

否,不支援在衍生自也使用屬性的類別上使用屬性。