I'm coding an app, using C++17 standards and graphical library MFC. I have two virtual classes, ViewerGet and ViewerSet, that both inherit from Viewer class, that inherits from CListCtrl class from MFC. My problem is about ViewerGet, built as such :
void ViewerGet::InitViewer(CWnd* pParent, CRect oWndRect)
{
if (!Create(WS_TABSTOP | WS_CHILD | LVS_REPORT | LVS_OWNERDATA, oWndRect, pParent, 0))
return;
// Set a Global Style + add tips
SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES | LVS_EX_INFOTIP | LVS_EX_LABELTIP);
ListView_SetExtendedListViewStyleEx(*pParent, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES);
// Columns Creation
LPTSTR lpszCols[] = { _T("Variable name"),_T("Variable path"),_T("Value read"),_T("Validity"),_T("Recording"),_T("Type"),0};
CRect rect;
GetWindowRect(&rect);
int columnSize[] = { int(rect.Width() * 0.3), int(rect.Width() * 0.45), int(rect.Width() * 0.12), int(rect.Width() * 0.07), int(rect.Width() * 0.03) };
LV_COLUMN lvColumn;
lvColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
lvColumn.fmt = LVCFMT_LEFT;
for (int x = 0; lpszCols[x] != NULL; x++)
{
lvColumn.pszText = lpszCols[x];
lvColumn.cx = columnSize[x];
InsertColumn(x, &lvColumn);
}
m_arrowImage.Create(IDB_LOGO_LIST, 24, 0, RGB(255, 255, 255));
SetImageList(&m_arrowImage, LVSIL_SMALL);
}
When I try to put data in my ViewerGet, I follow those steps :
- Select lines in yet another CListCtrl
- Right click to make pop-up window appear
- Click on the button "Add to ViewerGet" Then, the relevant lines are added to my ViewerGet. Up until now, everything is OK.
However, when I then want to select lines in ViewerGet, 3 possible behaviors :
- Everything works out normally (I can select, remove, check checkboxes...)
- The ViewerGet is instantly frozen (when I click on a line, it's not selected as it should)
- The ViewerGet starts out normally, but at one point (which one, I wasn't able to pinpoint it), it freezes again I noticed that when I minimise + maximise my window, the ViewerGet is refreshed, once. But no more after that. This does not happens with ViewerSet, the other child class, only with ViewerGet I don't think it's important, but ViewerGet is supposed to receive & refresh data every 50ms, received from a CAN bus. This does not seem important as the ViewerGet freeze happens even if I'm not receiving data, even if I have no CAN bus plugged in...
Here is the method called when chosing to add a line to the ViewerGet table :
void AppDlg::OnEditOnLeftTab()
{
m_oTabViewer.SetCurSel(0);
OnSelchangeTabViewer(NULL, NULL);
m_poViewGet->LockWindowUpdate();
EnterCriticalSection(database.GetMutex());
std::vector<IascVariable*> selVars = m_list.GetSelectedVariables();
for (IascVariable* var : selVars)
if (database.ReadEntryFor(var)==NULL)
database.AddReadEntry(new ReadEntry(var));
m_poViewGet->SetItemCount(database.ReadEntriesListCount());
LeaveCriticalSection(database.GetMutex());
}
Expected behavior : just to have my ViewerGet work normally, being refreshed when I need it (click to change selected lines, new value refreshed in relevant column of ViewerGet when CAN communication is OK...)
What I tried :
- Used several CListCtrl styles such as WS_CLIPCHILDREN
- Used LockWindow() and UnlockWindow() methods
- Used SetRedraw(FALSE) and SetRedraw(TRUE) methods
- Verified the data was updated in the background of the display
- Verified OnGetDispInfo notifications :
void Viewer::OnGetDispInfo(NMHDR* pNMHDR, LRESULT* pResult)
{
NMLVDISPINFO* plvdi = (NMLVDISPINFO*)pNMHDR;
if (plvdi->item.mask & LVIF_TEXT)
lstrcpyn(plvdi->item.pszText, CellContent(plvdi->item.iItem, plvdi->item.iSubItem), plvdi->item.cchTextMax);
if (plvdi->item.mask & LVIF_IMAGE)
{
plvdi->item.iImage = CellImage(plvdi->item.iItem, plvdi->item.iSubItem);
plvdi->item.mask |= LVIF_STATE;
plvdi->item.stateMask |= LVIS_STATEIMAGEMASK;
plvdi->item.state = INDEXTOSTATEIMAGEMASK(CheckboxContent(plvdi->item.iItem, plvdi->item.iSubItem));
}
*pResult = 0;
}
- Tried to force ViewerGet refresh with methods RedrawItems(item,item) (only one line) or even RedrawWindow() for full ViewerGet
- Change OnCustomDraw method :
void Viewer::OnCustomDrawBgColor(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMLVCUSTOMDRAW pLVCD = reinterpret_cast<LPNMLVCUSTOMDRAW>(pNMHDR);
*pResult = 0;
pLVCD->nmcd.rc.top += 7;
int nItem = pLVCD->nmcd.dwItemSpec;
int nSubItem = pLVCD->iSubItem;
// what we do next depends on the drawing stage we are processing
switch (pLVCD->nmcd.dwDrawStage)
(...) //other cases, for prepaint mainly
case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:
this->RedrawWindow();
break;
case CDDS_ITEMPOSTPAINT:;
this->RedrawWindow();
break;
}
}
EDIT : I may be wrong, but I don't think this is caused by deadlock. In my understanding, deadlocks would paralyze my ViewerGet, however it is still functional, it just... doesn't display want I want it to