2009-11-29 23:32:11

MinGWでウィンドウ(2)

テーマ:win開発

たまにはMinGWもやらねばということで、


MinGWは「#include <windows.h>」とやるだけで「Win32API」を使えるように作られているので、プログラミングの情報は豊富にあります。


Win32API 入門 」などのキーワードで検索すれば解説ページがたくさんヒットします。



と、、、知った風に書いてしまいましたが実はWin32API等を使ったウィンドウズソフト作成はあまりやったことがないので私自身もっと勉強しないといけません。


ただ、豊富なAPI群が用意されているのでパズルのように組み合わせればそう難しくなさそうなのがウィンドウズプログラムといった感じです。



ウィンドウを伴うプログラムでは、コンパイル時に-mwindowsオプションを付けないと以下のようなリンケージエラーが出ますのでご注意を。

undefined reference to `GetStockObject@4'
collect2: ld returned 1 exit status



■リソースを使ったメニュー作成(menu.rc)


メニューバー作成方法は前回書きましたが、もっと分かり易そうなものをコチラ で見つけましたので今回はこの方法を利用して書きます。



[menu.rcソースコード]
WIN_MENU MENU {
    POPUP "ファイル" {
    MENUITEM "開く" , 40001
    POPUP "サブ" {
            MENUITEM "ブー" , 40002
            MENUITEM "フー" , 40003
            MENUITEM "ウー" , 40004
        }
        MENUITEM SEPARATOR
        MENUITEM "保存" , 40005
        MENUITEM SEPARATOR
        MENUITEM "終了" , 40006

    }
    POPUP "編集" {
        MENUITEM "切り取り" , 40007
        MENUITEM "コピー" , 40008
        MENUITEM "貼り付け" , 40009
    }
    POPUP "表\示" {
        MENUITEM "ツールバー" , 40010
        MENUITEM SEPARATOR
        MENUITEM "ソース" , 40011
    }
    POPUP "ヘルプ" {
        MENUITEM "ヘルプ" , 40012
        MENUITEM SEPARATOR
        MENUITEM "バージョン情報" , 40013
    }
}



上記リソースの「WIN_MENU」という部分を、次に挙げるwin.cソースコードのLoadMenu()関数の第2引数と合わせることで取り込まれるようになります。


各メニューに一意な数値を割り当てることでどのメニューが選択されたかの判別に使います。(ホントはヘッダファイルを別に用意して意味のわかる定数でマクロ置換させたほうがよい)


■メイン処理(win.c)


VisualC++で動作確認されたコチラ のWin32API解説ページを参考にちょっとだけメニュー部分を改変して書いてみました。



[win.cソースコード]
#include <windows.h>
#include <tchar.h>

// 定数
#define WINDOW_WIDTH (400) // ウィンドウの幅
#define WINDOW_HEIGHT (300) // ウィンドウの高さ
#define WINDOW_X ((GetSystemMetrics( SM_CXSCREEN ) - WINDOW_WIDTH ) / 2)
#define WINDOW_Y ((GetSystemMetrics( SM_CYSCREEN ) - WINDOW_HEIGHT ) / 2)


// プロトタイプ宣言
HWND Create(HINSTANCE hInst);
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp);



// 開始位置
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, int showCmd)
{
    HWND hWnd;
    MSG msg;


    // ウィンドウを作成する
    hWnd = Create( hInst );
    if( hWnd == NULL )
    {
        MessageBox( NULL, _T("ウィンドウの作成に失敗しました"), _T("エラー"), MB_OK );
        return 1;
    }


    // ウィンドウを表示する
    ShowWindow( hWnd, SW_SHOW );
    UpdateWindow( hWnd );


    // メッセージループ
    while( 1 )
    {
        BOOL ret = GetMessage( &msg, NULL, 0, 0 ); // メッセージを取得する
        if( ret == 0 || ret == -1 )
        {
            // アプリケーションを終了させるメッセージが来ていたら、
            // あるいは GetMessage() が失敗したら( -1 が返されたら )、ループを抜ける
            break;
        }
        else
        {
            // メッセージを処理する
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
    }


    return 0;
}


// ウィンドウを作成する
HWND Create(HINSTANCE hInst)
{
    WNDCLASSEX wc;


    // ウィンドウクラスの情報を設定
    wc.cbSize = sizeof(wc); // 構造体サイズ
    wc.style = CS_HREDRAW | CS_VREDRAW; // スタイル
    wc.lpfnWndProc = WndProc; // ウィンドウプロシージャ
    wc.cbClsExtra = 0; // 拡張情報1
    wc.cbWndExtra = 0; // 拡張情報2
    wc.hInstance = hInst; // インスタンスハンドル
    wc.hIcon = (HICON)LoadImage( // アイコン
        NULL, MAKEINTRESOURCE(IDI_APPLICATION), IMAGE_ICON,
        0, 0, LR_DEFAULTSIZE | LR_SHARED
    );
    wc.hIconSm = wc.hIcon; // 子アイコン
    wc.hCursor = (HCURSOR)LoadImage( // マウスカーソル
        NULL, MAKEINTRESOURCE(IDC_ARROW), IMAGE_CURSOR,
        0, 0, LR_DEFAULTSIZE | LR_SHARED
    );
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // ウィンドウ背景
    wc.lpszMenuName = NULL; // メニュー名
    wc.lpszClassName = _T("Default Class Name");// ウィンドウクラス名

    // ウィンドウクラスを登録する
    if( RegisterClassEx( &wc ) == 0 ){ return NULL; }


    // ウィンドウを作成する
    return CreateWindow(
        wc.lpszClassName, // ウィンドウクラス名
        _T("Sample Program"), // タイトルバーに表示する文字列
        WS_OVERLAPPEDWINDOW, // ウィンドウの種類
        WINDOW_X, // ウィンドウを表示する位置(X座標)
        WINDOW_Y, // ウィンドウを表示する位置(Y座標)
        WINDOW_WIDTH, // ウィンドウの幅
        WINDOW_HEIGHT, // ウィンドウの高さ
        NULL, // 親ウィンドウのウィンドウハンドル
        NULL, // メニューハンドル
        hInst, // インスタンスハンドル
        NULL // その他の作成データ
    );
}


// ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
    static HMENU hMenu;
    int wmId;


    switch( msg )
    {
    case WM_CREATE: // ウィンドウが作られたとき
        // メニューリソースをロードする
        hMenu = LoadMenu( NULL, _T("WIN_MENU") );
        // ウィンドウにメニューリソースを割り当てる
        SetMenu( hWnd, hMenu );


        return 0;


    case WM_COMMAND:
        wmId= LOWORD(wp);
        switch (wmId){
        case 40006: DestroyWindow(hWnd);
            break;
        default: ;
        }
        break;


    case WM_CLOSE: // ウィンドウが閉じられるとき
        // ウィンドウからメニューバーを削除
        SetMenu( hWnd, NULL );
        // メニューバーリソースを破棄する
        DestroyMenu( hMenu );
        hMenu = NULL;


        break; // ウィンドウを閉じる処理はDefWindowProc()に任せる


    case WM_DESTROY: // ウィンドウが破棄されるとき
        PostQuitMessage( 0 );
        return 0;
    }


    return DefWindowProc( hWnd, msg, wp, lp );
}




■Makefile作成


Makefileを使わずに、先にリソースをオブジェクトファイルに(リソースコンパイラとCのコンパイラは別なので)して、
% windres menu.rc menu.o


最終的にCのソースをオブジェクトファイルにしたものと先のオブジェクトファイルをリンクさせて実行ファイルを作り出すということを手打ちですることもできます。
% gcc win.c menu.o -mwindows -o win.exe


が、もっと大規模になることを見据えてMakefileを作って
% make
で済ませるようにしておくことは意義があります。



[Makefileソースコード]
SRC=win.c
OBJS=$(SRC:.c=.o)
RC=menu.rc
WINDRES=$(RC:.rc=.o)
PROG=win.exe
CC=gcc
CFLAGS=-Wall -O3
LDFLAGS=-mwindows
RM=del

%.o: %.c
    $(CC) $(CFLAGS) -o $@ -c $<



.PHONY : all
all: $(PROG)


$(PROG): $(OBJS) $(WINDRES)
    $(CC) $(OBJS) $(WINDRES) $(LDFLAGS) -o $@


$(WINDRES): $(RC)
    windres $(RC) $(WINDRES)



.PHONY : clean
clean:
    $(RM) $(OBJS) $(WINDRES)




■コンパイル作業


DOS窓を起動させて、「make」または「make all」と打ち込みコンパイル実行させます。


C:\Users\Administrator\Desktop\cwin>make
gcc -Wall -O3 -o win.o -c win.c
gcc win.o menu.o -mwindows -o win.exe


C:\Users\Administrator\Desktop\cwin>


この結果出来上がったwin.exeを実行させてみます。


■ウィンドウ画像


そろそろホンキ出す-mingw


今回は前回と比べて扱うファイル数も少なく済んでスッキリした感じになりました。



AD
いいね!した人  |  コメント(0)  |  リブログ(0)

そろそろホンキ出すさんの読者になろう

ブログの更新情報が受け取れて、アクセスが簡単になります

最近の画像つき記事
 もっと見る >>

コメント

[コメントをする]

コメント投稿

AD

ブログをはじめる

たくさんの芸能人・有名人が
書いているAmebaブログを
無料で簡単にはじめることができます。

公式トップブロガーへ応募

多くの方にご紹介したいブログを
執筆する方を「公式トップブロガー」
として認定しております。

芸能人・有名人ブログを開設

Amebaブログでは、芸能人・有名人ブログを
ご希望される著名人の方/事務所様を
随時募集しております。