Freigeben über


Exemplarische Vorgehensweise: Erstellen einer grundlegenden Windows-Runtime-Komponente in C++ und Aufrufen dieser Komponente über JavaScript oder C#

In dieser exemplarischen Vorgehensweise wird die Erstellung einer grundlegenden Windows-Runtime-Komponenten-DLL erläutert, die aus JavaScript, C# oder Visual Basic aufgerufen werden kann. Bevor Sie die einzelnen Schritte durcharbeiten, machen Sie sich mit Konzepten wie der abstrakten binären Schnittstelle (ABI), Verweisklassen und der Komponentenerweiterungen von Visual C++ vertraut, die das Arbeiten mit Verweisklassen vereinfachen. Weitere Informationen finden Sie unter Erstellen von Windows-Runtime-Komponenten in C++ und Sprachreferenz zu Visual C++ (C++/CX).

Erstellen der Komponenten-DLL in C++

In diesem Beispiel wird zuerst das Komponentenprojekt erstellt, Sie können aber auch erst das JavaScript-Projekt erstellen. Die Reihenfolge spielt keine Rolle.

Beachten Sie, dass die Hauptklasse der Komponente Beispiele für Definitionen von Eigenschaften und Methoden sowie eine Ereignisdeklaration enthält. Dies dient nur zur Veranschaulichung der Vorgehensweise. Die Beispiele sind nicht erforderlich, und in diesem Beispiel wird der gesamte generierte Code durch eigenen Code ersetzt.

So erstellen Sie das C++-Komponentenprojekt

  1. Klicken Sie in Visual Studio in der Menüleiste auf Datei, auf Neu und dann auf Projekt.

  2. Erweitern Sie im Dialogfeld Neues Projekt links den Eintrag Visual C++, und wählen Sie den Knoten für Windows Store aus.

  3. Wählen Sie in der Mitte Komponente für Windows-Runtime aus, und benennen Sie das Projekt in WinRT_CPP.

  4. Klicken Sie auf OK.

So fügen Sie eine aktivierbare Klasse zur Komponente hinzu

  • Eine aktivierbare Klasse ist eine Klasse, die der Clientcode mithilfe eines new-Ausdrucks (New in Visual Basic oder ref new in C++) erstellen kann. In der Komponente wird sie als public ref class sealed deklariert. Tatsächlich haben die Dateien "Class1.h" und "Class1.cpp" bereits eine Verweisklasse. Der Name kann geändert werden. In diesem Beispiel wird aber der Standardname Class1 verwendet. Bei Bedarf können Sie in der Komponente zusätzliche Verweisklassen oder reguläre Klassen definieren. Weitere Informationen über ref-Klassen finden Sie unter Typsystem (C++/CX).

So fügen Sie die erforderlichen #include-Direktiven hinzu

  • Fügen Sie der Datei "Class1.h" diese #include-Direktiven hinzu:

    #include <collection.h>
    #include <amp.h>
    #include <amp_math.h>
    

    collection.h ist die Headerdatei für konkrete C++-Klassen wie Platform::Collections::Vector-Klasse und Platform::Collections::Map-Klasse, die sprachneutrale Schnittstellen implementieren, die von der Windows-Runtime definiert werden. Mit amp-Headern werden Berechnungen auf dem GPU ausgeführt. Sie haben keine Windows-Runtime-Äquivalente, was aufgrund ihrer privaten Natur sinnvoll ist. Aus Leistungsgründen sollten Sie ISO-C++-Code und Standardbibliotheken allgemein intern innerhalb der Komponente verwenden; lediglich die Windows-Runtime-Schnittstelle muss in Windows-Runtime-Typen ausgedrückt werden.

So fügen Sie einen Delegaten zum Namespacebereich hinzu

  • Ein Delegat ist ein Konstrukt, das die Parameter und den Rückgabetyp für Methoden definiert. Ein Ereignis ist eine Instanz eines bestimmten Delegattyps, und jede Ereignishandlermethode, die das Ereignis abonniert, muss über die Signatur verfügen, die im Delegaten angegeben ist. Der folgende Code definiert einen Delegattyp, der int akzeptiert und void zurückgibt. Anschließend deklariert der Code ein öffentliches event dieses Typs; dadurch kann Clientcode Methoden bereitstellen, die aufgerufen werden, wenn das Ereignis ausgelöst wird.

    Fügen Sie in Class1.h die folgende Delegatdeklaration im Namespacebereich hinzu, direkt vor der Class1-Deklaration.

    public delegate void PrimeFoundHandler(int result);    
    

    Tipp

    Sollte der Code beim Einfügen in Visual Studio nicht korrekt aneinandergereiht werden, drücken Sie einfach STRG+K+D, um den Einzug für die gesamte Datei zu korrigieren.

So fügen Sie öffentliche Member hinzu

  • Die Klasse macht drei öffentliche Methoden und ein öffentliches Ereignis verfügbar. Die erste Methode erfolgt synchron, da sie immer sehr schnell ausgeführt wird. Da die anderen beiden Methoden einige Zeit in Anspruch nehmen können, sind sie asynchron, damit sie den UI-Thread nicht blockieren. Diese Methoden geben IAsyncOperationWithProgress und IAsyncActionWithProgress zurück. Erstere definiert eine asynchrone Methode, die ein Ergebnis zurückgibt, letztere definiert eine asynchrone Methode, die „void“ zurückgibt. Über diese Schnittstellen kann Clientcode auch Aktualisierungen zum Status des Vorgangs empfangen.

    public:
    
        // Synchronous method. 
        Windows::Foundation::Collections::IVector<double>^  ComputeResult(double input);
    
        // Asynchronous methods
        Windows::Foundation::IAsyncOperationWithProgress<Windows::Foundation::Collections::IVector<int>^, double>^
            GetPrimesOrdered(int first, int last);
        Windows::Foundation::IAsyncActionWithProgress<double>^ GetPrimesUnordered(int first, int last);
    
        // Event whose type is a delegate "class"
        event PrimeFoundHandler^ primeFoundEvent;
    

So fügen Sie private Member hinzu

  • Die Klasse enthält drei private Member: zwei Hilfsmethoden für die numerischen Berechnungen und ein CoreDispatcher-Objekt, mit dem die Ereignisaufrufe von den Arbeitsthreads zum UI-Thread zurückgemarshallt werden.

    private:
        bool is_prime(int n);
        Windows::UI::Core::CoreDispatcher^ m_dispatcher;
    

So fügen Sie die Header- und Namespace-Direktiven hinzu

  1. Fügen Sie in Class1.cpp diese #include-Direktiven hinzu:

    #include <ppltasks.h>
    #include <concurrent_vector.h>
    
  2. Fügen Sie nun diese using-Anweisungen hinzu, um die erforderlichen Namespaces zu erhalten:

    using namespace concurrency;
    using namespace Platform::Collections;
    using namespace Windows::Foundation::Collections;
    using namespace Windows::Foundation;
    using namespace Windows::UI::Core;
    

So fügen Sie die Implementierung für ComputeResult hinzu

  • Fügen Sie in Class1.cpp die folgende Methodenimplementierung hinzu. Diese Methode wird synchron im aufrufenden Thread ausgeführt. Dies erfolgt jedoch sehr schnell, da C++ AMP verwendet wird, um die Berechnung auf dem GPU zu parallelisieren. Weitere Informationen finden Sie unter Übersicht über C++ AMP. Die Ergebnisse werden an einen konkreten Plattform::Collections::Vector<T>-Typ angefügt, der bei der Rückgabe implizit in Windows::Foundation::Collections::IVector<T> konvertiert wird.

    //Public API
    IVector<double>^ Class1::ComputeResult(double input)
    {
        // Implement your function in ISO C++ or
        // call into your C++ lib or DLL here. This example uses AMP.
        float numbers[] = { 1.0, 10.0, 60.0, 100.0, 600.0, 10000.0 };
        array_view<float, 1> logs(6, numbers);
    
        // See https://msdn.microsoft.com/en-us/library/hh305254.aspx
        parallel_for_each(
            logs.extent,
            [=] (index<1> idx) restrict(amp)
        {
            logs[idx] = concurrency::fast_math::log10(logs[idx]);
        }
        );
    
        // Return a Windows Runtime-compatible type across the ABI
        auto res = ref new Vector<double>();
        int len = safe_cast<int>(logs.extent.size());
        for(int i = 0; i < len; i++)
        {      
            res->Append(logs[i]);
        }
    
        // res is implicitly cast to IVector<double>
        return res;
    }
    

So fügen Sie die Implementierung für GetPrimesOrdered und die zugehörige Hilfsmethode hinzu

  • Fügen Sie in Class1.cpp die Implementierungen für GetPrimesOrdered und die is_prime - Hilfsmethode hinzu. GetPrimesOrdered verwendet eine concurrent_vector-Klasse- und eine parallel_for-Funktion-Schleife zum Aufteilen der Aufgaben und zur Nutzung aller Ressourcen des Computers, auf dem das Programm ausgeführt wird, um Ergebnisse zu erzielen. Nachdem die Ergebnisse berechnet, gespeichert und sortiert wurden, werden sie zu Plattform::Collections::Vector<T> hinzugefügt und als Windows::Foundation::Collections::IVector<T> an Clientcode zurückgegeben.

    Beachten Sie den Code für den Status-Reporter, der dem Client ermöglicht, eine Statusanzeige oder eine andere Benutzeroberfläche zu verknüpfen, um dem Benutzer anzuzeigen, wie lange der Vorgang noch andauert. Die Fortschrittsberichterstellung hat jedoch auch Nachteile. Auf der Komponentenseite muss ein Ereignis ausgelöst und im UI-Thread behandelt werden, und der Statuswert muss in jeder Iteration gespeichert werden. Diesem kann begegnet werden, indem z. B. die Häufigkeit, mit der ein Statusereignis ausgelöst wird, beschränkt wird. Wenn der Aufwand noch immer zu hoch ist oder Sie die Dauer des Vorgangs nicht abschätzen können, sollten Sie die Verwendung eines Statusrings erwägen, der anzeigt, dass der Vorgang gerade ausgeführt wird, nicht jedoch die verbleibende Zeit bis zur Fertigstellung.

    // Determines whether the input value is prime.
    bool Class1::is_prime(int n)
    {
        if (n < 2)
            return false;
        for (int i = 2; i < n; ++i)
        {
            if ((n % i) == 0)
                return false;
        }
        return true;
    }
    
    // This method computes all primes, orders them, then returns the ordered results.
    IAsyncOperationWithProgress<IVector<int>^, double>^ Class1::GetPrimesOrdered(int first, int last)
    {
        return create_async([this, first, last]
        (progress_reporter<double> reporter) -> IVector<int>^ {
            // Ensure that the input values are in range.
            if (first < 0 || last < 0) {
                throw ref new InvalidArgumentException();
            }
            // Perform the computation in parallel.
            concurrent_vector<int> primes;
            long operation = 0;
            long range = last - first + 1;
            double lastPercent = 0.0;
    
            parallel_for(first, last + 1, [this, &primes, &operation, 
                range, &lastPercent, reporter](int n) {
    
                    // Increment and store the number of times the parallel 
                    // loop has been called on all threads combined. There 
                    // is a performance cost to maintaining a count, and 
                    // passing the delegate back to the UI thread, but it's
                    // necessary if we want to display a determinate progress
                    // bar that goes from 0 to 100%. We can avoid the cost by
                    // setting the ProgressBar IsDeterminate property to false
                    // or by using a ProgressRing.
                    if(InterlockedIncrement(&operation) % 100 == 0)
                    {
                        reporter.report(100.0 * operation / range);
                    }
    
                    // If the value is prime, add it to the local vector.
                    if (is_prime(n)) {
                        primes.push_back(n);
                    }
            });
    
            // Sort the results.
            std::sort(begin(primes), end(primes), std::less<int>());      
            reporter.report(100.0);
    
            // Copy the results to a Vector object, which is 
            // implicitly converted to the IVector return type. IVector
            // makes collections of data available to other
            // Windows Runtime components.
            return ref new Vector<int>(primes.begin(), primes.end());
        });
    }
    

