Windowsアプリの基礎

前回、プロジェクトで簡単なウインドウを作ってみました。
今回は、何でウインドウが作られて、ボタンを押すとそれに対応した動作をするのか、簡単に解説します。
筆者の文章は破綻しているので、よく分からない説明になることが予測されます。
読み飛ばしてもかまいません。

Windowsアプリ(ウインドウが表示されるものですよ)は大体、以下のような構成になっています。
1,ウインドウクラスを設定する。
2,ウインドウを作る。
3,メッセージループに入る。
4,メッセージをコールバック関数に渡す。
5,メッセージに対応した処理を行う。
言葉はあまり正確ではありませんが、こんな感じです。
ABでは1,ウインドウクラスの設定と、2,ウインドウを作るはMakeWindow.wbpに書かれます。
3,メッセージループはプロジェクト名.abp(プロジェクト名により名前が変わります)に、
4,コールバック関数はCallback.wbpに、
5のメッセージに対応した処理はMainWnd.sbpなど、ウインドウ名.sbpに書かれます。ウインドウが増えたり、名前を変えるとそれに応じて作られます。

実際はどうなのよ

実際にプログラムを見てみましょう。細かく調べることはしません。
気になって夜も眠れないという人はヘルプにそれぞれの関数の説明があります。
プログラムは、人によって異なると思います。細かい差異は無視して、大筋を捉えてください。
MakeWindow.wbpです。
Dim _RadSys_wcl As WNDCLASSEX
FillMemory(VarPtr(_RadSys_wcl),Len(_RadSys_wcl),0)
_RadSys_wcl.cbSize=Len(_RadSys_wcl)
_RadSys_wcl.hInstance=GetModuleHandle(0)
_RadSys_wcl.style=CS_HREDRAW or CS_VREDRAW or CS_DBLCLKS
_RadSys_wcl.hCursor=LoadCursor(NULL,IDC_ARROW)

_RadSys_wcl.hIcon=LoadIcon(_RadSys_wcl.hInstance,IDI_ICON1)
_RadSys_wcl.hIconSm=LoadIcon(_RadSys_wcl.hInstance,IDI_ICON1)
_RadSys_wcl.lpszClassName="NORMAL0"
_RadSys_wcl.lpfnWndProc=AddressOf(MainWndProc)
_RadSys_wcl.hbrBackground=h3DFaceBrush
RegisterClassEx(_RadSys_wcl)

'↓は長いので折っています。本来は1行です。
CreateWindowEx(&H00000000,"NORMAL0","test", _
&H10cf0000,-2147483648,-2147483648,493,312,0,0, _
GetModuleHandle(0),0)
Dim _RadSys_wcl As WNDCLASSEXでウインドウクラスを設定する_RadSysを宣言します。
FillMemoryで構造体メンバを0に初期化しています。
そこからしばらく_RadSysにデータをいれます。
RegisterClassExで作ったウインドウクラスを登録します。このウインドウクラスを有効にします。
CreateWindowExが実際にウインドウを作る関数です。長いですねえ。

次にメッセージループです。
プロジェクト名.abpです。
#include "test.idx"

' ---------------------------
'  ウィンドウ メッセージ処理
' ---------------------------
Dim msgMain As MSG, iResult As Long
Do
    iResult=GetMessage(msgMain,0,0,0)
    If iResult=0 or iResult=-1 Then Exit Do
    TranslateMessage(msgMain)
    DispatchMessage(msgMain)
Loop
ExitProcess(0)
#include"test.idx"はプロジェクトによって異なります。.idxのファイルを開くと分かりますが、全てのプログラムをつなげるだけのファイルです。
Dim msgMain As MSGは、MSG構造体の宣言です。この構造体にメッセージを格納します。
メッセージは、ウインドウが動かされた(WM_MOVE)、ボタンを押した(BM_CLICK)などのイベントがOSから送られてきます。
これを実際に取得するのがGetMessage関数です。
もしこの関数の戻り値が0(メッセージがWM_QUIT=終了),-1(関数が失敗)の時はExitProcess関数で終了させ、
それ以外のメッセージの時はTranslateMessage関数で、キーボードからの入力を使いやすく変換し、
DispatchMessage関数で、コールバック関数にメッセージを渡します。
簡単に言うと、WM_QUIT以外のメッセージをコールバック関数に渡すだけです。

次に最大のとりで、コールバック関数です。
Callback.wbpを見ると、大変なことになっています。
重要なのはEventCall_MainWnd関数のところです。これが実際のコールバック関数です。
長い関数があり、折ったところがあります。
Function EventCall_MainWnd( _
    hWnd As HWND, message As DWord, wParam As WPARAM, lParam As LPARAM) _
        As LRESULT
    Select Case message
        Case WM_DESTROY
            MainWnd_Destroy()
        Case WM_CREATE
            hMainWnd=hWnd
            CreateWindowEx(&H00000000,"BUTTON","Button1", _
                &H50000000,51,42,222,115,hWnd,CommandButton1 As HMENU, _
                GetModuleHandle(0),0)
            SendMessage(GetDlgItem(hWnd,CommandButton1),WM_SETFONT, _
                hFont_MainWnd As WPARAM,0)
        Case WM_CLOSE
            Dim cancel=0 As Integer
            If cancel=0 Then DestroyWindow(hWnd)
        Case WM_COMMAND
            Select Case LOWORD(wParam)
                Case CommandButton1
                    Select Case HIWORD(wParam)
                        Case BN_CLICKED
                            MainWnd_CommandButton1_Click()
                    End Select
            End Select
        Case Else
            EventCall_MainWnd=DefWindowProc(hWnd,message,wParam,lParam)
            Exit Function
    End Select
    EventCall_MainWnd=0
End Function
Select Case messageでメッセージを分岐させています。
あとは、見ればなんとなく分かると思います。
WM_CREATEはウインドウが作られたときの処理で、WM_CLOSEはウインドウが閉じたときかな?くらいで良いです。
それから、WM_CREATEのところのCreateWindowEx関数ですが、これはボタンを作っています。ボタンなどはウインドウの子ウインドウになります。
コールバック関数を書き換えたら、様々なメッセージに対応した処理を行うことができます。

まとめ

ABは自動的にこんなプログラムを作ってくれます。
普段は意識しなくて良いのでABでは簡単にプログラミングが可能です。
今回覚えていただきたいのは、メッセージです。
メッセージをコールバック関数で処理されることを知っておいてください。
そして、実際にはコールバック関数の処理を書いていることを理解してください。