Why call CoFreeUnusedLibraries() before OleUninitialize()? - windows

While trying to resolve process hanging on CoUninitialize() I came upon a piece of code shared by many of our projects. When a program is going to quit it first calls CoFreeUnusedLibraries(), then immediately OleUninitialize().
While the effect of OleUninitialize() is quite clear I can't find why one would want to call CoFreeUnusedLibraries() before calling OleUnitialize(). What might be the use of this call at this specific point?

CoFreeUnusedLibraries() will trigger a call to the DllCanUnloadNow for each in-process COM DLL that exports this function. Not sure about threading issues or out-of-process COM components as it relates to this API.
Presumably, someone who wrote the code that calls DllCanUnloadNow before OleUnitialize was attempting to reduce working set and ensure cleanup.
I don't think there's much value in calling CoFreeUnusedLibraries right before application shutdown (the DLLs will get unloaded anyway).
My experience is that calling CoFreeUnusedLibraries results in crashes and hangs in 3rd party COM DLLs that never had their DllCallUnloadNow implementation tested before release. (Because not too many apps call this function).
You didn't provide a call stack or hint as to where the hang was occurring (did you break into a debugger to see what DLL is at the top of the stack?). My guess is that you can likely take this call out if you can't fix the offending DLL.

Docs indicate that
This function is provided for
compatibility with 16-bit Windows.
Hmmm...
Have you seen this problem report? This call seems redundant to me - maybe this leaves one or more DLLs in a state where OleUninitialize does not work properly - waiting for some state change due to the earlier call. However this does allude to the need to wait a while between calls...
CoFreeUnusedLibraries does not
immediately release DLLs that have no
active object. There is a ten minute
delay for multithreaded apartments
(MTAs) and neutral apartments (NAs).
For single-threaded apartments (STAs),
there is no delay. The ten minute
delay for CoFreeUnusedLibraries is to
avoid multithread race conditions
caused by unloading a component DLL.
There are also comments elsewhere re a 6 -minute closedown timeout when using DCOM - is that applicable to you?

Related

Can I unload a DLL from another process? (Win32)

I want to unload a DLL from another process. Is it possible?
If yes, how to do that? (I'm using Win32 API)
Thank you very much.
Yes, this is possible. It is called DLL ejection and is featured by some DLL injectors. The way a DLL is usually loaded is via LoadLibrary and it is subsequently unloaded via FreeLibrary. FreeLibrary takes only one parameter which is a handle to the module to be unloaded. If you injected the DLL in the first place, you should be able to find this very easily. Otherwise there are ways of obtaining the handle such as CreateToolHelp32Snapshot with further enumeration with Module32First/Module32Next. Suppose you have obtained the handle through some means, then the steps to eject the DLL are simple:
Get the address of FreeLibrary with GetProcAddress. This address will match the one for the same function in the target because of how Windows works.
Call CreateRemoteThread on the target process, specifying lpStartAddress as the address of FreeLibrary, and with lpParameter as the module's handle
There are several caveats to DLL ejection.
You should only ever eject a DLL which you are certain no code is going to make use of again in the future. If any dynamically linked code attempts to make a call to your code after it has been freed, it will most likely trigger some form of page access violation.
You should ensure that no threads are executing within the code of the DLL whilst ejection is being performed for similar reasons.
DLL ejection should be avoided with general. If the library wants to have the option of being freed, it should supply some interface which users can access it through which eventually calls FreeLibraryAndExitThread.
If you require a code example for this, I have written an ejector as part of an injector I wrote in the past in C. I can search it up and find it but it's from many years ago and the code quality is not likely to be good.
You don't want to do this.
"Loading" a DLL is much more than simply opening (and locking) a file. When the NT loader starts an executable, it processes all the DLLs referenced by the image (recursively) and wires up the function calls (recursively): loading the DLLs, calling the DLL initialization code, etc.
Unloading a DLL would mean that you'd need to stop all processes that loaded your DLL, load the new DLL, and perform all the operations the NT loader would. Of course, unloading and re-loading a DLL would need to restore that old DLL's state (initialized variables etc), an operation which is not specified in Win32.
For a bit of background information, see this article on MSDN and this Under the Hood article in MSJ.
Short answer: No, it is impossible.
Win32 doesn't provide an API to unload a DLL of another process. If a library is freed unexpectedly, the process will crash. This leads to a serious security hole as it breaks process protection mechanism.
If you can modify both of the processes, you can modify the application and add routines to free a library, and let the other application to send the message.
I would instead look to change the function called when the process tries to invoke the functions in that dll. I know this is possible in theory.
It would mean a bit of memory hacking and knowing where the pointers to the functions are stored, but all of that can be found easily enough (ollydbg manages to do it), it would be harder if they use ordinals, even harder if they hard code the pointers, but no one does that nowadays. You could then inject your own code that (ideally) mimics the functions they mask, but does not actually do anything. They will probably have to be injected into the process, and that way you could get it to work without the process ever knowing, and without any crashes.

Questions about SetWindowsHookEx() and hooking

Here is a little background information. I'm working on replacing a dll that has been used in a dll injection technique via the AppInit_DLLs registry entry. Its purpose was to be present in every process and set hooks into the GDI32.dll to gather information about printing. This is kind of a funky way to get what we want. The .dll itself is over 10 years old (written in Visual Studio 97) and we'd like to replace it with something a little less invasive than an injected dll.
It appears SetWindowsHookEx() maybe what we are looking for. I've been having some trouble with it, but I've also had some discussions with co-workers about whether or not this tree is worth barking up. Here are some questions that we could not determine:
When we hook a routine out of a dll, for example StartDoc() from GDI32.dll, do we really get a notification every time any other process uses that rotuine out of that dll? This is kind of the functionality we were getting with our injected .dll and we need the same functionality going forward.
When the hook is triggered, does the hook handling procedure run in the process space of the process that initiated the actual call, or in the process space of the process that set up the hook? My opinion is that it has to run in the process space of the process that called the routine. For example, if a program calls StartDoc() from GDI32.dll, it will have the hook handling procedure code "injected" into its space and executed. Otherwise, there would have to be some inter-process communication that automatically gets set up between the calling process and the process that set up the hook, and I just don't see that as being the case. Also, its kind of necessary that this hook handling routine run in the process space of the calling process since one of the things it needs to know is the name of that calling process, and I'm not sure on how to get that information if it wasn't actually running in that process.
If the hook handling routine is written using the .NET managed environment, will it break when getting hooked into a process not utilizing the .NET managed environment? We'd really like to move away from C++ here and use C#, but what would happen if we our hook gets called from a process that isn't managed? As stated before, I think that our hook handling procedure will run in the process that originally called the routine that was hooked. But if this is true, than I would think that we'd run into trouble if this process was not using the .NET run time environment, but the incoming hooked handling code is.
Yes.
Generally, it's the former: it executes in the context of the process whose event it is hooking.
After a successful call to SetWindowsHookEx, the operating system automatically injects the hook DLL (the one that contains the callback function) into the address space of all target processes that meet the requirements for the specified hook type. (Of course, the hooking code is not necessarily injected immediately.)
The exception to this general rule are the low-level keyboard and mouse hooks (WH_LL_KEYBOARD and WH_LL_MOUSE). Since those hook types are not injected into the client processes, the callback is called in the same thread that originally called SetWindowsHookEx.
That last point is important to keep in mind to answer your third question. Because the low-level keyboard and mouse hooks are the only two global hooks that do not require DLL injection, they are also the only two types of hooks that can be written in managed .NET code.
For the other hook types, your concerns expressed in the question are precisely correct. You would need to write these hook DLLs in C or C++. Of course, the rest of your application's pieces could still be written in a managed language. The only thing that matters is the hook DLL.
You might consider looking into either Microsoft Detours or EasyHook.

Why does my windows program die with its frozen (bluish gray) Forms or windows?

My delphi program (NOT for .NET) on windows 7 seems to be running for couple of days straight and then the program sort of freezes with all of its windows painted with blueish grey color as if its windows are disabled. You simply don't have control over the program anymore but has to kill its process and start it up again. You don't need to reboot the system itself.
Has anyone experience this or anything similar? If so, what did you do to resolve or try to resolve it?
Thanks,
Your question context is very vague. We do not have any information about your application, even its design and architecture.
Nethertheless, my (general-purpose) suggestions are the following:
If your application is not multi-threaded, do the process in background threads, then leave the main thread ready to process GDI messages;
If your application is multi-threaded, take care that all VCL access from background threads are made via a Synchronize call;
If your application is multi-threaded or use timers, take care that no method is re-entrant (in some circonstances, you may come into a race condition);
Hunt any memory leak;
Use a detailed logging of the program execution, logging all exceptions risen, to guess the context of the program hang (it may be used on the customer side also to hunt race conditions);
Download the great free tool named ProcessExplorer (now hosted by Microsoft), and check out the state of your frozen program: you will see detailed information about threads, CPU use, memory, network, libraries, handles - this is a must have for any serious debugging - track especially the GDI handles leaks (number of those should remain stable);
If you did not check it already, take a look at the global Windows system event log: there may be some information here;
Perhaps a third party component or library is responsible of the process hang: try to isolate the part of your code which may be responsible of this hang.
I've Delphi application running for months without any problem. Issue is definitively in application code, not in the Delphi architecture (its RTL and VCL are very stable).
The bluish grey color is probably the default window color, meaning the window is no longer painting itself. This is consistent with the other symptom that the program no longer responds to any input. This means it isn't processing any window messages.
The easiest way to debug is to run the program in a debugger, and when it's hung just stop it and see where it's at.
If you have a memory leak you may eventually run out of memory in your process space, and it's possible that the program doesn't properly respond to that condition. Check Task Manager to see the amount of memory it's using.
Yes I fixed several hangs and other problems in the past years.
I used ProcessExplorer before (to view the stack), but it needs Microsoft debug symbols. And with Delphi you can only create a .map file. With map2dbg I could convert the .map to a .dbg, but this does not always work (note: .dbg is deprecated, newer versions of Microsoft debugging tools do not use them anymore).
So I made my own tool :-)
It is part of "AsmProfiler Sampling" tool:
http://code.google.com/p/asmprofiler/downloads/detailname=AsmProfiler_Sampling%20v1.0.7.13.zip
Click on the "Stack view of Process" button in the first screen.
Then select your process from the list and double click on it:
http://code.google.com/p/asmprofiler/wiki/ProcessStackViewer
Now you can view the stack trace of each thread. If the GUI does not respond, the main thread hangs, so check the first thread. (note: sometimes you see an "emtpy" stack because a function misaligned the stack for calculation etc, use the raw strack tracing algoritm to get more the full stack again (with a lot of false positives, because every pointer on the stack which is possible a function is shown!)).
Please post the stack here if you can't solve it, so we can take a look at it.
Note: it uses the jclDebug.pas unit of the JEDI library, so it can read .map and .jdbg files (also .dbg and .pdb debug files of Windows dlls) and also internal JCLDEBUG sections (embedded .jdbg file in one .exe). So you must at least build an .exe with detailed (!) map file, see Project Options -> Compiler -> Linking.

