\\ Home : Articoli : Stampa
DirectX e Windows Presentation Foundation
Di robydx (del 29/11/2007 @ 22:01:38, in DotNet, linkato 2121 volte)

Con il framework .Net 3.0 disponibile ormai da parecchi mesi e con Visual Studio 2008 uscito queste settimane nella sua versione Express è tempo di iniziare ad utilizzare le nuove funzionalità di .Net. La novità più visibile è senza dubbio la nuova interfaccia grafica Windows Presentation Foundation che permette di creare Form con grafica vettoriale e tridimensionale.

Tramite WPF si possono creare elementi esteticamente più belli e con maggiore interattività ma esiste un problema per chi, come me, vuole utilizzare tali elementi come cornice di un’applicazione DirectX: i controlli WPF non sono controlli Windows!

I controlli basati sulle Api Win32 sono creati dal sistema operativo generando indici univoci chiamati Handle, un sistema superato dalle WPF che usa un motore di rendering in DirectX. Di conseguenza i controlli non hanno handle.

Direct3D però ne ha bisogno per lavorare, in quanto utilizza il controllo associato a quel codice per mandare a video il rendering. Per questo è necessario un controllo Win32.

La soluzione è fondere la nuova interfaccia WPF con le vecchie Win32 ed in questo tutorial spiegherò come fare.

Per prima cosa create una applicazione WPF con un form. Create dentro ciò che volete e create un controllo che fungerà da contenitore per l’applicazione DirectX (io ho scelto un oggetto Border). Ora create una nuova classe, questa sarà il vostro controllo Win32.

Ereditando la classe HwndHost è possibile creare un controllo WPF che faccia da Host ad un controllo WIN32. I due metodi da sovrascrivere sono il build ed il destroy. Il primo viene chiamato in fase di inizializzazione, passa il riferimento ad un handle che .Net fornirà e richiede la restituzione dell’handle del controllo creato. Qui dentro creeremo un form Win32 utilizzando la chiamata Win32 CreateWindowEx. Questa chiamata restuirà l'handle che Windows assegnerà al controllo. Questo handle deve essere conservato ed utilizzato per la creazione del device di DirectX. Il secondo metodo da sovrascrivere è il Destroy che verrà chiamato quando il controllo sarà distrutto (solitamente alla chiusura del form). Qui distruggerete il form tramite l'istruzione DestroyWindow. Il codice sarà simile a quello qui sotto

 
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Interop;
using System.Runtime.InteropServices;


namespace WPFDirectX
{
    class DXControll : HwndHost
    {
        System.Threading.Thread thread;

        [DllImport("user32.dll", EntryPoint = "CreateWindowEx", CharSet = CharSet.Auto)]
        internal static extern IntPtr CreateWindowEx(
        int dwExStyle,
        string lpszClassName,
        string lpszWindowName,
        int style,
        int x, int y,
        int width, int height,
        IntPtr hwndParent,
        IntPtr hMenu,
        IntPtr hInst,
        [MarshalAs(UnmanagedType.AsAny)] object pvParam);

        [DllImport("user32.dll", EntryPoint = "DestroyWindow", CharSet = CharSet.Auto)]
        internal static extern bool DestroyWindow(IntPtr hwnd);

        private const int WS_CHILD = 0x40000000;
        private const int WS_VISIBLE = 0x10000000;
        private const int WS_BORDER = 0x00800000;

        IntPtr hwndHost = IntPtr.Zero;

        
        protected override HandleRef BuildWindowCore(HandleRef hwndParent)
        {
            hwndHost = CreateWindowEx(0, "static", "",
            WS_CHILD | WS_VISIBLE,
            0, 0,
            100, 100,
            hwndParent.Handle,
            IntPtr.Zero,
            IntPtr.Zero,
            0);


            return new HandleRef(this, hwndHost);
        }

        
        protected override void DestroyWindowCore(HandleRef hwnd)
        {
            DestroyWindow(hwnd.Handle);
        }

    }
}

 

Se ora provate il programma vedrete un classico pannello Windows dove si trova il vostro oggetto Border. Ora non dovrete far altro che inizializzare DirectX usando come handle la variabile hwndHost che avete preso in fase di inizializzazione. Da qui potrete usare DirectX tranquillamente creandovi un thread in cui fare il rendering. Nella classe potrete fare l’override dei metodi che vi possono servire (per esempio il resize).

Ultima nota fondamentale, non inizializzate DirectX nel build, in quanto il controllo non è ancora stato creato e vi darebbe errore. Createvi una funzione da chiamare quando l'applicazione è completamente inizializzata.

Vi lascio al codice che richiede Visual Studio 2005 con le estensioni per .Net 3.0 installate o in alternativa Visual Studio 2008 (Express o Professional). Il sorgente girerà su XP con il Framework .Net 3.0 installato o su Vista (dove per altro girerà accellerato in Hardware).

Link