From: Joseph M. Newcomer on
On Wed, 20 Jan 2010 04:56:08 -0800, wek(a)newsgroups.nospam
<weknewsgroupsnospam(a)discussions.microsoft.com> wrote:

>"Goran" wrote:
>
>> On Jan 20, 10:51 am, w...(a)newsgroups.nospam
>> <weknewsgroupsnos...(a)discussions.microsoft.com> wrote:
>> > "Joseph M. Newcomer" wrote:
>> > > See below...
>> > > On Tue, 19 Jan 2010 02:25:01 -0800, w...(a)newsgroups.nospam
>> > > <weknewsgroupsnos...(a)discussions.microsoft.com> wrote:
>> >
>> > > >I have a DLL which uses MFC and is compiled with /clr (because it contains
>> > > >classes which must be callable from C#).
>> > > >That works well when being used from a C# application by calling :
>> > > >if (!AfxWinInit(::GetModuleHandle("<dllname>"), NULL, ::GetCommandLine(),
>> > > >0)) return false;
>> > > >AfxGetApp())->InitInstance();
>> > > >so that the DLL has its own App-Object/State which is initialized by the
>> > > >above source code.
>> >
>> > > >But now I also want to use that DLL in a C++ MFC application which already
>> > > >has a CWinApp object; so I would like not to establish a new one for the DLL
>> > > >but use the one of the MFC application.
>> >
>> > > >How can I prevent the DLL having it's own App-Object/State ?
>> > > ****
>> > > You can't. Nor does it make sense to. Microsoft has confused the concept of a CWinApp
>> > > object by reusing the same class in DLLs. But it has no relationship to the CWinApp of
>> > > your app and you should not think that it does. And in fact it could not POSSIBLY make
>> > > sense to use the CWinApp of the application, since the DLL can know nothing of the
>> > > application class. What is it you think you need from the executable CWinApp? Note that
>> > > since this is designed to run with C#, it already cannot know anything about the
>> > > executable that calls it, let alone anything about a CWinApp in MFC. So how is it that it
>> > > can have no knowledge of a CWinApp when you call it from C# and *must* have this knowledge
>> > > if you call it from MFC? Doesn't make any sense. The DLL is a DLL.. It is not an MFC
>> > > Extension DLL, and it cannot share anything with its executable because it doesn't know if
>> > > the executable is VB, C#, or MFC. Or, for that matter, that it was loaded and called from
>> > > a regular DLL or an MFC extension DLL. I don't understand why you even think this is an
>> > > issue. Perhaps the textual similarity of the name confuses you; given Microsoft chose
>> > > this badly, it is not surprising, but remember this: that textual name means nothing
>> > > outside the DLL. It doesn't matter if it is called "CWinApp" or "DLL_Thing"; nobody
>> > > outside the DLL can know or care about its existence. It does not "conflict" with the
>> > > executable because it cannot possibly know what the executable IS. For "CWinApp"
>> > > substitute any name of your choice and you see that it has nothing to do with the
>> > > executable.
>> > > joe
>> > > ****
>> >
>> > > >Thanks in advance for any hint.
>> > > Joseph M. Newcomer [MVP]
>> > > email: newco...(a)flounder.com
>> > > Web:http://www.flounder.com
>> > > MVP Tips:http://www.flounder.com/mvp_tips.htm
>> > > .
>> >
>> > Hello Joseph, thanks for your posts.
>> >
>> > My problem is not that I don't want to have the AppState/CWinApp instance in
>> > the DLL; my problem is that I do want access to the CWinApp derived instance
>> > of the application because this is a very extended class with lots of
>> > additional properties and functionality like user authentification, database
>> > initialization (which is done in InitInstance of the CWinApp-derived App -
>> > instance) etc; the result of those operations done at startup and "stored" in
>> > the App-object should be accessible by my dll.
>> > This makes sense and works well when I use the DLL from a C# app (and in
>> > this case the app object is initialized in the DLL itself (see my orig.post),
>> > because C# apps don't have an CWinApp-object of their own). But when I have a
>> > C++/CLI MFC app which HAS its own CWinApp-derived instance I don't want to
>> > have the startup things (auth, db init etc) to be done 2 times but want to
>> > "reuse" the results of the C++ MFC app exe; I would only need a possibility
>> > to get a pointer to the native C++ app object of the EXE to that I could
>> > wrap it with a .NET class and then could use it in my C# assemblies.
>>
>> The way you want things, you are making a cyclical module reference
>> (app uses dll, dll uses app). That's normally a bad idea. What you
>> should instead do is to move all that code into a third module and
>> have both exe and dll use that. See what a guy that has put a lot of
>> thought into these things has to say: http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod
>> (in particular, look for ADP).
>>
>> It is normally also a mistake to put any significant functionality in
>> CWinApp-derived class. I know that even MDSN samples do that, MSDN
>> itself might recommend it, and App-wizard does a derived class, but
>> it's still a bad, BAD idea. And I mean BAAAAAAD.
>>
>> Think about it: WHAT do you gain by putting bunch of (often unrelated)
>> artifacts into CMyWinApp? You can just as well have them in separate
>> places and avoid any dependency to the app class. Only benefit is "one
>> central place to have all in". Well, that benefit is bunk. It does not
>> matter if you write theApp.Whatever(), or just Whatever(), or
>> anotherClass.Whatever(). But once your code gets bigger, your
>> compilation time goes up and up, because you have a lot of "Whatevers"
>> that don't relate much with each other.
>>
>> Goran.
>> .
>Hello Goran, thanks for your post.
>I think you are right in general, BUT :
>1.
>The problem is that the app source exists for a long time (grown in about 15
>years since MFC 1.0 ..) and is well tested ;-)
>The requirement to make it accessible by .NET C# source used by the app is
>very new. It's not possible to do a complete "refactoring"
****
It is also not possible to achieve what you want in the way you suggest. Unfortunately,
the "impossible" that says that the system cannot possibly under any circumstances do what
you want trumps the "we don't want to do it" impossibility.
****
>2.
>I think it makes sense that auth, dbinit etc. are implemented in that app
>class (or in helper classes which are members of the app) and it's very
>comfortable to have access to data like usernames, app-options, dbinfo etc at
>every place in your MFC Source with AfxGetApp()
****
No, actually, you are completely wrong. It does not make sense, and never made sense, to
implement something like a database interface as part of a CWinApp-derived base class.
Whoever did this 15 years ago clearly had no comprehension of modularity. If you want a
database reference and it has helper functions, we call this a "class" and you would
create a database class object. It should not be part of the CWinApp-derived class, nor
should the CWinApp-derived class have any knowledge that such a thing exists. There are
lots of ways to handle this correctly; a simple global variable of the class type does the
job (there is a "religion" in C++ that says "no global variables", and due to a total
failure of comprehension, this translates as "a member variable of the CWinApp-derived
class is not a global variable, so it is OK". No, it is not, never was, and never can be.
The proper C++ approach is a singleton class. But if you start out with an unbelievably
poor program structure, it makes no sense to warp everything to support that fundamentally
bad design. And it certainly makes no sense to create an even more unmanageable and
unmaintainable monster by given a DLL access to a structure which it has no business
knowing exists, in the name of "we don't want to fix the problem". You are asking the
impossible, anyway. It is not going to be possible to share in the way you want; the
fundamental implementation principles of DLLs prevent this.

The very first thing you must realize, if you ever write "((CSomeAppClass*)AfxGetApp())->"
is that you have made a deep and fundamental design error. Nothing can save you. You
have to reconsider the design, so that it is never, ever necessary to write that kind of
code. Programs that do this have deep structural problems that will come back to bite you
in the future. And guess what: this one just bit you. The above code is simply wrong.
****
>
>3
>The real situation is a bit more complex; what I need is not the CWinApp *
>to the derived app of the EXE; to be precise it is access to a CWinApp
>derived CBaseApp which is implemented in in a base LIB which is used by
>nearly 20 MFC programs which derive from this CBaseApp instead of CWinApp;
>the C# DLL which is between EXE and Base LIB in hierarchy must only be able
>to access the members of CBaseApp, not the derived CxxxApp objects.
****
That is a truly scary concept. Not only was there a fundamentally bad design done, but
this bad design was then used as the basis of a suite of programs! This is what happens
when you let C programmers who don't understand C++ do software design. This is a design
so horrible that if someone proposed it, I would be torn between firing them for
incompetence and wondering if they should receive some training that would salvage them.
But it should never have been accepted. Given that you have it, it is not going to be
possible to replicate this class in your DLL, nor would it make sense to use the
executable instance in the DLL. If you cannot fix this problem, which seems to be a very
deep one, then you have to live with the consequences, which is to initialize twice.
****
>
>Given the actual situation and requirements it would be a very elegant (in
>the sense of "much benefit with little effort") solution if we simply could
>access the MFC app object from C# source ..
****
No. There is no possible way the word "elegant" could EVER be used in this description,
except possible "It is possible to produce a solution which is the polar opposite of the
word 'elegant', that is, an unmaintainable kludge, which probably will not work and can
never be made to work, but which gives the illusion of being a low-cost solution". Then
you can use the word "elegant".

The CAUSE of this disaster was someone thinking that deriving a heavy-duty class from
CWinApp was "much benefit with little effort". It was certainly little effort; in the
short term, it gave the illusion of benefit, but in fact it was a horrible example of
worst-possible design, and guess what: it had distinct negative benefit in the context of
needed to do a DLL of the type you describe. So I would never confuse the word "elegant"
with "cheap, and sufficing to satisfy lazy programmers".

The DLL does not need to know about the base class. The DLL needs to have access to
objects which are the initialized objects for, say, the database interface. You are free
to provide these objects to it. Wrapping this initailization up in a CWinApp-derived
class is a structural failure, a linguistic failure, and a design failure. It is the
result of letting someone who was totally clueless about OO design and C++ make design
decisions 15 years ago. You are now stuck with a mess. There are two ways to fix this
mess: (a) clean up the design so it doesn't involve any of the poor decisions that have
been made (b) live with the fact that initialization is done twice.
joe
>
>Werner
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm