I like the WTL approach myself.
gg
Printable View
I like the WTL approach myself.
gg
I don't think complexity is subjective. If something requires two steps instead of one to do something, I'd say it's more complex. Definitely measurable. Now, whether it's harder to use the first or second approach is subjective, as it depends on the programmer, experiences, etc. Nevertheless, as has probably been proven, more complexity equals more bugs and more code to maintain. Why would I create and register a class, then create a window with all its parameters when I can just, say, do:
CMyWindow Window?
You may be used to WinAPI by now, but why should I put new people through it when, for them, there are easier frameworks to work with (because less complexity)? If they don't need the additional flexibility provided by the WinAPI, why should they use it? This is basics of basics in programming: abstractions. Abstract everything. Then use the high-level building blocks to construct your program. So if you would use the WinAPI, you'd have to abstract it yourself and then use that abstraction. But why bother when others have done the work already?
I posted this topic in the C++ section because it *was* originally about MFC. Additionally, with MFC you get the design view for building windows applications, which makes GUI creation much easier than using the direct Win32 API, so I somewhat disagree with MFC not achieving anything more than using the Win32 API directly. To me, there's no complexity with the Win32 API, and as freddie says I think it's more of a subjective matter... If you know C, there's no reason why you can't eventually learn the Win32 API. The problem is the same as with any other library or framework; you have to take the time to learn the framework/library regardless of whether you know the language or not. In most places, things are consistent, so if you know the way it was written and what certain prefixes and suffixes mean, it's not that bad.
Duplicating functionality but under the constraints and design principles of the C++ language itself, making things more type safe, among other things, which is what needs to be kept in mind here...Quote:
So when one creates Class Frameworks in C++ or any other language to 'simplify' Windows Desktop/Laptop/Tablet programming, all one is doing is duplicating functionality contained within the underlying C based Api
Okay, but that is expected with a language like C++ which is notorious for having wrappers for everything. The reason? The type system. Additionally it's not really your responsibility to make sure that things don't leak if you design around the idea of RAII and you understand it properly. I think you are making C++ look like a bulky language with wrappers that makes things more complex with no benefit here. Bulky, I would agree, but properly written C++ code makes things much safer than what you can write for maintainable code in C.Quote:
but if your goal is to make it look like C++ and have C++ classes and objects, then you can really start adding up the lines of code and Ks in your binary - not to mention the C++ stuff which its now your responsibility to keep track of and not leak.
If you want an example from .NET, have you ever considered how the using statement works? There is no easy way to implement that same kind of safety in C as far as I know, without the use of compiler extensions like GCC has for cleanup.
Yes, you can't get away from having to learn it. But in the end, since frameworks are typically more abstract than the Win32 API, it is often easier to learn. But let's say we disregard that.
When you start coding your application, you're to write a lot of code to get something working. That means more bugs, more time typing it out, more code to maintain and more duplicated code, among other things. So what do you do? You abstract it! Boom! Now you've pretty much created your GUI framework - time which you could have saved if you'd just invested time into actually learning to use a framework right off the bat. Remember that you actually have to create, debug and maintain your framework code PLUS your code that uses the framework. Double work. If you use a preexisting framework, you can skip the first part. You save time.
If you want to, you can certainly learn both. But if you're short on time, picking a framework to learn would be better. But again, I wouldn't suggest investing time learn it because that's just time wasted that you can something else with. You're most likely going to end up using some framework in the end, anyway.
Okay.. But you are neglecting to consider one critical point here -- The public GUI frameworks that already exist out there for people to use contain absolutely everything to accommodate all functionality and features. What if I don't want all of that bulk and garbage?Quote:
That means more bugs, more time typing it out, more code to maintain and more duplicated code, among other things. So what do you do? You abstract it! Boom! Now you've pretty much created your GUI framework - time which you could have saved if you'd just invested time into actually learning to use a framework right off the bat
I think the final consensus here is subjective to project specific requirements, from what I've gathered by this thread.
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.
This is what I'm concluding here for myself. 100% agreed.Quote:
Better to have bulk and garbage than reinventing the wheel, unless you have a hard requirement that prevents you from using it.
I'm enjoying this discussion more than I ought to be. I've learned a few things. For one, from Brewbuck...
And from Elysia...Quote:
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...Quote:
I know of no good WYSIWYG GUI library for C++.
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!Quote:
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.
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...
...to this, which takes about 85 keystrokes to make and compiles to about 6 k...Code:#include <iostream> // compiles to 457 k with C++ compilation
using namespace std;
int main()
{
string strHello("Hello, World!");
cout << strHello << endl;
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.Code:#include <cstdio> // compiles to 6 k with C++ compilation
int main()
{
printf("Hello, World!\n");
getchar();
return 0;
}
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...
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?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 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 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...Quote:
I know of no good WYSIWYG GUI library for C++.
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...
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...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;
}
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...
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...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
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...
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> 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;
}
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.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;
}
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.
But it isn't. It is ridiculous to compare "hello world" programs like this. std::string is a badly designed piece of work, but even then it does have advantages over null-terminated strings with manual memory management that is certainly not evident in a contrived "hello world" program.Quote:
Originally Posted by freddie
Refer to Stroustrup's answer to the FAQ Why is the code generated for the "Hello world" program ten times larger for C++ than for C? concerning the executable bloat issue. The MinGW website used to have (and maybe still has) an FAQ answer that referenced the same issue about library organisation, as well as pointing out that as programs become non-trivial, the overall difference narrows, with a caveat about heavy template usage.
It sounds like you do not understand namespaces since you say "using namespace std" as if you do not understand that the feature of note is namespaces, not using directives, and then dismissing "Class Frameworks" as a whole makes it seem as if you do not understand RAII. Your way or the highway indeed.Quote:
Originally Posted by freddie
^^ I can get that executable down to about 2k even instead of 4k, but if you are using C++ without the STL then how can it be considered C++? Why didn't you just write the code in C? Sounds like you dismiss the use of classes alltogether, yet do you remember how C++ started out as "C with Classes"? Remove "with Classes" and you basically have "C". (Not 100% true anymore due to some minor language differences, but in principle it's exactly the truth.)
This is my thought. RAII is very nice for memory management, and without compiler extensions in gcc like the cleanup attribute I haven't found a good alternative. Additionally, vectors are still very handy.