天天看點

Windows程式設計-子視窗控件

按鈕類别

Windows程式設計-子視窗控件
/*----------------------------------------
   BTNLOOK.C -- Button Look Program
                (c) Charles Petzold, 1998
  ----------------------------------------*/

#include <windows.h>

struct
{
     int     iStyle ;
     TCHAR * szText ;
}
button[] =
{
     BS_PUSHBUTTON,      TEXT ("PUSHBUTTON"),
     BS_DEFPUSHBUTTON,   TEXT ("DEFPUSHBUTTON"),
     BS_CHECKBOX,        TEXT ("CHECKBOX"), 
     BS_AUTOCHECKBOX,    TEXT ("AUTOCHECKBOX"),
     BS_RADIOBUTTON,     TEXT ("RADIOBUTTON"),
     BS_3STATE,          TEXT ("3STATE"),
     BS_AUTO3STATE,      TEXT ("AUTO3STATE"),
     BS_GROUPBOX,        TEXT ("GROUPBOX"),
     BS_AUTORADIOBUTTON, TEXT ("AUTORADIO"),
     BS_OWNERDRAW,       TEXT ("OWNERDRAW")
} ;

#define NUM (sizeof button / sizeof button[0])

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = TEXT ("BtnLook") ;
     HWND         hwnd ;
     MSG          msg ;
     WNDCLASS     wndclass ;

     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = szAppName ;

     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("This program requires Windows NT!"),
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }

     hwnd = CreateWindow (szAppName, TEXT ("Button Look"),
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;

     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;

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

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     static HWND  hwndButton[NUM] ;
     static RECT  rect ;
     static TCHAR szTop[]    = TEXT ("message            wParam       lParam"),
                  szUnd[]    = TEXT ("_______            ______       ______"),
                  szFormat[] = TEXT ("%-16s%04X-%04X    %04X-%04X"),
                  szBuffer[50] ;
     static int   cxChar, cyChar ;
     HDC          hdc ;
     PAINTSTRUCT  ps ;
     int          i ;

     switch (message)
     {
     case WM_CREATE :
          cxChar = LOWORD (GetDialogBaseUnits ()) ;
          cyChar = HIWORD (GetDialogBaseUnits ()) ;

          for (i = 0 ; i < NUM ; i++)
               hwndButton[i] = CreateWindow ( TEXT("button"), 
                                   button[i].szText,
                                   WS_CHILD | WS_VISIBLE | button[i].iStyle,
                                   cxChar, cyChar * (1 + 2 * i),
                                   20 * cxChar, 7 * cyChar / 4,
                                   hwnd, (HMENU) i,
                                   ((LPCREATESTRUCT) lParam)->hInstance, NULL) ;
          return 0 ;

     case WM_SIZE :
          rect.left   = 24 * cxChar ;
          rect.top    =  2 * cyChar ;
          rect.right  = LOWORD (lParam) ;
          rect.bottom = HIWORD (lParam) ;
          return 0 ;

     case WM_PAINT :
          InvalidateRect (hwnd, &rect, TRUE) ;

          hdc = BeginPaint (hwnd, &ps) ;
          SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)) ;
          SetBkMode (hdc, TRANSPARENT) ;

          TextOut (hdc, 24 * cxChar, cyChar, szTop, lstrlen (szTop)) ;
          TextOut (hdc, 24 * cxChar, cyChar, szUnd, lstrlen (szUnd)) ;

          EndPaint (hwnd, &ps) ;
          return 0 ;

     case WM_DRAWITEM :
     case WM_COMMAND :
          ScrollWindow (hwnd, 0, -cyChar, &rect, &rect) ;

          hdc = GetDC (hwnd) ;
          SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)) ;

          TextOut (hdc, 24 * cxChar, cyChar * (rect.bottom / cyChar - 1),
                   szBuffer,
                   wsprintf (szBuffer, szFormat,
                         message == WM_DRAWITEM ? TEXT ("WM_DRAWITEM") : 
                                                  TEXT ("WM_COMMAND"),
                         HIWORD (wParam), LOWORD (wParam),
                         HIWORD (lParam), LOWORD (lParam))) ;

          ReleaseDC (hwnd, hdc) ;
          ValidateRect (hwnd, &rect) ;
          break ;

     case WM_DESTROY :
          PostQuitMessage (0) ;
          return 0 ;
     }
     return      

所有按鈕視窗樣式都以字母「BS」開頭,它表示「按鈕樣式」

CreateWindow調用使用下面這些參數:

  • Class name(類别名稱)​

    ​TEXT ("button")​

  • Window text(視窗文字)​

    ​button[i].szText​

  • Window style(視窗樣式)​

    ​WS_CHILD | WS_VISIBLE |button[i].iStyle​

  • x position(x位置)
  • y position(y位置)​

    ​cxChar​

  • Width(寬度)​

    ​cyChar * (1 + 2 * i)​

  • Height(高度)​

    ​20 * xChar​

  • Parent window(父視窗)​

    ​7 * yChar / 4​

  • Child window ID(子視窗ID) hwnd
  • Instance handle(執行實體句柄)​

    ​(HMENU) i​

  • Extra parameters(附加參數)​

    ​((LPCREATESTRUCT) lParam) ->hInstance NULL​

    ​​

    GetDialogBaseUnits函數來獲得内定字型字元的寬度和高度。這是對話框用來獲得文字尺寸的函數。此函數傳回一個32位的值,其中低字組表示寬度,高字組表示高度。

