Back to School Sail

As of December 2011, this topic has been archived. As a result, it is no longer actively maintained. For more information, see Archived Content. For information, recommendations, and guidance regarding the current version of Internet Explorer, see Internet Explorer Developer Center.

Jay Allen, Mark Davis, Heidi Housten, and Dan Mohr
Microsoft Corporation

September 3, 2001

Summer is over here in the northern hemisphere. Kids are back in school. The hints of autumn approaching have infected the team with that school-starting feeling. When will we ever grow up?! We have broken Jay in, as has his daughter, so autumn should be smooth sailing here at Web Team Talking. You can look forward to content, content, and more content.

Spitballs and new haircuts aside, this month we delve into MSN® Messenger, some fancy JavaScript functionality, and updating XML data on the server, as well as a collection of shorts to keep you busy.

Contents

Instant Gratification—embedding the messenger
Send It Back—updating the server XML
Sorting Dates—non-alphabetical file listings

Web Team in Short

Instant Gratification

Dear Web Team:

How can I embed the MSN Instant Messenger like on msn.com?

Thanks,
Joshua Carroll

The Web Team replies:

Ah, what better monument to our growing need for better-than-instant gratification than MSN Messenger. The IM features found on http://www.msn.com are implemented using two Microsoft ActiveX® controls that provide the Messenger functionality along with some script that provides the DHTML user interface. Let's say for the sake of brevity that we want to add a little sidebar to our intranet home page that lists a user's contacts (and their connection states) if that user is logged on, and provides a logon button if they're not. A sample is provided below, but for those who are wondering if we had to consult an oracle (note the lower case "o") to divine this info, here is a quick overview of the techniques involved.

Because there's no documentation available for these controls, we'll need to use some detective work to accomplish our goal. First, we can check out the code that msn.com uses to get some hints. This is not for the faint of heart, but by slogging through it we can get a general idea of what the two controls do, and of how we might write our own code. The second (and far more helpful) tool we can use is OLE View. OLE View is a utility that ships with Microsoft Visual Studio® and it, among other talents, can parse and display type information for COM objects.

So, we fired up OLE View, found the two controls (whose friendly names are MSN Messenger Application and MSN Messenger Object), right-clicked on them, and chose View type information. This view shows the various interfaces and enumerations that are used by the object. Any interfaces labeled as dispinterfaces should be available to script-based callers, so we rolled up our sleeves and started coding!

The first thing the code needs to do (after ensuring that the controls get instantiated correctly) is to determine whether or not the user is online. This is done by checking the LocalState property of the Messenger Object. This property returns a value from the MSTATE enumeration whose definitions we've partly included in our code. If the user is not online, we'll enable our logon button that calls the Messenger Application's LaunchLogonUI method. If the user is online, we need to populate our DIV with all of the user's contacts. To accomplish this, we iterate through each contact in the default list (List(0)) and retrieve both their FriendlyName and the MSTATE value describing their current state, and then create a new DIV containing this information.

Because we want to allow the user to send a message to any of the contacts in the list by clicking on them, we programmatically attach an onclick event handler to the new DIV. That event handler function (sendMessage) is basically a wrapper around the Messenger Application's LaunchIMUI method. Because LaunchIMUI takes the target contact as a parameter, we need to be able to determine which contact in the Messenger Object's default list corresponds to the DIV that was clicked on. This is an ideal use for an expando property. We attach the contact's index in the default list to the new DIV element we created to represent it. That way, the onclick handler can retrieve this index and then grab the correct contact from the Messenger Object's list and pass it to LaunchIMUI.

The bonus feature that is included in this sample is the ability to handle log offs and log ons after the page is loaded. This is done by handling the OnLocalStateChangeResult event fired by the Messenger Object. This event (not too shockingly) fires when our LocalState property changes. So, in response, we just check to see if we've gone offline (in which case we empty our UI list of contacts) or gone online (in which case we call populateContacts after a brief setTimeout that ensures everything syncs up properly). And because the ActiveX controls are tied to the running instance of stand-alone Messenger, our page also updates in response to events triggered by it as well.

And to our readers in Geekland who are shouting "enough babble, show me the code!", here ya go.

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

   <OBJECT CLASSID="clsid:F3A614DC-ABE0-11d2-A441-00C04F795683" 
   CODEBASE="#Version=2,0,0,83"
      CODETYPE="application/x-oleobject" ID="oMsgrObj" WIDTH="0" 
      HEIGHT="0" OnUserStateChanged="alert();">
   </OBJECT>
   <OBJECT CLASSID="clsid:FB7199AB-79BF-11d2-8D94-0000F875C541" 
   CODETYPE="application/x-oleobject"
      ID="oMsgrApp" WIDTH="0" HEIGHT="0">
   </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()
{
   // First, we need to make sure that the Messenger controls got instantiated correctly

   if ("undefined" != typeof(oMsgrObj) && null != oMsgrObj.object && "undefined" 
   != typeof(oMsgrApp) && null != oMsgrApp.object)
   {
      // If so, let's check to see if we're online and (if so) populate our contacts UI

      if (oMsgrObj.LocalState == MSTATE_ONLINE)
      {
         populateContacts();
      }
      else if (oMsgrObj.LocalState == 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 oList = oMsgrObj.List(0);
   var oContact;
   var i;

   // To populate our contact list, we're going to iterate throughout the 
   // default list collection, check the state of each contact,
   // and add a DIV with the approppriate appearance to our UI

   for (i = 0; i < oList.Count; i++)
   {
      oContact = oList.Item(i);

      oNewElement = document.createElement("DIV");
      oNewElement.innerText = oContact.FriendlyName;

      switch (oContact.State)
      {
      case MSTATE_ONLINE:
         // Don't need to do anything
         break;
      case MSTATE_OFFLINE:
         oNewElement.innerText += " (Offline)";
         oNewElement.style.color = "graytext";
         break;
      case MSTATE_BUSY:
         oNewElement.innerText += " (Busy)";
         break;
      case MSTATE_BE_RIGHT_BACK:
         oNewElement.innerText += " (Be Right Back)";
         break;
      case MSTATE_IDLE:
         oNewElement.innerText += " (Idle)";
         break;
      case MSTATE_AWAY:
         oNewElement.innerText += " (Away)";
         break;
      default:
         oNewElement.innerText += "(Just plain not around!)";
         oNewElement.style.color = "graytext";
         break;
      }
      oNewElement.className = "clsContact";

      // To enable us to respond to the onclick event, 
      // we're programmatically setting the event
      // handler AND we're defining an expando property
      // on the contact DIV whose value is set to
      // the index of the contact in the default list (so we can find them later)

      oNewElement.onclick = sendMessage;
      oNewElement.setAttribute("CONTACTID", i.toString());

      divContacts.appendChild(oNewElement);
   }
}
function doLogon()
{
   // To logon, we just ask Messenger to display its logon UI

   if (oMsgrObj.LocalState == MSTATE_OFFLINE)
   {
      btnLogon.disabled = true;
      oMsgrApp.LaunchLogonUI();
   }
}

function sendMessage()
{
   // To send a message, we likewise just ask Messenger to do the heavy
   // lifting (we just have to
   // pass it a contact from the default list)

   var nContactID = parseInt(window.event.srcElement.getAttribute("CONTACTID"));
   if (!isNaN(nContactID))
   {
      var oContact = oMsgrObj.List(0).Item(nContactID);
      oMsgrApp.LaunchIMUI(oContact);
   }
}

</SCRIPT>

<SCRIPT LANGUAGE="JScript" EVENT="onLocalStateChangeResult(hr)" FOR="oMsgrObj">

if (hr == 0)
{
   if (oMsgrObj.LocalState == MSTATE_ONLINE)
   {
      // Now we're online

      window.setTimeout("populateContacts();", 3000);
   }
   else if (oMsgrObj.LocalState == MSTATE_OFFLINE)
   {
      // Now we're offline

      divContacts.innerHTML = "";
      btnLogon.disabled = false;
   }
}

</SCRIPT>

<DIV CLASS="clsHeading">Contacts (click on a contact to send a message!)</DIV>
<DIV ID="divContacts" STYLE="MARGIN-TOP: 8px; 
 MARGIN-BOTTOM: 8px; BORDER: 1px solid steelblue"></DIV>
<INPUT TYPE="BUTTON" ID="btnLogon" VALUE="Logon" onClick="doLogon();" DISABLED="yes">

</BODY>
</HTML>

Send It Back

Dear Web Team:

How can you modify XML on the client Web browser and send the resulting XML to the Web server?

The Web Team replies:

We'll assume that your Web server is running Microsoft Internet Information Server (IIS) version 4.0 or later, or a product that supports Active Server Page (ASP) technology.

Let's review briefly how Web browsers provide a rich, interactive Internet experience. In their simplest form, Web browsers request a page from a Web server, process the returned information—usually as HyperText Markup Language (HTML)—and display the results. The HyperText Transfer Protocol (HTTP) defines the language that Web servers and browsers use to talk to each other. The Web browser also does a lot of work behind the scenes to enable the user to navigate the Web and display a variety of media types.

So, you want an interactive Web site—how does a user send information to your Web server?

We will cover two of the many ways for a Web browser, or Web application, to send XML to the Web server. Web browsers generally use the HTTP GET method to request a Web page and use the HTTP POST method to send information. The easiest way to provide communication between the user and your Web server is to use the HTML FORM element.

The FORM element provides a way to send data to the server using either the GET or POST method. You decide which controls are placed within the form, and only those controls that have a NAME attribute specified will have their data submitted. When the user clicks on the Submit button, for example, the data for each control is sent to the Web server.

In the following example, XML stored in an XML data island is submitted to the server as part of a form. The XML can be obtained in many different ways: hard-coded; loaded from an external file by setting the SRC attribute; retrieved from an ADO recordset; retrieved from SQL Server 2000 or created/modified using the XML DOM script object model. The XML can be presented to the user by binding it to HTML elements (see Binding HTML Elements to Data). Including your XML data in the form submission is as easy as assigning the XML to a hidden INPUT element in an onsubmit event handler, as shown below:

<FORM ACTION="http://yourserver/form.asp" METHOD="post" NAME="myform" 
ONSUBMIT=" myform.mytext.value = myxml.XMLDocument.xml;">
 <INPUT TYPE="HIDDEN" NAME="Text" ID="mytext">
 <INPUT TYPE="Submit">
</FORM>

<XML ID="myxml">
 <root>
  <item id="1" name="Item 1"/>
  <item id="2" name="Item 2"/>
 </root>
</XML>

Here are the contents of the FORM.ASP page:

<%@ language=JScript %>
<% 
  var xmldom = Server.CreateObject( "Microsoft.XMLDOM" );
  var xml = Request.Form( "Text" );
  Response.Write( "<XMP>" + xml + "</XMP>" );
%>
Note   The server returns the XML inside an XMP element as a matter of convenience for this example. Although this HTML element is deprecated, it has the benefit of displaying HTML and XML elements as text.

The XMLHttpRequest object is part of the MSXML component that shipped with Microsoft Internet Explorer version 5.0 or later. The objectis created on a Web page and used to send XML to a Web server. The object is created by specifying Microsoft.XMLHTTP as the application name. You would normally call the Open method, optionally set header information, call Send, and then check the responseXML or responseText property. One of the benefits of using this object is that the POST can be performed without refreshing the page, enabling the seamless transfer of data between the server and browser. The XMLHttpRequest object is used by the Internet Explorer Web service behavior to provide calls to .NET XML Web services (using SOAP requests).

The following example demonstrates sending an XML document to a Web server. Note that this example uses a synchronous call. To make an asynchronous call, provide a value of true for the third argument to the Open method and use an onreadystatechange event handler to be notified when the Send method has completed.

<HEAD>
<SCRIPT LANGUAGE="JScript">
function PostXml(xmldoc)
{    
  var xmlhttp = new ActiveXObject( "Microsoft.XMLHTTP" );
  xmlhttp.Open( "POST", "http://yourserver/xmlhttp.asp", false );
  xmlhttp.Send( xmldoc );
  return xmlhttp.responseXML;
}
function ShowResults()
{
  var resp = PostXml( myxml.XMLDocument );
  mydiv.innerHTML = "<XMP>" + resp.xml + "</XMP>";
}
</SCRIPT></HEAD>
<BODY>
<BUTTON ONCLICK="ShowResults()">Post XML</BUTTON>
<DIV ID="mydiv"></DIV>

<XML ID="myxml">
 <root>
  <item id="1" name="Item 1"/>
  <item id="2" name="Item 2"/>
 </root>
</XML>

Here are the contents of the XMLHTTP.ASP file:

<%@ language=JScript %>
<% 
  // Load XML
  var doc = Server.CreateObject( "Microsoft.XMLDOM" );
  doc.load( Request );

  // Process the XML ...

  // Return result
  Response.ContentType = "text/xml";
  doc.save( Response );
%>

There are many situations where storing XML on the client can provide innovative features for your Web sites, such as caching frequently used data, user personalization, or in-line data editing. We've discussed two mechanisms for sending XML data to the Web server. Processing the XML data on the server is simple when using ASP technology and is even easier with the new features in ASP.NET. The server can choose to process the XML in many ways, such as saving the information to a file or database, or performing actions according to the XML content.

Here are some other ways to send data to a Web server that are beyond the scope of this article:

  • HTTP GET method, using a query string (the text after a '?') of the requested URL to send information, but the size of a URL is limited to 2K.
  • HTTP PUT method, though security would be a concern.
  • The HTML INPUT TYPE=FILE element can be used to upload a file selected by the user.
  • Call the low-level WinInet functions directly from an ActiveX control or application to gain more control over communication with the Web server.
  • Use the Internet Explorer Web service behavior to invoke calls to a .NET XML Web service.

Sorting Dates

Dear Web Team:

I am trying to display the contents of a particular folder, and have the files sorted by the date they were created (not alphabetically like I am getting now.) Is there a way, using ASP and the FileSystemObject to do this? Any help would be greatly appreciated.

Matt Pierce

The Web Team replies:

All you had to do was ask, Matt! Here's a sample (thanks, Eric!) ASP page that uses the FileSystemObject scripting object to get a collection of file names and then sorts these by creation date. Documentation for the FileSystemObject scripting object can be found at the Microsoft Windows Script Technologies site.

The GetFolder() method is called to retrieve the folder object for a specified path. The folder object contains a files collection that can be accessed using an Enumerator object. Each file item is retrieved in order of file name, so these are assigned to an array to be sorted later.

    arr[i++] = {path : fc.item().Path, date : fc.item().DateCreated};

The unusual assignment syntax shown here is known as an object literal and consists of a comma-separated list of property specifications. Each property specification consists of a property name followed by a property value. The object literal syntax is used to create an object that has two properties, path and date.

The sort() method of the Array object allows us to specify our own comparison function, sortByDate, to determine the sort order. In this case, the comparison function returns a value indicating the relative order of two items by creation date, but could easily be adapted for other file properties.

<%@ language=JScript %>
<%
function sortByDate(f1, f2)
{
  if (f1.date < f2.date)
    return -1;
  else if (f1.date > f2.date)
    return 1;
  else 
    return 0;
}
function showfiles(path)
{
  var fso, f, f1, fc, arr, i, s;
  fso = new ActiveXObject( "Scripting.FileSystemObject" );
  f = fso.GetFolder( path );

  // Build the file list
  arr = new Array();
  i = 0;
  for ( fc = new Enumerator( f.files ); !fc.atEnd(); fc.moveNext() )
    arr[i++] = {path : fc.item().Path, date : fc.item().DateCreated};

  // Sort the file list
  arr.sort( sortByDate );

  // Display the file list
  s = "";
  for ( i=0 ; i<arr.length ; ++i )
    s += arr[i].path + "<br>";
  return s;
}
Response.Write( showfiles( Server.MapPath( "." ) ) );
%>

Web Team in Short

Web Accessibility

Q: Rob wanted to know how to make Web sites accessible.

A: Check out the accessibility Web guidelines on the Microsoft Enable site.

Color Blind Considerations

Q: Becca asked if there was any information on color blindness and Web development.

A: Have a look at Robert Hess's article Can Color-Blind Users See Your Site? in his regular column More or Hess.

Behaviors

Q: Pierre asked for what purpose are DHTML Behaviors used.

A: There is a good overview article on behaviors in the MSDN Online Library. The DHTML Dude column also covers this topic in the column titled Fun with Tables.

Intranet Authentication

Q: Paul wants to know how corporate users can be authenticated automatically against a Web site using their Domain username and password.

A: In Internet Explorer, go to Tools/Internet Options, and click on the Security tab. Then click on Custom Level, scroll down to User Authentication, and select Automatic logon only in Intranet zone. This option will be the default unless your company's IT group configured it differently.

The Web Team

Mark Davis is a software design engineer on the Internet Explorer SDK team. Mark originates from England and is currently training to climb the major summits in the Northwest.

Heidi Housten works as a Consultant with Microsoft Consulting Services in Sweden after spending some time in Developer Support and MSDN. It is only a rumor that she moved there to escape the drizzle of Seattle; she really went for the traditional crayfish parties in August.

Dan Mohr, an engineer with Microsoft Developer Support's Internet Client team, spends his free minutes recording bands in his basement, programming his Commodore 64, and extolling the virtues of late '70s punk rock.

Jay Allen, a Support Engineer for the Internet Client team in Microsoft Developer Support, longs for the integration of Notepad and Emacs Lisp. What little time is not consumed by his four children is usually spent reading math books, studying Japanese and programming in Haskell.



The Web Team's Greatest Hits

List of Web Team Topics


  
Show: