jump to navigation

AfxGetMainWnd in C# June 27, 2007

Posted by codinglifestyle in C#, CodeProject, Winform.
Tags: , , , ,
trackback

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 a 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, lets 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 to 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);

Advertisements

Comments»

No comments yet — be the first.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: