Figures
© 2004 Microsoft Corporation. All rights reserved.
Figure 1 Win32API.cs
// Win32API: wrapper for selected Win32 API functions
// To compile:
//    csc /t:library /out:Win32API.dll Win32API.cs
//
using System;
using System.Drawing;
using System.Text;
using System.Runtime.InteropServices;

//////////////////
// namespace to wrap Win32 API functions. Add them here as you need...
//
namespace Win32API {
   [StructLayout(LayoutKind.Sequential)]
   public struct POINT {
      public POINT(int xx, int yy) { x=xx; y=yy; }
      public int x;
      public int y;
      public override string ToString() {
         String s = String.Format("({0},{1})", x, y);
         return s;
      }
   }

   [StructLayout(LayoutKind.Sequential)]
   public struct SIZE {
      public SIZE(int cxx, int cyy) { cx=cxx; cy=cyy; }
      public int cx;
      public int cy;
      public override string ToString() {
         String s = String.Format("({0},{1})", cx, cy);
         return s;
      }
   }

   [StructLayout(LayoutKind.Sequential)]
   public struct RECT {
      public int left;
      public int top;
      public int right;
      public int bottom;
      public int Width()      { return right - left; }
      public int Height()     { return bottom - top; }
      public POINT TopLeft()  { return new POINT(left,top); }
      public SIZE  Size()     { return new SIZE(Width(), Height()); }
      public override string ToString() {
         String s = String.Format("{0}x{1}", TopLeft(), Size());
         return s;
      }
   }

   public class Win32 {
      [DllImport("user32.dll")]
      public static extern bool IsWindowVisible(int hwnd);

      [DllImport("user32.dll")]
      public static extern int GetWindowText(int hwnd,
         StringBuilder buf, int nMaxCount);

      [DllImport("user32.dll")]
      public static extern int GetClassName(int hwnd,
         [MarshalAs(UnmanagedType.LPStr)] StringBuilder buf,
         int nMaxCount);

      [DllImport("user32.dll")]
      public static extern int GetWindowRect(int hwnd, ref RECT rc);

      [DllImport("user32.dll")]
      // note the runtime knows how to marshal a Rectangle
      public static extern int GetWindowRect(int hwnd, ref Rectangle rc);

      // ... add more here
   }
}
Figure 2 WinArray.cs
// WinArray: generate ArrayList of top-level windows using EnumWindows.
//
using System;
using System.Collections;
using System.Runtime.InteropServices;

namespace WinArray {

   public class WindowArray : ArrayList {
      private delegate bool EnumWindowsCB(int hwnd, IntPtr param);

      // This is declared private since only I use it—no need
      [DllImport("user32")]
      private static extern int EnumWindows(EnumWindowsCB cb, 
         IntPtr param); 

      private static bool MyEnumWindowsCB(int hwnd, IntPtr param) {
         GCHandle gch = (GCHandle)param;
         WindowArray itw = (WindowArray)gch.Target;
         itw.Add(hwnd);
         return true;
      }

      // This is the only public method, the only one you need to call
      public WindowArray() {
         GCHandle gch = GCHandle.Alloc(this);
         EnumWindowsCB ewcb = new EnumWindowsCB(MyEnumWindowsCB);
         EnumWindows(ewcb, (IntPtr)gch);
         gch.Free();
      }
   }
}
Figure 3 ListWin.cs
using System;
using System.Text;
using System.Drawing;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Win32API; // home-brew wrapper for native API
using WinArray; // home-brew window iterator

class MyApp {
   // global command-line switches
   static bool bRectangle = false; // show window rect using Rectangle
   static bool bRect = false;      // show window Rect using RECT
   static bool bClassName = false; // show class name
   static bool bTitle = false;     // show title
   static bool bHwnd = false;      // show HWND

   [STAThread]
   // main entry point
   static int Main(string[] args) {
      // Parse command line. Switches can come in any order.
      if (args.GetLength(0)<=0)
         return help();
      for (int i=0, len=args.GetLength(0); i<len; i++) {
         if (args[i].StartsWith("/") || args[i].StartsWith("-") ) {
            for (int j=1; j<args[i].Length; j++) {
               switch (args[i][j]) {
               case 'c': bClassName = true; break;
               case 'h': bHwnd = true; break;
               case 'r': bRect = true; break;
               case 'R': bRectangle = true; break;
               case 't': bTitle = true; break;
               case '?': default: return help();
               }
            }
         }
      }
      
      WindowArray itw = new WindowArray();
      foreach (int hwnd in itw) {
         if (Win32.IsWindowVisible(hwnd)) {
            if (bHwnd) {
               Console.Write("{0:x8}", hwnd);
            }
            if (bClassName) {
               StringBuilder cname = new StringBuilder(256);
               Win32.GetClassName(hwnd, cname, cname.Capacity);
               Console.Write(" {0}",cname);
            }
            if (bRectangle) {
               Rectangle rc = new Rectangle();
               Win32.GetWindowRect(hwnd, ref rc);
               Console.Write(" {0}",rc);
            } else if (bRect) {
               RECT rc = new RECT();
               Win32.GetWindowRect(hwnd, ref rc);
               Console.Write(" {0}",rc);
            }
            if (bTitle) {
               StringBuilder title = new StringBuilder(256);
               Win32.GetWindowText(hwnd, title, title.Capacity);
               Console.Write(" {0}",title);
            }
            Console.WriteLine();
         }
      }
      return 0;
   }

   static int help() {
      Console.WriteLine("ListWin:  List top-level windows.");
      Console.WriteLine("          Copyright 2002 Paul DiLascia.");
      Console.WriteLine("Format:   ListWin [/chrRt]");
      Console.WriteLine("Options:");
      Console.WriteLine(" /c(lassname) show window class name");
      Console.WriteLine(" /h(wnd)      show HWNDs");
      Console.WriteLine(" /t(itle)     show title (caption)");
      Console.WriteLine(" /r(ect)      show window rect using RECT");
      Console.WriteLine(" /R(ectangle) show window rect using Rectangle");
      Console.WriteLine("");
      return 0;
   }
}
Figure 6 kp
#include "stdafx.h"
#include "EnumProc.h"

typedef list<string> CStringList;         // like MFC, but with STL
inline BOOL isswitch(TCHAR c) { return c==L'/' || c==L'-'; }

int main(int argc, TCHAR* argv[], TCHAR* envp[])
{
    CStringList cmdargs;         // command-line args (processes to kill)
    BOOL bDisplayOnly=FALSE;     // don't kill, just show results
    BOOL bQuiet=FALSE;           // suppress error messages
    BOOL bZap=FALSE;             // force-kill process

    // Parse command line. Switches can come in any order.
    for (int i=1; i<argc; i++) {
        if (isswitch(argv[i][0])) {
            for (UINT j=1; j<strlen(argv[i]); j++) {
                switch(tolower(argv[i][j])) {
                case '?':    help();    return 0;
                case 'n':    bDisplayOnly=TRUE; break;
                case 'q':    bQuiet=TRUE;       break;
                case 'z':    bZap=TRUE;         break;
                default:
                    return help();
                }
            }
        } else {
            cmdargs.push_back(argv[i]);     // got a non-switch arg: add 
                                            // to list
        }
    }
    if (cmdargs.size()<=0)
        help();

    // Now iterate args (module names), killing each one
    CStringList::iterator it;
    for (it=cmdargs.begin(); it!=cmdargs.end(); it++) {
        CFindKillProcess fkp;
        DWORD pid = fkp.FindProcess(it->c_str());
        if (pid) {
            if (bDisplayOnly) {
                _tprintf(_T("Kill process %d(0x%08x)\n"),pid,pid);
            } else {
                fkp.KillProcess(pid, bZap);
            }
        } else if (!bQuiet) {
            _tprintf(_T("Error: Can't find process '%s'.\n"),it-
            >c_str());
        }
    }
    return 0;
}
Figure 7 EnumProc

EnumProc.h
// Code from last month's column not shown: CProcessIterator,
// CWindowIterator, etc.

//////////////////
// Handy class to facilitate finding and killing a process by name.
//
class CFindKillProcess {
public:
    CFindKillProcess();
    ~CFindKillProcess();
    DWORD FindProcess(LPCTSTR lpModname, BOOL bAddExe=TRUE);
    BOOL  KillProcess(DWORD pid, BOOL bZap);
};
EnumProc.cpp
#include "stdafx.h"
#include "EnumProc.h"

// Code from last month's column not shown: CProcessIterator,
// CWindowIterator, etc.

////////////////////////////////////////////////////////////////
// CFindKillProcess - to find/kill a process by module name.
//
CFindKillProcess::CFindKillProcess()
{
}

CFindKillProcess::~CFindKillProcess()
{
}

//////////////////
// Search for process whose module name matches parameter.
// Finds "foo" or "foo.exe"
//
DWORD CFindKillProcess::FindProcess(LPCTSTR modname, BOOL bAddExe)
{
    CProcessIterator itp;
    for (DWORD pid=itp.First(); pid; pid=itp.Next()) {
        TCHAR name[_MAX_PATH];
        CProcessModuleIterator itm(pid);
        HMODULE hModule = itm.First(); // .EXE
        if (hModule) {
            GetModuleBaseName(itm.GetProcessHandle(),
                hModule, name, _MAX_PATH);

            string sModName = modname;
            if (strcmpi(sModName.c_str(),name)==0)
                return pid;
            sModName += ".exe";
            if (bAddExe && strcmpi(sModName.c_str(),name)==0)
                return pid;
        }
    }
    return 0;
}

//////////////////
// Kill a process cleanly: Close main windows and wait.
// bZap=TRUE to force kill.
//
BOOL CFindKillProcess::KillProcess(DWORD pid, BOOL bZap)
{
    CMainWindowIterator itw(pid);
    for (HWND hwnd=itw.First(); hwnd; hwnd=itw.Next()) {
        DWORD bOKToKill = FALSE;
        SendMessageTimeout(hwnd, WM_QUERYENDSESSION, 0, 0,
            SMTO_ABORTIFHUNG|SMTO_NOTIMEOUTIFNOTHUNG, 100, &bOKToKill);
        if (!bOKToKill)
            return FALSE;  // window doesn't want to die: abort
        PostMessage(hwnd, WM_CLOSE, 0, 0);
    }

    // I've closed the main windows; now wait for process to die. 
    BOOL bKilled = TRUE;
    HANDLE hp=OpenProcess(SYNCHRONIZE|PROCESS_TERMINATE,FALSE,pid);
    if (hp) {
        if (WaitForSingleObject(hp, 5000) != WAIT_OBJECT_0) {
            if (bZap) { // didn't die: force kill it if zap requested
                TerminateProcess(hp,0);
            } else {
                bKilled = FALSE;
            }
        }
        CloseHandle(hp);
    }
    return bKilled;
}
Page view tracker