Windows 10で始めるC言語開発 第27回 WindowsでC言語開発! ウィンドウクラス○はじめてのウィンドウプログラミングWindows APIを使ってシンプルなウィンドウを作成するサンプルコードを取り上げた。ダイアログを作成する場合と比べるとだいぶソースコードが増えたが、前回取り上げたサンプル
○はじめてのウィンドウプログラミング
Windows APIを使ってシンプルなウィンドウを作成するサンプルコードを取り上げた。
ダイアログを作成する場合と比べるとだいぶソースコードが増えたが、前回取り上げたサンプルソースコードはWindowsにおけるウィンドウプログラミングのエッセンスが詰まっており、ウィンドウプログラミングを理解するうえでとても大切なものだ。
前回は次のようなサンプルコードを取り上げた(今後説明しやすいようにいくらか変更してある)。
winmain.c
#ifndef UNICODE
#define UNICODE
#endif
#include
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
/*
* ウィンドウプログラムエントリポイント関数
*/
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow)
{
// ウィンドウクラス名
const wchar_t CLASS_NAME[] = L"ウィンドウ作成の学習用プログラムクラス";
// ウィンドウクラス構造体を用意
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = CLASS_NAME;
// ウィンドウクラス構造体を登録
RegisterClass(&wc);
// ウィンドウを作成
HWND hwnd = CreateWindowEx(
0, // ウィンドウスタイル(オプション)
CLASS_NAME, // ウィンドウクラス名
L"ウィンドウプログラミング学習", // ウィンドウタイトル
WS_OVERLAPPEDWINDOW, // ウィンドウスタイル
// サイズとポジション
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL, // 親ウィンドウ
NULL, // メニュー
hInstance, // インスタンスハンドル
NULL // 追加のアプリケーションデータ
);
if (hwnd == NULL)
{
return 0;
}
// ウィンドウを表示
ShowWindow(hwnd, nCmdShow);
// メッセージループを実行
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
/*
* ウィンドウプロシージャ関数
*/
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
FillRect(hdc, &ps.rcPaint, (HBRUSH) (COLOR_WINDOW+1));
EndPaint(hwnd, &ps);
}
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
上記サンプルソースコードはMicrosoftがWindows APIを使ったウィンドウプログラミングのチュートリアルとして提供している次のドキュメントから、本連載でセットアップした開発環境でビルドして使用できるように多少の変更を加えたものだ。
Module 1. Your First Windows Program - Win32 apps | Microsoft Docs
このサンプルソースコードはWindowsにおけるウィンドウプログラミングのエッセンスが詰まっている。
一度にすべてを説明することはできないので、最初に構造を示した上で、最初から順に説明を行っていく。
○ウィンドウプログラミングの主な流れ
Windows APIを使ったウィンドウプログラミングの主な流れは次のようになる。
クラス名を用意
ウィンドウプロシージャを作成(WindowProc())
ウィンドウクラス(WNDCLASS)構造体の変数を作成(先程作成したWindowProc()を登録、クラス名を指定)
ウィンドウクラス(WNDCLASS)構造体の変数を登録(RegisterClass())
ウィンドウを作成(CreateWindowEx()、クラス名を指定)
ウィンドウを表示(ShowWindow())
ウィンドウメッセージループを作成(GetMessage()、TranslateMessage()、DispatchMessage())
最初はもっとざっくりと流れを理解しておいた方がよいかもしれない。
次のような流れだと考えておくとわかりやすいと思う。
ウィンドウクラスを作成
ウィンドウクラスを登録
ウィンドウを作成
ウィンドウを表示
ウィンドウメッセージループを構築
今回はこの「ウィンドウクラス」というものについて説明していく。
○クラス名を用意
ウィンドウクラスを作成していくのだが、ウィンドウプログラミングを行うにあたってまずはそれよりも前に、「クラス名」を定める必要がある。
これは対象となるアプリケーションを特定することになるもので、アプリケーションに対して一意にすることが求められる。
たとえば製品としてアプリケーションを開発する場合には、そのアプリケーションを公開するURLをクラス名にするなど、一意に特定できるようなものにする必要がある。
このサンプルでは次のような文字列をクラス名にしてある。
クラス名を用意
// ウィンドウクラス名
const wchar_t CLASS_NAME[] = L"ウィンドウ作成の学習用プログラムクラス";
クラス名は、このあとに作成するウィンドウクラス構造体において、ウィンドウの作成時においても使用するので、ここでは定数として定義してある。
まずはユニークな名前をつけるものだと思っておいてもらえればと思う。
○ウィンドウクラスを作成
Windows APIによるウィンドウプログラミングでは、まず「ウィンドウクラス」と呼ばれる、複数のウィンドウに共通する動作セットを作成して登録する。
もっとも基盤となる共通の動作を設定しておくようなイメージだ。
これは「ウィンドウクラス」と呼ばれているが、C++といったオブジェクト指向プログラミング言語におけるクラスではなく、WNDCLASSという構造体として用意されている。
この構造体を用意して必要なメンバをはめ込んでいくというのが最初に行うべきことということになる。
サンプルコードでは次の部分がこれに該当している。
ウィンドウクラスの作成部分
// ウィンドウクラス構造体を用意
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = CLASS_NAME;
WNDCLASS構造体のメンバがそれぞれどのような意味を持っているかは次のページに説明が掲載されている。
WNDCLASSW (winuser.h) - Win32 apps | Microsoft Docs
主な内容をまとめると次のようになる。
WNDCLASS構造体のstyleメンバに指定できるスタイルについては次のページに説明がまとまっている。
Window Class Styles (Winuser.h) - Win32 apps | Microsoft Docs
主な内容をまとめると次のようになる。
WNDCLASS構造体のhCursorメンバに指定できるスタイルについては次のページに説明がまとまっている。
LoadCursorA function (winuser.h) - Win32 apps | Microsoft Docs
主な内容をまとめると次のようになる。
WNDCLASS構造体のhbrBackgroundメンバに指定できるスタイルについては次のページに説明がまとまっている。
GetSysColor function (winuser.h) - Win32 apps | Microsoft Docs
主な内容をまとめると次のようになる。
詳しい説明は次回に行うが、こんな感じで基盤となる動作を指定してウィンドウクラスを作成する。
これが先程示した次の部分だ。
短いようでいて結構な情報が書き込まれている。
ウィンドウクラスの作成部分
// ウィンドウクラス構造体を用意
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = CLASS_NAME;
WNDCLASS構造体のメンバをひとつひとつ見ていくだけでも、Windowsにおけるウィンドウプログラミングがどのように整理されているのかを推測することができるようになってくる。
最初にある程度把握しておきたい構造体だ。
○ウィンドウクラスを登録
WNDCLASS構造体のメンバを埋めたら、次のようにRegisterClass()をコールしてWNDCLASS構造体を登録する。
ウィンドウクラスを登録
// ウィンドウクラス構造体を登録
RegisterClass(&wc);
まずはここがスタートラインだ。
このあとにウィンドウの生成と表示、メッセージ処理ループの構築などを行っていくのだが、まずはその基盤としてWNDCLASS構造体を登録する必要があるのだ。
WNDCLASSにはウィンドウプログラミングに必要となるかなり基本的な情報を登録することになる。
ウィンドウプログラミングの中身を知るために大切な構造体なので、この構造体についてちゃんと理解していくことが大切になってくる。
何回かはこの構造体とその動きについて説明を行っていく。
○付録
掲載したサンプルソースコードをnmakeでビルドするためのMakefileのサンプルを掲載しておく。
nmake用のMakefile
CMD= winmain
CC= cl.exe
CFLAGS= /c /source-charset:utf-8
LINK= link.exe
LIBS= user32.lib
LFLAGS=
EXIST= cmd.exe /C if exist
all: build
build: $(CMD).exe
$(CMD).exe: $(CMD).obj
$(LINK) $(LFLAGS) $(LIBS) *.obj
dir
.c.o:
$(CC) $(CFLAGS) $*.c
run: build
$(CMD).exe
clean:
$(EXIST) $(CMD).obj del *.obj
$(EXIST) $(CMD).exe del $(CMD).exe
dir
○参考
Module 1. Your First Windows Program - Win32 apps | Microsoft Docs
WNDCLASSA (winuser.h) - Win32 apps | Microsoft Docs
Window Class Styles (Winuser.h) - Win32 apps | Microsoft Docs
LoadCursorA function (winuser.h) - Win32 apps | Microsoft Docs
GetSysColor function (winuser.h) - Win32 apps | Microsoft Docs
评论