子視窗向父視窗發消息

用滑鼠單擊按鈕時,子視窗控件就向其父視窗發送一個WM_COMMAND消息。BTNLOOK攔截WM_COMMAND消息并顯示wParam和lParam的值,它們的含義如下:

  • LOWORD (wParam) 子視窗ID
  • HIWORD (wParam) 通知碼
  • lParam 子視窗句柄

父視窗向子視窗發送消息

父視窗可以向子視窗發送以字首WM開頭的許多消息,也可以發送字首BM表示的按鈕消息。

每個子視窗控件都具有一個在其兄弟中唯一的視窗句柄和ID值。對于句柄和ID這兩者,知道其中的一個您就可以獲得另一個。如果您知道子視窗控件的視窗句柄,那麼您可以用下面的叙述來獲得ID:

id = GetWindowLong (hwndChild, GWL_ID) ;      

前面滑鼠例子中的CHECKER3程式曾用此函數(與SetWindowLong一起)來維護注冊視窗類别時保留的特殊區域的資料。在建立子視窗時,Windows保留了GWL_ID辨別符存取的資料。

您也可以使用:

id = GetDlgCtrlID (hwndChild) ;      

雖然函數中的「Dlg」部分指的是對話框,但實際上這是一個通用的函數。知道ID和父視窗句柄,您就能獲得子視窗句柄:

hwndChild = GetDlgItem (hwndParent, id) ;      

案件

仿真按鈕閃動

SendMessage (hwndButton, BM_SETSTATE, 1, 0) ;
SendMessage (hwndButton, BM_SETSTATE, 0, 0) ; // 恢複正常      

複選框

初始化帶勾選标記的BS_CHECKBOX

SendMessage (hwndButton, BM_SETCHECK, 1, 0) ;      

擷取按鈕狀态

iCheck = (int) SendMessage (hwndButton, BM_GETCHECK, 0, 0) ;      

如果該按鈕被選中,則iCheck的值為TRUE或者非零數;如果按鈕末被選中,則iCheck的值為FALSE或0。

單選按鈕

當您收到來自單選按鈕的WM_COMMAND消息時,應該向它發送wParam等于1的BM_SETCHECK消息來顯示其選中狀态:

SendMessage (hwndButton, BM_SETCHECK, 1, 0) ;      

對同組中的其它所有單選按鈕,您可以通過向它們發送wParam等于0的BM_SETCHECK消息來顯示其未選中狀态:

SendMessage (hwndButton, BM_SETCHECK, 0, 0) ;      

分組方塊

SetWindowText (hwnd, pszString) ; // 改變文字
// 獲得文字      

iMaxLength指定複制到pszBuffer指向的緩沖區中的最大字元數。該函數傳回複制的字元數。您可以首先通過下面的呼叫來獲得特定文字的長度:

iLength = GetWindowTextLength (hwnd) ;      

可見的和啟用的按鈕

// 沒有将WS_VISIBLE包含在視窗類别中,就這樣顯示
ShowWindow (hwndChild, SW_SHOWNORMAL);
ShowWindow (hwndChild, SW_HIDE) ; // 隐藏
IsWindowVisible (hwndChild) ; // 擷取狀态
EnableWindow (hwndChild, FALSE) ; // 禁用
EnableWindow (hwndChild, TRUE) ; // 啟用
IsWindowEnabled (hwndChild) ;  // 啟用狀态      

按鈕和輸入焦點

父視窗可以阻止子視窗控件獲得輸入焦點。

case WM_KILLFOCUS :
if (hwnd == GetParent ((HWND) wParam))
SetFocus (hwnd) ;
return 0      

控件與顔色

使用SetTextColor和SetBkColor将文字和文字背景的顔色改變為系統顔色

SetBkColor (hdc, GetSysColor (COLOR_BTNFACE)) ;
SetTextColor (hdc, GetSysColor (COLOR_WINDOWTEXT)) ;      

這樣顯示區域背景、文字背景和文字的顔色都與按鈕的顔色一緻了。但是,如果當您的程式執行時,使用者改變了系統顔色,您可能要改變文字背景顔色和文字顔色。這時您可以使用下面的程式代碼:

case WM_SYSCOLORCHANGE:
InvalidateRect (hwnd, NULL, TRUE) ;
break      

當子視窗即将為其顯示區域着色時,由按鈕控件發送給其父視窗消息處理程式的一個消息:WM_CTLCOLORBTN消息。父視窗可以利用這個機會來改變子視窗消息處理程式将用來着色的顔色。

當父視窗消息處理程式收到WM_CTLCOLORBTN消息時,wParam消息參數是按鈕的裝置内容句柄,lParam是按鈕的視窗句柄。當父視窗消息處理程式得到這個消息時,按鈕控件已經獲得了它的裝置内容。當您的視窗消息處理程式處理一個WM_CTLCOLORBTN消息

時,您必須完成以下三個動作:

  • 使用SetTextColor選擇設定一種文字顔色。
  • 使用SetBkColor選擇設定一種文字背景顔色。
  • 将一個畫刷句柄傳回給子視窗。

擁有者繪制按鈕

