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

How can I get a MFC DLL with NO own CWinApp/AfxGetApp() ?

1,148 views
Skip to first unread message

weknewsgr...@discussions.microsoft.com

unread,
Jan 19, 2010, 5:25:01 AM1/19/10
to
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 ?

Thanks in advance for any hint.

Goran

unread,
Jan 19, 2010, 7:43:08 AM1/19/10
to
On Jan 19, 11:25 am, w...@newsgroups.nospam

IIRC...

Normally, you don't prevent this, you work with it.What's the reason
you want to prevent this?

Normally, a regular DLL that uses MFC works fine with other such DLLs/
exes. If, in your DLL, you link to MFC dynamically, what you need to
do is to to put AFX_MANAGE_STATE(AfxGetStaticModuleState()) at each
dll boundary method. That tells MFC what "module state" is in effect,
and so while running code from a given module, that module uses it's
own module state. That's it. (A tutorial explaining MFC dlls should
explain that in more detail).

If you link statically, I __think__ you don't need to do anything.

I don't remember what should be done when you are writing an MFC
__extension__ dll, but since you're using this from managed code,
you're not doing that.

Goran.

weknewsgr...@discussions.microsoft.com

unread,
Jan 19, 2010, 8:55:01 AM1/19/10
to
"Goran" wrote:

> .
Hello Goran, thanks for your post.
The reason is that the CWinApp-derived class in the (MFC-)EXE implements a
lot of basic initialization and functionality (which is time consuming) which
I want to be available in the CWinApp/AfxGetApp() called from the DLL also;
but this is only the case if AfxGetApp() called from the DLL points to the
App-object of the EXE and not to a separate App-Object of the DLL

Werner

Ajay Kalra

unread,
Jan 19, 2010, 9:02:56 AM1/19/10
to
On Jan 19, 5:25 am, w...@newsgroups.nospam

You cant prevent it. However you can switch states using
AFX_MANAGE_STATE macros. Also, the scenario you pointed out would be
present in a Regular MFC dll and not in a MFC Extension DLL. Any
reason to have a regular DLL as opposed to an MFC Extension DLL?

--
Ajay

Joseph M. Newcomer

unread,
Jan 19, 2010, 11:04:19 AM1/19/10
to
See below...

****
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: newc...@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

Joseph M. Newcomer

unread,
Jan 19, 2010, 11:59:12 AM1/19/10
to
See below...

****
This is because you think it is an "App-object" that might have something to do with the
CWinApp-derived class of your executable. As I pointed out, this confusion arises because
of the similar textual name. You are clearly thinking that the functionality of the
CWinApp class in a DLL has something to do with the CWinApp class of an executable.

What functionality executed in the DLL is "time consuming"? Can you quantize this time?
Generally, when we use the phrase "time consuming" we actually have a belief that this
consumes enough time to matter, and can usually say "This uses 200ms" or some similar
explicit statement. I saw 23 assignment statments and a few function calls, so I would
guess that it takes something under 100ns to do the initiialization I saw in the
constructor. Not what I would consider a serious consumption of time. Are you seeing
something different? If so, please explain. Note that in loading the DLL, if the disk
misses a sector because of rotational latency, this will typically add 5-10ms (5000-10000
times more delay than the initialization I saw). If it has to seek, because the DLL is
stored on a different cylinder, you lose another factor of a hundred or so. This means
that the time lost in 10,000 executions by the "overhead" you are referring to more than
likely is completely swamped by a single load of the DLL in a single execution. So I fail
to see where there is any "time consuming" overhead here. Did you single-step execute the
initialization of the CWinApp class in your DLL? Did you instrument it in any way? If
you cannot tell me the exact amount of time it "consumes", you are probably trying to
"optimize" something not even worthy of discussion.

Now, let's say I'm off by a couple orders of magnitude. For example, suppose it takes
10,000 instructions to initialize the CWinApp. 10,000 instructions. At 2 instructions
per clock cycle (not uncommon, sometimes it can be 3 or 4 with newer chips), that's 5,000
clock cylces. On a 2.8GHz machine, that's, wow, almost TWO WHOLE MICROSECONDS. A single
rotational delay miss (5-10ms) means that you can do somewhere between 2500 and 5000
initalizations in a single rotational miss. And what makes you otpimisitically think that
you would have only one rotational miss per load? Unless you have raw numbers and can
make a quantitative case, phrases like "time consuming" are meaningless noise.

Note that a single page fault costs you 20,000,000-40,000,000 CPU cycles.

So why are you overly concerned about a nonexistent problem?
joe
>Werner

weknewsgr...@discussions.microsoft.com

unread,
Jan 20, 2010, 4:36:01 AM1/20/10
to
"Ajay Kalra" wrote:

> .
Hello Ajay, thanks for your help.
My DLL (.NET) exposes .NET classes and must be accessible from anonther .NET
DLL written in C#. My EXE is written in C++, uses MFC and is compiled with
/clr.
http://msdn.microsoft.com/en-us/library/h5f7ck28(VS.80).aspx says :
"An extension DLL can also be used by a regular DLL that is dynamically
linked to MFC.", but my C# DLL is not linked to MFC, only the EXE is.
So I think I can't use a MFC extension DLL; or am I wrong with this ?

Werner

weknewsgr...@discussions.microsoft.com

unread,
Jan 20, 2010, 4:51:01 AM1/20/10
to


"Joseph M. Newcomer" wrote:

> .
>
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.

Werner

Goran

unread,
Jan 20, 2010, 6:02:37 AM1/20/10
to
On Jan 20, 10:51 am, w...@newsgroups.nospam
> > email: newco...@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.

weknewsgr...@discussions.microsoft.com

unread,
Jan 20, 2010, 7:56:08 AM1/20/10
to
"Goran" wrote:

> > > if you call it from MFC? Doesn't make any sense. The DLL is a DLL.. It is not an MFC

> .
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"
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()

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.

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 ..

Werner

Ajay Kalra

unread,
Jan 20, 2010, 8:47:32 AM1/20/10
to

> 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 ;-)

Why does a C# app need CWinapp object/functionality from MFC? I would
expose exactly and only what is needed by clients, C# or not, without
even letting them know that CWinApp object exists. Expose the
functionality instead of the object.

--
Ajay

Joseph M. Newcomer

unread,
Jan 20, 2010, 8:55:40 AM1/20/10
to
An extension DLL is a concept normally applied to native code. If you have a DLL compiled
with /clr, and you are calling it from MFC code, then the MFC code has to be prepared to
handle CLR-style objects. But the concept of CWinApp is not relevant here. There might
be a thing derived from "CWinApp" in your DLL, but any impression that it has anything at
all to do with the thing called "CWinApp" in the application is mistaken.
joe

Joseph M. Newcomer [MVP]
email: newc...@flounder.com

Goran

unread,
Jan 20, 2010, 9:03:29 AM1/20/10
to
On Jan 20, 1:56 pm, w...@newsgroups.nospam
<weknewsgroupsnos...@discussions.microsoft.com> wrote:

> "Goran" wrote:
> 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"  

Ok, so in fact you already have a (legacy) application. I don't see
where does the DLL come from. Did you just started writing a DLL with
the requirement to access the app from .NET? If so, I would suggest
you drop the idea, and go with COM, the most standard Windows app
interoperability approach. Did you consider that?

> 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, you did not think that through. It's not comfortable. In reality,
the code that uses auth/dbinit "services" has to do e.g. the
following:

#include "MyApp.h"
...
static_cast<CMyApp*>(AfxGetApp())->auth();
// In fact, if your team was any smart,
// that should have become theApp.auth()
// at some point

So why do you want to pull CWinApp into a piece of code that uses only
"custom" functionality? There's no reason! I know, I've been doing it
for years before dropping the idea. It's stupid, and I am sure that
others here will tell you the same.

