[C#] Benutzung des Backgroundworker-Objektes

using System.Threading;

BackgroundWorker bw = new BackgroundWorker();

private void btnStartWorker_Click(object sender, EventArgs e)
{
    if (!bw.IsBusy)
    {
        bw.WorkerReportsProgress = true;
        bw.WorkerSupportsCancellation = true;
        bw.DoWork += new DoWorkEventHandler(worker_DoWork);
        bw.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
        bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
        bw.RunWorkerAsync();

        btnStartWorker.Text = "Abbruch";
        this.Cursor = Cursors.Wait;
    }
    else
    {
        bw.CancelAsync();
    }
}

private void worker_DoWork(object sender, DoWorkEventArgs e)
{
    for (int i = 0; i < 10000; i++)
    {
        if (bw.CancellationPending)
        {
            e.Cancel = true;
            return;
        }

        // irgendwas rechnen
        int iPc = (int)(((double)i / 10000.0) * 100);

        // Fortschrittswert melden
        bw.ReportProgress(iPc);

        // BackgroundWorker schlafen schicken
        Thread.Sleep(100);
    }
}

private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
	this.BeginInvoke((MethodInvoker)delegate
	{
		pbProgressBar.Value = e.ProgressPercentage;
	});
}

private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // hier Dinge erledigen, die auftreten, wenn Backgroundworker fertig ist
    this.Cursor = Cursors.Arrow;
    
    if (e.Cancelled)
    {
        btnStartWorker.Text = "Start";
    }
    
    if (e.Error != null)
    {
        MessageBox.Show(e.Error.Message);
    }
}

Plattformtyp (32Bit, 64Bit) herausfinden

Folgende Klasse bestimmt die Plattform auf welcher der akt. Prozess ausgeführt wird.

using System;

/// <summary>
/// freeware helper class for getting platform info
/// (W) 2011 by admin of codezentrale.de
/// </summary>
public static class PlatFormDetect
{
    private const string sX86 = "x86";
    private const string sAMD64 = "AMD64";

    public enum EPlatformType
    {
        Unknown,
        Native32Bit, // 32Bit process on 32Bit OS
        Native64Bit, // 64Bit process on 64Bit OS
        WOW64        // 32Bit process on 64Bit OS
    }

    /// <summary>
    /// returns the current platform type
    /// </summary>
    public static EPlatformType PlatformType
    {
        get
        {
            EPlatformType ePT = EPlatformType.Unknown;

            // get native process bitness
            // x86   - 32bit native AND WOW64
            // AMD64 - 64bit native
            string sArchitecture = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE", EnvironmentVariableTarget.Machine);
            // get original CPU architecture
            // undefined (null) == 32Bit
            //            AMD64 == 64Bit
            string sArchitectureW6432 = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITEW6432", EnvironmentVariableTarget.Machine);

            // 32Bit process on 32Bit OS
            if ((sArchitecture == sX86) && string.IsNullOrEmpty(sArchitectureW6432)) ePT = EPlatformType.Native32Bit;
            // 64Bit process on 64Bit OS
            if ((sArchitecture == sAMD64) && string.IsNullOrEmpty(sArchitectureW6432)) ePT = EPlatformType.Native64Bit;
            // 32Bit process on 64Bit OS
            if ((sArchitecture == sX86) && (sArchitectureW6432 == sAMD64)) ePT = EPlatformType.WOW64;

            return ePT;
        }
    }
}

Ab .NET-Framework 4.0 stehen die Funktionen Environment.Is64BitProcess und Environment.Is64BitOperatingSystem zur Verfügung.

using System;

// helper class for getting platform info
// (W) 2010 by admin of codezentrale.de
public static class PlatFormDetect4
{
    private const string s32Bit = "32Bit";
    private const string s64Bit = "64Bit";

    /// <summary>
    /// prints the OS bitness
    /// </summary>
    /// <returns>OS bitness</returns>
    public static string OSBitness
    {
        get
        {
            return Environment.Is64BitOperatingSystem ? s64Bit : s32Bit;
        }
    }
    /// <summary>
    /// prints the process bitness
    /// </summary>
    /// <returns>process bitness</returns>
    public static string ProcessBitness
    {
        get
        {
            return Environment.Is64BitProcess ? s64Bit : s32Bit;
        }
    }
}

Berechnungsfortschritt einer Threadfunktion in einem Fenster anzeigen

Häufig möchte man rechenintensive Aufgaben in Threads auslagern und dennoch deren Forschritt in einem kleinen Fenster anzeigen. Im folgenden Beispiel wird dazu eine Fensterklasse mit Fortschrittsbalken erzeugt und ein zugehöriges Threadobjekt angelegt.

  • Fortschrittsfenster mit einem Label – lblWait, Progressbar – pbWait und einem Abbrechen-Button – btnCancel
  • alle Properties werden Threadsafe ausgelegt, damit der Workerthread ohne Probleme seine Ausgaben machen kann
using System.Windows.Forms;

public partial class frmWait : Form
{
    /// <summary>
    /// Dialognachricht
    /// </summary>
    public string WaitMessage
    {
        get { return lblWait.Text; }
        set 
        {
            if (lblWait.InvokeRequired)
            {
                BeginInvoke((MethodInvoker)delegate() { lblWait.Text = value; });
            }
            else
            {
                lblWait.Text = value;
            }
        }
    }
    /// <summary>
    /// Fortschrittsanzeige in %
    /// </summary>
    public int Progress
    {
        get { return pbWait.Value; }
        set 
        {
            int iValue = 0;

            if (value ->= pbWait.Minimum && value <= pbWait.Maximum)
            {
                iValue = value;
            }
            else
            {
                if (value < pbWait.Minimum)
                {
                    iValue = pbWait.Minimum;
                }
                else
                     if (value -> pbWait.Maximum)
                     {
                         iValue = pbWait.Maximum;
                     }
            }

            if (pbWait.InvokeRequired)
            {
                BeginInvoke((MethodInvoker)delegate() { pbWait.Value = iValue; });
            }
            else
            {
                pbWait.Value = iValue;
            }
        }
    }
    /// <summary>
    /// Caption des Dialoges
    /// </summary>
    public string Title
    {
        get { return this.Text; }
        set 
        {
            if (this.InvokeRequired)
            {
                BeginInvoke((MethodInvoker)delegate() { this.Text = value; });
            }
            else
            {
                this.Text = value;
            }
        }
    }
    /// <summary>
    /// Konstruktor
    /// </summary>
    public frmWait()
    {
        InitializeComponent();

        // Abbrechen-Button vorinitialisieren
        btnCancel.DialogResult = DialogResult.Cancel;
        btnCancel.TabStop = false;
    }
}
  • Thread-Objekt zur Kapselung des Berechnungsthreads
using System.Threading;
using System;
using System.Windows.Forms;

/// <summary>
/// Eventargument wenn ein Thread beendet wird
/// </summary>
public class ThreadEndingEventArgs : EventArgs
{
    private string _msg;

    public string Message
    {
        get { return _msg; }
    }

    public ThreadEndingEventArgs(string Message)
    {
        _msg = Message;
    }
}

// die Klasse zum Kapseln der Berechnung in einem Thread
public class CWorker
{
    // Referenz auf den Fortschrittsdialog
    private frmWait _frmWaitDlg = null;
    // aktuell ausgeführter Thread
    private Thread _Thread = null;
    
    private int _iMin = 0;
    private int _iMax = 10000000;
    
    /// <summary->
    /// Event, wird ausgelöst, wenn ein Thread beendet wird
    /// </summary->
    public event EventHandler<ThreadEndingEventArgs-> ThreadEnding;
    
    public CWorker(int iMin, int iMax, frmWait frmWaitDlg)
    {
        _iMin = iMin;
        _iMax = iMax;
        _frmWaitDlg = frmWaitDlg;
    }

    // Startfunktion
    public Thread StartCalculation()
    {
        _Thread = new Thread(WorkFunktion);

        _Thread.IsBackground = true;
        _Thread.Priority = ThreadPriority.BelowNormal; // Priorität des Threads senken um der GUI Zeit zu lassen
        _Thread.Start();

        return _Thread;
    }
    
    // Abbruchfunktion
    public void AbortCalculation()
    {
        if (_Thread != null && _Thread.IsAlive)
        {
            _Thread.Abort();
        }
    }

