Thursday, September 3, 2009

The Mysterious Missing Attribute

Copyright © 2009, Steven E. Houchin

Something about my XP system has been driving me crazy for a long time. I use Visual Source Safe for source control of my development projects on. VSS makes use of Windows’ Read Only file attribute to prevent modification of source-controlled files in a project’s working directory. When a file is checked out of VSS, that attribute is cleared, and the user can then change the file. When checked back in, Read Only is set again.

So, what was my problem? It’s this: the Read Only attribute on those source-controlled files (and others) would simply disappear periodically. I’d have to go through all my files and reassert Read Only by hand. I looked into a number of causes: that VSS was doing it, or Visual Studio; maybe it was compiling the files over a network share; maybe it was my anti-virus software.

Then I stumbled across the cause: backing up the files to a CD via Windows Explorer. It seems that somebody in Redmond Land decided it would be a clever idea to clear the Read Only attribute for all files burned to a CD. When I searched the web for others with this problem, I actually saw the opposite complaint: that files retained their R/O attributes on a CD. Okay, so what? The CD is … wait for it … wait for it … READ ONLY!

Maybe there is some obscure Windows setting that will stop this behavior on my system. Let me know if you find one. In the meantime, I now have to first copy my files into a zip file, then back up the zip – a real pain.

So, call me crazy. This problem has certainly driven me mad.

Monday, April 27, 2009

Setting a Win32 Control's Font and Sizing It to Fit the Text

Copyright © 2009, Steven E. Houchin
In my latest application, I have a Static control that I use as a label at the top of a rectangular box. I wanted to change the font, then resize the control to fit the text exactly. First, I needed to set the font. This is done by initializing a LOGFONT structure for the desired font family and size. The code below speicifies the minimum LOGFONT fields necessary:
LOGFONT lf;
ZeroMemory(&lf, sizeof(LOGFONT));
lf.lfHeight = 12;
_tcscpy(lf.lfFaceName, _T("MS Sans Serif"));
Now that we have a LOGFONT, a Win32 font object needs to be created and associated with the control:
// the LOGFONT must have some valid data in it
HFONT hFont = CreateFontIndirect(&lf);
if ((HFONT)0 != hFont)
{
     SetWindowFont(hCtrl, hFont, TRUE);
}
The SetWindowFont call is really a macro that expands into a call to SendMessage that specifies the WM_SETFONT message. At this point, when the control is redrawn, it will use the new font.
Now, we need to resize the control so it fits exactly the text it contains. Let's assume the variable lpszText points to our null-terminated text string that the Static control already displays. We must call the Win32 GetTextExtentPoint32 function to get the dimensions of the text. This function requires the device context (DC) of the control. And, to make sure we're getting the proper dimensions, our new font must be selected into the device context.
HDC hdc = GetDC(hCtrl); // get the static control's DC
HFONT hfOld = reinterpret_cast<hfont>(SelectObject(hdc, hFont));
DeleteObject(hfOld);    // free the old font handle

// measure the text height and width
size_t iLen = _tcslen(lpszText);
SIZE s;
if (GetTextExtentPoint32(hdc, m_pszLabelText, static_cast<int>(iLen), &s))
{
     // control's x,y position set by CreateWindow
     POINT p = this->ptControlOrigin;
     MoveWindow(hCtrl, p.x, p.y, s.cx, s.cy,
     FALSE /* no repaint now */);
}
ReleaseDC(hCtrl, hdc); // free the DC
That completes the task. We've changed the control's font to 12 point "MS Sans Serif" and have resized the control to fit the control's text string exactly. If the control's text string is changed, then the calls to GetTextExtentPoint32 and MoveWindow must be repeated for the new string's length.