Hilfsklasse zum Starten und Beenden von Prozessen, Finden und Aktivieren von Fenstern

Folgende Klasse erleichtert die Arbeit beim

  • Fenster finden
  • Fenster in den Vordergrund holen
  • Übersenden von Windows-Messages an Fenster
  • Übersenden von Strings an Fenster
  • Fenster schließen
  • Anwendungen/Prozesse starten
  • Anwendungen/Prozesse beenden
  • Prozesse anhand der ID finden

Alle dazu benötigten Funktionen aus der User32.dll werden eingebunden und auch alle in der windows.h definierten Windows-Message-Konstanten sind enthalten.

  • Aufrufbeispiel:
// eigene Message definieren
private const int WM_MYOWNMESSAGE = 11111;

// Hilfsobjekt erzeugen
CAppCtrlObj wc = new CAppCtrlObj();

// Fenster-Handle von einer Beispielanwendung holen
IntPtr hWnd = wc.GetWindowHandle("FensterTitelMeinerAnwendung", null);

// Message an Fensterhandle schicken, in LParam wird beispielhaft die akt. Prozess-ID des aufrufenden Prozesses mitgesendet, auf Abarbeitung der Message warten
IntPtr err = wc.SendMessageToWindow(hWnd, WM_MYOWNMESSAGE, IntPtr.Zero, (IntPtr)System.Diagnostics.Process.GetCurrentProcess().Id);
if ((int)err != 0)
{
    // Fehler
}

// Nachricht WM_CLOSE senden, Fenster schließen, nicht auf Abarbeitung der Message warten
if (wc.PostMessageToWindow(hWnd, CAppCtrlObj.WM_CLOSE, IntPtr.Zero, IntPtr.Zero))
{
    // ok
}

// String an Fensterhandle schicken
IntPtr err = wc.SendStringMessageToWindow(hWnd, IntPtr.Zero, "Hallo.");
if ((int)err != 0)
{
    // Fehler
}

// Fenster in den Vordergrund holen
if (wc.ActivateWindow(hWnd))
{
    // ok
}

// Notepad mit Datei meintext.txt sichtbar und maximiert starten, ProzessID zurückholen
int iProzessID = wc.StartApplication(@"c:\WINDOWS\notepad.exe", @"c:\meintext.txt", false, true);

// zu ProzessID gehörendes Prozessobjekt holen
Process proc = wc.GetProcess(iProzessID);

if (proc != null)
{
    // Hauptfenster des Prozesses schließen, 10s auf Schließen-Bestätigung warten, sonst Fehler
    if (wc.CloseWindow(proc, false, true, 10000))
    {
    }
}
  • Klasse:
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.IO;

/// <summary>
/// Struct für die Stringübergabe an andere Fenster
/// </summary>
public struct SCopyData
{
    public IntPtr dwData;
    public int cbData;
    [MarshalAs(UnmanagedType.LPStr)]
    public string lpData;
}

public class CAppCtrlObj
{
    #region Message-Konstanten aus der Windows.h

