Preciso escrever uma exibição de lista que funcione com dados do proprietário, para Windows, em C. Com os dados fornecidos no momento da criação e sem o estilo OWNERDATA, tudo funciona corretamente.
assim que eu defino o sinalizador OWNERDATA na criação e escrevo o manipulador para a notificação LVN_GETDISPINFO, apenas o item principal funciona, os subitens estão todos errados. Eu depurei e, aparentemente, o Windows pede IDs de subitens completamente fora do intervalo e diferentes toda vez que eu executo. Eu escrevi este pequeno trecho para reproduzir este problema para ver se alguém poderia me ajudar com isso.
#ifndef UNICODE
#define UNICODE
#define _UNICODE
#endif
#include <Windows.h>
#include <CommCtrl.h>
#include <assert.h>
#include <malloc.h>
#include <stdio.h>
#include <stdbool.h>
#pragma comment(lib,"comctl32.lib")
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
static HWND MainWindowHandle;
LRESULT MainWindowProcedure(HWND WindowHandle, UINT Message, WPARAM wParam, LPARAM lParam)
{
static unsigned ColumnFormat[5];
static unsigned ColumnOrder[5];
static unsigned ColumnCount = 5;
switch (Message)
{
case WM_CREATE:
{
for (unsigned index = 0; index < 5; ++index)
{
ColumnFormat[index] = LVCFMT_WRAP;
ColumnOrder[index] = index;
}
break;
}
case WM_NOTIFY:
{
LPNMHDR Notification = (LPNMHDR)lParam;
switch (Notification->code)
{
case LVN_GETDISPINFO:
{
NMLVDISPINFO *DisplayInfo = (NMLVDISPINFO *)lParam;
if (DisplayInfo->item.mask & LVIF_COLFMT)
{
DisplayInfo->item.piColFmt = ColumnFormat;
DisplayInfo->item.cColumns = ColumnCount;
}
if (DisplayInfo->item.mask & LVIF_COLUMNS)
{
DisplayInfo->item.puColumns = ColumnOrder;
DisplayInfo->item.cColumns = ColumnCount;
}
if (DisplayInfo->item.mask & LVIF_TEXT)
{
_snwprintf(DisplayInfo->item.pszText, DisplayInfo->item.cchTextMax, L"%u - %u", DisplayInfo->item.iItem, DisplayInfo->item.iSubItem);
}
if (DisplayInfo->item.mask & LVIF_INDENT)
DisplayInfo->item.iIndent = 0;
if (DisplayInfo->item.mask & LVIF_STATE)
{
DisplayInfo->item.state = 0;
DisplayInfo->item.stateMask = 0;
}
DisplayInfo->item.mask |= LVIF_DI_SETITEM;
break;
}
}
break;
}
}
return DefWindowProc(WindowHandle, Message, wParam, lParam);
}
int wWinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPWSTR pWideCmdLine,
int nShowCmd
)
{
WNDCLASSEX UIWindowClass = { 0 };
if (UIWindowClass.cbSize == 0)
{
UIWindowClass.cbSize = sizeof(UIWindowClass);
UIWindowClass.style = CS_OWNDC | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
UIWindowClass.lpfnWndProc = (WNDPROC)MainWindowProcedure;
UIWindowClass.cbClsExtra = 0;
UIWindowClass.cbWndExtra = 0;
UIWindowClass.hInstance = GetModuleHandle(NULL);
UIWindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
UIWindowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
UIWindowClass.lpszMenuName = NULL;
UIWindowClass.lpszClassName = TEXT("MyClass");
if (RegisterClassEx(&UIWindowClass) == 0)
{
return -1;
}
}
INITCOMMONCONTROLSEX ICCE = { 0 };
if (ICCE.dwSize == 0)
{
memset(&ICCE, 0, sizeof(ICCE));
ICCE.dwSize = sizeof(ICCE);
ICCE.dwICC = ICC_LISTVIEW_CLASSES | ICC_STANDARD_CLASSES | ICC_TAB_CLASSES | ICC_TREEVIEW_CLASSES;
if (InitCommonControlsEx(&ICCE) == 0)
{
return -1;
}
}
DWORD Style = 0, ExStyle = 0;
ExStyle |= WS_EX_APPWINDOW;
Style |= WS_VISIBLE;
Style |= WS_CLIPSIBLINGS;
Style |= WS_CLIPCHILDREN;
HWND NewHWND = CreateWindowEx(
ExStyle,
TEXT("MyClass"),
TEXT("MainWindow"),
Style,
10, 10,
1800, 900,
NULL,
NULL,
GetModuleHandle(NULL),
NULL);
if (NewHWND == 0)
return -1;
Style = 0;
ExStyle = 0;
Style |= WS_TABSTOP;
Style |= WS_VISIBLE;
Style |= WS_CHILD;
Style |= WS_CLIPSIBLINGS;
Style |= WS_CLIPCHILDREN;
Style |= LVS_AUTOARRANGE;
Style |= LVS_SHOWSELALWAYS;
Style |= WS_BORDER;
Style |= LVS_OWNERDATA;
HWND ListViewHandle = CreateWindowEx(
ExStyle,
WC_LISTVIEW,
TEXT("ListView"),
Style,
10, 10,
1500, 800,
NewHWND,
NULL,
GetModuleHandle(NULL),
NULL);
if (ListViewHandle == NULL)
return -1;
ListView_SetItemCount(ListViewHandle, 20);
LVTILEVIEWINFO ViewInfo;
memset(&ViewInfo, 0, sizeof(ViewInfo));
ViewInfo.cbSize = sizeof(ViewInfo);
ViewInfo.cLines = 4;
ViewInfo.dwFlags = LVTVIF_AUTOSIZE;
ViewInfo.dwMask = LVTVIM_TILESIZE | LVTVIM_COLUMNS;
ListView_SetTileViewInfo(ListViewHandle, &ViewInfo);
ListView_SetView(ListViewHandle, LV_VIEW_TILE);
for (unsigned Index = 0; Index < 5; ++Index)
{
LVCOLUMN NewColumn;
memset(&NewColumn, 0, sizeof(NewColumn));
NewColumn.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
NewColumn.fmt = LVCFMT_LEFT;
NewColumn.cx = 120;
NewColumn.pszText = calloc(100, sizeof(TCHAR));
_swprintf(NewColumn.pszText, L"Column %u", Index);
NewColumn.iSubItem = Index;
ListView_InsertColumn(ListViewHandle, Index, &NewColumn);
}
bool ShouldQuit = false;
while (ShouldQuit == false)
{
MSG Message;
int Result = GetMessage(&Message, NULL, 0, 0);
if (Result <= 0)
return false;
TranslateMessage(&Message);
DispatchMessage(&Message);
}
return 0;
}
Este código me dá este resultado:
que claramente tem alguns ids de subitens muito errados para essas linhas extras. O que estou fazendo errado?
Não está explicitamente escrito na documentação, mas os campos
piColFmt
epuColumns
são alocados pelo chamador e precisam ser preenchidos pelo chamado. Em vez de:Você precisa fazer: