kero Поведение кнопки-крестика. Если ее нажать мышкой она "утОпнет", если курсор мышки убрать "всплывет", если навести курсор снова "утОпнет", если нажать на "утОпленную" приложение закроется. Если "утопить", затем ткнуть мышкой куда-нибудь мимо крестика, то при наведении крестик уже не "утоплен". Так задумано?
Цель была - WS_SYSMENU, а сопутствующие артефакты, каюсь, были пофигу Если раздражает - поправить легко. Например, добавив такой фрагментик: ... .elseif dx==WM_LBUTTONDOWN .if cx==HTCLOSE mov uMsg,edx jmp @f .endif .if eax==13h ...
Вот мой код. Не на ассемблере. Извиняюсь за "многословность" кода - не могу иначе. Обработки WM_SETCURSOR нет. Кнопка закрытия там где надо - в правой стороне - не нарисована только, но если подвести курсор и подождать - видим Tooltip. Углы окна тоже не обработаны для resize, но это только добавит кода. Принцип ясен - мне кажется. Код (Text): #include <Windows.h> // ------------------------------------------------------------------------- #define BORDER_WIDTH 10 #define CAPTION_HEIGHT 16 #define _3D_BORDER_RAISED TRUE #define _3D_BORDER_PUSHED FALSE // ------------------------------------------------------------------------- void Draw3DRect (HDC hDC, RECT& area, BOOL bRaised) { HGDIOBJ hDefaultPen = SelectObject (hDC, GetStockObject (WHITE_PEN)); HPEN dark_gray = CreatePen (PS_SOLID, 1, RGB (128, 128, 128)); HPEN white = (HPEN) GetStockObject (WHITE_PEN); HPEN left_top = dark_gray; HPEN right_bottom = white; if (bRaised) { left_top = white; right_bottom = dark_gray; } int x2 = area.right - 1; int y2 = area.bottom - 1; SelectObject (hDC, left_top); MoveToEx (hDC, area.left, area.top, NULL); LineTo (hDC, area.left, y2); MoveToEx (hDC, area.left, area.top, NULL); LineTo (hDC, x2, area.top); SelectObject (hDC, right_bottom); MoveToEx (hDC, x2, y2, NULL); LineTo (hDC, area.left, y2); MoveToEx (hDC, x2, y2, NULL); LineTo (hDC, x2, area.top); SelectObject (hDC, hDefaultPen); DeleteObject (dark_gray); } // ------------------------------------------------------------------------- void OnPaint (HWND hWnd) { PAINTSTRUCT ps; HDC hDC = BeginPaint (hWnd, &ps); RECT client; RECT interior; HBRUSH marine = CreateSolidBrush (RGB (0, 64, 128)); HBRUSH silver = (HBRUSH) GetStockObject (LTGRAY_BRUSH); GetClientRect (hWnd, &client); interior = client; InflateRect (&interior, -BORDER_WIDTH, -BORDER_WIDTH); FillRect (hDC, &client, silver); FrameRect (hDC, &client, marine); RECT rc3DFrame = client; InflateRect (&rc3DFrame, -1, -1); RECT rcClientRaised = interior; InflateRect (&rcClientRaised, 1, 1); RECT rcClientPushed = rcClientRaised; InflateRect (&rcClientPushed, 1, 1); Draw3DRect (hDC, rc3DFrame, _3D_BORDER_RAISED); Draw3DRect (hDC, rcClientRaised, _3D_BORDER_RAISED); Draw3DRect (hDC, rcClientPushed, _3D_BORDER_PUSHED); RECT rcCaption = interior; HBRUSH dark_blue = CreateSolidBrush (RGB (16, 74, 139)); rcCaption.bottom = rcCaption.top + CAPTION_HEIGHT; InflateRect (&rcCaption, -1, -1); FillRect (hDC, &rcCaption, dark_blue); DeleteObject (dark_blue); EndPaint (hWnd, &ps); DeleteObject (marine); } // ------------------------------------------------------------------------- LRESULT OnNcHitTest (HWND hWnd, LPARAM lp) { RECT client; RECT interior; GetClientRect (hWnd, &client); interior = client; InflateRect (&interior, -BORDER_WIDTH, -BORDER_WIDTH); POINT pt = { LOWORD (lp), HIWORD (lp) }; ScreenToClient (hWnd, &pt); if (PtInRect (&interior, pt)) { if (pt.y < (interior.top + CAPTION_HEIGHT)) { if (pt.x > (interior.right - CAPTION_HEIGHT)) { return HTCLOSE; } return HTCAPTION; } return HTCLIENT; } else if (PtInRect (&client, pt)) { if (pt.x < interior.left) return HTLEFT; if (pt.x > interior.right) return HTRIGHT; if (pt.y < interior.top) return HTTOP; if (pt.y > interior.bottom) return HTBOTTOM; } return HTNOWHERE; } // ------------------------------------------------------------------------- LRESULT CALLBACK callback_GenericWndProc (HWND hWnd, UINT uiMsg, WPARAM wp, LPARAM lp) { switch (uiMsg) { case WM_NCLBUTTONDOWN: if (wp == HTCLOSE) { PostMessage (hWnd, WM_CLOSE, 0, 0); return 0; } return DefWindowProc (hWnd, uiMsg, wp, lp); case WM_NCHITTEST: return OnNcHitTest (hWnd, lp); case WM_ERASEBKGND: return 1; case WM_CLOSE: PostQuitMessage (0); break; case WM_PAINT: OnPaint (hWnd); break; default: return DefWindowProc (hWnd, uiMsg, wp, lp); } return 0; } // ------------------------------------------------------------------------- int WINAPI WinMain (HINSTANCE hModule, HINSTANCE, LPSTR, int iCmdShow) { WNDCLASS wc = {0}; wc.style = CS_VREDRAW | CS_HREDRAW; wc.hCursor = LoadCursor (NULL, IDC_ARROW); wc.hInstance = hModule; wc.lpfnWndProc = callback_GenericWndProc; wc.lpszClassName = L"NcHitTestSample"; RegisterClass (&wc); HWND hMainWnd = CreateWindowEx ( 0, wc.lpszClassName, L"Win32 Wm_NcHitTest Sample", WS_POPUP, 100, 60, 500, 480, NULL, NULL, hModule, NULL ); ShowWindow (hMainWnd, iCmdShow); UpdateWindow (hMainWnd); MSG message; while (GetMessage (&message, NULL, 0, 0)) { TranslateMessage (&message); DispatchMessage (&message); } return 0; }
Да принцип-то ясен, см. пост #15 Дело в другом: еще пост #12 выводит на ситуации, когда одного WM_NCHITTEST для ресайза (или драгдропа) - мало. Тогда как WM_SETCURSOR хватит и одного (да с бонусом: WM_NCHITTEST резервируется для решения иных задач).