2012-09-24 45 views
0

我想創建一個使用C++WRL(Windows運行時C++模板庫)是在通過C#靜態方法調用託管代碼消耗部件WinRT的組件。在C靜態方法創建的WinRT組件++/WRL

int sum = Math.FastAdd(5,6); 

對我不起作用的實現如下。
這裏有什麼問題?

  1. IDL文件中創建一個數學類。它將成爲託管端的靜態方法的主機。創建 IMathStatics接口與 FastAdd方法。這個只包含一堆靜態方法。 Mark Math class with a static attribute with參數 IMathStatics
 

    import "inspectable.idl"; 
    #define COMPONENT_VERSION 1.0 
    namespace WRLNativeComponent 
    { 
     runtimeclass Math; 
     [uuid(EFA9D613-BA8F-4F61-B9E7-C6BE7B7765DD)] 
     [exclusiveto(WRLNativeComponent.Math)] 
     [version(COMPONENT_VERSION)] 
     interface IMathStatics : IInspectable 
     { 
      HRESULT FastAdd([in] int a, [in] int b, [out, retval] int* value); 
     } 
     [uuid(650438BA-C401-49E1-8F06-58DCD5A4B685), version(COMPONENT_VERSION)] 
     interface IMath : IInspectable 
     { 
      HRESULT InstanceMethod(void); 
     } 
     [static(WRLNativeComponent.IMathStatics, COMPONENT_VERSION)] 
     [version(COMPONENT_VERSION), activatable(COMPONENT_VERSION)] 
     runtimeclass Math 
     { 
      [default] interface IMath; 
     } 
    } 
  1. 創建 MathStatics C++類。讓 InspectableClassStatic宏指向 IMathStatics字符串標識符。添加 ActivatableStaticOnlyFactory宏指向 MathStatics類的實現。
 

    #pragma once 
    #include <wrl.h> 
    #include "MyMath_h.h" // generated from IDL 
    using namespace Microsoft::WRL; 
    namespace WRLNativeComponent { 
    class Math : public Microsoft::WRL::RuntimeClass, 
     ABI::WRLNativeComponent::IMath> 
    { 
     InspectableClass(RuntimeClass_WRLNativeComponent_Math, BaseTrust); 
    public: 
     Math(void) {} 
     ~Math(void) {} 
     STDMETHODIMP InstanceMethod() override 
     { 
      return S_OK; 
     } 
    }; 
    class MathStatics : public Microsoft::WRL::ActivationFactory 
    { 
     InspectableClassStatic(InterfaceName_WRLNativeComponent_IMathStatics, BaseTrust); 
    public: 
     MathStatics(void) {} 
     ~MathStatics(void) {} 
     STDMETHODIMP FastAdd(_In_ int a, _In_ int b, _Out_ int* value) override 
     { 
      if (value == nullptr) return E_POINTER; 
      *value = a + b; 
      return S_OK; 
     } 
    }; 
    ActivatableClass(Math); 
    ActivatableStaticOnlyFactory(MathStatics); 
    } 
  1. 編譯後的 WRLNativeComponent.winmd創建文件。我可以看到數學類與公共靜態FastAdd方法。

  2. 構造C#客戶端來調用靜態方法。撥打電話時,會引發'System.InvalidCastException'。這預計會正常工作。

回答

3

運行時類最多可能有一個激活工廠。每個使用Activatable宏之一的宏都會爲運行時類型註冊一個激活工廠。因此,從資料庫下面的代碼

ActivatableClass(Math); 
ActivatableStaticOnlyFactory(MathStatics); 

嘗試註冊兩個激活工廠:第一個註冊了Math類和第二寄存器另一個簡單的激活工廠並非實際可用簡單的激活工廠(我們」你會明白爲什麼)。

由於第一個簡單激活工廠與Math類相關聯,因此當C#組件嘗試調用靜態成員函數時會返回它。然後,C#組件會嘗試將此接口指針轉換爲簡單激活工廠未實現的接口IMathStatics,因此投射失敗,您將獲得InvalidCastException


由於只能有一個激活工廠給定的運行時類,您MathStatics類需要實現兩個IMathStatics靜態成員接口和IActivationFactory接口,用於默認的構造(這是必需的,因爲你將Math類型聲明爲默認可構造類型,使用activatable屬性而不使用工廠接口名稱)。

您激活工廠必須像這樣實現的:

class MathStatics : public ActivationFactory<IMathStatics> 
{ 
    InspectableClassStatic(RuntimeClass_WRLNativeComponent_Math, BaseTrust); 

public: 

    MathStatics() {} 
    ~MathStatics() {} 

    STDMETHODIMP ActivateInstance(_Outptr_result_nullonfailure_ IInspectable** ppvObject) override 
    { 
     return MakeAndInitialize<Math>(ppvObject); 
    } 

    STDMETHODIMP FastAdd(_In_ int a, _In_ int b, _Out_ int* value) override 
    { 
     if (value == nullptr) return E_POINTER; 
     *value = a + b; 
     return S_OK; 
    } 
}; 

ActivatableClassWithFactory(Math, MathStatics); 

ActivationFactory基類模板提供了IActivationFactory接口的默認實現。當客戶端嘗試默認構造Math類型的實例時,此默認實現簡單地返回E_NOTIMPL,因此我們需要重寫此成員函數以實際默認構造Math對象。

注意使用InspectableClassStatic時完成IInspectable用於激活工廠實施,類名應該是運行時類(在這種情況下,RuntimeClass_WRLNativeComponent_Math)的名稱,靜態接口的不是名稱。激活是通過類型名稱執行的,它是WRL基礎結構使用的名稱,用於使用名稱爲激活工廠查找運行時類型。

ActivatableClassWithFactory用於向關聯的激活工廠註冊運行時類。