1.ダイアログボックス(モードレス)

 リソースにダイアログボックスを挿入し、テキストボックス(IDC_EDIT1)とボタン(IDC_BUTTON1)を追加する。
 ダイアログボックスを追加したリソースファイル(.rc)と、以下のようなソースファイル(.cpp)を作成後、2つともプロジェクトに追加してビルドする。
 ダイアログプロシージャの戻り値は、WM_INITDIALOGメッセージでSetFocus関数を使用してコントロールの1つにフォーカスをセットしたときはFALSEを、しなかったらTRUEを返す。それ以外のメッセージの場合は処理をしたらTRUEを、しなかったらFALSEを返すようにする。

 プログラムを終了させたいときは、DestroyWindow(hDlg); ではなく、
SendMessage(hDlg,WM_CLOSE,0,0); を使用する。
 DestroyWindow(hDlg); では終了処理が行われない。
 DestroyWindow(hDlg); を実行すると ダイアログの中のコントロールハンドルも破棄されるので、先にコントロールハンドルを破棄しないようにする。
 先に破棄すると、オーバーフローする恐れあり。
 SendMessage(hDlg,WM_CLOSE,0,0); は、自作関数内ではなく、DlgProc関数内で使用する。
 自作関数では、成否の戻り値を返すようにする。
 DirectX や ATL などの COM の終了処理は、メインウィンドウを閉じてメッセージループを抜けた後で行う。
 MSDN の CoUninitialize() を参照。

 モーダル ダイアログボックスは排他制御のダイアログボックスで、CreateDialog マクロの代わりに DialogBox マクロ で作成する。
 モーダルダイアログボックスのWM_CLOSEメッセージをインプリメントしない場合は、IDCANCEL が呼び出される。
 そのため、[×]ボタンがモーダルダイアログボックスの右上にあり、メモリの解放等の処理が必要な場合は、どちらか一方を必ずインプリメントする。

MSDEV の操作手順
  1. [ファイル] メニューの [新規作成] をクリックし、[プロジェクト] タブをクリックします。
  2. [プロジェクト] タブの [Win32 Application] をクリックし、プロジェクトに名前を付けます。
  3. [プロジェクト] メニューの [プロジェクトへ追加] をクリックし、[ファイル] をクリックして、C ソース コードが記述されたファイルとリソースファイルをプロジェクトに追加します。
  4. [ビルド] メニューの [ビルド] をクリックしてプロジェクトをビルドします。
#include < windows.h >
#include "resource.h"

int CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_INITDIALOG:
        // ダイアログボックス内コントロールの初期化など
        break;
    case WM_COMMAND:
        switch( LOWORD(wParam) )
        {
        case IDC_BUTTON1:
            switch( HIWORD(wParam) )
            {
            case BN_CLICKED:// ボタンが押されたとき
                char ss[256];
                SendDlgItemMessage(hDlg, IDC_EDIT1, WM_GETTEXT, 256, (LPARAM) ss);
                MessageBox(hDlg, ss, "以下の文字列を取得しました", MB_OK);
                break;
            }
            break;
        case IDOK:
            // OKボタンが押された時
            SendMessage(hDlg, WM_CLOSE, 0, 0);
            break;
        case IDCANCEL:
            // キャンセルボタンが押された時
            SendMessage(hDlg, WM_CLOSE, 0, 0);
            break;
        default:
            return FALSE;
        }
        break;
    case WM_CLOSE:
        // 終了処理
        DestroyWindow(hDlg); // ダイアログの破棄
        PostQuitMessage(0);  // メッセージ ループを抜ける
        break;
    default:
        return FALSE;
    }
    return TRUE;
}

int APIENTRY WinMain(HINSTANCE hInst,HINSTANCE hInstPrev,LPSTR lpCmdLine,int nCmdShow)
{
    MSG msg;
    HWND hDlg;

    hDlg = CreateDialog(hInst, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc);
    ShowWindow(hDlg, nCmdShow);

    while(GetMessage(&msg, NULL, 0, 0)) {
        if (IsDialogMessage(hDlg, &msg)) continue;
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    // ここに COM の終了処理を記述
    return msg.wParam;
}

2.ウィンドウ

 以下のようなウィンドウプログラムの雛型を書いてCPPファイルとして保存する。

 ウィンドウプログラムは、他のウィンドウが上に重なったりするとクライアント領域の描画が消えるので再描画コードを書く。
 ただし、他のコントロールが誤動作する要因になるため、BeginPaint や EndPaint には、子ウィンドウやピクチャーコントロールのハンドルを渡さないようにする。  ピクチャーコントロールの再描画処理は、サブクラス化などで行うこと。

 プロジェクトに追加後、[ビルド]すると実行ファイルが生成される。

 @でウィンドウを作成し、Aでマウス操作などのメッセージを受け取りBの関数で受け取ったメッセージを処理する。

 以下のサンプルは、プロシージャで自分が処理したメッセージにはデフォルトの処理をさせない場合。
 自分が処理したメッセージにもデフォルトの処理をさせたい場合は、return 0; を break; に置き換える。

 ダブルクリックのメッセージを受け取りたいときは、クラスの style で CS_DBLCLKS を追加する。

 プログラムを終了させたいときは、DestroyWindow(hWnd); ではなく、
SendMessage(hWnd,WM_CLOSE,0,0); を使用する。
 DestroyWindow(hWnd); では終了処理が行われない。
 DestroyWindow(hWnd); を実行すると 子ウィンドウやコントロールのハンドルも破棄されるので、先に子ウィンドウやコントロールのハンドルを破棄しないようにする。
 先に破棄すると、オーバーフローする恐れあり。
 SendMessage(hWnd,WM_CLOSE,0,0); は、自作関数内ではなく、WinProc関数内で使用する。
 自作関数では、成否の戻り値を返すようにする。
 DirectX や ATL などの COM の終了処理は、メインウィンドウを閉じてメッセージループを抜けた後で行う。
 MSDN の CoUninitialize() を参照。

MSDEV の操作手順
  1. [ファイル] メニューの [新規作成] をクリックし、[プロジェクト] タブをクリックします。
  2. [プロジェクト] タブの [Win32 Application] をクリックし、プロジェクトに名前を付けます。
  3. [プロジェクト] メニューの [プロジェクトへ追加] をクリックし、[ファイル] をクリックして、C ソース コードが記述されたファイルをプロジェクトに追加します。
  4. [ビルド] メニューの [ビルド] をクリックしてプロジェクトをビルドします。
#include < windows.h >

#define MYWNDCLASS  "MYWNDCLASS"
#define MYWNDTITLE  "MYWNDTITLE"

// 関数のプロトタイプ宣言
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hInstPrev,LPSTR lpCmdLine,int nCmdShow)
{
    MSG        msg;
    WNDCLASSEX wc;
    HWND       hWnd;


    ZeroMemory(&wc, sizeof(wc));
    wc.cbSize           = sizeof(WNDCLASSEX); 
    wc.lpfnWndProc      = (WNDPROC)WndProc;
    wc.hInstance        = hInst;
    wc.hIcon            = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor          = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground    = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName     = NULL;
    wc.lpszClassName    = MYWNDCLASS;
    wc.style            = 0;
    RegisterClassEx(&wc);

    // @ ウィンドウの作成と表示
    hWnd = CreateWindowEx(0, 
                MYWNDCLASS,
                MYWNDTITLE,
                WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
                NULL,
                NULL,
                hInst,
                NULL);
    
    // A メッセージループ
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    // ここに COM の終了処理を記述
    return msg.wParam;
}

// B プロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_CREATE:
        // 初期化処理
        return 0;
    case WM_PAINT:
        HDC         hDC;
        PAINTSTRUCT ps;

        hDC = BeginPaint(hWnd,&ps);
        // ここに再描画用のコードを記述
        EndPaint(hWnd,&ps);
        return 0;
    case WM_CLOSE:
        // 終了処理
        DestroyWindow(hWnd); // ウィンドウの破棄
        PostQuitMessage(0);  // メッセージ ループを抜ける
        return 0;
    default:
        break;
    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

3.メニューバー

リソースに以下のようなメニューを作成して保存し、プロジェクトに追加する。
ソースコードも追記してビルドする。
ID:IDR_MENU1
キャプション:ファイル(&F)
ID:IDM_CLOSEキャプション:閉じる(&C)
// ヘッダーファイルの読み込み
#include "resource.h"

WinMain関数内
    hWnd = CreateWindowEx(0, 
                MYWNDCLASS,
                MYWNDTITLE,
                WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                CW_USEDEFAULT, CW_USEDEFAULT, 256, 256,
                NULL,
                LoadMenu(hInst,MAKEINTRESOURCE(IDR_MENU1)),
                hInst,
                NULL);



LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg) {
    case WM_PAINT:
        HDC         hDC;
        PAINTSTRUCT ps;

        hDC = BeginPaint(hWnd,&ps);
        EndPaint(hWnd,&ps);
        return 0;
    case WM_COMMAND:
        switch( LOWORD(wParam) )
        {
        case IDM_CLOSE:// 終了
            SendMessage(hWnd,WM_CLOSE,0,0);
            return 0;
        }
        break;
    case WM_CLOSE:
        DestroyWindow(hWnd);
        PostQuitMessage(0);
        return 0;
    default:
        break;
    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

4.ショートカットキー

リソースに[Ctrl]+[C]などのアクセラレータを追加し、そのリソースファイルをプロジェクトに追加する。
WimMain関数内

    HACCEL hAC = LoadAccelerators( hInst, MAKEINTRESOURCE(IDR_ACCELERATOR1) );
    
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        if(TranslateAccelerator( hWnd, hAC, &msg )){
            continue;
        }
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;

5.スクロールバー

テキストファイルの中身をウィンドウに出力する。

スクロールバーを非表示にする場合
ShowScrollBar( hWnd, SB_BOTH, FALSE );
SB_BOTH
SB_CTL
SB_HORZ
SB_VERT
#include < windows.h >
#include < stdio.h >

#define MYWNDCLASS  "MYWNDCLASS"
#define MYWNDTITLE  "MYWNDTITLE"    // タイトル

// 外部変数
char    str1[1024][256];        // ファイルから読み込んだテキスト
int     str1_num = 0;           // テキストの行数
int     x_max = 0;              // テキストの横幅の最大値

// 関数のプロトタイプ宣言
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void Open_File(HWND hWnd);

int APIENTRY WinMain(HINSTANCE hInst,HINSTANCE hInstPrev,LPSTR lpCmdLine,int nCmdShow)
{
    MSG        msg;
    WNDCLASSEX wc;
    HWND       hWnd;

    ZeroMemory(&wc, sizeof(wc));
    wc.cbSize           = sizeof(WNDCLASSEX); 
    wc.lpfnWndProc      = (WNDPROC)WndProc;
    wc.hInstance        = hInst;
    wc.hIcon            = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor          = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground    = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName     = NULL;
    wc.lpszClassName    = MYWNDCLASS;
    RegisterClassEx(&wc);

    hWnd = CreateWindowEx(WS_EX_CLIENTEDGE,   // 枠の形状を変える
                MYWNDCLASS,
                MYWNDTITLE,
                WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                CW_USEDEFAULT, CW_USEDEFAULT, 256, 256,
                NULL,
                NULL,
                hInst,
                NULL);
   
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static SCROLLINFO   si_h,si_v;              // スクロールバーの情報
    static int          scr_x = 0,  scr_y = 0;  // 現在のスクロールバーの位置
    static int          scr_x0 = 0, scr_y0 = 0; // 以前のスクロールバーの位置
    
    switch (uMsg) {
    case WM_CREATE:                 // 初期化など
        ZeroMemory(&si_v,sizeof(si_v));
        si_v.cbSize = sizeof(si_v);
        si_v.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
        SetScrollInfo(hWnd,SB_VERT,&si_v,TRUE);

        ZeroMemory(&si_h,sizeof(si_h));
        si_h.cbSize = sizeof(si_h);
        si_h.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
        SetScrollInfo(hWnd,SB_HORZ,&si_h,TRUE);

        Open_File(hWnd);                        // テキストファイルを読み込む
        si_h.nMax = x_max;                      // 横スクロールバーの最大値を設定
        SetScrollInfo(hWnd,SB_HORZ,&si_h,TRUE); //
        si_v.nMax = str1_num * 20;              // 縦スクロールバーの最大値を設定
        SetScrollInfo(hWnd,SB_VERT,&si_v,TRUE); //
        break;

    case WM_SIZE:                   // ウィンドウサイズが変更された時
        si_h.nPage = LOWORD(lParam);
        if((unsigned)si_h.nMax <= si_h.nPage)     si_h.nPos = 0;
        scr_x = SetScrollInfo(hWnd,SB_HORZ,&si_h,TRUE);
        si_v.nPage = HIWORD(lParam);
        if((unsigned)si_v.nMax <= si_v.nPage)     si_v.nPos = 0;
        scr_y = SetScrollInfo(hWnd,SB_VERT,&si_v,TRUE);
        ScrollWindowEx(hWnd,scr_x0 - scr_x,scr_y0 - scr_y,0,0,0,0,
                        SW_INVALIDATE | SW_ERASE);
        scr_x0 = scr_x;
        scr_y0 = scr_y;
        break;

    case WM_HSCROLL:                // 横スクロールバーが動いた時
        switch(LOWORD(wParam))
        {
        case SB_LINELEFT:
            if (si_h.nPos) si_h.nPos--;
            break;
        case SB_LINERIGHT:
            if (si_h.nPos < si_h.nMax - 1) si_h.nPos++;
            break;
        case SB_PAGELEFT:
            si_h.nPos -= si_h.nPage;
            break;
        case SB_PAGERIGHT:
            si_h.nPos += si_h.nPage;
            break;
        case SB_THUMBTRACK:
            si_h.nPos = HIWORD(wParam);
            break;
        }
        scr_x = SetScrollInfo(hWnd,SB_HORZ,&si_h,TRUE);
        if(scr_x != scr_x0){
            ScrollWindowEx(hWnd,scr_x0 - scr_x,0,0,0,0,0,
                SW_INVALIDATE | SW_ERASE);  // 画像ビューワの場合は SW_INVALIDATE のみ
            scr_x0 = scr_x;
        }
        break;

    case WM_VSCROLL:                // 縦スクロールバーが動いた時
        switch(LOWORD(wParam))
        {
        case SB_LINEUP:
            if (si_v.nPos) si_v.nPos--;
            break;
        case SB_LINEDOWN:
            if (si_v.nPos < si_v.nMax - 1) si_v.nPos++;
            break;
        case SB_PAGEUP:
            si_v.nPos -= si_v.nPage;
            break;
        case SB_PAGEDOWN:
            si_v.nPos += si_v.nPage;
            break;
        case SB_THUMBTRACK:
            si_v.nPos = HIWORD(wParam);
            break;
        }
        scr_y = SetScrollInfo(hWnd,SB_VERT,&si_v,TRUE);
        if(scr_y != scr_y0){
            ScrollWindowEx(hWnd,0,scr_y0 - scr_y,0,0,0,0,
                SW_INVALIDATE | SW_ERASE);  // 画像ビューワの場合は SW_INVALIDATE のみ
            scr_y0 = scr_y;
        }
        break;

    case WM_PAINT:
        PAINTSTRUCT ps;
        HDC         hDC;
        int         i;
        hDC = BeginPaint(hWnd,&ps);
        if(str1_num != 0){
            for(i=0;i< str1_num;i++){
                // クライアント領域にテキストを出力
                TextOut(hDC, 0 - scr_x, i * 20 - scr_y, str1[i], strlen(str1[i]));
            }
        }
        EndPaint(hWnd,&ps);
        break;

    case WM_CLOSE:
        DestroyWindow(hWnd);
        PostQuitMessage(0);
        break;

    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return 0;
}

// ファイルを開いて文字列を読み込む
void Open_File(HWND hWnd)
{
    FILE    *file_r;
    HDC     hDC;
    int     i = 0;
    SIZE    size;

    if((file_r=fopen("a.txt","r")) == NULL){
        exit(1);
    }

    hDC = GetDC(hWnd);
    str1_num = 0;

    while(!feof(file_r)){
        fgets(str1[str1_num],256,file_r);

        for(i=0;i<256;i++)
            if(str1[str1_num][i] == '\n')
                str1[str1_num][i] = '\0';

        // 各文字列の長さを測る
        GetTextExtentPoint32(hDC, str1[str1_num], strlen(str1[str1_num]), &size);
        // 各文字列の長さの最大値を求める
        if(size.cx > x_max)
            x_max = size.cx;

        str1_num ++;
    }

    fclose(file_r);
}

6.ツールバーボタンの編集

comctl32.lib のリンク設定が必要。
(あるいは、#pragma comment(lib, "comctl32.lib") をソースに追加)
シフトキーを押しながら、ツールボタンをドラッグで並び替え。
ツールバーをダブルクリックで[ツールバーの変更]ダイアログ表示
#include <windows.h>
#include <commctrl.h>
#include "resource.h"

#define MYWNDTITLE      "ツールバー(ボタン並び替え)"
#define MYWNDCLASS      "MYWNDCLASS"
#define TB_NUM          5      // ボタンの数
#define ID_TOOL         1501

// ボタンの絵
int     TB_Bmp[TB_NUM] = {STD_FILENEW,STD_FILEOPEN,STD_FILESAVE,-1,STD_PRINT};
// ボタンのコマンドID
int     TB_Command[TB_NUM] = {IDM_NEW,IDM_OPEN,IDM_SAVE,-1,IDM_PRINT};
// ボタンのテキスト
char    TB_Text[TB_NUM][16] = {"新規作成","開く","上書き保存","区切り","印刷"};

HWND      g_hTool  = NULL;  // ツールバーのハンドル

TBBUTTON    tbb[TB_NUM];

LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
void Set_ToolBar(HWND hWnd);

int APIENTRY WinMain(HINSTANCE hInst,HINSTANCE hInstPrev,LPSTR lpCmdLine,int nCmdShow)
{
    MSG        msg;
    WNDCLASSEX wc;
    HWND       hWnd;
    
    // 親ウィンドウ
    ZeroMemory(&wc, sizeof(wc));
    wc.cbSize           = sizeof(WNDCLASSEX);
    wc.lpfnWndProc      = (WNDPROC)WndProc;
    wc.hInstance        = hInst;
    wc.hIcon            = LoadIcon(hInst, IDI_APPLICATION);
    wc.hCursor          = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
    wc.hbrBackground    = (HBRUSH)(COLOR_BTNFACE+1);
    wc.lpszMenuName     = NULL;
    wc.lpszClassName    = MYWNDCLASS;
    RegisterClassEx(&wc);
    
    hWnd = CreateWindowEx(0,
                MYWNDCLASS,
                MYWNDTITLE,
                WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_VISIBLE,
                CW_USEDEFAULT, CW_USEDEFAULT, 300, 300,
                NULL,
                LoadMenu(hInst,MAKEINTRESOURCE(IDR_MENU1)),
                hInst,
                NULL);

    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}// WinMain

// 親ウィンドウ プロシージャ
LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_CREATE:
        InitCommonControls();   // コモンコントロール初期化
        Set_ToolBar(hWnd);      // ツールバーの作成
        break;
    case WM_SIZE:
        SendMessage(g_hTool, TB_AUTOSIZE, 0, 0);
        break;

    case WM_NOTIFY:
        NMHDR *phdr;
        phdr = (NMHDR *)lParam;
        switch (phdr->code)
        {
        case TTN_NEEDTEXT:      // ツールヒント
            LPTOOLTIPTEXT lpttText;
            lpttText = (LPTOOLTIPTEXT)lParam;
            int i;
            for(i=0;i<sizeof(TB_Command)/sizeof(int);i++){
                if((int)lpttText->hdr.idFrom == TB_Command[i]){
                    lpttText->lpszText = TB_Text[i];
                    break;
                }
            }
            break;
        case TBN_QUERYINSERT:   // ボタン追加許可
            return 1; // allow insert
        case TBN_QUERYDELETE:   // ボタン削除許可
            return 1; // allow delete
        case TBN_GETBUTTONINFO: // ダイアログに全てのボタンのデータを設定
            {
                LPTBNOTIFY ptbn = (LPTBNOTIFY) lParam;
                if (ptbn->iItem < TB_NUM){
                    ptbn->tbButton = tbb[ptbn->iItem];
                    ptbn->cchText = sizeof(TB_Text[ptbn->iItem]);
                    strcpy(ptbn->pszText, TB_Text[ptbn->iItem]);
                    return 1;
                }
            }
            return 0;
/*      case TBN_TOOLBARCHANGE: // ツールバーボタンが追加、削除、並び替えられたとき
            break;
        case TBN_BEGINADJUST:   // ダイアログ開始
            break;
        case TBN_RESET:         // ダイアログのリセットボタンが押されたとき
            break;
        case TBN_CUSTHELP:      // ダイアログのヘルプボタンが押されたとき
            break;
        case TBN_ENDADJUST:     // ダイアログ終了
            break;
*/      }
        break;

    case WM_COMMAND:
        switch( LOWORD(wParam) )
        {
        case IDM_NEW:
            MessageBox(hWnd,TB_Text[0],MYWNDTITLE,MB_OK);
            break;
        case IDM_OPEN:
            MessageBox(hWnd,TB_Text[1],MYWNDTITLE,MB_OK);
            break;
        case IDM_SAVE:
            MessageBox(hWnd,TB_Text[2],MYWNDTITLE,MB_OK);
            break;
        case IDM_PRINT:
            MessageBox(hWnd,TB_Text[4],MYWNDTITLE,MB_OK);
            break;
        case IDM_CHANGE:    // ツールバーの変更
            SendMessage(g_hTool,TB_CUSTOMIZE,0,0);
            break;
        case IDM_EXIT:      // 終了
            SendMessage(hWnd,WM_CLOSE,0,0);
            break;
        }
        break;

    case WM_CLOSE:
        DestroyWindow(hWnd);
        PostQuitMessage(0);
        break;

    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return 0;
}// WndProc

// ツールバーの作成
void Set_ToolBar(HWND hWnd)
{
    ZeroMemory(tbb,sizeof(TBBUTTON) * TB_NUM);

    for(int i=0;i<TB_NUM;i++){
        if(TB_Bmp[i] == -1){
            tbb[i].fsStyle = TBSTYLE_SEP;       // セパレータの表示
        }
        else{
            tbb[i].fsStyle = TBSTYLE_AUTOSIZE;  // ボタンの設定 (サイズを自動設定)
            tbb[i].fsState = TBSTATE_ENABLED;   // ボタンの状態(使用可能)
            tbb[i].iString = -1;                // ボタンのテキスト (なし)
            tbb[i].iBitmap = TB_Bmp[i];         // ボタンの絵
            tbb[i].idCommand = TB_Command[i];   // ボタンの命令
        }
    }
    
    g_hTool = CreateToolbarEx( hWnd, WS_CHILD | WS_VISIBLE | 
                                TBSTYLE_TOOLTIPS | TBSTYLE_FLAT | 
                                TBSTYLE_WRAPABLE | CCS_ADJUSTABLE,
                                ID_TOOL, TB_NUM, HINST_COMMCTRL,
                                IDB_STD_SMALL_COLOR, tbb, TB_NUM,
                                0, 0, 0, 0, sizeof(TBBUTTON));
}// Set_ToolBar

7.ツリービュー

comctl32.lib のリンク設定が必要。
(あるいは、#pragma comment(lib, "comctl32.lib") をソースに追加)
以下のビットマップをリソースにインポートしてプロジェクトに追加する。
ID
IDB_BITMAP1
IDB_BITMAP2
IDB_BITMAP3
#include < windows.h >
#include < commctrl.h >
#include "resource.h"

#define MYWNDTITLE      "Tree View Control Sample"
#define MYWNDCLASS      "StanderdWindowClass"
#define ITEM_NUM        10              // アイテムの数
#define MAX_LEN         64              // アイテム名の最大文字数(byte)
#define ID_TREE         1501            // ツリービューのID

HINSTANCE   g_hInst = NULL;             // インスタンスハンドル
HWND        hTree   = NULL;             // ツリービューのハンドル
HIMAGELIST  hIml;                       // イメージリストのハンドル

HTREEITEM   hTNode[ITEM_NUM];           // ツリービューのアイテムのハンドル
int         idxObj1,idxObj2,idxObj3;    // ツリービューのアイテムの番号
int         child_items[ITEM_NUM];      // 列挙された子アイテムの番号
int         parent_items[ITEM_NUM];     // 子アイテムの親の番号
int         child_ct = 0;               // 子アイテムの数

char    item_name[ITEM_NUM][MAX_LEN]={"item01","item02","item03","item04","item05",
                                      "item06","item07","item08","item09","item10"};


// 関数のプロトタイプ宣言
int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,int nCmdShow);
LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
void CreateTreeView(HWND hWnd);
void AddTreeViewItems();
HTREEITEM AddOneItem(HTREEITEM hParent,LPSTR szText,HTREEITEM hInsAfter,int iImage);
void MoveItem(HTREEITEM hDragItem);
void Get_Child_Items(HTREEITEM hItem);
void Get_Child_Items_Sub(HTREEITEM hItem);
int Get_Item_Index(HTREEITEM hItem);


int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,int nCmdShow)
{
    WNDCLASSEX wc;
    MSG        msg;


    g_hInst = hInst;

    // 親ウィンドウ
    ZeroMemory(&wc, sizeof(wc));
    wc.cbSize           = sizeof(WNDCLASSEX); 
    wc.lpfnWndProc      = (WNDPROC)WndProc;
    wc.hInstance        = hInst;
    wc.hIcon            = LoadIcon(hInst, IDI_APPLICATION);
    wc.hCursor          = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
    wc.hbrBackground    = (HBRUSH) COLOR_WINDOW;
    wc.lpszMenuName     = NULL;
    wc.lpszClassName    = MYWNDCLASS;
    if(RegisterClassEx(&wc) == 0)
        return 0;

    HWND hWnd = CreateWindowEx(0, 
                MYWNDCLASS,
                MYWNDTITLE,
                WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_VISIBLE,
                CW_USEDEFAULT, CW_USEDEFAULT, 300, 300,
                NULL,
                NULL,
                hInst,
                NULL);

    if(hWnd == NULL)
        return 0;

    while(GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}

// 親ウィンドウ プロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static BOOL         g_fDragging = FALSE;
    static HTREEITEM    hDragItem;
    static HWND         hEdit;
    
    switch (uMsg)
    {
    case WM_CREATE:
        CreateTreeView( hWnd );         // ツリービューを作成
        AddTreeViewItems();             // ツリービューにアイテムを追加
        break;
        
    case WM_SIZE:
        MoveWindow(hTree, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
        break;
        
    case WM_NOTIFY:
        switch(wParam)
        {
        case ID_TREE:
            switch( ((LPNMHDR)lParam)->code)
            {
            case TVN_BEGINDRAG:         //  ドラッグ開始
                NM_TREEVIEW *lpnmtv;
                int         level;
                UINT        xIndent;
                RECT        rcItem;
                HTREEITEM   htItem;

                lpnmtv = (NM_TREEVIEW *)lParam;

                SetCapture(GetParent(hTree));   // マウスキャプチャ開始

                g_fDragging = TRUE;             // ドラッグ中のフラグ

                // ドラッグアイテムのハンドルを取得
                hDragItem = lpnmtv->itemNew.hItem;

                // ドラッグアイテムを選択する
                TreeView_SelectItem(hTree, hDragItem);

                // ドラッグの画像を用意する
                HIMAGELIST hIml_DD;

                hIml_DD = TreeView_CreateDragImage(hTree, hDragItem);
                //ドラッグ画像の表示位置を求める計算
                htItem = hDragItem;
                level = 0;
                do{
                    htItem = TreeView_GetParent(hTree, htItem);
                    level++;
                }while(htItem);
                xIndent = TreeView_GetIndent(hTree);
                TreeView_GetItemRect(hTree, hDragItem, &rcItem, FALSE);
                
                // ドラッグ画像を表示する
                ImageList_BeginDrag(hIml_DD,0,lpnmtv->ptDrag.x-rcItem.left-
                                xIndent*level,lpnmtv->ptDrag.y-rcItem.top);
                break;

            case TVN_BEGINLABELEDIT:    // ラベルの編集を開始したときの処理
                // ラベルのエディットコントロールのハンドルを取得
                hEdit = TreeView_GetEditControl(hTree);
                // ラベルの文字数を制限
                SendMessage(hEdit,EM_SETLIMITTEXT,MAX_LEN,0);
                return FALSE;

            case TVN_ENDLABELEDIT:      // ラベルの編集が終了したときの処理
                HTREEITEM       hSelect;
                int             index;
                TV_ITEM         tvItem;
                
                hSelect = TreeView_GetSelection(hTree);
                index = Get_Item_Index(hSelect);

                // 選択されているアイテムのテキスト(ラベル)を取得
                SendMessage(hEdit,WM_GETTEXT,MAX_LEN,(LPARAM)item_name[index]);

                // アイテムの情報を設定
                tvItem.hItem = hSelect;
                tvItem.mask = TVIF_TEXT;
                tvItem.pszText = item_name[index];
                tvItem.cchTextMax = strlen(item_name[index]);

                TreeView_SetItem(hTree, &tvItem);
            
                return TRUE;
            }
            break;
        }
        break;

    case WM_MOUSEMOVE:              // ドラッグ中
        if (g_fDragging)
        {
            // マウスカーソルがアイテムの上に来たら、そののアイテムを
            // ドロップターゲットとして選択し、ドラッグ画像を表示する。
            TV_HITTESTINFO  tvhit;
            HTREEITEM       hTarget;
            tvhit.pt.x = LOWORD(lParam);
            tvhit.pt.y = HIWORD(lParam);
            if ((hTarget = TreeView_HitTest(hTree, &tvhit)) != NULL){
                ImageList_DragLeave(hTree);
                TreeView_SelectDropTarget(hTree, hTarget);
                ImageList_DragEnter(hTree, LOWORD(lParam), HIWORD(lParam));
            }
        }
        break;

    case WM_LBUTTONUP:              // ドラッグ終了
        if (g_fDragging)
        {
            ImageList_EndDrag();
            MoveItem(hDragItem);    // ドロップ処理
            ReleaseCapture();       // キャプチャ終了
            ImageList_DragLeave(hTree);
            g_fDragging = FALSE;           
        }
        break;

    case WM_CLOSE:
        if(hIml)
            ImageList_Destroy(hIml);
        DestroyWindow(hWnd);
        PostQuitMessage(0);
        break;

    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return 0;
}

void CreateTreeView(HWND hWnd)
{
    InitCommonControls();       // コモンコントロールの初期化

    hTree = CreateWindowEx(     // ツリービューコントロールを付ける
                WS_EX_CLIENTEDGE,
                WC_TREEVIEW,
                NULL,
                WS_CHILD | WS_VISIBLE | TVS_HASLINES | TVS_HASBUTTONS | 
                TVS_LINESATROOT | TVS_EDITLABELS | TVS_SHOWSELALWAYS,
                0, 0, 0, 0,
                hWnd,
                (HMENU) ID_TREE,
                g_hInst,
                NULL);

    HBITMAP hBmp;

    // イメージリストの作成
    hIml = ImageList_Create(16,16,0,3,0);

    hBmp = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP1));
    idxObj1 = ImageList_Add(hIml, hBmp, NULL);
    DeleteObject((HGDIOBJ)hBmp);

    hBmp = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP2));
    idxObj2 = ImageList_Add(hIml, hBmp, NULL);
    DeleteObject((HGDIOBJ)hBmp);

    hBmp = LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_BITMAP3));
    idxObj3 = ImageList_Add(hIml, hBmp, NULL);
    DeleteObject((HGDIOBJ)hBmp);

    TreeView_SetImageList(hTree, hIml, TVSIL_NORMAL);

}

// ツリービューにアイテムを追加
void AddTreeViewItems()
{
    static HTREEITEM hPrev;

    hTNode[0] = AddOneItem(NULL,      item_name[0], TVI_LAST, idxObj1);
    hTNode[1] = AddOneItem(hTNode[0], item_name[1], TVI_LAST, idxObj2);
    hTNode[2] = AddOneItem(hTNode[0], item_name[2], TVI_LAST, idxObj2);
    hTNode[3] = AddOneItem(hTNode[0], item_name[3], TVI_LAST, idxObj2);
    hTNode[4] = AddOneItem(hTNode[1], item_name[4], TVI_LAST, idxObj3);
    hTNode[5] = AddOneItem(hTNode[2], item_name[5], TVI_LAST, idxObj3);
    hTNode[6] = AddOneItem(hTNode[2], item_name[6], TVI_LAST, idxObj3);
    hTNode[7] = AddOneItem(hTNode[4], item_name[7], TVI_LAST, idxObj3);
    hTNode[8] = AddOneItem(hTNode[4], item_name[8], TVI_LAST, idxObj3);
    hTNode[9] = AddOneItem(NULL     , item_name[9], TVI_LAST, idxObj1);

    // ツリーを開いた状態にする
    for(int i=0;i<ITEM_NUM;i++){
        TreeView_Expand(hTree, hTNode[i], TVE_EXPAND);
    }
}

