C/C++でBrain用アプリを開発する

ページ名:C/C++でBrain用アプリを開発する

ここでは、C/C++ 言語を用いて Brain (Windows CE) 用アプリケーションを開発するうえでのノウハウを掲載しています。

目次

開発を始める[]

環境構築[]

開発環境・SDK に掲載している各開発環境の記事を参考にします。

学習[]

まず、C か C++ を学習してコーディングに慣れましょう。Brain の OS は Windows CE なので次は Windows CE 開発の情報を読んで進みたいところですが、CE 開発について取り扱うサイトはかなり少ないです。そのため、一般的な Windows PC 向けの Win32 API プログラミングを学んで CE 開発に応用することをお勧めします。以下に、参考にできるサイトを掲載します。

  • Windows プログラミング入門 - Web/DB プログラミング徹底解説
  • Win32 API入門

Win32 API は原始的な構造を引きずっているため開発が難しいです。焦らず、ゆっくり時間をかけて理解してください。サンプルをコピペして大まかに理解したら、サンプルを書き換えたり自力で行を追加したりしながら理解を進めるのが良いでしょう。Win32 API入門 は内容が多いぶん詳細に解説されているので、全て読まずに必要になったときに参照すると便利です。

実際に Brain 用アプリを作成するには、以下のサイトがよくまとまっていて参考になります。

  • WindowsCE+APIプログラミング SDK

Pocket PC 向けの解説となっていますが、基本的には同じです。先述の一般的な Windows PC 向けプログラミングと共通点が多いですが、Brain で動作する新鮮さは何とも言えないものがあるはずです。

「もっといろんな Windows CE の機能を知って高度なアプリを作りたい」とか、「Windows PC で使える○○関数が Windows CE で使えるかを確認したい」と思ったら、公式ドキュメントや Windows CE Developers FAQ を参照してください。

知見[]

メニューバーが出ない[]

「Win32 API におけるメニューバーの出し方は色んなサイトに載っているが、どれを試しても PC では表示されても Brain で表示されない」というよくある問題があります。これは、Windows CE におけるメニューバーの扱いが PC 版と異なるためです。

Windows CE は低解像度なモバイル端末用の OS です。タイトルバーやメニューバーなどの要素を PC と同じように並べると画面が狭くなってしまうため、Windows CE においてはこれらを1行にまとめるコマンドバーを使用します。具体的には、

  1. InitCommonControls() または InitCommonControlsEx() でコモンコントロールを初期化する
  2. CommandBar_Create() でコマンドバーを作成する
  3. CommandBar_InsertMenubar() または CommandBar_InsertMenubarEx() でメニューバーをコマンドバーに挿入する
  4. CommandBar_Show() でコマンドバーを表示する

という流れで表示します。

コマンドバーを表示すると、描画領域の上部分がコマンドバーで隠れる問題が起きます。Windows PC であれば、メニューバーの下から描画領域が始まるためこのような問題は発生しません。解決法としては面倒ではありますが、CommandBar_Height() によってコマンドバーの高さを取得し、その分だけ手動で描画領域をずらすという方法を取ります。

以上のコマンドバーの詳細な仕様に関しては Command Bars Reference に掲載されているので、実際にプログラムを書く際はご確認ください。

フォントダイアログでフォントがないと言われる[]

CHOOSEFONTW の Flags メンバで CF_BOTH の指定が必要です。そして、そのためには hDC メンバに GetDC で取得できる適当なウィンドウ (メインウィンドウで良い) のデバイスコンテキストを入れておき、ChooseFontW の呼び出し後に ReleaseDC で解放する、という手順が必要です。面倒ですが、これで Brain にある全てのフォントが表示されるようになります。

自作ダイアログの表示がおかしい[]

リソーススクリプトで、DIALOGEX ではなく DIALOG を使います。文法は同じなので、単にここを書き換えるだけで済むはずです。なお、そもそもコンパイルに失敗する場合は、こちらにあるような旧式の記法に書き換えます。

自作ダイアログで Windows CE 特有の OK ボタンを使いたい[]