Windows程式設計-子視窗控件
/*------------------------------------------------------------------------
OWNDRAW.C -- Owner-Draw Button Demo Program
(c) Charles Petzold, 1996
-------------------------------------------------------------------------*/
#include <windows.h>
#define ID_SMALLER 1
#define ID_LARGER 2
#define BTN_WIDTH ( 8 * cxChar)
#define BTN_HEIGHT ( 4 * cyChar)
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE hInst;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    PSTR szCmdLine, int iCmdShow)
{
    static TCHAR szAppName[] = TEXT("OwnDraw");
    MSG msg;
    HWND hwnd;
    WNDCLASS wndclass;
    hInst = hInstance;
    wndclass.style = CS_HREDRAW |
        CS_VREDRAW;
    wndclass.lpfnWndProc = WndProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = LoadIcon(NULL,
        IDI_APPLICATION);
    wndclass.hCursor = LoadCursor(NULL,
        IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)GetStockObject
        (WHITE_BRUSH);
    wndclass.lpszMenuName = szAppName;
    wndclass.lpszClassName = szAppName;
    if (!RegisterClass(&wndclass))
    {
        MessageBox(NULL, TEXT("This program requires Windows NT!"),
            szAppName, MB_ICONERROR);
        return 0;
    }
    hwnd = CreateWindow(szAppName, TEXT("Owner-Draw Button Demo"),
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, NULL, hInstance, NULL);
    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}
