15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


AFXEXT: complete Soap Opera

Matthias Bohlen -- MATTES@logotec.com
Tuesday, April 23, 1996

Hello,

two weeks ago, I started a thread here about linking problems with 
AFX extension DLL's. I have received responses from many people but 
the problem still remains. To put things absolutely clear, I re-state 
it with complete info (sorry for the extreme length of this mail 
message, but the MS guys seem to have a problem there).

-------------- List of facts starts here -------------------------

A) I use Visual C++ 4.0. I write an EXE program with several 
MFC extension DLL's (_AFXEXT, _AFXDLL, _WINDLL defined).

B) My problem is: I want to access resources inside the *.RES file that 
is linked to an extension DLL.

C) Microsoft offers two solutions:
C.1) call AfgxSetResourceHandle( hExtensionDLL ) (that works!)
C.2) call AFX_MANAGE_STATE( AfxGetStaticModuleState() ) (that does 
     NOT work!)

D) In "DLLs: Building and Using an Extension DLL", Microsoft states 
that I have to think about the following to have a correct MFC extension 
DLL:
" * It does not have a CWinApp-derived object.
 * It calls AfxInitExtensionModule in its DllMain function. The
return value of this function should be checked. If a zero value is
returned from AfxInitExtensionModule, return 0 from your DllMain
function.
 * It will create a CDynLinkLibrary object during
initialization if the extension DLL wishes to export CRuntimeClass
objects or resources to the application. * For an example of a DLL
that fulfills the basic requirements of an extension DLL, see the MFC
Advanced Concepts sample DLLHUSK. In particular, look at the
TESTDLL1.CPP and TESTDLL2.CPP files."
Found out: to do this, you have to #include "afxdllx.h".

E) In "Managing the State Data of MFC Modules", Microsoft states 
   that: 
A module's state data is contained in a structure, and is always via a
pointer to that structure. When the flow of execution enters a
particular module (as shown in Figure 2), that module's state must be
the "current" or "effective" state. Therefore, each thread object has
a pointer to the effective state structure of that application.
Keeping this pointer updated at all times is vital to managing the
application's global state and maintaining the integrity of each
module's state. Incorrect management of the global state can lead to
unpredictable application behaviour."

F) Statement E) told me that AFX_MANAGE_STATE would be absolutely 
necessary. Therefor, I chose to take Step C.2.

G) Step C.2 caused linker errors about multiply defined symbols:
mfcs40d.lib(dllmodul.obj) : error LNK2005: __pRawDllMain already
defined in DLLINIT.OBJ mfcs40d.lib(dllmodul.obj) : error LNK2005:
_DllMain@12 already defined in DLLINIT.OBJ 
mfcs40d.lib(dllmodul.obj) :
warning LNK4006: __pRawDllMain already defined in DLLINIT.OBJ; second
definition ignored 
mfcs40d.lib(dllmodul.obj) : warning LNK4006:
_DllMain@12 already defined in DLLINIT.OBJ; second definition ignored

H) To track the problem down, I browsed a little in \MSDEV\MFC\SRC 
and found the only place where AfxGetStaticModuleState() is defined. 
This file is called DLLMODUL.CPP. The file also contains these interesting 
lines of code:
//////////////////////////////////////////////////////////////////////
////// // export DllMain for the DLL

extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID
                    /*lpReserved*/)
{
   ...
}
extern "C" BOOL WINAPI RawDllMain(HINSTANCE, DWORD dwReason, LPVOID);
extern "C" BOOL (WINAPI* _pRawDllMain)(HINSTANCE, DWORD, LPVOID) =
                &RawDllMain;
extern "C"
BOOL WINAPI RawDllMain(HINSTANCE, DWORD dwReason, LPVOID)
{
   ...
}

K) From Step "D", we know that I had to #include "afxdllx.h". This 
file contains the interesting code lines:
extern "C" BOOL WINAPI ExtRawDllMain(HINSTANCE, DWORD dwReason,
                                     LPVOID);
extern "C" BOOL (WINAPI* _pRawDllMain)(HINSTANCE, DWORD,
                                       LPVOID) = &ExtRawDllMain;

L) From "H" and "K" we can see that we need not wonder about the
name clashes: We have two pRawDLLMain's (from DLLMODUL.CPP and from 
AFXDLLX.H) and two DLLMain's (one from DLLMODUL.CPP, the other from 
my own DLL initialization module). The linker messages from Step "G" 
are logical. Check mate!

----------- End of fact list ------------------------------------

OK, what do we learn from this? I think, one of the following must be 
true:

