Ich werde versuchen, die Frage so gut wie möglich zu beantworten, basierend auf WPF 4.5 Unleashed Kapitel 19. Wenn Sie nachschlagen möchten, finden Sie alle Informationen dort im Unterabschnitt "Mischen von DirectX-Inhalten mit WPF-Inhalt ".
Ihre C++ - DLL sollte 3 exposed Methoden Initialize(), Cleanup() und Render() haben. Die interessanten Methoden sind Initialize() und InitD3D(), die durch Initialisieren() aufgerufen wird:
extern "C" __declspec(dllexport) IDirect3DSurface9* WINAPI Initialize(HWND hwnd, int width, int height)
{
// Initialize Direct3D
if(SUCCEEDED(InitD3D(hwnd)))
{
// Create the scene geometry
if(SUCCEEDED(InitGeometry()))
{
if (FAILED(g_pd3dDevice->CreateRenderTarget(width, height,
D3DFMT_A8R8G8B8, D3DMULTISAMPLE_NONE, 0,
true, // lockable (true for compatibility with Windows XP. False is preferred for Windows Vista or later)
&g_pd3dSurface, NULL)))
{
MessageBox(NULL, L"NULL!", L"Missing File", 0);
return NULL;
}
g_pd3dDevice->SetRenderTarget(0, g_pd3dSurface);
}
}
return g_pd3dSurface;
}
HRESULT InitD3D(HWND hWnd)
{
// For Windows Vista or later, this would be better if it used Direct3DCreate9Ex:
if(NULL == (g_pD3D = Direct3DCreate9(D3D_SDK_VERSION)))
return E_FAIL;
// Set up the structure used to create the D3DDevice. Since we are now
// using more complex geometry, we will create a device with a zbuffer.
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
// Create the D3DDevice
if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice)))
{
return E_FAIL;
}
// Turn on the zbuffer
g_pd3dDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
// Turn on ambient lighting
g_pd3dDevice->SetRenderState(D3DRS_AMBIENT, 0xffffffff);
return S_OK;
}
Ermöglicht dem Weg zu den XAML-Code:
xmlns:interop="clr-namespace:System.Windows.Interop;assembly=PresentationCore"
<Button.Background>
<ImageBrush>
<ImageBrush.ImageSource>
<interop:D3DImage x:Name="d3dImage" />
</ImageBrush.ImageSource>
</ImageBrush>
</Button.Background>
I festgelegt haben es als Hintergrund einer Schaltfläche hier, mit einem ImageBrush. Ich glaube, das Hinzufügen als Hintergrund ist eine gute Möglichkeit, den DirectX-Inhalt anzuzeigen. Sie können das Bild jedoch beliebig verwenden.
initialisieren die Wiedergabe ein Handle auf das aktuelle Fenster erfassen und die Initialize() -Methode des DLL mit nennen:
private void initialize()
{
IntPtr surface = DLL.Initialize(new WindowInteropHelper(this).Handle,
(int)button.ActualWidth, (int)button.ActualHeight);
if (surface != IntPtr.Zero)
{
d3dImage.Lock();
d3dImage.SetBackBuffer(D3DResourceType.IDirect3DSurface9, surface);
d3dImage.Unlock();
CompositionTarget.Rendering += CompositionTarget_Rendering;
}
}
Das CompositionTarget.Rendering Ereignis ausgelöst wird, kurz bevor die Benutzeroberfläche gerendert wird. Sie sollten Ihre DirectX Inhalt dort machen:
private void CompositionTarget_Rendering(object sender, EventArgs e)
{
if (d3dImage.IsFrontBufferAvailable)
{
d3dImage.Lock();
DLL.Render();
// Invalidate the whole area:
d3dImage.AddDirtyRect(new Int32Rect(0, 0, d3dImage.PixelWidth, d3dImage.PixelHeight));
d3dImage.Unlock();
}
}
, die im Grunde war es, ich hoffe, es hilft. Jetzt nur noch ein paar wichtige Randnoten:
- immer dein Bild sperren, um zu verhindern, dass WPF zieht Rahmen teilweise
- Dont Anruf Gegenwart auf dem Direct 3D-Gerät. WPF stellt einen eigenen Backbuffer basierend auf der Oberfläche bereit, die Sie an d3dImage.SetBackBuffer() übergeben haben.
Das Ereignis IsFrontBufferAvailableChanged sollte behandelt werden, da der Frontpuffer manchmal nicht verfügbar sein kann (z. B. wenn der Benutzer den Sperrbildschirm eingibt). Sie sollten die Ressourcen basierend auf der Pufferverfügbarkeit freigeben oder abrufen.
private void d3dImage_IsFrontBufferAvailableChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (d3dImage.IsFrontBufferAvailable)
{
initialize();
}
else
{
// Cleanup:
CompositionTarget.Rendering -= CompositionTarget_Rendering;
DLL.Cleanup();
}
}
helfen ich für ein Beispiel dafür, wie Host Direct2D in einer WPF-Anwendung suchen wäre. gute Frage. –
Haben Sie Zugriff auf die DLL? Kannst du den Code ändern? Ich glaube, der Aufruf von CreateWindow() ist problematisch – Domysee
WPF ist sehr nah an WIC, also würde ich stattdessen d2d1.CreateWicBitmapRenderTarget mit einer IWicBitmap von Ihnen verwenden. Diese IWicBitmap kann dann in einer Klasse verwendet werden, die von WPFs abstrakter BitmapSource stammt (genau wie InteropBitmap, aber mit einer eigenen Klasse, da WPF seine WIC-Bitmaps nicht freigibt ...). Diese BitmapSource kann jetzt ein untergeordnetes Element des Bereichs sein. Wenn Sie eine Beispiel-App zum Arbeiten haben, könnten wir dies weiter entwickeln. –