A
Al Norman
We have two separate DLLs that do not interact (directly, at least). One is
an MFC extension DLL that was built back in VC++ 6 days (but has been
recompiled with VS2005). The other is a DLL that contains .Net functions
wrapped in C++ (as described by Paul DiLascia -- see
http://msdn.microsoft.com/msdnmag/issues/06/06/CAtWork/default.aspx). Both
DLLs specify 'Use MFC in a shared DLL'.
Since we have an old VC 6 application (large) that we would like to start
using .Net classes with (e.g. regular expressions), we have been trying to
implement the wrapped approach, which involves creating a DLL with the
wrapped .Net stuff in it. Hope that's clear ...
What we have found is that, when we use the wrapped DLL, we blow up with a
'loader lock' issue. This only occurs, though, when we do the following:
1. Implicitly link to the MFC extension DLL (XMap).
2. Create a thread, using AfxBeginThread, that will use the XMap DLL to do
some time-consuming initialization stuff.
3. When the initialization is done, that secondary worker thread exits -- at
which point we get the following (i.e. the mda:msg -- I have included the
debug output from the point at which the XMap DLL got loaded):
XMAP.DLL Initializing!
'CAD.exe': Loaded
'D:\views\al08333_view_SS_9_3_Dev\xwaveCAD\Workstation\ciids96\debug\Splash.dll',
Symbols loaded.
'CAD.exe': Unloaded
'D:\views\al08333_view_SS_9_3_Dev\xwaveCAD\Workstation\ciids96\debug\Splash.dll'
'CAD.exe': Loaded
'C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll', Symbols loaded
(source information stripped).
'CAD.exe': Loaded
'C:\WINDOWS\WinSxS\x86_Microsoft.VC80.CRT_1fc8b3b9a1e18e3b_8.0.50727.91_x-ww_0de56c07\msvcr80.dll',
Symbols loaded (source information stripped).
CDEQView::OnInitialUpdate() called
Comms IndicationHandler set to CWorkstation::HandleIndications
'CAD.exe': Loaded
'C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Culture.dll', Symbols loaded
(source information stripped).
'CAD.exe': Unloaded
'C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Culture.dll'
'CAD.exe': Loaded
'C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\mscorlib\467bb10fb591904e8c6509fc55279db2\mscorlib.ni.dll',
No native symbols in symbol file.
'CAD.exe': Loaded
'C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Culture.dll', Symbols loaded
(source information stripped).
'CAD.exe': Unloaded
'C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Culture.dll'
<mda:msg xmlns:mda="http://schemas.microsoft.com/CLR/2004/10/mda">
<!--
DLL 'c:\tools\RegexWrapD.dll' is attempting managed execution inside
OS Loader
lock. Do not attempt to run managed code inside a DllMain or image
initialization function since doing so can cause the application to
hang.
-->
<mda:loaderLockMsg break="true"/>
</mda:msg>
CAD.exe has triggered a breakpoint
If I don't allow the thread to exit (by putting an INFINITE wait on a handle
right before the return statement), everything works!
It appears as though when tearing the thread down, MFC gets confused about
the wrapped DLL (RegexWrapD.dll). Where I get confused is that neither DLL
is explicitly aware of the other (i.e. neither one calls any functions in
the other).
When looking at the stack backtrace, the 'green arrow' in the backtrace
points to the following ATL source:
In module dllmodul.cpp, function:
extern "C"
BOOL WINAPI InternalDllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID
/*lpReserved*/)
error (green arrow) occurs at line 195:
else if (dwReason == DLL_THREAD_DETACH)
{
#ifdef _AFXDLL
AFX_MANAGE_STATE(&afxModuleState); //// LINE 195 -- ERROR
HERE!
#endif
The MFC extension DLL has a DllMain, which is supposed to be supported in
VS2005. Here is what is does:
static AFX_EXTENSION_MODULE NEAR XMapDLL = { NULL, NULL };
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
// Remove this if you use lpReserved
UNREFERENCED_PARAMETER(lpReserved);
if (dwReason == DLL_PROCESS_ATTACH)
{
// Extension DLL one-time initialization
if (!AfxInitExtensionModule(XMapDLL, hInstance))
return 0;
new CDynLinkLibrary(XMapDLL);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
//TRACE0("XMAP.DLL Terminating!\n");
// Terminate the library before destructors are called
AfxTermExtensionModule(XMapDLL);
}
return 1; // ok
}
We have tried creating a separate initialization function that get's called
explicitly by the thread(s), and putting the 'new CDynLinkLibrary' call in
it, but that does not work either (i.e. calling it once from the main thread
only, or calling it twice (once from the main thread, once from the worker
thread). I have also created a dummy MFC extension DLL using the VS2005
wizard and I can access a function within it fine from 2 different threads.
The only thing about this dummy MFC extension DLL is that I don't allocate
any MFC objects, whereas the XMap DLL does (both global, static objects like
CPtrArray and other objects created by existing initialization calls from
the application).
Any thoughts on the problem?
Thanks
Al
an MFC extension DLL that was built back in VC++ 6 days (but has been
recompiled with VS2005). The other is a DLL that contains .Net functions
wrapped in C++ (as described by Paul DiLascia -- see
http://msdn.microsoft.com/msdnmag/issues/06/06/CAtWork/default.aspx). Both
DLLs specify 'Use MFC in a shared DLL'.
Since we have an old VC 6 application (large) that we would like to start
using .Net classes with (e.g. regular expressions), we have been trying to
implement the wrapped approach, which involves creating a DLL with the
wrapped .Net stuff in it. Hope that's clear ...
What we have found is that, when we use the wrapped DLL, we blow up with a
'loader lock' issue. This only occurs, though, when we do the following:
1. Implicitly link to the MFC extension DLL (XMap).
2. Create a thread, using AfxBeginThread, that will use the XMap DLL to do
some time-consuming initialization stuff.
3. When the initialization is done, that secondary worker thread exits -- at
which point we get the following (i.e. the mda:msg -- I have included the
debug output from the point at which the XMap DLL got loaded):
XMAP.DLL Initializing!
'CAD.exe': Loaded
'D:\views\al08333_view_SS_9_3_Dev\xwaveCAD\Workstation\ciids96\debug\Splash.dll',
Symbols loaded.
'CAD.exe': Unloaded
'D:\views\al08333_view_SS_9_3_Dev\xwaveCAD\Workstation\ciids96\debug\Splash.dll'
'CAD.exe': Loaded
'C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll', Symbols loaded
(source information stripped).
'CAD.exe': Loaded
'C:\WINDOWS\WinSxS\x86_Microsoft.VC80.CRT_1fc8b3b9a1e18e3b_8.0.50727.91_x-ww_0de56c07\msvcr80.dll',
Symbols loaded (source information stripped).
CDEQView::OnInitialUpdate() called
Comms IndicationHandler set to CWorkstation::HandleIndications
'CAD.exe': Loaded
'C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Culture.dll', Symbols loaded
(source information stripped).
'CAD.exe': Unloaded
'C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Culture.dll'
'CAD.exe': Loaded
'C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\mscorlib\467bb10fb591904e8c6509fc55279db2\mscorlib.ni.dll',
No native symbols in symbol file.
'CAD.exe': Loaded
'C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Culture.dll', Symbols loaded
(source information stripped).
'CAD.exe': Unloaded
'C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Culture.dll'
<mda:msg xmlns:mda="http://schemas.microsoft.com/CLR/2004/10/mda">
<!--
DLL 'c:\tools\RegexWrapD.dll' is attempting managed execution inside
OS Loader
lock. Do not attempt to run managed code inside a DllMain or image
initialization function since doing so can cause the application to
hang.
-->
<mda:loaderLockMsg break="true"/>
</mda:msg>
CAD.exe has triggered a breakpoint
If I don't allow the thread to exit (by putting an INFINITE wait on a handle
right before the return statement), everything works!
It appears as though when tearing the thread down, MFC gets confused about
the wrapped DLL (RegexWrapD.dll). Where I get confused is that neither DLL
is explicitly aware of the other (i.e. neither one calls any functions in
the other).
When looking at the stack backtrace, the 'green arrow' in the backtrace
points to the following ATL source:
In module dllmodul.cpp, function:
extern "C"
BOOL WINAPI InternalDllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID
/*lpReserved*/)
error (green arrow) occurs at line 195:
else if (dwReason == DLL_THREAD_DETACH)
{
#ifdef _AFXDLL
AFX_MANAGE_STATE(&afxModuleState); //// LINE 195 -- ERROR
HERE!
#endif
The MFC extension DLL has a DllMain, which is supposed to be supported in
VS2005. Here is what is does:
static AFX_EXTENSION_MODULE NEAR XMapDLL = { NULL, NULL };
extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
// Remove this if you use lpReserved
UNREFERENCED_PARAMETER(lpReserved);
if (dwReason == DLL_PROCESS_ATTACH)
{
// Extension DLL one-time initialization
if (!AfxInitExtensionModule(XMapDLL, hInstance))
return 0;
new CDynLinkLibrary(XMapDLL);
}
else if (dwReason == DLL_PROCESS_DETACH)
{
//TRACE0("XMAP.DLL Terminating!\n");
// Terminate the library before destructors are called
AfxTermExtensionModule(XMapDLL);
}
return 1; // ok
}
We have tried creating a separate initialization function that get's called
explicitly by the thread(s), and putting the 'new CDynLinkLibrary' call in
it, but that does not work either (i.e. calling it once from the main thread
only, or calling it twice (once from the main thread, once from the worker
thread). I have also created a dummy MFC extension DLL using the VS2005
wizard and I can access a function within it fine from 2 different threads.
The only thing about this dummy MFC extension DLL is that I don't allocate
any MFC objects, whereas the XMap DLL does (both global, static objects like
CPtrArray and other objects created by existing initialization calls from
the application).
Any thoughts on the problem?
Thanks
Al