How to avoid the White Blank Screen?

Using VB6
At the time of executing, it showing white blank screen while it was working with database,
How to avoid the white blank screen in VB6.
WHITE BLANK SCREEN MEANS HANGING (WHEN IT WAS WORKING WITH DATABASE).
How to avoid that?
I assume you mean that the GUI won't redraw itself when executing a long-running operation. (Shouldn't actually be that visible starting with Vista, but I digress).
If your long-running operation is composed of several steps or tight loops, then you can sprinkle a call to DoEvents every once in a while to cause the form to remain somewhat responsive even when doing work.
Another option would be to migrate your long-running work into a separate thread but last I looked this wasn't exactly trivial or easily possible in VB6.
You should work with data base in separate thread, and any time-consuming operation should be run in a separate thread too. In this case your user interface won't be frozen.
I posted this as an answer to another question, but the pattern applies here as well:
VB6, on its own, is single threaded. However, you can make it somewhat multithreaded via the use of ActiveX EXE that run in their own process, yet still are tethered to the original VB6-created EXE.
What I've used in the past is the Timer object in conjunction with an ActiveX EXE. This approach will give you an ability to localize all the downloading logic in one place, control it like you control a regular object and have it run in a separate EXE, thus by default making it multi-threaded.
So the way this works is like so:
You call the LongRunningOperation method on the ActiveX EXE object
In the LongRunningOperation method, you instantiate the Timer and have it kick off almost immediately.
You get out of the LongRunningOperation method, thus giving control back to the entity that called it.
Then you communicate back to the main app via Events (e.g. LongRunningOperationProgress or LongRunningOperationComplete, etc...)
I recommend the Timer object from Karl Petersen.
This is actually the same problem as your "How to exit the program immediately" question. In both cases, the problem is that your database operation is blocking the VB6 program from executing.
The answer you accepted for the other question - use ADO to carry out the operations asynchronously - will also solve this blank screen problem.
Or if you prefer, follow one of my suggestions in my answer to your other question and use a .NET background worker component through Interop like this.
Or follow my other suggestion and delegate the database work to an ActiveX exe like this. EDIT AngryHacker's nice answer to this question uses this method.
Your first instinct should be to put your resource-intensive operations in a separate thread. This is a bit difficult in VB6, although possible (but not recommended) if you invoke the native CreateThread API.
You can also migrate to VB.NET, and use Thread objects natively.

What exactly is the risk when using TerminateProcess?

My Win32 console applicaton uses a third-party library. After it exits WinMain global objects destruction begins and an AV happens somewhere deep inside. I'm really tempted to just write
TerminateProcess( GetCurrentProcess(), 0 );
somewhere near the end of WinMain. If I do this the application ends gracefully.
But MSDN says that doing so can compromise the state of global data maintained by dynamic-link libraries (DLLs) which is not clear. I understand that if I have some global object its destructor is not run and I risk not finalizing a database connection or something similar. I don't have anything like that in my program.
What exactly is the risk when using TerminateProcess? How do I determine if I can use it for my purpose?
Based on the documentation for that and ExtiProcess it seems the primary concern is that DLL's are unloaded without a call to DllMain with the flag DLL_PROCESS_DETACH.
My 2cents: The documentation is being paranoid that you will upset some critical operation which runs in DllMain + DLL_PROCESS_DETACH. Anyone who depends on that to maintain critical state is already at the mercy of task manager so I don't see a huge risk in using this API.
Generally the bad things will happen when interacting with objects outside of your process. For an example say you have some shared memory used by multiple processes that your process will write to and other processes read and or write to. Typically to synchronize the reading and writing a mutex is used. If a thread in your process has acquired the mutex and is in the middle of making changes when TerminatePorcess is called, the mutex will be abandoned and the shared memory potentially left in an inconsistent state.
I suspect you are miss using one of the third party libraries. DllMain is somewhat limiting so the library may have initialize and uninitialize functions that you are supposed to call.
AFAIK, if you're not doing anything "fancy" (which includes but is not limited to: creating threads, locks, DB connections, using COM objects), nothing terrible will happen. But as Earwicker says, you don't know what OS-wide stuff a DLL is doing, and you certainly don't know if that will change in the future, so relying on this is very fragile.
Aren't you curious to know why this access violation is occurring? It may well be the sign of something that became corrupted much earlier on. Please at least confirm that the bug is caused by this 3rd-party library, e.g. by writing a program that links with the library but whose main() does nothing, and confirming that this causes the same crash.
It depends how you interpret "global data". If you take it to mean (as I normally would) data stored in the process's address space, then the advice makes no sense - we know that memory is going to disappear, so who cares what happens to that?
So it may be referring to OS-wide stuff that a DLL may have done, that persists outside the lifetime of any process. A simple example would be a temporary file that might need to be cleaned up; crash the process too many times and you'll run out of disk space, so probably best not to make a habit of it.

Resources