チュートリアル: C++/CX での Windows ランタイム コンポーネントの作成と JavaScript または C# からの呼び出しWalkthrough: Creating a Windows Runtime component in C++/CX, and calling it from JavaScript or C#

注意

このトピックは、C++/CX アプリケーションの管理ができるようにすることを目的としています。This topic exists to help you maintain your C++/CX application. ただし、新しいアプリケーションには C++/WinRT を使用することをお勧めします。But we recommend that you use C++/WinRT for new applications. C++/WinRT は Windows ランタイム (WinRT) API の標準的な最新の C++17 言語プロジェクションであり、ヘッダー ファイル ベースのライブラリとして実装され、最新の Windows API への最上位アクセス権を提供するように設計されています。C++/WinRT is an entirely standard modern C++17 language projection for Windows Runtime (WinRT) APIs, implemented as a header-file-based library, and designed to provide you with first-class access to the modern Windows API. C++/WinRTを使用して、Windows ランタイム コンポーネントを作成する方法については、C++/WinRT でのイベントの作成を参照してください。To learn how to create a Windows Runtime Component using C++/WinRT, see Author events in C++/WinRT.

このチュートリアルでは、JavaScript、C#、または Visual Basic から呼び出すことができる基本的な Windows ランタイム コンポーネント DLL を作成する方法について説明します。This walkthrough shows how to create a basic Windows Runtime Component DLL that's callable from JavaScript, C#, or Visual Basic. このチュートリアルを開始する前に、抽象バイナリ インターフェイス (ABI)、ref クラス、Visual C++ コンポーネント拡張などの概念を必ず理解しておいてください。ref クラスの操作が容易になります。Before you begin this walkthrough, make sure that you understand concepts such as the Abstract Binary Interface (ABI), ref classes, and the Visual C++ Component Extensions that make working with ref classes easier. 詳しくは、「C++ での Windows ランタイム コンポーネントの作成」および「Visual C++ の言語リファレンス (C++/CX)」をご覧ください。For more information, see Creating Windows Runtime Components in C++ and Visual C++ Language Reference (C++/CX).

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

この例では、最初にコンポーネント プロジェクトを作成しますが、JavaScript プロジェクトを最初に作成しても構いません。In this example, we create the component project first, but you could create the JavaScript project first. 順序は重要ではありません。The order doesn’t matter.

コンポーネントのメイン クラスには、プロパティとメソッドの定義およびイベント宣言の例が含まれています。Notice that the main class of the component contains examples of property and method definitions, and an event declaration. これらは方法を示すことだけを目的に用意されており、These are provided just to show you how it's done. 必須ではありません。この例では、生成されたコードはすべて独自のコードに置き換えます。They are not required, and in this example, we'll replace all of the generated code with our own code.

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

  1. Visual Studio のメニュー バーで、 [ファイル]、[新規作成]、[プロジェクト] の順にクリックします。On the Visual Studio menu bar, choose File, New, Project.

  2. [新しいプロジェクト] ダイアログ ボックスの左ペインで、 [Visual C++] を展開し、ユニバーサル Windows アプリのノードを選択します。In the New Project dialog box, in the left pane, expand Visual C++ and then select the node for Universal Windows apps.

  3. 中央のウィンドウで次のように選択します。 Windows ランタイム コンポーネントし名前をプロジェクト WinRT_CPP します。In the center pane, select Windows Runtime Component and then name the project WinRT_CPP.

  4. [OK] ボタンをクリックします。Choose the OK button.

コンポーネントに、アクティブ化可能なクラスを追加するにはTo add an activatable class to the component

アクティブ化可能なクラスとは、クライアント コードで new 式 (Visual Basic では New、C++ では ref new) を使って作成できるクラスのことです。An activatable class is one that client code can create by using a new expression (New in Visual Basic, or ref new in C++). コンポーネントでは、public ref class sealed として宣言します。In your component, you declare it as public ref class sealed. 実際には、Class1.h ファイルと .cpp ファイルに ref クラスが既に含まれています。In fact, the Class1.h and .cpp files already have a ref class. 名前を変更することはできますが、この例では既定の名前 (Class1) を使います。You can change the name, but in this example we’ll use the default name—Class1. 必要に応じて、コンポーネント内で追加の ref クラスまたは regular クラスを定義できます。You can define additional ref classes or regular classes in your component if they are required. ref クラスについて詳しくは、「型システム (C++/CX)」をご覧ください。For more information about ref classes, see Type System (C++/CX).

