Quantcast
Channel: かずきのBlog@hatena
Viewing all articles
Browse latest Browse all 1387

C++/WinRT で Windows Runtime Component を作って C# から呼ぶまで

$
0
0

ちょっと迷ったのでメモしておきます。

C+/WinRT自体についてはこちら

docs.microsoft.com

上のドキュメントの、このページの部分に関連してます。

docs.microsoft.com

docs.microsoft.com

Step 1: Windows Runtime Component プロジェクトの作成と idl の定義

Windows Runtime Component (C++/WinRT) のプロジェクトを作成します。今回は名前は MyComponents にしました。 Class.idl` があるのですが、これは消します。

そして Person.idlを作成するのと Person.hPerson.cppも作成します。 Person.idlに Person クラスを定義します。

namespace MyComponents
{
    runtimeclass Person : Windows.UI.Xaml.Data.INotifyPropertyChanged
    {
        Person();
        String Name;
    }
}

インテリセンスとかないので辛いです。

Step 2: Person クラスの作成

idl を書いてビルドしてプロジェクトのすべてのファイルを表示すると Person.g.hPerson.g.cppが生成されています。

f:id:okazuki:20190920135105p:plain

ここには winrt::MyComponents::implementation::Person_baseクラスと、その別名の winrt::MyComponents::implementation::PersonTと、winrt::MyComponents::factory_implementation::PersonTが定義されています。この PersonTという名前の 2 つのクラスを継承して Personクラスを自分のコードに追加します。

Person.hは以下のような感じになります。

#pragma once#include "Person.g.h"// 生成されたヘッダーを includenamespace winrt::MyComponents::implementation
{
    struct Person : PersonT<Person>
    {
    };
}

namespace winrt::MyComponents::factory_implementation
{
    struct Person : PersonT<Person, implementation::Person>
    {
    };
}

PersonTとか Personとか同じ名前が出てきますが、これは名前空間が違うので気を付けてみましょう。

Step 3: Person クラスの実装

Person クラスの中を作っていきます。idl ファイルに定義していた Nameプロパティと INotifyPropertyChangedの実装をします。Person.hに、ここらへんを追加していきましょう。

#pragma once#include "Person.g.h"// 生成されたヘッダーを includenamespace winrt::MyComponents::implementation
{
    struct Person : PersonT<Person>
    {
        Person() = default;
        winrt::hstring Name() const;
        void Name(winrt::hstring const& name);

        winrt::event_token PropertyChanged(winrt::Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler);
        void PropertyChanged(winrt::event_token const& token);

    private:
        winrt::hstring _name;
        winrt::event<winrt::Windows::UI::Xaml::Data::PropertyChangedEventHandler> _propertyChanged;
    };
}

namespace winrt::MyComponents::factory_implementation
{
    struct Person : PersonT<Person, implementation::Person>
    {
    };
}

Person.cppに実装を書いていきます。頭にお決まりの include を書いて namespaceを定義したらヘッダーに戻って実装したいメソッドで Ctrl + .で以下のように、いい感じにひな型が作られます。

#include "pch.h"#include "Person.h"#include "Person.g.cpp"// 自動生成された cpp を includenamespace winrt::MyComponents::implementation
{
    winrt::hstring Person::Name() const
    {
        return winrt::hstring();
    }
    void Person::Name(winrt::hstring const& name)
    {
    }
    winrt::event_token Person::PropertyChanged(winrt::Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler)
    {
        return winrt::event_token();
    }
    void Person::PropertyChanged(winrt::event_token const& token)
    {
    }
}

中身を実装してこんな感じ。

#include "pch.h"#include "Person.h"#include "Person.g.cpp"// 自動生成された cpp を includenamespace winrt::MyComponents::implementation
{
    winrt::hstring Person::Name() const
    {
        return _name;
    }
    void Person::Name(winrt::hstring const& name)
    {
        _name = name;
        _propertyChanged(*this, Windows::UI::Xaml::Data::PropertyChangedEventArgs(L"Name"));
    }
    winrt::event_token Person::PropertyChanged(winrt::Windows::UI::Xaml::Data::PropertyChangedEventHandler const& handler)
    {
        return _propertyChanged.add(handler);
    }
    void Person::PropertyChanged(winrt::event_token const& token)
    {
        _propertyChanged.remove(token);
    }
}

Step 4: C# から使う

C# の UWP アプリを作ります。ここでは CSharpUWPAppにしました。 CSharpUWPAppから MyComponentsに参照設定を追加します。ここらへんは普通の C# のクラスライブラリ使うときと一緒ですね。という`か、ちゃんと C++/WinRT で Windows ランタイムコンポーネントが定義出来ていれば C# から使うのは普通の C# のクラスを使うときと変わりありません。

ということで MainPage.xaml.csPerson` クラスをプロパティに持たせて…

using MyComponents;
using Windows.UI.Xaml.Controls;

// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409namespace CSharpUWPApp
{
    /// <summary>/// An empty page that can be used on its own or navigated to within a Frame./// </summary>publicsealedpartialclass MainPage : Page
    {
        private Person Person { get; } = new Person { Name = "Tanaka" };
        public MainPage()
        {
            this.InitializeComponent();
        }
    }
}

MainPage.xamlで適当にバインドしましょう。

<Pagex:Class="CSharpUWPApp.MainPage"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="using:CSharpUWPApp"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"><StackPanel><TextBox Text="{x:Bind Person.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /><TextBlock Text="{x:Bind Person.Name, Mode=OneWay}" /></StackPanel></Page>

実行するとちゃんと使えています。

f:id:okazuki:20190920151918g:plain

まとめ

ハイパフォーマンスで美しい Windows Runtime Component を C++/WinRT で!!…作れるようになる道のりは自分にとってははるか長いように見える。 がんばろっと。

ソースコードはこちら。

github.com


Viewing all articles
Browse latest Browse all 1387

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>