Click here to Skip to main content
15,867,568 members
Articles / Desktop Programming / Win32

Application Management

Rate me:
Please Sign up or sign in to vote.
3.71/5 (5 votes)
18 Feb 2010Ms-PL3 min read 27.3K   649   48   8
Application Management makes your application's life easier. It will automatically do memory management, handle and log unhandled exceptions, profile your functions, make your application single instance, and also provide utility functions to get system information.

Table of Contents

Introduction

Application Management makes your application life easier. It will automatic do memory management, handle and log unhandled exceptions, profile your functions, make your application single instance, and also provide utility functions to get system information.

Supported platforms

This library works on multiple platforms, and was tested on Windows XP, Windows 7, and Linux Ubuntu 9.10. For Linux, I have supplied Mono compilations that you can recompile or execute. The Debug and Release folders under bin were compiled used Visual Studio 2008 (Windows). The Mono folder under bin was compiled using MonoDevelop (Mono systems compatible).

Classes and functions are protected from incompatibility OS exceptions. All WinAPI functions wont work outside a Windows system.

If you want your own system verification, use the following code:

C#
if(Environment.OSVersion.Platform == PlatformID.Win32NT)
{
    // Windows NT Platform
}
else
{
    // Non Windows System
}

ApplicationManagement_app_v1

Background

This library does not replace your inline optimizations, you always have to Dispose your objects whenever possible.

Using the code

Most of that classes should be used outside scope and declared as static. I'm going to use public static to allow me to access classes anywhere. Classes that have a Start(); also have a Stop();.

Classes in the library

See the documentation file for more information about the classes.

  • WinAPI (Contains all the Win API calls) namespace
    • Dbghelp (All API calls for Dbghelp.dll) static class
    • Kernel32 (All API calls for Kernel32.dll) static class
  • About (Store some constants about the library, author, webpage, etc...) static class
  • AssemblyEx (Util functions from the assembly) static class
  • ExceptionHandler (Automatic handles and log unhandled exceptions) classs
  • Instance (Make your application single instance) class
  • MemoryManagement (Automatic memory management) class
  • MiniDump (Used to create mini dumps) static class
  • Profiling (Used for profiling your functions, Dictionary of ProfilingData) class
    • ProfilingData (Class that holdd the profiling data, StartDate, EndDate, TimeTaken, ...) class
  • SystemInformationEx (Provides some GET functions related to system information) static class
  • VistaSecurity (Functions related to Windows Vista and/or above) static class

Instance vlass

C#
public static Instance instance;
[STAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    #region Instance Class (Make single instance app)
    // Check if that is a single instance, and name mutex as: "{ProductName}Mutex"
    instance = new Instance(Application.ProductName);
    // instance is created but make sure you call next line:
    // First parameter is used to define mutex level (Global or this session only)
    // Second parameter is used to check processes equality after check mutex
    if (!instance.MakeSingleInstance(true, false))
    {
        Instance.ShowDuplicateInstanceDialogError();
        // Stop and quit App.
        return;
    }
    #endregion

    Application.Run(new MainFrm());
    // Note: by calling 'Instance.Dispose' method will release mutex,
    // and app will be multi instance,
    // But still checks for process equality!
    // instance.Dispose();
}

MemoryManagement class

appmanagement_memorymanagement.png

Note: MemoryManagement only takes effect in WinNT systems; otherwise, you can still use static methods under any system.

C#
public static MemoryManagement memory;
[STAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    #region Memory Management class
    // MemoryManagement only make effect in WinNT Systems, 
    // if your app is multi system use that.
    if (MemoryManagement.CanUseClass())
    {
        memory = new MemoryManagement();
        memory.Start();
    }
    else
    {
        memory = null;
    }
    #endregion

    Application.Run(new MainFrm());
}

ExceptionHandler class

Note: Please be sure you start before running your application. If you do not, please use the following code before running the application:

C#
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

appmanagement_exceptiondialog.png

This class can generate a .txt file with detailed error information. It also can create a dump (.dmp) file that can be debugged with a program like Visual Studio. Minidump Files (Windows) [^]

The default directory to store the logs is: APPEXEdir\Logs\AppErrors\. And, the filename format is: yyyy_MM_dd_HH_mm_ss.

C#
public static ExceptionHandler exceptionHandler;
[STAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    #region Exception Handler Class 
           (Automatic cath and log unhandled exceptions)
    // Automatic cath and log unhandled exceptions
    exceptionHandler = new ExceptionHandler();
    // Next two lines are optional
    exceptionHandler.PrefixText = 
      "This file represets an error cath on our program";
    exceptionHandler.SuffixText = 
         "Please fell free to send us that errors " + 
         "files via email: myapp@company.com";
    exceptionHandler.StartHandlingExceptions();
    #endregion

    Application.Run(new MainFrm());
}

Here is a sample of an unhandled exception log (MyTestApp__2010_02_15_18_35_29.txt).