void Triangle(HDC hdc, POINT pt[])
{
    SelectObject(hdc, GetStockObject(BLACK_BRUSH));
    Polygon(hdc, pt, 3);
    SelectObject(hdc, GetStockObject(WHITE_BRUSH));
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM
    wParam, LPARAM lParam)
{
    static HWND hwndSmaller, hwndLarger;
    static int cxClient, cyClient, cxChar,
        cyChar;
    int cx, cy;
    LPDRAWITEMSTRUCT pdis;
    POINT pt[3];
    RECT rc;
    switch (message)
    {
    case WM_CREATE:
        cxChar = LOWORD(GetDialogBaseUnits());
        cyChar = HIWORD(GetDialogBaseUnits());
        // Create the owner-draw pushbuttons
        hwndSmaller = CreateWindow(TEXT("button"), TEXT(""),
            WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
            0, 0, BTN_WIDTH, BTN_HEIGHT,
            hwnd, (HMENU)ID_SMALLER, hInst, NULL);
        hwndLarger = CreateWindow(TEXT("button"), TEXT(""),
            WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
            0, 0, BTN_WIDTH, BTN_HEIGHT,
            hwnd, (HMENU)ID_LARGER, hInst, NULL);
        return 0;
    case WM_SIZE:
        cxClient = LOWORD(lParam);
        cyClient = HIWORD(lParam);
        // Move the buttons to the new center
        MoveWindow(hwndSmaller, cxClient / 2 - 3 *
            BTN_WIDTH / 2,
            cyClient / 2 - BTN_HEIGHT / 2,
            BTN_WIDTH, BTN_HEIGHT, TRUE);
        MoveWindow(hwndLarger, cxClient / 2 + BTN_WIDTH /
            2, cyClient / 2 - BTN_HEIGHT / 2,
            BTN_WIDTH, BTN_HEIGHT,
            TRUE);
        return 0;
    case WM_COMMAND:
        GetWindowRect(hwnd, &rc);
        // Make the window 10% smaller or larger
        switch (wParam)
        {
        case ID_SMALLER:
            rc.left += cxClient / 20;
            rc.right -= cxClient / 20;
            rc.top += cyClient / 20;
            rc.bottom -= cyClient / 20;
            break;
        case ID_LARGER:
            rc.left -= cxClient / 20;
            rc.right += cxClient / 20;
            rc.top -= cyClient / 20;
            rc.bottom += cyClient / 20;
            break;
        }
        MoveWindow(hwnd, rc.left, rc.top, rc.right - rc.left,
            rc.bottom - rc.top, TRUE);
        return 0;
    case WM_DRAWITEM:
        pdis = (LPDRAWITEMSTRUCT)lParam;
        // Fill area with white and frame it black
            FillRect(pdis->hDC, &pdis->rcItem,
                (HBRUSH)GetStockObject(WHITE_BRUSH));
        FrameRect(pdis->hDC, &pdis->rcItem,
            (HBRUSH)GetStockObject
            (BLACK_BRUSH));
        // Draw inward and outward black triangles
            cx = pdis->rcItem.right - pdis->rcItem.left;
        cy = pdis->rcItem.bottom - pdis->rcItem.top;
        switch (pdis->CtlID)
        {
        case ID_SMALLER:
            pt[0].x = 3 * cx / 8; pt[0].y = 1 * cy / 8;
            pt[1].x = 5 * cx / 8; pt[1].y = 1 * cy / 8;
            pt[2].x = 4 * cx / 8; pt[2].y = 3 * cy / 8;
            Triangle(pdis->hDC, pt);
            pt[0].x = 7 * cx / 8; pt[0].y = 3 * cy / 8;
            pt[1].x = 7 * cx / 8; pt[1].y = 5 * cy / 8;
            pt[2].x = 5 * cx / 8; pt[2].y = 4 * cy / 8;
            Triangle(pdis->hDC, pt);
            pt[0].x = 5 * cx / 8; pt[0].y = 7 * cy / 8;
            pt[1].x = 3 * cx / 8; pt[1].y = 7 * cy / 8;
            pt[2].x = 4 * cx / 8; pt[2].y = 5 * cy / 8;
            Triangle(pdis->hDC, pt);
            pt[0].x = 1 * cx / 8; pt[0].y = 5 * cy / 8;
            pt[1].x = 1 * cx / 8; pt[1].y = 3 * cy / 8;
            pt[2].x = 3 * cx / 8; pt[2].y = 4 * cy / 8;
            Triangle(pdis->hDC, pt);
            break;
        case ID_LARGER:
            pt[0].x = 5 * cx / 8; pt[0].y = 3 * cy / 8;
            pt[1].x = 3 * cx / 8; pt[1].y = 3 * cy / 8;
            pt[2].x = 4 * cx / 8; pt[2].y = 1 * cy / 8;
            Triangle(pdis->hDC, pt);
            pt[0].x = 5 * cx / 8; pt[0].y = 5 * cy / 8;
            pt[1].x = 5 * cx / 8; pt[1].y = 3 * cy / 8;
            pt[2].x = 7 * cx / 8; pt[2].y = 4 * cy / 8;
            Triangle(pdis->hDC, pt);
            pt[0].x = 3 * cx / 8; pt[0].y = 5 * cy / 8;
            pt[1].x = 5 * cx / 8; pt[1].y = 5 * cy / 8;
            pt[2].x = 4 * cx / 8; pt[2].y = 7 * cy / 8;
            Triangle(pdis->hDC, pt);
            pt[0].x = 3 * cx / 8; pt[0].y = 3 * cy / 8;
            pt[1].x = 3 * cx / 8; pt[1].y = 5 * cy / 8;
            pt[2].x = 1 * cx / 8; pt[2].y = 4 * cy / 8;
            Triangle(pdis->hDC, pt);
            break;
        }
        // Invert the rectangle if the button is selected
        if (pdis->itemState & ODS_SELECTED)
            InvertRect(pdis->hDC,
                &pdis->rcItem);
        // Draw a focus rectangle if the button has the focus
            if (pdis->itemState & ODS_FOCUS)
            {
                pdis->rcItem.left += cx / 16;
                pdis->rcItem.top += cy / 16;
                pdis->rcItem.right -= cx / 16;
                pdis->rcItem.bottom -= cy / 16;
                DrawFocusRect(pdis->hDC,
                    &pdis->rcItem);
            }
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
}
return      

靜态類

在CreateWindow函數中指定視窗類别為「static」,您就可以建立靜态文字的子視窗控件。這些子視窗非常「文靜」。它既不接收滑鼠或鍵盤輸入, 也不向父視窗發送WM_COMMAND消息。

當您在靜态子視窗上移動或者按下滑鼠時,這個子視窗将攔截WM_NCHITTEST消息并将HTTRANSPARENT的值傳回給Windows,這将使Windows向其下層視窗,通常是它的父視窗,發送相同的WM_NCHITTEST消息。父視窗常常将該消息傳遞給DefWindowProc,在這裡,它被轉換為顯示區域的滑鼠消息。

滾動條

滾動條包括:視窗滾動條和滾動條控件。

與按鈕控件(以及将在後面讨論的編輯和清單方塊控件)不同,滾動條控件不向父視窗發送WM_COMMAND消息,而是像視窗滾動條那樣發送WM_VSCROLL和WM_HSCROLL消息。在處理卷動消息時,您可以通過lParam參數來區分視窗滾動條與滾動條控件。對子視窗滾動條其值為0,對于滾動條控件其值為滾動條視窗句柄。對視窗滾動條和滾動條控件來說,wParam參數的高字組和低字組的含義相同。

取得滾動條的高寬:

GetSystemMetrics (SM_CYHSCROLL) ;
GetSystemMetrics (SM_CXVSCROLL) ;      

對視窗滾動條,您可以使用同樣的呼叫來建立滾動條控件的範圍和位置:

SetScrollRange (hwndScroll, SB_CTL, iMin, iMax, bRedraw) ;
SetScrollPos (hwndScroll, SB_CTL, iPos, bRedraw) ;
SetScrollInfo (hwndScroll, SB_CTL, &si, bRedraw) ;      

其差別在于:視窗滾動條将父視窗的句柄作為第一個參數,并且以SB_VERT或者SB_HORZ作為第二個參數。

Windows程式設計-子視窗控件
/*------------------------------------------------------------------------
COLORS1.C -- Colors Using Scroll Bars
(c) Charles Petzold, 1998
-------------------------------------------------------------------------*/
#include <windows.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ScrollProc(HWND, UINT, WPARAM, LPARAM);
int idFocus;
WNDPROC OldScroll[3];
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    PSTR szCmdLine, int
    iCmdShow)
{
    static TCHAR szAppName[] = TEXT("Colors1");
    HWND hwnd;
    MSG msg;
    WNDCLASS wndclass;
    wndclass.style = CS_HREDRAW |
        CS_VREDRAW;
    wndclass.lpfnWndProc = WndProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = LoadIcon(NULL,
        IDI_APPLICATION);
    wndclass.hCursor = LoadCursor(NULL,
        IDC_ARROW);
    wndclass.hbrBackground = CreateSolidBrush(0);
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = szAppName;
    if (!RegisterClass(&wndclass))
    {
        MessageBox(NULL, TEXT("This program requires Windows NT!"),
            szAppName, MB_ICONERROR);
        return 0;
    }
    hwnd = CreateWindow(szAppName, TEXT("Color Scroll"),
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, NULL, hInstance, NULL);
    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM
    wParam, LPARAM lParam)
{
    static COLORREF crPrim[3] = { RGB(255, 0, 0), RGB(0, 255, 0),
        RGB(0, 0, 255) };
    static HBRUSH hBrush[3], hBrushStatic;
    static HWND hwndScroll[3], hwndLabel[3], hwndValue[3],
        hwndRect;
    static int color[3], cyChar;
    static RECT rcColor;
    static TCHAR *szColorLabel[] = { TEXT("Red"), TEXT("Green"),
        TEXT("Blue") };
    HINSTANCE hInstance;
    int i, cxClient, cyClient;
    TCHAR szBuffer[10];
    switch (message)
    {
    case WM_CREATE:
        hInstance = (HINSTANCE)GetWindowLong(hwnd,
            GWL_HINSTANCE);
        // SS_WHITERECT樣式的靜态子視窗,作為三個滾動條的背景
            // 子視窗ID is 9.
            hwndRect = CreateWindow(TEXT("static"), NULL,
                WS_CHILD | WS_VISIBLE | SS_WHITERECT,
                0, 0, 0, 0,
                hwnd, (HMENU)9, hInstance, NULL);
        for (i = 0; i < 3; i++)
        {
            //  三個滾動條控件,視窗IDs 0, 1, and 2, with
            // 設定WS_TABSTOP才可以Tab切換焦點
                hwndScroll[i] = CreateWindow(TEXT("scrollbar"), NULL,
                    WS_CHILD | WS_VISIBLE |
                    WS_TABSTOP | SBS_VERT,
                    0, 0, 0, 0,
                    hwnd, (HMENU)i, hInstance, NULL);
            SetScrollRange(hwndScroll[i], SB_CTL, 0, 255,
                FALSE);
            SetScrollPos(hwndScroll[i], SB_CTL, 0, FALSE);
            // 三個顔色靜态視窗:紅綠藍,ID是3,4,5
            hwndLabel[i] = CreateWindow(TEXT("static"), szColorLabel[i],
                WS_CHILD | WS_VISIBLE | SS_CENTER,
                0, 0, 0, 0,
                hwnd, (HMENU)(i + 3),
                hInstance, NULL);
            // 三個色值文本靜态子視窗 IDs 6, 7,
            // and 8, and initial text strings of "0".
            hwndValue[i] = CreateWindow(TEXT("static"), TEXT("0"),
                WS_CHILD | WS_VISIBLE | SS_CENTER,
                0, 0, 0, 0,
                hwnd, (HMENU)(i + 6),
                hInstance, NULL);
            // 通過GWL_WNDPROC參數,設定新的視窗消息處理程式(視窗子類化)
            // 這樣可以挂鈎
            OldScroll[i] = (WNDPROC)SetWindowLong
                (hwndScroll[i],
                    GWL_WNDPROC, (LONG)ScrollProc);
            // 定義畫刷
            hBrush[i] = CreateSolidBrush(crPrim[i]);
        }
        hBrushStatic = CreateSolidBrush(
            GetSysColor(COLOR_BTNHIGHLIGHT));
        cyChar = HIWORD(GetDialogBaseUnits());
        return 0;
    case WM_SIZE:
        cxClient = LOWORD(lParam);
        cyClient = HIWORD(lParam);
        SetRect(&rcColor, cxClient / 2, 0, cxClient, cyClient);
        MoveWindow(hwndRect, 0, 0, cxClient / 2, cyClient, TRUE);
        for (i = 0; i < 3; i++)
        {
            MoveWindow(hwndScroll[i],
                (2 * i + 1) * cxClient / 14, 2 * cyChar,
                cxClient / 14, cyClient - 4 * cyChar, TRUE);
            MoveWindow(hwndLabel[i],
                (4 * i + 1) * cxClient / 28, cyChar / 2, cxClient / 7, cyChar, TRUE);
                MoveWindow(hwndValue[i],
                    (4 * i + 1) * cxClient / 28,
                    cyClient - 3 * cyChar / 2,
                    cxClient / 7, cyChar, TRUE);
        }
        SetFocus(hwnd);
        return 0;
    case WM_SETFOCUS:
        SetFocus(hwndScroll[idFocus]);
        return 0;
    case WM_VSCROLL:
        // 獲得子視窗ID
        i = GetWindowLong((HWND)lParam, GWL_ID);
        switch (LOWORD(wParam))
        {
        case SB_PAGEDOWN:
            color[i] += 15;
            // fall through
        case SB_LINEDOWN:
            color[i] = min(255, color[i] + 1);
            break;
        case SB_PAGEUP:
            color[i] -= 15;
            // fall through
        case SB_LINEUP:
            color[i] = max(0, color[i] - 1);
            break;
        case SB_TOP:
            color[i] = 0;
            break;
        case SB_BOTTOM:
            color[i] = 255;
            break;
        case SB_THUMBPOSITION:
        case SB_THUMBTRACK:
            color[i] = HIWORD(wParam);
            break;
        default:
            break;
        }
        // 設定滾動的位置
        SetScrollPos(hwndScroll[i], SB_CTL, color[i], TRUE);
        // 設定底部文字
        wsprintf(szBuffer, TEXT("%i"), color[i]);
        SetWindowText(hwndValue[i], szBuffer);
        DeleteObject((HBRUSH)
            SetClassLong(hwnd,
                GCL_HBRBACKGROUND, (LONG)
                CreateSolidBrush(RGB(color[0], color[1], color[2]))));
        // 無效視窗,強制重新整理
        InvalidateRect(hwnd, &rcColor, TRUE);
        return 0;
    case WM_CTLCOLORSCROLLBAR:
        i = GetWindowLong((HWND)lParam, GWL_ID);
        return (LRESULT)hBrush[i];
    case WM_CTLCOLORSTATIC:
        i = GetWindowLong((HWND)lParam, GWL_ID);
        if (i >= 3 && i <= 8) // static text controls
        {
            SetTextColor((HDC)wParam, crPrim[i % 3]);
            SetBkColor((HDC)wParam, GetSysColor
                (COLOR_BTNHIGHLIGHT));
            return (LRESULT)hBrushStatic;
        }
        break;
    case WM_SYSCOLORCHANGE:
        DeleteObject(hBrushStatic);
        hBrushStatic = CreateSolidBrush
            (GetSysColor(COLOR_BTNHIGHLIGHT));
        return 0;
    case WM_DESTROY:
        // 清除畫刷。SetClassLong設定畫刷,并傳回舊畫刷
        DeleteObject((HBRUSH)
            SetClassLong(hwnd,
                GCL_HBRBACKGROUND, (LONG)
                GetStockObject(WHITE_BRUSH)));
        for (i = 0; i < 3; i++)
            DeleteObject(hBrush[i]);
        DeleteObject(hBrushStatic);
        PostQuitMessage(0);
        return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
LRESULT CALLBACK ScrollProc(HWND hwnd, UINT message,
    WPARAM wParam, LPARAM lParam)
{
    int id = GetWindowLong(hwnd, GWL_ID);
    switch (message)
    {
    case WM_KEYDOWN:
        if (wParam == VK_TAB)
            // 設定輸入焦點
            SetFocus(GetDlgItem(GetParent
                (hwnd),
                (id + (GetKeyState(VK_SHIFT) < 0 ? 2 : 1)) % 3));
        break;
    case WM_SETFOCUS:
        idFocus = id;
        break;
    }
    return      

編輯類

Windows程式設計-子視窗控件
/*---------------------------------------------------------------------------
POPPAD1.C -- Popup Editor using child window edit box
(c) Charles Petzold, 1998
---------------------------------------------------------------------------*/
#include <windows.h>
#define ID_EDIT 1
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
TCHAR szAppName[] = TEXT("PopPad1");
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
    HWND hwnd;
    MSG msg;
    WNDCLASS wndclass;
    wndclass.style =
        CS_HREDRAW | CS_VREDRAW;
    wndclass.lpfnWndProc = WndProc;
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra = 0;
    wndclass.hInstance = hInstance;
    wndclass.hIcon = LoadIcon
        (NULL, IDI_APPLICATION);
    wndclass.hCursor = LoadCursor
        (NULL, IDC_ARROW);
    wndclass.hbrBackground = (HBRUSH)
        GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName = szAppName;
    if (!RegisterClass(&wndclass))
    {
        MessageBox(NULL, TEXT("This program requires Windows NT!"),
            szAppName, MB_ICONERROR);
        return 0;
    }
    hwnd = CreateWindow(szAppName, szAppName,
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, NULL, hInstance, NULL);
    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);
    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM
    wParam, LPARAM lParam)
{
    static HWND hwndEdit;
    switch (message)
    {
    case WM_CREATE:
        // 建立多行文本編輯器 ES_字首定義編輯器樣式
        // ES_MULTILINE 多行
        // ES_AUTOHSCROLL 自動水準滾動
        // ES_NOHIDESEL 沒有輸入焦點時被選擇的文字仍然被加亮
        hwndEdit = CreateWindow(TEXT("edit"), NULL,
            WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL |
            WS_BORDER | ES_LEFT | ES_MULTILINE |
            ES_AUTOHSCROLL | ES_AUTOVSCROLL,
            0, 0, 0, 0, hwnd, (HMENU)ID_EDIT,
            ((LPCREATESTRUCT)lParam)->hInstance, NULL);
        return 0;
    case WM_SETFOCUS:
        SetFocus(hwndEdit);
        return 0;
    case WM_SIZE:
        // 編輯控件的尺寸
        MoveWindow(hwndEdit, 0, 0, LOWORD(lParam), HIWORD(lParam),
            TRUE);
        return 0;
    case WM_COMMAND:
        if (LOWORD(wParam) == ID_EDIT)
            if (HIWORD(wParam) == EN_ERRSPACE ||
                HIWORD(wParam) == EN_MAXTEXT)
                MessageBox(hwnd, TEXT("Edit control out of space."),
                    szAppName, MB_OK | MB_ICONSTOP);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return      

清單框類

列出環境變量

/*----------------------------------------
   ENVIRON.C -- Environment List Box
                (c) Charles Petzold, 1998
  ----------------------------------------*/

#include <windows.h>

#define ID_LIST     1
#define ID_TEXT     2

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = TEXT ("Environ") ;
     HWND         hwnd ;
     MSG          msg ;
     WNDCLASS     wndclass ;

     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1) ;
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = szAppName ;

     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("This program requires Windows NT!"),
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }

     hwnd = CreateWindow (szAppName, TEXT ("Environment List Box"),
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;

     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;

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

void FillListBox (HWND hwndList) 
{
     int     iLength ;
     TCHAR * pVarBlock, * pVarBeg, * pVarEnd, * pVarName ;

     pVarBlock = GetEnvironmentStrings () ;  // Get pointer to environment block

     while (*pVarBlock)
     {
          if (*pVarBlock != '=')   // Skip variable names beginning with '='
          {
               pVarBeg = pVarBlock ;              // Beginning of variable name
               while (*pVarBlock++ != '=') ;      // Scan until '='
               pVarEnd = pVarBlock - 1 ;          // Points to '=' sign
               iLength = pVarEnd - pVarBeg ;      // Length of variable name

                    // Allocate memory for the variable name and terminating
                    // zero. Copy the variable name and append a zero.

               pVarName = calloc (iLength + 1, sizeof (TCHAR)) ;
               CopyMemory (pVarName, pVarBeg, iLength * sizeof (TCHAR)) ;
               pVarName[iLength] = '\0' ;

                    // Put the variable name in the list box and free memory.

               SendMessage (hwndList, LB_ADDSTRING, 0, (LPARAM) pVarName) ;
               free (pVarName) ;
          }
          while (*pVarBlock++ != '\0') ;     // Scan until terminating zero
     }
     FreeEnvironmentStrings (pVarBlock) ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     static HWND  hwndList, hwndText ;
     int          iIndex, iLength, cxChar, cyChar ;
     TCHAR      * pVarName, * pVarValue ;

     switch (message)
     {
     case WM_CREATE :
          cxChar = LOWORD (GetDialogBaseUnits ()) ;
          cyChar = HIWORD (GetDialogBaseUnits ()) ;

               // Create listbox and static text windows.

          hwndList = CreateWindow (TEXT ("listbox"), NULL,
                              WS_CHILD | WS_VISIBLE | LBS_STANDARD,
                              cxChar, cyChar * 3,
                              cxChar * 16 + GetSystemMetrics (SM_CXVSCROLL),
                              cyChar * 5,
                              hwnd, (HMENU) ID_LIST,
                              (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE),
                              NULL) ;

          hwndText = CreateWindow (TEXT ("static"), NULL,
                              WS_CHILD | WS_VISIBLE | SS_LEFT,
                              cxChar, cyChar, 
                              GetSystemMetrics (SM_CXSCREEN), cyChar,
                              hwnd, (HMENU) ID_TEXT,
                              (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE),
                              NULL) ;

          FillListBox (hwndList) ;
          return 0 ;

     case WM_SETFOCUS :
          SetFocus (hwndList) ;
          return 0 ;

     case WM_COMMAND :
          if (LOWORD (wParam) == ID_LIST && HIWORD (wParam) == LBN_SELCHANGE)
          {
                    // Get current selection.

               iIndex  = SendMessage (hwndList, LB_GETCURSEL, 0, 0) ;
               iLength = SendMessage (hwndList, LB_GETTEXTLEN, iIndex, 0) + 1 ;
               pVarName = calloc (iLength, sizeof (TCHAR)) ;
               SendMessage (hwndList, LB_GETTEXT, iIndex, (LPARAM) pVarName) ;

                    // Get environment string.

               iLength = GetEnvironmentVariable (pVarName, NULL, 0) ;
               pVarValue = calloc (iLength, sizeof (TCHAR)) ;
               GetEnvironmentVariable (pVarName, pVarValue, iLength) ;

                    // Show it in window.

               SetWindowText (hwndText, pVarValue) ;
               free (pVarName) ;
               free (pVarValue) ;
          }
          return 0 ;

     case WM_DESTROY :
          PostQuitMessage (0) ;
          return 0 ;
     }
     return      

列出檔案

/*---------------------------------------------
   HEAD.C -- Displays beginning (head) of file
             (c) Charles Petzold, 1998
  ---------------------------------------------*/

#include <windows.h>

#define ID_LIST     1
#define ID_TEXT     2

#define MAXREAD     8192
#define DIRATTR     (DDL_READWRITE | DDL_READONLY | DDL_HIDDEN | DDL_SYSTEM | \
                     DDL_DIRECTORY | DDL_ARCHIVE  | DDL_DRIVES)
#define DTFLAGS     (DT_WORDBREAK | DT_EXPANDTABS | DT_NOCLIP | DT_NOPREFIX)

LRESULT CALLBACK WndProc  (HWND, UINT, WPARAM, LPARAM) ;
LRESULT CALLBACK ListProc (HWND, UINT, WPARAM, LPARAM) ;

WNDPROC OldList ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = TEXT ("head") ;
     HWND         hwnd ;
     MSG          msg ;
     WNDCLASS     wndclass ;

     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1) ;
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = szAppName ;

     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("This program requires Windows NT!"),
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }

     hwnd = CreateWindow (szAppName, TEXT ("head"),
                          WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;

     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;

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

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
     static BOOL     bValidFile ;
     static BYTE     buffer[MAXREAD] ;
     static HWND     hwndList, hwndText ;
     static RECT     rect ;
     static TCHAR    szFile[MAX_PATH + 1] ;
     HANDLE          hFile ;
     HDC             hdc ;
     int             i, cxChar, cyChar ;
     PAINTSTRUCT     ps ;
     TCHAR           szBuffer[MAX_PATH + 1] ;

     switch (message)
     {
     case WM_CREATE :
          cxChar = LOWORD (GetDialogBaseUnits ()) ;
          cyChar = HIWORD (GetDialogBaseUnits ()) ;

          rect.left = 20 * cxChar ;
          rect.top  =  3 * cyChar ;

          hwndList = CreateWindow (TEXT ("listbox"), NULL,
                              WS_CHILDWINDOW | WS_VISIBLE | LBS_STANDARD,
                              cxChar, cyChar * 3,
                              cxChar * 13 + GetSystemMetrics (SM_CXVSCROLL),
                              cyChar * 10,
                              hwnd, (HMENU) ID_LIST,
                              (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE),
                              NULL) ;

          GetCurrentDirectory (MAX_PATH + 1, szBuffer) ;

          hwndText = CreateWindow (TEXT ("static"), szBuffer,
                              WS_CHILDWINDOW | WS_VISIBLE | SS_LEFT,
                              cxChar, cyChar, cxChar * MAX_PATH, cyChar,
                              hwnd, (HMENU) ID_TEXT,
                              (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE),
                              NULL) ;
          // 視窗子類,使用回調函數ListProc
          OldList = (WNDPROC) SetWindowLong (hwndList, GWL_WNDPROC,
                                               (LPARAM) ListProc) ;

          SendMessage (hwndList, LB_DIR, DIRATTR, (LPARAM) TEXT ("*.*")) ;
          return 0 ;

     case WM_SIZE :
          rect.right  = LOWORD (lParam) ;
          rect.bottom = HIWORD (lParam) ;
          return 0 ;

     case WM_SETFOCUS :
          SetFocus (hwndList) ;
          return 0 ;

     case WM_COMMAND :
          if (LOWORD (wParam) == ID_LIST && HIWORD (wParam) == LBN_DBLCLK)
          {
               if (LB_ERR == (i = SendMessage (hwndList, LB_GETCURSEL, 0, 0)))
                    break ;

               SendMessage (hwndList, LB_GETTEXT, i, (LPARAM) szBuffer) ;

               // 使用CreateFile來檢查是目錄還是檔案
               if (INVALID_HANDLE_VALUE != (hFile = CreateFile (szBuffer, 
                         GENERIC_READ, FILE_SHARE_READ, NULL, 
                         OPEN_EXISTING, 0, NULL)))

               {
                    CloseHandle (hFile) ;
                    bValidFile = TRUE ;
                    lstrcpy (szFile, szBuffer) ;
                    GetCurrentDirectory (MAX_PATH + 1, szBuffer) ;

                    if (szBuffer [lstrlen (szBuffer) - 1] != '\\')
                         lstrcat (szBuffer, TEXT ("\\")) ;
                    SetWindowText (hwndText, lstrcat (szBuffer, szFile)) ;
               }
               else
               {
                    bValidFile = FALSE ;
                    szBuffer [lstrlen (szBuffer) - 1] = '\0' ;

                         // If setting the directory doesn't work, maybe it's
                         // a drive change, so try that.
                    // SetCurrentDirectory不能執行就是磁盤驅動
                    if (!SetCurrentDirectory (szBuffer + 1))
                    {
                         szBuffer [3] = ':' ;
                         szBuffer [4] = '\0' ;
                         // 如果是磁盤驅動,則要去掉開頭斜線,并加上一個冒号
                         SetCurrentDirectory (szBuffer + 2) ;
                    }

                         // Get the new directory name and fill the list box.
                    // GetCurrentDirectory傳回檔案句柄
                    GetCurrentDirectory (MAX_PATH + 1, szBuffer) ;
                    SetWindowText (hwndText, szBuffer) ;
                    SendMessage (hwndList, LB_RESETCONTENT, 0, 0) ;
                    SendMessage (hwndList, LB_DIR, DIRATTR, 
                                           (LPARAM) TEXT ("*.*")) ;
               }
               InvalidateRect (hwnd, NULL, TRUE) ;
          }
          return 0 ;

     case WM_PAINT :
          if (!bValidFile)
               break ;

          if (INVALID_HANDLE_VALUE == (hFile = CreateFile (szFile, GENERIC_READ, 
                    FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)))
          {
               bValidFile = FALSE ;
               break ;
          }

          ReadFile (hFile, buffer, MAXREAD, &i, NULL) ;
          CloseHandle (hFile) ;

               // i now equals the number of bytes in buffer.
               // Commence getting a device context for displaying text.

          hdc = BeginPaint (hwnd, &ps) ;
          SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)) ;
          SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT)) ;
          SetBkColor   (hdc, GetSysColor (COLOR_BTNFACE)) ;

               // 假設檔案是ASCII編碼的

          DrawTextA (hdc, buffer, i, &rect, DTFLAGS) ;

          EndPaint (hwnd, &ps) ;
          return 0 ;

     case WM_DESTROY :
          PostQuitMessage (0) ;
          return 0 ;
     }
     return DefWindowProc (hwnd, message, wParam, lParam) ;
}

LRESULT CALLBACK ListProc (HWND hwnd, UINT message, 
                           WPARAM wParam, LPARAM lParam)
{
     if (message == WM_KEYDOWN && wParam == VK_RETURN)
          SendMessage (GetParent (hwnd), WM_COMMAND, 
                       MAKELONG (1, LBN_DBLCLK), (LPARAM) hwnd) ;

     return