So fügen Sie die Implementierung für GetPrimesUnordered hinzu

  1. Im letzten Schritt der Erstellung der C++-Komponente wird die Implementierung für GetPrimesUnordered in Class1.cpp hinzugefügt. Diese Methode gibt jedes gefundene Ergebnis zurück, ohne zu warten, bis alle Ergebnisse gefunden wurden. Jedes Ergebnis wird im Ereignishandler zurückgegeben und in Echtzeit in der Benutzeroberfläche angezeigt. Beachten Sie, dass auch hier ein Status-Reporter verwendet wird. Diese Methode verwendet auch die is_prime-Hilfsmethode.

    // This method returns no value. Instead, it fires an event each time a 
    // prime is found, and passes the prime through the event.
    // It also passes progress info.
    IAsyncActionWithProgress<double>^ Class1::GetPrimesUnordered(int first, int last)
    {
    
        auto window = Windows::UI::Core::CoreWindow::GetForCurrentThread();
        m_dispatcher = window->Dispatcher;
    
    
        return create_async([this, first, last](progress_reporter<double> reporter) {
    
            // Ensure that the input values are in range.
            if (first < 0 || last < 0) {
                throw ref new InvalidArgumentException();
            }
    
            // In this particular example, we don't actually use this to store 
            // results since we pass results one at a time directly back to 
            // UI as they are found. However, we have to provide this variable
            // as a parameter to parallel_for.
            concurrent_vector<int> primes;
            long operation = 0;
            long range = last - first + 1;
            double lastPercent = 0.0;
    
            // Perform the computation in parallel.
            parallel_for(first, last + 1, 
                [this, &primes, &operation, range, &lastPercent, reporter](int n) 
            {
                // Store the number of times the parallel loop has been called  
                // on all threads combined. See comment in previous method.
                if(InterlockedIncrement(&operation) % 100 == 0)
                {
                    reporter.report(100.0 * operation / range);
                }
    
                // If the value is prime, pass it immediately to the UI thread.
                if (is_prime(n))
                {                
                    // Since this code is probably running on a worker 
                    // thread, and we are passing the data back to the 
                    // UI thread, we have to use a CoreDispatcher object.
                    m_dispatcher->RunAsync( CoreDispatcherPriority::Normal,
                        ref new DispatchedHandler([this, n, operation, range]() 
                    {
                        this->primeFoundEvent(n);
    
                    }, Platform::CallbackContext::Any));
    
                }
            });
            reporter.report(100.0);
        });
    }
    
    
  2. Drücken Sie STRG+UMSCHALT+B, um die Komponente zu erstellen.

Erstellen einer JavaScript-Client-App

So erstellen Sie ein JavaScript-Projekt

  1. Hinweis

    Wenn Sie nur einen C#-Client erstellen möchten, können Sie diesen Abschnitt überspringen.

    Öffnen Sie in Projektmappen-Explorer das Kontextmenü des Knotens Projektmappe und wählen Sie die Option Hinzufügen, Neues Projekt aus.

  2. Erweitern Sie JavaScript (ggf. geschachtelt unter Andere Sprachen) und wählen Sie Leere App aus.

  3. Übernehmen Sie den Standardnamen – App1 – durch Auswählen der Schaltfläche OK.

  4. Öffnen Sie das Kontextmenü für den App1-Projektknoten, und wählen Sie dann Als Startprojekt festlegen aus.

  5. Ergänzen Sie WinRT_CPP mit einem Projektverweis:

    1. Öffnen Sie das Kontextmenü des Knotens Verweise und wählen Sie Verweis hinzufügen aus.

    2. Wählen Sie links im Dialogfeld Verweis-Manager die Option Projektmappe und dann Projekte aus.

    3. Wählen Sie in der Mitte WinRT_CPP aus, und wählen Sie dann die Schaltfläche OK.

So fügen Sie HTML-Code hinzu, mit dem die JavaScript-Ereignishandler aufgerufen werden

  • Fügen Sie auf der Seite „default.html“ den folgenden HTML-Code in den <body>-Knoten ein:

    <div id="LogButtonDiv">
         <button id="logButton" onclick="LogButton_Click()">Logarithms using AMP</button>
     </div>
     <div id="LogResultDiv">
         <p id="logResult"></p>
     </div>
     <div id="OrderedPrimeButtonDiv">
         <button id="orderedPrimeButton" onclick="ButtonOrdered_Click()">Primes using parallel_for with sort</button>
     </div>
     <div id="OrderedPrimeProgress">
         <progress id="OrderedPrimesProgressBar" style="-ms-grid-column-span:2" value="0" max="100"></progress>
     </div>
     <div id="OrderedPrimeResultDiv">
         <p id="orderedPrimes">
             Primes found (ordered):
         </p>
     </div>
     <div id="UnorderedPrimeButtonDiv">
         <button id="ButtonUnordered" onclick="ButtonUnordered_Click()">Primes returned as they are produced.</button>
     </div>
     <div id="UnorderedPrimeDiv">
         <progress id="UnorderedPrimesProgressBar" value="0" max="100"></progress>
     </div>
     <div id="UnorderedPrime">
         <p id="unorderedPrimes">
             Primes found (unordered):
         </p>
     </div>
     <div id="ClearDiv">
         <button id="Button_Clear" onclick="ButtonClear_Click()">Clear</button>
     </div>
    
    <div id="LogButtonDiv">
         <button id="logButton" onclick="LogButton_Click()">Logarithms using AMP</button>
     </div>
     <div id="LogResultDiv">
         <p id="logResult"></p>
     </div>
     <div id="OrderedPrimeButtonDiv">
         <button id="orderedPrimeButton" onclick="ButtonOrdered_Click()">Primes using parallel_for with sort</button>
     </div>
     <div id="OrderedPrimeProgress">
         <progress id="OrderedPrimesProgressBar" value="0" max="100"></progress>
     </div>
     <div id="OrderedPrimeResultDiv">
         <p id="orderedPrimes">
             Primes found (ordered):
         </p>
     </div>
     <div id="UnorderedPrimeButtonDiv">
         <button id="ButtonUnordered" onclick="ButtonUnordered_Click()">Primes returned as they are produced.</button>
     </div>
     <div id="UnorderedPrimeDiv">
         <progress id="UnorderedPrimesProgressBar" value="0" max="100"></progress>
     </div>
     <div id="UnorderedPrime">
         <p id="unorderedPrimes">
             Primes found (unordered):
         </p>
     </div>
     <div id="ClearDiv">
         <button id="Button_Clear" onclick="ButtonClear_Click()">Clear</button>
     </div>
    

So fügen Sie Stile hinzu

  • Entfernen Sie in der Datei „default.css“ den body-Stil, und fügen Sie die folgenden Stile hinzu:

    #LogButtonDiv {
    border: orange solid 1px;
    -ms-grid-row: 1; /* default is 1 */
    -ms-grid-column: 1; /* default is 1 */
    }
    #LogResultDiv {
    background: black;
    border: red solid 1px;
    -ms-grid-row: 1;
    -ms-grid-column: 2;
    }
    #UnorderedPrimeButtonDiv, #OrderedPrimeButtonDiv {
    border: orange solid 1px;
    -ms-grid-row: 2;   
    -ms-grid-column:1;
    }
    #UnorderedPrimeProgress, #OrderedPrimeProgress {
    border: red solid 1px;
    -ms-grid-column-span: 2;
    height: 40px;
    }
    #UnorderedPrimeResult, #OrderedPrimeResult {
    border: red solid 1px;
    font-size:smaller;
    -ms-grid-row: 2;
    -ms-grid-column: 3;
    -ms-overflow-style:scrollbar;
    }
    

So fügen Sie die JavaScript-Ereignishandler hinzu, welche die Komponenten-DLL aufrufen

  1. Fügen Sie am Ende der Datei "default.js" die folgenden Funktionen hinzu: Diese Funktionen werden bei Auswahl der Schaltflächen auf der Hauptseite aufgerufen. Beachten Sie, wie JavaScript die C++-Klasse aktiviert und dann die zugehörigen Methoden aufruft und mithilfe der Rückgabewerte die HTML-Bezeichnungen ausfüllt.

    
    var nativeObject = new WinRT_CPP.Class1();
    
    function LogButton_Click() {
    
        var val = nativeObject.computeResult(0);
        var result = "";
    
        for (i = 0; i < val.length; i++) {
            result += val[i] + "<br/>";
        }
    
        document.getElementById('logResult').innerHTML = result;
    }
    
    function ButtonOrdered_Click() {
        document.getElementById('orderedPrimes').innerHTML = "Primes found (ordered): ";
    
        nativeObject.getPrimesOrdered(2, 10000).then(
            function (v) {
                for (var i = 0; i < v.length; i++)
                    document.getElementById('orderedPrimes').innerHTML += v[i] + " ";
            },
            function (error) {
                document.getElementById('orderedPrimes').innerHTML += " " + error.description;
            },
            function (p) {
                var progressBar = document.getElementById("OrderedPrimesProgressBar");
                progressBar.value = p;
            });
    }
    
    function ButtonUnordered_Click() {
        document.getElementById('unorderedPrimes').innerHTML = "Primes found (unordered): ";
        nativeObject.onprimefoundevent = handler_unordered;
    
        nativeObject.getPrimesUnordered(2, 10000).then(
            function () { },
            function (error) {
                document.getElementById("unorderedPrimes").innerHTML += " " + error.description;
            },
            function (p) {
                var progressBar = document.getElementById("UnorderedPrimesProgressBar");
                progressBar.value = p;
            });
    }
    
    var handler_unordered = function (n) {
        document.getElementById('unorderedPrimes').innerHTML += n.target.toString() + " ";
    };
    
    function ButtonClear_Click() {
    
        document.getElementById('logResult').innerHTML = "";
        document.getElementById("unorderedPrimes").innerHTML = "";
        document.getElementById('orderedPrimes').innerHTML = "";
        document.getElementById("UnorderedPrimesProgressBar").value = 0;
        document.getElementById("OrderedPrimesProgressBar").value = 0;
    }
    
    
    
    var nativeObject = new WinRT_CPP.Class1();
    
    function LogButton_Click() {
    
        var val = nativeObject.computeResult(0);
        var result = "";
    
        for (i = 0; i < val.length; i++) {
            result += val[i] + "<br/>";
        }
    
        document.getElementById('logResult').innerHTML = result;
    }
    
    function ButtonOrdered_Click() {
        document.getElementById('orderedPrimes').innerHTML = "Primes found (ordered): ";
    
        nativeObject.getPrimesOrdered(2, 10000).then(
            function (v) {
                for (var i = 0; i < v.length; i++)
                    document.getElementById('orderedPrimes').innerHTML += v[i] + " ";
            },
            function (error) {
                document.getElementById('orderedPrimes').innerHTML += " " + error.description;
            },
            function (p) {
                var progressBar = document.getElementById("OrderedPrimesProgressBar");
                progressBar.value = p;
            });
    }
    
    function ButtonUnordered_Click() {
        document.getElementById('unorderedPrimes').innerHTML = "Primes found (unordered): ";
        nativeObject.onprimefoundevent = handler_unordered;
    
        nativeObject.getPrimesUnordered(2, 10000).then(
            function () { },
            function (error) {
                document.getElementById("unorderedPrimes").innerHTML += " " + error.description;
            },
            function (p) {
                var progressBar = document.getElementById("UnorderedPrimesProgressBar");
                progressBar.value = p;
            });
    }
    
    var handler_unordered = function (n) {
        document.getElementById('unorderedPrimes').innerHTML += n.target.toString() + " ";
    };
    
    function ButtonClear_Click() {
    
        document.getElementById('logResult').innerHTML = "";
        document.getElementById("unorderedPrimes").innerHTML = "";
        document.getElementById('orderedPrimes').innerHTML = "";
        document.getElementById("UnorderedPrimesProgressBar").value = 0;
        document.getElementById("OrderedPrimesProgressBar").value = 0;
    }
    
    
  2. Drücken Sie F5, um die Anwendung auszuführen.

Erstellen einer C#-Client-App

Die Komponenten-DLL für Windows-Runtime in C++ kann von einem C#-Client ebenso problemlos aufgerufen werden wie von einem JavaScript-Client. In den folgenden Schritten wird gezeigt, wie ein C#-Client erstellt wird, der dem JavaScript-Client im vorherigen Abschnitt weitgehend ähnelt.

So erstellen Sie ein C#-Projekt

  1. Öffnen Sie in Projektmappen-Explorer das Kontextmenü des Knotens Projektmappe, und wählen Sie dann die Option Hinzufügen, Neues Projekt aus.

  2. Erweitern Sie Visual C# (ggf. geschachtelt unter Andere Sprachen), wählen Sie links Windows Store aus, und wählen Sie dann in der Mitte Leere App aus.

  3. Nennen Sie diese App CS_Client, und wählen Sie dann die Schaltfläche OK.

  4. Öffnen Sie das Kontextmenü für den CS_Client-Projektknoten, und wählen Sie dann Als Startprojekt festlegen aus.

  5. Ergänzen Sie WinRT_CPP mit einem Projektverweis:

    1. Öffnen Sie das Kontextmenü des Knotens Verweise und wählen Sie Verweis hinzufügen aus.

    2. Wählen Sie links im Dialogfeld Verweis-Manager die Option Projektmappe und dann Projekte aus.

    3. Wählen Sie in der Mitte WinRT_CPP aus, und wählen Sie dann die Schaltfläche OK.

