Introduction
I have long been a fan of code project and finally I have something to
share. Browsing the Microsoft site I came across the
documentation
for MSN Messenger so
minutes later I had fired up Visual Studio and started to investigate the possibility's.
Having looked at what is available I decided to make this add-in for VS.NET
Referencing Messenger
I am not much a person for writing so I will let the code do the talking.
The first thing you need to do is reference the Messenger ActiveX normally this can be
done just by adding a reference to the COM object but in this case because of a bug it
does not work. You actually need to rebuild the assembly created from TLBImp after
changing a couple of methods. This in one of the things that makes the project more interesting.
- Use Tlbimp.exe to generate a Messenger interop assembly
(this is located in C:\Program Files\Messenger by default):
tlbimp msmgs.exe /out:Messenger.dll
- Disassemble the interop assembly, and then save it as an IL file:
ildasm /text Messenger.dll /out:Messenger.il
- Open the IL file in any text editor, and then change the following line
(mark the class as public instead of private):
.class private auto ansi sealed DMsgrObjectEvents_SinkHelper
to
.class public auto ansi sealed DMsgrObjectEvents_SinkHelper
and just below that
.class private auto ansi sealed DMsgrObjectEvents_EventProvider
to
.class public auto ansi sealed DMsgrObjectEvents_EventProvider
-
Compile the IL file:
ilasm /dll Messenger.il
-
This DLL is now ready to be referenced later in our project.
Creating an Addin
Visual Studio has always been great for generating code from a wizard one
less thing for me to do. If you just choose New Project\Other Projects\Extensibility
Projects\Visual Studio .NET add-in and run through the wizard. I will assume everyone
here is sensible enough to configure these but here is a brief description:
- Create an add-in using C# (default)
- This relates to the environments you want to use the add-in up to you really
but I chose both
- Give your add-in a nice name
- Options
- Add a button to the tools menu at present this will not do anything
except load the add-in
- The next two options relate to when you want the add-in to load
- Do you want all users to use the add-in
- Help about options (maybe I should have put something here)
- On the summary page just click finish
Creating a Tool Window
Now we have our add-in how do we get it to be a tool window? This is an area I
think could be improved both in the IDE and MSDN as it took a fair amount of searching
to find out what i needed to do.
In the end a
Tool
Window Sample was located. The sample is from Microsoft and shows how to create a
Tool Window in .NET. If you just build the VSUserControlHost
ActiveX control and I will try and
explain what you need to do in the add-in we have.
- Add a reference to the ActiveX control created by building
VSUserControlHost
- Locate the Connect.cs file in the Messenger add-in and add the following code
to the end of the
OnConnection
method
object objTemp = null;
string guidstr = "{716238D9-8ED3-48aa-A7A0-A73CA6FDF1EF}";
EnvDTE.Window windowToolWindow =
applicationObject.Windows.CreateToolWindow (
addInInstance,
"VSUserControlHost.VSUserControlHostCtl",
"Messenger", guidstr, ref objTemp);
windowToolWindow.Visible = true;
VSUserControlHostLib.IVSUserControlHostCtl objControl =
(VSUserControlHostLib.IVSUserControlHostCtl)objTemp;
objControl.HostUserControl(
System.Reflection.Assembly.GetExecutingAssembly().Location,
"MsgAddin.HostUserControl");
The guidstr
in the above code was generated using guidgen.exe and I would
advise for your future add-ins you use this also. The only other part of this code that
can differ is the last parameter to HostUserControl()
which is the full
class name for your Tool Window in our case "MsgrAddin.HostUserControl"
.
The Messenger Code
Right, now for the Messenger window itself. I hope everyone here already knows how to create
a windows form and find their way round the source code because the only difference here is that
this will be a User Control. A user control can be created with by adding a new item to the
Messenger add-in project and choosing a user control. From here on it is exactly the same as working
with a windows form, which I will get to in a moment. Once you have added the controls and events
for the Send button and the user ListView
we can now add the code. There are a couple of members
in the control class that we need:
Initialization
Messenger.MsgrObjectClass msg;
Messenger.IMsgrUser CurrentUser;
Messenger.IMsgrUsers Users;
We set these up in the constructor as follows:
msg = new Messenger.MsgrObjectClass();
try
{
if(msg.LocalState == Messenger.MSTATE.MSTATE_OFFLINE)
{
Messenger.MessengerAppClass app =
new Messenger.MessengerAppClass();
app.IMessengerApp_LaunchLogonUI();
while(msg.LocalState != Messenger.MSTATE.MSTATE_ONLINE)
System.Threading.Thread.Sleep(5000);
}
Users = msg.get_List(Messenger.MLIST.MLIST_CONTACT);
for(int i = 0; i < Users.Count; i++)
{
Messenger.IMsgrUser u = Users.Item(i);
userList.Items.Add(new ListViewItem(u.FriendlyName, GetStateImage(u.State)));
}
msg.OnTextReceived +=
new Messenger.DMsgrObjectEvents_OnTextReceivedEventHandler
(this.OnTextRecieved);
msg.OnUserStateChanged += new
Messenger.DMsgrObjectEvents_OnUserStateChangedEventHandler
(this.OnUserStateChanged);
}
catch(Exception e)
{
MessageBox.Show(e.Message);
}
Receiving Messages
Having now set all our objects we just need the code for the different events
OnTextRecieved()
is called whenever Messenger receives a message. The only time we are
interested is when the content type is text.
private void OnTextRecieved(Messenger.IMsgrIMSession s,
Messenger.IMsgrUser u, string header, string text,
ref bool default)
{
if(header.IndexOf("Content-Type: text/plain") != -1 &&
u.FriendlyName != "Hotmail")
{
messageWindow.AppendText(u.FriendlyName + ": " + text + "\r\n");
CurrentUser = u;
default = false;
}
}
When we receive a text message this is appended to the edit control (anyone want to enhance
the text control to support fonts, hyperlinks, smileys etc). You will notice that the
default
parameter is changed to false
this causes Messenger not to show a chat window itself.
Sending Messages
As the code runs the current contact changes depending on what you have selected in the user list
and the last message received so be aware of who you are sending your message to. To send a message
to the current contact a message can be typed into the edit box and clicking send with this code:
private static string header =
"MIME-Version: 1.0\r\nContent-Type: text/plain;" +
"charset=UTF-8\r\nX-MMS-IM-Format: " +
"FN=MS%20Shell%20Dlg; EF=; CO=0; CS=0; PF=0\r\n\r\n";
private void send_Click(object sender, System.EventArgs e)
{
CurrentUser.SendText(header, this.sendText.Text,
Messenger.MMSGTYPE.MMSGTYPE_ALL_RESULTS);
messageWindow.AppendText("You say: " + sendText.Text + "\r\n");
}
On sending the message it is appended to the message window. Messenger sends a header with the
message a bit of debugging supplied the header
string shown above this is so messenger know
what to do with the message at the other end just like we do in the OnTextRecieved()
above.
Updating contacts status
As with the main messenger client I show the status of users with different icons in the
ListView
. This status is first updated when the constructor is called but as this status
changes the OnUserStatusChanged()
event is called using this event the icons can be updated:
private void OnUserStateChanged(Messenger.IMsgrUser user,
Messenger.MSTATE state, ref bool default)
{
for(int i = 0; i < Users.Count; i++)
{
if(user == Users.Item(i))
{
ListViewItem item = userList.Items[i];
item.ImageIndex = GetStateImage(user.State);
}
}
}
The state
parameter that is passed holds the previous state so it is
necessary to find the user in our list of Users
in order to find their
new status. The
ListView
is then updated with the new status.
Summary
I hope this has been of some interest to somebody. Now that you know how to use a small
part of the Messenger functionality, have a play with the other things that are
available. I think there are many other things that could be done with Messenger and I hope
someone comes up with other articles with these ideas. On a more serious note having seen
how easy it is to create add-ins for VS.NET you can now produce some more productive
add-ins.
Disclaimer
It works on my machine