リソーススクリプトで、DIALOG の EXSTYLE として WS_EX_CAPTIONOKBTN を指定します。ヘッダがこの定数を定義していない環境では、直接 0x80000000L と数値で指定します。ユーザがこのボタンを押すとダイアログのウィンドウプロシージャに IDOK の WM_COMMAND が送信されるので、これを適切に処理します。

高解像度モードで最大化すると、ボタンなどの右の表示がおかしくなる[]

表示位置のずれが一定幅の場合に、本来再描画しなければならない場所が OS にマークされず、再描画が実行されずにおかしな表示になるようです。ウィンドウを動かすなどして強制的に再描画しなければならないような状態にすることで直りますが、プログラム的に対策することは不可能だと思われます。唯一、コマンドバー上においては、WM_SIZE で MoveWindow(コマンドバーのハンドル, 0, 0, 0, 0, TRUE); を行うと対策可能です。

Brain のキーボードに刻印されている数字に従って、数字として入力を受け取りたい[]

これは、残念ながら力技しかありません。例えば「q の入力をプログラム内で受け取ったら 1 を変数に代入する」といったことです。エディットコントロールの場合は、サブクラス化で用意したウィンドウプロシージャ内で「L'q' の WM_CHAR を受け取ったら SendMessageW(hWnd, EM_REPLACESEL, 0, (WPARAM)L"1"); を実行する」という形で実装できます。

第2世代以降の辞書アプリで使われている滑らかなフォントを使いたい[]

ゴシック体は DFGHSGothic-W5-SH、明朝体は DFGHSMincho-W5-SH としてインストールされています。CreateFontIndirectW 等でこのフォント名を指定すれば使用できますが、Brain ではシステムレベルでのアンチエイリアスが無効化されているため、そのままではぐちゃぐちゃの見づらい表示になります。ダイアログなどではオーナードローにしないと回避不能ですが、それ以外の場面では、CreateFontIndirectW に渡す lfQuality に ANTIALIASED_QUALITY (値は 4) を指定すると、辞書アプリと同じ綺麗な表示になります。

なお、Windows Embedded CE 6.0 は Windows PC で用いられている「ClearType」という高度なアンチエイリアスにも対応し、CLEARTYPE_QUALITY (値は 5) とすることで使用できますが、Brain の画面が横倒しに取り付けられているため綺麗な表示にはなりません。

ウィンドウサイズを限定したい[]

Windows PC であれば WM_GETMINMAXINFO を処理してやればいいですが、Windows CE はこのメッセージを送信しないため使えません。代わりに、「WM_SIZE を受け取った際に、制限を満たさないサイズなら SetWindowPos 等で再度サイズを変える」という対応を行います。Windows PC を対象とする記事では「この方法を使うと WM_SIZE が繰り返し送信されてしまうためその対応が必要」とありますが、Windows CE では多重送信されないようなので、単に強制的にサイズを変えるのみで大丈夫です。

変数型が変[]

Win32 API プログラミングでは、一般に Win32 API ヘッダが提供する変数型を利用します[1]。各型の詳細は Windows Data Types を参照してください。P から始まる型と LP から始まる型は 16-bit Windows 時代の名残であり、CE を含む 32-bit Windows では同一なので気にしなくても構いません。LP の L は long で、通常の 16-bit のポインタに対して 32-bit の長いポインタという意味でしたが、32-bit Windows ではどちらも 32-bit となり、以後差異が無くなりました。

なお、Windows CE では TCHAR 系は必ず WCHAR 系になります。これは、Windows CE に ANSI 版 API が実装されていないため、UNICODE、_UNICODE マクロが標準で定義されていることによります。現在は UTF-8 対応の観点で再興の兆しを見せている ANSI 版 API ですが、当時は互換性のためだけに残されていたものだったため、容量や性能が貧弱な CE デバイスでは取り除かれていました。例えば、CreateWindowW は存在する一方 CreateWindowA は存在しません。

あるはずの API 関数が使えない[]

