Übersicht über die Direct2D- und GDI-Interoperabilität
In diesem Thema wird beschrieben, wie Direct2D und GDI zusammen verwendet werden. Es gibt zwei Möglichkeiten, Direct2D mit GDI zu kombinieren: Sie können GDI-Inhalte in ein Direct2D GDI-kompatibles Renderziel schreiben, oder Sie können Direct2D-Inhalt in einen GDI-Gerätekontext (DC) schreiben.
Dieses Thema enthält folgende Abschnitte:
- Voraussetzungen
- Zeichnen von Direct2D-Inhalten in einen GDI-Gerätekontext
- ID2D1DCRenderTargets, GDI-Transformationen und Rechts-nach-Links-Sprach-Builds von Windows
- Zeichnen von GDI-Inhalten auf ein Direct2D-GDI-Compatible Renderziel
- Zugehörige Themen
Voraussetzungen
In dieser Übersicht wird davon ausgegangen, dass Sie mit den grundlegenden Direct2D-Zeichnungsvorgängen vertraut sind. Ein Tutorial finden Sie im Direct2D-Schnellstart. Außerdem wird davon ausgegangen, dass Sie mit GDI-Zeichnungsvorgängen vertraut sind.
Zeichnen von Direct2D-Inhalten in einen GDI-Gerätekontext
Um Direct2D-Inhalt auf einen GDI-DC zu zeichnen, verwenden Sie id2D1DCRenderTarget. Zum Erstellen eines DC-Renderziels verwenden Sie die ID2D1Factory::CreateDCRenderTarget-Methode. Diese Methode verwendet zwei Parameter.
Der erste Parameter, eine D2D1 _ RENDER _ TARGET _ PROPERTIES-Struktur, gibt Rendering-, Remoting-, DPI-, Pixelformat- und Nutzungsinformationen an. Damit das DC-Renderziel mit GDI funktioniert, legen Sie das DXGI-Format auf DXGI _ FORMAT _ B8G8R8A8 _ UNORM und den Alphamodus auf D2D1 _ ALPHA MODE _ _ PREMULTIPLIED oder D2D1 _ ALPHA MODE _ _ IGNORE fest.
Der zweite Parameter ist die Adresse des Zeigers, der den DC-Renderzielverweis erhält.
Der folgende Code erstellt ein DC-Renderziel.
// Create a DC render target.
D2D1_RENDER_TARGET_PROPERTIES props = D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_DEFAULT,
D2D1::PixelFormat(
DXGI_FORMAT_B8G8R8A8_UNORM,
D2D1_ALPHA_MODE_IGNORE),
0,
0,
D2D1_RENDER_TARGET_USAGE_NONE,
D2D1_FEATURE_LEVEL_DEFAULT
);
hr = m_pD2DFactory->CreateDCRenderTarget(&props, &m_pDCRT);
Im vorangehenden Code ist m _ pD2DFactory ein Zeiger auf eine ID2D1Factory,und m _ pDCRT ist ein Zeiger auf eine ID2D1DCRenderTarget.
Bevor Sie mit dem DC-Renderziel rendern können, müssen Sie dessen BindDC-Methode verwenden, um es einem GDI-DC zu zuordnen. Dies ist jedes Mal der Fall, wenn Sie einen anderen Domänencontroller verwenden oder die Größe des Bereichs, den Sie zeichnen möchten, um Änderungen vorzunehmen.
Die BindDC-Methode verwendet die beiden Parameter hDC und pSubRect. Der hDC-Parameter stellt ein Handle für den Gerätekontext, der die Ausgabe des Renderziels empfängt. Der pSubRect-Parameter ist ein Rechteck, das den Teil des Gerätekontexts beschreibt, in dem Inhalt gerendert wird. Das DC-Renderziel aktualisiert seine Größe an den von pSubRect beschriebenen Gerätekontextbereich, falls sich die Größe ändert.
Der folgende Code bindet einen DC an ein DC-Renderziel.
HRESULT DemoApp::OnRender(const PAINTSTRUCT &ps)
{
// Get the dimensions of the client drawing area.
GetClientRect(m_hwnd, &rc);
| C++ |
|---|
|
Nachdem Sie das DC-Renderziel einem DC zuordnen, können Sie es zum Zeichnen verwenden. Der folgende Code zeichnet Direct2D- und GDI-Inhalt mithilfe eines Domänencontrollers.
HRESULT DemoApp::OnRender(const PAINTSTRUCT &ps)
{
HRESULT hr;
RECT rc;
// Get the dimensions of the client drawing area.
GetClientRect(m_hwnd, &rc);
//
// Draw the pie chart with Direct2D.
//
// Create the DC render target.
hr = CreateDeviceResources();
if (SUCCEEDED(hr))
{
// Bind the DC to the DC render target.
hr = m_pDCRT->BindDC(ps.hdc, &rc);
m_pDCRT->BeginDraw();
m_pDCRT->SetTransform(D2D1::Matrix3x2F::Identity());
m_pDCRT->Clear(D2D1::ColorF(D2D1::ColorF::White));
m_pDCRT->DrawEllipse(
D2D1::Ellipse(
D2D1::Point2F(150.0f, 150.0f),
100.0f,
100.0f),
m_pBlackBrush,
3.0
);
m_pDCRT->DrawLine(
D2D1::Point2F(150.0f, 150.0f),
D2D1::Point2F(
(150.0f + 100.0f * 0.15425f),
(150.0f - 100.0f * 0.988f)),
m_pBlackBrush,
3.0
);
m_pDCRT->DrawLine(
D2D1::Point2F(150.0f, 150.0f),
D2D1::Point2F(
(150.0f + 100.0f * 0.525f),
(150.0f + 100.0f * 0.8509f)),
m_pBlackBrush,
3.0
);
m_pDCRT->DrawLine(
D2D1::Point2F(150.0f, 150.0f),
D2D1::Point2F(
(150.0f - 100.0f * 0.988f),
(150.0f - 100.0f * 0.15425f)),
m_pBlackBrush,
3.0
);
hr = m_pDCRT->EndDraw();
if (SUCCEEDED(hr))
{
//
// Draw the pie chart with GDI.
//
// Save the original object.
HGDIOBJ original = NULL;
original = SelectObject(
ps.hdc,
GetStockObject(DC_PEN)
);
HPEN blackPen = CreatePen(PS_SOLID, 3, 0);
SelectObject(ps.hdc, blackPen);
Ellipse(ps.hdc, 300, 50, 500, 250);
POINT pntArray1[2];
pntArray1[0].x = 400;
pntArray1[0].y = 150;
pntArray1[1].x = static_cast<LONG>(400 + 100 * 0.15425);
pntArray1[1].y = static_cast<LONG>(150 - 100 * 0.9885);
POINT pntArray2[2];
pntArray2[0].x = 400;
pntArray2[0].y = 150;
pntArray2[1].x = static_cast<LONG>(400 + 100 * 0.525);
pntArray2[1].y = static_cast<LONG>(150 + 100 * 0.8509);
POINT pntArray3[2];
pntArray3[0].x = 400;
pntArray3[0].y = 150;
pntArray3[1].x = static_cast<LONG>(400 - 100 * 0.988);
pntArray3[1].y = static_cast<LONG>(150 - 100 * 0.15425);
Polyline(ps.hdc, pntArray1, 2);
Polyline(ps.hdc, pntArray2, 2);
Polyline(ps.hdc, pntArray3, 2);
DeleteObject(blackPen);
// Restore the original object.
SelectObject(ps.hdc, original);
}
}
if (hr == D2DERR_RECREATE_TARGET)
{
hr = S_OK;
DiscardDeviceResources();
}
return hr;
}
Dieser Code erzeugt Ausgaben wie in der folgenden Abbildung dargestellt (Es wurden Aufrufe hinzugefügt, um den Unterschied zwischen Direct2D und GDI-Rendering hervorzuheben).)

