Open end2endzone opened 1 year ago
Files are not unloaded after unregistration according to Process Explorer:
The Shell automatically unloads any DLL when its 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. You can shorten the inactive period by adding the following information to the registry.
HKEY_LOCAL_MACHINE
Software
Microsoft
Windows
CurrentVersion
Explorer
AlwaysUnloadDll
From https://www.tenforums.com/performance-maintenance/163171-unload-dll-ram-memory-tweak-question.html :
This is one of those useless tweaks that has been around since at least XP days. It has largely disappeared but can still be found. At least it is harmless. And finally, the setting hasn't been supported since Windows 2000. Unsupported registry entries are silently ignored.
Some thoughts about why this might be occurring:
DllRegisterServer()
and DllUnregisterServer()
with a call to SHChangeNotify(SHCNE_ASSOCCHANGED, 0, 0, 0);
(version 0.7.0 and current version). A new API call or a new flag might be required in order to notify explorer.exe.EDIT:
Possible solutions:
DisableThreadLibraryCalls(hInstance);
in dllmain.cpp. ShellAnything is lacking this guard. This seems like good practice in many shell extension. For example:
When the reference count on an object reaches zero, Release must cause the interface pointer to free itself. When the released pointer is the only (formerly) outstanding reference to an object (whether the object supports single or multiple interfaces), the implementation must free the object. Call this method when you no longer need to use an interface pointer. If you are writing a method that takes an in-out parameter, call Release on the pointer you are passing in before copying the out-value on top of it.
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Cached
. It contains an entry about ShellAnything's extension. The key contains a value matching ShellAnything's class id. The value is still in the registry after the shell extension is unregistered. This might be an issue.
Note: There is no reference to the shell extension under HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions\Cached
.Fixed Cache registry key in e7d4b328b2e4cd1d1ba278654192d52c1cb0c07f.
Disabled option 6: Rewrite the shell extension's high level code based on the code from https://www.codeproject.com/Articles/441/The-Complete-Idiot-s-Guide-to-Writing-Shell-Extens#gettingstarted.
There does not seems to be a way to "force" or tell File Explorer to unload the Shell Extension once it is unregistered.
According to https://stackoverflow.com/questions/11365944/how-to-unload-c-shell-extension-dll-properly, Windows Installer should be able to use MoveFile to move a loaded dll. This could be an acceptable solution.
ShellAnything recently moved to dynamic linked libraries (DLL) for GLOG and libexprtk libraries (https://github.com/end2endzone/ShellAnything/issues/103). There might be a hook or something similar which prevents explorer.exe to unload the main DLL because it can't also unload glog.dll or libexprtk.dll.
This has been proven incorrect. A dumb/empty new shell extension was created (see code attached below). The shell extension is really simple and has no dependencies on other DLL. Once unregistered, File Explorer is still holding to the shell extension's dll file. The file can be moved but not deleted. Waiting 2h+ did not resolved the issue.
See the following code used for testing: FooBarShellExt.zip Note: This is a stripped down version of a shell extension from an GPLv2 licensed projet.
I have implemented an utility to restart File Explorer so that uninstalling the shell extension can be done without rebooting. The plan is to modify the uninstaller to show instructions to run the File Explorer restart before actually uninstalling.
The plan is to show a dialog when uninstalling such as the following:
--------------------------------------------------------------------------------------------------------
Before you uninstall
Should you renew File Explorer before you continue?
--------------------------------------------------------------------------------------------------------
Shell Extensions do not uninstall as easily as other softwares. Shell Extensions DLLs cannot be deleted because
File Explorer usually have a lock on the file. There is an issue with File Explorer which do not automatically
release shell extensions dll even if they have been unregistered from the system. Because of the lock, these dll
files cannot be deleted. A system reboot is usually the prefered option to make sure all dll files are released
and can be deleted.
ShellAnything provides a workaround which allow complete uninstallation without rebooting the system.
File Explorer Renew is an utility provided with ShellAnything that can close and reopen all File Explorer windows.
If the shell extension is unregistered, it will renew all windows and release the lock on the shell extension dll.
To enable the workaround, close the uninstaller, unregister the shell extension (unregister.bat)
and then run "file_explorer_renew.exe".
You can also continue normally and reboot the system to complete the uninstall process.
It seems that showing a dialog or a message box during the uninstall process is a bad idea. This is a bad practice because the uninstaller is usually executed in Silent Mode :
I wouldn't mess with this uninstall sequence. Any modal dialog that pops up when the installation is run in silent mode (which it is from add/remove) could cause your entire product to be axed in a corporate environment.
See the following references:
Forcing a restart of File Explorer (without the user's consent) may also be a bad idea:
According to the link above, it appears the appropriate solution is to use MoveFile:
You can use the same mechanism in your homebrew installer and move the old file that is in use out of its original location and move the other one in right away. Any new application instance will then make use of the new shell extension (*), while the old one will continue to be used by any of the running applications that loaded it at one point or another.
This would allow the uninstallation of an old version and the installation of a new ShellAnything version. However, the new installed version would not be available to the system:
[Windows have] rules that apply to DLL loading and prevent modules with the same name to be loaded again under some circumstances.
Added a new dialog in the installer about instructions before uninstalling. See e453904af127c909617966858f0a0b9220fcc11f for details.
Leaving the issue opened in case someone else has an actual way of solving the problem.
Official shell extension example from Microsoft: https://github.com/microsoftarchive/msdn-code-gallery-microsoft/tree/master/OneCodeTeam/C%2B%2B%20Windows%20Shell%20context%20menu%20handler%20(CppShellExtContextMenuHandler)
Describe the bug After the shell extension is unregistered from the system, explorer.exe does not unload
sa.shellextension.dll
.To Reproduce Steps to reproduce the behavior:
register.bat
inside an administrator command prompt.unregister.bat
inside an administrator command prompt.Expected behavior Explorer.exe should release/unload shell anything dlls when unregistering ShellAnything.
Screenshots After unregistering the application, if we try to uninstall the application, the following dialog is displayed:
Environment
Additional context N/A