无法从所有者绘制的组合框中获取itemData

时间:2017-01-22 12:58:00

标签: winapi

我有一个用CBS_OWNERDRAWFIXED创建的所有者绘制的组合框,没有 CBS_HASSTRINGS

这个组合框应该显示正在运行的进程的顶级窗口列表。我在名为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_GETITEMDATACB_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;
};

1 个答案:

答案 0 :(得分: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_PTRlpdis->itemID == -1