2012-09-24 1 views
0

Je veux créer un WinRT composant à l'aide C++ et WRL (Windows Runtime C++ Template Library) pour être consommable dans un code managé via C# appel statique de la méthode.Création composants WinRT avec des méthodes statiques en C++/WRL

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

La mise en œuvre qui ne fonctionne pas pour moi est ci-dessous.
Qu'est-ce qui ne va pas ici?

  1. Dans le fichier IDL créer une classe Math. Ce sera un hôte pour les méthodes statiques sur un côté géré. Créer Interface IMathStatics avec la méthode FastAdd. Celui-ci contient juste un tas de méthodes statiques. Mark Math classe avec statique attribut avec le paramètre 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. Créer MathStatics de classe C++. Let InspectableClassStatic macro pour pointer sur IMathStatics identificateur de chaîne. Ajouter ActivatableStaticOnlyFactory macro pour pointer sur MathStatics implémentation de classe.
 

    #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. Après la compilation du fichier WRLNativeComponent.winmd est créé. Je peux voir le Math classe avec méthode statique statique FastAdd.

  2. Construire le client C# pour appeler la méthode statique. Lorsque l'appel est effectué, le 'System.InvalidCastException' est levé. Cela devrait fonctionner correctement.

Répondre

3

Une classe d'exécution peut avoir au plus une usine d'activation. Chaque utilisation de l'une des macros Activatable enregistre une fabrique d'activation pour un type d'exécution. Par conséquent, le code suivant à partir de votre bibliothèque

ActivatableClass(Math); 
ActivatableStaticOnlyFactory(MathStatics); 

tente d'enregistrer deux usines d'activation: le premier registre d'une simple usine d'activation pour la classe Math et les seconds registres une autre usine d'activation simple qui n'est pas réellement utilisable (nous » Je vais voir pourquoi dans le moment). La première usine d'activation simple étant associée à la classe Math, elle est renvoyée lorsque le composant C# tente d'appeler la fonction de membre statique. Le composant C# tente ensuite de convertir ce pointeur d'interface vers l'interface IMathStatics, que la fabrique d'activation simple ne met pas en œuvre. La distribution échoue donc et vous obtenez le InvalidCastException.


Comme il ne peut y avoir une usine d'activation pour une classe d'exécution donné, votre classe a besoin de MathStatics pour mettre en œuvre à la fois l'interface membres statiques IMathStatics et l'interface IActivationFactory, qui est utilisé pour la construction par défaut (cela est nécessaire parce que vous a déclaré votre type Math comme constructible par défaut, en utilisant l'attribut activatable sans nom d'interface d'usine).

Votre usine d'activation doit être mis en œuvre comme ceci:

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); 

Le modèle de classe de base ActivationFactory fournit une implémentation par défaut de l'interface IActivationFactory. Cette implémentation par défaut renvoie simplement E_NOTIMPL lorsqu'un client tente de construire par défaut une instance du type Math, nous devons donc remplacer cette fonction membre pour construire par défaut un objet Math.

Notez que lors de l'utilisation du InspectableClassStatic pour achever la mise en œuvre de IInspectable pour une usine d'activation, le nom de la classe doit être le nom de la classe d'exécution (dans ce cas, RuntimeClass_WRLNativeComponent_Math), pas le nom de l'interface statique. L'activation est effectuée par nom de type, et c'est ce nom qui est utilisé par l'infrastructure WRL pour rechercher dans l'usine d'activation un type d'exécution utilisant son nom.

ActivatableClassWithFactory est utilisé pour enregistrer une classe d'exécution avec une fabrique d'activation associée.

Questions connexes