Click here to Skip to main content
15,884,099 members
Articles / Desktop Programming / Windows Forms

AfxGetMainWnd in C#

Rate me:
Please Sign up or sign in to vote.
4.67/5 (3 votes)
2 Apr 2011CPOL2 min read 16.6K   5   1
AfxGetMainWnd in C#

Back in the heady days of MFC, men were men; toiling away in C++ and writing hundreds of lines to do things which are now ludicrously simple. However, we had a trick up our sleeves which doesn’t exist in today’s plastic fantastic .NET:

AfxGetMainWnd() and AfxGetApp() were two fantastic macros we could exploit from nearly anywhere in our app to get a pointer to our main window or application, respectively.

Yesterday, I was writing a quick client/server app. The server was a WinForm tray application whose main form consists of a simple list to display status messages. I wanted the thread listening for incoming traffic to update the status list. I really missed AfxGetMainWnd() as I had a hard time finding a way to get a handle to my main window. Because this was a tray app, which starts minimized, I was unable to use _FormMain.ActiveForm or Process.GetCurrentProcess().MainWindowHandle. In fact, MainWindowHandle was interesting as when I double-clicked the tray icon (opening the main window), the handle became valid and I could use it. But the minute I minimized the window back to the tray, the handle became null again. So I was stuck with no reliable way of getting a handle to talk to my main window.

There may have been a better way, but this was a simple project and I wanted to move on quick. I changed my main window to be a singleton, hiding the constructor and exposing an Instance variable which returned the one instance of the form.

To do this, let's look at the constructor:

C#
private _FormMain()
{
InitializeComponent();
}
 
private static _FormMain m_Form = null;
public static _FormMain Instance
{
get
{
if (m_Form == null)
m_Form = new _FormMain();
return m_Form;
}
}

We then need to make a simple change in program.cs:

C#
//Application.Run(new _FormMain());
Application.Run(_FormMain.Instance);

And lastly, to handle calls from another thread:

C#
// This delegate enables asynchronous calls from other threads
delegate void AddMessageCallback(string sMsg, Color c);
 
public void AddMessage(string sMsg, Color c)
{
if (_ListStatus.InvokeRequired)
{
AddMessageCallback amc = new AddMessageCallback(AddMessage);
this.Invoke(amc, new object[] { sMsg, c });
}
else
{
ListViewItem lvi = new ListViewItem(sMsg);
lvi.ForeColor = c;
_ListStatus.Items.Add(lvi);
_ListStatus.Refresh();
}
}

Note the delegate/invoke code used in AddMessage is straight from MSDN’s How to make thread-safe calls to Winform controls.

This way, I was able to simply call the following from anywhere in my code:

C#
_FormMain.Instance.AddMessage("Client has connected…", Color.Green);

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Avaya Inc.
Ireland Ireland
Formerly a C++ client developer, nowadays I'm all about C# and ASP.NET. Over the years I have mastered some and played with many aspects of .NET.

Follow my blog as I catalogue the more arcane problems I encounter and their solutions at CodingLifestyle.com

Comments and Discussions

 
Generalthoughts [modified] Pin
HaBiX4-Apr-11 21:37
HaBiX4-Apr-11 21:37 

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.