Improve company productivity with a Business Account.Sign Up

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 614
  • Last Modified:

DLL's and PROCESS_DETACH - Windows NT

Windows NT 4/sp3

I have a DLL that is used to interface to one of my device drivers.

I rely on getting the DLLentry called with PROCESS_DETACH and THREAD_DETACH to clean up resources on a per-process basis.

I have now discovered that, under certain circumstances, it appears possible for a process to exit without calling my DLLentry routine. This appears to happen if a user kills a process with the WindowsNT Task Manager. Also, so a customer tells me, it can happen if a processes is being debugged or has a fatal error.

Can anyone help me out here - I need the DLL to know if a process exits/dies so that the DLL can clean up after the process (open files, resources etc).
 
0
mwright012397
Asked:
mwright012397
  • 12
  • 6
  • 4
  • +3
1 Solution
 
nietodCommented:
I don't think there is anything you are going to be able to do about this.  But these are exceptional cases.  They should not happen often or ever in the field.

The OS will do a decent job of cleaning for your.  It will close all handles (that is files, mutexes) that are closed with Closehandle().  It will release all the memory that was alocated with GlobalAlloc() or LocalAlloc().

What sort of things are you concerned about?
0
 
mwright012397Author Commented:
I have some memory and resources allocated to the process that must be freed.

The device driver implements numbered "ports" (somewhat like TCP ports), These are "opened" by a process and must be freed if the process does not close them itself. If not, then these "ports" become unavailable to another process.

I wondws how other systems manage this if these events are not-catchable ?



0
 
