次の方法で共有


チュートリアル : C++ での基本 Windows ランタイム コンポーネントの作成、および JavaScript または C# からの呼び出し

このチュートリアルでは、JavaScript、C#、または Visual Basic から呼び出すことのできるの基本的な Windows ランタイム コンポーネント DLL を作成する方法を示します。 このチュートリアルを開始する前に、抽象バイナリ インターフェイス (ABI)、ref クラス、Visual C++ コンポーネント拡張などの概念を理解しておくなら、ref クラスの扱いが簡単になります。 詳細については、「C++ での Windows ランタイム コンポーネントの作成」および「Visual C++ の言語リファレンス (C++/CX)」を参照してください。

C++ コンポーネント DLL の作成

この例では、コンポーネント プロジェクトを最初に作成しますが、JavaScript のプロジェクトを最初に作成することもできます。 順序は重要ではありません。

コンポーネントのメイン クラスには、プロパティとメソッド定義の例、およびイベント宣言が含まれます。 これらは扱いの方法を示すために用意されます。 必須ではなく、この例では、生成されたコードはすべて独自のコードで置き換えられます。

C++ コンポーネント プロジェクトを作成するには

  1. Visual Studio メニュー バーで [ファイル] をクリックし、[新規] を選択し、[プロジェクト] をクリックします。

  2. [新しいプロジェクト] ダイアログ ボックスで、左ペインの [Visual C++] を展開し、Windows ストア アプリのノードを選択します。

  3. 中央のペインで、[Windows ランタイム コンポーネント] をクリックし、プロジェクト名を WinRT_CPP にします。

  4. [OK] をクリックします。

アクティブ化可能なクラスをコンポーネントに追加するには

  • アクティブ化可能なクラスは、クライアント コードが new 式 (Visual Basic の New、または C++ の ref new) を使用して作成できるクラスです。 コンポーネントでは、public ref class sealed として宣言します。 実際、Class1.h と .cpp ファイルには既に ref クラスがあります。 名前は変更できますが、この例では既定の名前 Class1 を使用します。 必要に応じて、コンポーネント内で追加の ref クラスまたは regular クラスを定義できます。 ref クラスの詳細については、「型システム (C++/CX)」を参照してください。

必須の #include ディレクティブを追加するには

  • これらの #include ディレクティブを Class1.h に追加します。

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

    collection.h は、Windows ランタイム によって定義されている、Platform::Collections::Vector クラスPlatform::Collections::Map クラス のように、言語に依存しないインターフェイスを実装する C++ の具象クラス用のヘッダー ファイルです。 amp ヘッダーは、GPU で計算を実行する目的で使用します。 これらに相当する Windows ランタイム は存在しませんが、これらはプライベートであるため、問題はありません。 一般に、パフォーマンス上の理由により、コンポーネント内部では ISO C++ のコードや、標準ライブラリを使用する必要があります。Windows ランタイム 型で表現する必要があるのは、Windows ランタイム インターフェイスのみです。

名前空間のスコープでデリゲートを追加するには

  • デリゲートは、メソッドのパラメーターおよび戻り値の型を定義するコンストラクトです。 イベントは、特定のデリゲート型のインスタンスであり、そのイベントにサブスクライブするイベント ハンドラー メソッドは、そのデリゲート内で指定されているシグネチャを持つ必要があります。 次のコードは、int を受け取り、void を返すデリゲート型を定義します。 次に、このコードは、この型のパブリック event を宣言します。この結果、クライアント コードは、このイベントが発生したときに呼び出されるメソッドを提供できます。

    Class1.h の中で、Class1 宣言の直前に、名前空間のスコープで次のデリゲート宣言を追加します。

    public delegate void PrimeFoundHandler(int result);    
    

    ヒント

    Visual Studio に貼り付けた時点でコードが整列されていない場合、Ctrl+K+D キーを押すだけで、ファイル全体でインデントを修正できます。

パブリック メンバーを追加するには

  • クラスでは 3 つのパブリック メソッドと 1 つのパブリック イベントを公開します。 最初のメソッドは常に非常に高速で実行されるため、同期型です。 他の 2 つのメソッドは時間がかかる可能性があるため、UI スレッドをブロックしないように非同期型にします。 これらのメソッドは IAsyncOperationWithProgress および IAsyncActionWithProgress を返します。 前者は結果を返す 1 つの非同期メソッドを定義し、後者は void を返す 1 つの非同期メソッドを定義します。 また、これらのインターフェイスにより、クライアント コードは操作の進行状況に関する更新を受け取ることができます。

    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;
    

プライベート メンバーを追加するには

  • クラスには 3 つのプライベート メンバーが含まれています。数値計算用の 2 つのヘルパー メソッド、およびワーカー スレッドから UI スレッドへのイベント呼び出しをマーシャリングするために使用される 1 つの CoreDispatcher オブジェクトです。

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

ヘッダーおよび名前空間のディレクティブを追加するには

  1. Class1.cpp で、これらの #include ディレクティブを追加します。

    #include <ppltasks.h>
    #include <concurrent_vector.h>
    
  2. ここで、次の using ステートメントを追加し、必要な名前空間を取り込めるようにします。

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

ComputeResult の実装を追加するには

  • Class1.cpp で、次のメソッドの実装を追加します。 このメソッドは、呼び出し元のスレッドで同期的に実行されますが、AMP C++ を使用して GPU で計算を並列化するため、非常に高速に処理されます。 詳細については、「C++ AMP の概要」を参照してください。 結果は Platform::Collections::Vector<T> 具象型に対して追加され、返されるときに、暗黙的に Windows::Foundation::Collections::IVector<T> に変換されます。

    //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;
    }
    

GetPrimesOrdered とそのヘルパー メソッドの実装を追加するには

  • Class1.cpp で、GetPrimesOrdered および is_prime ヘルパー メソッドの実装を追加します。 GetPrimesOrdered は concurrent_vector クラス および parallel_for 関数 のループを使用して作業を分割し、結果を生成するためにプログラムを実行しているコンピューターのリソースを最大限に使用します。 結果の計算、保存、および並べ替えが終わった後、結果は Platform::Collections::Vector<T> に追加され、Windows::Foundation::Collections::IVector<T> の形でクライアント コードに返されます。

    進行状況レポート機能のコードに注目してください。クライアントはこのコードを使用して、どれほどの時間を要する見込みかユーザーに示すプログレス バーまたは他の UI をフックすることができます。 進行状況のレポートには、コストがかかります。 イベントは、コンポーネント側で発生させ、UI スレッドで処理する必要があります。また、イテレーションごとに、進行状況の値を保存する必要があります。 コストを最小化する 1 つの方法は、進行状況イベントの発生頻度を制限することです。 それでもまだコストが非常に大きい場合や、操作の長さを推定できない場合は、操作が進行中であることを示し、しかし完了までの残り時間を示さない進行状況リング (円形) を使用することを検討してください。

    // 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());
        });
    }
    

GetPrimesUnordered の実装を追加するには

  1. C++ コンポーネントを作成する最後の手順は、GetPrimesUnordered の実装を Class1.cpp に追加することです。 このメソッドは、すべての結果が見つかるまで待たずに、結果が見つかるたびに各結果を返します。 各結果は、イベント ハンドラーの中で返され、UI にリアルタイムで表示されます。 ここでも、進行状況レポート機能が使用されていることに注意してください。 このメソッドも、is_prime ヘルパー メソッドを使用します。

    // 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. Ctrl キーと Shift キーを押しながら B キーを押してコンポーネントをビルドします。

JavaScript クライアント アプリケーションの作成

JavaScript プロジェクトを作成するには

  1. 注意

    C# クライアントのみを作成することを希望する場合は、このセクションをスキップできます。

    ソリューション エクスプローラーで、[ソリューション] ノードのショートカット メニューを開き、[追加][新しいプロジェクト] の順にクリックします。

  2. [JavaScript] ([他の言語] の下に入れ子になっている可能性があります) を展開し、[空のアプリケーション] を選択します。

  3. [OK] をクリックし、既定の名前である App1 を受け入れます。

  4. App1 プロジェクト ノードのショートカット メニューを開き、[スタートアップ プロジェクトに設定] をクリックします。

  5. 次のように、WinRT_CPP へのプロジェクト参照を追加します。

    1. [参照] ノードのショートカット メニューを開き、[参照の追加] をクリックします。

    2. [参照マネージャー] ダイアログ ボックスの左ペインで、[ソリューション] を選択して、[プロジェクト] をクリックします。

    3. 中央のペインで [WinRT_CPP] を選択し、[OK] をクリックします。

JavaScript イベント ハンドラーを呼び出す HTML を追加するには

  • default.html ページの <body> ノードに、この HTML を貼り付けます。

    <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>
    

スタイルを追加するには

  • default.css で、body スタイルを削除し、次のスタイルを追加します。

    #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;
    }
    

コンポーネント DLL 内の呼び出しを行う JavaScript イベント ハンドラーを追加するには

  1. 次の関数を default.js ファイルの末尾に追加します。 これらの関数は、メイン ページのボタンが選択されたときに呼び出されます。 JavaScript が C++ クラスをアクティブにして、そのメソッドを呼び出し、戻り値を使用して HTML ラベルを設定することに注目します。

    
    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. F5 キーを押して、アプリケーションを実行します。

C# クライアント アプリケーションの作成

C++ の Windows ランタイム コンポーネント DLL は、JavaScript クライアントから呼び出す場合と同様の簡単さで、C# クライアントから呼び出すことができます。 次の手順では、前のセクションの JavaScript クライアントとほぼ同等である C# クライアントを作成する方法を示します。