先述の公式ドキュメントには記載されているのに関数が存在せず呼べない場合、まずはスペルミスを確認してください。その次に、公式ドキュメントに記載のある必要なヘッダファイルとライブラリファイルを追加していることを確認してください。ライブラリファイルの追加方法は開発環境によりプロジェクト設定のリンカ設定から行う、コマンドラインオプションに追加するなど様々です。それでも解消せず、かつ Brain にその API が実装されているのであれば、それが含まれる DLL からライブラリファイルを作成して追加するか、LoadLibrary() で動的に読み出すことで使用できます。

正しいはずの C/C++ プログラムがコンパイルできない[]

まずは、新しい C/C++ 規格で書かれていることが考えられます。C/C++ 規格は数年おきに更新されますが、Windows CE の開発環境はもはや更新されておらず、C89 や C++98 等の古い C/C++ 規格にしか対応しないことが多いです。古い入門サイトを参考にするなどして対応してください。CeGCC は GCC 9.3.0 と比較的新しく、-std=gnu18 や -std=c18 を指定することによって C18、std=gnu++17 や std=c++17 を指定することによって C++17 に準拠しますが、C23 (std=gnu2x/std=c2x) や C++20 (-std=gnu++2a/-std=c++2a) への準拠はドラフト段階のものであり不完全です。

他には、windows.h を読み込んだ後に C++ STL のヘッダを読み込んでいることが考えられます。windows.h は、NOMINMAX マクロが定義されていない場合に min や max といったマクロを定義することがあります。しかし、詳しくは説明しませんが、マクロ機能はあまりに強力な機能のため、C++ STL の中の min や max を置き換えて破壊してしまいます。これを防ぐには、windows.h を読み込む前に NOMINMAX マクロを定義するか、C++ STL の読み込みを windows.h より先に書きます。

どれにも合致しない場合は、エラーメッセージを上から丁寧に読み、よく分からない場合はコピペして検索しましょう。

C/C++ の躓きやすいポイント[]

Win32 API 関連のサンプルコードをあたっていると、意味の分からないコードに出会うことが多いです。これは、Win32 API 呼び出しによる実装が通常のアプリケーション開発と比べるとかなり原始的で、C/C++ の入門レベルではあまり扱われないような高度な機能を駆使していることが多いためです。初心者が躓きがちな点を紹介します。

if/while/for 文の括弧の中身が条件式のように見えない[]

if/while/for の条件式の部分には任意の式が入ります。式には値・演算子・変数・関数とその組み合わせが含まれ、式の評価結果がゼロか非ゼロか[2]で分岐します。ゼロであれば偽 (false)、非ゼロであれば真 (true) です。式の左にたまにあるビックリマークは右の真偽を反転させる演算子です。ですから、関数呼び出しが条件式として書いてある場合、その返り値が条件分岐に使われていることがわかります。

比較演算子である == や < 等は計算結果を持つ演算子で、C では整数値、C++ では真偽値です。cout や printf 等で一度試してみると面白いですよ。

ちなみに、メッセージループは無限ループですが、while 文の「条件式」部分に入れている GetMessage() は「メッセージが来たときだけ値を返し、それ以外は待つ」というものなので、ビジーループにはなりません。

if/switch 文の括弧の中に「;」が入っている[]

if(初期化式; 条件式)「初期化式」では変数に値を代入するなど、「条件式」の前に行う処理を指定します。「初期化式」が実行された後、「条件式」の判定が行われます。switch(初期化式; 条件値)上と同様、「初期化式」を実行した後に switch ブロック内で条件と「条件値」の比較が行われます。

この文法は C++17 という比較的新しい規格で導入されましたが、これに現在対応しているのは CeGCC のみとなっています。それ以外の開発環境を使っているのであれば該当部分を書き換えましょう。

計算式に「&」「|」「^」「~」「<<」「>>」が出てくるのは何?[]

これらはビット演算子という演算子の一種です。「コンピュータは2進数で動いている」という話は聞いたことがあるかと思いますが、ビット演算ではその2進数(ビット単位)の演算を行います。C/C++ に代表されるシステムプログラミング言語では頻繁に用いる計算ですが、初心者が使うことはあまりありません。CreateWindow() のスタイル指定等で bitwise OR を表す「|」が現れますが、「そんなものがあるんだ」程度で問題ありません。

