Store Guide

Store Application(Windows 10, Windows 8) のプログラムガイドです。
ストアアプリの C++ が従来の .NET Framework のものではなく、新しい WinRT(C++/CX) という API を利用しています。

前田稔(Maeda Minoru)の超初心者のプログラム入門

Store Programing Guide Index

文字コードの説明

  1. Windows の文字コードには Shift_JIS(ANSI) 文字セットと Unicode 文字セットがあります。
    昔は必ず Shift_JIS(ANSI) を使ったものですが、最近では Unicode が主流になってきました。
    また UNIX(ユニックス)では、初期の頃は EUC コードが使われていましたが、これも Unicode になってきたようです。
    Unicode にも 8 bit, 16 bit, 32 bit, etc が存在します。
    8bit Unicode も MultiByte(8 Bit or 16 Bit Charcter Set) に含まれると思うのですが、一般的に MultiByte と言えば Shift_JIS を指すようです。
    Shift_JIS では、英数字や一部の記号を8ビットで、ひらかなや漢字などを16ビットで表現します。
  2. 普通 Unicode と言えば utf-16 を指すようですが、ソースプログラムファイルには utf-8 が使われることが多いようです。
    私も C++, C#, JavaScript, DirectX, HTML, etc のソースファイルは utf-8 でタイプしています。
    utf-16 にも LE と BE があり、C# や StoreApp で作成したプログラムの内部コードには utf-16LE が使われているようです。
    Unicode には BOM が格納されているものと、格納されていないものがあります。
    BOM(byte order mark)とはテキストファイルの先頭に格納される文字コードを示すIDです。
    BOM が格納されていると文字コードが自動的に認識されて、文字化けすることなく正しく読むことができます。
    Shift_JIS や EUC には当然ながら BOM は格納されていません。
    従って utf-8(BOM無し) と Shift_JIS や EUC コードの区別がつかず、文字化けすることがあります。
    文字コード BOM 説明
    utf-16LE FFFE 先頭2バイトが BOM です
    utf-16BE FEFF 先頭2バイトが BOM です
    utf-8 EFBBBF先頭3バイトが BOM です
    utf-8(BOM無し) BOM は格納されていません
    Shift_JISBOM は格納されていません
    EUCBOM は格納されていません
    Shift_JIS(ANSI), Unicode, EUC 以外にも文字コードは山のように存在します。
    詳しい説明は Encoding クラス を参照して下さい。
  3. 1行の終わりを示す改行コードの説明です。
    「\」はエスケープコードなどと呼ばれ、改行コードには \r(carriage return) と \n(line field) が使われます。
    これはタイプライタの名残で、\r は復帰(タイプライターでは左端に戻す)で、\n は改行(タイプライターでは次の行に送る)です。
    タイプライターを使っていた時代には \r と \n を組み合わせて1行の終わりとしていました。
    タイプライターでは \r(復帰)をタイプして既に印字されている行に重ねて印字することや、\n(改行)で次の行の現在のカラムに合わすことが出来ました。
    つまり復帰と改行で次の行の先頭になる訳です。
    タイプライタでは、改行と逆方向に用紙を戻す機能も使われていました。
    さすがにパソコンでは、このコードは無いようです。 (^_^;)
    パソコンでも \r\n を組み合わせて使っていたのですが、最近は \n だけが使われるケースも良く見かけます。
    パソコンでは \r と \n を組み合わせる必要は無く、どちらか一個で用が足ります。
  4. 現在ではOSやファイル(TEXT FILE)に使われている文字コードにより違いがあり、一概には決められません。
    一般的には Shift_JIS や utf-8 でタイプされた TEXT FILE には \r(CR)+\n(LF) が用いられるようです。
    プログラム内部で行の終わりを示す場合は \n が使われるようです。
    "TEXT DATA\r\n"
    "TEXT DATA\n"
    所がシフトJIS ファイルを \n だけで保存すると、notepad.exe(文字コード ANSI) で開いたとき改行されませんでした。
    シフトJIS では \r\n で保存するのが良いようです。
    ちなみに、この確認は 2013/09/24 に次の環境で行いました。
    ・Windows8.1 評価版
    ・Microsoft Visual Studio Professional 2013 Preview - 日本語
    ・C:\Windows\System32\notepad.exe
  5. Windows10 でタイプするときは、Windows のアクセサリからメモ帳でタイプしてみて下さい。
    規定値では utf-8(BOM無し)で、改行コードは \r(0x0D)+\n(0x0A) のファイルが作成されます。
    「名前を付けて保存・開く」を選ぶと文字コードを選んで「保存・入力」が出来るようになっています。
    一般的には、規定値(utf-8 BOM無し)で保存するのですが、用途によっては BOM が無いので文字化けする危険性があります。