So fügen Sie XAML hinzu, das die Benutzeroberfläche definiert

  • Fügen Sie das folgende ScrollViewer-Objekt sowie den zugehörigen Inhalt zum Raster in „mainpage.xaml“ hinzu:

    <ScrollViewer>
                <StackPanel Width="1400">
    
                    <Button x:Name="Button1" Width="340" Height="50"  Margin="0,20,20,20" Content="Synchronous Logarithm Calculation" FontSize="16" Click="Button1_Click_1"/>
                    <TextBlock x:Name="Result1" Height="100" FontSize="14"></TextBlock>
                <Button x:Name="PrimesOrderedButton" Content="Prime Numbers Ordered" FontSize="16" Width="340" Height="50" Margin="0,20,20,20" Click="PrimesOrderedButton_Click_1"></Button>
                <ProgressBar x:Name="PrimesOrderedProgress" IsIndeterminate="false" Height="40"></ProgressBar>
                    <TextBlock x:Name="PrimesOrderedResult" MinHeight="100" FontSize="10" TextWrapping="Wrap"></TextBlock>
                <Button x:Name="PrimesUnOrderedButton" Width="340" Height="50" Margin="0,20,20,20" Click="PrimesUnOrderedButton_Click_1" Content="Prime Numbers Unordered" FontSize="16"></Button>
                <ProgressBar x:Name="PrimesUnOrderedProgress" IsIndeterminate="false" Height="40" ></ProgressBar>
                <TextBlock x:Name="PrimesUnOrderedResult" MinHeight="100" FontSize="10" TextWrapping="Wrap"></TextBlock>
    
                <Button x:Name="Clear_Button" Content="Clear" HorizontalAlignment="Left" Margin="0,20,20,20" VerticalAlignment="Top" Width="341" Click="Clear_Button_Click" FontSize="16"/>
            </StackPanel>
    </ScrollViewer>
    

So fügen Sie die Ereignishandler für die Schaltflächen hinzu

  1. Öffnen Sie im Projektmappen-Explorer die Datei „mainpage.xaml.cs“. (Die Datei ist ggf. unter „mainpage.xaml“ geschachtelt.) Fügen Sie eine using-Direktive für System.Text hinzu, und fügen Sie dann den Ereignishandler für die Logarithmusberechnung in der MainPage-Klasse direkt nach OnNavigateTo hinzu.

    private void Button1_Click_1(object sender, RoutedEventArgs e)
    {
        // Create the object
        var nativeObject = new WinRT_CPP.Class1();
    
        // Call the synchronous method. val is an IList that
        // contains the results. 
        var val = nativeObject.ComputeResult(0);
        StringBuilder result = new StringBuilder();
        foreach (var v in val)
        {
            result.Append(v).Append(System.Environment.NewLine);
        }
        this.Result1.Text = result.ToString();
    }
    
  2. Fügen Sie den Ereignishandler für das geordnete Ergebnis hinzu:

    async private void PrimesOrderedButton_Click_1(object sender, RoutedEventArgs e)
    {
        var nativeObject = new WinRT_CPP.Class1();
    
        StringBuilder sb = new StringBuilder();
        sb.Append("Primes found (ordered): ");
    
        PrimesOrderedResult.Text = sb.ToString();
    
        // Call the asynchronous method
        var asyncOp = nativeObject.GetPrimesOrdered(2, 100000);
    
        // Before awaiting, provide a lambda or named method
        // to handle the Progress event that is fired at regular
        // intervals by the asyncOp object. This handler updates
        // the progress bar in the UI.
        asyncOp.Progress = (asyncInfo, progress) =>
            {
                PrimesOrderedProgress.Value = progress;
            };
    
        // Wait for the operation to complete
        var asyncResult = await asyncOp;
    
        // Convert the results to strings
        foreach (var result in asyncResult)
        {
            sb.Append(result).Append(" ");
        }
    
        // Display the results
        PrimesOrderedResult.Text = sb.ToString();
    }
    
  3. Fügen Sie den Ereignishandler für das ungeordnete Ergebnis und für die Schaltfläche hinzu. Letztere löscht die Ergebnisse, damit Sie den Code erneut ausführen können.

    private void PrimesUnOrderedButton_Click_1(object sender, RoutedEventArgs e)
    {
        var nativeObject = new WinRT_CPP.Class1();
    
        StringBuilder sb = new StringBuilder();
        sb.Append("Primes found (unordered): ");
        PrimesUnOrderedResult.Text = sb.ToString();
    
        // primeFoundEvent is a user-defined event in nativeObject
        // It passes the results back to this thread as they are produced
        // and the event handler that we define here immediately displays them.
        nativeObject.primeFoundEvent += (n) =>
        {
            sb.Append(n.ToString()).Append(" ");
            PrimesUnOrderedResult.Text = sb.ToString();
        };
    
        // Call the async method.
        var asyncResult = nativeObject.GetPrimesUnordered(2, 100000);
    
        // Provide a handler for the Progress event that the asyncResult
        // object fires at regular intervals. This handler updates the progress bar.
        asyncResult.Progress += (asyncInfo, progress) =>
            {
                PrimesUnOrderedProgress.Value = progress;
            };
    }
    
    private void Clear_Button_Click(object sender, RoutedEventArgs e)
    {
        PrimesOrderedProgress.Value = 0;
        PrimesUnOrderedProgress.Value = 0;
        PrimesUnOrderedResult.Text = "";
        PrimesOrderedResult.Text = "";
        Result1.Text = "";
    }
    

Ausführen der App

Wählen Sie entweder das C#-Projekt oder das JavaScript-Projekt als Startprojekt aus, indem Sie das Kontextmenü für den Projektknoten in Projektmappen-Explorer öffnen und Als Startprojekt festlegen auswählen. Drücken Sie anschließend F5, um die Seite mit Debuggen auszuführen, oder drücken Sie STRG+F5, um die Seite ohne Debuggen auszuführen.

Überprüfen der Komponente im Objektkatalog (optional)

Im Objektkatalog können Sie alle Windows-Runtime-Typen überprüfen, die in WINMD-Dateien definiert werden. Dazu gehören auch die Typen im Platform-Namespace und im Standard-Namespace. Da die Typen im Platform::Collections-Namespace in der Headerdatei „collections.h“ und nicht in einer WINMD-Datei definiert sind, werden sie nicht in Objektkatalog angezeigt.

So überprüfen Sie die Komponente

  1. Wählen Sie in der Menüleiste Ansicht, Weitere Fenster, Objektkatalog aus.

  2. Erweitern Sie links im Objektkatalog den Knoten WinRT_CPP, um die in der Komponente definierten Typen und Methoden einzusehen.

Tipps zum Debuggen

Eine bessere Debugleistung erzielen Sie, wenn Sie die Debugsymbole von den öffentlichen Microsoft-Symbolservern herunterladen:

  1. Wählen Sie in der Menüleiste Extras, Optionen aus.

  2. Erweitern Sie im Dialogfeld Optionen den Eintrag Debugging, und wählen Sie Symbole aus.

  3. Wählen Sie Microsoft-Symbolserver aus, und wählen Sie dann die Schaltfläche OK.

Das erstmalige Herunterladen der Symbole kann etwas dauern. Wenn Sie das nächste Mal F5 drücken, können Sie den Vorgang etwas beschleunigen, indem Sie ein lokales Verzeichnis angeben, in dem die Symbole zwischengespeichert werden sollen.

Wenn Sie eine JavaScript-Projektmappe debuggen, die über eine Komponenten-DLL verfügt, können Sie den Debugger so festlegen, dass entweder das schrittweise Ausführen des Skripts oder das schrittweise Ausführen des systemeigenen Codes in der Komponente, nicht jedoch beides aktiviert wird. Um die Einstellung zu ändern, öffnen Sie in Projektmappen-Explorer das Kontextmenü des JavaScript-Projektknotens, und wählen Sie dann Eigenschaften, Debugging, Debuggertyp aus.

Im Paket-Designer müssen die entsprechenden Funktionen ausgewählt sein. Wenn Sie beispielsweise versuchen, programmgesteuert auf eine Datei im Ordner "Bilder" zuzugreifen, aktivieren Sie auf jeden Fall das Kontrollkästchen Bildbibliothek im Bereich Funktionen.

Werden die öffentlichen Eigenschaften oder Methoden der Komponente mithilfe des JavaScript-Codes nicht erkannt, überprüfen Sie, dass in JavaScript die Kamel-Schreibweise verwendet wird. Beispielsweise muss in JavaScript auf die ComputeResult-C++-Methode mit computeResult verwiesen werden.

Wenn Sie ein Windows-Runtime-Komponentenprojekt in C++ aus einer Projektmappe löschen, muss auch der Projektverweis manuell aus dem JavaScript-Projekt entfernt werden. Andernfalls können anschließend keine Debugging- oder Erstellungsvorgänge ausgeführt werden. Bei Bedarf können Sie dann einen Assemblyverweis auf die DLL hinzufügen.

Siehe auch

Referenz

Roadmap for Windows Store apps using C++

Weitere Ressourcen

Entwickeln des Reise-Optimierers von Bing Maps, einer Windows Store-App in JavaScript und C++