    public const int WM_NULL = 0x00;
    public const int WM_CREATE = 0x01;
    public const int WM_DESTROY = 0x02;
    public const int WM_MOVE = 0x03;
    public const int WM_SIZE = 0x05;
    public const int WM_ACTIVATE = 0x06;
    public const int WM_SETFOCUS = 0x07;
    public const int WM_KILLFOCUS = 0x08;
    public const int WM_ENABLE = 0x0A;
    public const int WM_SETREDRAW = 0x0B;
    public const int WM_SETTEXT = 0x0C;
    public const int WM_GETTEXT = 0x0D;
    public const int WM_GETTEXTLENGTH = 0x0E;
    public const int WM_PAINT = 0x0F;
    public const int WM_CLOSE = 0x10;
    public const int WM_QUERYENDSESSION = 0x11;
    public const int WM_QUIT = 0x12;
    public const int WM_QUERYOPEN = 0x13;
    public const int WM_ERASEBKGND = 0x14;
    public const int WM_SYSCOLORCHANGE = 0x15;
    public const int WM_ENDSESSION = 0x16;
    public const int WM_SYSTEMERROR = 0x17;
    public const int WM_SHOWWINDOW = 0x18;
    public const int WM_CTLCOLOR = 0x19;
    public const int WM_WININICHANGE = 0x1A;
    public const int WM_SETTINGCHANGE = 0x1A;
    public const int WM_DEVMODECHANGE = 0x1B;
    public const int WM_ACTIVATEAPP = 0x1C;
    public const int WM_FONTCHANGE = 0x1D;
    public const int WM_TIMECHANGE = 0x1E;
    public const int WM_CANCELMODE = 0x1F;
    public const int WM_SETCURSOR = 0x20;
    public const int WM_MOUSEACTIVATE = 0x21;
    public const int WM_CHILDACTIVATE = 0x22;
    public const int WM_QUEUESYNC = 0x23;
    public const int WM_GETMINMAXINFO = 0x24;
    public const int WM_PAINTICON = 0x26;
    public const int WM_ICONERASEBKGND = 0x27;
    public const int WM_NEXTDLGCTL = 0x28;
    public const int WM_SPOOLERSTATUS = 0x2A;
    public const int WM_DRAWITEM = 0x2B;
    public const int WM_MEASUREITEM = 0x2C;
    public const int WM_DELETEITEM = 0x2D;
    public const int WM_VKEYTOITEM = 0x2E;
    public const int WM_CHARTOITEM = 0x2F;

    public const int WM_SETFONT = 0x30;
    public const int WM_GETFONT = 0x31;
    public const int WM_SETHOTKEY = 0x32;
    public const int WM_GETHOTKEY = 0x33;
    public const int WM_QUERYDRAGICON = 0x37;
    public const int WM_COMPAREITEM = 0x39;
    public const int WM_COMPACTING = 0x41;
    public const int WM_WINDOWPOSCHANGING = 0x46;
    public const int WM_WINDOWPOSCHANGED = 0x47;
    public const int WM_POWER = 0x48;
    public const int WM_COPYDATA = 0x4A;
    public const int WM_CANCELJOURNAL = 0x4B;
    public const int WM_NOTIFY = 0x4E;
    public const int WM_INPUTLANGCHANGEREQUEST = 0x50;
    public const int WM_INPUTLANGCHANGE = 0x51;
    public const int WM_TCARD = 0x52;
    public const int WM_HELP = 0x53;
    public const int WM_USERCHANGED = 0x54;
    public const int WM_NOTIFYFORMAT = 0x55;
    public const int WM_CONTEXTMENU = 0x7B;
    public const int WM_STYLECHANGING = 0x7C;
    public const int WM_STYLECHANGED = 0x7D;
    public const int WM_DISPLAYCHANGE = 0x7E;
    public const int WM_GETICON = 0x7F;
    public const int WM_SETICON = 0x80;

    public const int WM_NCCREATE = 0x81;
    public const int WM_NCDESTROY = 0x82;
    public const int WM_NCCALCSIZE = 0x83;
    public const int WM_NCHITTEST = 0x84;
    public const int WM_NCPAINT = 0x85;
    public const int WM_NCACTIVATE = 0x86;
    public const int WM_GETDLGCODE = 0x87;
    public const int WM_NCMOUSEMOVE = 0xA0;
    public const int WM_NCLBUTTONDOWN = 0xA1;
    public const int WM_NCLBUTTONUP = 0xA2;
    public const int WM_NCLBUTTONDBLCLK = 0xA3;
    public const int WM_NCRBUTTONDOWN = 0xA4;
    public const int WM_NCRBUTTONUP = 0xA5;
    public const int WM_NCRBUTTONDBLCLK = 0xA6;
    public const int WM_NCMBUTTONDOWN = 0xA7;
    public const int WM_NCMBUTTONUP = 0xA8;
    public const int WM_NCMBUTTONDBLCLK = 0xA9;