文字コードの特殊事情

  1. Shift-JIS では、1バイトコード(8 bit)と2バイトコード(16 bit)が混在しています。
    第1バイトが 81-9F ならびに E0-FC で始まるコードは2バイトコード(ひらかな, 漢字など)です。
    このとき、第2バイトは 40-7E ならびに 80-FC で構成されます。
    ユニコード(16ビット)を使っている場合は問題ないのですが、シフトJIS を使っている場合は次のような問題が発生します。
    ディレクトリの区切り文字として \(5C) が使われます。
    "C:\DATA\TEST\WK.TXT"
    "C:\HTML\PUBLIC\Windows.html"
    
    また文字列のエスケープコードとしても \(5C) が使われます。
    従って文字列の中で \ を使うときは \\ と書きます。
    "C:\\DATA\\TEST\\WK.TXT"
    
    同様に文字列の中で " を使うときは \" と書きます。
    "\"TEXT DATA\""
    
  2. パスを指定するとき問題になるのが 0x5C のコードで、全角文字の中に 5C を含む文字があります。
    次の例はほんの一部で、調べればもっと出てくるでしょう。
    文字 16進数
    \ 5C
    835C
    8D5C
    955C
    次のディレクトリ名を見て下さい。
    本来は親の名前を「c:\TMP\ソース」としなければならないのに「ソ」の 5C をエスケープコードと判断する間違いを犯すことがあります。
    c:\TMP\ソース\テスト.TXT
    
    この処理は結構面倒で、全角/半角を判断しながら 5C を調べなければなりません。
    具体的な例は「前田稔のプログラム入門(C言語 Windows)/Windows Program Note/フルパスを調べる」を参照して下さい。
    ワイドキャラが使われるようになると、このような問題は起こらなくなります。
    Shift-JIS の詳しい説明は Shift_JIS を参照して下さい。
  3. シフトJIS は8ビット(256通り)のキャラクタコードで、非常にうまく日本語を使うコード体系でした。
    昔はメモリ(記憶装置)の値段も高く、いかに少ない容量で記憶するかも重要で、シフトJIS はその要望にもマッチしていました。
    余談にはなりますが、西暦年を4桁で表現するのは「もったいない」と「下2桁で記録」したために、2000年問題が起こったことは記憶に新しい所です。
    最近のようにメモリの値段が安くなり、飛躍的に容量がアップしたことを考えると、ワイドキャラは時代の流れかもしれません。 (^_^;)
  4. 「\」の問題は Shift_JIS だけかと思っていたのですが、UTF-8 でも存在するようです。
    次の2行は見た目には全く同じで、C#で作成した Text Editor で検索しても文字列として一致しました。

    所が Binary Editor で調べると文字コードが違うのです。
    上の行の「\」は「C2A5」ですが、下の行の「\」は「5C」になっています。

    見た目は同じでも、文字コードが違うので同一とはみなされないのです。
    私もこのような事が起きているとは夢にも思わず、苦労した経験があります。