a) MS did not pay attention when writing the code (I cannot imagine
   that!).

b) MS does not want me to call AFX_MANAGE_STATE inside an MFC 
   extension DLL but forgot to say that.

Possibility "b" is more likely because in "TN058: MFC Module State 
Implementation", Microsoft states:

"Note that certain kinds of DLLs, specifically "MFC Extension" DLLs
don't switch the module state in their RawDllMain (actually, they
usually don't even have a RawDllMain). This is because they are
intended to behave "as if" they were actually present in the
application that uses them. They are very much a part of the
application that is running and it is their intention to modify that
application's global state."

----------

End of the story: I kept my DLLMain, threw out AFX_MANAGE_STATE and 
replaced it by the following C++ class:

extern AFX_EXTENSION_MODULE LOGOCADDLL;
class dll_instance_switcher
{
    public:
        dll_instance_switcher()
          {
            m_hinst = AfxGetResourceHandle();
            AfxSetResourceHandle (LOGOCADDLL.hResource);
          }

        ~dll_instance_switcher()
          {
            AfxSetResourceHandle (m_hinst);
          }

    private:
        HINSTANCE m_hinst;
};


I put an object of this class into every exported function and I can 
find the resources OK.

Does somebody want to comment?

Bye...
Matthias Bohlen

-------------------------------------------------------
Matthias Bohlen               Logotec Software GmbH
Phone: +49 228 64 80 520      Chateauneufstr. 10 
FAX:   +49 228 64 80 525      D-53347 Alfter, Germany

E-mail: mattes@logotec.com
-------------------------------------------------------



Mike Blaszczak -- mikeblas@msn.com
Friday, April 26, 1996

----------
From: 	owner-mfc-l@netcom.com on behalf of Matthias Bohlen
Sent: 	Tuesday, April 23, 1996 09:39

 > To put things absolutely clear, I re-state 
 > it with complete info (sorry for the extreme length of this mail 
 > message, but the MS guys seem to have a problem there).

What problem do MS guys seem to have with long mail? I'm guessing that you're 
using VC++ 4.0 and MFC 4.0 but you don't explicitly say so.  Are you saying 
that the way I ask for the specific versions of your tools all of the time is 
a problem?

 > B) My problem is: I want to access resources inside the *.RES file that 
 > is linked to an extension DLL.

You don't say what module wants to retrieve resources from what module or 
modules.

If you want your EXE to access resources in your MFC extension DLLs, you 
should have no problem doing so if the DLLs are loaded.  Just call the 
appropriate load routine, like CBitmap::LoadBitmap(). If you want your DLL to 
load resources from its own self, you should have no problem doing so. If you 
want your DLL to load reousrces from other DLLs, you'll need to call 
AfxSetResourceHandle().

If you're explicitly loading these DLLs, or if you have some resources in one 
DLL with the same ID as resources in another DLL, you have other problems and 
these rules might not apply to you.

> F) Statement E) told me that AFX_MANAGE_STATE would be absolutely 
> necessary. Therefor, I chose to take Step C.2.

The article you quoted should have explained that the entry points in question 
come from outside of your modules.  If your _AFXDLL-build MFC application is 
running and calls into an MFC extension DLL, MFC will maintain the module 
state for you.  If some other module that is _not_ an MFC program or not an 
_AFXDLL-built MFC program calls into your DLL, you'll need to worry about 
managing the module state yourself.

> H) To track the problem down, I browsed a little in \MSDEV\MFC\SRC 

You should browse a little more in MSDEV\MFC\SRC.  It sounds like the original 
problem you had was that some DLL or EXE in your scenario was trying to load a 
resource or two and wasn't able to do so. If that happened to me, I would 
trace into the MFC function which did the loading. There' you'd learn about 
the function AfxFindResource() and probably be able to make some conclusions 
about what's really going on.

> b) MS does not want me to call AFX_MANAGE_STATE inside an MFC 
>   extension DLL but forgot to say that.

There are situations when you need to do this; see a couple of paragraphs ago. 
 "Forgot to say that" is downright abrasive: when you buy a car, do you think 
that the car company "forgot to say" that you shouldn't drive into trees, 
shouldn't drive into children on tricycles, and shouldn't drive in reverse 
down the highway?  Even if the manual said all of that, do you think that the 
manufacturer also "forgot to say that" you shouldn't drive into the lake?

You can invent tens of dozens of different DLL architectures. It is impossible 
that Microsoft would have all the forsight to predict every one of them, the 
forsight to guess what problems you might run into, and the time and resources 
to document every combination of those situations.

