Essentially, if your DLL has the need for a thread to do its job then, in my
case, the thread is ideally started, on behalf of the calling process,
during DLL_PROCESS_ATTACH. The DLL entry-points can then be called until the
process wants to exit , at which point DllMain is called with
DLL_PROCESS_DETACH. Unfortunately, at this stage, you cannot wait for events
etc. so how do you terminate the thread. Even the NT4 audio driver sample
suffers in this respect and has the following comment :
//
// This is all wrong - we need to find out how to terminate threads !
//
Of course, I could have an entry point in the DLL which must be called
before the process exits, during which I can wait on the thread handle for
the thread to exit. Unfortunately this is not a viable solution since I am
dealing with a fixed, legacy interface.
I don't actually know if there is a solution to this problem. I have faced the
same issue but have solved it by implementing an "un-initialise" routine which
the calling application needs to call before unloading the dll. Then I can do a
"wait" in my un-initialise routine. Of course, then you have to ensure that the
calling application isn't actually calling "un-initialise" from another dll's
process detach....
Otherwise, in situations like yours where I was dealing with a "legacy"
application, my only other solution was to order the thread to terminate and not
wait to see if it did terminate.
I would be grateful to hear of any better solution you come up with.
Peter.
Peter A. Kirk wrote in message <391FFF0A...@iccc.dk>...
1. Any cleanup done at dll_process_detach time is likley to be missed by BC.
The system does not guarantee the order in which dll's will get
dll_process_detach messages when the process is closing - thus it is quite
likley that the BC hook dll's that do the monitoring will be closed before
your dll is terminated thus "missing" the good and proper cleanup of
resources.
2. BCs bitching notwithstanding, at process shutdown _everything_ is cleaned
up for you. Unless you have persisent data that may be corrupted if threads
are not cleaned up synchronously its actually generally quite safe to simply
allow the system to terminate the threads and clean up the processes
objects.
3. Conversely - if you recieve a dll_process_detach due to a FreeLibrary
(rather than process shutdown) and your dll has "live" threads within it,
they will cause faults when next they are scheduled.
4. The "uninitialize function" option is the safest, and is used by a number
of system dll's. OLE & Winsock come to mind.
5. You cannot:
5.1 signal the thread to exit, and let it exit in its own time as the dll
will be unmapped whn next it executes causing an exception, or
5.2 signal the thread to exit and wait for it to exit as you are very likley
to cause a deadlock situation, so
5.3 The only viable option for Dll's that maintain internal worker threads
is to call TerminateThread() on any threads they have in response to
process_detach.
If the calling application calls LoadLibrary / FreeLibarary repeatedly in a
loop this will cause memory leaks.
Finally, I finish :) There are two cases when you recieve process_detach
1. The process is being shut down. Really: don't wory about this situation -
the system will terminate the threads and cleanup memory - BC is just being
retentive.
2. The app called "FreeLibrary" on the dll. You can either:
2.1 *ignore* te issue by documenting that the dll will leak if shutdown and
loaded repeatedly, or
2.2 Make a shim dll that you pass to the application. This dll implements
the legacy interface as the application sees it. It passes all calls through
to a 2nd dll that contains the worker thread. When the "interface" dll is
freed you handle the dll_process_detach and use that to signal a handle in
the 2nd dll that the worker thread watches for. The worker thread can then
clean up anything that needs cleaning and exit using the
FreeLibraryAndExitThread API which was designed for just this situation.
Chris.
--
VisualC++ & Win32 FAQ: http://www.mvps.org/vcfaq
My Win32 Page: http://www.mvps.org/user32
1. Creating a thread during a DLL notification may not work exactly as
expected. Since DLL initialization routines are single-threaded, the new
thread's start routine will not begin execution until the current thread
"unwinds" out of the DLL notification. (Think about it this way. If you
create a worker thread in a DLL_PROCESS_ATTACH notification, the worker
thread cannot issue the DLL_THREAD_ATTACH while the current thread is still
processing the process attach.)
2. Likewise, if you request a worker thread to kill itself (say, by
signalling an event) from within a DLL notification, the thread will not
become "fully terminated" (i.e. the thread handle will not become signalled)
until the current thread "unwinds" out of the DLL notification.
Here's one way to use worker threads from within a DLL:
1. Before you create the worker thread (this could be during
DLL_PROCESS_ATTACH, but it's better do defer this until it's actually
needed), use GetModuleFileName() and LoadLibrary() to add an "artificial"
reference to the DLL. This will keep the DLL from disappearing from
"beneath" the worker thread. You will need to either pass the DLL's module
handle to the worker thread, or store it away in a global.
2. When it's time to kill the worker thread, signal an event (or use
whatever mechanism you need to tell the worker thread to kill itself). If
you're doing this from within a DLL attach/detach notification, then *do
not* wait for the thread to die, or you will deadlock.
3. The last thing the worker thread should do is call
FreeLibraryAndExitThread(). This will remove the artificial DLL reference
and terminate the worker thread. Since the thread will terminate during this
call, it will not have a chance to return back to the (possibly freed) DLL.
I've used this technique a number of times. It works great.
KM
"Will Barker" <will....@farsite.co.uk> wrote in message
news:8fotth$630$1...@ayers.ftech.net...