String Guid

  1. 文字列(char の配列)で最も悩まされるのは、文字列の長さの問題です。
        char    msg[256];
    
    必要以上に大きな領域を確保するのも気が引けますし、領域をオーバーしてアクセスすると何が起こるか解りません。
    特にサイズが確定しない文字列を扱うときは、何時も悩まされます。
    この問題を一挙に解決してくれるのが String(string) です。
    ストリングは C++ や C# や STL や C++ Maneged や Windows8(10) や MFC で独自のストリングが使えるようになっていて、それぞれサポートされている関数や書き方が異なるのが混乱の原因です。
    そこで Store Application に適した String(string) をまとめてみました。
  2. Windows Store で提供されている C++ のストリングは非力であまり役に立ちません。 (^_^;)
    String から特定の文字を参照するときや、文字列を切り分けるときは苦労します。
    Win8 String
    Week Class
    #include <windows.h>    // OutputDebugString
    
        String^ str;
        int     v1 = 12;
        int     v2 = 345;
        str = "v1:" + v1.ToString() + "  v2:" + v2.ToString();
        OutputDebugString(str->Data());
    
  3. C++ で機能が充実していて、使いやすいのは STL の stirng(wstirng) です。
    文字列の中の特定の文字を参照するときや、文字列を切り分けるときは STL のストリングを使います。
    STL の string を使う(wstring を使う)
    Win10 OBJ Model
    #include <string>       // STL の String を使う
    using namespace std;
    
        wstring s;
        s = L"12, 3.45, {67}, { ab }; XYZ\r\n";
        OutputDebugString(s.data());
    
        // Token を切り出す
        wstring Word;
        int    Size, Col, wk;
        Size = s.length() - 1;
    
        for (Col = 0; Col<Size;)
        {
            wk = s.find_first_not_of(L" ,;{}", Col);
            Debug(L"Left=", wk);
            Col = wk;
            wk = s.find_first_of(L" ,;}\r\n", Col);
            Debug(L"Right=", wk);
            if (wk == Col)  break;
            Word = Word.assign(s, Col, wk - Col);
            OutputDebugString(Word.data());
            OutputDebugString(L"\r\n");
            Col = wk + 1;
        }
    
  4. Windows Store で提供されている C# の string 機能です。
    C++ の String^ は非力ですが、C# の string は強力です。
    string⇔char[]
    Calender
    string str = "2019/02/21";
    string[] ymd;
    ymd= str.Split(new char[] {'/', '-'});
    
    for(int i=0; i<m_ymd.GetLength(0); i++)
    {
        Debug.WriteLine("i={0}、ymd[i]={1}", i,m_ymd[i]);
    }
    

配列(Array)

  1. Windows Store で提供されている C++ の Array は非力であまり役に立ちません。 (^_^;)
    VC-2019 DebugString
    Win8 String
    #include <windows.h>
        int i, wk;
        Platform::Array<int>^ ary = ref new Array<int>(5);
        for (i = 0; i < 5; i++)     ary[i] = i;
        for (i = 0; i < 5; i++)
        {   wk = ary[i];
            OutputDebugString(wk.ToString()->Data());
        }
    
  2. C++ で機能が充実していて、使いやすいのは STL の vector です。
    vector を使うときは <vector> を #include して下さい。
    STL vector
    Calender
    #include <vector>
        std::vector<int> v;
    
        v.push_back(1);
        v.push_back(23);
        v.push_back(456);
    
  3. Windows Store で提供されている C# の ArrayList は強力です。
    ArrayList は List 型の配列で、要素の「追加/挿入/削除」が簡単に出来るようになっています。
    ArrayList を使うときは System.Collections; を指定して下さい。
    Array List
    using System.Collections;
        ArrayList   array;
    
        array = new ArrayList();
        for(i=0; i<10; i++)     array.Add(i);
        foreach(int DAT in array)
        {
            Debug.WriteLine("value={0} ", DAT);
        }
    

