Date: | June 28, 2004 / year-entry #256 |
Tags: | code |
Orig Link: | https://blogs.msdn.microsoft.com/oldnewthing/20040628-00/?p=38663 |
Comments: | 13 |
Summary: | The SHLoadInProc function instructs Explorer to create an instance of a particular CLSID. This causes the DLL responsible for that CLSID to be loaded. But when is it unloaded? This is one of those puzzles you should be able to figure out by thinking about it. Consider: The object is created by calling CoCreateInstance and... |
The SHLoadInProc function instructs Explorer to create an instance of a particular CLSID. This causes the DLL responsible for that CLSID to be loaded. But when is it unloaded? This is one of those puzzles you should be able to figure out by thinking about it. Consider: The object is created by calling CoCreateInstance and then immediately releasing the returned object. That's all. Explorer pays no attention to your DLL from then on. With this hint, maybe now you can answer the question: When is it unloaded? Still don't know? Here's another hint: The issue is no longer a shell issue. Now it's a COM issue. When is any DLL loaded via CoCreateInstance unloaded? Answer: The DLL is periodically asked whether it is safe to unload. Once the DLL response in the affirmative (via S_OK), COM will unload it. |
Comments (13)
Comments are closed. |
That’s not quite true – it actually waits 10 minutes AFTER you respond that it’s safe to unload. The CoFreeUnusedLibraries API can force them to be unloaded.
I ran into this issue when stopping audiosrv on longhorn :)
Haha, I like how you make it seems like the answer is cut and dry, but yeah, the actual answer is "whenever explorer feels like unloading it after DllCanUnloadNow." Which is sensible enough, because if it was constantly loading and unloading context menu or icon shell extensions, that would be a performance nightmare.
What’s the purpose of this function ? Why would one want the shell to create an object and then release it immediately ?
TIA for your lights.
Serge> Getting a DLL into another process is the first step in spying on APIs, or subclassing windows, or other neat tricks.
Larry Osterman > That’s not quite true – it actually waits 10 minutes AFTER you respond that it’s safe to unload.
You can force windows to upload the DLL directly after instead of the ten minute wait.
I know this is supported in the Windows 9x line, but I’m not to sure if its officially supported under Windows 2000 and onwards.
M Night: According to CoFreeUnusedLibrariesEx(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/cmf_a2c_19yw.asp), if the 10 minute delay wasn’t in place, there could be a deadlock.
Of course calling CoUninitialize for the last time in an apartment causes all the DLL’s loaded in that apartment to be unloaded, so…
I think M Knight is referring to the reg key for debugging to unload dll straight away
It is for system prior to 2000
Unloading the DLL
The Shell automatically unloads a DLL when the DLL’s usage count is zero, but only after the DLL has not been used for a period of time. This inactive period might be unacceptably long at times, especially when a Shell extension DLL is being debugged. For operating systems prior to Windows 2000, you can shorten the inactive period by adding the following information to the registry.
HKLM
Software
Microsoft
Windows
CurrentVersion
Explorer
AlwaysUnloadDll
A long time ago, the shell did its own COM activation of shell extensions instead of actually calling through to COM. This caused no end of grief so they eventually fixed it.
I bet that this API is left over from the non-COM activation.
Presumably the dll’s reference count becomes positive again and it’s reused.
This optimization is probably why dlls aren’t unloaded instantly by COM in the first place…
OK, but if COM waits 10 min. *AFTER* call DllCanUnloadNow() and then unloads the DLL, what will happens if one create another object from this DLL?
This reminds me of a bug in ATL to do with window subclassing.
When an ATL based dll creates a control window using CContainedWindow or CWindowImpl
it registers a window class with an address for the windowproc but then fails to
unregister it when the window is destroyed. If a second dll is later loaded at
the same base address as the first and creates a window with the same class
name, the original windowproc address is not overwritten. This then caused an
access violation when windowproc was called at an invalid address, or more often in an unexpected bit of code. see MSDN KB article
Q248400 for more details. What made me think of this was that the bug only occured when the first DLL was unloaded and typically this happened whenever windows thought it would cause most confusion.
We solved this bug by adding a fix into atlwin.h to always unregister
window classes. IIRC the bug could also be avoided by linking to ATL.dll rather than by building in release min dependency because then the windowproc address for AtlAxWindow was always the same.
Larry Osterman: The way I read the description, the delay is recommended for compatibility with broken COM DLLs that lie and claim to be ready for unloading too early. There’s no inherent risk of deadlock (and if there was, merely delaying a bit surely wouldn’t eliminate it).