Home  |  FAQ  |  About  |  Contact  |  View Source   
 
SEARCH:
 
BROWSE:
    My Hood
Edit My Info
View Events
Read Tutorials
Training Modules
View Presentations
Download Tools
Scan News
Get Jobs
Message Forums
School Forums
Member Directory
   
CONTRIBUTE:
    Sign me up!
Post an Event
Submit Tutorials
Upload Tools
Link News
Post Jobs
   
   
Home >  Tutorials >  General Web Development >  Put Messenger Contacts on Your Site
Add to MyHood
   Put Messenger Contacts on Your Site   [ printer friendly ]
Stats
  Rating: 4.69 out of 5 by 16 users
  Submitted: 06/27/02
Heath Stewart ()

 
A thread here at DevHood started back on Monday, June 10, 2002, about getting the status of users in your MSN / Windows Messenger ("Messenger" from now on) list and displaying it on your web site. If you take a quick peek, there were a lot of questions about such a feat. As I researched the problem, I thought this would warrant a tutorial since it's a great way to enhance your site with Messenger. This tutorial will help you understand a little about the Messenger API's and will help you put a Messenger Buddy List on your site. Once finished, you should be able to understand the API's and extend the features, such as putting images next to a pre-existing list of users, perhaps from a database, for those that have Messenger and associated Passports.


What You'll Need

Before we get started, you'll want to download one or two things. Even though the web page uses client-side scripting to display (or harness) a Messenger contact list - which requires the end-user to have Messenger - you'll want Messenger too in order to test it (if you don't already).
  1. If you're not using MSN Messenger (pre-Windows XP) or Windows Messenger (Windows XP), you're missing out. Packed with features and a low footprint on your system, you may download it at .
  2. You'll also benefit from the Messenger API documents (CHM - or Compiled HTML Help - files), which you can get from . If you have a newer version of Messenger, you already have the automation interfaces registered on your system.


Introduction to the Messenger API's

The Messenger API is a very rich API (unlike AOL IM, who won't let anyone touch their precious protocol), but can be a little confusing. There is an automation interface for controlling the user interface, an automation interface for writing plugins, and an automation interface for services extensions (like the Exchange service plugin for Messenger). The one we're interested in today is the user interface automation library.

If you're using VC++, you'll want to take a look at the MessengerUI.chm file, especially the documentation for VC++ describing all the interfaces and UUIDs. If you're a VB programmer or .NET developer, you'll want to take a look at the section for VB. It describes everything using objects, enumerations, and still gives you the juicy stuff.


Writing a Simple Macro with the Messenger API's

For a simple test, I added a reference to the "Messenger API Type Library" in Excel's VBA environment, and made this quick little macro:
Public Sub GetBuddies()
    Dim msgr As New MessengerAPI.Messenger
    Dim groups As IMessengerGroups
    Dim group As IMessengerGroup
    Dim contacts As IMessengerContacts
    Dim contact As IMessengerContact
    Dim I As Integer
    Dim J As Integer
    
    I = 1
    J = 1
    
    Set groups = msgr.MyGroups
    For Each group In groups
        Sheet1.Cells(I, 1) = group.Name
        Set contacts = group.contacts
        J = I + 1
        For Each contact In contacts
            Sheet1.Cells(J, 2) = contact.FriendlyName
            Sheet1.Cells(J, 3) = contact.SigninName
            Sheet1.Cells(J, 4) = GetStatus(contact.Status)
            J = J + 1
        Next
        I = J
    Next
End Sub

Public Function GetStatus(I As Integer) As String
    Dim str As String
    Select Case I
        Case 1
            str = "Offline"
        Case 2
            str = "Online"
        Case 6
            str = "Invisible"
        Case 10
            str = "Busy"
        Case 14
            str = "Be Right Back"
        Case 18
            str = "Idle"
        Case 34
            str = "Away"
        Case 50
            str = "On the Phone"
        Case 66
            str = "Out to Lunch"
        Case Else
            str = "Unknown"
    End Select
    
    GetStatus = str
End Function

With command-completion, this was a breeze. If you try taking the same approach with a scripting language like JScript (Microsoft's JavaScript) or VBScript, you'll find that it doesn't work. Even if you use "var msgr = new ActiveXObject(...)" for JScript or "Set msgr = CreateObject(...)" for VBScript, you'll get a scripting error from Internet Explorer (IE) that states it can't create the automation object.

So what gives? Beats me. I use the delightful and extremely helpful OLEView.exe utility that comes with every free and commercial development environment Microsoft distributes to look at all the automation interfaces, coclasses, and type library information and wound up just scratching my head. While Visual Basic can use the ProgID to create an instance of the coclass (class that implements the interface to which you think you're talking) and Visual C++ can use the CLSID, you can use neither in your scripting environment because the ProgIDs don't actually create objects in that instance. If you can figure this one out, by all means email me!

There is hope, however. If you dig around in Hotmail's source, you'll find a reference to a JavaScript file (.js) that contains all the goodies. Microsoft uses the infamous <object/> tag to instantiate the object.


Writing a Simple Script with the Messenger API's

So, lets create a simple HTML page with some basic functionality to display your name:

<html>
    <head>
        <title>Messenger Contact List</title>
        <script language="jscript" event="onload" for="window">
        if ("undefined" != typeof(msgrUI))
            document.all.welcome.InnerText = msgrUI.MyFriendlyName
                + "'s Messenger Contacts";
        </script>
    </head>
    <body background="white" text="black">
        <p><b id="welcome">Messenger Buddies</b></p>
        <p id="msgrList"><ol id="msgrBuds"/></p>
        <object classid="clsid:B69003B3-C55E-4B48-836C-BC5946FC3B28"
            id="msgrUI" width="1" height="1" style="display: none;"/>
    </body>
</html>

When you open this page, you get a scripting error that "MyFriendlyName" isn't supported. You'll notice it's in the docs for the MessengerAPI.Messenger coclass that you instantiate (that's the CLSID for that ProgID in the <object/> tag). If you try the VC++ method of prepending "get_" to the property like "get_MyFriendlyName", you don't get an error but "undefined" is returned. In fact, as you'll find, "undefined" is returned for almost everything, including "MyContacts" and "MyGroups". Even though these properties are available in compiled languages such as VC++ and VB, they are not available in scripting languages. I'm sure this is by design, it's just not documented.

Don't give up hope, yet! Where there's a will, there's a way. Digging around in Hotmail's source a little more, I noticed a different set of CLSID's that they were using. Unfortunately, the one CLSID they were using was not documented in the CHM files I had you download, which was for the Messenger.MsgrObject ProgID. OLEView.exe showed me the light once again, however, and I ended up using the CLSID's for both the Messenger.MsgrObject and Messenger.UIAutomation objects, the latter of which implements all the things that Visual Basic could use so easily.


Writing a Advanced Script using the Messenger API's

We will finally create a page that works. We will use two objects, one of which is undocumented, but is described thoroughly by OLEView.exe if you understand IDL (the "COM language").

We can't rely on the Messenger.UIAutomation object since it apparently returns "undefined" when hosted in IE (or perhaps any scripting language). The other object (Messenger.MsgrObject) we will use does the trick, but it's by no means as elegant as Messenger.UIAutomation, which provides more functionality that actually does work in a scripting environment.

What follows is the final HTML for this tutorial, and I'll explain certain sections briefly below it:

<html>
    <head>
        <title>Messenger Contact List</title>
        <script language="jscript">
        <!--
function getStatus(state) { switch (state) { case 1: return "Offline"; case 2: return "Online"; case 6: return "Invisible"; case 10: return "Busy"; case 14: return "Be Right Back"; case 18: return "Idle"; case 34: return "Away"; case 50: return "On the Phone"; case 66: return "Out to Lunch"; } return "Unknown"; } function setLink(user) { if ("undefined" == typeof(msgrUI)) return name.FriendlyName; return str = "<a href=\"#\" onclick=\"instantMessage('" + user.EmailAddress + "');\">" + user.FriendlyName + "</a>"; } function instantMessage(email) { if ("undefined" != typeof(msgrUI)) msgrUI.InstantMessage(email); } function signIn() { if ("undefined" != typeof(msgrUI)) { msgrUI.AutoSignin(); window.setTimeout(location.reload, 2000); } } function writeListError() { document.all.msgrList.innerHTML = "<span style=\"color: red;\">Unable " + "to retrieve your Messenger buddy list. Make sure you are <a " + "href=\"#\" onclick=\"signIn();\">signed-in</a>.</span>"; } //--> </script> <script language="jscript" event="onload" for="window"> <!--
if ("undefined" == typeof(msgr) || msgr.LocalState == 1) { writeListError(); return; } var me = msgr.LocalFriendlyName; if ("undefined" != typeof(me)) document.all.welcome.innerText = me + "'s Messenger Buddies"; var users = msgr.List(0); if ("undefined" == typeof(users)) { writeListError(); return; } for (i=0; i<users.count; i++) { var user = users.Item(i); document.all.msgrBuds.innerHTML = document.all.msgrBuds.innerHTML + "<li>" + setLink(user) + " (" + user.EmailAddress + ") - " + getStatus(user.State); } //--> </script> </head> <body background="white" text="black"> <p><b id="welcome">Messenger Contacts</b></p> <p id="msgrList"><ol id="msgrBuds"></ol></p> <object classid="clsid:F3A614DC-ABE0-11d2-A441-00C04F795683" id="msgr" width="1" height="1" style="display: none;"/> <object classid="clsid:B69003B3-C55E-4B48-836C-BC5946FC3B28" id="msgrUI" width="1" height="1" style="display: none;"/> </body> </html>

As you can see, we now use two <object/> tags: "msgr" is the Messenger.MsgrObject object, and "msgrUI" is the Messenger.UIAutomation object. Remember, if you try to instantiate these using "new ActiveXObject()" or "CreateObject()", the automation interface won't be created. Also, don't try this server-side, it will just use your Messenger contact list - if it even works (the documentation warns against this, too).

You could add some browser detection code in there to keep Mozilla / Netscape from trying to do something it can't, but that should be taken care of by specifying the language as "JScript" instead of "JavaScript" (last time I checked, at least with 4.x).

The <script/> block that is attached to the "window.onload" event displays the list, or an error message depending on the state of you or your clients' Messenger. The regular <script/> block contains helper functions and event handlers used throughout the page.

In the "window.onload()" event handler, we use the "msgr" object and simply get your friendly name and the list of users. If you used "msgrUI", this wouldn't work since "undefined" would be return for each. We then iterate through the list of users and display HTML appropriate for each one. In that event handler - at the point we add HTML to output - we call another function, "setLink()". This method outputs an "a.onclick" event in the output HTML. When the user clicks the link for a name, it calls the "instantMessage()" function.

The "instantMessage()" function uses the other object, "msgrUI". It contains a method (which actually works) that displays the Instant Messaging (chat) window with the specified user as the recipient.

We also use the "AutoSignin()" method of the "msgrUI" object in the "signIn()" method we defined because it doesn't require user credentials (username and password). It tried to log in with the last-known credentials, just like Messenger does when it starts-up. The "msgr" object does have a "Login()" method, but it requires a username and password, which you must prompt for and handle on your own. There could also be security hazards depending on your environment as well. If the "msgrUI" object can't automatically signin, it will prompt for credentials on its own, which is probably a more secure method than JScript or VBScript could provide.

The rest of the code is pretty basic and self-explanitory, so I won't explain those.


Extending Functionality: What Else You can Do

This script just scratched the surface of what you can do. As you can see from Hotmail, they display an icon for each user that is in your list and that is online. If you wanted, you can create a bunch of icons (or tear them from the Messenger executable) to display next to users instead of their status as text, which is what I did in my latter sample. Just output "<img ...>" with the proper information instead of "Offline", "Online", etc.

If you're displaying a bunch of users with email addresses from a database already and you would like to add an icon next to each as described above, you could write a method that would search for the email address in the clients' contact list and then place an icon next to each, such as the following:

<script language="JScript" event="onload" for="window">
<!--
if ("undefined" == typeof(msgr)) return; var users = msgr.List(0); if ("undefined" == typeof(users)) return; for (i=0; i<users.count; i++) { var user = users.Item(i); var cells = document.all[user.EmailAddress]; for (j=0; j<cells.length; j++) cells[j].innerHTML = "<a href=\"#\" onclick=\"instantMessage('" + user.EmailAddress + "');\"><img src=\"/images/" + user.Status + ".gif" border=\"0\"></a>" + cells[j].innerHTML; } //--> </script> <table ...> <tr> <td id="">...</td> </tr> <tr> <td id="">...</td> </tr> <tr> <td id="">...</td> </tr> ... </table>

Explore the API and find out all the things you can do with Messenger to leverage greater functionality for your clients.


Summary

The Messenger API is an extensive API for of many objects, methods, properties, and events you can use in your compiled and interpreted applications. You have to treat them differently, however. Scripting languages don't work with the same ProgIDs that you may use in VC++, VB, or even .NET. With a little patience, OLEView.exe, and a little scripting experience, you can greatly enhance your site with Messenger!

Return to Browsing Tutorials

Email this Tutorial to a Friend

Rate this Content:  
low quality  1 2 3 4 5  high quality

Reader's Comments Post a Comment
 
Oh boy, this sucks. I guess I should've tried this with a file on our Intranet / Internet. The names and email addresses only show up when accessed locally, i.e. "My Computer" security zone. otherwise, you can only find out the status of whether or not a user is online. So, "user.Status" still works and you can use that part of it like Hotmail.

I apologize for getting anyone's hopes up. I still hope you found it to be a good tutorial and that it will at least help you put contact status for users on your site, such as here at DevHood (hint hint).
-- Heath Stewart, June 27, 2002
 
I also wanted to mention that the original point of the thread at the top was to display a user's status just like in Hotmail. You can still do that. users.Item() can take a string representing the email address, like so:

var user = users.Item("");

If the email address is in your contact list, user is an object; otherwise, user is null. If user is not null, you can still get their status with user.Status.

See the original thread for more details.
-- Heath Stewart, June 27, 2002
 
Excellent work, especially for doing it so quickly.
5 Stars ***** I'd give you more stars for this one if I could ;-)
-- Ammon Beckstrom, June 27, 2002
 
very good job heath. i just have a quick question for you.

[cs]
function getStatus(state)
{
switch (state)
{
case 1: return "Offline";
case 2: return "Online";
case 6: return "Invisible";
case 10: return "Busy";
case 14: return "Be Right Back";
case 18: return "Idle";
case 34: return "Away";
case 50: return "On the Phone";
case 66: return "Out to Lunch";
}

return "Unknown";
}
[/cs]

on your cases...where did you come up with the numbers? just very curious. were they randomly choosen, or do they come from somewhere?
-- J J, June 28, 2002
 
Is there a messenger API link where you can make your own clients and see the protocols for sending and retreiving?
-- Victor Vuong, June 28, 2002
 
This is a great tutorial, even though it only works locally. It is very well written and is more than a small tutorial that is mostly copied from some other source, as some of the tutorials seem to be. A good addition to DevHood!
-- Philip Lanier, June 28, 2002
 
Justing, the values are taken from the header files for the Messenger API, which you can download indirectly by a link I gave on this site (toward the top of the tutorial). That'll take you to a page on MSDN, which is where you can download the .lib, .h, and .chm (compiled HTML Help) files. As I stated in the tutorial, if you have Messenger installed, you already have the automation libraries installed so you can start programming with it right away.

As far as protocol documentation, I don't believe there is anything as of yet. These automation libraries are meant for automating and extending Messenger. In my example code, I use the libraries to enumerate and display the status of my contacts, as well as bring-up the Instant Messege window when a user clicks on a name. There is much more you can do, but nothing low-level like protocols.
-- Heath Stewart, July 01, 2002
 
Pretty neat... Definitely adds functionality to a website...
-- David Harris, July 05, 2002
 
Well written tutorial
THanks
-- Yusno Yunos, July 09, 2002
 
Sweet tutorial. I really wish I knew more people who used Messenger so I could implement this. Despite the fact that Messenger is quite a bit better than some of the alternatives, I don't know anyone that uses it outside of some of my CS contacts. Until the ladies drop AIM, I'll stick with that.
-- Adam Summers, July 17, 2002
 
Hello,

I wonder if anyone had programmed with the Messenger API in Visual C++ before.
I am programming with the Messenger API
with MSN instant messenger Version 4.6. Basically, I am
creating an dialog to call some Messenger APIs.

Here is the major part of my sample test program:

LONG & count = 0;
CComPtr<IMessenger> pIMessenger;
CComPtr<IMessengerContacts> pIMessengerContacts;
.......

hr = pIMessenger->Signin(NULL, NULL, NULL);

........ // sign in successful

hr = pIMessenger->get_MyContacts(&pIMessengerContacts);
hr = pIMessengerContacts->get_Count(&count);



There are two problems encountered.

1) Referring to the Messenger API help (messengerua.chm),
in the section of "IMessengerContacts Interface", we
should be about to call get_MyContacts without casting the
&IMessengerContacts to IDispatch** pointer, but it doesn't
work in Visual C++ when compiling. So I need to
explicitly cast the &pIMessengerContacts to IDispatch** to
make it compilable.

i.e. hr = pIMessenger->get_MyContacts((IDispatch**)
&pIMessengerContacts);


2) When it runs, there's an Access Violation problem, when
it call the line "hr = pIMessengerContacts->get_Count
(&count);" to the the number of contact in the Messenger
Object. I had debug it and it gave me message like
"Unhandled exception in WinMsg.exe:0x0000005: Access
Violation". I tried in different programs with the same
procedure and the message is always the same.

I have tried the other interfaces like IMessenger2 and
IMessengerContacts and it stll have the same problem for
Access Violation.

Does anyone got idea how to solve the problem?
Does anyone got any sample code with the Messenger API?

Regards,
-- Kenric Li, August 13, 2002
 
I'm not sure about the first problem since I haven't looked a lot into the automation APIs, but the second is obviously because your pIMessengerContacts reference is null, or that count is null and getting its address would cause an access violation.
-- Heath Stewart, August 29, 2002
 
Is there a way to do this without requiring the user to use the actual MSN Messenger client (ie. Trillian, etc.)?

"If you're not using MSN Messenger (pre-Windows XP) or Windows Messenger (Windows XP), you're missing out. Packed with features and a low footprint on your system, you may download it at http://messenger.msn.com/." <-- I do believe it, however by the third or fourth client, it's becoming very cumbersome on the system, and as most of the people that I have on my contact list do not use the actual messengers, but combinations (ie. Trillian) thereof, it would be nice to have a script that actually runs serverside.
-- Matthew Hildebrand, September 22, 2002
 
Matt, having a script that runs server-side really does nothing for your. It would show *you're* contacts' availability, not the person using the page. I doubt that IM's like Trillian are implementing the COM servers that make this tutorial work, so I doubt this would work for you. All these scripts above the COM objects exposed by the Messenger APIs. If Trillian has merely implemented the protocol, they wouldn't have exposed such COM objects.
-- Heath Stewart, October 01, 2002
 
Hi guys. I notice that is working only localy, but it must be a way to make it work. I mean it works on Hotmail!?!?!


anybody have an Idea??
-- Martin Belanger, December 03, 2002
 
I guess that whene doing it on Hotmail you are already singed in using your "passport" account.

On a custom web-server that has passport sign-in, i guess it would be possible to somehow utilize Messenger users context.

// John
-- John Savage, October 07, 2003
 
I did a cut and paste straight from the article and it does not work. I am running Windows Messenger 4.7..

What the?
-- Ron Antinori, November 01, 2003
 
Here is some code that works but I can not access properties about the contact like FriendlyName. Any ideas?

<HTML>
<HEAD>
<TITLE>Embedding MSN Messenger Test</TITLE>

CODEBASE="#Version=2,0,0,83"
CODETYPE="application/x-oleobject" ID="oMessenger" WIDTH="0"
HEIGHT="0" OnUserStateChanged="alert();" >
</OBJECT>

<STYLE>
BODY
{
FONT-FAMILY: Verdana, Arial, Helvetica;
FONT-SIZE: 8pt;
}
INPUT
{
FONT-FAMILY: Verdana, Arial, Helvetica;
FONT-SIZE: 8pt;
}
.clsHeading
{
FONT-WEIGHT: bolder;
FONT-SIZE: 10pt;
}
.clsContact
{
PADDING: 2px;
CURSOR: hand;
}
</STYLE>
</HEAD>

<BODY onLoad="body_onLoad();">

<SCRIPT LANGUAGE="JScript">

// Here are the definitions for the Messenger enumerated values we use

var MSTATE_OFFLINE = 1;
var MSTATE_ONLINE = 2;
var MSTATE_BUSY = 10;
var MSTATE_BE_RIGHT_BACK = 14;
var MSTATE_IDLE = 18;
var MSTATE_AWAY = 34;

function body_onLoad()
{

if ("undefined" != typeof(oMessenger) && null != oMessenger.object)
{
// If so, let's check to see if we're online and (if so) populate our contacts UI
if (oMessenger.MyStatus == MSTATE_ONLINE)
{
populateContacts();
}
else if (oMessenger.MyStatus == MSTATE_OFFLINE)
{
btnLogon.disabled = false;
}
}
else
{
// Uh, oh - the controls didn't get instantiated correctly;
// the user probably needs to install Messenger

alert("You need to install the latest version of MSN Messenger!\nGo to http://messenger.msn.com right now!");
}
}

function populateContacts()
{
var oContacts = oMessenger.MyContacts;
var oContact;
var i;

// To populate our contact list, we're going to iterate throught the
// default list collection, check the state of each contact,
// and add a DIV with
-- Ron Antinori, November 01, 2003
 
1.- It doesn´t work if you use IE6 and and WinXP. The code its wrong but you could take as a reference.
2.- I sugest use UIAutomation object just for any reason its impossible get the FriendlyName:

Conclusion: Doesnt exist suport anymore to get Messenger Contact List with Win Messenger 4.7. So We have to wait to release MSN MEssenger API:

If this code could help you guys (Dont get contacts' FriendlyName )
<HTML>
<script language= "javascript">
function getStatus(state)
{
switch (state)
{
case 1: return "Offline";
case 2: return "Online";
case 6: return "Invisible";
case 10: return "Busy";
case 14: return "Be Right Back";
case 18: return "Idle";
case 34: return "Away";
case 50: return "On the Phone";
case 66: return "Out to Lunch";
}
return "Unknown";
}

function setLink(user)
{
if ("undefined" == typeof(user))
return user.FriendlyName;
return str = "
" + user.FriendlyName + "";}

function instantMessage(email)
{
var msgrUI = new ActiveXObject("Messenger.UIAutomation");
if ("undefined" != typeof(msgrUI))
{
msgrUI.InstantMessage(email);
delete msgrUI;
}
}

function RenderContactList()
{
var MsgrObj = new ActiveXObject("Messenger.MsgrObject");
var me = MsgrObj.LocalFriendlyName;
var msgrUI = new ActiveXObject("Messenger.UIAutomation.1");
var list = msgrUI.MyContacts;
if ("undefined" != typeof(list))
{
if (list.count > 0)
{
renderText = ""; renderText = renderText + ""; for (var i=0; i < list.count; i++)
{
//renderText = renderText + "" renderText = renderText + "
" + me + "Contact List
" + list.Count + "
" + getStatus(list.Item(i).Status) +" " + setLink(list.Item(i)) + "
" + i + " " + getStatus(lis
-- Charly GTz, November 18, 2003
 
Copyright © 2001 DevHood® All Rights Reserved