Program Debug Note

    デバッグガイド

  1. Debug Tool に依存しすぎると、無駄な時間ばかり浪費してろくなことはありません。
    デバッグに必要な情報を表示するソースコードをプログラムに組み込みましょう。
    ①MessageBox などを利用する。
    ②WriteLine などで出力ウインドウに書き出す。
    ③タイトルバーに表示する。

    メッセージボックスを使う

  2. メッセージボックスはどこからでも手軽に利用することが出来るので、デバッグのときに重宝します。
    Win32 API では MessageBox() を使っていました。
    マウスのクリックで終了確認
    MessageBox.Show("プログラムを終了します","Message Box");
    
  3. ストアアプリ(C++)では MessageDialog を使います。
    Windows8 Blank App
        Windows::UI::Popups::MessageDialog^ dlg =
            ref new Windows::UI::Popups::MessageDialog("Test Message");
        dlg->ShowAsync();
    
  4. ストアアプリ(C#)の書き方です。
    MessageDialog
    async private void Button_Click(object sender, RoutedEventArgs e)
    {
        Windows.UI.Popups.MessageDialog dlg =
            new Windows.UI.Popups.MessageDialog("Hello World");
        await dlg.ShowAsync();
    }
    

    出力ウインドウに書き出す

  5. 応答するのが面倒なら Visual Studio の出力ウインドウを使う方法がお勧めです。
    メッセージは Debug モードで実行した時に出力ウインドウに表示されます。
    Debug モードで実行が終わった後で「出力」タブをクリックして下さい。
    普通に実行した場合は全く影響が無く、デバッグ情報の収集に適しています。
    OutputDebugString() は、Windows10/C++ でも Windows10/DirectX でも使用可能です。
  6. ストアアプリ(C++)では OutputDebugString を使います。
    <windows.h> をインクルードして下さい。
    #include <windows.h>
        OutputDebugString(L"★Test Debug Message\n");
    
        int num = 123;
        OutputDebugString(num.ToString()->Data());
    
    void Debug(Platform::String^ msg, int v)
    {   Platform::String^ str = msg + v.ToString() + "\r\n";
        OutputDebugString(str->Data());
    }
    
  7. ストアアプリ(C#)では Debug.Write を使います。
    using System.Diagnostics; を宣言して下さい。
    using System.Diagnostics;   //Debug.Write を使うとき
        Debug.Write("\n*** Debug Message ***\n");
    
        int num = 123;
        Debug.WriteLine("NUM:" + num);
    

    タイトルバーに表示する

  8. Title Bar を利用して Debug 情報を確認する方法も便利です。
    時々刻々と変化する情報を常時確認することが出来ます。
  9. ストアアプリ(C#)で Title Bar に表示するプログラム Title Bar です。
    using Windows.UI.ViewManagement;
    
        public MainPage()
        {
            public MainPage()
            {
                this.InitializeComponent();
                var view = ApplicationView.GetForCurrentView();
                view.Title = "現在の時刻:" + DateTime.Now.ToString();
            }
        }
    
  10. ストアアプリ(C++)でも使えますが Title Bar C++ の場合はちょっと面倒です。
        <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
            <Grid.RowDefinitions>
                <RowDefinition Height="30"/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Border x:Name="TitleBar" BorderBrush="Black" Background="DarkBlue" BorderThickness="1">
                <TextBlock x:Name="TitleName" Text="My Application" Foreground="White"
                    Style="{ThemeResource BodyTextBlockStyle}" />
            </Border>
        </Grid>
    
    MainPage::MainPage()
    {
        Windows::ApplicationModel::Core::CoreApplication::GetCurrentView()->TitleBar->ExtendViewIntoTitleBar = true;
        InitializeComponent();
        Windows::Globalization::Calendar^ cal = ref new Windows::Globalization::Calendar();
        auto longTime = ref new Windows::Globalization::DateTimeFormatting::DateTimeFormatter("longtime");
        DateTime time = cal->GetDateTime();
        TitleName->Text = longTime->Format(time);
    }
    

Program Guid 古いページの Windows & DirectX のプログラムガイドです。