如果不妥善处理,Windows API资源可能会导致内存泄漏。无论是否是这个问题,我都假设它是相关的。虽然我展示了我如何确定问题的来源,但我无法解决问题。
我使用Win32 API有两种类型的静态类控件,它在我的类中抽象出来:
Label
LinkLabel
问题:每当我添加这两个控件时,当我启用setFont()或setHoverColor()行时,Visual Studio 2017的诊断工具显示进程内存(MB)从3MB增加到11MB,最终我的GUI中的所有内容空间消失了 - 就像一些着名的书店一样,从存在中消失了。
此代码很好(3MB在Process Memory中保持相同的恒定速率):
// Linked Label
myLinkLabel.init("http://www.google.com", 50, 450);
myLinkLabel.setColor(0, 0, 255);
myLinkLabel.onClick(lbl_Click);
myLinkLabel.setFont("Arial", 40, true);
//lbl.setHoverColor(255, 0, 0);
// label
myLabel.init("A regular static label", 0, 0);
myLabel.setColor(0, 255, 0);
myLabel.setFont("Arial", 40);
//myLabel.setHoverColor(255, 0, 0);
下一个代码取消注释最后一行。将鼠标悬停在myLabel上并显示红色突出显示颜色后,Process Memory的3MB增加到7MB +。它坐了一会儿,然后上升到9MB +。所以,它有些不对劲。
// Linked Label
myLinkLabel.init("http://www.google.com", 50, 450);
myLinkLabel.setColor(0, 0, 255);
myLinkLabel.onClick(lbl_Click);
myLinkLabel.setFont("Arial", 40, true);
//lbl.setHoverColor(255, 0, 0);
// label
myLabel.init("A regular static label", 0, 0);
myLabel.setColor(0, 255, 0);
myLabel.setFont("Arial", 48);
myLabel.setHoverColor(255, 0, 0);
所以,让我们深入了解我的setHoverColor():
void Label::setHoverColor(const BYTE red, const BYTE blue, const BYTE green)
{
m_hoverColorEnabled = true;
m_hoverColor = RGB(red, green, blue);
}
好的,上面的代码没什么太惊人的了。这告诉我要看看WndProc。
此静态控件使用的事件是WM_SETCURSOR。
case WM_SETCURSOR:
{
HWND m_handle = (HWND)wParam;
// Label
for (int i = 0; i < frm.getLabelControlCount(); i++)
{
if (frm.getLabelControl(i).getHandle() == m_handle)
{
if (frm.getLinkLabelControl(i).isLink())
{
// Set hover color to link
if (frm.getLabelControl(i).isHoverColorEnabled())
frm.getLabelControl(i).setColor(frm.getLabelControl(i).getHoverColor());
// Update cursor to hand
SetClassLongPtr(frm.getLabelControl(i).getHandle(), GCLP_HCURSOR, (LONG_PTR)frm.getLabelControl(i).getHoverCursor());
}
}
else
{
// Set link to blue and use default arrow
if (frm.getLabelControl(i).isHoverColorEnabled())
frm.getLabelControl(i).setColor(0, 0, 255);
SetClassLongPtr(frm.getLabelControl(i).getHandle(), GCLP_HCURSOR,
(LONG_PTR)LoadCursor(NULL, IDC_ARROW));
}
}
在评论此部分代码时,进程内存保持不变为3MB。取消注释此部分时,进程内存会增加。所以,这是导致问题的主要代码。
这部分代码基本上是根据当前鼠标悬停状态更新标签的文本颜色。没有盘旋时它是蓝色的,当它盘旋时它是红色的。
setColor()是以下代码:
void Label::setColor(const COLORREF color)
{
m_foreColor = color;
setFont(m_fontName, m_fontSize, m_bold, m_italic, m_underlined);
}
还调用setFont()来更新它:
bool Label::setFont(const std::string &fontName, const int size, const bool bold,
const bool italic, const bool underlined)
{
DWORD dwItalic;
DWORD dwBold;
DWORD dwUnderlined;
SIZE linkSize;
dwItalic = (italic) ? TRUE : FALSE;
dwBold = (bold) ? FW_BOLD : FW_DONTCARE;
dwUnderlined = (underlined) ? TRUE : FALSE;
m_font = CreateFont(size, 0, 0, 0, dwBold, dwItalic, dwUnderlined, FALSE,
ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH | FF_SWISS, fontName.c_str());
SendMessage(m_handle, WM_SETFONT, WPARAM(m_font), TRUE);
// Calculate the correct width and height size
HDC hDC = GetDC(m_handle);
SelectFont(hDC, m_font);
GetTextExtentPoint32(hDC, m_text.c_str(), (int) m_text.length(), &linkSize);
setSize(linkSize.cx, size);
// Store font information
m_fontName = fontName;
m_fontSize = size;
m_bold = bold;
m_underlined = underlined;
m_italic = italic;
return true;
}
我的猜测是,对于创建字体并根据每个悬停重新创建字体需要进行大量更新。我的理由是除非再次设置字体,否则不会更新字体颜色。虽然我在不久的将来看到了这个空间,但我忘记删除这里的资源了吗?欢迎任何想法。很确定这也将解决LinkLabel问题。
答案 0 :(得分:4)
您的基本问题是您不断生成新字体而不会发布旧字体。
每次调用setfont时,都会分配并选择一种新字体。但是当您在HDC中选择NEW字体时,您永远不会清理旧字体。
SelectFont会返回您需要的以前选择的字体(除非它是一个股票字体)来执行DeleteFont。
此外,您在GetDC调用上有更大的资源泄漏 - getDC的MS文档建议您在完成使用后使用releaseDC。
据我了解,不需要重置字体只是为了重置颜色。