Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

AfxGetMainWnd in C#

0.00/5 (No votes)
2 Apr 2011 2  
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:

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:

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

And lastly, to handle calls from another thread:

// 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:

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

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here