Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A Windows Service Which Kills Unwanted Windows: Part 2

0.00/5 (No votes)
8 Sep 2008 1  
Shows how to kill unwanted windows on the user desktop on Vista, using COM+ to allow a Windows service to interact with user applications.

Introduction

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.

Background

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 DesktopManager class.

Desktop Manager

This COM object exposes the following IDesktopManager interface:

  [ComVisible(true)]
  [Description("Exposed DesktopManager interface")]
  [Guid("258E4449-6ACC-40d8-8C37-4F47476D30C2")]
  [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
  public interface IDesktopManager
  {
    [DispId(1)]
    int FindTopWindow(string wndClass, string wndTitle);

    [DispId(2)]
    int FindChildWindow(int hwndParent, string wndClass, string wndTitle);

    [DispId(3)]
    bool CloseWindow(int hwnd, string wndClass);

    [DispId(4)]
    void ExitProcess(string processToExit);

    [DispId(5)]
    void MessageBoxShow(string text, string caption, string icon);

    [DispId(6)]
    string GetMainWindowTitle(string process);
  }

This interface is implemented in the DesktopManager class:

  [ComVisible(true)]
  [Description("ServicedComponenet class to control IDesktopManager Interface")]
  [Guid("56919971-22CB-4de7-9393-D55C72A20A1C")]
  [ClassInterface(ClassInterfaceType.None)]
  [ProgId("DesktopManagerDll.DesktopManager")]
  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:

  1. Install the assembly using RegistrationHelper.
  2. Create an ICOMAdminCatalog object.
  3. Get all the roles for the current COM+ application.
  4. Find the role AverageUser.
  5. Assign accounts to the found AverageUser role.
  6. Get all COM+ components for the current application.
  7. Check if the DesktopManager COM+ component exists.
  8. Grant access to users in the role AverageUser

Using the DesktopManager COM+ object

First, you have to create a DesktopManager object:

m_desktopManager = new DesktopManagerDll.DesktopManager();
// this will instantiate the DesktopManager

Second, use m_desktopManager in the WindowsFinder class:

m_windowFinder.KillPopupWindow(m_titleToKill, classToKill);

where:

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);
   }
}

Third, release m_desktopManager when done:

Marshal.ReleaseComObject(m_desktopManager);

Finally, shutdown the COM+ application:

ICOMAdminCatalog cac = (ICOMAdminCatalog)Activator.CreateInstance(
    Type.GetTypeFromProgID("COMAdmin.COMAdminCatalog"));
cac.ShutdownApplication("{75FA7F8B-7F94-4023-B4B8-7CCF6F988713}");

Installation

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:

InstallUtil.exe DesktopManagerDll.dll
InstallUtil.exe WindowKiller.exe

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...

WindowKiller -a

... 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.

History

This is Part 2 of my previous article.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here