進捗置き場というわけでもない場所

プログラミングしてる中で見つけたこととか

自分の活動と作っているものの宣伝【中高生プログラマAdC 9日目】

この記事は中高生プログラマAdC 2015の9日目の記事です。

AdCのためにアプリをPonと作れるプロになれなかったので自己紹介とちょっとした宣伝を書こうと思います。

めちゃくちゃ簡単な自己紹介

Azaika(@azaika_)です。どっかの学校に通う男子学生です。
プログラミングは学校の部活で学んでます。

部としての活動

部としては主に次の2つの活動をしています。

  • 競技プログラミング
  • ゲーム開発

その他にも3DCGやDTMなどのPCを使った創作活動をしている部員がいます。
しかし、創作物に関しては基本的にチーム開発などはあまり行わず、個々が作った創作物に関して部員同士で相談できる場として機能していると感じます。

自分の活動

さて、部の活動として競プロとゲーム開発を上げましたが、僕はそのどちらも熱心にしてはいません。
では何をしているかというと、ライブラリの開発です。
うちの部では最近まで、ゲーム開発は先代が作ったWinAPIとGDI+を軽くラップしたライブラリを使い続けて来たのですが、
このご時世にGDI+もないだろうということでDirect2Dで書きなおしたり(書き終えたあたりで部での開発用ライブラリがSiv3Dに移行して悲しい)
その折でWinAPI使いにくい、となったのでWinAPIのラッパーを書いたりしてます(そのWinAPIラッパーはGithubに公開していますので使ってみて感想くれたり、あわよくばプルリクなど頂けると泣いて喜びます)
その間にC++の言語仕様も少しづつ勉強して、最近は新入生向けのプログラミング教育もしてたりしてなかったり。

また最近ではC++だけでなく、Windows10のUWPを開発しようとC#も勉強中です。
あとはほんのちょろっとHTML/CSS勉強したり、Haskell触ったり、Linux(Arch)で遊んだりしてます。

WinAPIラッパーについて

さて、自己紹介だけで終わるのもアレなので、さっき書いたWinAPIラッパーの解説(宣伝)と苦労話でもしようかと思います。

僕の作っているWinAPIラッパーは名をwawl(Windows Api Wrapper Library)と言い、設計思想としては「WinAPIを本家の設計をあまりいじらずC++といえるくらいにする」というのがあります。
そのためあまり構造をいじらず、機能ごとのclass分け、定数のenum class化などが主になります。
具体例を出せば、Processクラスのコンストラクタの引数構造がだいたいWinAPIのCreateProcessと同じです。
ただし、WinAPIネイティブ(?)な型は一切存在しておらず、全てwawl内部の型で完結しています。
また、WinAPIを用いた外部ライブラリとの同時使用も視野に入れ、それぞれのclass毎にWinAPIネイティブである内部型を取得する機能も用意しています(Processで言えば、process.get()でPROCESS_INFORMATION構造体が取得できる等)
これらにより、泥臭いWinAPIをかなり手軽に扱えるようになっています。

サンプル

#include "Window.h"
#include "FileSystem.h"
#include "Input.h"
#include "Using.h"

void wawlMain() {
    wnd::RootWindow window(
        L"Kitty on your lap",
        wnd::Prop({ wnd::PropOption::HRedraw, wnd::PropOption::VRedraw }),
        { 640, 480 },
        wnd::Style::Overlapped
        );
    fs::Process proc;

    //Window表示
    window.setShowMode();

    //左クリックしたらメモ帳起動
    window.on(Msg::LClick, [&](UintPtr lp, IntPtr rp) {
        if (!proc)
            proc.open(L"notepad");

        return window.defaultProc(Msg::LClick, lp, rp);
    });
    //右クリックしたらペイント起動
    window.on(Msg::RClick, [&](UintPtr lp, IntPtr rp) {
        if (!proc)
            proc.open(L"mspaint");

        return window.defaultProc(Msg::LClick, lp, rp);
    });

    while (Sleep(10), true) {
        //Tが押されたら起動しているアプリを終了
        if (kb::getState(KeyCode::T) && proc)
            proc.terminate();

        //Esc押したら終了するかユーザーが選択
        if (kb::getState(KeyCode::Escape) &&
            mb::show(L"wawl", L"Do you shutdown this application?", mb::Button::YesNo)
                == mb::Result::Yes
            )
            return;

        //Windowが存在すればUpdate、存在しなければ終了
        if (window)
            window.update();
        else
            return;
    }
}

簡略化のためにエラー処理は省いてあります。
このコードを実行すると、真っ白なWindowが出てきてソースのコメントに書いたままの挙動をします。
ちなみに、描画等に関してはWinAPIの範疇ではない(DirectX等の範疇)としてサポートしていません。
これに関しては@yuki74wさんがDirect3Dラッパーを作ってくれると言ってくれていますし、僕もDirect2Dラッパーを作ろうかと思っています。

ここからは苦労話

WinAPIで何が一番辛いかというと資料集めです。ある程度メジャーなところまでは日本語の資料があるのですが、それ以上になると英語のMSDNを巡礼し始め、知らぬ間にロシア語をページ翻訳して読む羽目になったりします。
これで一番よくあるのが定数の詳細等です。例えばキーコード定数にVK_CRSELという定数があるのですが、これが何かというとCursorSelectという昔のIBMキーボードについていたもの用の定数だったりします。
あとは、ProcessやFileでのアクセス制限や権限関係の定数などのファイルシステムに踏み込むかのような内容が含まれたものもあり、非常に混乱しました。
あとC++的なところの辛みで言えば、参照の寿命問題などに直面して2週間潰したり、WinAPIの仕様との兼ね合いでclassの構造を工夫せざるを得なくなったりしました。

最後に

初AdCだったので結構怯えながら書いてます。
あとプログラミング(IT)関連の方は是非Twitterでフォローしていただけると嬉しいです。
長い駄文でしたが、ありがとうございました。