2017-01-22 3 views
-1

У меня есть нарисованная владельцем combobox, созданная с CBS_OWNERDRAWFIXED и безCBS_HASSTRINGS.Невозможно получить itemData от нарисованного владельцем combobox

Это поле со списком должно отображать список окон верхнего уровня запущенных процессов. Я сохраняю соответствующую информацию об этих окнах (значок, заголовок, дескриптор) в классе с именем RunningProcess. Это код, который заполнит выпадающий:

void populateProcessList(HWND combobox) { 
    SendMessage(combobox, CB_RESETCONTENT, 0, 0); 

    std::vector<RunningProcess*> topLevelWindows = RunningProcesses::enumerateTopLevelWindows(); 
    for (int index = 0; index < topLevelWindows.size(); index++) { 
     RunningProcess *proc = topLevelWindows[index]; 
     SendMessage(combobox, CB_ADDSTRING, 0, (LPARAM)proc); 
    } 
} 

MSDN documentation говорит:

Если создать поле со списком с стилем владельца нарисованным, но без CBS_HASSTRINGS стиля, значение параметра lParam хранится как данные элемента, а не строка, на которую он указывает. Данные элемента можно получить или изменить, отправив сообщение CB_GETITEMDATA или CB_SETITEMDATA.

Теперь, когда я захватить WM_DRAWITEM сообщение, я использую этот фрагмент кода, чтобы получить RunningProcess объект и использовать данные внутри

LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam; 
RunningProcess *proc = (RunningProcess*)lpdis->itemData; 

Очевидно, что отладчик показывает, что память не может быть прочитана, потому что в противном случае я здесь не просили бы о помощи!

Не могли бы вы мне помочь? Пожалуйста, скажите мне, есть ли что-то еще для того, чтобы лучше понять мою проблему!

P.S. Вот enumerateTopLevelWindows функции и некоторые из его зависимостей:

BOOL RunningProcesses::processWindows(HWND window, LPARAM lParam) { 
    std::vector<RunningProcess*>& windows = *(std::vector<RunningProcess*>*)lParam; 

    TCHAR windowTitle[260]; 
    HICON windowIcon; 

    GetWindowText(window, windowTitle, 260); 
    windowIcon = RunningProcesses::getAppIcon(window); 

    windows.push_back(new RunningProcess(window, windowTitle, windowIcon)); 
    return TRUE; 
} 

std::vector<RunningProcess*> RunningProcesses::enumerateTopLevelWindows() { 
    std::vector<RunningProcess*> windows; 
    BOOL ret = EnumWindows(RunningProcesses::processWindows, reinterpret_cast<LPARAM>(&windows)); 

    return windows; 
} 

HICON RunningProcesses::getAppIcon(HWND window) { 
    HICON iconHandle = (HICON)SendMessage(window, WM_GETICON, ICON_SMALL2, 0); 
    if (iconHandle == nullptr) 
     iconHandle = (HICON)SendMessage(window, WM_GETICON, ICON_SMALL, 0); 
    if (iconHandle == nullptr) 
     iconHandle = (HICON)SendMessage(window, WM_GETICON, ICON_BIG, 0); 
    if (iconHandle == nullptr) 
     iconHandle = (HICON)GetClassLongPtr(window, GCL_HICON); 
    if (iconHandle == nullptr) 
     iconHandle = (HICON)GetClassLongPtr(window, GCL_HICONSM); 

    if (iconHandle == nullptr) 
     return nullptr; 

    return iconHandle; 
} 

RunningProcess класса следующим образом:

class RunningProcess { 
public: 
    RunningProcess(HWND hWnd, TCHAR* windowTitle, HICON windowIcon) { 
     m_hWnd = hWnd; 
     lstrcpy(m_windowTitle, windowTitle); 
     m_windowIcon = windowIcon; 
    } 
    ~RunningProcess(); 

    const TCHAR* getTitle() const { return m_windowTitle; } 

    const char* getTitleMb() const { 
     unsigned bufferLen = lstrlen(m_windowTitle); 
     char *mbTitle = new char[bufferLen + 1]; 
     wcstombs(mbTitle, m_windowTitle, bufferLen + 1); 

     return mbTitle; 
    } 
    const HWND getHandle() const { return m_hWnd; } 
    const HICON getIcon() const { return m_windowIcon; } 

private: 
    HWND m_hWnd; 
    TCHAR m_windowTitle[260]; 
    HICON m_windowIcon; 
}; 
+0

Предположительно, эти объекты больше не существуют. Совсем не очевидно, как вы управляете жизнью. Мы не видим enumerateTopLevelWindows. –

+0

'enumerateTopLevelWindows' возвращает этот' std :: vector', я могу опубликовать его также ... – Victor

+0

Требуется [mcve]. Я могу видеть, что возвращает функция, но я не вижу, как управление жизнью. –

ответ

1

вы не проверить lpdis->itemID для -1 значения. конечно, вы потерпите крах в этом случае. Ваш код должен быть, как это

PDRAWITEMSTRUCT lpdis = (PDRAWITEMSTRUCT) lParam; 
if (lpdis->itemID == -1) 
{ 
    // assert (lpdis->itemData == MAXULONG_PTR); 
} 
else 
{ 
    RunningProcess *proc = (RunningProcess*)lpdis->itemData; 
} 

общих правила том, как отлаживать эти случаи: в вашем RunningProcess конструкторе и деструкторе добавить DbgPrint("%s<%p>\n", __FUNCTION__, this); для просмотра адреса всех объектов, созданных и уничтоженных. и сравните lpdis->itemData при сбое с этими адресами - и вы просто просматриваете - вы уже удаляете объект или lpdis->itemData недействительны (никогда не указывайте ни на какой RunningProcess даже удален). в вашем случае я уверен, что lpdis->itemData == MAXULONG_PTR и lpdis->itemID == -1