Windows API/イベントドリブン方式
イベントドリブン方式

Win32APIのプログラムの実行順序は、ユーザーの操作によって変わります。
イベントドリブン方式

例えば、キーボード操作をされたときには、 case WM_KEYDOWN: のブロックが実行されます。(なお、初期設定のテンプレートには case WM_KEYDOWN: のブロックは無いので、自分で書く必要がある。)
イベントドリブン方式

キーボード操作など、なんらかのイベントがされた時にだけプログラムの特定ブロックが実行されるので、イベントドリブン方式といいます。
イベントドリブン方式

Win32APIのプログラムの実行方式はイベントドリブン方式です。
イベントドリブン方式

なお、(グローバル変数の宣言などの例外を除くと、)プログラム中のなんらかの処理は、ほとんどが、なんらかのイベントと関連づけられます。
イベントドリブン方式

もし、「操作に関わらず常に何度も実行させたい処理を書きたい」と思っても、そういう処理は書けません。仮にアナタが「C言語のコンソールアプリのmain関数のように、特定の関数に依存しない処理を書こう」と思っても、Win32APIで書くプログラムには、そういう中枢の関数は無いのです。
イベントドリブン方式

wWinMain 関数のブロックは、単に、Win32APIアプリの開始時点をあらわすブロックにすぎず、アプリ起動時に1回だけ実行されるプログラムにすぎません。
イベントドリブン方式

また、一般に、けっして、なんらかの( wWinMain 以外の)他の関数の実行が終わったからといって、wWinMain 関数から呼び出した関数の終了直後でないかぎり、wWinMain 関数には戻りません。
イベントドリブン方式

Win32APIでは、キーボード操作とは無関係にアプリ起動時に1回だけ実行する処理というのは書けますが、それだって、「アプリ起動」というイベントによって駆動されたプログラムです。
イベントドリブン方式

なので、もし、wWinMain 関数のブロック内で変数を宣言しても、その変数は通常、他のイベントからは呼び出せないです。たとえば描画イベントやキーボード入力受付イベントなどからは、一切、wWinMain 関数のブロック内で宣言された変数は呼び出せないです。
イベントドリブン方式

このように、wWinMain 関数のブロックは、単に、アプリケーション開始というイベントを表すブロックに過ぎないのです。(なお、グローバル変数の宣言の場所は、別の場所にある。くわしくは後述。)
イベントドリブン方式

とにかく、Win32APIにおいて、原則的にプログラム内の個別の処理は、かならず、イベントと関連づけられます。(Win32APIでも、グローバル変数や、includeなど、冒頭文だけ、イベントと無関係に宣言できる。しかし、プログラムの具体的に動作は、必ず、発生条件のイベントと関連づけられる。)
イベントドリブン方式

テンプレートを自動作成すると、
イベントドリブン方式

冒頭の数行目あたりに
イベントドリブン方式

とありますので、グローバル変数を宣言して使いたい場合、この下に入力します。
イベントドリブン方式

たとえば、整数型の変数 kazu を宣言したい場合、次のようになります。
イベントドリブン方式

なお、wWinMain 関数で変数を宣言しても、その変数は他のイベントからは呼び出せません。
イベントドリブン方式

wWinMain 関数には、
イベントドリブン方式

とテンプレート文で書かれている場所がありますので、
イベントドリブン方式

てっきりここに入力しがちですが、
イベントドリブン方式

しかしグローバル変数の入力場所はwWinMain 関数とは違います。
イベントドリブン方式

キーボード操作イベントにかぎらず、基本的にwin32APIプログラムでは、たいてい、あるイベントの詳細の定義と、そのイベント発生後に行う処理を、一緒に書く場合になることが、ほとんどです。
イベントドリブン方式

たとえば、キーボード操作イベントの処理は、どのキーが押されたかというイベントと、キーが押された後に行う処理とを、一緒のブロックに書きます。
イベントドリブン方式

C言語のコンソールアプリの感覚だと、ついつい、イベントの詳細の定義と、イベント発生後に行う処理とを、べつべつのブロックに書こうと考えがちですが、しかしWin32APIでは、そういう書き方は通常は不可能です。
イベントドリブン方式

もし、どうしても、プログラム全体を管理したいブロックが欲しい場合、アプリ起動中に何度も発生するイベントの処理を書くブロックを流用します。
イベントドリブン方式

キーボード操作イベント(WM_KETDOWN)や、時間経過イベント(WM_TIMER)など、何度でも発生できるイベントのブロックを流用して、そのブロック内に、目的の、プログラム管理的な処理を書くことになります。
イベントドリブン方式

このため、一見すると、そのイベントとは関係なさそうな、管理的な処理も、何らかのイベント発生後処理のブロックに書かれることも、あります。
イベントドリブン方式