Don't you think?

> I put an object of this class into every exported function and I can 
> find the resources OK.

Exported function?  So, your DLL offers a C-level interface?  Your first 
statement:

> A) I use Visual C++ 4.0. I write an EXE program with several 
> MFC extension DLL's (_AFXEXT, _AFXDLL, _WINDLL defined).

seems ambiguous. Is your EXE an MFC program, or not?  Is your EXE built with 
_AFXDLL or not?  That you need this helper class suggests that you've not 
written an MFC _AFXDLL executable or that you're loading resources that belong 
to one DLL from another DLL, or that the resources aren't really in a proper 
extension DLL.  Otherwise, you shouldn't need to play with 
AfxSetResourceHandle().

 > Does somebody want to comment?

See above.

.B ekiM
TCHAR sz[] = _T("I don't speak for Microsoft.");



Dan Kirby -- dkirby@accessone.com
Monday, April 29, 1996

You're solution is a good  one.  Your discoveries are "by design".  The 
module state for an extension DLL is the same as the .EXE since there is no 
CWinApp object in an Extension DLL.   Your resources will be found if you 
have properly hooked up the CDynlinklibrary object and you don't have any 
conflicting resource IDs in other modules (.EXE and .DLLs).  So normally, 
there isn't a need to call AfxSetResourceHandle().  But if you want to call 
AfxSetResourceHandle() to be explicit about which module has the resource 
that is perfectly fine.

--dan


----------
From: 	Matthias Bohlen[SMTP:mattes@logotec.com]
Sent: 	Tuesday, April 23, 1996 9:39 AM
To: 	mfc-l@netcom.com
Subject: 	AFXEXT: complete Soap Opera

Hello,

two weeks ago, I started a thread here about linking problems with
AFX extension DLL's. I have received responses from many people but
the problem still remains. To put things absolutely clear, I re-state
it with complete info (sorry for the extreme length of this mail
message, but the MS guys seem to have a problem there).

-------------- List of facts starts here -------------------------

A) I use Visual C++ 4.0. I write an EXE program with several
MFC extension DLL's (_AFXEXT, _AFXDLL, _WINDLL defined).

B) My problem is: I want to access resources inside the *.RES file that
is linked to an extension DLL.

C) Microsoft offers two solutions:
C.1) call AfgxSetResourceHandle( hExtensionDLL ) (that works!)
C.2) call AFX_MANAGE_STATE( AfxGetStaticModuleState() ) (that does
     NOT work!)

D) In "DLLs: Building and Using an Extension DLL", Microsoft states
that I have to think about the following to have a correct MFC extension
DLL:
" * It does not have a CWinApp-derived object.
 * It calls AfxInitExtensionModule in its DllMain function. The
return value of this function should be checked. If a zero value is
returned from AfxInitExtensionModule, return 0 from your DllMain
function.
 * It will create a CDynLinkLibrary object during
initialization if the extension DLL wishes to export CRuntimeClass
objects or resources to the application. * For an example of a DLL
that fulfills the basic requirements of an extension DLL, see the MFC
Advanced Concepts sample DLLHUSK. In particular, look at the
TESTDLL1.CPP and TESTDLL2.CPP files."
Found out: to do this, you have to #include "afxdllx.h".

E) In "Managing the State Data of MFC Modules", Microsoft states
   that:
A module's state data is contained in a structure, and is always via a
pointer to that structure. When the flow of execution enters a
particular module (as shown in Figure 2), that module's state must be
the "current" or "effective" state. Therefore, each thread object has
a pointer to the effective state structure of that application.
Keeping this pointer updated at all times is vital to managing the
application's global state and maintaining the integrity of each
module's state. Incorrect management of the global state can lead to
unpredictable application behaviour."

F) Statement E) told me that AFX_MANAGE_STATE would be absolutely
necessary. Therefor, I chose to take Step C.2.

G) Step C.2 caused linker errors about multiply defined symbols:
mfcs40d.lib(dllmodul.obj) : error LNK2005: __pRawDllMain already
defined in DLLINIT.OBJ mfcs40d.lib(dllmodul.obj) : error LNK2005:
_DllMain@12 already defined in DLLINIT.OBJ
mfcs40d.lib(dllmodul.obj) :
warning LNK4006: __pRawDllMain already defined in DLLINIT.OBJ; second
definition ignored
mfcs40d.lib(dllmodul.obj) : warning LNK4006:
_DllMain@12 already defined in DLLINIT.OBJ; second definition ignored

