This is Part 2 of my previous article. The main goal of this project is to create a Windows service in C# which will monitor all the appearing windows and kill the unwanted ones. After Part 1 has been published, I found (thanks to the forum attached to that article) that it does not work on Vista because of the enhanced security there. That means, Windows services are running in the hidden session #0, and they cannot interact with user sessions (#1, #2, ...). All PInvoke methods, such as
SendMessage, do not work with windows/processes running on user desktops. After some search on CodeProject, I found a great article by Stefan Repas which shows how to allow a Windows service written in .NET to communicate with desktop applications using an out-of-proc COM server. To run a .NET COM-visible assembly as an out-of-proc COM server, he used COMAdmin.dll to register the DLL as an out-of-proc COM server.
Any COM visible assembly (or .dll) created in .NET using Visual Studio is hosted by dllhost.exe, which is called a "COM Surrogate". By default, it runs on Vista in session #0, which has its User Name as
SYSTEM in the Task Manager. A Windows service can communicate with this COM server, but this server runs in the same session #0 as the service, and it does not see the user windows/applications. To force a COM DLL to be hosted in dllhost.exe, which is running in a user session, we have to register it under a user account using COMAdmin.dll. I created a class
DesktopManager which has a rudimentary interface, to work with desktop windows/applications. Of course, this simple class could be easily extended to whatever you need. This class is implemented as a COM+ object in the DesktopManagerDll assembly registered as an out-of-proc COM server using COMAdmin.dll, and runs under a user account. All methods from the
WindowFinder class (see my previous article) are moved to the
This COM object exposes the following
[Description("Exposed DesktopManager interface")]
public interface IDesktopManager
int FindTopWindow(string wndClass, string wndTitle);
int FindChildWindow(int hwndParent, string wndClass, string wndTitle);
bool CloseWindow(int hwnd, string wndClass);
void ExitProcess(string processToExit);
void MessageBoxShow(string text, string caption, string icon);
string GetMainWindowTitle(string process);
This interface is implemented in the
[Description("ServicedComponenet class to control IDesktopManager Interface")]
public class DesktopManager : ServicedComponent, IDesktopManager
Notice that this class is derived from the
ServicedComponent class which is needed to expose the
DesktopManager as a COM+ object. This object implements all the
IDesktopManager interface methods. To implement the
FindChildWindow method, for example, this class uses the same technique as was used in the
WindowFinder class from my previous article.
To make this object an out-of-proc COM+ server, there is a class
DesktopManagerInstaller which performs the following steps:
- Install the assembly using RegistrationHelper.
- Create an
- Get all the roles for the current COM+ application.
- Find the role
- Assign accounts to the found
- Get all COM+ components for the current application.
- Check if the
DesktopManager COM+ component exists.
- Grant access to users in the role
Using the DesktopManager COM+ object
First, you have to create a
m_desktopManager = new DesktopManagerDll.DesktopManager();
m_desktopManager in the
public bool KillPopupWindow(string titleToKill, PopupWindowType popupType)
m_hwndFound = FindTopWindow(classToKill, titleToKill);
if (m_hwndFound != IntPtr.Zero)
return m_iDesktopManager.CloseWindow(m_hwndFound.ToInt32(), classToKill);
m_desktopManager when done:
Finally, shutdown the COM+ application:
ICOMAdminCatalog cac = (ICOMAdminCatalog)Activator.CreateInstance(
To install this service, you can use the MS Installer output produced by the WindowKillerSetup project which is a part of the WindowKiller solution, or do manual registration of the two assemblies: DesktopManagerDll and WIndowKiller.exe, using InstallUtil, which is a part of the .NET Framework:
Note: The WindowKiller EXE has implemented a self-installing feature - see my previous article. So, you can install/uninstall this service by calling it from the command line, like this...
... where the parameter -a means "auto" install/uninstall depending on the current service status. To get help on the other command line parameters, you can call the service with the -h parameter.
This is Part 2 of my previous article.