// ツリービューにアイテムを1つ追加
HTREEITEM AddOneItem(HTREEITEM hParent,LPSTR szText,
                     HTREEITEM hInsAfter,int iImage)
{
    HTREEITEM       hItem;
    TV_ITEM         tvi;
    TV_INSERTSTRUCT tvin;

    // 文字列, 画像, 選択画像 を設定
    tvi.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
    tvi.pszText = szText;
    tvi.cchTextMax = lstrlen(szText);
    tvi.iImage = iImage;
    tvi.iSelectedImage = iImage;

    tvin.item = tvi;
    tvin.hInsertAfter = hInsAfter;
    tvin.hParent = hParent;
    
    hItem = (HTREEITEM)SendMessage(hTree, TVM_INSERTITEM, 0, (LPARAM) &tvin);

    return (hItem);

}

// ドロップ後の処理
void MoveItem(HTREEITEM hDragItem)
{
    HTREEITEM   hParent, hTarget;
    TV_ITEM     tvDragItem;
    int         index,i;
    
    // ドロップターゲットのハンドルを取得
    hTarget = TreeView_GetDropHilight(hTree);
    
    // ドロップターゲットを未選択にする
    TreeView_SelectDropTarget(hTree, NULL);
    
    // 子孫アイテムの番号を取得
    Get_Child_Items(hDragItem);
    
    for(i=0;i<child_ct;i++){
        // 子孫アイテムの親アイテムのハンドルを取得
        hParent = TreeView_GetParent(hTree, hTNode[child_items[i]]);
        // 子孫アイテムの親アイテムの番号を取得
        parent_items[child_items[i]] = Get_Item_Index(hParent);
    }
    
    // 自分の子アイテムには、入れられない
    for(i=0;i<child_ct;i++){
        if(hTarget == hTNode[child_items[i]])   return;
    }
    
    // ドラッグアイテムは自身には、入れられない
    if(hTarget == hDragItem)    return;
    
    // ドラッグ中のアイテムの情報を取得
    tvDragItem.hItem = hDragItem;
    tvDragItem.mask = TVIF_IMAGE;
    TreeView_GetItem(hTree, &tvDragItem);
        
    // アイテムの番号を取得
    index = Get_Item_Index(hDragItem);

    if(Get_Item_Index(hTarget) == -1)    // ドロップターゲット未検出のときは終了
        return;

    // アイテムを追加
    hTNode[index] = AddOneItem(hTarget,item_name[index],TVI_LAST,tvDragItem.iImage);

    // その子アイテムも追加する
    for(i=0;i<child_ct;i++){
        // アイテムの画像を取得
        tvDragItem.hItem = hTNode[child_items[i]];
        tvDragItem.mask = TVIF_IMAGE;
        TreeView_GetItem(hTree, &tvDragItem);
        
        hTNode[child_items[i]] = AddOneItem( hTNode[parent_items[child_items[i]]],
                             item_name[child_items[i]], TVI_LAST, tvDragItem.iImage);
    }

    // 以前のアイテムを削除
    TreeView_DeleteItem(hTree, hDragItem);
    // 挿入したアイテムを選択する
    TreeView_SelectItem(hTree, hTNode[index]);
    // アイテムをソートする
    TreeView_SortChildren(hTree,hTarget,0);

}

