Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Relationships between CWnd and CWinApp

404 views
Skip to first unread message

Vladimir

unread,
Oct 10, 2008, 6:58:51 AM10/10/08
to
Hello. I have a question about relationships between CWnd derived class
and CWinApp derived one in an MFC application. What responsibility
should each of them take? I mean should all the app's work be done in
CWnd responding to messages of its own controls or should it serve just
as an interface and pass all user input to the app. What should CWnd
know about CWinApp's interface, should it know its methods? What is the
right way, the best practice on this matter? Thanks.

David Webber

unread,
Oct 10, 2008, 11:06:16 AM10/10/08
to

"Vladimir" <thamior...@gmail.com> wrote in message
news:gcnchb$amg$1...@aioe.org...

First a CWnd is just a window. I'll assume that you mean the main frame
window. In an MDI application there is a view window for each document.

So in general there are *at least* the following places where you can put
data and code:

the app (CWinAPP derived class)
the main frame window class
the document window class
the document class.

On the whole there is no right answer. But you need to build up a mental
model of each of these objects and what it is and what it does, and then
design your object orientation accordingly.

The point about object orientation is that objects have data within them and
also process that data with their own methods, as much as possible
independently of other objects. So a window shouldn't have to consult the
application to do operations which only affect the window. A document
shouldn't have to ask a view to do operations which only affect the
document.

For example anything intrinsic to the document, and independent of how it is
viewed should go into the document class. anything to do with how it is
viewed should go into the view class. (It can be useful to consider two
different views of the same document to decide on this, even if you don't
plan to allow them.) For example the text of a document belongs to the
document; the position of the caret belongs to the view.

(However usually (in my case) messages for a document will also affect the
view and I usually catch them in the view window and have it tell the
document what to do, before doing its own tasks.)

Anything which belongs to the frame window (for example menu, status bar and
toolbars) should go in the frame window class.

The app class is perhaps the most difficult to identify things which belong
to it. It may turn out to be anything which doesn't obviously belong
somewhere else. I have application-specific things like command line
handling classes, and also "global" data for the application. I hate actual
globals, so I make them members of the application and salve my conscience.
:-)

Hope this helps a bit,

Dave
--
David Webber
Author of 'Mozart the Music Processor'
http://www.mozart.co.uk
For discussion/support see
http://www.mozart.co.uk/mozartists/mailinglist.htm

Joseph M. Newcomer

unread,
Oct 11, 2008, 10:43:40 AM10/11/08
to
CWnd is any generic window class, and therefore all windows in your app derive from CWnd.

CWinApp is nearly totally useless except in very rare cases. For example, you would never
put any variables in your CWinApp-derived class that were not used solely and exclusively
by your CWinApp-derived class. Other than the OnIdle handler, InitInstance, and
ExitInstance (rarely), your CWinApp class rarely has anything to do with your app. The
generic CWinApp class is often used to hold utility functions.

In a deep failure of design, Microsoft insists on putting the header file for the
CWinApp-derived class in every file you create; no one has ever been able to
satisfactorily explain why such an incredibly stupid action was ever thought to make
sense. I simply delete it from every file, usually replacing it by
#include "resource.h"
except in those cases where I don't use anything in resource.h at all.

Nobody outside your CWinApp-derived class should know or care in the slightest about any
methods of CWinApp, except those generic CWinApp methods (such as LoadCursor, LoadIcon,
etc.) that provide window-independent functionality.

Tossing global variables into the CWinApp-derived class simply so they won't be "global"
(and thus violate some C++ programming convention) is, in my opinion, a horrific practice
which has no place in modern programming. I consider that if you ever write
(CMyApp *)AfxGetApp()
you have made a serious programming error (and *never* use "theApp" for anything!)

Similarly, a CWinApp-derived class should know nothing about documents or views; the
mainframe should never presume that the functions GetActiveDocument() or GetActiveView()
return other than a generic CDocument* or CView* (never cast them! If you need to do a
cast, you have made a serious programming error!), a document never knows anything about
its views, a dialog never knows anything about any component other than itself and perhaps
child dialogs it needs to interface to (but never have a #include of a CWinApp, CDocument,
CView, CMainFrm, etc. class in a dialog!). It's one of these "new ideas" that a lot of
people believe in, called "modularity", and it replaces the
"scatter-includes-and-casts-like-pixie-dust-until-it-compiles" paradigm.
joe

Joseph M. Newcomer [MVP]
email: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

Mark Salsbery [MVP]

unread,
Oct 11, 2008, 3:03:03 PM10/11/08
to
"Joseph M. Newcomer" <newc...@flounder.com> wrote in message
news:2ae1f41nhahfp8pf4...@4ax.com...

> CWnd is any generic window class, and therefore all windows in your app
> derive from CWnd.
>
> CWinApp is nearly totally useless except in very rare cases. For example,
> you would never
> put any variables in your CWinApp-derived class that were not used solely
> and exclusively
> by your CWinApp-derived class. Other than the OnIdle handler,
> InitInstance, and
> ExitInstance (rarely), your CWinApp class rarely has anything to do with
> your app. The
> generic CWinApp class is often used to hold utility functions.


Useless? In a normal MFC app, it represents the initial thread, provides
the execution entry point into the MFC classes (by representing the initial
thread), and provides a message loop.

Where do YOU put data that is application wide in scope (not specific to a
given window)??

(I'm talking as designed here, not how MFC could have been designed)

Mark

--
Mark Salsbery
Microsoft MVP - Visual C++


David Webber

unread,
Oct 12, 2008, 5:05:10 AM10/12/08
to

"Joseph M. Newcomer" <newc...@flounder.com> wrote in message
news:2ae1f41nhahfp8pf4...@4ax.com...

>...


> In a deep failure of design, Microsoft insists on putting the header file
> for the
> CWinApp-derived class in every file you create; no one has ever been able
> to
> satisfactorily explain why such an incredibly stupid action was ever
> thought to make
> sense. I simply delete it from every file, usually replacing it by
> #include "resource.h"
> except in those cases where I don't use anything in resource.h at all.

Yes, I do the same, and have often wondered about why MS did that.

> Nobody outside your CWinApp-derived class should know or care in the
> slightest about any
> methods of CWinApp, except those generic CWinApp methods (such as
> LoadCursor, LoadIcon,
> etc.) that provide window-independent functionality.

I use it for:
Command line parsing
Storing a name with which to register my main window class
Data to be used when other thread is launched.
Data indicating what actions to perform as the program exits.
Data indicting which optional plug-in DLLs are available.
Launching/terminating GDI+
Storing a cache of miscellaneous objects.

> Tossing global variables into the CWinApp-derived class simply so they
> won't be "global"
> (and thus violate some C++ programming convention) is, in my opinion, a
> horrific practice
> which has no place in modern programming.

Yes, I thought not everyone would wholeheartedly approve. :-) [My last
item on the list is one of those.] But then I don't regard it as an
unreasonable philosophy that something which, in a previous life, would have
been "global", now "belongs to your application". And I still use them as
sparingly as possible.

> I consider that if you ever write
> (CMyApp *)AfxGetApp()
> you have made a serious programming error

Yes, I try to avoid it. If things need access to "global" data stored as
members of the app, then their constructors should accept a reference to it.
I also try to avoid getting the main window on the same basis, but sometimes
one needs to send messages to it.

> (and *never* use "theApp" for anything!)

Agreed.

> Similarly, a CWinApp-derived class should know nothing about documents or
> views; the
> mainframe should never presume that the functions GetActiveDocument() or
> GetActiveView()
> return other than a generic CDocument* or CView* (never cast them! If you
> need to do a
> cast, you have made a serious programming error!), a document never knows
> anything about
> its views, a dialog never knows anything about any component other than
> itself and perhaps
> child dialogs it needs to interface to (but never have a #include of a
> CWinApp, CDocument,
> CView, CMainFrm, etc. class in a dialog!). It's one of these "new ideas"
> that a lot of
> people believe in, called "modularity", and it replaces the
> "scatter-includes-and-casts-like-pixie-dust-until-it-compiles" paradigm.

Again I'd say take everything in moderation - including advice. :-) I
reckon what you say is true 99% of the time. But I have one dialogue which
acts as a rather complicated page formatter for the document. The clearest
interface I have yet found is to have its controls actually implemet the
changed dimensions on a view of a document. To this effect the dialogue has
a pointer to the view on which it is operating. [If you don't like what
you have done, you can press Ctrl+Z afterwards!] It isn't standard, but
when the page has dozens of dimensions you can alter, it is useful.

Joseph M. Newcomer

unread,
Oct 12, 2008, 8:39:26 PM10/12/08
to
See below...

On Sat, 11 Oct 2008 12:03:03 -0700, "Mark Salsbery [MVP]"
<MarkSalsbery[MVP]@newsgroup.nospam> wrote:

>"Joseph M. Newcomer" <newc...@flounder.com> wrote in message
>news:2ae1f41nhahfp8pf4...@4ax.com...
>> CWnd is any generic window class, and therefore all windows in your app
>> derive from CWnd.
>>
>> CWinApp is nearly totally useless except in very rare cases. For example,
>> you would never
>> put any variables in your CWinApp-derived class that were not used solely
>> and exclusively
>> by your CWinApp-derived class. Other than the OnIdle handler,
>> InitInstance, and
>> ExitInstance (rarely), your CWinApp class rarely has anything to do with
>> your app. The
>> generic CWinApp class is often used to hold utility functions.
>
>
>Useless? In a normal MFC app, it represents the initial thread, provides
>the execution entry point into the MFC classes (by representing the initial
>thread), and provides a message loop.

****
Yes, but in terms of your actual programming, it is useless. It is pure framework, and
serves critical purposes in the framework, but it is useless in your main frame, your
views, your documents, and your dialogs. It's role is simply to provide, as you describe,
the initial thread handler, the initial execution point (the virtual method InitInstance),
corresponding cleanup when appropriate, and the message loop. Those are all critical
*functions*, but their existence is preordained in that module. Adding other things to
that module that have nothing to do with the aforementioned roles, just tossing variables
in willy-nilly because someone once said "global variables are bad" and pretending that
making them class variables of your CWinApp-derived class solves the problem is wrong.
This is actually poorer practice than having global variables (two of my thesis advisors
co-authored the paper titled "Global Variables Considered Harmful")
[http://portal.acm.org/citation.cfm?id=953355] so when I say "I come from the school of
global variables considered harmful" I mean it literally). But creating variables in the
CWinApp class is actually *more* destructive than the classic global variables for the
reasons I describe below. There is no rationale that justifies tossing variables into the
CWinApp-derived class unless they are used by your CWinApp-derived class.
****


>
>Where do YOU put data that is application wide in scope (not specific to a
>given window)??

****
Where they belong: as global variables. There might be one or two of these. Putting them
in the CWinApp-derived class is silly. It means that every module that uses any "global"
variable requires the header file that reveals ALL global variables, and ANY change in the
CWinApp-derived class triggers massive recompilations. It introduces gratuitous
dependencies and interdependencies that make no sense. And potentially any file that
includes the CWinApp-derived header can access or modify any variable.

If you create a single global variable, create a header file for it, and include that
header file ONLY in the modules that require it, you have introduced no incidental or
irrelevant dependencies; only the modules that use it (and there are very few in most real
programs) ever include it, and it is also clear just by searching for the #includes
exactly which modules actually care about it.

If you are afraid to declare a .cpp file that has two lines
#include "whatever.h"
Whatever variablename;
and declare a header file
#pragma once
extern Whatever variablename;
then you need to rethink what it means to do development. There's nothing wrong with
having a single module that defines a single variable and a header file that gives access
to it. It simply doesn't make sense to include some "blanket" header file that includes
some framework class into which random unrelated variables are tossed.

The use of gratuitous variables in header files actually reduces productivity. I was an
advisor to a student whose PhD thesis demonstrates this, with substantiating data, beyond
any doubt [http://portal.acm.org/citation.cfm?id=916690]. She shows that if you introduce
gratuitous dependencies, your development time is longer. Since there is no reason other
than sheer laziness to introduce such dependencies, they make no sense (I'd been saying
this for years, which is why I was chosen to serve on her committee, and while I was no
longer able to be a principle advisor to her, I was the outside member of the committee).

[Folks at CMU say they are in the process of making every PhD dissertation in the history
of the department be available online, and hope to complete that project and make them
available in the near future. It has been actively underway for a while now, so soon I
may be able to give a full-text citation]

A variable should have its scope limited to just those modules that use it. If its
lifetime is global, that's one thing, but making all global variables (or logically global
variables) visible to all modules at all times makes no sense whatsoever. Therefore, it
has never made sense from a structural viewpoint to put anything in the CWinApp-derived
class that is not used by the CWinApp-derived class.
joe
****


>
>(I'm talking as designed here, not how MFC could have been designed)
>
>Mark

Joseph M. Newcomer

unread,
Oct 12, 2008, 8:51:43 PM10/12/08
to
See below...
On Sun, 12 Oct 2008 10:05:10 +0100, "David Webber" <da...@musical-dot-demon-dot-co.uk>
wrote:

>
>"Joseph M. Newcomer" <newc...@flounder.com> wrote in message
>news:2ae1f41nhahfp8pf4...@4ax.com...
>
>>...
>> In a deep failure of design, Microsoft insists on putting the header file
>> for the
>> CWinApp-derived class in every file you create; no one has ever been able
>> to
>> satisfactorily explain why such an incredibly stupid action was ever
>> thought to make
>> sense. I simply delete it from every file, usually replacing it by
>> #include "resource.h"
>> except in those cases where I don't use anything in resource.h at all.
>
>Yes, I do the same, and have often wondered about why MS did that.
>
>> Nobody outside your CWinApp-derived class should know or care in the
>> slightest about any
>> methods of CWinApp, except those generic CWinApp methods (such as
>> LoadCursor, LoadIcon,
>> etc.) that provide window-independent functionality.
>
>I use it for:
> Command line parsing

*** Yes


> Storing a name with which to register my main window class

*** Yes


> Data to be used when other thread is launched.

***
No. Data passed into a thread should be passed in as a pointer to an object which is the
thread parameter. In many cases, it might be a pointer to 'this', and in other cases it
is a pointer to a heap object that has useful data, but putting the data in the CWinApp
class makes no sense. It isn't CWinApp-related data
****


> Data indicating what actions to perform as the program exits.

****
ExitInstance should only undo state that was set in InitInstance; in other cases, objects
should properly destruct when their clients go away
****


> Data indicting which optional plug-in DLLs are available.

****
It is a global variable, and therefore is outside the CWinApp class and CMainFrame class
(in one app, I call a function in my DLL-plugin class manager, pointing it at a CMenu&
which it fills in with the names of the DLLs, which I obtain from each of the DLLs.) But
managing a set of loadable DLLs is not a function related to CWinApp, so why put it there?

Note that singleton classes are also good substitutes for global variables as well.
****
> Launching/terminating GDI+
****
Yes, because this is global state that needs a single initialization and termination
point. Also, WinSock initialization, Rich Edit initialization, etc., because they have no
specific client locations and CAsyncSocket, for example, assumes AfxSockInit (or whatever
its name is) *has* been called as part of the global initialization
****


> Storing a cache of miscellaneous objects.

****
No. Whatever they are, they are almost certainly not used by the CWinApp-derived class.
They may be global state, but they don't belong in the CWinApp-derived class.
****


>
>> Tossing global variables into the CWinApp-derived class simply so they
>> won't be "global"
>> (and thus violate some C++ programming convention) is, in my opinion, a
>> horrific practice
>> which has no place in modern programming.
>
>Yes, I thought not everyone would wholeheartedly approve. :-) [My last
>item on the list is one of those.] But then I don't regard it as an
>unreasonable philosophy that something which, in a previous life, would have
>been "global", now "belongs to your application". And I still use them as
>sparingly as possible.

****
Belonging to the application is not the same as being a component of the CWinApp-derived
class. That's my point.
****


>
>> I consider that if you ever write
>> (CMyApp *)AfxGetApp()
>> you have made a serious programming error
>
>Yes, I try to avoid it. If things need access to "global" data stored as
>members of the app, then their constructors should accept a reference to it.
>I also try to avoid getting the main window on the same basis, but sometimes
>one needs to send messages to it.

****
Since messages are essentially virtual methods and don't require knowing the internal
structure of the main window (in fact, some messages I send to the main window are routed
to other windows by SendMessageToDescendants, or in some cases GetActiveView or
GetActiveDocument, although that has been rare in the last few years) they are reasonable.
****

****
What I would have is a CView*, and send it a message. Therefore, no internals of the view
itself need to be exposed, and no dependency is introduced in the wrong direction. I
include the message type as part of an interface file to the view, which is included only
in the view and the dialog which needs to interact with the view. The interface is "Send
this message and get this result". It doesn't care *how* the message is interpreted.
That's up to the view, and the dialog does not need to know anything about the view except
that sending a particular message to a generic CView obtains a specific result.
joe
****
>
>Dave

David Webber

unread,
Oct 13, 2008, 5:26:43 AM10/13/08
to

"Joseph M. Newcomer" <newc...@flounder.com> wrote in message
news:e665f4hqs95fhlmj5...@4ax.com...
> See below...

Hi, Joe,

This and your other recent posts are beringing me round, and I have started
to look in more detail at what my app class actually does. :-)

[Some of this code is 15 years old and I *need* to look.]

It turns out that almost all of my AfxGetApp() calls (and there aren't many
in my, as opposed to Microsoft's, code) are to get

- the hInstance of the .exe module and the
- the m_pszHelpFilePath member
- the LoadStandardIcon() method.
- to use other MFC methods like OpenDocumentFile();

In fact I seem to have taken my growing but still vague aversion to using it
(less well thought out than your considerations) furthar than I thought.

>>I use it for:
>> Command line parsing
> *** Yes
>> Storing a name with which to register my main window class
> *** Yes
>> Data to be used when other thread is launched.
> ***

> No....

Turns out that I "misspoke" on that. I have one integer. I thought it was
used by the MIDI play-back thread, but in fact it is just obtained from
timeGetDevCaps() and passed to timeBeginPeriod() in the app initialisation
code, and then again to timeEndPeriod() later on. The code is so old that
I even forget why these are necessary.

> ****
>> Data indicating what actions to perform as the program exits.
> ****
> ExitInstance should only undo state that was set in InitInstance; in other
> cases, objects
> should properly destruct when their clients go away

Yes. Good. Effectively it does, - almost. It also saves any global
preferences, which may have changed during the session, to the registry.
[The data *are* stored globally - see below.]

> ****
>> Data indicting which optional plug-in DLLs are available.
> ****
> It is a global variable, and therefore is outside the CWinApp class and
> CMainFrame class
> (in one app, I call a function in my DLL-plugin class manager, pointing it
> at a CMenu&
> which it fills in with the names of the DLLs, which I obtain from each of
> the DLLs.) But
> managing a set of loadable DLLs is not a function related to CWinApp, so
> why put it there?

Well my philosophy was that the DLLs belong to the application. I too have
a DLL-manager class but it is a member of the App. I suppose I could put
it elsewhere. as ytou say, the main frame window's menu has to be adjusted
to reflect what plug-in's are avaiilable, and so it is nice to know that
before the main window is created.

> Note that singleton classes are also good substitutes for global variables
> as well.

I am not sure what "singleton class" is - but I may effectively be doing
this (see below).


> ****
>> Launching/terminating GDI+
> ****
> Yes,...


> ****
>> Storing a cache of miscellaneous objects.
> ****
> No. Whatever they are, they are almost certainly not used by the
> CWinApp-derived class.
> They may be global state, but they don't belong in the CWinApp-derived
> class.
> ****

I may have "misspoken" there too :-( When I look at the cache object,
it is barely used. I have moved almost all of its function elsewhere.
Memo to self: complete the job.

>...


> Belonging to the application is not the same as being a component of the
> CWinApp-derived
> class. That's my point.

Well "object orientation" is a flexible philosophy :-)

> [general points of agreement snipped.]

>>Again I'd say take everything in moderation - including advice. :-) I
>>reckon what you say is true 99% of the time. But I have one dialogue
>>which
>>acts as a rather complicated page formatter for the document. The
>>clearest
>>interface I have yet found is to have its controls actually implemet the
>>changed dimensions on a view of a document. To this effect the dialogue
>>has
>>a pointer to the view on which it is operating. [If you don't like what
>>you have done, you can press Ctrl+Z afterwards!] It isn't standard,
>>but
>>when the page has dozens of dimensions you can alter, it is useful.
> ****

> What I would have is a CView*, and send it a message....

Yes. That is what I do - I have large numbers of WM_USER+... messages. I
actually have a CMyView &, but I suspect I could demote it to CView &. [I
like storing references to objects in cases when nothing can be done without
one as it physically stops me from getting a null pointer.]

Anyway a final note on global data: I have a hierarchy of EXE and DLLs

1. The exe.
2. The UI DLL - (MFC extension) does all the drawing, has the dialogues
3. The music DLL - (non-MFC) does musical computations, exports music
objects
4. A utility DLL - (non-MFC) for low level utility operations.

[and others on the side.] This structure lets me have more than one
program which can share all the methods exposed by the DLLs.

Levels 2 and 3 each have global data, and I implement this by a class with
only static data and only static methods to handle it. When I need it, I
just declare a class ("constructing" would be an exaggeration <g>) and use
its methods. It works like a poor man's namespace :-) I have
actually, over the years, removed stuff from the App and put it here, partly
because I need it in the DLLs.

It sort of makes me feel that the data isn't really "global", in the old
sense which I have come to deprecate, but of course it is really. :-)

Joseph M. Newcomer

unread,
Oct 13, 2008, 5:02:55 PM10/13/08
to
Some years ago I got back a program I'd written five years before. My reaction: "Did I
write this????" because my style had evolved to the point where I would not write code
like that the year I got it. I get much more obsessive about modularity as I program
larger and larger programs.

On Mon, 13 Oct 2008 10:26:43 +0100, "David Webber" <da...@musical-dot-demon-dot-co.uk>
wrote:

>

Device drivers typically have zero static-lifetime variables. There is one particular
case where a single global integer is needed (to number device instances, e.g., COM1,
COM2, COM3, ...) and this is only required if such names need to be generated (the desire
is to use GUIDs for devices, which has not achieved acceptance with end users because
Microsoft not only makes them hard to use [100 lines of code to open a file instead of 1]
but hides the critical APIs as "Setup" APIs, not "Device" APIs [where is the adult
supervision when names are created? Not to mention spell-checkers...]). So I've really
gotten out of the habit of static lifetime variables in a lot of cases.

See my above comment about aging code. I'd be embarrassed today by what I thought made
sense ten years ago.
****


>
>> ****
>>> Data indicating what actions to perform as the program exits.
>> ****
>> ExitInstance should only undo state that was set in InitInstance; in other
>> cases, objects
>> should properly destruct when their clients go away
>
>Yes. Good. Effectively it does, - almost. It also saves any global
>preferences, which may have changed during the session, to the registry.
>[The data *are* stored globally - see below.]
****

Perferences should be changed when they are made, not when the program exits. I consider
this one of the most significant flaws in Microsoft code. If you make changes in Visual
Studio and don't exit, your changes are lost, and if you are running multiple versions,
the preferences don't propagate. When it was explained to me that preferences shouldn't
be changed except at exit, I looked at the person and said "You mean you actually EXIT
programs? How quaint! I haven't done that since MS-DOS!" I would keep VS6 up for MONTHS
(alas, 2003, 2005 and 2008 keep crashing...and losing my customizations!) I keep
PowerPoint, Outlook, IE, Epsilon (my editor), Forte Agent (my newsgroup reader) and Word
up for MONTHS (actually, the only time I exit these programs is when I'm doing Windows
Update and have to reboot!) Why would it ever be necessary to exit a program if it is
active? Or potentially active?

My email machine (the most lightly used of all my machines) is running 10 different
programs, including 4 instances of Word, 21 instances of IE and 3 instances of Windows
Explorer (a total of 36 items in my taskbar, counting the multiple dropdowns like IE).
Other machines will have 2-3 instances of VS (sometimes 2-3 instances of 2003, 2005 and
2008 EACH), 4-6 instances of PowerPoint, 8 instances of Word, 1-2 instances of Excel, and
that means 40-50 program instances representing perhaps 20 different programs.

The only reason I exit most programs is the asinine GDI limits that Microsoft imposes. If
I have a 4GB quad processor machine, I expect to run 4GB quad-processor-scaled suites of
applications, and that means perhaps 50 apps running, but I start running out of GDI
space, so have to exit to satisfy someone's 4MB Win16 image of the world. If I have three
orders of magnitude more physical memory, I deserve t have three orders of magnitude more
GDI space.
****


>
>> ****
>>> Data indicting which optional plug-in DLLs are available.
>> ****
>> It is a global variable, and therefore is outside the CWinApp class and
>> CMainFrame class
>> (in one app, I call a function in my DLL-plugin class manager, pointing it
>> at a CMenu&
>> which it fills in with the names of the DLLs, which I obtain from each of
>> the DLLs.) But
>> managing a set of loadable DLLs is not a function related to CWinApp, so
>> why put it there?
>
>Well my philosophy was that the DLLs belong to the application. I too have
>a DLL-manager class but it is a member of the App. I suppose I could put
>it elsewhere. as ytou say, the main frame window's menu has to be adjusted
>to reflect what plug-in's are avaiilable, and so it is nice to know that
>before the main window is created.

*****
I just didn't bother making it part of the app. And as I indicated, the mainframe menu is
dynamic--at least the one for the plugins--and so all the OnInitMenuPopup (or
OnInitPopupMenu, I never remember but the wizard gets it right...) has to do is call the
DLL manager to get the names of the DLLs .
****


>
>> Note that singleton classes are also good substitutes for global variables
>> as well.
>
>I am not sure what "singleton class" is - but I may effectively be doing
>this (see below).
****

A singleton class is a class that has only one actual instantiation of its data, so when
you declare an instance of the class, all the instances share the same data.
****


