zouhuidong / HiEasyX

HiEasyX 是基于 EasyX 的扩展库,支持创建多窗口、透明抗锯齿绘图、系统 UI 组件等等。
MIT License
114 stars 21 forks source link

getmessage_win32函数会导致程序无法正常退出 #28

Open lkm77 opened 1 year ago

lkm77 commented 1 year ago

以下是相关代码

ExMessage getmessage_win32(BYTE filter, HWND hWnd)
{
    while (!IsNewMessage(filter, hWnd)) HpSleep(1);
    ExMessage msg = GetNextMessage(filter, hWnd);
    RemoveMessage(hWnd);
    return msg;
}
bool IsNewMessage(BYTE filter, HWND hWnd)
{
    for (auto& element : GetMsgVector(hWnd))
        if (filter & GetExMessageType(element))
            return true;
    return false;
}
std::vector<ExMessage>& GetMsgVector(HWND hWnd)
{
    static std::vector<ExMessage> vec;
    int index = GetWindowIndex(hWnd);
    if (IsAliveWindow(index))
    {
        return g_vecWindows[index].vecMessage;
    }
    else
    {
        vec.clear();
        return vec;
    }
}

如果把窗口销毁,GetMsgVector会一直返回空的消息容器,getmessage_win32会一直循环,导致无法判断窗口存在,程序无法退出.

void RegisterExMessage(int indexWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    // 记录消息事件
    switch (msg)
    {
        // EM_MOUSE
    case WM_MOUSEMOVE:
    case WM_MOUSEWHEEL:
    case WM_LBUTTONDOWN:
    case WM_LBUTTONUP:
    case WM_LBUTTONDBLCLK:
    case WM_MBUTTONDOWN:
    case WM_MBUTTONUP:
    case WM_MBUTTONDBLCLK:
    case WM_RBUTTONDOWN:
    case WM_RBUTTONUP:
    case WM_RBUTTONDBLCLK:
    {
        ExMessage msgMouse = {};
        msgMouse.message = msg;
        msgMouse.x = GET_X_LPARAM(lParam);
        msgMouse.y = GET_Y_LPARAM(lParam);
        msgMouse.wheel = GET_WHEEL_DELTA_WPARAM(wParam);
        msgMouse.shift = LOWORD(wParam) & 0x04 ? true : false;
        msgMouse.ctrl = LOWORD(wParam) & 0x08 ? true : false;
        msgMouse.lbutton = LOWORD(wParam) & 0x01 ? true : false;
        msgMouse.mbutton = LOWORD(wParam) & 0x10 ? true : false;
        msgMouse.rbutton = LOWORD(wParam) & 0x02 ? true : false;

        // 有滚轮消息时,得到的坐标是屏幕坐标,需要转换
        if (msgMouse.wheel)
        {
            POINT p = { msgMouse.x ,msgMouse.y };
            ScreenToClient(g_vecWindows[indexWnd].hWnd, &p);
            msgMouse.x = (short)p.x;
            msgMouse.y = (short)p.y;
        }

        g_vecWindows[indexWnd].vecMessage.push_back(msgMouse);
    }
    break;

    // EM_KEY
    case WM_KEYDOWN:
    case WM_KEYUP:
    case WM_SYSKEYDOWN:
    case WM_SYSKEYUP:
    {
        // code from MSDN
        WORD vkCode = LOWORD(wParam);                                 // virtual-key code
        WORD keyFlags = HIWORD(lParam);
        WORD scanCode = LOBYTE(keyFlags);                             // scan code
        BOOL isExtendedKey = (keyFlags & KF_EXTENDED) == KF_EXTENDED; // extended-key flag, 1 if scancode has 0xE0 prefix

        if (isExtendedKey)
            scanCode = MAKEWORD(scanCode, 0xE0);

        BOOL repeatFlag = (keyFlags & KF_REPEAT) == KF_REPEAT;        // previous key-state flag, 1 on autorepeat
        WORD repeatCount = LOWORD(lParam);                            // repeat count, > 0 if several keydown messages was combined into one message
        BOOL upFlag = (keyFlags & KF_UP) == KF_UP;                    // transition-state flag, 1 on keyup

        // 功能键:不区分左右
        // if we want to distinguish these keys:
        //switch (vkCode)
        //{
        //case VK_SHIFT:   // converts to VK_LSHIFT or VK_RSHIFT
        //case VK_CONTROL: // converts to VK_LCONTROL or VK_RCONTROL
        //case VK_MENU:    // converts to VK_LMENU or VK_RMENU
        //  vkCode = LOWORD(MapVirtualKeyW(scanCode, MAPVK_VSC_TO_VK_EX));
        //  break;
        //}

        ExMessage msgKey = {};
        msgKey.message = msg;
        msgKey.vkcode = (BYTE)vkCode;
        msgKey.scancode = (BYTE)scanCode;
        msgKey.extended = isExtendedKey;
        msgKey.prevdown = repeatFlag;

        g_vecWindows[indexWnd].vecMessage.push_back(msgKey);

        // 给控制台发一份,支持 _getch() 系列函数
        PostMessage(g_hConsole, msg, wParam, lParam);
    }
    break;

    // EM_CHAR
    case WM_CHAR:
    {
        ExMessage msgChar = {};
        msgChar.message = msg;
        msgChar.ch = (TCHAR)wParam;
        g_vecWindows[indexWnd].vecMessage.push_back(msgChar);

        // 通知控制台
        PostMessage(g_hConsole, msg, wParam, lParam);
    }
    break;

    // EM_WINDOW
    case WM_ACTIVATE:
    case WM_MOVE:
    case WM_SIZE:
    {
        ExMessage msgWindow = {};
        msgWindow.message = msg;
        msgWindow.wParam = wParam;
        msgWindow.lParam = lParam;
        g_vecWindows[indexWnd].vecMessage.push_back(msgWindow);
    }
    break;
    }
}

并且RegisterExMessage函数不会登记窗口销毁消息,无法通过处理销毁消息退出. 是否应该加一个判断窗口是否存在或是登记窗口销毁消息的操作呢?