[MyTestApp]
Date=15-02-2010 18:35:29
Application=MyTestApp 1.0.0.0
ExecutablePath=D:\caza\c++\ApplicationManagement\MyTestApp\
                        bin\Release\MyTestApp.exe
Company=MyTestApp

This file represets an error cath on our program

########################
##        Error       ##
########################
[Exception1]
Message=O valor não pode ser nulo.
StackTrace=   em MyTestApp.MainFrm.ButtonClick(Object sender, EventArgs e) 
   em D:\caza\c++\ApplicationManagement\MyTestApp\MainFrm.cs:line 115
   em System.Windows.Forms.Control.OnClick(EventArgs e)
   em System.Windows.Forms.Button.OnClick(EventArgs e)
   em System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   em System.Windows.Forms.Control.WmMouseUp(
                   Message& m, MouseButtons button, Int32 clicks)
   em System.Windows.Forms.Control.WndProc(Message& m)
   em System.Windows.Forms.ButtonBase.WndProc(Message& m)
   em System.Windows.Forms.Button.WndProc(Message& m)
   em System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   em System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   em System.Windows.Forms.NativeWindow.Callback(
                   IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
TargetSite=Void ButtonClick(System.Object, System.EventArgs)
Source=MyTestApp
HelpLink=


########################
## System Information ##
########################
[System]
OperativeSystem=Windows 7 x86
ProcessorCount=2


########################
##     Open Forms     ##
########################
[Forms]
Form1=MyTestApp.MainFrm, Text: ApplicationManagement Library Test


########################
## Loaded Assemblies  ##
########################
[mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]
   Location=C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorlib.dll

[MyTestApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]
   Location=D:\caza\c++\ApplicationManagement\
                 MyTestApp\bin\Release\MyTestApp.exe

[ApplicationManagement, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]
   Location=D:\caza\c++\ApplicationManagement\MyTestApp\
                 bin\Release\ApplicationManagement.dll

[System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
                                    PublicKeyToken=b77a5c561934e089]
   Location=C:\Windows\assembly\GAC_MSIL\System.Windows.Forms\
                  2.0.0.0__b77a5c561934e089\System.Windows.Forms.dll

[System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]
   Location=C:\Windows\assembly\GAC_MSIL\System\
                 2.0.0.0__b77a5c561934e089\System.dll

[System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a]
   Location=C:\Windows\assembly\GAC_MSIL\System.Drawing\
                  2.0.0.0__b03f5f7f11d50a3a\System.Drawing.dll

[System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]
   Location=C:\Windows\assembly\GAC_32\System.Data\
                  2.0.0.0__b77a5c561934e089\System.Data.dll

[mscorlib.resources, Version=2.0.0.0, Culture=pt, PublicKeyToken=b77a5c561934e089]
   Location=C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorlib.dll

Please fell free to send us that errors files via email: myapp@company.com

Profiling class

Note: It is always better to work directly with Profiling.ProfilingData. The Profiling class is a Profiling.ProfilingData Dictionary.

C#
public static Profiling profiling;
[STAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    #region Profiling Class
    // Our profiling will determinate the time taken by the app to initialize.
    profiling = new Profiling();
    Profiling.ProfilingData profilingData = profiling.Create("InitApp", true);
    #endregion

    // Wait 1.5s and see the output
    Thread.Sleep(1500);

    #region End started profile and show results
    profilingData.Stop();
    MessageBox.Show(
        string.Format(
            "Start Date: {0}\nEnd Date: {1}\nTime Taken: {2}ms", 
                 profilingData.StartDate,
                 profilingData.EndDate,
                 profilingData.TimeTaken.TotalMilliseconds
            ),
        "Our application initializes time");
    #endregion

    Application.Run(new MainFrm());
}

Another example

C#
/// <summary>
/// Do some job and returns the time it takes
/// </summary>
Profiling.ProfilingData MyFunction()
{
    // Note is better use a single class to all your profiling, but...
    // Initialize class, create a profiling and start it
    Profiling profiling = new Profiling("MyFunction", true);
    // Also can use:
    // Profiling.ProfilingData pData = profiling.Create("MyFunction");
    // if (pData == null)
    //     Console.WriteLine("Won't execute profiling, name already exists.");
    
    // Lets make some garbage
    for(int i = 1; i <= 10000; i++)
    {
        Random rand = new Random();
        Console.WriteLine(rand.Next(0, i));
    }
    
    // Function ends now let stop profiling and return the results.
    Profiling.ProfilingData pData = profiling.Get("MyFunction");
    // Note: you can check if pData is null if you not sure that exists
    pData.Stop(); // profiling.Stop("MyFunction"); also works
    return pData;
}

Profiling.ProfilingData pData = MyFunction();
if(pData.IsConcluded)
{
    Console.WriteLine("Total time to execute 'MyFunction': {0} ({1}ms)", 
                pData.TimeTaken, 
                pData.TimeTaken.TotalMilliseconds);
}
else
{
    Console.WriteLine("Developer doesn't write the function correct");
    Console.WriteLine("A ProfilingData must be Stopped, " + 
                      "before use EndDate and TimeTaken");
}

Note: To avoid duplicate keys and for fast coding, you can use Profiling.ProfilingData. Again, the Profiling class is optional and is just a wrapper of the Profiling.ProfilingData class that holds a Dictionary<string, Profiling.ProfilingData>. But, if you want to keep and store a profiling function to use later or to get results, it is better to use the Profiling class.

C#
Profiling.ProfilingData pData = new Profiling.ProfilingData();
pData.Start();

// Do your job here, time is counting!!!
// This way is more simple than use Profiling Class

pData.Stop();
/*
*
* pData.StartDate;
* pDate.EndDate;
* pDate.TimeTaken;
*
*/
// Discard variable
pData = null;

VistaSecurity class

C#
/// <summary>
/// Under Windows Vista, if current user is not an administrator, 
/// try elevate the permissions and exit from current application.
/// </summary>
if(!VistaSecurity.IsAdmin())
{
    if(VistaSecurity.RestartElevated(Application.ExecutablePath))
        Application.Exit();
}

Putting it all together

C#
#region Variables
public static Instance instance;
public static MemoryManagement memory;
public static Profiling profiling;
public static ExceptionHandler exceptionHandler;
#endregion
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    #region Profiling Class
    // Our profiling will determinate
    // the time taken by the app to initialize.
    profiling = new Profiling();
    Profiling.ProfilingData profilingData = 
       profiling.Create("InitApp", true);
    #endregion

    #region Instance Class (Make single instance app)
    // Check if that is a single instance, and name
    // mutex as: "{ProductName}Mutex"
    instance = new Instance(Application.ProductName);
    // instance is created but make sure you call next line:
    // First parameter is used to define mutex level
    // (Global or this session only)
    // Second parameter is used to check
    // processes equality after check mutex
    if (!instance.MakeSingleInstance(true, false))
    {
        Instance.ShowDuplicateInstanceDialogError();
        // Stop and quit App.
        return;
    }
    #endregion

    #region Memory Management class
    // MemoryManagement only make effect in WinNT Systems, 
    // if your app is multi system use that.
    if (MemoryManagement.CanUseClass())
    {
        memory = new MemoryManagement();
        memory.Start();
    }
    else
    {
        memory = null;
    }
    #endregion

    #region Exception Handler Class 
       (Automatic cath and log unhandled exceptions)
    // Automatic cath and log unhandled exceptions
    exceptionHandler = new ExceptionHandler();
    // Next two lines are optional
    exceptionHandler.PrefixText = 
      "This file represets an error cath on our program";
    exceptionHandler.SuffixText = 
      "Please fell free to send us that errors " + 
      "files via email: myapp@company.com";
    exceptionHandler.StartHandlingExceptions();
    #endregion

    #region End started profile and show results
    profilingData.Stop();
    MessageBox.Show(
        string.Format(
            "Start Date: {0}\nEnd Date: {1}\nTime Taken: {2}ms", 
                 profilingData.StartDate,
                 profilingData.EndDate,
                 profilingData.TimeTaken.TotalMilliseconds
            ),
        "Our application initializes time");
    #endregion
            
    Application.Run(new MainFrm());
    // Note: by calling 'Instance.Dispose' method will release mutex,
    // and app will be multi instance,
    // But still checks for process equality!
    // instance.Dispose();
}