>
>
>> ****
>>> Launching/terminating GDI+
>> ****
>> Yes,...
>> ****
>>> Storing a cache of miscellaneous objects.
>> ****
>> No. Whatever they are, they are almost certainly not used by the
>> CWinApp-derived class.
>> They may be global state, but they don't belong in the CWinApp-derived
>> class.
>> ****
>
>I may have "misspoken" there too :-( When I look at the cache object,
>it is barely used. I have moved almost all of its function elsewhere.
>Memo to self: complete the job.

****
Old code never dies, it just gets edited out of existence...
****


>
>>...
>> Belonging to the application is not the same as being a component of the
>> CWinApp-derived
>> class. That's my point.
>
>Well "object orientation" is a flexible philosophy :-)

****
It's the dependency issue...
****


>
>> [general points of agreement snipped.]
>
>>>Again I'd say take everything in moderation - including advice. :-) I
>>>reckon what you say is true 99% of the time. But I have one dialogue
>>>which
>>>acts as a rather complicated page formatter for the document. The
>>>clearest
>>>interface I have yet found is to have its controls actually implemet the
>>>changed dimensions on a view of a document. To this effect the dialogue
>>>has
>>>a pointer to the view on which it is operating. [If you don't like what
>>>you have done, you can press Ctrl+Z afterwards!] It isn't standard,
>>>but
>>>when the page has dozens of dimensions you can alter, it is useful.
>> ****
>> What I would have is a CView*, and send it a message....
>
>Yes. That is what I do - I have large numbers of WM_USER+... messages. I
>actually have a CMyView &, but I suspect I could demote it to CView &. [I
>like storing references to objects in cases when nothing can be done without
>one as it physically stops me from getting a null pointer.]

****
That's what I try to do. It is unfortunate that so many MFC methods use something* when
it is never possible to pass a NULL pointer, but the Win32 API used something* so the
method has to use something* instead of something& (e.g., GetWindowRect, GetClientRect
come to mind here)
****


>
>Anyway a final note on global data: I have a hierarchy of EXE and DLLs
>
>1. The exe.
>2. The UI DLL - (MFC extension) does all the drawing, has the dialogues
>3. The music DLL - (non-MFC) does musical computations, exports music
>objects
>4. A utility DLL - (non-MFC) for low level utility operations.
>
>[and others on the side.] This structure lets me have more than one
>program which can share all the methods exposed by the DLLs.
>
>Levels 2 and 3 each have global data, and I implement this by a class with
>only static data and only static methods to handle it. When I need it, I
>just declare a class ("constructing" would be an exaggeration <g>) and use
>its methods. It works like a poor man's namespace :-) I have
>actually, over the years, removed stuff from the App and put it here, partly
>because I need it in the DLLs.

*****
I do a lot of this to control namespace. Rather than #define, I'll create a class with an
enum type embedded.
****


>
>It sort of makes me feel that the data isn't really "global", in the old
>sense which I have come to deprecate, but of course it is really. :-)

****
The "Global Variables Considered Harmful" was primarily an indictment of scope, not
lifetime. Lifetime can be static but the variable doesn't have to be universally global
to everyone to accomplish this. That's my objection to CWinApp: tossing variables at
CWinApp is the moral equivalent of creating a bunch of global variables that everyone
inherits: scope is not controlled. Anything can be seen and modified anywhere at any
time. By using separate modules to encapsulate data, I limit the scope by using #include
but don't limit the lifetime. There is a lot of confusion about scope and lifetime, and
I've used so many different languages that I've seen just about every example of how to
get these right and wrong. C++ gives the ability to get it right (even C doesn't do too
bad a job) but also makes it *easier* to get it wrong because getting it right means you
have to stop programming like Freshman Programming 101 Using C. Or Petzold.

Mark Salsbery [MVP]

unread,
Oct 13, 2008, 6:18:40 PM10/13/08
to
Excellent!

I always thought, because of it's name, CWinApp, the one required CWinApp
object was a good place for variables needing app scope.
I never bothered thinking it out farther than that.

Thank you Joe, I really appreciate the detail of your reply.

Mark

"Joseph M. Newcomer" <newc...@flounder.com> wrote in message

news:gj45f4paok6csl0kl...@4ax.com...

0 new messages