ID2D1DCRenderTargets, GDI-Transformationen und Rechts-nach-Links-Sprach-Builds von Windows
Wenn Sie ein ID2D1DCRenderTargetverwenden, rendert es Direct2D-Inhalt in einer internen Bitmap und rendert die Bitmap dann mit GDI auf dem DC.
GDI kann eine GDI-Transformation (über die SetWorldTransform-Methode) oder einen anderen Effekt auf den dc anwenden, der vom Renderziel verwendet wird. In diesem Fall transformiert GDI die von Direct2D erzeugte Bitmap. Die Verwendung einer GDI-Transformation zum Transformieren des Direct2D-Inhalts kann die visuelle Qualität der Ausgabe herabsetzen, da Sie eine Bitmap transformieren, für die Antialiasing und Subpixelpositionierung bereits berechnet wurden.
Angenommen, Sie verwenden das Renderziel, um eine Szene zu zeichnen, die Geometrien und Text mit Antialiasing enthält. Wenn Sie eine GDI-Transformation verwenden, um eine Skalierungstransformation auf den DC anzuwenden und die Szene so zu skalieren, dass sie 10-mal größer ist, werden Pixelisierung und verknoffene Kanten angezeigt. (Wenn Sie jedoch eine ähnliche Transformation mit Direct2D angewendet haben, würde die visuelle Qualität der Szene nicht beeinträchtigt.)
In einigen Fällen ist es möglicherweise nicht offensichtlich, dass GDI zusätzliche Verarbeitungen vor sich hat, die die Qualität des Direct2D-Inhalts herabsetzen könnten. Bei einem RTL-Build (Right-to-Left) von Windows kann der von id2D1DCRenderTarget gerenderte Inhalt beispielsweise horizontal umgekehrt werden, wenn GDI ihn in sein Ziel kopiert. Ob der Inhalt tatsächlich umgekehrt wird, hängt von den aktuellen Einstellungen des Domänencontrollers ab.
Je nach Art des gerenderten Inhalts sollten Sie die Umkehrung verhindern. Wenn der Direct2D-Inhalt ClearType-Text enthält, beeinträchtigt diese Umkehrung die Qualität des Texts.
Sie können das RTL-Renderingverhalten mithilfe der GDI-Funktion SetLayout steuern. Um die Spiegelung zu verhindern, rufen Sie die SetLayout-GDI-Funktion auf, und geben Sie LAYOUT _ BITMAPORIENTATIONPRESERVED als einzigen Wert für den zweiten Parameter an (kombinieren Sie ihn nicht mit LAYOUT _ RTL), wie im folgenden Beispiel gezeigt:
SetLayout(m_hwnd, LAYOUT_BITMAPORIENTATIONPRESERVED);
Zeichnen von GDI-Inhalten auf ein Direct2D-GDI-Compatible Renderziel
Im vorherigen Abschnitt wird beschrieben, wie Direct2D-Inhalt auf einen GDI-DC geschrieben wird. Sie können GDI-Inhalt auch in ein Direct2D GDI-kompatibles Renderziel schreiben. Dieser Ansatz ist nützlich für Anwendungen, die in erster Linie mit Direct2D gerendert werden, aber über ein Erweiterbarkeitsmodell oder andere Legacyinhalte verfügen, die die Möglichkeit zum Rendern mit GDI erfordern.
Um GDI-Inhalte in einem Direct2D GDI-kompatiblen Renderziel zu rendern, verwenden Sie eine ID2D1GdiInteropRenderTarget,die Zugriff auf einen Gerätekontext bietet, der GDI-Zeichnen-Aufrufe akzeptieren kann. Im Gegensatz zu anderen Schnittstellen wird ein ID2D1GdiInteropRenderTarget-Objekt nicht direkt erstellt. Verwenden Sie stattdessen die QueryInterface-Methode einer vorhandenen Renderzielinstanz. Dies wird im folgenden Code veranschaulicht:
D2D1_RENDER_TARGET_PROPERTIES rtProps = D2D1::RenderTargetProperties();
rtProps.usage = D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE;
// Create a GDI compatible Hwnd render target.
hr = m_pD2DFactory->CreateHwndRenderTarget(
rtProps,
D2D1::HwndRenderTargetProperties(m_hwnd, size),
&m_pRenderTarget
);
if (SUCCEEDED(hr))
{
hr = m_pRenderTarget->QueryInterface(__uuidof(ID2D1GdiInteropRenderTarget), (void**)&m_pGDIRT);
}
Im vorangehenden Code ist _ m pD2DFactory ein Zeiger auf eine ID2D1Factory,und m _ pGDIRT ist ein Zeiger auf eine ID2D1GdiInteropRenderTarget.
Beachten Sie, dass das Flag D2D1 _ RENDER TARGET USAGE _ _ _ GDI _ COMPATIBLE beim Erstellen des Hwnd GDI-kompatiblen Renderziels angegeben wird. Wenn ein Pixelformat erforderlich ist, verwenden Sie DXGI _ FORMAT _ B8G8R8A8 _ UNORM. Wenn ein Alphamodus erforderlich ist, verwenden Sie D2D1 _ ALPHA _ MODE _ PREMULTIPLIED oder D2D1 _ ALPHA MODE _ _ IGNORE.
Beachten Sie, dass die QueryInterface-Methode immer erfolgreich ist. Um zu testen, ob die Methoden der ID2D1GdiInteropRenderTarget-Schnittstelle für ein bestimmtes Renderziel funktionieren, erstellen Sie eine D2D1 _ RENDER TARGET _ _ PROPERTIES-Eigenschaft, die GDI-Kompatibilität und das entsprechende Pixelformat angibt, und rufen Sie dann die IsSupported-Methode des Renderziels auf, um festzustellen, ob das Renderziel GDI-kompatibel ist.
Das folgende Beispiel zeigt, wie Sie ein Kreisdiagramm (GDI-Inhalt) auf das Hwnd GDI-kompatible Renderziel zeichnen.
HDC hDC = NULL;
hr = m_pGDIRT->GetDC(D2D1_DC_INITIALIZE_MODE_COPY, &hDC);
if (SUCCEEDED(hr))
{
// Draw the pie chart to the GDI render target associated with the Hwnd render target.
HGDIOBJ original = NULL;
original = SelectObject(
hDC,
GetStockObject(DC_PEN)
);
HPEN blackPen = CreatePen(PS_SOLID, 3, 0);
SelectObject(hDC, blackPen);
Ellipse(hDC, 300, 50, 500, 250);
POINT pntArray1[2];
pntArray1[0].x = 400;
pntArray1[0].y = 150;
pntArray1[1].x = static_cast<LONG>(400 + 100 * 0.15425);
pntArray1[1].y = static_cast<LONG>(150 - 100 * 0.9885);
POINT pntArray2[2];
pntArray2[0].x = 400;
pntArray2[0].y = 150;
pntArray2[1].x = static_cast<LONG>(400 + 100 * 0.525);
pntArray2[1].y = static_cast<LONG>(150 + 100 * 0.8509);
POINT pntArray3[2];
pntArray3[0].x = 400;
pntArray3[0].y = 150;
pntArray3[1].x = static_cast<LONG>(400 - 100 * 0.988);
pntArray3[1].y = static_cast<LONG>(150 - 100 * 0.15425);
Polyline(hDC, pntArray1, 2);
Polyline(hDC, pntArray2, 2);
Polyline(hDC, pntArray3, 2);
DeleteObject(blackPen);
// Restore the original object.
SelectObject(hDC, original);
m_pGDIRT->ReleaseDC(NULL);
}
Der Code gibt Diagramme wie in der folgenden Abbildung mit Rückrufen aus, um den Unterschied bei der Renderingqualität hervorzuheben. Das rechte Kreisdiagramm (GDI-Inhalt) hat eine geringere Renderingqualität als das linke Kreisdiagramm (Direct2D-Inhalt). Dies liegt daran, dass Direct2D mit Antialiasing gerendert werden kann.
![]()