    public const int WM_KEYFIRST = 0x100;
    public const int WM_KEYDOWN = 0x100;
    public const int WM_KEYUP = 0x101;
    public const int WM_CHAR = 0x102;
    public const int WM_DEADCHAR = 0x103;
    public const int WM_SYSKEYDOWN = 0x104;
    public const int WM_SYSKEYUP = 0x105;
    public const int WM_SYSCHAR = 0x106;
    public const int WM_SYSDEADCHAR = 0x107;
    public const int WM_KEYLAST = 0x108;

    public const int WM_IME_STARTCOMPOSITION = 0x10D;
    public const int WM_IME_ENDCOMPOSITION = 0x10E;
    public const int WM_IME_COMPOSITION = 0x10F;
    public const int WM_IME_KEYLAST = 0x10F;

    public const int WM_INITDIALOG = 0x110;
    public const int WM_COMMAND = 0x111;
    public const int WM_SYSCOMMAND = 0x112;
    public const int WM_TIMER = 0x113;
    public const int WM_HSCROLL = 0x114;
    public const int WM_VSCROLL = 0x115;
    public const int WM_INITMENU = 0x116;
    public const int WM_INITMENUPOPUP = 0x117;
    public const int WM_MENUSELECT = 0x11F;
    public const int WM_MENUCHAR = 0x120;
    public const int WM_ENTERIDLE = 0x121;

    public const int WM_CTLCOLORMSGBOX = 0x132;
    public const int WM_CTLCOLOREDIT = 0x133;
    public const int WM_CTLCOLORLISTBOX = 0x134;
    public const int WM_CTLCOLORBTN = 0x135;
    public const int WM_CTLCOLORDLG = 0x136;
    public const int WM_CTLCOLORSCROLLBAR = 0x137;
    public const int WM_CTLCOLORSTATIC = 0x138;

    public const int WM_MOUSEFIRST = 0x200;
    public const int WM_MOUSEMOVE = 0x200;
    public const int WM_LBUTTONDOWN = 0x201;
    public const int WM_LBUTTONUP = 0x202;
    public const int WM_LBUTTONDBLCLK = 0x203;
    public const int WM_RBUTTONDOWN = 0x204;
    public const int WM_RBUTTONUP = 0x205;
    public const int WM_RBUTTONDBLCLK = 0x206;
    public const int WM_MBUTTONDOWN = 0x207;
    public const int WM_MBUTTONUP = 0x208;
    public const int WM_MBUTTONDBLCLK = 0x209;
    public const int WM_MOUSELAST = 0x20A;
    public const int WM_MOUSEWHEEL = 0x20A;

    public const int WM_PARENTNOTIFY = 0x210;
    public const int WM_ENTERMENULOOP = 0x211;
    public const int WM_EXITMENULOOP = 0x212;
    public const int WM_NEXTMENU = 0x213;
    public const int WM_SIZING = 0x214;
    public const int WM_CAPTURECHANGED = 0x215;
    public const int WM_MOVING = 0x216;
    public const int WM_POWERBROADCAST = 0x218;
    public const int WM_DEVICECHANGE = 0x219;

    public const int WM_MDICREATE = 0x220;
    public const int WM_MDIDESTROY = 0x221;
    public const int WM_MDIACTIVATE = 0x222;
    public const int WM_MDIRESTORE = 0x223;
    public const int WM_MDINEXT = 0x224;
    public const int WM_MDIMAXIMIZE = 0x225;
    public const int WM_MDITILE = 0x226;
    public const int WM_MDICASCADE = 0x227;
    public const int WM_MDIICONARRANGE = 0x228;
    public const int WM_MDIGETACTIVE = 0x229;
    public const int WM_MDISETMENU = 0x230;
    public const int WM_ENTERSIZEMOVE = 0x231;
    public const int WM_EXITSIZEMOVE = 0x232;
    public const int WM_DROPFILES = 0x233;
    public const int WM_MDIREFRESHMENU = 0x234;

    public const int WM_IME_SETCONTEXT = 0x281;
    public const int WM_IME_NOTIFY = 0x282;
    public const int WM_IME_CONTROL = 0x283;
    public const int WM_IME_COMPOSITIONFULL = 0x284;
    public const int WM_IME_SELECT = 0x285;
    public const int WM_IME_CHAR = 0x286;
    public const int WM_IME_KEYDOWN = 0x290;
    public const int WM_IME_KEYUP = 0x291;

    public const int WM_MOUSEHOVER = 0x2A1;
    public const int WM_NCMOUSELEAVE = 0x2A2;
    public const int WM_MOUSELEAVE = 0x2A3;

    public const int WM_CUT = 0x300;
    public const int WM_COPY = 0x301;
    public const int WM_PASTE = 0x302;
    public const int WM_CLEAR = 0x303;
    public const int WM_UNDO = 0x304;

    public const int WM_RENDERFORMAT = 0x305;
    public const int WM_RENDERALLFORMATS = 0x306;
    public const int WM_DESTROYCLIPBOARD = 0x307;
    public const int WM_DRAWCLIPBOARD = 0x308;
    public const int WM_PAINTCLIPBOARD = 0x309;
    public const int WM_VSCROLLCLIPBOARD = 0x30A;
    public const int WM_SIZECLIPBOARD = 0x30B;
    public const int WM_ASKCBFORMATNAME = 0x30C;
    public const int WM_CHANGECBCHAIN = 0x30D;
    public const int WM_HSCROLLCLIPBOARD = 0x30E;
    public const int WM_QUERYNEWPALETTE = 0x30F;
    public const int WM_PALETTEISCHANGING = 0x310;
    public const int WM_PALETTECHANGED = 0x311;

    public const int WM_HOTKEY = 0x312;
    public const int WM_PRINT = 0x317;
    public const int WM_PRINTCLIENT = 0x318;

    public const int WM_HANDHELDFIRST = 0x358;
    public const int WM_HANDHELDLAST = 0x35F;
    public const int WM_PENWINFIRST = 0x380;
    public const int WM_PENWINLAST = 0x38F;
    public const int WM_COALESCE_FIRST = 0x390;
    public const int WM_COALESCE_LAST = 0x39F;
    public const int WM_DDE_FIRST = 0x3E0;
    public const int WM_DDE_INITIATE = 0x3E0;
    public const int WM_DDE_TERMINATE = 0x3E1;
    public const int WM_DDE_ADVISE = 0x3E2;
    public const int WM_DDE_UNADVISE = 0x3E3;
    public const int WM_DDE_ACK = 0x3E4;
    public const int WM_DDE_DATA = 0x3E5;
    public const int WM_DDE_REQUEST = 0x3E6;
    public const int WM_DDE_POKE = 0x3E7;
    public const int WM_DDE_EXECUTE = 0x3E8;
    public const int WM_DDE_LAST = 0x3E8;

    public const int WM_USER = 0x400;
    public const int WM_APP = 0x8000;

    #endregion

    #region Importfunktionen aus User32.dll

    // Wenn möglich sollte beim Aufruf der Funktionen immer mit IntPtr gearbeitet werden, da es sonst zu Adressierungs-Fehlern auf 64Bit-Systemen kommen kann!
    // http://www.pinvoke.net/default.aspx/user32.GetDesktopWindow
    [DllImport("user32", SetLastError = true)]
    public static extern IntPtr GetDesktopWindow();