// hItem の子孫アイテムを列挙する
void Get_Child_Items(HTREEITEM hItem)
{
    int         i;
    int         class_ct0 = 0;   // 前段までの子アイテム数
    int         class_ct1 = 0;   // 現段までの子アイテム数

    child_ct = 0;
    for(i=0;i<ITEM_NUM;i++)
        child_items[i] = -1;

    Get_Child_Items_Sub(hItem);

    while(child_ct != class_ct0){
        class_ct0 = class_ct1;
        class_ct1 = child_ct;
        for(i=class_ct0;i<class_ct1;i++)
            Get_Child_Items_Sub(hTNode[child_items[i]]);
    }
}

// hItem の子アイテムを列挙する
void Get_Child_Items_Sub(HTREEITEM hItem)
{
    HTREEITEM   hChild;

    hChild = TreeView_GetChild(hTree, hItem);

    if(hChild != NULL){
        child_items[child_ct ++] = Get_Item_Index(hChild);
        while(hChild != NULL){
            hChild = TreeView_GetNextSibling(hTree,hChild);
            if(hChild != NULL){
                child_items[child_ct ++] = Get_Item_Index(hChild);
            }
        }
    }
}

// hItem が、ツリービューに追加したアイテムと一致したときに、その番号を返す
int Get_Item_Index(HTREEITEM hItem)
{
    for(int i=0;i<ITEM_NUM;i++)
    {
        if (hTNode[i] == hItem)
            return i;
    }
    return -1;
}