このため、他人の書いたプログラムを読む際に、一見するとキーボード操作とは関係なさそうな処理でも、キーボード操作のブロックに処理が書かれている場合があります。
イベントドリブン方式

また、上記のような都合のため、書かれたプログラムではキーボード操作のブロックは長くなりがちなので、プログラムの全体像が分かりづらくなるので、もし複数人で共同開発する際には、あらかじめ仕様書などを作っておき、その仕様書でシステムの概要を説明しておき、全体像を把握しやすくすべきでしょう。
イベントドリブン方式

なお、Win32APIプログラミングでは、いわゆる「無限ループ」をプログラマーが新規に書くことは、通常、ありません。もし、無理やり書いても、動作が遅くなったり、バグの原因になります。
イベントドリブン方式

Visual Studio での Win32APIのテンプレート作成時に、アプリを勝手に終了させないための無限ループのようなものが、すでに書かれているので、通常は、そのテンプレートを流用します。
イベントドリブン方式

なお、タイマー機能のある case WM_TIMER: のブロックを追加したり SetTimer というコマンドを使い、「一定の秒数が経過したら○○を実行する」というタイマーのイベントを宣言することにより、キーボード操作とは無関係に自動的な処理を書くこともできます。しかし、これだって「○○秒の経過」というイベントによって駆動されるプログラムにすぎません。
イベントドリブン方式

そして、このタイマーのブロックにも、けっして「何秒、経過したか」という時間経過のプログラムだけでなく、さらに時間経過イベント後に必要になる処理も一緒に書くことになります。
イベントドリブン方式をやめたい場合

伝聞では、PeekMessage() 関数を使うと、イベントドリブン方式はやめられると言われており、(かつてのMS-DOSやBASICのような)手続き型のような処理になると言われています。
イベントドリブン方式をやめたい場合

PeekMessage() 関数とは、マイクロソフト社の仕様用上では、イベントからのメッセージを待たずに、制御を実行するという関数です。なので理屈上は、PeekMessage() 関数でイベントドリブン方式をやめることができるだろう、と考えられています。
イベントドリブン方式をやめたい場合

ですが、実際の実装があまりよくなく、PeekMessage() 関数を用いたアプリケーションがしばしば動作停止をするので、あまりイベントドリブン方式をやめる事を試みるのは、すすめられません。
イベントドリブン方式をやめたい場合

どうも、Visual C++ でイベント・ドリブン方式をやめる事は、マイクロソフト的にはサポートされていないようです。
イベントドリブン方式をやめたい場合

どうしてもPeekMessage() 関数を使う場合、使い方は下記の通りです。
イベントドリブン方式をやめたい場合

WindowsAPIの起動時にVisual Studio の自動作成するコードをよく見ると、
イベントドリブン方式をやめたい場合

というような感じのコードが、最初から作成されています(Visual Studioのバージョンによって多少の差異の可能性あり)。
イベントドリブン方式をやめたい場合

コード中のGetMessage() 関数を除去し、おおむね次のコードのようにPeekMessage() 関数に置き換えれば
イベントドリブン方式をやめたい場合

( たとえばPeekMessage(&msg,NULL,0,0,PM_REMOVE)など )、イベントドリブン方式をやめて、メッセージの到着を待たずに処理をしていく、従来的な手続き型になります。
イベントドリブン方式をやめたい場合

一方、GetMessage() 関数のままの場合なら、メッセージの到着を待って処理をしていく方式になるので、「イベントドリブン方式でループをしていく」と宣言していることになります。
イベントドリブン方式をやめたい場合

なお、実際には描画処理などのため、さらに CreateWindowW() 関数などによる hWnd の初期化が必要です、
イベントドリブン方式をやめたい場合

なお、ネットには下記のように while側で WM_QUIT の有無を判断する類のコードがありますが、しかし2020年現代のVisual Studio2019では、これはコンパイルが通らないです。(「C4700 初期化されていないローカル変数 msg が使用されます」というエラーが出ます。)
イベントドリブン方式をやめたい場合

先に PeekMessage を実行してからでないと、msgの値が取得されないからか、上記のコードはエラーになるようです。
イベントドリブン方式をやめたい場合

なので、while文ではなくdo~while文によって、先に PeekMessage を実行すれば、エラーは無くなり、コンパイルできるようになります。
イベントドリブン方式をやめたい場合

上述のこれらのコードは、実際にelseブロック内に図形の描画を描くなどの処理をすると、コンパイルは可能ですが、フリーズを多発します。
イベントドリブン方式をやめたい場合

また、動作の開始直後は動きますが、しばらく秒数が経つと、動作停止をすることがあります。