Contents
Introduction
In this tutorial I would like to show you how to create a custom Windows control (one of possible methods) and how to write MFC
front-end class for it.
Setting up tutorial environment
Launch Visual C++ and select File->New.... In appeared dialog box, choose MFC AppWizard (exe) and give the project an appropriate name. Let it be CustButtonDemo since we're going to compose a custom button control:

Then press OK button. Look at the screen: we currently have launched MFC AppWizard and we are requested to do the very first step. Since this is tutorial, not Ph.D. thesis, we'll choose the simplest thing here, viz: Dialog based:

Accept the default options in the dialog boxes for AppWizard Steps 1, 2, and 3 by clicking Next. Click Finish in the dialog box for MFC AppWizard � Step 4.

After completing all these operations we'll see such a thoughtful picture:

Delete the TODO: Place dialog controls here. static text from dialog template and save our new project (File->Save All).
Creating DLL for our control
Choose FileView in the workspace window and right-click the Workspace 'CustButtonDemo': 1 project(s) entry, like this:

Our old acquaintance must appear, I mean the New dialog box. This time choose Win32 Dynamic-Link Library from the project types list and give it appropriate name, in our case, CustButton:

Note that this new project is added into current (already existing) workspace, not into new one. Note also, that AppWizard will create folder for new project inside CustButtonDemo folder. After pressing the OK button the Win32 Dynamic-Link Library wizard should appear:

Leave default choice (An empty DLL project) as is and press the Finish button. We currently have created new empty DLL project inside CustButtonDemo workspace. Note that our freshly-created DLL project is automatically set as active project:

Now we're going to add to it, two simple but very important files. Choose Project->Add To Project->New... menu item. In the New dialog box that must appear, choose C/C++ Header File from the list of possible choices and give an appropriate new file name (CustButton in our case). Note that the .h file extension will be added automatically in this case.
Important
Change the Location field for the header file we're going to create now to be one level up, i.e. to be not in the C:\CustButtonDemo\CustButton, but in the C:\CustButtonDemo directory:

Repeat this simple technique to add to project another new file, this time a C source file:

Note that in this case we should add the .c extension explicitly (since we're going to work not with C++ but with 'plain' C language), otherwise, C++ source file would be created.
Switch to CustButton.h file. This file will be our coding starting point. Remember? We didn't write yet no one line of code, so stop clicking your mouse: it's time for serious business.
The CustButton.h file should be thought of as an interface of our visual control. It is the very place to store such information as our control's window class name, its window message definitions, control structures and so on.
Let's begin with window class name. Let it be CustButton
. No objections? OK, add the next lines to the header file:
#ifndef _CUST_BUTTON_H
#define _CUST_BUTTON_H
#include <windows.h>
#define CUST_BUTTON_CLASS_NAME "CustButton"
void InitCustButton(void);
#endif
Now it's time to fill the CustButton.c source file with useful and sensible information. First, we should include CustButton.h file, of course:
#include "CustButton.h"
Second, we should define the prototype of our control's window procedure. According to MSDN,
The WindowProc
function is an application-defined function that processes messages sent to a window. The WNDPROC
type defines a pointer to this callback function. WindowProc
is a placeholder for the application-defined function name.
To put it simple, WindowProc
is the heart and brain in every single bottle of any Windows visual control. This is the place where all decisions are made: what to show on the screen, how to respond to keyboard and mouse events and so on. Add the next line to the CustButton.c source file:
LRESULT CALLBACK CustButtonWindowProc(HWND hWnd,
UINT Msg, WPARAM wParam, LPARAM lParam);
Now, it's time to write the body of our custom button initialization procedure:
void InitCustButton(void)
{
WNDCLASSEX wc;
ATOM atom;
if (GetClassInfoEx(NULL, CUST_BUTTON_CLASS_NAME, &wc))
return;
wc.cbClsExtra = 0;
wc.cbSize = sizeof(WNDCLASSEX);
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = NULL;
wc.hIconSm = NULL;
wc.hInstance = NULL;
wc.lpfnWndProc = CustomButtonWindowProc;
wc.lpszClassName = MY_CONTROL_CLASS_NAME;
wc.lpszMenuName = NULL;
wc.style = CS_GLOBALCLASS;
atom = RegisterClassEx(&wc);
}
Our custom button window procedure:
LRESULT CALLBACK CustButtonWindowProc(HWND hWnd,
UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg) {
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hDC;
RECT rect;
BOOL bSuccess;
hDC = BeginPaint(hWnd, &ps);
bSuccess = GetClientRect(hWnd, &rect);
bSuccess = DrawFrameControl(
hDC,
&rect,
DFC_BUTTON,
DFCS_BUTTONPUSH
);
bSuccess = EndPaint(hWnd, &ps);
return 1;
}
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
Everybody knows that DLL is the thing that exports some functions. But our DLL will be an exception. We don't need to export any function. The only purpose of our DLL is to register our custom button's window class. Add to the CustButton project a new C source file, name it CustButtonDll.c, place it in C:\CustButtonDemo directory and add to it these lines:
#include "CustButton.h"
BOOL WINAPI DllMain(
HINSTANCE hinstDLL,
DWORD fdwReason,
LPVOID lpvReserved
)
{
if (fdwReason == DLL_PROCESS_ATTACH)
InitCustButton();
return TRUE;
}
When somebody loads this DLL (DLL_PROCESS_ATTACH
), this would implicitly initialize our custom button by registering its window class.
Important
Launch Project settings dialog (<Alt+F7> or Project->Settings) and change Output file name to "../Debug/CustButton.dll" for debug configuration and to "../Release/CustButton.dll" for release configuration. This assures that our .dll and .exe will be in the same directory.
Finally, compile CustButton DLL project.
Creating MFC wrapper class
Activate the MFC Application project that we have created in the beginning of the tutorial:

Launch MFC ClassWizard (<Ctrl+W> or View->ClassWizard) and press the Add Class button and choose New...:

In the New Class dialog that must appear, set class Name to CCustomButton
and Base class to generic CWnd
as shown below:

Open CustomButton.h file and include CustButton.h into it:
#include "CustButton.h"
Add the next line into CCustomClass
definition:
protected:
HMODULE m_hModule;
Open CustButton.cpp file. Our task here is to fill the constructor with... well... useful and sensible information. What could be sensible here? All our common sense is already included into CustButton.dll, so I think the constructor is the proper place to load this wonderful dynamic library:
CCustomButton::CCustomButton()
{
m_hModule = LoadLibrary(_T("CustButton.dll"));
ASSERT(m_hModule);
}
Including dynamic library unloading code into class destructor is a good idea also:
CCustomButton::~CCustomButton()
{
BOOL bSuccess;
bSuccess = FreeLibrary(m_hModule);
ASSERT(bSuccess);
}
We already passed the most complicated and painful phases of our work. The rest is dessert...
Open dialog resource, insert custom control and set its properties as shown below:

Open CustButtonDemoDlg.h header file and include our custom button MFC class definition:
#include "CustomButton.h"
Insert custom button variable into CCustButtonDemoDlg
class definition:
CCustomButton m_custButton;
Finally, run the application and see such a picture:

Cool isn't it?
To be continued...