次の追加#ディレクティブを Class1.h に。Add these #include directives to Class1.h:

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

collection.h は、Windows ランタイムによって定義されている言語に依存しないインターフェイスを実装する C++ の具象クラス (Platform::Collections::Vector クラスや Platform::Collections::Map クラスなど) のヘッダー ファイルです。collection.h is the header file for C++ concrete classes such as the Platform::Collections::Vector class and the Platform::Collections::Map class, which implement language-neutral interfaces that are defined by the Windows Runtime. amp ヘッダーは、GPU で計算を実行する際に使用されます。The amp headers are used to run computations on the GPU. Windows ランタイムには amp ヘッダーに相当するものはありませんが、これらはプライベートであるため、問題はありません。They have no Windows Runtime equivalents, and that’s fine because they are private. 一般に、パフォーマンス上の理由から、コンポーネント内部では ISO C++ コードと標準ライブラリを使います。Windows ランタイム型で表現する必要があるのは、Windows ランタイム インターフェイスだけです。In general, for performance reasons you should use ISO C++ code and standard libraries internally within the component; it’s just the Windows Runtime interface that must be expressed in Windows Runtime types.

名前空間スコープでデリゲートを追加するにはTo add a delegate at namespace scope

デリゲートとは、メソッドのパラメーターと戻り値の型を定義するコンストラクトです。A delegate is a construct that defines the parameters and return type for methods. イベントは特定のデリゲート型のインスタンスであり、イベントにサブスクライブするイベント ハンドラー メソッドには、デリゲートで指定されているシグネチャが必要です。An event is an instance of a particular delegate type, and any event handler method that subscribes to the event must have the signature that's specified in the delegate. 次のコードでは、int を受け取り、void を返すデリゲート型を定義します。The following code defines a delegate type that takes an int and returns void. 次に、このコードでこの型のパブリック イベントを宣言します。これにより、クライアント コードはイベントが発生したときに呼び出されるメソッドを提供できるようになります。Next the code declares a public event of this type; this enables client code to provide methods that are invoked when the event is fired.

Class1.h で、Class1 宣言の直前に名前空間スコープで次のデリゲート宣言を追加します。Add the following delegate declaration at namespace scope in Class1.h, just before the Class1 declaration.

public delegate void PrimeFoundHandler(int result);

Visual Studio に貼り付けたときにコードが整列されていない場合は、Ctrl + K + D キーを押すと、ファイル全体のインデントが修正されます。If the code isn’t lining up correctly when you paste it into Visual Studio, just press Ctrl+K+D to fix the indentation for the entire file.

パブリック メンバーを追加するにはTo add the public members

クラスで 3 つのパブリック メソッドと 1 つのパブリック イベントを公開します。The class exposes three public methods and one public event. 最初のメソッドは常に高速で実行されるので、同期メソッドです。The first method is synchronous because it always executes very fast. 他の 2 つのメソッドは時間がかかる場合があるので、UI スレッドをブロックしないように非同期にします。Because the other two methods might take some time, they are asynchronous so that they don’t block the UI thread. これらのメソッドは、IAsyncOperationWithProgress と IAsyncActionWithProgress を返します。These methods return IAsyncOperationWithProgress and IAsyncActionWithProgress. 前者は結果を返す非同期メソッドを定義し、後者は void を返す非同期メソッドを定義します。The former defines an async method that returns a result, and the latter defines an async method that returns void. また、これらのインターフェイスにより、クライアント コードは操作の進行状況の更新を受け取ることができます。These interfaces also enable client code to receive updates on the progress of the operation.

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;

プライベート メンバーを追加するにはTo add the private members

クラスには 3 つのプライベート メンバーが含まれています。数値計算用の 2 つのヘルパー メソッドと、ワーカー スレッドから UI スレッドにイベント呼び出しをマーシャリングするために使われる CoreDispatcher オブジェクトです。The class contains three private members: two helper methods for the numeric computations and a CoreDispatcher object that’s used to marshal the event invocations from worker threads back to the UI thread.

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

ヘッダーと名前空間のディレクティブを追加するにはTo add the header and namespace directives

  1. Class1.cpp で、次の #include ディレクティブを追加します。In Class1.cpp, add these #include directives:
#include <ppltasks.h>
#include <concurrent_vector.h>
  1. 次の using ステートメントを追加して必要な名前空間を追加します。Now add these using statements to pull in the required namespaces:
using namespace concurrency;
using namespace Platform::Collections;
using namespace Windows::Foundation::Collections;
using namespace Windows::Foundation;
using namespace Windows::UI::Core;

ComputeResult の実装を追加するにはTo add the implementation for ComputeResult

Class1.cpp で、次のメソッド実装を追加します。In Class1.cpp, add the following method implementation. このメソッドは呼び出しスレッドで同期的に実行されますが、C++ AMP を使って GPU での計算を並列化するため、非常に高速です。This method executes synchronously on the calling thread, but it is very fast because it uses C++ AMP to parallelize the computation on the GPU. 詳しくは、「C++ AMP の概要」をご覧ください。For more information, see C++ AMP Overview. 結果は Platform::Collections::Vector 具象型に追加されます。この型は、返されるときに Windows::Foundation::Collections::IVector に暗黙的に変換されます。The results are appended to a Platform::Collections::Vector concrete type, which is implicitly converted to a Windows::Foundation::Collections::IVector when it is returned.

//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 http://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 とそのヘルパー メソッドの実装を追加するにはTo add the implementation for GetPrimesOrdered and its helper method

Class1.cpp で、GetPrimesOrdered と is_prime ヘルパー メソッドの実装を追加します。In Class1.cpp, add the implementations for GetPrimesOrdered and the is_prime helper method. GetPrimesOrdered は、concurrent_vector クラスと parallel_for 関数ループを使って作業を分割し、プログラムが実行されているコンピューターのリソースを最大限に使って結果を生成します。GetPrimesOrdered uses a concurrent_vector class and a parallel_for function loop to divide up the work and use the maximum resources of the computer on which the program is running to produce results. 結果の計算、保存、並べ替えが終わると、結果は Platform::Collections::Vector に追加され、Windows::Foundation::Collections::IVector としてクライアント コードに返されます。After the results are computed, stored, and sorted, they are added to a Platform::Collections::Vector and returned as Windows::Foundation::Collections::IVector to client code.

進行状況レポーターのコードに注意してください。このコードにより、クライアントは操作の予想される所要時間をユーザーに示す進行状況バーまたは他の UI をフックできます。Notice the code for the progress reporter, which enables the client to hook up a progress bar or other UI to show the user how much longer the operation is going to take. 進行状況レポートにはコストがかかります。Progress reporting has a cost. イベントはコンポーネント側で発生させ、UI スレッドで処理する必要があります。また、イテレーションごとに進行状況値を保存する必要があります。An event must be fired on the component side and handled on the UI thread, and the progress value must be stored on each iteration. コストを最小限に抑える 1 つの方法として、進行状況イベントの発生頻度を制限します。One way to minimize the cost is by limiting the frequency at which a progress event is fired. それでもコストがかかりすぎる場合や、操作の所要時間を推定できない場合は、完了までの残り時間は示さず、操作が進行中であることだけを示すプログレス リングを使うことを検討してください。If the cost is still prohibitive, or if you can't estimate the length of the operation, then consider using a progress ring, which shows that an operation is in progress but doesn't show time remaining until completion.

// 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 の実装を追加するにはTo add the implementation for GetPrimesUnordered