8.コモンダイアログのフック

フックプロシージャを使用すると、オープンファイルダイアログのイベントを処理できる。
[ファイルの種類]の選択を変更すると、拡張子を変更するサンプル。
メッセージ説明
CDN_FILEOKOKボタンが押された
CDN_FOLDERCHANGE新しいフォルダが開かれた
CDN_HELP[?]ボタンが押された
CDN_INITDONE初期化が終わった
CDN_SELCHANGEリストボックスの選択が変更された
CDN_SHAREVIOLATIONネットワーク上のファイル
CDN_TYPECHANGEファイルの種類が変更された
ID説明
cmb1ファイルの種類
cmb2保存する場所
cmb13 
edt1ファイル名
lst1リストボックス
stc1lst1のラベル
stc2cmb1のラベル
stc3cmb13のラベル
stc4cmb2のラベル
IDOKOKボタン
IDCANCELキャンセルボタン
pshHelpヘルプボタン
#include < windows.h >
#include < stdio.h >

// 保存ダイアログ フックプロシージャ
int CALLBACK SaveHookProc (HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
    static char ext[][4] = {"bmp","gif","jpg"};

    switch( uMsg )
    {
    case WM_INITDIALOG:
        return TRUE;
    case WM_NOTIFY:
        NMHDR *phdr;
        phdr = (NMHDR *)lParam;
        switch(phdr->code)
        {
        case CDN_TYPECHANGE:    // [ファイルの種類]の選択が変更されたとき
            LPOFNOTIFY  lpon;
            char        *p,ss[MAX_PATH];
            lpon = (LPOFNOTIFY) lParam;
            SendDlgItemMessage(GetParent(hDlg),edt1,WM_GETTEXT,MAX_PATH,(LPARAM)ss);
            if(strlen(ss)){
                p = strrchr(ss,'.');
                if(p){
                    sprintf(p,".%s",ext[lpon->lpOFN->nFilterIndex-1]);
                }
                else{
                    sprintf(ss,"%s.%s",ss,ext[lpon->lpOFN->nFilterIndex-1]);
                }
                SendDlgItemMessage(GetParent(hDlg),edt1,WM_SETTEXT,0,(LPARAM)ss);
            }
            return TRUE;
        default:
            return FALSE;
        }
        return TRUE;
    default:
        return FALSE;
    }
    return TRUE;
}// CALLBACK SaveHookProc

