Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
O Win2D é implementado como uma camada sobre o Direct2D e suporta interoperabilidade em ambas as direções. Se tiveres um objeto Win2D, podes aceder ao objeto Direct2D nativo que é usado para o implementar. Se tiveres um objeto Direct2D, podes procurar o objeto Win2D que o envolve, ou criar um novo wrapper se ainda não existir um.
A interoperabilidade permite combinar e alternar entre o Win2D e as APIs nativas do DirectX. Podes escrever uma aplicação que use maioritariamente Win2D, mas a qualquer momento passar para o DirectX nativo – talvez para aceder a outra API ou componente de terceiros que exija interfaces nativas. Ou a tua aplicação pode ser maioritariamente DirectX nativa, mas podes mudar para Win2D em locais específicos onde quiseres maior conveniência ou suporte a C#.
Interop APIs
As APIs de interoperabilidade C++/CX são definidas no cabeçalho Microsoft. Graphics.Canvas.native.h:
#include <Microsoft.Graphics.Canvas.native.h>
using namespace Microsoft::Graphics::Canvas;
Para obter o objeto Direct2D nativo que é envolto por um objeto Win2D:
template<typename T, typename U>
Microsoft::WRL::ComPtr<T> GetWrappedResource(U^ wrapper);
template<typename T, typename U>
Microsoft::WRL::ComPtr<T> GetWrappedResource(CanvasDevice^ device, U^ wrapper);
template<typename T, typename U>
Microsoft::WRL::ComPtr<T> GetWrappedResource(CanvasDevice^ device, U^ wrapper, float dpi);
Para a maioria dos tipos GetWrappedResource, pode ser invocado apenas com um objeto encapsulador do Win2D como parâmetro. Para alguns tipos (ver tabela abaixo) também deve ser transmitido um valor de dispositivo e/ou DPI. Não constitui erro passar um dispositivo ou DPI ao usar GetWrappedResource com tipos que não os exigem.
Para obter um objeto Win2D que envolve um objeto Direct2D nativo:
template<typename WRAPPER>
WRAPPER^ GetOrCreate(IUnknown* resource);
template<typename WRAPPER>
WRAPPER^ GetOrCreate(CanvasDevice^ device, IUnknown* resource);
template<typename WRAPPER>
WRAPPER^ GetOrCreate(ID2D1Device1* device, IUnknown* resource);
template<typename WRAPPER>
WRAPPER^ GetOrCreate(CanvasDevice^ device, IUnknown* resource, float dpi);
template<typename WRAPPER>
WRAPPER^ GetOrCreate(ID2D1Device1* device, IUnknown* resource, float dpi);
GetOrCreate devolve uma instância de wrapper existente se já existir, ou cria um novo wrapper se não existir. Chamá-lo repetidamente no mesmo objeto nativo devolverá o mesmo wrapper todas as vezes, desde que essa instância do wrapper continue a existir. Se todas as referências ao wrapper forem libertadas ao ponto de a sua contagem de referências chegar a zero e o wrapper ser destruído, qualquer chamada posterior a GetOrCreate terá de criar um novo wrapper.
Para alguns tipos GetOrCreate pode ser chamado apenas com um objeto de recurso Direct2D como parâmetro, enquanto para outros tipos (ver tabela abaixo) também deve ser passado um dispositivo e um valor DPI. Não constitui erro passar um dispositivo ou DPI ao usar GetOrCreate com tipos que não os exigem. Se já existir um wrapper Win2D, é aceitável omitir o dispositivo e o DPI mesmo para tipos que normalmente os precisariam: estes parâmetros só são usados ao criar novas instâncias de wrapper.
GetOrCreate compreende hierarquias de herança e criará sempre o tipo de wrapper mais derivado apropriado. Por exemplo, se chamar GetOrCreate<CanvasBitmap>(ID2D1Bitmap1*) com um ID2D1Bitmap1 que tem o D2D1_BITMAP_OPTIONS_TARGET flag, a instância do wrapper retornada será de facto um CanvasRenderTarget (que deriva de CanvasBitmap). Por outro lado, se invocares GetOrCreate<CanvasRenderTarget>(ID2D1Bitmap1*) com um ID2D1Bitmap1 que não tem D2D1_BITMAP_OPTIONS_TARGET, será lançada uma exceção de conversão inválida.
Levando isto ao extremo, é válido chamar GetOrCreate<Object>(IUnknown*), e também GetWrappedResource<IUnknown>(Object^).
Tipos que suportam interoperabilidade
| Tipo Win2D | Tipo Direct2D |
GetOrCreate Parâmetros |
GetWrappedResource Parâmetros |
|---|---|---|---|
CanvasBitmap |
ID2D1Bitmap1 sem D2D1_BITMAP_OPTIONS_TARGET |
Device | - |
CanvasCachedGeometry |
ID2D1GeometryRealization |
Device | - |
CanvasCommandList |
ID2D1CommandList |
Device | - |
CanvasDevice |
ID2D1Device1 |
- | - |
CanvasDrawingSession |
ID2D1DeviceContext1 |
- | - |
CanvasFontFace |
IDWriteFontFaceReference |
- | - |
CanvasFontSet |
IDWriteFontSet |
- | - |
CanvasGeometry |
ID2D1Geometry, ou uma das suas interfaces ID2D1PathGeometryderivadas , ID2D1RectangleGeometry, ID2D1RoundedRectangleGeometry, ID2D1EllipseGeometry, ID2D1TransformedGeometry, ou ID2D1GeometryGroup |
Device | - |
CanvasGradientMesh |
ID2D1GradientMesh |
Device | - |
CanvasImageBrush |
ID2D1BitmapBrush1 (se a imagem for do tipo CanvasBitmap e SourceRectangle for null) ou ID2D1ImageBrush (se for qualquer outro tipo de ICanvasImage, ou se SourceRectangle is set) |
Device | DPI^1 opcional |
CanvasLinearGradientBrush |
ID2D1LinearGradientBrush |
Device | - |
CanvasNumberSubstitution |
IDWriteNumberSubstitution |
- | - |
CanvasRadialGradientBrush |
ID2D1RadialGradientBrush |
Device | - |
CanvasRenderTarget |
ID2D1Bitmap1 com D2D1_BITMAP_OPTIONS_TARGET |
Device | - |
CanvasSolidColorBrush |
ID2D1SolidColorBrush |
Device | - |
CanvasStrokeStyle |
ID2D1StrokeStyle1 |
- | Device |
CanvasSvgDocument |
ID2D1SvgDocument^2 |
Device | - |
CanvasSwapChain |
IDXGISwapChain1 |
Dispositivo, DPI | - |
CanvasTextFormat |
IDWriteTextFormat1 |
- | - |
CanvasTextLayout |
IDWriteTextLayout3 |
Device | - |
CanvasTextRenderingParameters |
IDWriteRenderingParams3 |
- | - |
CanvasTypography |
IDWriteTypography |
- | - |
CanvasVirtualBitmap |
ID2D1ImageSource ou ID2D1TransformedImageSource |
Device | - |
ColorManagementProfile |
ID2D1ColorContext |
Device | Device |
EffectTransferTable3D |
ID2D1LookupTable3D |
Device | - |
Microsoft.Graphics.Canvas.Effects.* (múltiplas classes Win2D correspondem ao mesmo tipo D2D) |
ID2D1Effect com o D2D1_PROPERTY_TYPE_CLSID adequado |
Device | Dispositivo, DPI^1 opcional |
Note
^1: DPI opcional significa que é válido chamar GetWrappedResource para este tipo sem especificar um valor de DPI, mas se especificar DPI, o Win2D pode conseguir configurar grafos de efeitos de forma mais eficiente omitindo nós redundantes de compensação de DPI. Isto aplica-se ao invocar GetWrappedResource num efeito, ou num CanvasImageBrush cuja imagem de origem é um efeito.
Note
^2: quando um CanvasSvgDocument é produzido a partir de um ID2D1SvgDocument utilizando interoperabilidade nativa de C++, o tamanho da viewport de ID2D1SvgDocument é ignorado.
Interop usando C++/CX
Aqui está um exemplo de como o Win2D pode interoperar com o Direct2D, usando C++:
#include <Microsoft.Graphics.Canvas.native.h>
#include <d2d1_2.h>
using namespace Microsoft::Graphics::Canvas;
using namespace Microsoft::WRL;
// Interop Win2D -> Direct2D.
CanvasDevice^ canvasDevice = ...;
CanvasBitmap^ canvasBitmap = ...;
ComPtr<ID2D1Device> nativeDevice = GetWrappedResource<ID2D1Device>(canvasDevice);
ComPtr<ID2D1Bitmap1> nativeBitmap = GetWrappedResource<ID2D1Bitmap1>(canvasBitmap);
// Interop Direct2D -> Win2D.
canvasDevice = GetOrCreate<CanvasDevice>(nativeDevice.Get());
bitmap = GetOrCreate<CanvasBitmap>(canvasDevice, nativeBitmap.Get());
Note
A interoperabilidade também é possível via C#, por vários meios (por exemplo, usando interoperabilidade COM/WinRT incorporada, via APIs do CsWinRT ou usando bindings blittable). Para mais informações sobre interoperabilidade manual em C#, consulte a documentação sobre o CsWinRT.
Interop usando C++/WinRT
Também pode realizar interoperabilidade usando C++/WinRT com alguma modificação do acima. Note que os cabeçalhos C++/WinRT para os Componentes Win2D Windows Runtime devem ser gerados automaticamente quando adicionar o pacote Win2D NuGet ao seu projeto C++/WinRT. No entanto, para interop ainda terá de usar o ficheiro de cabeçalho Microsoft.Graphics.Canvas.native.h, que contém a interface ABI de baixo nível ICanvasFactoryNative no espaço de nomes ABI::Microsoft::Graphics::Canvas. A interface tem as seguintes funções que pode usar para realizar a interoperabilidade.
HRESULT GetOrCreate(ICanvasDevice* device, IUnknown* resource, float dpi, IInspectable** wrapper);
HRESULT GetNativeResource(ICanvasDevice* device, float dpi, REFIID iid, void** resource);
Aqui está um exemplo que mostra como criar um CanvasVirtualBitmap a partir de um IWICBitmapSource começando com o IWICBitmapSource e o partilhado CanvasDevice.
#include "pch.h"
#include <wincodec.h>
#include <wincodecsdk.h>
#include <winrt/Microsoft.Graphics.Canvas.h> //This defines the C++/WinRT interfaces for the Win2D Windows Runtime Components
#include <Microsoft.Graphics.Canvas.h> //This defines the low-level ABI interfaces for the Win2D Windows Runtime Components
#include <Microsoft.Graphics.Canvas.native.h> //This is for interop
#include <d2d1_3.h>
using namespace winrt::Microsoft::Graphics::Canvas;
namespace abi {
using namespace ABI::Microsoft::Graphics::Canvas;
}
namespace winrt::Win2DInteropTest::implementation {
CanvasVirtualBitmap CreateVirtualBitmapFromBitmapSource(com_ptr<IWICBitmapSource> const& pBitmapSource){
CanvasDevice sharedDevice = CanvasDevice::GetSharedDevice();
//First we need to get an ID2D1Device1 pointer from the shared CanvasDevice
com_ptr<abi::ICanvasResourceWrapperNative> nativeDeviceWrapper = sharedDevice.as<abi::ICanvasResourceWrapperNative>();
com_ptr<ID2D1Device1> pDevice{ nullptr };
check_hresult(nativeDeviceWrapper->GetNativeResource(nullptr, 0.0f, guid_of<ID2D1Device1>(), pDevice.put_void()));
//Next we need to call some Direct2D functions to create the ID2D1ImageSourceFromWic object
com_ptr<ID2D1DeviceContext1> pContext{ nullptr };
check_hresult(pDevice->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_NONE, pContext.put()));
com_ptr<ID2D1DeviceContext2> pContext2 = pContext.as<ID2D1DeviceContext2>();
com_ptr<ID2D1ImageSourceFromWic> pImage{ nullptr };
check_hresult(pContext2->CreateImageSourceFromWic(pBitmapSource.get(), D2D1_IMAGE_SOURCE_LOADING_OPTIONS_RELEASE_SOURCE, pImage.put()));
//Finally we need to wrap the ID2D1ImageSourceFromWic object inside
com_ptr<::IInspectable> pInspectable{ nullptr };
auto factory = winrt::get_activation_factory<CanvasDevice, abi::ICanvasFactoryNative>(); //abi::ICanvasFactoryNative is the activation factory for the CanvasDevice class
check_hresult(factory->GetOrCreate(sharedDevice.as<abi::ICanvasDevice>().get(), pImage.as<::IUnknown>().get(), 0.0f, pInspectable.put())); //Note abi::ICanvasDevice is defined in the header Microsoft.Graphics.Canvas.h
CanvasVirtualBitmap cvb = pInspectable.as<CanvasVirtualBitmap>();
return cvb;
}
}
Lembre-se de incluir o cabeçalho <unknwn.h> em pch.h antes de qualquer cabeçalho WinRT (exigido no SDK 17763 e posteriores).
Windows developer