C++ コンポーネントを作成する最後の手順として、Class1.cpp で GetPrimesUnordered の実装を追加します。The last step to create the C++ component is to add the implementation for the GetPrimesUnordered in Class1.cpp. このメソッドは、すべての結果が見つかるまで待たずに、結果が見つかるたびに各結果を返します。This method returns each result as it is found, without waiting until all results are found. 各結果はイベント ハンドラー内で返され、UI にリアルタイムで表示されます。Each result is returned in the event handler and displayed on the UI in real time. ここでも進行状況レポーターが使われていることに注意してください。Again, notice that a progress reporter is used. このメソッドも、is_prime ヘルパー メソッドを使います。This method also uses the is_prime helper method.

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

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

C# クライアントだけを作成する場合は、このセクションをスキップして構いません。If you just want to create a C# client, you can skip this section.

JavaScript プロジェクトを作成するにはTo create a JavaScript project

  1. ソリューション エクスプローラーで、[ソリューション] ノードのショートカット メニューを開き、 [追加]、[新しいプロジェクト] の順にクリックします。In Solution Explorer, open the shortcut menu for the Solution node and choose Add, New Project.

  2. [JavaScript] ( [他の言語] の下に入れ子になっていることがあります) を展開し、 [空白のアプリ (ユニバーサル Windows)] を選択します。Expand JavaScript (it might be nested under Other Languages) and choose Blank App (Universal Windows).

  3. [OK] をクリックして、既定の名前 (App1) を受け入れます。Accept the default name—App1—by choosing the OK button.

  4. App1 プロジェクト ノードのショートカット メニューを開き、 [スタートアップ プロジェクトに設定] をクリックします。Open the shortcut menu for the App1 project node and choose Set as Startup Project.

  5. WinRT_CPP へのプロジェクト参照を追加します。Add a project reference to WinRT_CPP:

  6. [参照] ノードのショートカット メニューを開き、 [参照の追加] をクリックします。Open the shortcut menu for the References node and choose Add Reference.

  7. [参照マネージャー] ダイアログ ボックスの左ペインで、 [プロジェクト] をクリックし、 [ソリューション] をクリックします。In the left pane of the References Manager dialog box, select Projects and then select Solution.

  8. 中央ペインで [WinRT_CPP] を選択し、 [OK] をクリックします。In the center pane, select WinRT_CPP and then choose the OK button

JavaScript イベント ハンドラーを呼び出す HTML を追加するにはTo add the HTML that invokes the JavaScript event handlers

default.html ページの ノードに、次の HTML を貼り付けます。Paste this HTML into the node of the default.html page:

<div id="LogButtonDiv">
     <button id="logButton">Logarithms using AMP</button>
 </div>
 <div id="LogResultDiv">
     <p id="logResult"></p>
 </div>
 <div id="OrderedPrimeButtonDiv">
     <button id="orderedPrimeButton">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">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">Clear</button>
 </div>

スタイルを追加するにはTo add styles

default.css で body スタイルを削除し、次のスタイルを追加します。In default.css, remove the body style and then add these styles:

#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 イベント ハンドラーを追加するにはTo add the JavaScript event handlers that call into the component DLL

default.js ファイルの末尾に次の関数を追加します。Add the following functions at the end of the default.js file. これらの関数は、メイン ページのボタンが選択されたときに呼び出されます。These functions are called when the buttons on the main page are chosen. JavaScript が C++ クラスをアクティブにして、そのメソッドを呼び出し、戻り値を使って HTML ラベルを設定する手順に注目してください。Notice how JavaScript activates the C++ class, and then calls its methods and uses the return values to populate the HTML labels.

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

default.js 内の app.onactivated での WinJS.UI.processAll の既存の呼び出しを、then ブロックでイベント登録を実装する次のコードに置き換えて、イベント リスナーを追加するコードを追加します。Add code to add the event listeners by replacing the existing call to WinJS.UI.processAll in app.onactivated in default.js with the following code that implements event registration in a then block. これの詳細については、次を参照してください。 "Hello, World"アプリ (JS) 作成です。For a detailed explanation of this, see Create a "Hello, World" app (JS).

args.setPromise(WinJS.UI.processAll().then( function completed() {
    var logButton = document.getElementById("logButton");
    logButton.addEventListener("click", LogButton_Click, false);
    var orderedPrimeButton = document.getElementById("orderedPrimeButton");
    orderedPrimeButton.addEventListener("click", ButtonOrdered_Click, false);
    var buttonUnordered = document.getElementById("ButtonUnordered");
    buttonUnordered.addEventListener("click", ButtonUnordered_Click, false);
    var buttonClear = document.getElementById("Button_Clear");
    buttonClear.addEventListener("click", ButtonClear_Click, false);
}));