// 名前を付けて保存
void Save_File(HWND hWnd,char *filename,int index)
{
    OPENFILENAME    ofn;
    char            fn[MAX_PATH];
    int             r;
    
    strcpy(fn,filename);

    ZeroMemory(&ofn, sizeof(ofn));
    ofn.lStructSize  = sizeof(ofn);
    ofn.hwndOwner    = hWnd;
    ofn.Flags        = OFN_ENABLEHOOK | OFN_EXPLORER | OFN_OVERWRITEPROMPT;
    ofn.lpstrFile    = fn;
    ofn.nMaxFile     = MAX_PATH;
    ofn.lpstrFilter  = "ビットマップ (*.bmp)\0*.bmp\0"
                      "GIF形式 (*.gif)\0*.gif\0"
                      "JPEG形式 (*.jpg)\0*.jpg;*.jpeg\0";
    ofn.nFilterIndex = index;
    ofn.lpfnHook     = (LPOFNHOOKPROC) SaveHookProc;
    r = GetSaveFileName(&ofn);
    if (r) {
        MessageBox(hWnd,fn,"保存するファイル名",MB_OK);
    }
}

int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,int nCmdShow)
{
    Save_File(NULL,"image01.gif",2);
    return 0;
}

9.サブクラス化

 コントロールをサブクラス化すると、コントロールのプロシージャを取得できる。
 以下は、使えないコマンドに対応するメニュー項目を無効化するサンプルである。
 具体的には、エディットのデフォルトのプロシージャをサブクラス化して、WM_LBUTTONUPとWM_KEYUPをオーバーライドする。
 メニュー(IDR_MENU1)をリソースファイルに追加し、プロジェクトにそのファイルを追加する。
 このサンプルは、WM_MENUSELECT や WM_INITMENU メッセージなどを処理すると3行で置き換えられる
case WM_MENUSELECT:
  Menu_State();
  break;

編集 
元に戻すIDM_UNDO
切り取りIDM_CUT
コピーIDM_COPY
貼り付けIDM_PASTE
削除IDM_DEL
すべて選択IDM_ALL
#include < windows.h >
#include "resource.h"

#define MYWNDCLASS  "TEDIT"
#define MYWNDTITLE  "TEDIT"
#define MAX_LEN     1024 * 256      // 最大文字数
#define ID_EDIT1    1501

HINSTANCE   g_hInst  = NULL;
HWND        g_hEdit1 = NULL;
HMENU       g_hMenu  = NULL;

WNDPROC lpPreEditProc;              // 本来のエディットコントロールのプロシージャ

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK EditProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
void Menu_State();

int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,int nCmdShow)
{
    MSG         msg;
    WNDCLASSEX  wc;
    HWND        hWnd;

    g_hInst = hInst;

    ZeroMemory(&wc, sizeof(wc));
    wc.cbSize           = sizeof(WNDCLASSEX); 
    wc.lpfnWndProc      = (WNDPROC)WndProc;
    wc.hInstance        = hInst;
    wc.hIcon            = LoadIcon(hInst, MAKEINTRESOURCE(IDI_ICON1));
    wc.hCursor          = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground    = (HBRUSH)(COLOR_BTNFACE+1);
    wc.lpszMenuName     = NULL;
    wc.lpszClassName    = MYWNDCLASS;
    RegisterClassEx(&wc);

    g_hMenu = LoadMenu(hInst,MAKEINTRESOURCE(IDR_MENU1));

    hWnd = CreateWindowEx(0, 
                MYWNDCLASS,
                MYWNDTITLE,
                WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_VISIBLE,
                CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
                NULL,
                g_hMenu,
                hInst,
                NULL);

    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}

// メインウィンドウのプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_CREATE:     // 初期化
        // エディットコントロールの作成
        g_hEdit1 = CreateWindowEx(WS_EX_CLIENTEDGE,
                "EDIT",
                NULL,
                WS_CHILD | WS_BORDER | WS_VISIBLE | ES_MULTILINE | ES_WANTRETURN |
                WS_VSCROLL | WS_HSCROLL | ES_AUTOVSCROLL | ES_AUTOHSCROLL,
                0, 0, 0, 0,
                hWnd,
                (HMENU)ID_EDIT1,
                g_hInst,
                NULL);
        SendMessage(g_hEdit1, EM_SETLIMITTEXT, (WPARAM) MAX_LEN, 0);
        
        // エディットコントロールのフックプロシージャを作成
        lpPreEditProc = (WNDPROC)SetWindowLong(g_hEdit1,GWL_WNDPROC,(LONG)EditProc);

        Menu_State();
        break;

    case WM_SIZE:
        MoveWindow(g_hEdit1, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE);
        break;

    case WM_ACTIVATE:
        SetFocus(g_hEdit1);
        break;

    case WM_COMMAND:
        switch( LOWORD(wParam) )
        {
        case IDM_UNDO:      // 元に戻す
            SendMessage(g_hEdit1,WM_UNDO,0,0);
            Menu_State();
            break;

        case IDM_CUT:       // 切り取り
            SendMessage(g_hEdit1,WM_CUT,0,0);
            Menu_State();
            break;

        case IDM_COPY:      // コピー
            SendMessage(g_hEdit1,WM_COPY,0,0);
            Menu_State();
            break;

        case IDM_PASTE:     // 貼り付け
            SendMessage(g_hEdit1,WM_PASTE,0,0);
            Menu_State();
            break;

        case IDM_DEL:       // 削除
            SendMessage(g_hEdit1,WM_CLEAR,0,0);
            Menu_State();
            break;

        case IDM_ALL:       // すべて選択
            SendMessage(g_hEdit1,EM_SETSEL,0,(LONG)(int)-1);
            Menu_State();
            break;
        default:
        }
        break;

    case WM_CLOSE:
        DestroyWindow(hWnd);
        PostQuitMessage(0);
        break;

    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return 0;
}

// エディットコントロールのプロシージャ
LRESULT CALLBACK EditProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch ( uMsg )
    {
        case WM_LBUTTONUP:          // マウスの左ボタンが離れたとき
            Menu_State();
            break;

        case WM_KEYUP:              // キー入力が離れたとき
            Menu_State();
            break;
        default:
    }
    // 全てのメッセージを本来のプロシージャへ送る(停止したい機能は送らない)
    return CallWindowProc(lpPreEditProc,hWnd,uMsg,wParam,lParam);
}

// メニュー項目の状態変更 (有効化,無効化)
void Menu_State()
{
    DWORD sel = SendMessage(g_hEdit1,EM_GETSEL,0,0L);
    EnableMenuItem(g_hMenu, 
        IDM_UNDO, SendMessage(g_hEdit1,EM_CANUNDO,0,0L)?MF_ENABLED:MF_GRAYED);
    EnableMenuItem(g_hMenu, 
        IDM_CUT, HIWORD(sel)!=LOWORD(sel)?MF_ENABLED:MF_GRAYED);
    EnableMenuItem(g_hMenu, 
        IDM_COPY, HIWORD(sel)!=LOWORD(sel)?MF_ENABLED:MF_GRAYED);
    EnableMenuItem(g_hMenu, 
        IDM_DEL, HIWORD(sel)!=LOWORD(sel)?MF_ENABLED:MF_GRAYED);
    EnableMenuItem(g_hMenu, 
        IDM_PASTE,IsClipboardFormatAvailable(CF_TEXT)?MF_ENABLED:MF_GRAYED);
    EnableMenuItem(g_hMenu, 
        IDM_ALL,SendMessage(g_hEdit1,WM_GETTEXTLENGTH,0,0L)?MF_ENABLED:MF_GRAYED);
}

