A. microsoft.public.vc.mfc, microsoft.public.mfc.database, and comp.lang.c++. There are actually several news groups under the microsoft.public.vc.* listing.
A. A handle is a 32-bit value (in win32) given to you by Windows to allow you to work with system resources. Some of the types of handles you will see in a Windows program are:
You setup and use system resources via their handles. For example, when displaying text, you can ask the system for a handle to a specific font, then 'select' (via the SelectObject function) that font handle, and the next TextOut function will output the text in that font.
A. A DeviceContext represents an area where you can output text or graphics. You can think of a Device Context as a canvas. When your program is asked to display the contents of a window, or print a report, in both cases you will be working with a Device Context. Device Contexts are also used with MetaFiles.
All of the GDI (Graphical Device Interface) functions need a DC (Device Context) to work against, and functions like LineTo or TextOut will need a handle to a Device Context as their first parameter.
The most common place you will be working with a Device Context is in response to a WM_PAINT message. For this message, you must create a DC by calling the BeginPaint function. Once you have the DC, you can output anything you like (windows will take care of things like child windows: buttons, check boxes, etc.). Once your done with the DC you release it by calling the EndPaint function.
You can create a DC at anytime by calling the GetDC function, permitting you to draw to a window whenever you want. When your done with a DC that you got with GetDC, you should call ReleaseDC to release it. But, keep in mind the following:
Q. I placed code in my program to output text (or draw anything), and it works, but if I minimize and maximize the program, then what I displayed is gone.
A. This normally happens because the code to do the output to the client area of the program is not in response to a WM_PAINT message. As part of the WM_PAINT process, the client area is normally cleared, and then the WM_PAINT is invoked. This means that anything placed on the client area by a message other than WM_PAINT is erased.
As a general rule, all output to the client area is done by the WM_PAINT message response. If you have data that is available only at a specific time, and not during the WM_PAINT message, then you should save that data somewhere so that WM_PAINT can retrieve it.
For example, imagine that you want to display the location of a mouse click. The WM_LBUTTONDOWN message will give you the coordinates of the click. But, if you display the coordinates on the WM_LBUTTONDOWN message, then the next time a WM_PAINT message is sent, that text will be cleared from the client area. A better approach would be to have the WM_LBUTTONDOWN message store the coordinates in a global variable, and then call the InvalidateRect function, which will trigger a WM_PAINT message. Now, in the WM_PAINT message, the handler gets the coordinates out of the global variable, and displays them.
A. A Metafile is a file that stores an image. Unlike Bitmap or JPEG files which store each pixel of an image, a MetaFile stores the Windows GDI commands need to re-display the file. Because of this storage method, Metafiles are very small, but they are not useful for photo-quality images.
When you create a metafile, you are given a Device Context to it. Now, any TextOut, LineTo, or anyother GDI functions you call will store information in the Metafile, they will not appear on screen. The information stored in the file is really just a list of the GDI functions you called, so that the file can be displayed by replaying the commands.
A metafile more accurately represents a macro in which graphics commands are played back, than a conventional image file.
Q. My program seems to lockup (or go recursively forever) in WM_PAINT (or in any specific message. Why?
A. One aspect of Windows programming that escapes some people at first, is that you can call functions in your program that generate a message. For example, the InvalidateRect function generates a WM_PAINT message. Now, if you were to call the InvalidateRect function, while you were processing a WM_PAINT message it would trigger another WM_PAINT message, which would in turn cause InvalidateRect to be called again, and so one. In otherwords, this would lead to a recursive calling problem.
You should try to avoid this problem by being familiar with the messages that function might invoke if you call it. However, if it turns out that you must perform this sort of recursion, you should try to put a flag somewhere to indicate that recursion is possible. For example:
int InFunc; // A global
case: WM_SomeMessage:
if( InFunc==0 )
{
InFunc=1;
// Some code that might cause WM_SomeMessage to be sent again
InFunc=0;
}
break;
Finally, a specific oddity to the WM_PAINT message is that you must call BeginPaint and EndPaint in the function to perform the painting. Part of the logic to BeginPaint is that it tells Windows that you have painted something. If you were to call GetDC to get a Device Context, instead of BeginPaint, then Windows would not know that you did your output, and it will call WM_PAINT again, and again, etc.
Q. What's the difference between DispatchMessage and SendMessage?
A. Very little actually. DispatchMessage is normally used inside a message loop of an application to send a message to a WndProc. SendMessage is normally used by your WndProc to send a message to a WndProc (possibly itself).
In a small test program, inside the message loop, I was able to replace:
With:
Inside the WndProc, I was able to replace:
with:
I can see the usage of SendMessage is easier in the WndProc, simply because you don't have to create the MSG structure and initialize it. The usage of DispatchMessage in the event loop is easier, because you only need to pass 1 parameter, not 4. But, besides the typing-savings benefit, the usage of the two functions in the message loop and the WndProc is 'the norm'. It's possible that DispatchMessage does further processing with Windows that I am unaware. But in the very least you should use the functions for their intended purpose, because future versions of Windows might make a clear distinction between the two. In other words, your program should be 'well-behaved', and follow the norm.
Q. What's the difference between PostMessage and SendMessage?
A. PostMessage and SendMessage take the same parameters, and eventually send a message to a WndProc. PostMessage will place the message in the message queue, while SendMessage will send it right to the WndProc, by-passing the queue.
You might want to call PostMessage to avoid recursion in the WndProc, or to allow Windows to properly handle the precedence of a message. Windows does not treat all messages as the same, certain messages are moved to the front of the queue (for priority), and some messages are removed from the queue automatically if there's already a message of the same type already in the queue.
Q. When I compile my program, I get
an error:unresolved external symbol_WinMain@16
Q. When I compile my program, I get an error:unresolved external symbol
_main
A. Both of these error messages are similar in cause. When you write a Windows program, the compiler provides you with a main function, and expects you write a WinMain. If you write a 'console' (text-based) program, the compiler expects you write a main function. WinMain is where a windows program starts execution, and main is where a console program begins exeution.
In the case where WinMain is undefined, the project has a target type of 'Windows', and you didn't write WinMain (maybe you really want a target type of 'console'?). In the case of main, the project type is 'console', and you didn't write main (maybe you really wanted a target type of 'Windows'?).
To determine what the project type is:
1) Open the project
2) Press ALT-F7, and the 'Project Settings' dialog will appear.
3) Click the 'C++' tab, in this dialog.
4) Examine the 'Prepocessor Definitions', near the middle of the dialog.
If, you see _WINDOWS here, then that means it's a Windows project.
If you don't see _WINDOWS here, then it means that it's not a Windows project.
When you first create a project in Visual C++, you should make a choice between Win32 Application, and Win32 Console Application. I don't know how to change a project type (Project Platform) after the project has been created. It's usually easier to just re-create the project, and copy the files you have changed into the new project.
Q. Why would a function like SelectObject (or any other function) return an error value?
A. A function in the GDI, or any Windows API failing, can usually be traced down to wrong parameters being passed to it. For example, the SelectObject might return NULL, if it were given a NULL or bad font handle. Check these values first. In otherwords, the error might have actually occured before this, but wasn't caught correctly.
If this isn't the case, it is possible that the program is running out of resources (though, SelectObject does not create any new resources). Make sure that any resources you create are properly released.
You can call the GetLastError function of the Windows API to determine exactly why a function failed. You'll have to display the error code returned by this function, and then look it up in the online help for exact meaning:
char ErrCode[32];
sprintf( ErrCode, "%lu", GetLastError() );
MessageBox( NULL, ErrCode, MB_OK );
Q. How do I change the color of a dialog/window?
A. You can control the background color of your main window, by specfiying the hbrBackground member of the WNDCLASS structure when you register the window class. If you want to be able to change the color on the fly (at the user's request for example), or in a dialog, then you need to respond to the WM_CTLCOLOR???? messages in your message loop. These messages are sent just prior to drawing the items in the window, and passes in the wParam parameter the HDC that will be used to draw the item. In response to the message, you should return the brush to be used for drawing. For example:
static HBRUSH hBrush;
switch( Message ) { case WM_CTLCOLORDLG: case WM_CTLCOLORSTATIC: case WM_CTLCOLORBTN: case WM_CTLCOLOREDIT: case WM_CTLCOLORLISTBOX: case WM_CTLCOLORSCROLLBAR: if( !hBrush ) hBrush=CreateSolidBrush( RGB(192,0,0) ); /Red SetBkColor( (HDC)wParam, RGB(192,0,0) ); SelectObject( (HDC)wParam, hBrush ); return( (LONG)hBrush);
...
}