F5 キーを押してアプリを実行します。Press F5 to run the app.

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

C# プロジェクトを作成するにはTo create a C# project

  1. ソリューション エクスプローラーで、[ソリューション] ノードのショートカット メニューを開き、 [追加]、[新しいプロジェクト] の順にクリックします。In Solution Explorer, open the shortcut menu for the Solution node and then choose Add, New Project.

  2. [Visual C#] ( [他の言語] の下に入れ子になっていることがあります) を展開し、 [Windows] をクリックします。左ペインで [ユニバーサル] をクリックし、中央ペインで [空のアプリケーション] を選択します。Expand Visual C# (it might be nested under Other Languages), select Windows and then Universal in the left pane, and then select Blank App in the middle pane.

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

  4. CS_Client プロジェクト ノードのショートカット メニューを開き、 [スタートアップ プロジェクトに設定] をクリックします。Open the shortcut menu for the CS_Client project node and choose Set as Startup Project.

  5. WinRT_CPP へのプロジェクト参照を追加します。Add a project reference to WinRT_CPP:

    • [参照] ノードのショートカット メニューを開き、 [参照の追加] をクリックします。Open the shortcut menu for the References node and choose Add Reference.

    • [参照マネージャー] ダイアログ ボックスの左ペインで、 [プロジェクト] をクリックし、 [ソリューション] をクリックします。In the left pane of the References Manager dialog box, select Projects and then select Solution.

    • 中央ペインで [WinRT_CPP] を選択し、 [OK] をクリックします。In the center pane, select WinRT_CPP and then choose the OK button.

ユーザー インターフェイスを定義する XAML を追加するにはTo add the XAML that defines the user interface

MainPage.xaml 内の Grid 要素に次のコードをコピーします。Copy the following code into the Grid element in MainPage.xaml.

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

ボタンのイベント ハンドラーを追加するにはTo add the event handlers for the buttons

ソリューション エクスプローラーで、MainPage.xaml.cs を開きますIn Solution Explorer, open MainPage.xaml.cs. (ファイルは MainPage.xaml の下で入れ子に可能性があります)。使用して、追加、System.Text のディレクティブを MainPage クラスで、対数の計算のイベント ハンドラーを追加します。(The file might be nested under MainPage.xaml.) Add a using directive for System.Text, and then add the event handler for the Logarithm calculation in the MainPage class.

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

順序付けされた結果のイベント ハンドラーを追加します。Add the event handler for the ordered result:

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

順序付けされていない結果のイベント ハンドラーと、コードを再度実行できるように結果をクリアするボタンのイベント ハンドラーを追加します。Add the event handler for the unordered result, and for the button that clears the results so that you can run the code again.

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

アプリの実行Running the app

ソリューション エクスプローラーでプロジェクト ノードのショートカット メニューを開き、 [スタートアップ プロジェクトに設定] を選んで、C# プロジェクトまたは JavaScript プロジェクトをスタートアップ プロジェクトとして選びます。Select either the C# project or JavaScript project as the startup project by opening the shortcut menu for the project node in Solution Explorer and choosing Set As Startup Project. デバッグして実行する場合は、F5 キーを押します。デバッグせずに実行する場合は、Ctrl キーを押しながら F5 キーを押します。Then press F5 to run with debugging, or Ctrl+F5 to run without debugging.

オブジェクト ブラウザーでのコンポーネントの検査 (省略可能)Inspecting your component in Object Browser (optional)

オブジェクト ブラウザーで、.winmd ファイルで定義されているすべての Windows ランタイム型を検査できます。In Object Browser, you can inspect all Windows Runtime types that are defined in .winmd files. これには、Platform 名前空間と既定の名前空間の型が含まれます。This includes the types in the Platform namespace and the default namespace. ただし、Platform::Collections 名前空間の型は、winmd ファイルではなく、collections.h ヘッダー ファイルで定義されているため、オブジェクト ブラウザーでは表示されません。However, because the types in the Platform::Collections namespace are defined in the header file collections.h, not in a winmd file, they don’t appear in Object Browser.

コンポーネントを検査するにはTo inspect a component

  1. メニュー バーで、 [表示]、[オブジェクト ブラウザー] の順にクリックします (または、Ctrl + Alt + J キーを押します)。On the menu bar, choose View, Object Browser (Ctrl+Alt+J).

  2. オブジェクト ブラウザーの左側のウィンドウで、展開、WinRT_CPP ノード、コンポーネントで定義されているメソッドや型を表示します。In the left pane of the Object Browser, expand the WinRT_CPP node to show the types and methods that are defined on your component.

デバッグのヒントDebugging tips

デバッグ操作を向上させるには、パブリックな Microsoft シンボル サーバーからデバッグ シンボルをダウンロードします。For a better debugging experience, download the debugging symbols from the public Microsoft symbol servers:

デバッグ シンボルをダウンロードするにはTo download debugging symbols

  1. メニュー バーで、 [ツール]、[オプション] の順にクリックします。On the menu bar, choose Tools, Options.

  2. [オプション] ダイアログ ボックスで、 [デバッグ] を展開し、 [シンボル] をクリックします。In the Options dialog box, expand Debugging and select Symbols.

  3. [Microsoft シンボル サーバー] を選択し、 [OK] をクリックします。Select Microsoft Symbol Servers and the choose the OK button.

シンボルを初めてダウンロードするときは時間がかかる場合があります。It might take some time to download the symbols the first time. 次回 F5 キーを押したときのパフォーマンスを向上させるには、シンボルをキャッシュするローカル ディレクトリを指定します。For faster performance the next time you press F5, specify a local directory in which to cache the symbols.

コンポーネント DLL を含む JavaScript ソリューションをデバッグするときは、コンポーネントでスクリプトのステップ実行またはネイティブ コードのステップ実行を有効にするようにデバッガーを設定できますが、この両方を同時に有効にすることはできません。When you debug a JavaScript solution that has a component DLL, you can set the debugger to enable either stepping through script or stepping through native code in the component, but not both at the same time. 設定を変更するには、ソリューション エクスプローラーで JavaScript プロジェクト ノードのショートカット メニューを開き、 [プロパティ]、[デバッグ]、[デバッガーの種類] の順にクリックします。To change the setting, open the shortcut menu for the JavaScript project node in Solution Explorer and choose Properties, Debugging, Debugger Type.

パッケージ デザイナーで必ず適切な機能を選んでください。Be sure to select appropriate capabilities in the package designer. パッケージ デザイナーを開くには、Package.appxmanifest ファイルを開きます。You can open the package designer by opening the Package.appxmanifest file. たとえば、プログラムを使ってピクチャ フォルダーのファイルにアクセスする場合は、パッケージ デザイナーの [機能] ペインで [画像ライブラリ] チェック ボックスをオンにしてください。For example, if you are attempting to programmatically access files in the Pictures folder, be sure to select the Pictures Library check box in the Capabilities pane of the package designer.

JavaScript コードがコンポーネントのパブリック プロパティまたはパブリック メソッドを認識しない場合は、JavaScript で camel 規約を使っていることを確認します。If your JavaScript code doesn't recognize the public properties or methods in the component, make sure that in JavaScript you are using camel casing. たとえば、ComputeResult C++ メソッドは、JavaScript で computeResult として参照する必要があります。For example, the ComputeResult C++ method must be referenced as computeResult in JavaScript.

C++ Windows ランタイム コンポーネント プロジェクトをソリューションから削除する場合、JavaScript プロジェクトからプロジェクト参照も手動で削除する必要があります。If you remove a C++ Windows Runtime Component project from a solution, you must also manually remove the project reference from the JavaScript project. これを行わないと、後続のデバッグまたはビルド操作が妨げられます。Failure to do so prevents subsequent debug or build operations. その後、必要に応じてアセンブリ参照を DLL に追加できます。If necessary, you can then add an assembly reference to the DLL.