Windows 10で始めるC言語開発 第27回 WindowsでC言語開発! ウィンドウクラス

調理器具 2022-03-26 85459 0

Windows 10で始めるC言語開発 第27回 WindowsでC言語開発! ウィンドウクラス

    Windows 10で始めるC言語開発 第27回 WindowsでC言語開発! ウィンドウクラス○はじめてのウィンドウプログラミングWindows APIを使ってシンプルなウィンドウを作成するサンプルコードを取り上げた。ダイアログを作成する場合と比べるとだいぶソースコードが増えたが、前回取り上げたサンプル

Windows 10で始めるC言語開発 第27回 WindowsでC言語開発! ウィンドウクラス

    

○はじめてのウィンドウプログラミング

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);

}

winmain.cの実行サンプル

上記サンプルソースコードは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

评论

精彩评论