mwright012397Author Commented:
Unfortunately they do happen - my customer sees this problem all the time and is getting fed up with me about it ;-{

He sees the problem when debugging - if he quits the program under the debugger the DLL knows nothing about it

0
The 14th Annual Expert Award Winners

The results are in! Meet the top members of our 2017 Expert Awards. Congratulations to all who qualified!

 
nietodCommented:
Why would the customer be debugging?

There may be hope.  I'm doing a little rearch now.   Its on termination handling, part of structured exceptiopn handling.
0
 
nietodCommented:
Nope, no hope.  But I think we can get around the problem

What are these ports and in what sense are they not freed when the DLL is closed (abnormally)?  
0
 
mwright012397Author Commented:
OK - background time.

I have a driver that implements "port" on a MultibusII backplane (doesn't really matter - pretend that they are TCP ports.)

User "opens a port" from a process - my dll gets the request - passes the open request to the driver - fields the reply - allocates the port to the "current" process and returns.

Normally, end user "closes the port" before exiting - dll gets erquest - passes to driver - fields reply - deallocates the port.

If the user "forgets" to close the ports - DLL gets the PROCESS_DETACH call - looks up all the ports that current process had open - closes them.

Now - if the appilcation dies in the "wrong" way - or user kill the process because something else has gone wrong - DLL never "sees" the PROCESS_DETACH - cant clean up. Result: ports opened but never closed - these ports are now unavailable.

User is debugging HIS application - not my DLL. Same result. If you "kill" the application within IDE - DLL never sees the PROCESS_DETACH.

Hope that rambling was of some use - any help appreciated here - I am really stuck for a solution.


0
 
nietodCommented:
I understand more now, but what are these ports?  It take it they are not something that the OS can figure out to close, like a file or memory mapping.  (It closes those and others under these circumstances.)

Just some thoughts, When debugging can you DLL create a log of some sort that can be used to close the ports by running a clean-up program.  Perhaps it could just clean up each time it is loaded.

Or if you don't like the idea of logging the information, can the DLLdetermine what ports are open and what processes are usig them.  If a process is terminated and is using a port it could clean up by closing that port.

Another approach is to try to leave the DLL "running"  That could be done by making it a service (I'm REALLY sketchy on this stuff--could be total BULL) or a divice driver.  Another possibility is to run an application that loads the DLL and keeps the DLL loaded, perhaps it can configure the DLL and/or report its status etc.  Then when the application that uses the DLL is killed, the DLL will still remain loaded and would have a decent chance of cleaning up, if might even keep track of the processes that are attached and periodically check to see if some died, or the first EXE could have some sort of manual cleanup option.  To make this work you would probably need some data segments in the DLL that are shared between processes.  Usually when a DLL is loaded by two or more processes it is so seperate that you really can't tell that it has been loaded multiple times and would make this sort of approach useles.  But by using shared data segments (pages) you can make this sort of approach work.

Let me know if any of this sounds like it might be owrth persuing.
0
 
duneramCommented:
You could catch exceptions with something like this:

LONG MyHandler (LPEXCEPTION_POINTERS *ExceptionInfo );


In the DLL setup (entrypoint)


            case DLL_PROCESS_ATTACH:
            // The DLL is being mapped into the process's address space.
                  SetUnhandledExceptionFilter
                              ((LPTOP_LEVEL_EXCEPTION_FILTER) MyHandler );
                  break;

            case DLL_PROCESS_DETACH:
                    STAMPLOG("DLL_PROCESS_DETACH")
                  // The DLL is being unmapped from the process's address
                  // space.
                  SetUnhandledExceptionFilter(NULL);  
                  break;


LONG MyHandler ( LPEXCEPTION_POINTERS *ExceptionInfo )
// Note: the structure (using) we could get the crash address...
{
   // Do some close up stuff
   return 0;
}


0
 
nietodCommented:
But if the user terminates the program you don't get an exception.
0
 
ArkadiyCommented:
Just a thought - can you change your driver so that your "ports" are recognized as something Windows has to close when a process exits (like events, mutexes, files etc.)
0
 
duneramCommented:
That would cover the ipf/gpf cases.
0
 
nietodCommented:
That would cover all the cases, but I would guess that if it could be designed that way it would have been.
0
 
s_griffinCommented:
Why not keep a list of the process/thread IDs that are accessing the DLL and every time a new process/thread attachs check if other process/thread ids are still alive in the system using the WIN 32 calls. If it doesn't then tidy it up. ?
0
 
nietodCommented:
The problem is that if only one process uses the DLL, it will be unloaded when the process is killed.   However, look at the suggestion I made on August 10th at 8:24.
0
 
mwright012397Author Commented:
Thanks for all the comments - I have been away for a day and I will have to catch up.

I still don't understand why this doesn't just "work". Why NT does not call my DLL when either a process is being debugged or killed.

Anyway - I have to fix this soon. I quite like the s_griffin idea - could you point me at the right system calls ? I could quite easily add a process list to the DLL and use that.

nietod noted that it would not work for the single caller case - I think it does because the lack of notification means that the DLL is NOT unloaded (I think - I will have to check). Or if it is - is there any mechanism for me to catch the unload ?

regards

0
 
nietodCommented:
>> nietod noted that it would not work for the single caller case - I think
>> it does because the lack of notification means that the DLL is NOT
>> unloaded (I think - I will have to check). Or if it is - is there any
>> mechanism for me to catch the unload ?
It is unloaded, but the library entry point procedure is not called to notify it of this fact.
If there was another mechanism to catch the unload, then you could just use that mechanism to clean up.

That is why, with this approach A) you need to keep the DLL loaded with a second process and B) the DLL will need to share memory between processes.
0
 
juhapekkaCommented:
I Use Semaphores to detect if my program is run twise in the same computer, after process dies and if doesn't destroy semaphores, according to microsoft documentation, windows cleans them, and for me it have worked fine, in few seconds the semaphores are gone after the process has ended.
0
 
nietodCommented:
That's true juhapekka, if many resources, including files handles, and memory mappings etc.

But what does that have to do with this question!
0
 
ArkadiyCommented:
As a variation of nietod's suggestions, in your internal tables in the driver you can keep some sort of link to process that created a port with that port's info. Im user mode, I could just open a handle to process and keep asking if that process is runnig. If NT has some sort of process ID that is not likely to be reused - you can use that. Then, every time you open a port (or maybe every time you run out of resources or encounter a port alredy opened - check the processes that own those ports. If the port's process is dead, kill the driver's resources.
P.S. Come to think about it, even if NT has a process ID that is somewhat likely to be reused, that schema may still apply. So the resources willbe freed a bit later, so what? :)
0
 
mwright012397Author Commented:
I don't see what that has to do with the original problem ?

0
 
ArkadiyCommented:
Well, unless I am mistaken, the goal is to clean up some resources allocated by the driver. Normally you do it  on PROCESS_DETACH. I suggest an alternative way to do it, some sort of garbage collection in the driver itself. Do I misunderstand the goal?
0
 
juhapekkaCommented:
Whoops... being tired misunderstood the idea... sorry.
0
 
mwright012397Author Commented:
Arkadiy-

Now we are getting somewhere. For my sake (being an idiot) could you expand upon "open a handle to the process". How do I tell if a process is still running ?


0
 
nietodCommented:
That's really what I was suggesting.
When a port is opened you will use GetCurrentProcessID() to get the ID of the process openign the port (since this is a call into the DLL the ID will be for the process making the call).  Then use OpenProcess()  to open a handle for that process and save it.  This needs to be save in some sort of data structure that will be shared among all applications that use the DLL.  Then when you want to check if the process that attacked to the port is still around, retreive the process handle and use WaitforSingleObject() on the handle (specify a short or 0 wait time).  If the process has terminated the handle will be signaled and this will be indicated in the return value from the the wait function (WAIT_OBJECT_O).  if the process is running, the handle will be non-signaled and the return value will be WAIT_TIMEOUT.  If you find the process has terminated, then you can take steps to clean up.  

Now whenever a port is closed (properly or by detecting a termination), you must close the process handle associated with that port with CloseHandle().

the key that makes this work, however, is having a second process to keep the DLL loaded so that the process and port information is retained even when the process that really uses the DLL crashes.

That is the general idea.  look up those functions and ask if you have questions.
0
 
ArkadiyCommented:
Nietod explains the process handle nicely. However, I am not sure if the code he suggests wil work in the driver. And the main difference between my and him is that I propose to perform the garbage collection in the driver - that IS the piece of code that is shared between all instances of DLL, and it's always running, and it has its own memory. Unfortunately, I do not know how to store a process handle in kernel mode, or how to check if the process is still runniing. That's why I did not post my idea as an answer. I am not a device driver guy. Quick search in MSDN gave me PsGetCurrentProcess() and IoGetCurrentProcess(). However, I could not find PEPROCESS structure they refer to.

0
 
nietodCommented:
Opps, I didn't understand arkadiy's suggestion.  I thought it was the same as mine.  I didn't realize we was proposing changing the driver.  I don't think you HAVE to change the driver, my suggestion should work without doing so, however, that may be a more direct solution.
0
 
nietodCommented:
That is supposed to be "he was proposing".  Just to add more confusion by taking credit through a typo.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

  • 12
  • 6
  • 4
  • +3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now