条件式に「&」や「=」が出てくるのはなぜ?[]

まず、「&」は一つ上で説明したビット演算子です。具体的には bitwise AND であり、「左右の式を見て共に1であるビットのみ1にした値を返す」計算をします。これが条件式に登場するのは、例えば「ある変数 a を2進数で見たとき、下から5番目の桁が1になっているか確認したい」という場面で「a & 0b10000 [3]の計算結果が0なら違い、0以外なら真である」という形で確認できるからです。なお、右の数値は一般的にマクロか、10進数で 16 のように記述されます[4]。おそらく、あなたが遭遇したのもこのようなケースでしょう。

次に、「=」 は代入の記号ですが、こいつは代入した結果を返す機能も持っています。これを駆使すると、「変数にバックアップを取りながら、その値で分岐する」というのを1行で書けます。

計算結果、変数、関数の先頭に括弧書きで変数型が書いてあるのは何?[]

これは明示的キャスト (explicit cast) と呼ばれるもので、元々その型ではないものをその型の値に変換する操作です。例えば、(int)1.6 とあれば、double 型の 1.6 が int 型の 1 に変換されます。キャストは、例えば int 型整数に double 型の値を代入するなどの場面では暗黙的に(=勝手に)起こります。こちらは暗黙のキャスト (implicit cast) と言います。プログラマーが意図してなさそうな暗黙的キャストは、たまに警告やエラーになるものがあります。その場合に、間違っていないことをコンパイラに伝えるときにも明示的キャストを使います。なお、C ではポインタの暗黙的キャストが許可されますが、C++ では明示的キャストが必要です。

計算式じゃないところに & が出てくるのは何?[]

& の右に続く変数の番地 (address) を取得する演算子です。「番地」や「アドレス」と聞くと小難しい印象を受けるかもしれませんが、要するに「メモリ上でその変数が置かれた場所」のことです。そして、この番地を格納した変数をポインタ変数と呼びます。番地を取得する用途は様々あります。

例えば C/C++ では配列変数を丸ごと関数に渡せませんが、番地は1つの値なので渡せます。関数内ではその番地から相対的に見る位置をずらすことで配列全体を読み書きできます。

また、変数を関数に渡したときには普通その値のコピーが渡されますが、コピーではなく呼び出し元が渡した変数そのものに結果を入れてほしいことがあります。ここで、関数に変数のコピーではなく番地を渡せば、受け取った側はその番地に結果を入れることで呼び出し元に結果を返せます[5]

さらに、構造体は丸ごと普通に渡すこともできますが、一般にコピー処理が重くなるため避けられます。このように無駄なコピー処理を避けるためにも有用です。

おまけ: ウィンドウクラスの登録で、ウィンドウプロシージャの関数名を書く部分があります。実行時には変数のようなデータのほかに CPU の命令もメモリに格納されるため、各関数がメモリ上のどこにあるかも変数と同様に定義できます。C/C++ においては、関数名の後にカッコを書かないと、それは関数の場所(番地)を表す式になります。よって、該当箇所ではウィンドウプロシージャ関数はここにあるよという情報を WNDCLASS 構造体に記録していて、その構造体の場所を RegisterClass() に与えることで、RegisterClass() は何をウィンドウプロシージャとして実行すればよいかを知ることができる、ということです。この関数が失敗したときのエラー処理の書き方は、上記で説明した条件文の話につながりますね。

脚注[]

  1. 例えば int 型は(本来) CPU のレジスタサイズの整数型であり、CPU アーキテクチャによってサイズが変わります。これによる移植性などの問題を避けるために導入されたものだと思われます。
  2. C++ では真偽値ですが、整数などの真偽値でない値を与えた場合はゼロか非ゼロかで真偽値に変換するため、結果的には C と同じ挙動になります。
  3. 左右はどちらでも構いませんが、大抵この順番で書きます。
  4. 古い C/C++ では逆にこの記法しかできません。
  5. このような変数の渡し方をポインタ渡しと言います。C++ では、似た機能の「参照渡し」も利用できます。


特に記載のない限り、コミュニティのコンテンツはCC BY-SAライセンスの下で利用可能です。

