新規記事の投稿を行うことで、非表示にすることが可能です。
2018年06月30日
《その419》XAML(図形の描画)
XAML(図形の描画)
C++/CXコードで図形を描画する方法については、本ブログ《380》〜《382》で扱いましたが、今回は、XAML を用いた描画です。
以下は、MainPage.xaml のコードです。
<Page
x:Class="App14.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App14"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Canvas x:Name="canvas1" HorizontalAlignment="Left" Height="200"
VerticalAlignment="Top" Width="200" Margin="0,0,0,0">
<Line
X1="10" Y1="150"
X2="190" Y2="50"
Stroke="Green"
StrokeThickness="6"
/>
</Canvas>
<Canvas x:Name="canvas2" HorizontalAlignment="Left" Height="200"
VerticalAlignment="Top" Width="200" Margin="200,0,0,0">
<Rectangle
Width="180"
Height="100"
Stroke="Red"
StrokeThickness="6"
Margin="10,50,0,0"
/>
</Canvas>
<Canvas x:Name="canvas3" HorizontalAlignment="Left" Height="200"
VerticalAlignment="Top" Width="200" Margin="400,0,0,0">
<Polygon
Fill="Yellow"
Points="100,24,10,180,190,180"
Stroke="Black"
StrokeThickness="3"
/>
</Canvas>
<Canvas x:Name="canvas4" HorizontalAlignment="Left" Height="200"
VerticalAlignment="Top" Width="200" Margin="0,200,0,0">
<Polygon
Fill="Pink"
Points="70,0,0,40,0,120,70,160,138,120,138,40"
Stroke="Brown"
StrokeThickness="5"
Margin="25,25,0,0"
/>
</Canvas>
<Canvas x:Name="canvas5" HorizontalAlignment="Left" Height="200"
VerticalAlignment="Top" Width="200" Margin="200,200,0,0">
<Ellipse
Fill="Beige"
Height="150"
Width="150"
Stroke="Blue"
StrokeThickness="3"
Margin="25,25,0,0"
/>
</Canvas>
<Canvas x:Name="canvas6" HorizontalAlignment="Left" Height="200"
VerticalAlignment="Top" Width="200" Margin="400,200,0,0">
<Ellipse
Height="140"
Width="100"
Stroke="Purple"
StrokeThickness="10"
Margin="50,20,0,0"
/>
</Canvas>
</Grid>
</Page>
《その418》XAML(コントロールの重なり順)
XAML(コントロールの重なり順)
今回のアプリの実行結果画面です。文字と円の重なり順が、左側と右側で、逆になっています。
以下は、MainPage.xaml のコードです。
<Page
x:Class="App4.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App4"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<!-- 円 (左側) 円は MainPage.xaml.cpp で描画しています。-->
<Canvas x:Name="canvas1" HorizontalAlignment="Left" Height="80"
Margin="60,105,0,0" VerticalAlignment="Top" Width="80"/>
<!-- 文字 (左側) -->
<TextBlock x:Name="textblock1" HorizontalAlignment="Left" Margin="50,100,0,0"
Text="A" TextWrapping="Wrap" VerticalAlignment="Top"
FontFamily="Wide Latin" FontSize="72"/>
<!-- 文字 (右側) -->
<TextBlock x:Name="textblock2" HorizontalAlignment="Left" Margin="250,100,0,0"
Text="A" TextWrapping="Wrap" VerticalAlignment="Top"
FontFamily="Wide Latin" FontSize="72"/>
<!-- 円 (右側) 円は MainPage.xaml.cpp で描画しています。-->
<Canvas x:Name="canvas2" HorizontalAlignment="Left" Height="80"
Margin="260,105,0,0" VerticalAlignment="Top" Width="80"/>
</Grid>
</Page>
Pageコントロールの中に 1つの Grigコントロールが入っています。
そして、その Gridコントロール内に Canvasコントロールが2つ、TextBlockコントロールが2つ入っています。
Pageタグの中の記述、
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App4"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
は、XML名前空間の宣言です。
xmlns は、XML名前空間の指定を意味していますが、ここを手動で書きかえることはないと思うので、気にする必要はないと思います。
上の XAMLコードでは、
<!-- 円 (左側) 円は MainPage.xaml.cpp で描画しています。-->
<Canvas x:Name="canvas1" HorizontalAlignment="Left" Height="80"
Margin="60,105,0,0" VerticalAlignment="Top" Width="80"/>
<!-- 文字 (左側) -->
<TextBlock x:Name="textblock1" HorizontalAlignment="Left" Margin="50,100,0,0"
Text="A" TextWrapping="Wrap" VerticalAlignment="Top"
FontFamily="Wide Latin" FontSize="72"/>
<!-- 文字 (右側) -->
<TextBlock x:Name="textblock2" HorizontalAlignment="Left" Margin="250,100,0,0"
Text="A" TextWrapping="Wrap" VerticalAlignment="Top"
FontFamily="Wide Latin" FontSize="72"/>
<!-- 円 (右側) 円は MainPage.xaml.cpp で描画しています。-->
<Canvas x:Name="canvas2" HorizontalAlignment="Left" Height="80"
Margin="260,105,0,0" VerticalAlignment="Top" Width="80"/>
のように、記述の順序が、
円,文字 の順
文字,円 の順
の2通りになっています。
※ C++/CXコードでの図形描画については、本ブログ《380》〜《382》で扱っています。
◆ 円,文字 の順 ・・・ 円の上に文字が乗ります。
◆ 文字,円 の順 ・・・ 文字の上に円が乗ります。
つまり、後方に記述されたコントロールが上になるように表示されるわけです。
以下は、MainPage.xaml.cpp のコードです。
//
// MainPage.xaml.cpp
// MainPage クラスの実装。
//
#include "pch.h"
#include "MainPage.xaml.h"
using namespace App4;
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Navigation;
MainPage::MainPage()
{
InitializeComponent();
// 円の描画
auto circle1 = ref new Shapes::Ellipse();
circle1->Width = 80; circle1->Height = 80;
circle1->Stroke
= ref new SolidColorBrush(Windows::UI::Colors::Aqua);
circle1->StrokeThickness = 10;
canvas1->Children->Append(circle1);
// 円の描画
auto circle2 = ref new Shapes::Ellipse();
circle2->Width = 80; circle2->Height = 80;
circle2->Stroke
= ref new SolidColorBrush(Windows::UI::Colors::Aqua);
circle2->StrokeThickness = 10;
canvas2->Children->Append(circle2);
}
2018年06月29日
《その417》XAML(Imageタグ)
XAML(Imageタグ)
コードの文字数は多いですが、VS2017 は XAMLコードを自動生成してくれるので助かります。
◆ ソリューションエクスプローラー -> App##(Universal Windows)
Assets を右クリック
◆ 追加(D) -> 既存の項目(G)
◆ 取り込む画像ファイルを選択
◆ 表示(V) -> ツールボックス(X)
Imageコントロールをフォーム上にドラッグ&ドロップ
◆ 自動生成された Imageタグを編集します。
取り込んだ画像のサイズに合わせて、Height="80", Width="80" にしました。
また、HorizontalAlignment="Left" VerticalAlignment="Top" なので、
Margin は左と上だけ決めます。とりあえず 左100, 上100 にしました。
<Image HorizontalAlignment="Left" Height="80" Margin=
"100,100,0,0" VerticalAlignment="Top" Width="80"/>
◆ Image のプロパティで、img05.png を選択しました。
それと、コントロールに image という名前を付けました。
◆ 画像が表示されました。
◆ Imageタグに、Source="img05.png" が追加されています。
<Image x:Name="image" HorizontalAlignment="Left" Height="80" Margin=
"100,100,0,0" VerticalAlignment="Top" Width="80" Source="img05.png"/>
以上の操作は 本ブログ《368》で行った作業と全く同じですが、XAMLタグを確認するために復習してみました。
以下の "MainPage.xaml.cpp のように、左Margin と 上Margin を変数 x, y としておき、その値を変更することで画像を動かすことができます(これも《377》〜《393》辺りで確認済みです)。
今回は、XAML がテーマなので、画像は、単純に 左上から右下に動くだけです。
//
// MainPage.xaml.cpp
// MainPage クラスの実装。
//
#include "pch.h"
#include "MainPage.xaml.h"
using namespace App14;
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Navigation;
MainPage::MainPage()
{
InitializeComponent();
StartTimer();
}
float x;
float y;
void MainPage::StartTimer() {
auto timer = ref new Windows::UI::Xaml::DispatcherTimer();
TimeSpan span;
span.Duration = 1000;
timer->Interval = span;
timer->Start();
auto rcpt
= timer->Tick +=
ref new EventHandler<Object^>(this, &MainPage::OnTick);
}
void MainPage::OnTick(Object^ sender, Object^ e) {
x += 1; y += 1;
// Thickness(x, y, 0, 0) で、Margin(x, y, 0, 0) を指定しています。
image->Margin = Windows::UI::Xaml::Thickness(x, y, 0, 0);
}
《その416》XAML(TextBoxタグ)
XAML(TextBoxタグ)
本ブログの《364》〜《399》では、XAMLコードを 全て VS2017 に自動作成してもらいました。
このまま XAML の知識ゼロで先に進むのは ちょっと不安なので、基礎の基礎くらいは知っておきたいと思います。
XAML を使える人には、申しわけありません m(_ _)m
以下が、今回の手順です。
◆ ファイル(F) -> 新規作成(N) -> プロジェクト(P)
◆ Visual C++ -> Windowsユニバーサル -> 空白のアプリ(ユニバーサルWindows)
◆ そのまま OK で いいと思います。
◆ MainPage.xaml を開きます。
◆ 次の4行を追加して、Gridコントロールの中にTextBoxコントロールを4つ配置します。
<TextBox HorizontalAlignment
="Left" VerticalAlignment="Top" Text="あいうえお" />
<TextBox HorizontalAlignment
="Right" VerticalAlignment="Top" Text="かきくけこ" />
<TextBox HorizontalAlignment
="Left" VerticalAlignment="Bottom" Text="さしすせそ" />
<TextBox HorizontalAlignment
="Right" VerticalAlignment="Bottom" Text="たちつてと" />
コードを一から入力するのは大変なので、
表示(V) -> ツールボックス(X)
TextBoxコントロールをフォーム上の適当な位置にドラッグ&ドロップ
として、コードの自動生成後に、それを編集するようにします。
◆ デバッグ(D) -> デバッグなしで開始(H)
アプリケーションの実行画面です。
◆ App.xaml を開きます。
◆ コード中の Applicationタグをクリック
◆ プロパティの RequestedTheme を Dark に設定
◆ デバッグ(D) -> デバッグなしで開始(H)
アプリケーションの実行画面です。
2018年06月28日
《その415》Platform::Array
Platform::Array
Windows Runtime が提供する Platform::Array は、1次元配列を扱う参照型クラスです。
C++/CX においても、Platform::Array よりずっと使いやすい std::array(あるいは、
より強力な std::vector)を使うべきですが、ABI を介して配列の受け渡しをする場合には
Platform::Array型を使う必要があります。
※ABI : Application Binary Interface
Platform::Array は、std::array に似ています。
以下は、下記のプログラムに沿った説明です。
◆ Platform::Array型オブジェクト ary1, ary2 を作成します。
Array<String^>^ ary1 = ref new Array<String^>(3);
ary1[0] = "愛媛県";
ary1[1] = "神奈川県";
ary1[2] = "福島県";
Array<int>^ ary2 = { 100, 200, 300 };
◆ 配列の長さを確認します。
std::cout << ary1->Length << '\n';
std::cout << ary2->Length << '\n';
◆ foreach文で、全要素を出力表示させます。
for (auto x : ary1) {
// Platform::String^型を std::wstring型に変換します。
std::wstring wstr(x->Data());
std::wcout << wstr << ' ';
}
for (auto x : ary2) {
std::cout << x << ' ';
}
◆ ptr は ary2 の最初の要素へのポインタです。begin() は最初の要素へのポインタを返します。
int* ptr = ary2->begin();
◆ *ptr, *(ptr + 1) は、ary2 の 最初の要素 と 2番目の要素です。
また、end() は、最後の要素の次(実際には存在しない)へのポインタを返します。
したがって、*(ary2->end() - 1) は ary2 の最後の要素です。
std::cout << *ptr << ' '
<< *(ptr + 1) << ' '
<< *(ary2->end() - 1) << '\n';
#include <iostream>
#include <string>
using namespace Platform;
int main(Array<String^>^ args)
{
setlocale(LC_ALL, "Japanese");
Array<String^>^ ary1 = ref new Array<String^>(3);
ary1[0] = "愛媛県";
ary1[1] = "神奈川県";
ary1[2] = "福島県";
Array<int>^ ary2 = { 100, 200, 300 };
std::cout << ary1->Length << '\n';
std::cout << ary2->Length << '\n';
for (auto x : ary1) {
std::wstring wstr(x->Data());
std::wcout << wstr << ' ';
}
std::wcout <<'\n';
for (auto x : ary2) {
std::cout << x << ' ';
}
std::cout << '\n';
int* ptr = ary2->begin();
std::cout << *ptr << ' ' // 100
<< *(ptr + 1) << ' ' // 200
<< *(ary2->end() - 1) << '\n'; // 300
}
2018年06月27日
《その414》ガベージコレクション
ガベージコレクション
std::wstring* p
= new std::wstring(L"あいうえお");
で作成した文字列インスタンスを格納するメモリ領域は、明示的に
delete p;
として解放しない限り、メモリを占有し続けます。
for (int i = 0; i < 5000; i++)
for (int j = 0; j < 5000; j++)
std::wstring* p = new std::wstring(L"あいうえお");
のようなコードでは、メモリの解放をしないまま新しい文字列インスタンスを作り続けているので、メモリ確保に失敗してエラーになる可能性があります。
※メモリ確保に失敗した場合には、例外 bad_alloc が送出されます。
一方、
Platform::String^ s
= ref new Platform::String(L"あいうえお");
のように、ref new を用いて生成された参照クラスのインスタンスでは、不要になった場合にはシステムにより自動的にメモリ解放されます。
したがって、メモリ解放のための明示的なコードを必要としません。
このような、メモリの自動解放の仕組みのことを、ガベージコレクションと呼んでいます。
したがって、
for (int i = 0; i < 5000; i++)
for (int j = 0; j < 5000; j++)
Platform::String^ s
= ref new Platform::String(L"あいうえお");
std::wcout.imbue(std::locale("japanese"));
std::wcout << L"作業完了\n";
の場合には、例外 bad_alloc が送出されることなく、無事に "作業完了" します。
なお、上記の p はポインタと呼ばれるのに対して、上記の s はハンドルと呼ばれることがあります。
ポインタの場合、クラスのメンバにアクセスする際には、例えば、
p->length();
のようにしますが、ハンドルの場合も、同じように、
s->Length();
と書くことができます。
最初のプログラムでは、必要なメモリ解放をしていないため、例外 bad_alloc が送出されます。
#include <iostream>
int main(Platform::Array<Platform::String^>^ args)
{
try {
for (int i = 0; i < 5000; i++)
for (int j = 0; j < 5000; j++)
std::wstring* p
= new std::wstring(L"あいうえお");
std::wcout.imbue(std::locale("japanese"));
std::wcout << L"作業完了\n";
}
catch (std::bad_alloc& e) {
std::cout << e.what() << '\n';
}
}
次のプログラムでは、ガベージコレクションによるメモリの自動解放が行われるため、例外 bad_alloc は送出されません。
#include <iostream>
int main(Platform::Array<Platform::String^>^ args)
{
try {
for (int i = 0; i < 5000; i++)
for (int j = 0; j < 5000; j++)
Platform::String^ s
= ref new Platform::String(L"あいうえお");
std::wcout.imbue(std::locale("japanese"));
std::wcout << L"作業完了\n";
}
catch (std::bad_alloc& e) {
std::cout << e.what() << '\n';
}
}
2018年06月26日
《その413》文字列型の変換(Platform::String, wstring, wchar_t const*)
文字列型の変換(Platform::String, wstring, wchar_t const*)
下記のプログラムでは、
Platform::String型
wstring型
wchar_t const*型
の各文字列の型を 相互に変換しています。以下は、プログラムに沿っての説明になります。
【1】 unicodeの日本語文字が出力表示されるようにロケールを設定します。
setlocale(LC_ALL, "Japanese");
wcout.imbue(std::locale("japanese")); の記述も用いられます。
【2】 文字列リテラルで String^変数を初期化する際には、文字列の前に 'L' の挿入は必要ありません。
String^ str1 = "あいうえお_ABCDE";
String^ str1 = L"あいうえお_ABCDE"; としても、もちろんかまいません。
◆◆◆ String型 から wchar_t const型,wstring型 への変換
【3】 String型から wstring型への変換です。
wstring str2(str1->Data());
wstring str2(str1->Begin()); としても同じ結果です。
【4】 String型から wchar_t const*型への変換です。
wchar_t const* str3(str1->Data());
wchar_t const* str3(str1->Begin()); としても同じ結果です。
str2, str3 を出力表示します。
str2 は wstring型
str3 は wchar_t const*型です。
【5】 wstring の replace関数で、文字列の一部を置換えます。
wstring rep(L"かさたな");
str2.replace(1, 4, rep);
str2 を出力表示します。
◆◆◆ wchar_t const型 と wstring型 の間の相互変換
【6】 wstring型から wchar_t const*型への変換です。
wchar_t const* str4 = str2.c_str();
【7】 wchar_t const*型から wstring型への変換です。
wstring str5 = wstring(str3);
◆◆◆ wchar_t const型,wstring型 から String型 への変換
【8】 wchar_t const*型から String型への変換です。
String^ str6 = ref new String(str4);
【9】 wstring型から String型への変換です。
String^ str7 = ref new String(str5.c_str());
◆◆◆ auto を使用した String型 から wchar_t const*型 への変換
【10】 auto を使用した場合は、wchar_t const*型になります。
auto str8(str6->Data());
auto str9(str7->Data());
以下はプログラムです。
#include <iostream>
#include <string>
using namespace Platform;
using namespace std;
int main(Array<String^>^ args)
{
//【1】
setlocale(LC_ALL, "Japanese");
// wcout.imbue(std::locale("japanese"));
//【2】
String^ str1 = "あいうえお_ABCDE";
//【3】
wstring str2(str1->Data());
// wstring str2(str1->Begin());
//【4】
wchar_t const* str3(str1->Data());
// wchar_t const* str3(str1->Begin());
wcout << "(1) " << str2 << '\n';
wcout << "(2) " << str3 << '\n';
//【5】
wstring rep(L"かさたな");
str2.replace(1, 4, rep);
wcout << "(3) " << str2 << '\n';
//【6】
wchar_t const* str4 = str2.c_str();
//【7】
wstring str5 = wstring(str3);
//【8】
String^ str6 = ref new String(str4);
//【9】
String^ str7 = ref new String(str5.c_str());
//【10】
auto str8(str6->Data());
auto str9(str7->Data());
cout << "(4) " << typeid(str8).name() << '\n';
cout << "(5) " << typeid(str9).name() << '\n';
wcout << "(6) " << str8 << '\n';
wcout << "(7) " << str9 << '\n';
}
2018年06月25日
《その412》C++/CX のクラス
C++/CX のクラス
● C++/CX のクラスは、refクラスと呼ばれる参照型です。
● クラスオブジェクトのインスタンスはメモリのヒープ領域に置かれ、そのインスタンスを表す変数がインスタンスを参照します。
refクラスは例えば次のようにして作成します。
public ref class C_name sealed {
・・・・・・
};
※先頭の public はアクセス修飾子です。
Windows ランタイムの型は名前空間内で宣言されますが、public修飾子のあるクラスは、
宣言された名前空間外の Windowsランタイムコンポーネントから参照できます。
アクセス修飾子は省略することができ、省略した場合は、private になります。
※クラス名に続く sealed はクラス修飾子です。
sealed の場合は、基底クラスとして使うことが禁止されます。 クラス修飾子は省略できます。
以下は、下記プログラムについてです。
● ref クラスの変数を宣言する際には ^(ハット演算子)を使います。ref new でインスタンスが作られます。
C^ c_01 = ref new C;
● オブジェクトのインスタンスメソッドにアクセスするには -> を用います。
c_01->f();
#include <iostream>
ref class C {
public:
void f() { std::wcout << L"ABCDE" << "\n"; }
};
int main(Platform::Array<Platform::String^>^ args)
{
C^ c_01 = ref new C;
c_01->f();
}
2018年06月24日
《その411》int main(Array^ args)
int main(Array<String^>^ args)
前回《410》のプログラムの main関数は
int main(Platform::Array<Platform::String^>^ args) {
・・・・・・
}
のようになっていました。
その理由ですが、
int main() {
・・・・・・
}
として実行すると、
「warning C4447: スレッド モデルのない 'main' シグネチャが見つかりました。
'int main(Platform::Array<Platform::String^>^ args)' の使用を検討してください。」
という警告が出るためです。
つまり、コマンドライン引数を受け取る形式で記述せよ、ということのようです。
次のプログラムは、受け取ったコマンドライン引数を表示します。
プログラム名は test.exe, 与えている引数は "ABCDE", "12345", "XYZ" なので、
test ABCDE 12345 XYZ
と出力されるはずです。
#include <iostream>
#include <string>
int main(Platform::Array<Platform::String^>^ args) {
for (auto pstr : args) {
wchar_t const* wcs(pstr->Begin());
std::wcout << wcs << ' ';
}
std::cout << '\n';
}
2018年06月23日
《その410》C++/CX
C++/CX
本ブログの《364》〜《399》は、UWP(Universal Windows Platform)ベースの UWPアプリについての内容でした。その際の使用言語は C++/CX です。
作成した UWPアプリは、基礎的なものばかりですが、
・時計の作成
・画像の移動
・ポインタ位置・マウスの動作・ウィンドウサイズ 等の取得と その利用
・画像ファイルやテキストファイルの読み込み
・テキストファイルの編集と保存
等を実現するものでした。
UWPアプリを扱ってみて、非同期処理についての知識が欠かせないことを実感したので、
本ブログの《400》〜《409》では、スレッドやタスクといった内容について確認しました。
そして今回からは、あらためて、C++/CX言語について学習してみようと思います。
その際、UWPベースでは C++/CX言語そのものの学習にはやや大げさになってしまうので、
《001》〜《363》や《400》〜《409》で ずっと使ってきた、コンソールプロジェクトの形式で行います。
コンソール C++プロジェクトで C++/CX を利用できるようにする手順
ファイル(F) ―> 新規作成(N) ―> プロジェクト(P)
Visual C++ ―> 空のプロジェクト
プロジェクト(P) ―> 新しい項目の追加(W)
Visual C++ ―> C++ファイル(.cpp) ―> 追加(A)
cppプログラムの編集画面が表示されました。
ソリューションエクスプローラーで Project のスパナマークをクリックします。
構成プロパティ ―> 全般 ―> 文字セット ―> Unicode文字セットを使用する
構成プロパティ ―> C/C++ ―> 全般 ―> Windowsランタイム拡張機能の使用 ―> はい(/ZW)
構成プロパティ ―> C/C++ ―> コード生成 ―> 最小ビルドを有効にする ―> いいえ(/Gm)
構成プロパティ ―> C/C++ ―> 全般 ―> 追加の #usingディレクトリ
追加の #usingディレクトリに以下の2つのパスを記入します。
「 C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.16299.0 」
「 C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\
VC\Tools\MSVC\14.13.26128\lib\x86\store\references 」
※パスは Visual Studio のインストール状況によります(上記パスは私の使用環境でのものです)。
構成プロパティ ―> C/C++ ―> コマンドライン ―> 追加のオプション
「 /Zc:twoPhase- 」 を記入します。
※この設定項目は、VS2017 v15.3 以降の場合です。
構成プロパティ ―> リンカー ―> 詳細設定 ―> エントリポイント
「 mainCRTStartup 」を記入します。
以上の設定で、次のように C++/CX が使えるようになりました("ref new" などが使えます)。
#include <iostream>
ref class C
{
public:
void f(int n) {
for (int i = n; i < n + 10; i++)
std::cout << i << " ";
std::cout << '\n';
}
};
int main(Platform::Array<Platform::String^>^ args) {
(ref new C)->f(10);
}