Did your project use this library?

Please let me know if you are using my library in any of your projects. You can post your application name and link on discussions. This is also an incentive to me, knowing that people are using my libraries.

Donations

Writing libraries takes time and all my job is free. Donations are an incentive to me, and encourage me to make better libraries. Please consider making a donation: PayPal Donation[^].

Donate

You can alos donate using the SourceForge donations system:

Donate

Other homepages

History

Version 1.0

  • First release.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
Portugal Portugal
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionMemory management not good .... Pin
i0011-May-15 4:14
i0011-May-15 4:14 
GeneralNot Nearly Enough Description Pin
#realJSOP19-Feb-10 0:04
mve#realJSOP19-Feb-10 0:04 
GeneralRe: Not Nearly Enough Description Pin
Tiago Conceição19-Feb-10 4:53
Tiago Conceição19-Feb-10 4:53 
QuestionDonations? Pin
#realJSOP18-Feb-10 12:49
mve#realJSOP18-Feb-10 12:49 
AnswerRe: Donations? Pin
Tiago Conceição18-Feb-10 12:54
Tiago Conceição18-Feb-10 12:54 
GeneralRe: Donations? Pin
#realJSOP18-Feb-10 23:57
mve#realJSOP18-Feb-10 23:57 
GeneralA few suggestions Pin
The Man from U.N.C.L.E.18-Feb-10 8:18
The Man from U.N.C.L.E.18-Feb-10 8:18 
GeneralRe: A few suggestions Pin
Tiago Conceição18-Feb-10 12:38
Tiago Conceição18-Feb-10 12:38 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.