Re: shared DLL VS static Link, Are they different?
As Joe and Doug pointed out, that library has problems with DllMain and
thread local storage, etc.
I did some stepping in the code.
The problem is that that library is a mainly-C-interface library (even if
the sources are .cpp), and there is a structure called "CvContext" in that
library.
The authors provided internal functions like icvCreateContext(),
icvDestroyContext(), and icvGetContext() - see file cxcore\src\cxerror.cpp
(where DllMain is also defined).
The problem is that this "context" management is a real mess, and if you try
to log the calls to icvCreateContext() and the calls to icvDestroyContext(),
you will see that they do not match!
I saw that inserting a custom code in icvCreateContext() and
icvDestroyContext() bodies, this custom code basically uses
OutputDebugString to trace message like "icvCreateContext - CvContext
allocated at %08x <memory address here...>").
The problem is that icvGetContext is badly designed IMHO (with some
confusing #ifdef's, too), and there is a mix of TlsGetValue(), and also
calls to icvCreateContext from icvGetContext...
There are global variables defined in that DLL, and their constructor calls
icvGetContext - you can see that using call stack:
CvType constructor calls
cvGetErrStatus calls
icvGetContext
It may happen that icvGetContext is called like shown above *before* DllMain
(because the global variables are constructed before DllMain is called).
If you put breakpoints you can see how bad and non-linear the code flow is
to get these "CvContext"s...
And if you use proper tracing, you will see that *not all* the instances of
CvContext created on the heap using malloc() are properly destroyed!
(BTW: this library is a C++ library, but uses malloc instead of new...)
In general, I think that DllMain is a poor place to do initialization and
cleanup - better providing external public functions - and if there is some
"context" state to be shared by DLL functions, better passing it explicitly
(or use a C++ library, so the "state" is inside the class body).
A couple articles about DllMain...
http://blogs.msdn.com/oleglv/archive/2003/10/24/56141.aspx
http://blogs.msdn.com/larryosterman/archive/2004/04/23/118979.aspx
HTH,
Giovanni
"asm23" <asmwarrior@gmail.com> ha scritto nel messaggio
news:g73pir$kcu$1@aioe.org...
hi, everyone, I meet a strange problem:
I'm using VC6 and create a dialog based applications. And I want to add a
third part library( Open computer library--OpenCV AS DLL). I linked with
the cxcored.lib. My APP will call functions in cxcore001d.dll.
I only add two functions in the OnInitDialog function:
/////////////////////////////////////////////////////////////////
BOOL COpenCVdialogDlg::OnInitDialog()
{
......
m_iplImage = cvCreateImage(ImgSize,IPL_DEPTH_8U,IMAGE_CHANNELS);
cvReleaseImage(&m_iplImage);
......
}
////////////////////////////////////////////////////////////////
In the code above, I only create an Image and release it quickly, which
seems I do Nothing. ^_^ ,The two functions are exported from
cxcore100d.dll( associated with cxcored.lib)
Here comes my problem. When I build the APP with static MFC library, the
program works fine. But When I build the APP with "Using MFC as shared
DLL" option, there are many memory leak report when I exit the APP.
It is very strange that "using MFC as shared DLL" and "using MFC as a
static library" are much different? Otherwise, There are something wrong
with the source code generating cxcore100d.dll?
By the way, OpenCV is an open source library,so, I have the full source
code of "cxcore100d.dll" , I examine the code and can't find anything
wrong.
Here is its DLL Main entry:
////////////////////////////////////////////////////////////////
#if defined WIN32 || defined WIN64
BOOL WINAPI DllMain( HINSTANCE, DWORD fdwReason, LPVOID )
{
CvContext *pContext;
switch (fdwReason)
{
case DLL_PROCESS_ATTACH:
g_TlsIndex = TlsAlloc();
if( g_TlsIndex == TLS_OUT_OF_INDEXES ) return FALSE;
//break;
case DLL_THREAD_ATTACH:
pContext = icvCreateContext();
if( pContext == NULL)
return FALSE;
TlsSetValue( g_TlsIndex, (LPVOID)pContext );
break;
case DLL_THREAD_DETACH:
if( g_TlsIndex != TLS_OUT_OF_INDEXES )
{
pContext = (CvContext*)TlsGetValue( g_TlsIndex );
if( pContext != NULL )
icvDestroyContext( pContext );
}
break;
case DLL_PROCESS_DETACH:
if( g_TlsIndex != TLS_OUT_OF_INDEXES )
{
pContext = (CvContext*)TlsGetValue( g_TlsIndex );
if( pContext != NULL )
icvDestroyContext( pContext );
}
TlsFree( g_TlsIndex );
break;
default:
;
}
return TRUE;
}
////////////////////////////////////////////////////////////////
I was confused that why the "break" statement is commented after the
"case DLL_PROCESS_ATTACH:"?
Further more, the cvCreateImage and cvReleaseImage function in my APP is
regularly simple, they only allocate a piece of memory and delete it.
Thanks for reading my Post!