- ابتدا تابعی با نام DrawBorder را برای ترسیم یک مستطیل تعریف می کنیم.
- دقت کنید که از آن جایی که در خارج از پیام WM_PAINT در حال رسم هستیم لذا ابتدا هندل DC  یا همان display device context را برای انجام کارهای گرافیکی قسمت client area باید با استفاده از GetDC دریافت کنید و در پایان ترسیم نیز با  ReleaseDC آزاد کنید.
- تابع SetROP2 با فلگ R2_NOT باعث می شود مستطیل ما با رنگی معکوس زنگ زمینه در هنگام drag کردن mouse نمایش داده شود.
void DrawBorder(HWND hwnd, POINT ptBeg, POINT ptEnd)
{
    HDC hdc ;
    hdc = GetDC (hwnd) ;
    SetROP2 (hdc, R2_NOT) ;
    SelectObject (hdc, GetStockObject (NULL_BRUSH)) ;
    Rectangle (hdc, ptBeg.x, ptBeg.y, ptEnd.x, ptEnd.y) ;
    ReleaseDC (hwnd, hdc) ;
}
تابع WndProc را همانند مثال قبل  برای پیام ها به شکل زیر تغییر دهید:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, 
                      WPARAM wParam, LPARAM lParam)
{
    int          wmId, wmEvent;
    HDC             hdc ;
    PAINTSTRUCT  ps ;
    static BOOL  drawing, drawBox ;
    static POINT ptBeg, ptEnd, ptBoxBeg, ptBoxEnd ;
    switch (message)
    {
    case WM_LBUTTONDOWN :
        ptBeg.x = ptEnd.x = LOWORD (lParam) ;
        ptBeg.y = ptEnd.y = HIWORD (lParam) ;
        drawing = TRUE ;
        return 0 ;
    case WM_MOUSEMOVE :
        if (drawing)
        {
            SetCursor (LoadCursor (NULL, IDC_CROSS)) ;
            DrawBorder (hWnd, ptBeg, ptEnd) ;  // clean previous drawing
            ptEnd.x = LOWORD (lParam) ;
            ptEnd.y = HIWORD (lParam) ;
            DrawBorder (hWnd, ptBeg, ptEnd) ;
        }
        return 0 ;
    case WM_LBUTTONUP :
        if (drawing)
        {
            DrawBorder (hWnd, ptBeg, ptEnd) ;
            ptBoxBeg    = ptBeg ;
            ptBoxEnd.x  = LOWORD (lParam) ;
            ptBoxEnd.y  = HIWORD (lParam) ;
            SetCursor (LoadCursor (NULL, IDC_ARROW)) ;
            drawing = FALSE ;
            drawBox = TRUE ;
            InvalidateRect (hWnd, NULL, TRUE) ;
        }
        return 0 ;
    case WM_PAINT :
        hdc = BeginPaint (hWnd, &ps) ;
        if (drawBox)
        {
            SelectObject (hdc, GetStockObject (LTGRAY_BRUSH)) ;
            Rectangle (hdc, ptBoxBeg.x, ptBoxBeg.y, ptBoxEnd.x, ptBoxEnd.y) ;
        }
        if (drawing)
        {
            SetROP2 (hdc, R2_NOT) ;
            SelectObject (hdc, GetStockObject (NULL_BRUSH)) ;
            Rectangle (hdc, ptBeg.x, ptBeg.y, ptEnd.x, ptEnd.y) ;
        }
        
        EndPaint (hWnd, &ps) ;
        return 0 ;
    case WM_COMMAND:
        wmId    = LOWORD(wParam);
        wmEvent = HIWORD(wParam);
        // Parse the menu selections:
        switch (wmId)
        {
        case IDM_about:
            DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
            break;
        case IDM_EXIT:
            DestroyWindow(hWnd);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        break;
    case WM_DESTROY :
        PostQuitMessage (0) ;
        return 0 ;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;
    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}
پیام های mouse مورد استفاده :
- پیام WM_LBUTTONDOWN وقتی فراخوانی می شود که کلیک چپ mouse زده می شود.
- پیام WM_MOUSEMOVE وقتی که mouse در حال حرکت می باشد.
لذا با یک متغیر bool تست می کنیم که حتما پیام LBUTTONDOWN مقدار true داشته باشد و سپس عملیات انجام شود.
- پیام  WM_LBUTTONUP وقتی کلیک چپ mouse آزاد می شود
پس از پایان این پیام تابع InvalidateRect را فراخوانی می کنیم تا با رفرش کردن تصویر در قسمت WM_PAINT ترسیم نهایی مستطیل انجام شود (متغیر drawBox وقتی true می شود)
- با استفاده از lParam های در پیام های mouse مختصات x و y را دریافت می کنیم.
- تابع SetCursor نشان mosue را به یک شکل دیگر مانند + تغییر می دهد.
سورس کد پروژه ضمیمه شد
موفق باشید