Creating a no-VCL Windows application
by Kent Reisdorph
In the article “Working with Windows messages”, I mentioned the fact that writing Windows applications without the benefit of a class library is tedious. This is certainly true. You may, however, need to write a straight C or C++ Windows application using C++Builder. One reason may be that you need the smallest possible executable size. Or possibly you are forced to write straight C/C++ Windows programs by mandate of some higher power (your boss, for example). The good news is that you can easily create a Windows project that doesn’t require the use of the VCL.
The code in Listing A is a straight C “Hello World” Windows application. This application compiles to about 50K. Contrast this with a do-nothing VCL application, which compiles to about 350K.
C++Builder 1
Creating a straight C++ Windows application in C++Builder 1 requires a bit more work than for later versions of the compiler. These are the steps you must perform:
Create a new application.
Remove the main form using the “Remove File From Project” button on the toolbar.
Select View | Project Source from the main menu.
Remove the include for VCL.H and replace with WINDOWS.H.
Remove the USERES line.
Choose View | Project Makefile from the main menu. In the project makefile on the ALLLIB line, remove vcl.lib and replace cp32mt.lib with cw32mt.lib. This prevents the linker from pulling in unnecessary code and reduces the final executable by about 70K.
Write your code.
The C++Builder 1 IDE doesn’t allow you many compiler options so you will have to accept a C++ application with the overhead that comes with it. Put another way, C++Builder doesn’t allow you to create a Windows GUI application in straight C.
C++Builder 3 and 4
With C++Builder 3 and 4, creating a standard Windows GUI application gets easier. The steps are relatively few:
Choose File | New from the main menu. The Object Repository is displayed.
Double click the Console Wizard icon.
In the Console Wizard dialog box, select Window (GUI) from the Window Type section. Be sure the option to build with the VCL is not checked and click the Finish button.
Write your code.
Here again, you don’t have a lot of control over project options, but creating the initial project is fairly simple.
C++Builder 5
C++Builder 5 gives you the most flexibility in how you create your Windows GUI application. The steps are the basically the same as for C++Builder 4, but the Console Wizard gives you a couple of extra options. Most notably, you can elect to create an application that uses C only, resulting in a slightly smaller executable. You can also choose whether or not you want to use multi-threading. The C++Builder 5 Console Wizard dialog box is slightly different than in previous versions, so you must uncheck the Console Application option to create a GUI application.
Conclusion
Given the choice, you will likely opt to write Windows programs using the VCL. However, for those times when you need to write a Windows application the old fashioned way, it is good to know that you can do so with C++Builder.
Listing A: Code for a C “Hello World” Application
#include <windows.h>
#pragma hdrstop
LRESULT FAR PASCAL _export
WndProc(HWND, UINT, WPARAM, LPARAM);
int PASCAL WinMain(
HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmd, int nCmdShow)
{
static char AppName[] = "HelloWorld";
HWND hwnd;
MSG msg;
WNDCLASS wndclass;
if (!hPrevInstance)
{
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = (WNDPROC)WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon =
LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground =
(HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName = 0;
wndclass.lpszClassName = AppName;
RegisterClass(&wndclass);
}
hwnd = CreateWindow(AppName,
"Hello World",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hwnd, SW_NORMAL);
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT FAR PASCAL _export
WndProc(HWND hwnd,
UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_PAINT :
{
char text[] = "Hello World!!";
PAINTSTRUCT ps;
BeginPaint(hwnd, &ps);
TextOut(ps.hdc, 20, 20, text, 13);
EndPaint(hwnd, &ps);
break;
}
case WM_DESTROY : {
PostQuitMessage(0);
return 0;
}
default:
return DefWindowProc(
hwnd, message, wParam, lParam);
}
return 0;
}