C# プロジェクトを作成するには

  1. ソリューション エクスプローラーで、[ソリューション] ノードのショートカット メニューを開き、[追加][新しいプロジェクト] の順にクリックします。

  2. [Visual C#] ([他の言語] の下に入れ子になっている可能性があります) を展開し、左ペインで [Windows ストア] をクリックし、中央のペインで [空のアプリケーション] をクリックします。

  3. このアプリケーションに CS_Client という名前を付け、[OK] をクリックします。

  4. CS_Client プロジェクト ノードのショートカット メニューを開き、[スタートアップ プロジェクトに設定] をクリックします。

  5. 次のように、WinRT_CPP へのプロジェクト参照を追加します。

    1. [参照] ノードのショートカット メニューを開き、[参照の追加] をクリックします。

    2. [参照マネージャー] ダイアログ ボックスの左ペインで、[ソリューション] を選択して、[プロジェクト] をクリックします。

    3. 中央のペインで [WinRT_CPP] を選択し、[OK] をクリックします。

ユーザー インターフェイスを定義する XAML を追加するには

  • mainpage.xaml 内のグリッドに、次の ScrollViewer とその内容を追加します:

    <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>
    

ボタンに対応するイベント ハンドラーを追加するには

  1. ソリューション エクスプローラーで、mainpage.xaml.cs を開きます (このファイルは mainpage.xaml の下に入れ子になっている可能性があります)。System.Text に対応する using ディレクティブを追加し、その後、MainPage クラスの中で、OnNavigateTo の直後に、Logarithm (対数) の計算に対応するイベント ハンドラーを追加します。

    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. 次のように、順序付けされた結果に対応するイベント ハンドラーを追加します。

    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. 順序なしの結果に対応するイベント ハンドラーと、コードを再び実行できるように結果をクリアするボタンに対応するイベント ハンドラーを追加します。

    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 = "";
    }
    

アプリケーションの実行

スタートアップ プロジェクトとして、C# プロジェクトまたは JavaScript プロジェクトのどちらかを選択するために、ソリューション エクスプローラーでプロジェクト ノードのショートカット メニューを開き、[スタートアップ プロジェクトに設定] をクリックします。 デバッグを行って実行する場合は F5 キーを押し、デバッグを行わない場合は Ctrl キーを押しながら F5 キーを押します。

オブジェクト ブラウザーでコンポーネントを検査 (省略可能)

オブジェクト ブラウザーで、.winmd ファイル内で定義されている Windows ランタイム のすべての型を検査できます。 これには Platform 名前空間と既定の名前空間の型が含まれます。 ただし、Platform::Collections 名前空間内の型は、winmd ファイルではなく、ヘッダー ファイル collections.h 内で定義されているため、オブジェクト ブラウザー内に表示されません。

コンポーネントを検査するには

  1. メニュー バーで、[表示][その他のウィンドウ][オブジェクト ブラウザー] の順にクリックします。

  2. オブジェクト ブラウザーの左ペインで [WinRT_CPP] ノードを展開し、コンポーネントで定義されているメソッドや型を表示します。

デバッグのヒント

より詳細なデバッグ機能については、パブリックの Microsoft シンボル サーバーからデバッグ シンボルをダウンロードしてください。

  1. メニュー バーの [ツール][オプション] の順にクリックします。

  2. [オプション] ダイアログ ボックスで、[デバッグ] を展開し、[シンボル] をクリックします。

  3. [Microsoft シンボル サーバー] をクリックし、[OK] をクリックします。

初回のシンボル ダウンロードには時間がかかる場合があります。 次回に F5 キーを押したときのパフォーマンスを向上させるには、シンボルをキャッシュするローカル ディレクトリを指定します。

コンポーネント DLL を含む JavaScript ソリューションをデバッグする場合、デバッガーを設定して、スクリプトのステップ実行か、ネイティブ コードのステップ実行を有効にできますが、その両方を同時に有効にすることはできません。 設定を変更するには、ソリューション エクスプローラーにある JavaScript プロジェクト ノードのショートカット メニューを開き、[プロパティ][デバッグ][デバッガーの種類] の順にクリックします。

パッケージ デザイナーで適切な機能を選択してください。 たとえば、プログラムを使用してピクチャ フォルダーのファイルにアクセスする場合、パッケージ デザイナーの [機能] ペインの [画像ライブラリ] チェック ボックスをオンにしてください。

JavaScript コードがコンポーネントのパブリック プロパティまたはメソッドを認識していない場合、JavaScript で Camel 形式の大文字小文字の区別を使用していることを確認します。 たとえば、ComputeResult C++ メソッドは、JavaScript では computeResult として参照する必要があります。

ソリューションから C++ Windows ランタイム コンポーネント プロジェクトを削除する場合、JavaScript のプロジェクトから手動でプロジェクト参照も削除する必要があります。 これを行わなかった場合、後続のデバッグまたはビルド操作が妨げられます。 その後、必要に応じて DLL にアセンブリ参照を追加できます。

参照

関連項目

Roadmap for Windows Store apps using C++

その他の技術情報

JavaScript および C++ での Windows ストア アプリ (Bing Maps Trip Optimizer) の開発