シェアボタン: このページをSNSに投稿するのに便利です。


最近更新されたページ

左メニュー

左メニューサンプル左メニューはヘッダーメニューの【編集】&gt;【左メニューを編集する】をクリックすると編集できます。ご自由に編集してください。掲示板雑談・質問・相談掲示板更新履歴最近のコメントカウン...

音楽を聴く

目次1 Xaudio MP3 Player2 Nitrogen3 Winamp3.1 導入3.2 使い方3.2.1 メニューの項目3.2.2 スキンの適用3.2.3 イコライザー3.2.4 プレイリス...

電子辞書を買う、その前に

このページでは、進学して初めて電子辞書を購入される方、新しい機種に乗り換える方のために、それぞれのニーズに合わせた電子辞書を紹介していきます。特に最近の Brain は Windows CE を活用す...

開発者用ツール

開発者用ツール.pngここでは、Brain 上で動作する開発者用ツールを紹介しています。Brain 用ソフトウェア開発には、開発環境・SDK も参照してください。ソフト名できること備考Scalpelシ...

開発環境・SDK

注意: 2021年に発売された第5世代に該当するモデルで動作するアプリの作成方法は、現状不明です。詳細はこちら。開発環境[]各開発環境の環境構築や使い方などの詳細については、それぞれのリンク先の記事を...

記号・日本語の入力方法

Brain にはキーボードがありますが、辞書を引くための最低限のキーしか搭載されておらず、数字や記号を入力することができません。また、IME が搭載されていないため辞書アプリ外では日本語入力もできませ...

第5世代

第5世代機の発売日当日、突如として Brain Library に現れたポップアップ。多くの憶測を呼んだ。2021 年、例年より少し遅れて、見た目は PW-Sx7 とほぼ何の違いもない PW-S1, ...

第4世代

この世代では、PW-SB5 以降の大学生・ビジネス向けモデル (PW-SB 系) を除く機種に非公式アプリの起動プロテクトが掛かるようになりました。また、PW-Sx7 ではさらに強化したプロテクトが導...

第3世代

対象型番[]発売時期中学生高校生学校専売大学生ビジネス生活·教養シニアその他2014年前半SJ1SH1HC4SB1SA12014年後半SR12015年前半SJ2SH2HC5SB2SA22015年後半2...

第2世代

対象型番[]発売時期中学生高校生学校専売大学生ビジネス生活·教養シニアその他2012年前半G4200G5200HC2A9200A72002012年後半A7300GX5002013年前半G5300HC3...

第1世代

対象型番[]発売時期中学生高校生学校専売大学生ビジネス生活·教養シニアその他2008年後半AC880AC830TC9802009年前半GC590AC8902009年後半AC9002010年前半GC61...

倉庫番

Warehouse Guy プレイ画面グループゲーム開発者True DimensionsDLLmfcce211.dll1982 年に PC-8801 向けにリリースされて以降、30 年以上に渡って遊ば...

リンク集

Brain 用ソフトウェア開発者[]KnatechceOpener、KN PDF Reader など。川本優Task Switcher など。ソースコードはこちらで配布されています。lycorisON...

リバーシ

かつてはブレーンライブラリーで追加コンテンツとして「リバーシ」が販売されていましたが、削除されてしまいました。しかし、まだフリーソフトでリバーシを遊ぶことができます。目次1 Reversi1.1 操作...

ユーティリティ

便利ツール-0.pngソフト名解説備考Garmap CE(直リンク)オフライン地図アプリです。MioPocket の System に入れ、AYGSHELL.DLL を CE5 からコピーします。別途...

メガドライブエミュレータ

1988 年に当時のセガ・エンタープライゼスより発売された、据え置き型家庭用ゲーム機メガドライブのエミュレータの解説です。自由な利用と頒布が許諾されていない ROM のダウンロードは著作権侵害により罰...

ミニッツマスコット

ミニッツマスコット デフォルトのキャラクターは「耳長メイドのらんぷさん」グループユーティリティ利用用途デスクトップマスコット開発者上野智弘DLL不要デスクトップ常駐型のキャラクター表示アプリといえば、...