10.コモンダイアログのテンプレート

MSDN Library の ComDlg32: Common Dialog Boxes が
ファイルオープンコモンダイアログのテンプレートのサンプルである。
コントロールIDが stc32 の無文字のスタティックコントロールを使用する。

-------------------- resource.h --------------------------------
#define IDD_DIALOG1                     101

-------------------- opendlg_tmp.res ---------------------------
IDD_DIALOG1 DIALOG DISCARDABLE  0, 0, 300, 74
STYLE DS_3DLOOK | DS_CONTROL | WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS
FONT 8, "MS Shell Dlg"
BEGIN
    LTEXT           "",stc32,28,16,204,31
END

-------------------- opendlg_tmp.cpp ---------------------------
#include <windows.h>
#include "resource.h"

void Open_File(HINSTANCE hInst, HWND hWnd)
{
    OPENFILENAME    ofn;
    char            fn[MAX_PATH] = "";
    
    ZeroMemory(&ofn, sizeof(ofn));
    ofn.lStructSize  = sizeof(ofn);
    ofn.hwndOwner    = hWnd;
    ofn.hInstance    = hInst;
    ofn.Flags        = OFN_ENABLETEMPLATE | OFN_EXPLORER;
    ofn.lpstrFile    = fn;
    ofn.nMaxFile     = MAX_PATH;
    ofn.lpstrFilter  = "すべてのファイル (*.*)\0*.*\0";
    ofn.nFilterIndex = 1;
    ofn.lpTemplateName = MAKEINTRESOURCE(IDD_DIALOG1);
    int r = GetOpenFileName(&ofn);
    if (r) {
        MessageBox(hWnd,fn,"ファイル名",MB_OK);
    }
}

int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,int nCmdShow)
{
    Open_File(hInst, NULL);
    return 0;
}


それよりも遠回りになるが以下のような方法もある。

カラーダイアログのカスタムテンプレートを使用する。
リソースエディタでは、Altキーを押しながらコントロールをドラッグして移動する。
テキストエディタのほうが編集しやすい。
COLOR.DLGの日本語版を自作した。
ある程度、オリジナルに似せてある。
これを使うときは、下の4の作業はしなくて良い。
ただし、状況に応じてIDD_DIALOG1を別のIDに書き換える必要がある。

DOWNLOAD
ソースの先頭
    #include "resource.h"
    
    
カラーダイアログの追加位置
    static COLORREF Custm[16];
    CHOOSECOLOR     cc;
    ZeroMemory(&cc, sizeof(cc));
    cc.lStructSize  = sizeof(cc);
    cc.Flags        = CC_ANYCOLOR | CC_ENABLETEMPLATE;
    cc.hwndOwner    = hWnd;
    cc.hInstance    = (HWND) GetModuleHandle(NULL);
    cc.lpCustColors = (LPDWORD) Custm;
    cc.lpTemplateName = MAKEINTRESOURCE(IDD_DIALOG1);
    if(ChooseColor(&cc)){
    }

11.スピン・スライダーコントロールの増減幅変更

スピン(Up-Down)、又はスライダー(Trackbars)コントロールの増減幅を100ずつにする。
親ウィンドウのプロシージャに以下のコードを追加する。

スライダーの値の範囲には、マイナスや浮動小数点数を設定できない。
// スピンの場合
case WM_NOTIFY:
    switch(((LPNMHDR)lParam)->code)
    {
    case UDN_DELTAPOS:
        ((LPNMUPDOWN) lParam)->iDelta *= 100;
        break;
    }
    break;

// スライダーの場合
case WM_INITDIALOG:
    SendMessage(hSlider, TBM_SETLINESIZE, 0, 100);
    break;
case WM_HSCROLL:	// または、WM_VSCROLL
    int d;
    d = SendMessage(hSlider, TBM_GETPOS, 0, 0);
    d -= d % 100;
    SendMessage(hSlider, TBM_SETPOS, FALSE, d);
    break;

12.カスタムコントロール

 ダイアログにコードで直接コントロールを作成するのは、まずいらしいのでカスタムコントロールを使用する。
 リソースエディタでカスタムコントロールを設置後、プロパティにクラス名を記述する。
 RCファイルの該当箇所に、以下の場合であれば"CustmClass"と記述されているのを確認する。
 コントロールを一から作成することもできるらしいが、ダイアログボックスに同じコントロールを多数付けたいがリソースエディタで一つ一つ入れるのが面倒なときや設定が大きくなった既存コントロールを使いまわしたいときなどにも使える。
#include <windows.h>
#include "resource.h"

// クラスの登録
void Set_Class(char *cls, WNDPROC WndProc)
{
    WNDCLASSEX wc;
    ZeroMemory(&wc, sizeof(wc));
    wc.cbSize           = sizeof(WNDCLASSEX);
    wc.lpfnWndProc      = (WNDPROC)WndProc;
    wc.hInstance        = GetModuleHandle(NULL);
    wc.hCursor          = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground    = (HBRUSH)(COLOR_BTNFACE+1);
    wc.lpszClassName    = cls;
    RegisterClassEx(&wc);
}// Set_Class

// カスタムコントロール プロシージャ
LRESULT CALLBACK CustomProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_CREATE:
        RECT rect;
        GetClientRect(hWnd, &rect);
        break;
    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return 0;
}

// ダイアログボックス プロシージャ
int CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch( uMsg )
    {
    case WM_INITDIALOG:
        break;
    case WM_COMMAND:
        switch( LOWORD(wParam) )
        {
        case IDOK:
            EndDialog(hDlg,TRUE);
            return TRUE;
        case IDCANCEL:
            EndDialog(hDlg,FALSE);
            return TRUE;
        }
        return FALSE;
    default:
        return FALSE;
    }
    return TRUE;
}// CALLBACK ProcPalDlg

// 親ウィンドウ プロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_CREATE:
        Set_Class("CustmClass", CustomProc);// カスタムコントロールクラスの登録
        break;
    case WM_COMMAND:
        switch( LOWORD(wParam) )
        {
        case IDM_DLG:
            DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG1),
                      hWnd, DlgProc);
        }
        break;
    case WM_CLOSE:
        DestroyWindow(hWnd);
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return 0;
}

int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev,
                     LPSTR lpCmdLine, int nCmdShow)
{
    // 親ウィンドウクラスの登録
    Set_Class("MYWNDCLASS", WndProc);
    
    // 親ウィンドウの作成
    HWND hWnd = CreateWindowEx(0,
                "MYWNDCLASS",
                "MYWNDTITLE",
                WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_CLIPCHILDREN,
                CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
                NULL,
                LoadMenu(hInst,MAKEINTRESOURCE(IDR_MENU1)),
                hInst,
                NULL);
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}