Wie gebe ich eine integrierte WinRT-Komponente mithilfe von WRL zurück?
-
12-12-2019 - |
Frage
Wenn ich eine WinRT-Komponente mit WRL erstelle, besteht das Problem darin, dass ich sie nur verwenden kann ABI::Windows::xxx
Namespace, und ich kann ihn nicht verwenden Windows::UI::Xaml::Media::Imaging
Namensraum in WRL.
Wie erstelle ich dann eine integrierte WinRT-Komponente als Rückgabewert?
// idl
import "inspectable.idl";
import "Windows.Foundation.idl";
import "Windows.UI.Xaml.Media.Imaging.idl";
namespace Decoder
{
interface IPhotoDecoder;
runtimeclass PhotoDecoder;
interface IPhotoDecoder : IInspectable
{
HRESULT Decode([in] int width, [in] int height, [out, retval] Windows.UI.Xaml.Media.Imaging.BitmapImage **ppBitmapImage);
}
[version(COMPONENT_VERSION), activatable(COMPONENT_VERSION)]
runtimeclass PhotoDecoder
{
[default] interface IPhotoDecoder;
}
}
// cpp
using namespace Microsoft::WRL;
using namespace Windows::Foundation;
using namespace ABI::Windows::UI::Xaml::Media::Imaging;
namespace ABI
{
namespace Decoder
{
class PhotoDecoder: public RuntimeClass<IPhotoDecoder>
{
InspectableClass(L"Decoder.PhotoDecoder", BaseTrust)
public:
PhotoDecoder()
{
}
HRESULT __stdcall Decode(_In_ int width, _In_ int height, _Out_ IBitmapImage **ppBitmapImage)
{
// How to create Windows.UI.Xaml.Media.Imaging.BitmapImage without using Windows::UI::Xaml::Media::Imaging
}
};
ActivatableClass(PhotoDecoder);
}
}
Lösung
Es gibt zwei Gruppen von Namespaces:
- diejenigen, die im globalen Namensraum verwurzelt sind (z. B.
Windows::Foundation
) - diejenigen, die in der verwurzelt sind
ABI
Namensraum (z.B.ABI::Windows::Foundation
)
Der Inhalt eines jeden ist "dasselbe". Zum Beispiel, Windows::Foundation::IUriRuntimeClass
benennt die gleiche Schnittstelle wie ABI::Windows::Foundation::IUriRuntimeClass
.
Warum gibt es also zwei Gruppen von Namespaces?Die im globalen Namespace verwurzelten Namespaces sind für die Verwendung durch C++/CX reserviert:Es generiert seine Projektionen von Laufzeitklassen in diesen Namespaces.Wenn Sie WRL verwenden, arbeiten Sie immer mit den Namespaces, die in der verwurzelt sind ABI
Namespace (das sind die „nicht projizierten“ Namen, das heißt, sie sind genau das, was auf der ABI-Ebene existiert).
Laufzeitklassen werden auf zwei Arten instanziiert („aktiviert“).Wenn der Typ standardmäßig konstruierbar ist, kann er standardmäßig durch einen Aufruf erstellt werden RoActivateInstance
.Wenn ein Typ andere Konstruktoren deklariert, können diese Konstruktoren aufgerufen werden, indem durch Aufrufen die Aktivierungsfactory für den Laufzeittyp abgerufen wird RoGetActivationFactory
.Als Beispiel können Sie standardmäßig a konstruieren BitmapImage
etwa so:
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::UI::Xaml::Media::Imaging;
HStringReference classId(RuntimeClass_Windows_UI_Xaml_Media_Imaging_BitmapImage);
ComPtr<IInspectable> inspectable;
if (FAILED(RoActivateInstance(classId.Get(), inspectable.GetAddressOf())))
{
// Handle failure
}
ComPtr<IBitmapImage> bitmapImage;
if (FAILED(inspectable.As(&bitmapImage)))
{
// Handle failure
}
WRL verfügt auch über eine nützliche Funktionsvorlage, Windows::Foundation::ActivateInstance
, dass beide Anrufe RoActivateInstance
und führt die QueryInterface
zur gewünschten Zielschnittstelle:
using namespace Windows::Foundation;
ComPtr<IBitmapImage> bitmapImage;
if (FAILED(ActivateInstance(classId.Get(), bitmapImage.GetAddressOf())))
{
// Handle failure
}