Sunday, April 13, 2008

Why does ShowWindow cause a flicker?

When you call
ShowWindow(hwnd, SW_SHOW);
the WM_ERASEBKGND message is sent to the window procedure. If you are using your own custom paint routine, you probably don't need this. It will fill in your window with gray and then your paint routine will paint over it, but the gray fill appears briefly as a flicker. To prevent this, just override the WM_ERASEBKGND message handler.
case WM_ERASEBKGND:
return FALSE;

Friday, April 4, 2008

Why does my application fail when run on computers that don't have Visual Studio installed?

If you get an error message like "The application failed to initialize properly (0xc0150002)" when you try to run your application on a computer that doesn't have Visual Studio installed, it is probably because the proper C runtime DLLs are missing on that computer. This is one of the trickier aspects of using Microsoft's development tools because you need to have access to the same version of the DLLs that you linked with. So if you link dynamically to the C runtime library, you will have to either include the C runtime DLLs with your installer or provide a way for users to obtain the propert DLLs. To me this seems like a bad idea for most programs because it is rare that a program will use all that many functions in the runtime library. So for many cases it is probably more efficient to statically link the C runtime library using /MT on the command line instead of /MTD. This will usually yield binaries that are smaller than the combined size of the dynamically linked binary and the DLL file. Static linking will ensure that your program will run even without access to any DLLs.

Thursday, April 3, 2008

How do I send trace messages to the debug console in Visual Studio?

If you are not using MFC or ATL then there are some basic macros in crtdbg.h that allow you to write to the debug console in Visual Studio. The only problem is that they are not very user friendly - you have to use a different macro depending on how many parameters you have in your formatted string. I suspect that the reason behind this is that prior to the C99 specification there was no support for variadic macros. However, now that almost all compilers are C99 compliant, it is probably worth using a more convenient trace command for debugging purposes. The following macro works just like printf except that it sends its output to the debug console.
#include <stdio.h>
#include <crtdbg.h>
#define TRACE(...) \
do{ \
char *__trace = NULL; \
int len = 1+_scprintf(__VA_ARGS__); \
__trace = (char*)malloc(len*sizeof(char)); \
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG); \
sprintf_s(__trace, len, __VA_ARGS__); \
_RPT0(_CRT_WARN, __trace); \
if(__trace != NULL) \
free(__trace); \
} while(0)
This uses the do-while trick so that the calling syntax includes a trailing semicolon. This will only work when you compile with the debug version of the C runtime libraries (/MTd for example).

Wednesday, April 2, 2008

How do I disable font anti-aliasing (font smoothing) for a window?

This can be accomplished by creating a font with the NONANTIALIASED_QUALITY flag in the fdwQuality parameter. Then set the font by sending the WM_SETFONT message.
void DisableFontSmoothing(HWND hwnd)
{
HFONT font;

font = CreateFont(10, 0, 0, 0, FW_NORMAL, FALSE, FALSE, 0,
ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
NONANTIALIASED_QUALITY, DEFAULT_PITCH | FF_DONTCARE,
"MS Sans Serif");
SendMessage(hwnd, WM_SETFONT, (LPARAM)font, 0);
}
Be sure that you do not delete the font or else it will revert back. If you do not know what the font parameters will be at compile time, then you could modify this function to use WM_CHOOSEFONT_GETLOGFONT and WM_CHOOSEFONT_SETLOGFONT messages with a command to set the NONANTIALIASED_QUALITY flag in between.

Monday, March 31, 2008

How do I fix the problem where tooltips appear under the taskbar?

There is a bug in several versions of Windows that causes notification area tooltips to appear under the taskbar, obscuring them from view. The problem can be reproduced by the following procedure: open the start menu, select All Programs, right click on any program, press Open. This problem is documented in Microsoft's Knowledge Base, MS KB 912650. It seems that Microsoft has not had the time to make a patch to fix this bug yet. Their recommendation is to log off and log back on (terrible solution). You can use the following code as a hack in your programs until a bugfix is released.
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
char class[32];

GetClassName(hwnd, class, sizeof(class)/sizeof(char));
if(strcmp(class, "tooltips_class32") == 0)
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE);
return TRUE;
}
Then after showing a notification area tooltip, call
EnumWindows(&EnumWindowsProc, 0);
This code scans through all top-level desktop windows, checks if they are tooltip windows, and sets the tooltips to be always on top.

Sunday, March 30, 2008

Why are tabstops not working in my modeless dialog box?

The Microsoft Knowledge base has an article explaining this issue MS KB 71450. I do not know why they didn't decide to put tab functionality in the default dialog procedure. Instead you must keep track of which dialog box is active and call IsDialogMessage inside your message pump to process tab messages.
while(GetMessage(&msg, NULL, 0, 0))
{
if(!hDlgCurrent || !IsDialogMessage(hDlgCurrent, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}

How do I get rid of the ding that occurs when pressing enter on a TreeView control?

This can be easily fixed by overriding the default behavior of the WM_CHAR message. First subclass the control's window procedure using SetWindowLongPtr, then inside the new procedure use the following.
switch(message)
{
...
case WM_CHAR:
return 0;
...
}