H) To track the problem down, I browsed a little in \MSDEV\MFC\SRC
and found the only place where AfxGetStaticModuleState() is defined.
This file is called DLLMODUL.CPP. The file also contains these interesting
lines of code:
//////////////////////////////////////////////////////////////////////
////// // export DllMain for the DLL

extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID
                    /*lpReserved*/)
{
   ...
}
extern "C" BOOL WINAPI RawDllMain(HINSTANCE, DWORD dwReason, LPVOID);
extern "C" BOOL (WINAPI* _pRawDllMain)(HINSTANCE, DWORD, LPVOID) =
                &RawDllMain;
extern "C"
BOOL WINAPI RawDllMain(HINSTANCE, DWORD dwReason, LPVOID)
{
   ...
}

K) From Step "D", we know that I had to #include "afxdllx.h". This
file contains the interesting code lines:
extern "C" BOOL WINAPI ExtRawDllMain(HINSTANCE, DWORD dwReason,
                                     LPVOID);
extern "C" BOOL (WINAPI* _pRawDllMain)(HINSTANCE, DWORD,
                                       LPVOID) = &ExtRawDllMain;

L) From "H" and "K" we can see that we need not wonder about the
name clashes: We have two pRawDLLMain's (from DLLMODUL.CPP and from
AFXDLLX.H) and two DLLMain's (one from DLLMODUL.CPP, the other from
my own DLL initialization module). The linker messages from Step "G"
are logical. Check mate!

----------- End of fact list ------------------------------------

OK, what do we learn from this? I think, one of the following must be
true:

a) MS did not pay attention when writing the code (I cannot imagine
   that!).

b) MS does not want me to call AFX_MANAGE_STATE inside an MFC
   extension DLL but forgot to say that.

Possibility "b" is more likely because in "TN058: MFC Module State
Implementation", Microsoft states:

"Note that certain kinds of DLLs, specifically "MFC Extension" DLLs
don't switch the module state in their RawDllMain (actually, they
usually don't even have a RawDllMain). This is because they are
intended to behave "as if" they were actually present in the
application that uses them. They are very much a part of the
application that is running and it is their intention to modify that
application's global state."

----------

End of the story: I kept my DLLMain, threw out AFX_MANAGE_STATE and
replaced it by the following C++ class:

extern AFX_EXTENSION_MODULE LOGOCADDLL;
class dll_instance_switcher
{
    public:
        dll_instance_switcher()
          {
            m_hinst = AfxGetResourceHandle();
            AfxSetResourceHandle (LOGOCADDLL.hResource);
          }

        ~dll_instance_switcher()
          {
            AfxSetResourceHandle (m_hinst);
          }

    private:
        HINSTANCE m_hinst;
};


I put an object of this class into every exported function and I can
find the resources OK.

Does somebody want to comment?

Bye...
Matthias Bohlen

-------------------------------------------------------
Matthias Bohlen               Logotec Software GmbH
Phone: +49 228 64 80 520      Chateauneufstr. 10
FAX:   +49 228 64 80 525      D-53347 Alfter, Germany

E-mail: mattes@logotec.com
-------------------------------------------------------