Instead, your code could have had, for example, this:

#include "auth.h"
...
auth()
//or
someProbablyStaticObj.Auth();

And if same piece of code uses something from CWinApp, then AfxGetApp
() is OK, you just go e.g.:

AfxGetApp()->AddDocTemplate();

(No additional #include needed, because stdafx.h includes afxwin.h)

In other words, there is NO benefit to putting e.g. "auth" in the app
class. There is (I am repeating myself here), an inconvenience of
creating random compile time dependencies. If your code has been
developed, as you say, for 20 years, then consider this: if you change
smallest of things in your CBaseApp, that triggers massive, and I mean
MASSIVE, recompilation cycle. Just think how much time has been lost
waiting for this compilation over the years. All because your
colleagues put all their eggs in one basket, so to speak.

> 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.

> 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 ..

Accessing native C++ code from C# is AFAIK not possible. What should
be possible, is to write C++/CLI wrapper library for your base
library. That is similar to creating COM wrapper for your application,
but the wrapper is pure .NET code. That would be the best approach
then (better than COM, because you really only seem to be interested
in base LIB functionality, so no executable module is needed).

Goran.

Joseph M. Newcomer

unread,
Jan 20, 2010, 9:11:24 AM1/20/10
to
See below...

On Wed, 20 Jan 2010 01:51:01 -0800, w...@newsgroups.nospam
<weknewsgr...@discussions.microsoft.com> wrote:

****
No, This structure makes no sense. A DLL, by its very definition, has no concept of any
detail of an app. It cannot know any variable in the app, whether by name, or by function
such as AfxGetApp(). It cannot know the structure of objects owned by and managed by the
app. You are asking for a fundamental violation of modularity here, one so deep that it
is simply not possible to conceive of in the DLL structure.

While it is possible to argue that you could pass in a pointer to a CWinApp, the problem
now is that the DLL must precisely reflect the implementation of every single one of its
parent executables, and if any one of them change, it must be recompiled. This introduces
dependencies that are not only illogical, but impossible to realize in practice.

First premise: A DLL lives in a world of its own. Anything it accesses is either managed
entirely by the DLL, or passed into the DLL, and those things which are passed in must be
defined either by standard libraries (e.g., CString, std::string) or by the DLL itself.
Purists willl argue that you should not even use standard libraries. Bottom line: there
is no way it makes sense for a DLL that is going to be used in more than one app, and in
fact in more than one executable type, to have any knowledge of one realization of one
class in one executable type.
****


>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.

****
First, a very, very serious flaw here: why should you care? You clearly don't care if the
DLL has to initialize these when it is called from VB, JavaScript, C#, FORTRAN, Pascal, or
any of the other dozens of possible languages that might call a DLL; why should it matter
if it has to do it when called from an MFC app? It is the purest coincidence that the MFC
app happens to initialize the same things.

Now, if you want to provide pointers to objects, such as a database, then the correct
thing is to create a separate DLL that does this initialization and manages these objects.
Your MFC app calls this DLL, and gets back pointers to these objects, and your C# app
calls this DLL and gets back a something that references the object. The core
functionality is then in your DLL. Perhaps you need three DLLs: one to manage the
objects, one to interface the objects with the DLL that does the work, and one to do the
work.

It is a common mistake to think "because I have a pointer to something, I should share
that by giving access to the structure that contains the pointer" instead of "Give me an
abstraction of an object and let me share it around". If it is meant to be shared, it
must be managed by something that creates and shares it, that can be called independent of
the implementation mechanism. So if you have a "db interface", then it should be managed
by the "db interface" DLL, not by the executable. You have a very poor structure here if
it is owned and managed both by your current DLL and by an application.
joe
****
>
>Werner

Joseph M. Newcomer

unread,
Jan 20, 2010, 9:33:50 AM1/20/10
to

****
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: newc...@flounder.com

0 new messages