SetWindowLong в CustomDraw вызывает необработанное исключение

Я вношу некоторые изменения в CSliderCtrl с помощью Custom Draw, элемент управления должен использоваться в диалоговом окне. Вот структура: В моей MessageMap у меня есть: ON_NOTIFY_REFLECT_EX(NM_CUSTOMDRAW, OnNMCustomdraw)

Метод OnNMCustomdraw выглядит следующим образом:

BOOL CCustomSliderCtrl::OnNMCustomdraw(NMHDR *pNMHDR, LRESULT *pResult)
{
    *pResult = CDRF_DODEFAULT;
    LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);

    switch(pNMCD->dwDrawStage)
    {
        case CDDS_PREPAINT:
        {
            //Dialogs don't receive CDRF_NOTIFYITEMDRAW notifcations by returning it as part of pResult, we must
            //use the following so we ensure we receive the msg
            SetWindowLong(pNMHDR->hwndFrom, DWL_MSGRESULT, CDRF_NOTIFYITEMDRAW);
            return TRUE;
        }
        case CDDS_ITEMPREPAINT:
            if(pNMCD->dwItemSpec == TBCD_CHANNEL)
            {
                ...SNIP...
                SetWindowLong(pNMHDR->hwndFrom, DWL_MSGRESULT, CDRF_SKIPDEFAULT);
                return TRUE;
            }
    }
    return FALSE;
}

Читая вокруг, я узнал, что вам нужно было использовать SetWindowLong для установки возвращаемого значения для пользовательского рисования, иначе ваш метод не всегда будет получать сообщение CDDS_ITEMPREPAINT. Однако при использовании SetWindowLong мое приложение никогда не получит CDDS_ITEMPREPAINT, поэтому мой слайдер выглядит как стандартный слайдер. Приложение вылетает при любом взаимодействии с ползунком, например, при наведении курсора на него или сворачивании и развертывании диалогового окна.

Я вырезал код TBCD_CHANNEL, так как он никогда не достигается.

При работе в режиме отладки происходит сбой в конце метода AfxUnlockGlobals в afxcrit.cpp. Вот трассировка стека: Обновление: с момента добавления отладочных символов сбой, похоже, обнаружен в mwthod CWnd :: DefWindowProc.

comctl32.dll!_TrackBarWndProc@16()  + 0x551 bytes   
user32.dll!_InternalCallWinProc@20()  + 0x28 bytes  
user32.dll!_UserCallWinProcCheckWow@32()  + 0xb7 bytes  
user32.dll!_CallWindowProcAorW@24()  + 0x51 bytes   
user32.dll!_CallWindowProcW@20()  + 0x1b bytes  
mfc90ud.dll!CWnd::DefWindowProcW(unsigned int nMsg=15, unsigned int wParam=0, long lParam=0)  Line 1043 + 0x20 bytes    C++
mfc90ud.dll!CWnd::WindowProc(unsigned int message=15, unsigned int wParam=0, long lParam=0)  Line 1756 + 0x1c bytes C++
mfc90ud.dll!AfxCallWndProc(CWnd * pWnd=0x0012fdbc, HWND__ * hWnd=0x000308fe, unsigned int nMsg=15, unsigned int wParam=0, long lParam=0)  Line 240 + 0x1c bytes C++
mfc90ud.dll!AfxWndProc(HWND__ * hWnd=0x000308fe, unsigned int nMsg=15, unsigned int wParam=0, long lParam=0)  Line 403  C++
mfc90ud.dll!AfxWndProcBase(HWND__ * hWnd=0x000308fe, unsigned int nMsg=15, unsigned int wParam=0, long lParam=0)  Line 441 + 0x15 bytes C++
user32.dll!_InternalCallWinProc@20()  + 0x28 bytes  
user32.dll!_UserCallWinProcCheckWow@32()  + 0xb7 bytes  
user32.dll!_DispatchClientMessage@20()  + 0x4d bytes    
user32.dll!___fnDWORD@4()  + 0x24 bytes 
ntdll.dll!_KiUserCallbackDispatcher@12()  + 0x13 bytes  
user32.dll!_NtUserDispatchMessage@4()  + 0xc bytes  
user32.dll!_DispatchMessageW@4()  + 0xf bytes   
mfc90ud.dll!AfxInternalPumpMessage()  Line 183  C++
mfc90ud.dll!CWinThread::PumpMessage()  Line 900 C++
mfc90ud.dll!AfxPumpMessage()  Line 190 + 0xd bytes  C++
mfc90ud.dll!CWnd::RunModalLoop(unsigned long dwFlags=4)  Line 4386 + 0x5 bytes  C++
mfc90ud.dll!CDialog::DoModal()  Line 584 + 0xc bytes    C++
SetSelection.exe!CSetSelectionApp::InitInstance()  Line 64 + 0xb bytes  C++
mfc90ud.dll!AfxWinMain(HINSTANCE__ * hInstance=0x00400000, HINSTANCE__ * hPrevInstance=0x00000000, wchar_t * lpCmdLine=0x00020a84, int nCmdShow=1)  Line 37 + 0xd bytes C++
SetSelection.exe!wWinMain(HINSTANCE__ * hInstance=0x00400000, HINSTANCE__ * hPrevInstance=0x00000000, wchar_t * lpCmdLine=0x00020a84, int nCmdShow=1)  Line 34  C++
SetSelection.exe!__tmainCRTStartup()  Line 578 + 0x35 bytes C
SetSelection.exe!wWinMainCRTStartup()  Line 403 C
kernel32.dll!_BaseProcessStart@4()  + 0x23 bytes

Итак, есть ли у кого-нибудь представление об этом вопросе? Если вам нужна дополнительная информация, просто дайте мне знать.


Обновление: я нашел работу на данный момент, вместо использования SetWindowLong я просто присваиваю результат pResult, а затем возвращаюсь. Я принудительно перерисовываю подэлементы, вызывая SetRangeMin (GetRangeMin (), TRUE);, не совсем элегантно, но работает.


person Andrew    schedule 13.04.2010    source источник
comment
Совет: чтобы улучшить трассировку стека, настройте сервер символов   -  person MSalters    schedule 13.04.2010
comment
Спасибо, я сейчас поиграю с этим.   -  person Andrew    schedule 13.04.2010
comment
Добавлена ​​лучшая трассировка стека, спасибо за подсказку.   -  person Andrew    schedule 13.04.2010


Ответы (1)


Вы звоните SetWindowLong не в то окно. Первый параметр SetWindowLong - это диалоговое окно, обрабатывающее сообщение, а не окно, отправившее сообщение. SetWindowLong(m_hWnd, DWL_MSGRESULT, CDRF_NOTIFYITEMDRAW);.

Ваш код долго меняет окно в окне отправителя, что в конечном итоге приводит к повреждению личных данных этого окна.

person Raymond Chen    schedule 22.08.2011