begin 600 WINMAIL.DAT
M>)\^(A@$`0:0" `$```````!``$``0>0!@`(````Y 0```````#H``$(@ <`
M& ```$E032Y-:6-R;W-O9G0@36%I;"Y.;W1E`#$(`0V ! `"`````@`"``$$
MD 8`; (```(````,`````P``, ,````+``\.``````(!_P\!````/P``````
M``"!*Q^DOJ,0&9UN`-T!#U0"`````&UF8RUL0&YE=&-O;2YC;VT`4TU44 !M
M9F,M;$!N971C;VTN8V]M```>``(P`0````4```!33510`````!X``S !````
M$0```&UF8RUL0&YE=&-O;2YC;VT``````P`5# $````#`/X/!@```!X``3 !
M````$P```"=M9F,M;$!N971C;VTN8V]M)P```@$+, $````6````4TU44#I-
M1D,M3$!.151#3TTN0T]-`````P``.0`````+`$ Z`0````(!]@\!````! ``
M``````,-`````P``, 0````+``\.`0````(!_P\!````0P````````"!*Q^D
MOJ,0&9UN`-T!#U0"```!`&UA='1E``,P`0```!,`
M``!M871T97- ;&]G;W1E8RYC;VT```,`%0P!`````P#^#P8````>``$P`0``
M`!4````G;6%T=&5S0&QO9V]T96,N8V]M)P`````"`0LP`0```!@```!33510
M.DU!5%1%4T!,3T=/5$5#+D-/30`#```Y``````L`0#H``````@'V#P$````$
M````````! (!^0\!````0P````````"!*Q^DOJ,0&9UN`-T!#U0"```!`&UA
M='1E`!X,`0````4```!33510`````!X`'PP!````%0```&1K
M:7)B>4!A8V-E``@0`0``
M`&4```!93U5215-/3%5424].25-!1T]/1$].15E/55)$25-#3U9%4DE%4T%2
M12)"641%4TE'3B)42$5-3T153$535$%4149/4D%.15A414Y324].1$Q,25-4
M2$5304U%05-42$5%6$53``````(!"1 !````N@\``+8/``"W( ``3%I&=7<4
M/C/_``H!#P(5`J0#Y 7K`H,`4!,#5 (`8V@*P'-E=.XR!@`&PP*#,@/&!Q,"
M@S(S$P]F- /%`@!P,Q0@"PH2\@P!8P! ($I9"& G%Z @8QS0(U$(&+>:@60!4 +@"("
M12):'F%_'H07H!SP"' DT 0@`_!L90,@8B&R=6X>``:0(%IY"& @$< ?," 5
M\&^J< 20;" `:!W@:PF #"!U)B C4D-$>6[*; N :RQ@8G(*P" `KR9%`' >
M`"HB9 (@)P5 KRIC`' @``6@;AIP:2: Q0N 9RAG($E$!" FL6YO)0(@]00@
M*"13+9(N:2+A85,EH"602PD]RXR'; >0#4K@70EH&,S01-P
M9GAI!F!T4BB%2"V1(4 H[3*20AT@*>9W`' %0#3?OS7K-](I82) "U O4&DM
M<=,&X#;Q=V@O4&@@]A' OR,T+\0'3O2Q%+`E%O
M3&YU)E-3CT@+Y$%&)'!85%C02Q$+4%<2`!S0,M!A)B!/*N%A\T ?02,S-D*7
M%"(,`4.6)$AE*3!O+#Y\='=U):!W">!K'9$=T#. 2;\A8@`@*X$=L"-0%Z!A
M'@#_)1,ZQ"QB+X(JL0)@%H H\L\C4#[66K$B/"=S'F!AD'@)-!I'S >
M`"AQ@+2%T"H4ZD62#6S?O"X "
M$#&0'/!R+/$ATB-2KR)!:Q$%G=190_QS@">!H8#?A+G1J)R4#,I!S/GYWFB!,! `%0'(!9OT`
MT'1TL6'"!" E$W><=YDM/GQ!.;!AD'41\"!6#00`=0= ); K*R T]"XP9G)W
M!1 AH2;B)''_*K$)P".@9'01\!\Q?6$*A=A-1D-E?C&07UJT,X#'@B(BX8*1
M5TE.(N(-L=4^,61VGD(YL$UHL6I%_P0`6-!^(3>E`- HT00@*'@-:U%I#; C
M0RHN4D7_!? ^("%!/0-N5@0@+&(TI/LB'G:M0X5!+U #8!SP`8!_(YDI)F+A 'D>,*
MA9A33D]4DM.3-PJ%]D1\H0.@(C)26- VX ,0=Q[@+Y$MDE4DH9MR)PPB_S. 
MC1@A@= AP`Z!V!T *4/]Q]ZL&'. K
M0"$P'@`I81&PWP60*W%F<2H`';!Z!) EH/^LM 0`J]LK@6@SJ*\A$S. _:Q%
M,&@D*B&:$:J4"H6K!_^G>RD3!0!B@'YR+!-X@"R _WB +,LA( 40&J!N5K(!
M!S'\:7J6`1U2>JL`;(D1
MJ'$C4F(CX/LO4"AA<9L0<4(",+[!KV&_(BTS@'31= 2 X&369*RP_R3!'@`(
M4"3!!3!TL<&D(N'P2%532V9Q`Z *L981_R$P;6(7,"M@':!S\PJ%E4"#E1 B
MX3$N0U!0+8/=R^4RS&.)$F9@(@J%P1#_*;(ZX5C0-^$N$'(C,X J)YTWX2,D
ML0I B$$B83AP839@;'@N:"" /GQ%^YI$2-!N84"A,R#1EJ,BT-\AD!VP<@& 
MTI9$0=*'^=@>6(65?VP=Q]#TAP"H*A4L)X'#_T\0]4MUE*[#9
MD6("+7$I,?^]8C!QW'(!D/&A): #@=.G]^JVP#B!X6<7,,00`R A=/\MDFLR
MVD+3QMUR"< ZD"T!_]_QZ6%RUMB[R;*B%O+CQ-/_`(I3R\#?K[ 10.#R8R/E@&P=,!M@OR "@^,'!.2QP0,#6!6-!?7W!287>JAONZ(&)R>59E
M"[8FL2+A@V# 250N3T)*#1\.+\L/-U9E7ZJ%0#$)4!"U_Q&/$I4,OQ.O5F4W
MD*R +X)S#T%"$# V#[\6[Q(Z.[MTP2\!9!$JN?&ZDF/Q]$]R /_7 _K$@YL&NA<3"&\/^@$&GZ+A#C,&%RN##?L FB3]G NC!*
M0*GD7%QT4$2<158M48#@+5!34H#P_^JVV\%PD,["QM*M\#WQ7@'_/-$[(#/"
ME8^6E]OQ"[7 T'_+=JU3B2+9XC@A8@&[T4WX3T15B^#,<:N#B02Z(/^.8-H&
MP[-\\=US: "MT/-!?U9EBE%H`7(!HA +L([V+^\Z'SLO/#\]3R\YJSH!O*8_
MJH=PI<)85F6[,JR!(D,QSB9"3T^[\(-105 S89"JA2A(@V"5$4Y#/0,@:)I@
MY2''\<_P1%?H3U)$SW!WD(#$(*WP@<_P3%!63TE$E_JQ1ZTO*FP<@#=1Y?X+DK0_59F?4&?0PLPI.TN?0P0H0V3 \!QZ9BE.
M'T^W(#U'#YA4)O\*H]#?_]'B,Y2TYHDB-JHWBSE2.+3_I!9,#T-TD9%97UIO1F%4
M[_]KCVPX3]]0[U'_4P]4$6J/?W*_;(]4HE9 : MMMEPE3)E?!2)(I)#,LB)+
MI)#_8!'\$L:4DK+LL 3P\2&E4O^8\-O W:&@-P2&R."NH;VQ^[Q!'$!7[+#0
M5(XQ'(,T\?_:48'BL7,TZB[4=T+'1H+3_%@N*A',LHXB?5FC0*"QOWX>Y"*L
M\36VX<>_C,;O2N=WB5"DUI GE\>'OR-#Z8*UQ7SA'I)#JMN/1[]^@
MT["4$<#00Z[2]?'4<'HAF5PMB_AG\,[2U0!F_S P\6"Z,.6AB_F.;XOVF5S\
M3TM?\9=D8 +\4:R!L7/]\ (_*^&?T\_P@@+ZU:#8_^6%GF?M4#F'ZK8!0"UP
MSW#^:7FD7% $8.5 NU&MTS!Q[YB!]U'3QF5S* 9!P5"E4F_QT-.BJ\;7A2&&
MT-(L8O^6]*46(W#ZH0&R-H'Q@@(_OS;QEU#UHJ*#7+B[/&(*\?T%\6>E8<]1
MR- $8 'BTATV4 : Q#!B-A#W8B)B[V[ V_'B4(FB::\`+^'^T*,))DY23:
ML3*Q?]M!KO*#4Q$6"9"T4[#E9?_LH-K T%/9P&_I8K7;\::F_[3"
MB8)<)=UR>B%A(_[3T4+]\@%F;L"XXV 0X]&T)BL!_S=1^J&RU/.OWS+D80F1
MP[/^;36CN1/<@!3 !& +(.EQ_^LARA'ZQ;V?OJ7;\>U0FE#_\S+;L\,CLP2Y
MT[YT\L'B8/^NL*-DP<_TOO]NCV_2EHS$=]0"-_#G0'D<0$.PIE!P__H!!&!]
M5>0B_6#?P0KQGO_?+N)<)?U@,!/$$V*C8I0*>$,K*WNSJUY7A30
M,D!MMG.*_3#14][N?>#4R&* WP;?__?!>/O
MY/_8A/=0=HK1_]D^1%C>!6VV2W!V':CFV,'_E/#\(111^>+!8S1"U?/V(=\V
M@+91P'$_A"9Q9B] ^?#_F&(NXIH38Q@O53?1WS,*H/N0X ?-1)UR:D !L K0
M)?$OG?.>3_(<%UG?8 LT),0NQ%";_IHW\!NR*__OP#/`=_*
M%N_]S7.NB>"L<6-?8*K!(W'5RY!'#%!(I$9H@@$<0 `K-#D@,C(X(( V-" X
M," U%5"?.-7.$1"TU
MT#,S-#


Ranjiv Sharma -- RanjivS@datastorm.com
Wednesday, May 01, 1996


The only time you do not have to use your dll_instance_switcher class is   
if you do not have any resource ID's that are same in any of the   
extension DLL's that are being linked to the MFC App. This is really a   
problem, since the resource editor ends up using the same ID's for   
dialogs in different DLL's (starts with 101 for dialogs). Since it is a   
pain to keep track of unique resource ID's - especially if more than one   
person is working on a project, it is best to always use your   
dll_instance_switch class.

  The MFC solution may have been slightly more acceptable, if the   
resource chain always started with the Resource of the module in which   
the function was being executed, and then, if the resource was not found,   
to go through the other modules in the chain. The current implementation   
only leads to great confusion, when you have dialog boxes from other   
dll's coming up - or the wrong strings being loaded.

  In order to keep the same programming model for extension and non   
extension DLL's (which is what is desirable), you could define a macro   
something like this

#ifdef _AFXEXT
 #define SWITCH_RESOURCE  dll_instance_switcher
#else //_USRDLL
 #define SWITCH_RESOURCE AFX_MANAGE_STATE(AfxGetStaticModuleState())

Now you can do the same thing in every exported function in your dll

ExportedFuntion()
{
 SWITCH_RESOURCE;

 ....
}

 -Ranjiv
(ranjivs@datastorm.com)


 ----------
From:  owner-mfc-l[SMTP:owner-mfc-l@netcom.com]
Sent:  Monday, April 29, 1996 9:41 PM
To:  'mfc-l@netcom.com'; 'mattes@logotec.com'
Subject:  RE: AFXEXT: complete Soap Opera

You're solution is a good  one.  Your discoveries are "by design".  The   
module state for an extension DLL is the same as the .EXE since there is   
no CWinApp object in an Extension DLL.   Your resources will be found if   
you have properly hooked up the CDynlinklibrary object and you don't have   
any conflicting resource IDs in other modules (.EXE and .DLLs).  So   
normally, there isn't a need to call AfxSetResourceHandle().  But if you   
want to call AfxSetResourceHandle() to be explicit about which module has   
the resource that is perfectly fine.

 --dan


 ----------
From:  Matthias Bohlen[SMTP:mattes@logotec.com]
Sent:  Tuesday, April 23, 1996 9:39 AM
To:  mfc-l@netcom.com
Subject:  AFXEXT: complete Soap Opera

Hello,

two weeks ago, I started a thread here about linking problems with
AFX extension DLL's. I have received responses from many people but
the problem still remains. To put things absolutely clear, I re-state
it with complete info (sorry for the extreme length of this mail
message, but the MS guys seem to have a problem there).

 -------------- List of facts starts here -------------------------

A) I use Visual C++ 4.0. I write an EXE program with several
MFC extension DLL's (_AFXEXT, _AFXDLL, _WINDLL defined).

B) My problem is: I want to access resources inside the *.RES file that
is linked to an extension DLL.

C) Microsoft offers two solutions:
C.1) call AfgxSetResourceHandle( hExtensionDLL ) (that works!)
C.2) call AFX_MANAGE_STATE( AfxGetStaticModuleState() ) (that does
     NOT work!)

D) In "DLLs: Building and Using an Extension DLL", Microsoft states
that I have to think about the following to have a correct MFC extension
DLL:
" * It does not have a CWinApp-derived object.
 * It calls AfxInitExtensionModule in its DllMain function. The
return value of this function should be checked. If a zero value is
returned from AfxInitExtensionModule, return 0 from your DllMain
function.
 * It will create a CDynLinkLibrary object during
initialization if the extension DLL wishes to export CRuntimeClass
objects or resources to the application. * For an example of a DLL
that fulfills the basic requirements of an extension DLL, see the MFC
Advanced Concepts sample DLLHUSK. In particular, look at the
TESTDLL1.CPP and TESTDLL2.CPP files."
Found out: to do this, you have to #include "afxdllx.h".

E) In "Managing the State Data of MFC Modules", Microsoft states
   that:
A module's state data is contained in a structure, and is always via a
pointer to that structure. When the flow of execution enters a
particular module (as shown in Figure 2), that module's state must be
the "current" or "effective" state. Therefore, each thread object has
a pointer to the effective state structure of that application.
Keeping this pointer updated at all times is vital to managing the
application's global state and maintaining the integrity of each
module's state. Incorrect management of the global state can lead to
unpredictable application behaviour."

F) Statement E) told me that AFX_MANAGE_STATE would be absolutely
necessary. Therefor, I chose to take Step C.2.

G) Step C.2 caused linker errors about multiply defined symbols:
mfcs40d.lib(dllmodul.obj) : error LNK2005: __pRawDllMain already
defined in DLLINIT.OBJ mfcs40d.lib(dllmodul.obj) : error LNK2005:
_DllMain@12 already defined in DLLINIT.OBJ
mfcs40d.lib(dllmodul.obj) :
warning LNK4006: __pRawDllMain already defined in DLLINIT.OBJ; second
definition ignored
mfcs40d.lib(dllmodul.obj) : warning LNK4006:
_DllMain@12 already defined in DLLINIT.OBJ; second definition ignored

H) To track the problem down, I browsed a little in \MSDEV\MFC\SRC
and found the only place where AfxGetStaticModuleState() is defined.
This file is called DLLMODUL.CPP. The file also contains these   
interesting
lines of code:
//////////////////////////////////////////////////////////////////////
////// // export DllMain for the DLL

extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID
                    /*lpReserved*/)
{
   ...
}
extern "C" BOOL WINAPI RawDllMain(HINSTANCE, DWORD dwReason, LPVOID);
extern "C" BOOL (WINAPI* _pRawDllMain)(HINSTANCE, DWORD, LPVOID) =
                &RawDllMain;
extern "C"
BOOL WINAPI RawDllMain(HINSTANCE, DWORD dwReason, LPVOID)
{
   ...
}

K) From Step "D", we know that I had to #include "afxdllx.h". This
file contains the interesting code lines:
extern "C" BOOL WINAPI ExtRawDllMain(HINSTANCE, DWORD dwReason,
                                     LPVOID);
extern "C" BOOL (WINAPI* _pRawDllMain)(HINSTANCE, DWORD,
                                       LPVOID) = &ExtRawDllMain;

L) From "H" and "K" we can see that we need not wonder about the
name clashes: We have two pRawDLLMain's (from DLLMODUL.CPP and from
AFXDLLX.H) and two DLLMain's (one from DLLMODUL.CPP, the other from
my own DLL initialization module). The linker messages from Step "G"
are logical. Check mate!

 ----------- End of fact list ------------------------------------

OK, what do we learn from this? I think, one of the following must be
true:

a) MS did not pay attention when writing the code (I cannot imagine
   that!).

b) MS does not want me to call AFX_MANAGE_STATE inside an MFC
   extension DLL but forgot to say that.

Possibility "b" is more likely because in "TN058: MFC Module State
Implementation", Microsoft states:

"Note that certain kinds of DLLs, specifically "MFC Extension" DLLs
don't switch the module state in their RawDllMain (actually, they
usually don't even have a RawDllMain). This is because they are
intended to behave "as if" they were actually present in the
application that uses them. They are very much a part of the
application that is running and it is their intention to modify that
application's global state."

 ----------

End of the story: I kept my DLLMain, threw out AFX_MANAGE_STATE and
replaced it by the following C++ class:

extern AFX_EXTENSION_MODULE LOGOCADDLL;
class dll_instance_switcher
{
    public:
        dll_instance_switcher()
          {
            m_hinst = AfxGetResourceHandle();
            AfxSetResourceHandle (LOGOCADDLL.hResource);
          }

        ~dll_instance_switcher()
          {
            AfxSetResourceHandle (m_hinst);
          }

    private:
        HINSTANCE m_hinst;
};


I put an object of this class into every exported function and I can
find the resources OK.

Does somebody want to comment?

Bye...
Matthias Bohlen

 -------------------------------------------------------
Matthias Bohlen               Logotec Software GmbH
Phone: +49 228 64 80 520      Chateauneufstr. 10
FAX:   +49 228 64 80 525      D-53347 Alfter, Germany

E-mail: mattes@logotec.com
 -------------------------------------------------------






Mike Blaszczak -- mikeblas@msn.com
Friday, May 03, 1996

----------
From: 	owner-mfc-l@netcom.com on behalf of Ranjiv Sharma
Sent: 	Wednesday, May 01, 1996 09:33


 > The only time you do not have to use your dll_instance_switcher class is   
 > if you do not have any resource ID's that are same in any of the   
 > extension DLL's that are being linked to the MFC App.

This is not true.  It is _not_ necessary to manually manage the module state 
when the call is coming from another MFC AFXDLL-compiled module.  I outlined 
these rules in my previous note on this subject.  By insulating every entry 
point in your DLL with a class like the one in question, you'll can make a 
significant adverse effect on performance!

.B ekiM
TCHAR sz[] = _T("How's your Bud Ice?  Doo be doo be do...");




| Вернуться в корень Архива |