    // die eigentlich Threadfunktion
    private void WorkFunktion(object oObj)
    {
        try
        {
            if (_frmWaitDlg != null) _frmWaitDlg.Title = "Bitte warten ...";

            // etwas berechnen
            for (int iCurrent = _iMin; iCurrent < _iMax; iCurrent++)
            {
                int iProgress = 100 * ((iCurrent - _iMin) / _iMax - _iMin);

                if (_frmWaitDlg != null)
                {
                    _frmWaitDlg.WaitMessage = "Arbeite (" + iProgress.ToString() + "%)";
                    _frmWaitDlg.Progress = iProgress;
                }
            }
            
            if (_frmWaitDlg != null) _frmWaitDlg.DialogResult = System.Windows.Forms.DialogResult.OK;
            
            // Event "ThreadEnding" aufrufen, um das übergeordnete Obj zu informieren
            if (this.ThreadEnding != null) ThreadEnding(this, new ThreadEndingEventArgs("Berechnung fertig!"));
        }
        // ThreadAbort abfangen
        catch (ThreadAbortException)
        {
            if (_frmWaitDlg != null) _frmWaitDlg.DialogResult = System.Windows.Forms.DialogResult.Cancel;
        }
        // alle anderen Exceptions ausgeben
        catch (Exception e)
        {
            if (_frmWaitDlg != null) _frmWaitDlg.DialogResult = System.Windows.Forms.DialogResult.Cancel;
            MessageBox.Show("Fehler" + Environment.NewLine + Environment.NewLine + e.Message, "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
        finally
        {
            // hier noch evtl. aufräumen
        }
    }
}
  • Aufrufbeispiel
public bool CalcFct()
{
    bool bRetVal = false;
    
    // Wartedialog erzeugen
    frmWait frmWaitDlg = new frmWait();
    
    // Worker-Objekt mit Thread erzeugen
    CWorker oWorker = new CWorker(0, 1000000, frmWaitDlg);
    // Event für pos. Beenden des Threads festlegen
    oWorker.ThreadEnding += new EventHandler<ThreadEndingEventArgs->(oWorker_ThreadEnding);
    
    // Thread starten
    Thread trdCalc = oWorker.StartCalculation();
    
    // auf Resultat des Wartedialoges warten (Cancel oder OK)
    DialogResult result = frmWaitDlg.ShowDialog();
    
    // wenn im Dialog "Abbruch" geklickt wurde
    if (trdCalc != null && result != DialogResult.OK)
    {
        // ThreadAbort-Exception wird im Thread abgefangen und still behandelt
        oWorker.AbortCalculation();
        // dafür hier einen Dialog anzeigen
        MessageBox.Show("Berechnung wurde abgebrochen.", "Nachricht", MessageBoxButtons.OK, MessageBoxIcon.Information);
        
        bRetVal = false;
    }
    else
    {
        // alles ok
        bRetVal = true;
    }
    
    return bRetVal;
}

// Event-Funktion, für positives Worker-Thread-Ende
private void oWorker_ThreadEnding(object sender, ThreadEndingEventArgs e)
{
    MessageBox.Show(e.Message, "Nachricht", MessageBoxButtons.OK, MessageBoxIcon.Information);
}

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

Mehrfachstart einer Anwendung verhindern

// Programm.cs editieren
static class Program
{
    /// <summary>
    /// Der Haupteinstiegspunkt für die Anwendung.
    /// </summary>
    [STAThread]
    static void Main()
    {
        bool bNewMutex = false;
        // Mutex erzeugen, Mutexname = Test1
        System.Threading.Mutex mutex = new System.Threading.Mutex(true, "Test1", out bNewMutex);

        // wenn ein neuer Mutex erzeugt wurde,
        // dann wurde die Anwendung noch nicht
        // im System gestartet
        if (bNewMutex)
        {
            try
            {
                // Anwendung initialisieren und ausführen
                Application.EnableVisualStyles();
                Application.SetCompatibleTextRenderingDefault(false);
                Application.Run(new frmMain());
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
            }
            finally
            {
                // beim Beenden den Mutex wieder zerstören
                mutex.ReleaseMutex();
            }
        }
        else
        {
            // falls der Mutex nicht angelegt werden konnte, dann läuft die Anwendung bereits
            MessageBox.Show("Die Anwendung läuft bereits.", "Hinweis", MessageBoxButtons.OK, MessageBoxIcon.Information);
        } 
    }
}