    // http://www.pinvoke.net/default.aspx/user32.FindWindow
    [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

    // http://www.pinvoke.net/default.aspx/user32.GetWindowTextLength
    [DllImport("user32", SetLastError = true)]
    private static extern int GetWindowTextLength(IntPtr hWnd);

    // http://www.pinvoke.net/default.aspx/user32.GetWindowText
    [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

    // http://www.pinvoke.net/default.aspx/user32.SetForegroundWindow
    [DllImport("user32", SetLastError = true)]
    private static extern bool SetForegroundWindow(IntPtr hWnd);

    // http://www.pinvoke.net/default.aspx/user32.IsIconic
    [DllImport("user32", SetLastError = true)]
    private static extern bool IsIconic(IntPtr hWnd);

    // http://www.pinvoke.net/default.aspx/user32.OpenIcon
    [DllImport("user32", SetLastError = true)]
    private static extern bool OpenIcon(IntPtr hWnd);

    // http://www.pinvoke.net/default.aspx/user32.GetClassName
    [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

    // http://www.pinvoke.net/default.aspx/user32.SendMessage
    [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr SendMessage(IntPtr hWnd, uint uiMsg, IntPtr wParam, IntPtr lParam);

    // http://boycook.wordpress.com/2008/07/29/c-win32-messaging-with-sendmessage-and-wm_copydata/
    // http://craigcook.co.uk/samples/MessageHelper.cs.txt
    [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr SendMessage(IntPtr hWnd, uint uiMsg, IntPtr wParam, ref SCopyData lParam);

    // http://www.pinvoke.net/default.aspx/user32.PostMessage
    [DllImport("user32", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool PostMessage(IntPtr hWnd, uint iMsg, IntPtr wParam, IntPtr lParam);
    
    #endregion

    public CAppCtrlObj()
    {
    }
    /// <summary>
    /// ermittelt Fensterhandle des Desktops
    /// </summary>
    /// <returns>Handle</returns>
    public IntPtr GetDesktopWindowHandle()
    {
        return GetDesktopWindow();
    }
    /// <summary>
    /// ermittelt Fensterhandle
    /// </summary>
    /// <param name="sWindowTitle">Fenstertitel</param>
    /// <param name="sWindowClassName">Name der zugehörigen Fensterklasse, kann null sein</param>
    /// <returns>Handle</returns>
    public IntPtr GetWindowHandle(string sWindowTitle, string sWindowClassName)
    {
        return FindWindow(sWindowClassName, sWindowTitle);
    }
    /// <summary>
    /// versucht Fenster zu aktivieren
    /// </summary>
    /// <param name="iptrWindowHandle">Fensterhandle</param>
    /// <returns>true, false</returns>
    public bool ActivateWindow(IntPtr iptrWindowHandle)
    {
        bool bRetVal = false;

        if (iptrWindowHandle != null)
        {
            bool bGo = true;

            if (IsIconic(iptrWindowHandle))
            {
                bGo = OpenIcon(iptrWindowHandle);
            }

            if (bGo)
            {
                bRetVal = SetForegroundWindow(iptrWindowHandle);
            }
        }

        return bRetVal;
    }
    /// <summary>
    /// versucht Fenster zu aktivieren
    /// </summary>
    /// <param name="process">Process-Objekt</param>
    /// <returns>true, false</returns>
    public bool ActivateWindow(Process process)
    {
        return (process != null) ? this.ActivateWindow(process.MainWindowHandle) : false;
    }
    /// <summary>
    /// ermittelt Klassenname eines Fensters
    /// </summary>
    /// <param name="sWindowTitle">Fenstername</param>
    /// <returns>Klassenname des Fensters</returns>
    public string GetWindowClassName(string sWindowTitle)
    {
        string sRetVal = string.Empty;

        IntPtr hWnd = FindWindow(null, sWindowTitle);

        if (hWnd != null)
        {
            StringBuilder classname = new StringBuilder(255);

            if (GetClassName(hWnd, classname, 255) != 0)
            {
                sRetVal = classname.ToString();
            }
        }

        return sRetVal;
    }
    /// <summary>
    /// Nachricht an ein Fenster senden, wartet auf Ausführung
    /// </summary>
    /// <param name="hWnd">Fensterhandle</param>
    /// <param name="iMsg">Nachrichten-ID</param>
    /// <param name="wParam">1. Parameter, wenn nicht benötigt, dann IntPtr.Zero setzen</param>
    /// <param name="lParam">2. Parameter, wenn nicht benötigt, dann IntPtr.Zero setzen</param>
    /// <returns>Status</returns>
    public IntPtr SendMessageToWindow(IntPtr hWnd, uint uiMsg, IntPtr wParam, IntPtr lParam)
    {
        return SendMessage(hWnd, uiMsg, wParam, lParam);
    }
    /// <summary>
    /// String mittels WM_COPYDATA an ein Fenster senden, wartet auf Ausführung
    /// </summary>
    /// <param name="hWnd">Fensterhandle</param>
    /// <param name="wParam">1. Parameter, wenn nicht benötigt, dann IntPtr.Zero setzen</param>
    /// <param name="sMessage">2. Parameter als Nachrichtenstring</param>
    /// <returns>Status</returns>
    public IntPtr SendStringMessageToWindow(IntPtr hWnd, IntPtr wParam, string sMessage)
    {
        byte[] sarr = Encoding.Default.GetBytes(sMessage);

        SCopyData cds;
        cds.dwData = IntPtr.Zero;
        cds.lpData = sMessage;
        cds.cbData = sarr.Length + 1;

        return SendMessage(hWnd, WM_COPYDATA, wParam, ref cds);
    }
    /// <summary>
    /// Nachricht dem MessageQueue des Erzeugerthreads eines Fensters hinzufügen, wartet nicht auf Ausführung
    /// </summary>
    /// <param name="hWnd">Fensterhandle</param>
    /// <param name="iMsg">Nachrichten-ID</param>
    /// <param name="wParam">1. Parameter, wenn nicht benötigt, dann IntPtr.Zero setzen</param>
    /// <param name="lParam">2. Parameter, wenn nicht benötigt, dann IntPtr.Zero setzen</param>
    /// <returns>true, false</returns>
    public bool PostMessageToWindow(IntPtr hWnd, uint iMsg, IntPtr wParam, IntPtr lParam)
    {
        return PostMessage(hWnd, iMsg, wParam, lParam);
    }
    /// <summary>
    /// schließt das Hauptfenster eines Prozesses
    /// </summary>
    /// <param name="process">der Prozess, der beendet werden soll</param>
    /// <param name="bForce">Schließen erzwingen (Kill)?</param>
    /// <param name="bWaitForExit">Auf Beendigung warten?</param>
    /// <param name="iExitWaitTimeInMs">Zeit für das Warten auf Beendigung</param>
    /// <returns>true, false</returns>
    public bool CloseWindow(Process process, bool bForce, bool bWaitForExit, int iExitWaitTimeInMs)
    {
        bool bRetVal = false;

        if (process.CloseMainWindow())
        {
            if (bWaitForExit)
            {
                bRetVal = process.WaitForExit(iExitWaitTimeInMs);
            }
            else
            {
                bRetVal = true;
            }
        }
        else
        {
            if (bForce)
            {
                process.Kill();
                bRetVal = true;
            }
        }

        return bRetVal;
    }
    /// <summary>
    /// Startet eine Datei, prüft, ob Datei vorhanden
    /// </summary>
    /// <param name="sFileName">Pfad und Dateiname</param>
    /// <param name="sArguments">Argumentliste</param>
    /// <param name="bHidden">Prozess versteckt starten?</param>
    /// <param name="bMaximized">Wenn nicht versteckt, maximieren?</param>
    /// <returns>Prozess-ID, im Fehlerfall -1</returns>
    public int StartApplication(string sFileName, string sArguments, bool bHidden, bool bMaximized)
    {
        int iRetVal = -1;

        if (File.Exists(sFileName))
        {
            Process process = new Process();
            process.StartInfo.UseShellExecute = true;
            process.StartInfo.WindowStyle = bHidden ? ProcessWindowStyle.Hidden : bMaximized ? ProcessWindowStyle.Maximized : ProcessWindowStyle.Normal;
            process.StartInfo.FileName = sFileName;
            process.StartInfo.Arguments = sArguments;

            if (process.Start())
            {
                iRetVal = process.Id;
            }
        }

        return iRetVal;
    }
    /// <summary>
    /// Prozess anhand einer Prozess-ID im System ermitteln
    /// </summary>
    /// <param name="iProcessID">eindeutige systemweite Prozess-ID</param>
    /// <returns>Prozess</returns>
    public Process GetProcess(int iProcessID)
    {
        return Process.GetProcessById(iProcessID);
    }
}