I'm enjoying this discussion more than I ought to be. I've learned a few things. For one, from Brewbuck...
Nobody should be using MFC or Win32 directly any more. It's arcane and doesn't expose the full feature set of Windows in a usable way. I wouldn't use C++ in any form for UI code on Windows, it's just going against the current for no good reason.
And from Elysia...
I know of no good WYSIWYG GUI library for C++.
and...
That's why I suggested C#, because there's just no good library out there that is good and isn't a hundred megs. I'd still choose a framework if I had to work with C++, though. Better to have bulk and garbage than reinventing the wheel, unless you have a hard requirement that prevents you from using it.
So that's what its come to in the C++ world then? Don't even use it anymore! Move to another programming language! But if you absolutely must, use some garbage framework that takes up a couple hundred megabytes!
I'll tell you what the problem is people, and it started a long, long time ago. It started when you all blindly and without question accepted this, which takes about 128 typed characters and compiles to about 457 KB on Windows with my relatively recent GCC C++ compiler...
Code:
#include <iostream> // compiles to 457 k with C++ compilation
using namespace std;
int main()
{
string strHello("Hello, World!");
cout << strHello << endl;
return 0;
}
...to this, which takes about 85 keystrokes to make and compiles to about 6 k...
Code:
#include <cstdio> // compiles to 6 k with C++ compilation
int main()
{
printf("Hello, World!\n");
getchar();
return 0;
}
Once you all made the decision that the top program, which takes one and a half times more typing and is 76 times larger, is somehow superior to the bottom program, then it was only a matter of time for things to run their course and arrive at the point we've now reached where some of the best minds in C++ forums tell other users that the language isn't even worth using anymore. Try something else.
This issue with C++ isn't something unknown outside of traditional C++ circles. Users of other programming languages poke fun at C++ coders all the time for the things that they do and tolerate. Several years back well known compiler writer Bob Zale (Borland leased his DOS Basic compiler and marketed it under the name TurboBasic) made something of a 'stir' when he included his #Bloat metastatement in his 32 bit PowerBASIC programming language. His documentation on #Bloat looks like so...
Code:
#BLOAT metastatement
Purpose Artificially inflate the disk image size of a compiled program.
Syntax #BLOAT size_expression
Remarks #BLOAT allows the creation of artificially bloated program files on
disk, in order to match or exceed that generated by competing
"BloatWare" compilers. #BLOAT does not affect the memory image size
(running size) of a compiled program.
size_expression The size_expression parameter is a simple Long-integer expression
that specifies the total desired size of the compiled program’s disk
image, but is ignored if it is smaller than the actual program size.
#BLOAT uses sections of the actual compiled code to fill and
obfuscate the portion added to the file.
While #BLOAT adds no true merit to the technical efficiency of the
compiled code, there are a number of reasons for its use, including:
1) To allow "BloatWare" programmers to feel more comfortable when using PowerBASIC.
2) To impress project leaders/managers with the volume of executable code created.
3) To allay the fears of uninformed customers who may mistakenly infer that "such tiny programs
couldn't possibly do everything that..."
4) To make certain versions of a program more readily identifiable simply by examining the size of the
file on disk.
5) To improve convolution of the contents of the executable disk image, because the bloat region
appears to contain executable code.
See Also #COMPILE, #OPTIMIZE
Example #BLOAT 1024 * 1024 * 4 ' Create a 4 MB EXE file
So in my opinion you've killed it people. Its your fault. In my particular case I'm only thankful that I somehow saw through it early on and didn't abandon the language like a lot of others had. As a matter of fact, I did abandon it for a number of years back around 2000 or so. While I had been a C, BASIC, and Visual Basic coder for a long time I eventually taught myself C++ and then tried MFC. I was so completely turned off by MFC I abandoned the language and went back to C, Visual Basic, and later PowerBASIC. But for a number of years it just nagged at me that I might have made a mistake. Not about MFC but about C++. In other words, the language was so good, wasn't there a way to use it without having to endure horrible bloated libraries?
So to make a long story short the answer to that question is yes, its possible. The figures I previously gave on one of my major programs with 20,000+ lines of code being less than 100k isn't a lie. But it takes radical surgery to do it. The entirety of the C++ Standard Library has gotta go. Class Frameworks? Don't even think about it! It took me years really to write/debug all the library code needed for the real world applications I do. I had to create my own string class. I still periodically work on that. C++ has always had non-existant or poor dynamic multidimensional array capabilities. And I needed that very much for the work I do. So I developed my own templated multi-dimensional array class after the BASIC model. I could go on but I believe I've made my point.
You might be thinking, why didn't you just use another language that had the features you needed? Well, as a matter of fact, I did, partly. For Windows desktop/laptop applications I coded with PowerBASIC, but all those applications I coded strictly Win32 Api SDK style exactly like in Charles Petzold's famous "Programming Windows" books. But a big part of my work responsibilities involved coding handheld data collector applications running Windows CE. And in that world involving hardware with limited RAM and storage capacity C without Class Frameworks was still the way to go. And PowerBASIC didn't make any Windows CE compilers. So I suppose that's my official answer as to why I stayed in the C/C++ ecosystem. But my real answer is that I'm a programming junkie and I just really liked the C and C++ languages!
But it had to be my way or the highway in terms of the way I coded things. No C++ Standard Library crap, no 'using namespace std' crap, no Class Frameworks, and no bloatware.
In terms of Elysia's statement...
I know of no good WYSIWYG GUI library for C++.
...I suspect that's true, and its always been a wonderment to me why not. In the PowerBASIC programming community, which is much, much smaller than the C++ one, there have always been a lot of third party addon products to the language of this nature. And several of them at least auto-generate straight SDK Win Api code, which results in very small executables. And these add on products operate much like Visual Studio with its Visual Basic and C# where you have a 'Toolbox' and visually drag controls onto a Form, and the editors auto-generate the 'event procedures' where you can write your code. Here are links to two of them...
Phoenix Visual Designer
PlanetSquires Software - Company
I have them both and they are excellent. I really don't use them much though because I like to write my own code, if you all haven't figured that out already! But I wanted to support the two coders who created these products, because they are both top notch coders.
But getting back to C++ coding of GUIs, and Class Frameworks, lets take a look at about the most basic Win32 GUI program I can come up with. And then I'll do it with classes. We'll make our own Class Framework, and see just what that buys us. It doesn't even draw "Hello, World!", and it looks like so...
Code:
#include <windows.h> // 7168 bytes memory image, 8192 bytes on disk
LRESULT CALLBACK fnWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
}
return (DefWindowProc(hwnd, msg, wParam, lParam));
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
char szClassName[]="Form1";
WNDCLASSEX wc={};
MSG messages;
HWND hWnd;
wc.lpszClassName = szClassName;
wc.lpfnWndProc = fnWndProc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.hbrBackground = (HBRUSH)COLOR_BTNSHADOW;
wc.hInstance = hInstance;
RegisterClassEx(&wc);
hWnd=CreateWindowEx(0,szClassName,szClassName,WS_OVERLAPPEDWINDOW,200,175,320,200,HWND_DESKTOP,0,hInstance,0);
ShowWindow(hWnd,iShow);
while(GetMessage(&messages,NULL,0,0))
{
TranslateMessage(&messages);
DispatchMessage(&messages);
}
return messages.wParam;
}
I'm seeing 7168 bytes memory image and 8192 bytes on disk with my circa 2008 Windows Mingw compiler. If that file is named Main.cpp you can compile it like so with Mingw...
C:\Code\CodeBlks\Forms\Form1B>g++ Main.cpp -oForm1.exe -mwindows -m64 -Os -s
...for x64, or this with MSVC...
C:\Code\CodeBlks\Forms\Form1B>cl Main.cpp user32.lib /O1 /Os /MT /GA /FeForm1.exe
...and that compiles to like 39 K with VC 9 that came with Visual Studio 2008. Just as an aside, here is what the exact same thing looks like in PowerBASIC, and size-wise it beats even my GCC 4.4 from about 2008, which I usually use for C++ where I want small exes...
Code:
#Compile Exe 'Disk image: 6656 bytes Memory image: 5312 bytes.
#Include "Windows.inc"
Function fnWndProc(ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
If wMsg=%WM_DESTROY Then
Call PostQuitMessage(0)
Function=0 : Exit Function
End If
fnWndProc=DefWindowProcW(hWnd,wMsg,wParam,lParam)
End Function
Function WinMain(ByVal hIns As Long, ByVal hPrev As Long, ByVal lpCL As WStringz Ptr, ByVal iShow As Long) As Long
Local szClassName As Stringz*16
Local wc As WndClassEx
Local Msg As tagMsg
Local hWnd As Dword
szClassName = "Form1"
wc.lpszClassName = VarPtr(szClassName)
wc.lpfnWndProc = CodePtr(fnWndProc)
wc.cbSize = SizeOf(wc)
wc.hbrBackground = %COLOR_BTNFACE+1
wc.hInstance = hIns
Call RegisterClassExW(wc)
hWnd=CreateWindowEx(0,szClassName,szClassName,%WS_OVERLAPPEDWINDOW,200,100,325,300,0,0,hIns,ByVal 0)
Call ShowWindow(hWnd,iShow)
While GetMessage(Msg,%NULL,0,0)
Call TranslateMessage(Msg)
Call DispatchMessage(Msg)
Wend
Function=msg.wParam
End Function
However, using various arcane compiler switches and what-not I can get the above down to about 4 k. Here is a link to my work on that, which is based on Matt Pietrek's work, who used to write for Microsoft Systems Journal...
Reducing Executable Size In C/C++ Programs By Eliminating The C Runtime
But anyway, let's start writing a Class Framework for the above standard Win Api SDK based program. Here's the start which has a CWinClass, which REGCLASSEX's a Window Class, a CWindow base class which actually has a Constructor which creates a window instance, and a CFrame Class where the message handling functions are static members...
Code:
#include <windows.h> 148 LOC 21 K
class CWinClass
{
public:
CWinClass(WNDPROC fnWndProc, char const* szClassName, HBRUSH hBackColor, HINSTANCE hInst)
{
wc.style = 0;
wc.lpfnWndProc = fnWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = sizeof(void*);
wc.hInstance = hInst;
wc.hIcon = 0;
wc.hCursor = LoadCursor (0, IDC_ARROW);
wc.hbrBackground = hBackColor;
wc.lpszMenuName = 0;
wc.lpszClassName = szClassName;
RegisterClass(&wc);
}
private:
WNDCLASS wc;
};
class CWindow //CWindow
{
public:
CWindow(HINSTANCE hIns)
{
this->m_hInst=hIns;
}
CWindow
(
int iShow,
char const* szClassName,
char const* szCaption,
DWORD dwStyle,
int x,
int y,
int iWidth,
int iHeight,
HWND hParent,
HMENU hMenu,
HINSTANCE hIns,
void* lpCreateParams
)
{
this->m_hWnd=CreateWindowEx(0,szClassName,szCaption,dwStyle,x,y,iWidth,iHeight,hParent,(HMENU)hMenu,hIns,lpCreateParams);
this->m_hInst=hIns;
ShowWindow(this->m_hWnd,iShow);
UpdateWindow(this->m_hWnd);
}
WPARAM Run(void)
{
MSG msg;
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
HWND Window(void)
{
return this->m_hWnd;
}
virtual ~CWindow(void) {}
protected:
HINSTANCE m_hInst;
HWND m_hWnd;
};
class CFrame : public CWindow //CFrame
{
public:
CFrame
(
int iShow,
char const* szClassName,
char const* szCaption,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hParent,
HMENU hMenu,
HINSTANCE hIns,
void* lpCreateParams
):CWindow(iShow,szClassName,szCaption,dwStyle,x,y,nWidth,nHeight,hParent,hMenu,hIns,this)
{
SetWindowLongPtr(this->m_hWnd,0,(LONG_PTR)this);
this->m_nCmdShow=iShow;
}
static long OnCreate(HWND hWnd, LPARAM lParam)
{
CREATESTRUCT* pCreateStruct=(CREATESTRUCT*)lParam;
CFrame* pObj=(CFrame*)pCreateStruct->lpCreateParams;
SetWindowLongPtr(hWnd,0,(LONG_PTR)pObj);
return 0L;
}
static long OnDestroy()
{
PostQuitMessage(0);
return 0L;
}
virtual ~CFrame(void) {}
protected:
int m_nCmdShow;
};
LRESULT CALLBACK FrameWndProc(HWND hWnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
return CFrame::OnCreate(hWnd,lParam);
case WM_DESTROY:
return CFrame::OnDestroy();
}
return (DefWindowProc(hWnd, msg, wParam, lParam));
}
int __stdcall WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
CWinClass WinClass(FrameWndProc, "Form1", (HBRUSH)(COLOR_BTNSHADOW), hIns);
CFrame* pApp=new CFrame(iShow,"Form1","Form1",WS_OVERLAPPEDWINDOW,150,150,350,250,0,(HMENU)0,hIns,0);
WPARAM wRet=pApp->Run();
delete pApp;
return wRet;
}
Using my older GCC compiler (Mingw 4.4 series circa 2008 or so) where I got a 7 k executable from the 39 Lines of Code of my basic SDK template, I'm getting 21 K on this Class based Windows program which contains 148 Lines of code. So, wrapping it all up in classes is making the executable 3 times larger with almost 4 times the number of lines of code! And it doesn't do one darn thing more than the smaller program. Not one! Of course, if you like sweeping your dirt under the rug you can always play this dirty little trick and put all the classes in a seperate header - let's call it "CWinFrmwrk", and then we'll just have this...
Code:
#include <windows.h>
#include "CWinFrmWrk.h"
LRESULT CALLBACK FrameWndProc(HWND hWnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_CREATE:
return CFrame::OnCreate(hWnd,lParam);
case WM_DESTROY:
return CFrame::OnDestroy();
}
return (DefWindowProc(hWnd, msg, wParam, lParam));
}
int __stdcall WinMain(HINSTANCE hIns, HINSTANCE hPrevIns, LPSTR lpszArgument, int iShow)
{
CWinClass WinClass(FrameWndProc, "Form1", (HBRUSH)(COLOR_BTNSHADOW), hIns);
CFrame* pApp=new CFrame(iShow,"Form1","Form1",WS_OVERLAPPEDWINDOW,150,150,350,250,0,(HMENU)0,hIns,0);
WPARAM wRet=pApp->Run();
delete pApp;
return wRet;
}
But if you somehow feel like that foolishness bought you something, well ... forget it and go do something else rather than reading any more of this.
I could go on here and develop that example further with child window controls, i.e., buttons, text boxes, etc. But I’ve ran on long enough for now, and I think I’ve made some points. If anybody needs any more of my rants, or more code, just holler.