Windowsプログラミングに関する世界観1(Windows API)です。
自分の書いたブログ「わたしの名はフレイ」2020/12/20より。
Windowsプログラミングでは、ハンガリアン記法という統一されたルールで、変数や構造体メンバの名前を付ける。
たとえば、ポインタには必ずlpが付く。
これが分からないと、構造体メンバの意味が分からない。
(詳しくはやねうらお氏の「Windowsプロフェッショナルゲームプログラミング」が参考になります。)
素のC++では、関数に複数の値を渡すことはできるが、複数の値を返すことはできない。
しかしながら、複数の値を実行結果として、呼び出し元に返したい時もある。
このような時、構造体のポインタあるいは参照を渡して、関数の中から構造体を操作することができる。
返り値はエラーチェックに使う。
Windowsでは、こうしたやり方で関数に変数を与える。
(詳しくはやねうらお氏の「Windowsプロフェッショナルゲームプログラミング」が参考になります。)
Windowsでは、コールバック関数とハンドルを多用し、メッセージループでイベント駆動をする。
ここで使われるのが、Windowsメッセージ。
WM_という名前で定義されており、イベントの発生に対してメッセージが送られ、コールバック関数を実行する。
たとえば、「マウスがクリックされた時」とか、「画面が再描画された時」などに、場合や状況に応じてメッセージに応答する。
これを、メッセージループとか、イベントループと呼ぶ。
また、それぞれのウィンドウやアプリケーションインスタンスを識別するため、ハンドルを使用してOSとやり取りを行う。
イベント駆動を参照のこと。
MFCでは、メッセージマップによって、Onから始まるメソッドにメッセージをマップする。
ドキュメントデータを表すドキュメントクラスと、画面を表すビュークラスを継承する。
特に、データを保存するために、オブジェクトをファイルに書き出すことのできる、シリアライズを使用する。
ブラウザなどを作るのであれば、Visual C++のAppWizardやClassWizardなどを使って、スケルトンを作成したりメソッドを自動作成して関連づけながら、ビュークラスを継承していけば、IEコンポーネントを使った簡単なウェブブラウザを開発できる。
Visual C++/MFCを参照のこと。
Windowsでは、グラフィック操作などをする際に、Windowsとデバイスの仲介役として、デバイスコンテキストを使用する。
たとえばGDIなどの操作で、ペンやブラシから線や円、四角形などのグラフィックを描く時などに、必要となる。
GDIを参照のこと。
GUIのインターフェイスは、リソースファイルからデザインしたり、メソッドからコントロールを作成したり操作したりできる。
メニューはリソースファイルで作るのが一般的だが、ビュー画面などはさまざまな処理をするために、動的にコントロールを操作する。
また、VBやC#などでは、ポトペタ操作でデザインし、プロパティを操作したり、イベントハンドラを用いてイベントに応じてメソッドを実行したりして、イベント駆動で開発ができる。
Windowsは既にこうした.NET言語で開発することが一般的だが、Javaと同様、仮想マシンである.NET Frameworkが必要であり、ネイティブなコンパイル言語を使う場合よりも速度や効率のようなパフォーマンスは劣る。
しかしながら、優れたクラスライブラリを用いて、とても簡単にアプリケーションが開発できるとエンジニアから評判である。
Windows開発だけでなく、Unityなどのゲームエンジンにも、C#が採用されており、C++と並んでゲーム開発の標準言語になっている。
最近は、サーバーにもWindowsを使う事例が増えた。
これは、NTカーネルが安定して動いていることや、ActiveXやASP.NETなどのネットワーク技術が成熟し、UNIXと同等に使えるものになったこと、それから、契約や取引などの意味で、マイクロソフトと合意する政治的な判断などが、理由として挙げられる。
クライアントOSで圧倒的シェアを誇るWindowsだが、サーバーでも勢力を着実に伸ばしており、たとえばSQL ServerやWSLなどの努力はサーバーOSでは選択肢一択のLinuxをいずれ倒すことになるかもしれない。
ASP.NET、ADO.NET、Microsoft SQL Server、WSLを参照のこと。
詳しいコードはModule 1. Your First Windows Program - MSDNが参考になります。以下はこのコードに対する解説。
Windows APIによるプログラミングは、ウィンドウプロシージャ(システムから呼ばれるコールバック関数)とメッセージループを中心に成り立つ。
まず、プログラムはwWinMain()から実行される。最初に、WNDCLASSのlpfnWndProcにコールバック関数WindowProc()を登録する。
wWinMain()の最後にはメッセージループwhile (GetMessage()) {}が登場し、Windowsメッセージをやり取りする。
ウィンドウプロシージャはCALLBACK WindowProc() {}のようにCALLBACKをつけて定義する。
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_DESTROY: /* 処理 */ case WM_PAINT: /* 処理 */ } }
WindowProc()のオプションは、hwndはメッセージが送り付けられるウィンドウのハンドル、uMsgはメッセージ(「WM_XX」のような形で定義されている)、wParam, lParamはメッセージの補助的な内容を含むパラメータとなる。
hwndはCreateWindowEx()関数でウィンドウを作った後、ウィンドウをさまざまなところから操作するためにハンドルとして使う。
switch - case文でメッセージを処理することで、システムから呼び出されたメッセージに対してイベント駆動のプログラムを書くことができる。
ウィンドウがさまざまな理由で再描画が必要となった時、WM_PAINTメッセージが送られてくる。
このWM_PAINTメッセージに応じる形で、描画すべき処理を記述することで、ウィンドウの表示処理を行うことができる。
もし、自分のタイミングでウィンドウを再描画させたくなった時は、InvalidateRect()関数を実行することで、システムに「再描画の実行をお願いします」と要求することができる。
2022.12.07-08編集
以下はWindowsメッセージ - Hatada's Home Pageを参考に執筆しました。
主なWindowsメッセージの一覧:
関連 | メッセージ |
---|---|
ウィンドウの作成・破棄 | WM_CREATE(作成) WM_CLOSE(閉じる) WM_DESTROY(破棄) |
ウィンドウの変更 | WM_PAINT(描画) WM_SIZE(サイズ変更) WM_DRAWITEM(アイテムのオーナードロー描画) WM_CTLCOLORSTATIC(描画の直前) WM_ACTIVATE(アクティブ化) |
マウスイベント | WM_LBUTTONDOWN(左ボタンクリック) WM_LBUTTONDBLCLK(左ボタンダブルクリック) WM_RBUTTONDOWN(右ボタンクリック) WM_MOUSEMOVE(カーソル移動) WM_MOUSELEAVE(カーソルの領域外への移動) |
コントロールイベント | WM_COMMAND(メニュー・コントロール操作) WM_NOTIFY(コントロールへの通知) WM_SETFOCUS(キーボードフォーカスの取得) WM_KILLFOCUS(キーボードフォーカスの離脱) WM_HSCROLL(水平スクロール) WM_VSCROLL(垂直スクロール) |
Windows APIでは、OSのコントロールはウィンドウ内の子ウィンドウとして扱われるため、CreateWindowEx()関数で作成できる。
たとえば、CreateWindowEx()関数でツールバーを作成するには、ウィンドウクラスに「TOOLBARCLASSNAME」を指定すればよい。
以下のMicrosoftの記事が参考になる。
TOOLBARCLASSNAME以外にも、さまざまなコントロールを指定できる。以下に一覧がある。
単にツールバーを作りたいだけであれば、CreateWindowEx()関数ではなくCreateToolbarEx()関数を使用することもできる。
ツールバーやリストビューなど、Windows APIのコモンコントロールについては以下のサイトが参考になる。
メニューやアイコンなどのコントロールは、リソースファイルを用いて使うことが多いです。
たとえば以下のようになる。
HOGEMENU MENU BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "実行(&E)", IDM_EXE MENUITEM "終了(&Q)", IDM_QUIT END END
2022.12.08編集
テキストエディタを作る場合など、サイズがどれくらいになるか分からないバッファにはメモリを動的に確保する。
Windowsでは、メモリの動的確保にはGlobalAlloc()関数とGlobalLock()関数を使う。不要になったら、GlobalUnlock()関数とGlobalFree()関数で解放する。
(猫でもわかるWindowsプログラミングを参考に執筆しました。)
ウィンドウに単純に文字を表示するには、TextOut()関数やDrawText()関数を使う。
TextOut()関数やDrawText()関数では、第一引数にデバイスコンテキストハンドルを指定する。
このデバイスコンテキストハンドルはGetDC()関数で取得できる。GetDC()関数の引数にはウィンドウハンドル(hwndのこと)を指定する。必要がなくなればReleaseDC()関数で解放する。
あるいは、WM_PAINTメッセージが送られてきた時、BeginPaint()関数を実行する方法でも、デバイスコンテキストハンドルが得られる。描画が終わったらEndPaint()関数で終了する。
(猫でもわかるWindowsプログラミングを参考に執筆しました。)
2022.12.08
Windows APIの関数一覧は以下を参照のこと。
2023.05.13
Windowsの動的リンクライブラリはDLLと呼ばれる。
以下の記事を参照のこと。
以下の書籍が参考になります。
後日注記:初心者は、黙ってこの本を読みましょう。Windowsにまつわるさまざまなこと(Windowsメッセージ、ウィンドウやコントロール、関数・マクロ、デバイスコンテキストまで)が、この書籍に一通り書いてあります。
2023.01.22編集
Microsoftが開発する有料の統合開発環境・コンパイラ。
Visual Studioの無料の代替ソフトウェアとして、EclipseのC/C++バージョン(CDT)を入れると言う手もあります。僕はC言語で人工知能のプログラムを作る時はEclipse CDTを使っています。ただ、MSのライブラリが使えるのかどうかは定かではありません。ですが、GNUによるC/C++コンパイラのWindows版(MinGW)はWindowsでもきちんと動きます。
Eclipseも参照のこと。
C/C++言語とVisual C++について。
C/C++による、Windows APIプログラミング。
ATL/COMを参照のこと。
MFCを参照のこと。
MicrosoftによるWindowsのAPI。
MSDNにおけるサンプルです。
以下にサンプルコードがあります。
以下にサンプルコードがあります。
Windows APIでカスタムコントロールを作る方法:
Windowsプログラミングの入門サイトとしては、以下の参考リンクが良いと思います。
昔の16bitのコマンドラインOS。UNIXに比べると低機能だが、絶対に使えないわけではない。
DOSを参照のこと。
WineはWindows APIのUNIXにおける実装で、Linux上でWindowsアプリケーションを動かすことができる。
ReactOSはオープンソースのWindows NT(2000以降)のアプリケーションとドライバにおけるバイナリ互換性を目指すOS。言ってみればオープンソースのWindows 2000互換のOSだ。
どちらも、Microsoftの牙城を倒そうとするOS・APIだ。Wineは開発中で、エミュレータではなく、APIを作ることでWindowsアプリケーションをそのまま動かすことを目指している。
WineやWindows OSSを参照のこと。
Windows APIとX11は、同じイベントループを用いてメッセージを処理することが似通っている。X11設定とプログラミングを参照のこと。
JavaのSwingも、Windows APIとよく似た「リスナ」をベースにしたイベント処理を行う。Java Swingを参照のこと。
GUIの開発全般についてはGUI開発を参照のこと。
僕は、Windowsが大好きでプログラマになりたいとか、Windowsのフリーソフトを開発したいとなった時に、Windowsプログラミングからプログラミングの道に入ることをおすすめしません。
なぜなら、Windowsプログラミングは、OSの機能を使うことだけに終始し、自分でボタンやメニューのほとんどの機能を作っておらず、多くが既にあるコントロールを継承するだけで開発できてしまうからです。
Windowsプログラミングは、一見、デザインされたUIを持ちながら、機能はパソコンのできる多くの万能性を備えており、ゲームを開発するのと同じように面白く見えます。
ですが、実際のWindowsプログラミングは、Windows APIを使う場合であっても、MFCやC#/VB.NETを使う場合であっても、ほとんどが最初から用意されているものを使うだけです。
確かに、デザインをすることはありますが、ボタンやメニューを自分で作っているかというとそうではなく、カスタムコントロールを作る場合であっても、既に存在するOSの標準コントロールを継承して、いくらかカスタマイズするだけです。
Windowsプログラミングは、かっこよく見えて、本当はつまらないものです。もしかしたら、あなたがやりたかったことは、オープンソースやLinuxの世界にあるかもしれません。なぜなら、オープンソースやLinuxでは、GUIツールキットであるGTKやQtを使って、デスクトップ環境であるGNOMEやKDEを作っています。ウィンドウシステムのX11やWaylandすら、きちんと作っています。何より、OSの基本的な機能であるカーネルを共同開発でみんなで作っています。
そう、僕が、そしてあなたが、本当に進みたかった道は、WindowsではなくLinuxの方向にあるのです。
後日注記:僕は、GUIプログラミングがやりたいプログラミング入門者には、Visual StudioよりもDelphiをおすすめします。Delphiはとても素晴らしい環境であり、Object PascalというPascalをベースとした独自の言語ではありますが、コンポーネントとRADを使ったとても分かりやすい環境で、「プログラミングとはどのようなものであるか」ということが良く分かります。僕の経験から言って、いきなりVisual Studioを購入したところで、「どのようにプログラミングを行えばいいのか」ということは全く分かりません。高いお金を出して購入しても、無駄になります。Delphi 6 Personalは昔無料版がありましたが、僕はDelphi 7を購入して使っていました。僕はDelphiでOpen Jane(2ちゃんねる専用ブラウザ)のビルドに成功して、プログラミングとはなんであるかが分かりました。
Windowsプログラミングについて言うと、最初はDelphiのほうがおすすめです。
僕個人の意見として、C/C++でWindowsアプリを作ると、Windowsネイティブな実行ファイルは作れますが、その代わり、初心者にとってはわけの分からないコードを大量に書かなければならず、C/C++やWindowsの仕様も大きすぎてカオスを極めるなど、いろいろと初心者には難しいことばかりで、挫折してしまうと思います。
そのような人には、僕はDelphiをおすすめします。
Windows APIやVisual C++による開発を行うよりも、Delphiは直感的でありながら初心者や入門者に優しく、経験のない素人であってもある程度のプログラミング能力とセンスがつきます。
Delphiで初心者が中級者になってバリバリに開発することは、Windows APIやVisual C++で開発を行うよりも容易です。
最近どうなっているかは知りませんが、僕がDelphi 7を購入した時は、公式のマニュアル本と「オフィシャルコースウェア」と呼ばれるDelphiやPascalの入門本が開発環境とセットで含まれていて、この本を一通り読めばDelphiでプログラミングを行うことができるようになっていました。
なので、なんにも前提知識がなくても、Delphiだけを買えばプログラミングができるようにはなります。
ですが、本当のところを言うと、僕はあまりこの本は読んでいません。この本を読まなくても、Delphiの直感的なユーザーインターフェースとコンポーネントを使って、プログラミングが簡単にできるような優れた「環境」がすぐに使えることが、Delphiの大きなメリットです。
なので、僕はWindows APIの開発にもし挫折したら、それだけでプログラミングを諦めずに、まずはDelphiから入ってみることをおすすめします。
Delphiも参照のこと。
2023.05.09
Windows APIを学ぶことの意義とは、「APIを知らなければプログラミングの世界では何もできない」ということです。
言語の文法だけ覚えても、関数やクラスのような、用意されているAPIを覚えなければ何もできません。
確かに、言語だけですべてが完結し、言語の仕様だけ覚えればなんでもできるような、Delphiのような言語もあります(詳しくはDelphiゲームプログラミングのエッセンスを参照のこと)。
ですが、多くの言語では、言語の文法を覚えるだけでなく、OSに用意されているAPIを覚えなければなりません。
LinuxやUNIXにおいては、POSIXのシステムコールを覚えればいいのですが、WindowsにおいてはWindows APIを覚えなければなりません。
なので、C/C++のエンジニアになりたいなら、C/C++の言語仕様だけを覚えても、最初のステップを攻略しただけにすぎません。特に、Windows向けのまともなGUIアプリケーションを開発するためには、Windows APIを必ず覚えなければならないのです。
ひとつ、注意点として、必ずしもC/C++のAPIを選ぶ必要はありません。
たとえば、WindowsのGUIアプリケーションを作りたいのであれば、C#やVB.NETのような言語と、.NETのAPIを選ぶこともできます。
そして、多くの場合、C/C++を選ぶことはよい選択ではありません。C/C++はネイティブなアプリケーションを作ることはできますが、開発が極めて困難で、生産性が低いです。
新しいアプリケーションを開発する言語を選ぶなら、C/C++のような低水準言語といつまでも無駄な格闘をする選択をするよりも、C#あるいはPythonのような新しい言語を選びましょう。あるいはGolangやRustのようなもっと新しい言語もあります。新しい言語は新しいだけあって生産性が高いです。C/C++を選ぶ必要は絶対ではありません。
2023.05.11
Windowsコントロールは、一般のユーザーとしては使いやすいのだが、Windows APIやMFCなどから使おうと思うと、「超わけの分からないAPI」である。
Windowsとデバイスの仲介役。
MFCでグラフィックス処理を行う上では、「何をするにもまずはデバイスコンテキスト」。ここが難しい。
MSDN
サンプル
Windowsは、基本的に、MSDNを見れば事が足ります。
書籍