Home Interviews Developers Our View Blogs We Like The List

LiveSide - Developer Blog

  • Windows Live Writer Interview – Charles Teague

    Catherine Heller has recently done an interview with Charles Teague, Lead Developer on the Windows Live Writer team. In the interview (which you can see after the jump) Charles talks about what Live Writer is, what blog engines it supports, a couple of his favourite plugins, and then moves on to a quick example of how easy it is to write a Live Writer plugin.

    Of course, readers to this blog will already know how to write a cool plugin for Windows Live Writer, even having access to a template to get you going. But this is still a cool video, and it’s always nice to hear from the product team.

    Anyway, enjoy the video, and thanks Angus for the tip.


    Charles Teague: Building Windows Live Writer Plug-ins

    SL

  • Mashed08 – Are You Going?

    Last month we noted that the BBC and Microsoft will be running a UK Developer event taking place on June 21-22nd. Well, that time is upon us and I will be heading up to London tonight ready for it tomorrow as I will be co-hosting a “bean bag” session about Windows Live development with Luke Smith. Some of the things we will be covering are Delegated Authentication using Windows Live ID, accessing the contacts store using Windows Live Contacts API, some VE goodness, and some shameless plugging for LiveNet (which Luke and I wrote)

    So who else is going? If you wanted to meet up at the event, feel free to drop me an email (scott@liveside.net), or a message on twitter. I will try and do a little blogging about the event while it’s going on, but depends on how much time I get.

    SL

  • Uploading videos using the Silverlight Streaming plug-in for Expression Encoder 2.

    This article gives a simple introduction to Silverlight Streaming that will allow you to turn your own video content into a Silverlight Streaming application ready for you to place on your website or blog using Silverlight Streaming plug-in for Expression Encoder to publish to your Silverlight Streaming account.

    This article uses Expression Encoder 2 and the Silverlight Streaming Publishing Plugin for Expression Encoder 2.

    The basic steps are:

    • Encode and Upload to Silverlight Streaming
    • Place Silverlight video on your Website

    Encode and Upload your Video

    This section takes you through the basic steps of how to encode your video and upload to SilverLight Streaming.

    Prereqs:

    1. Get your video content in an accessible place. 
    2. Get Microsoft Expression Encoder 2.  A free trial download can be found here
    3. Get the Silverlight Streaming Publishing Pluging for Expression Encoder 2 which can be downloaded from here.

    Steps:

    1. Open Media Encoder

    2.Import your video using File->Import, and choose your file location.

     SS3_1

    3. Choose the player for your video by selecting the Output tab -> Job Output -> Template. I've chosen the Quicksilver Template.

    ss3_2

    4. To upload to Silverlight streaming, your video must be less then 105 MB. Chose the video and audio quality most appropriate to your use and check the estimated size on the Encode tab.

    ss3_3

    5. I like to the ability to display a thumbnail of my videos.  Encoder now makes this really easy.  Open the Output tab and select the type of thumbnail you want to display.  I usually choose 1st frame.

    ss3_8

    6. To setup publishing to Silverlight Streaming open the Output tab.

    7. In the Publish To section choose Publish To - Silverlight Streaming

    ss3_4

    8. Enter your Account ID and Key.  This can be found on the Manage Account Page of your Silverlight Streaming account.

    ss3_5

    9. If you are happy with your video and want to encode and publish in one step, check the Auto Start Publish checkbox and press the encode button. If you want to encode and preview before uploading to Silverlight Streaming, leave the Auto Start Publish unchecked. Press Encode and change setting until you are happy with your video and then press the Publish button.

    10. If you expand the publish directory you will now be able to see a code snippet or your video play from Silverlight Streaming by clicking on the Preview Tab

    ss3_6

     

     

    Place Silverlight video on your Website

    This section will show you how to place a Silverlight Streaming application on your website.  Previously this involved creation of javascript files or manual javacript creation.  With the plugin for Expression Encoder this is much simpler

    Steps:

    1. Click on the Code tab of the video you wish to put on your blog, site etc.

    2. Copy and paste the code from the tab to your site.

    ss3_7

    3. You're Done!

  • Live Search Web Page Error Toolkit Released

    Over at dev.live.com they have announced the release of the Web Page Error Toolkit which “allows you to display custom error messages with search results that generated from relevant keywords.” From the Live Search dev blog:

    For large web sites with extensive amounts of content, 2 to 10 percent of traffic is looking for pages that either don’t exist or have been moved. Most web servers return a generic 404 error page or a sitemap when a user’s desired page cannot be found. These unhelpful pages often result in a dead end for users.

    With Microsoft’s Web Page Error Toolkit, you can create dynamic 404 pages that contain customized error messages along with search results seeded with relevant keywords to help your users move past the missing page and find the information they need.

    The Toolkit is a customizable ASP.net application that replaces the default error page on your IIS server. The Toolkit enables you to use Live Search (or any search engine) to return results for the specified domain and locale, control the number of results returned on your page, choose whether to offer spelling corrections, and customize your error message.

    You also have the option of choosing from several keyword extraction strategies that are included with the install, or providing your own implementation.

    And a quick example of what happens from the dev.live post:

    Typical 404 Error Page

    Standard 404 Error Page

    Dynamic 404 Error Page

    Custom 404 Error Page with Search Results

    You can download the Toolkit from Microsoft Downloads

    SL

  • The New Live Writer SDK

    In my previous post, I mentioned that the Live Writer SDK had been updated as well as Live Writer itself. In this post I will show you how to build a couple of quick plugins that use the new APIs, but first, what’s changed?

    The big thing to note is that all the API calls in the previous version of the SDK are unchanged; the changes have been additions to the SDK. So the main two new additions are two new plugin classes: PublishNotificationHook and HeaderFooterSource. This gives us four types of plugins: ContentSource, SmartContentSource, PublishNotificationHook and HeaderFooterSource. There are also a couple of other new smaller additions, like the TaskServices class that will let you perform a task in the background whilst still keeping the Writer UI in a responsive state.

    But this post is going to concentrate on those two new Plugin base classes, which you can see after the jump.

    PublishNotificationHook

    This type of plugin can be used to access the post either before or after it’s published. The reason you might want to do this is to check the post for something, this can be the title, the contents or even the keywords (blog engine permitting). You would check the post for whatever you’re looking for and if it passes your check, you allow the post to be published, or else you tell Writer to stop publishing and the post remains unpublished.

    Let’s look at some code. The plugin starts off the same way as a ContentSource or SmartContentSource plugin in that you have to declare some WriterPlugin attributes:

        [WriterPlugin("07b95fc3-887e-4558-b53a-0e2a5a47f431", 
    "PublishNotification Example", PublisherUrl = "http://www.liveside.net", Description = " ", ImagePath = "writer.png", HasEditableOptions = false)]

    So now we create the plugin class and mark it as a PublishNotificationHook class:

        public class PublishNotificationExample : PublishNotificationHook
        {

    Like ContentSource or SmartContentSource plugins, you can override the Initialize() method (if your plugin requires settings), this is also true for HeaderFooter plugins too.

    With PublishNotificationHook plugins, I mentioned that you can access the post before (or after) it’s published, and we do this by overriding the OnPrePublish and OnPostPublish methods. In this very quick example, I’m going to check whether my post’s contents (ie, the body of the blog entry) contains the word “liveside”:

            public override bool OnPrePublish(IWin32Window dialogOwner, 
                IProperties properties, IPublishingContext publishingContext, 
                bool publish)
            {
                // Check the post contents to see if liveside appears, if it does, 
    // return true (publish),
    // if it doesn't, return false (cancel publish) return publishingContext.PostInfo.Contents.ToLower().Contains("liveside"); }

    Now, the publishingContext.PostInfo is where all the cool stuff is. In this property (which is an IPostInfo object), you have access to the Contents, Keywords, Title, Categories, and even tells you whether it’s a page or not (for Wordpress users). Now with this quick check, if my post doesn’t contain the word liveside, then the OnPrePublish method will return false which will stop the post from publishing, if it does contain it, then it will return true and continue to publish.

    The OnPostPublish method is slightly different, this method would allow you to do something once the post has been published, for example, update your Twitter status with the blog title and permalink:

            public override void OnPostPublish(IWin32Window dialogOwner, 
                IProperties properties, IPublishingContext publishingContext, 
                bool publish)
            {
                // If this post is a draft (false), don't do anything
                // if it's an actual publish, then publish = true;
                if (!publish)
                    return;
    
                string updateTwitter = string.Format("{0} - {1}",
                    publishingContext.PostInfo.Title,
                    publishingContext.PostInfo.Permalink);
    
                // Code to update Twitter
            }

    You’ll notice the variable publish that gets passed in both OnPostPublish and OnPrePublish, this will tell your plugin whether it’s being saved as a draft or as an actual published entry. This is the same for HeaderFooterSource plugins, too.

    And there you have it, a quick plugin that uses the PublishNotificationHook base class.

    HeaderFooterSource

    This type of plugin can be used to automatically add some html code to a blog post as either a header, or a footer. Quick examples of this could be a Digg button (header), or Social Bookmarking widget (footer). Now the cool thing about this type of plugin is you can actually specify the permalink for the post to be used, even if the post has yet to be published (I’ll cover this when I start going through the code). If you want to see what your post will look like when using this type of plugin, you just go to the Preview tab and the plugin will get loaded (there are separate methods for the Preview HTML and the Published HTML, but again, I’ll go through that in the code).

    Start off by creating the class and declaring it as a HeaderFooterSource plugin:

        public class HeaderFooterSourceExample : HeaderFooterSource
        {

    Now, as I mentioned, the cool thing about this base class is you can tell the plugin to use the post’s permalink (even though it hasn’t been published yet), but what we need to do is tell Writer that the plugin will require a [currently] non-existent permalink, we do this by overriding the RequiresPermalink boolean (whose default is false):

            public override bool RequiresPermalink
            {
                get
                {
                    return true;
                }
            }

    The HeaderFooterSource base class will create two methods for us: GeneratePreviewHtml() and GeneratePublishHtml(). Now these both work in a similar way to GeneratePublishHtml() and GenerateEditorHtml() in SmartContentSource plugins. The GeneratePreviewHtml() is what shows when you switch to the Preview tab, and the GeneratePublishHtml() is what gets published.

    So first off the GeneratePreviewHtml():

            public override string GeneratePreviewHtml(ISmartContent smartContent,
                IPublishingContext publishingContext, 
                out HeaderFooterSource.Position position)
            {
                // This tells the plugin where to put your code
                position = Position.Header;
                return "Nothing to see here yet!";
            }

    And then the GeneratePublishHtml():

            public override string GeneratePublishHtml(IWin32Window dialogOwner, 
                ISmartContent smartContent, IPublishingContext publishingContext, 
                bool publish, out HeaderFooterSource.Position position)
            {
                position = Position.Header;
                string yeehaaaa = string.Format("This blog entry's link is: <br />" + 
                    "<a href=\"{0}\">{0}</a>.", publishingContext.PostInfo.Permalink);
    
                return yeehaaaa;
            }

    So if you now click on the Preview tab, your post would look like this:

    image

    Notes about these plugins

    After you have have first added any of these plugins to Live Writer, when you click on the Publish button (or Preview for HeaderFooterSource), Writer will ask you if you want to use these plugins for the blog you’re currently using:

    image

    For these new types of plugins, you can enable or disable each plugin on a per blog basis, which you can do from the Accounts options window:

    image

    And that’s about all you need to know for now. I have made some plugins of my own using these new APIs, but I will cover those in another post.

    As always, the source code for this can be found in my skydrive area:

    http://cid-fabdddc5cad93494.skydrive.live.com/self.aspx/LiveSide%20-%20Public/SourceCode/NewAPIPlugin.zip

    SL

  • Windows Live Agents SDK Released

    The Windows Live Agents blog posted a couple of weeks back that a new version of the Platform and SDK was coming soon, and that day is seemingly upon us. In a blog entry that has just gone up on the WLA blog, the new SDK has been released. There have been strong hints as to what the SDK will now be from the documentation that has been on MSDN for a few weeks now, and it comes in the form of a Visual Studio Add-in, rather than its own IDE as it was when it was Colloquis.

    Angus Logan has a good summary of the blog entry (it’s quite long), but the key thing to point out for Live Agent developers are that Microsoft “will be retiring the old standalone Colloquis SDK (versions 4.3 and previous) within 90 days of our 5.0 release.”

    Further information:

    Expect a further post on the Live Agents SDK, how to use it and build a simple Agent.

    SL

  • BBC and Microsoft run UK developer event - Mashed

    If you're a developer and interested in working with some cool technologies at a BBC hack day, then check out Mashed 08. Being held in London at the Alexandra Palace on June 21-22, this is the BBC's very own "Hack Day", allowing developers to get creative over the course of a weekend.

    Microsoft is one of the partners (O'Reilly is another) and entrance is free for all registered participants. If you're interested then you might also like to know there will be Windows Live involvement, with some of us from LiveSide also in attendance. We want to see what cool things people can build with Windows Live, and hopefully we'll be showcasing some of the projects during and after the event.

    The Microsoft tickets have just been made available - Register for them now as they will go extremely quickly!

    Register for tickets UPDATE: Ticket allocation has closed and the event is now sold out.

  • Create a Deep Zoom Panorama with Windows Live

    In this article I will show you how to use a combination of free tools and services to produce and host a high quality panorama. You will render this using Silverlight2 and display it geo-referenced on Virtual Earth. The combination of hosted storage and services from Windows Live gives us a powerful Rich Internet Application from a basic HTML page. The tools and services you will use are:

    The final result below is made from eight photos taken of the Story Bridge in Brisbane, Australia at 6am.

    Step 1 - Find a good Subject

    Take you time to find a great landscape, cityscape or landmark. Choose a good time of day, dawn or dust offers better light then during the middle of the day.

    PreStitch

    You will need to take a set of overlapping photos to allow the stitching software to compose the final image. For my panorama I used a 17mm wide angled 'L' lenses on a Canon 350d DSLR, each image is 8MP. The more level the set of photos the better the final composition will be. I used a tripod with a special panorama head to eliminate parallax effects but you can still get great results from handheld shots. The images should be taken from the same spot and in rapid succession to reduce inconsistencies between shots. At dawn the light can change very rapidly.

    ManuStitch

    This shows the shots overlapping, you don't have to do anything manual here, you will use an automated stitching tool.

    Step 2 - Windows Live Photo Gallery

    Windows Live Photo Gallery is the consumer level photo tool for Windows. It offers a great importer, tagging, rating and publishing system for your photos. You download it as part of the Windows Live suit from http://get.live.com

    Get Window Live

    Within the interface creating a panorama couldn't be easier. You simply select the set of images, right click and choose "Create panoramic photo"

    CreatePanoramic

    The output is a 9745 x 3775 pixel stitch, colour corrected and aligned. The image file is 4.5MB so how can we effectively show this on the web with all of it resolution? For example this shows a full resolution section of the completed stitch:

    StitchedMarkedArea

    FullResSnippet

    Step 3 - Deep Zoom Composer

    The solution is to use the new Deep Zoom technology from Silverlight2. The new control, multiscaleimage, streams in the best resolution sections of the image as the user needs it based on their interactivity and their screen resolution. And with the newly updated Deep Zoom Composer this is as simple to create as a few clicks. Download the composer from here.

    DZNew

    Create a new project. Import the stitched image and drag it onto the compose area. The composer allows you to show many images, arrange and resize them on the canvas using a set of helpful align tools. You will drop on the one image.

    DZComposition

    For this project we need to simply export the image as a composition, that is a single image. The other option, a collection, allows you to export a set of composed images that can be rearranged programmatically at runtime. You may have seen something like this at http://memorabilia.hardrock.com

    For output type you want "Export Image and Silverlight Project". This will produces the visual assets as well as a ready to use silverlight2 project. This project contains all the functionality needed for this application, you don't need to write any .net Silverlight code.

    DZExporting

    When the export completes, you can preview the Silverlight application in a browser.

    DZExport

    Step 4 - Silverlight Streaming

    The application is about 10MB. To serve this on the web we would need a web server configured to serve Silverlight XAP files and you would need to consider the performance requirements and the bandwidth. The Silverlight Streaming service from Windows Live solves these problems allowing you to rapidly deploy your Silverlight application using hosting provided by Microsoft to facilitate the growth of Silverlight. Sign up for a free 10GB account at http://silverlight.live.com

    SilverStreamSteps

    1. Sign into your newly created account
    2. Goto Manage Applications
    3. Click Upload an Application
    4. Name the Application
    5. Create a Manifest file
    6. Zip the application
    7. Upload
    8. Get the Iframe snippet

    SilverStreamSteps2

    Give your application a Name.

    In order to upload the application you need to add an XML file called a Manifest. It specifies the application properties so the Silverlight service knows what to do with the application. Here is one for the default output from Deep Zoom Composer that you can reuse:

    <SilverlightApp>
      <version>2.0</version>
      <source>DeepZoomOutput.xap</source>
      <width>800</width>
      <height>600</height>
      <background>gray</background>
      <isWindowless>false</isWindowless>
    </SilverlightApp>

    This file needs to be put in the generated "C:\Users\john\Documents\Expression\Deep Zoom Composer Projects\LiveSideArticle\source images\OutputSdi\livesidearticle\DeepZoomOutput_Web\ClientBin" folder next to the DeepZoomOutput.xap and GeneratedImages folder. Compress these three items into a zip file. In Windows Vista you can do this off the right click context menu - Send to -> Commpressed (zipped) folder.

    SilverStreamSteps3

    Upload the single compressed file to Silverlight Streaming. When it is uploaded you will get the snippets page with two options for how you can display this new application in your web pages.

    SilverStreamSteps4

    For this project you will use the simple Iframe, this is a perfect snippet for including in an article or blog. Do note Method 2, the three snippets, allow your Silverlight application to be embedded into the page without the use of an Iframe. Also note that for Video there is a specific Upload Video section that will encode your video and produce the video application for you.

    You can preview your application by clicking on "Launch Application Test Page"

    Step 5 - Virtual Earth

    The final step for your project is to show the Deep Zoom image at the actual location you took the photo on a Virtual Earth map. This requires a simple HTML page with a little bit of Virtual Earth JavaScript. The concept is to the load the map in Aerial mode, add a pushpin and show it infobox (little popup) housing the Iframe with our newly created Silverlight application.

    The complete HTML follows, for your project simple replace the Iframe and the Latitude/Longitude position. It can be handy to have a GPS with you to record the exact location when you take the photo. Or using http://maps.live.com later you can choose the location manually.

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
             "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
      <head>
        <title>Silverlight Streaming Panoramas on Virtual Earth</title>
        <meta http-equiv="Content-Type"
                              content="text/html; charset=utf-8" />
          <script type="text/javascript"
    src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.1">
          </script>
          <style type="text/css">
              body
              {
                  margin: 0px;
              }
              .customInfoBox-body
              {
                  width: 420px;
                  height: 260px;
                  overflow: hidden;
                  padding: 0px !important;
                  top: 0 !important;
              }
              .customInfoBox-shadow
              {
                  width: 420px;
                  height: 260px;
              }
              .customInfoBox-with-leftBeak
              {
                  width: 0 !important;
                  height: 0 !important;
              }
              .VE_Pushpin_Popup_Title
              {
                  padding: 5px;
              }
              .VE_Pushpin_Popup_Body
              {
                  text-align: left;
                  margin-left: 0px;
              }
          </style>
          <script type="text/javascript">
    var map = null;
    function GetMap()
    {
        map = new VEMap("myMap");
        map.onLoadMap = onLoadMap;
        map.LoadMap(new VELatLong(-27.46212,153.03705)
            , 16
            , VEMapStyle.Aerial
            , false
            , VEMapMode.Mode2D
            , false);
    }
    function onLoadMap() {
        map.ClearInfoBoxStyles();
        var shape = new VEShape(VEShapeType.Pushpin
            , new VELatLong(-27.46212,153.03705));
        shape.SetTitle('The Story Bridge, Brisbane, Australia');
        var desc = '<iframe src="' + 
    'http://silverlight.services.live.com/invoke/31868/LiveSideArticlePanorama/iframe.html"' + 
    ' scrolling="no" frameborder="0" style='width:400px; height:200px'></iframe>'
        shape.SetDescription(desc);
        shape.SetCustomIcon('pin.png');
        map.AddShape(shape);
        map.Pan(200,0);
        //The pan causes our infobox to close so we have to wait 2 secs
        setTimeout(function(){ if (shape) map.ShowInfoBox(shape)},2000);
    }
          </script>
      </head>
      <body onload="GetMap();">
          <div id="myMap" 
            style="position:relative; width:600px; height:600px;"></div>
      </body>
    </html>

    Conclusion

    So in 5 easy steps and very little code we have a full interactive map with a pin that pops up a deep zoom Silverlight2 panorama allowing you explore your image at full resolution on demand. We only used free tools, it was pretty straightforward (I hope!) and all we need to host the Rich Application is a simple HTML page. I can even embed it in my blog as an Iframe. How cool is that?

    With a little more effort you could personalise the HTML page and add more panoramas from all your travels.

    I hope you have enjoyed this article and please post up links to your creations using these cool services.

  • Live Mesh, From A Developer’s Side

    With the release of Live Mesh and all that has been said about it (here and here), what’s in it for developers? Well Mesh is meant to be the platform that people can build upon, and we’re given a glimpse of that on the developer page on the Live Mesh website.

    Taken from the website, you have a link to the a welcome video for developers as well as hints as to some of the capabilities of the Mesh Platform, allowing you to build applications that:

    • Use the Live Mesh sync service to synchronize files, data, and applications across all the devices in a user's mesh—even in scenarios where devices are only occasionally connected to the service.
    • Use the Live Mesh member service to provide file- and data-sharing experiences to anyone.
    • Extend the Live Desktop experience to deliver applications that are accessible from anywhere.
    • Plug in to the Live Mesh news feed system to generate notifications for key activities in your application.

    So what sort of applications are we talking about? Well, in their white paper, they give us a glimpse of what’s on the Horizon (oh how we love puns):

    image

    Unfortunately, that’s as much as they do show (notice the Apps tab at the top of the screenshot and Mesh Applications shortcut on the desktop), going on to say:

    In the coming months, you’ll hear more about the developer platform for Live
    Mesh,  including  how  developers  can  write  services  and  applications  that
    interact  with  the  mesh  to  provide  a  more  personal  and  meaningful  user
    experience.

    So it looks like there are some very interesting times coming for developers wanting to Mesh about with Mesh. In the mean time, if you want to register your interest for the developer SDK, go to Connect and fill out the survey.

    SL

  • Is Microsoft serious about gadgets?

    If Silverlight 2 is Microsoft's shining new addition to the family (and deservingly so) then gadgets, both Windows Vista Sidebar and web gadgets are the all but forgotten middle children. In this article I pose the question: Has Microsoft all but given up on it's gadget platforms?

    Consider the following:

    1. Many groups within Microsoft have blogs where they talk about what's going on in the group, give advise on programming, etc, but some groups are more involved with their readers that others. The last post to the Windows Vista Sidebar Blog is dated July 31, 2007 and the Windows Live Gadget Blog is dated June 27, 2006.
    2. Most of the top players in Microsoft's Live.com group (the innovators of web gadgets) have either left the company or moved on to other groups within Microsoft.
    3. At Microsoft's MIX08 conference in Las Vegas, I did not hear the word "gadget" uttered once by any panel member or during the keynote.
    4. Code Focus magazine that came in the MIX08 goodie bag focused on Windows Live. There were articles on Live Search, Live ID and Live Writer but nothing on Live.com or web gadgets.
    5. Internet Explorer 8 beta 1 was released not long ago at MIX08 in Las Vegas. During one of the IE8 sessions I asked Chris Wilson, Platform Architect and long time IE team veteran how the new features of IE8 would effect Vista Sidebar. He didn't really have a good answer for me. I also asked him if the Windows Vista Sidebar team still exists. His response was "I'm not sure" which prompted several chuckles from the audience. Some have stated online that the Sidebar team has in fact been disbanded.
    6. Over the past year, Google has announced support for Open Social Gadgets and Google Gadgets Ads. During the same period of time, Microsoft's gadget innovations include (insert sound of crickets chirping here).
    7. And what may be the most telling... there are currently 53 Windows Vista Sidebar bugs listed on Jon Abbott's unofficial Windows Vista Sidebar bug list. Windows Vista SP1 was released to manufacturing and not one of these bugs has been resolved.

    Is it possible that Microsoft is backing off of on the Vista Sidebar gadget platform because of the security risks involved? Sidebar gadgets are prone to security problems and are hard to properly lock down. Many of us learned this the hard way when the Traffic by Live Search Maps gadget that I wrote for Microsoft was taken down for a short time to plug a security hole. Microsoft might be skittish about it's liability should a third party gadget be breached by a hacker to cause harm to the system.

    While the gadget platform seems to have gotten the cold shoulder at Microsoft, gadgets themselves are still alive and ticking. For example, the new version of the Traffic by Live Search Maps gadget is still the most download Microsoft branded gadget download with nearly a quarter of a million downloads. Other groups within Microsoft are advertising their brand as well with dedicated RSS gadgets like the new Channel 10 gadget. So while I'm disappointed with Microsoft's lack for support for the platforms, I'm happy to see groups with Microsoft still interested in promoting cool new gadgets.

    Posted Apr 11 2008, 11:21 AM by donavon with 2 comment(s)
    Filed under:
  • Windows Live Messenger Web Controls - Part 2

    Hopefully you will have read and followed the code from the first part of this article. The first part covered most of base functionality including how to sign in, get the users details and get their contact list. What is left is how to actually carry out a conversation with a contact.

    If you remember from the first article, in the signInCompleted event handler we defined three delegates to handle various events. The first part of this article talked about the first two of these delegates, and that leaves the last one to talk about :-

    _user.get_conversations().add_propertyChanged(Delegate.create(null, conversation_collectionChanged));

    This code adds an event handler that will call the conversation_collectionChanged() event handler whenever any of the conversations that you currently have ongoing changes.

    function conversation_collectionChanged(sender,e) {
       displayConversations();
    }

     

    Our event handler simply calls another method in which we will display the conversation. Again we are using a separate function as this function is used in multiple places so it makes sense to separate it out rather than code directly in the event handler itself.

    function displayConversations() {
       convArray = new Array();
       var sb = new StringBuilder('<p><b>Active Conversations: (click a conversation to resume):</b></p>');
       var item = 0;
       var enum1 = _user.get_conversations().getEnumerator();
       while (enum1.moveNext()) {
        var c = enum1.get_current();
        convArray.push(c + ":" + item);
        if (c.get_closed())
           continue;
        sb.append(convLink(c, item));
        sb.append("<hr />");
        item++;
       }
       document.getElementById('divConversations').innerHTML = sb.toString();
    }

     

    The displayConversations() method does exactly what it's name suggests, it displays a list of all the conversations that you currently have ongoing. What it does not do however is display the actual conversation itself, just the list of whom you are having conversations with.
    Like so many things in the Windows Live Writer API conversations are a collection. So in this code we simply loop through the conversation collection. For each individual conversation item we make a call to convLink() to extract some information from the conversation, and make a list of current conversations taking place which we then display in the conversations zone we defined the main body of the html page.

    function convLink(c, item)
    {
       var roster = c.get_roster();
       var enum1 = roster.getEnumerator();
       var names = new Array();
     
    while (enum1.moveNext())
    {
       var dispName = enum1.get_current().get_presence().get_displayName();
       var dispEmail = enum1.get_current().get_address();
       if (dispName !== '') {
        names.push(dispName);
       } else {
        names.push(dispEmail);
       } 
    }
     
       var sb = new StringBuilder();
       sb.append('<a href=\"BLOCKED SCRIPTswitchConv(' + item + ')\">');
       if (c == _conv)
        sb.append('<b>');
        sb.append(names.join(', '));
        if (c == _conv)
           sb.append('</b>');
           sb.append('</a>');
           sb.append('&nbsp;&nbsp;');
           sb.append('<a href=\"BLOCKED SCRIPTcloseConv(' + item + ')\">');
        sb.append('close</a>');
        return sb.toString();
    }

     

     

    Because you can have conversations with multiple participants, what we do here is get the roster of participants in the conversation from the conversation object that is passed in, loop through that list of participants and extract either display name if they have one or their email address if they don't. We store that information in an array then create a hyperlink that the user can click on to display that actual conversation. The hyperlink is simply a reference to the switchConv() function which displays the conversation. We also add a close conversation hyperlink in case the uses wishes to exit that conversation. This is passed back to our displayConversations() function which actually displays the information.

    function switchConv(id)
    {
       var c = _user.get_conversations().get_item(id);
       if (c)
       {
       if (_conv) {
        _conv.remove_messageReceived(_convSink);
       }
       _convSink = Delegate.create(null, recvMsg);
       _conv = c;
       _conv.add_messageReceived(_convSink);
       removeChildrenFromNode('txtConv');
       /* Display all messages from the conversation history. */
       var hist = c.get_history();
       var histEnum = hist.getEnumerator();
       while (histEnum.moveNext()) {
        displayMsg(histEnum.get_current());
       }
       document.getElementById('btnSend').disabled = false;
    }
       displayConversations();
       document.getElementById('txtMessage').focus();
    }

     

    Active Conversations

    Each conversation object in the conversations collection has a unique id to reference it. In the first line we get the actual conversation object from the ID passed into the function. We remove the existing delegate for messages received and setup a new one for this particular conversation. Then we clear out the zone we defined on the page to display the actual conversation.
    Next we get a collection of all the conversation items have already taken place in this conversation and simply loop through the conversation history collection, extract out individual conversation item and call a helper function to format the conversation text ready for display on the page. Once we have all the history of that conversation taken care of, we make sure that the button on the page to send a message is enabled, we update the list of the conversations that the user has going and finally we set the focus on the textbox we have defined on the page for the user to enter their message.

    function displayMsg(message) {
       var elMsg = message.createTextElement();
       var txtConv = document.getElementById('txtConv');
       var userName = "";
       if (message.get_sender().get_presence().get_displayName() != null)
        userName = message.get_sender().get_presence().get_displayName();
    else
        userName = message.get_sender().get_address();
     
    txtConv.appendChild(document.createTextNode(userName + ' says: '));
    txtConv.appendChild(elMsg);
    txtConv.appendChild(document.createElement('br'));
    }

     

    The helper method to display a message takes in a conversation item, from that we extract the username of the person who posted that particular message or the email address if that person does not have a username defined and format our output similar to what the Windows Live Messenger client displays (if you wish to make it exactly the same you can as the message object also has a property to get the timestamp of the message. See here for details). Once we have formatted the text by displaying the username/email address followed by the actual message we insert the conversation message into the zone we have defined in the actual html of the page.

    Message Window

    I'm sure at this point you'll be glad to hear that we're nearly finished. Up to now you've added code so that the user can login to Windows Live ID, displayed certain information about the user, received and displayed all their contacts within the appropriate groups, displayed a list of conversations that are ongoing and hooked up events various to help with all the above. All that really remains is sending a conversation message, receiving a conversation message and closing a conversation.

    If you remember back in our convLink() function, inserted two Javascript function calls into the display. One was to switch conversation which we've discussed above, the other was a hyperlink to close a conversation.

    sb.append('<a href=\"BLOCKED SCRIPTcloseConv(' + item + ')\">');

     

    Here is the code to close a conversation :-

    function closeConv(id) {
       var c = _user.get_conversations().get_item(id);
       convArray.splice(id, 1);
       c.close();
       if (c == _conv)
       {
        removeChildrenFromNode('txtConv');
       }
       displayConversations();
       if(_user.get_conversations().get_count() == 0)
        document.getElementById('btnSend').disabled = true;
    }

    To close a conversation we need the ID of the conversation we are about to close (remember each conversation object within the conversation collection has it's own unique ID). So first we retrieve the actual conversation object from the ID passed into the function then we call the close() method on the conversation object. Next we do some cleanup work. If the conversation we just closed was the current conversation (i.e. the one the user was currently interacting with) then we clear out all the messages that were displayed in our conversation zone. Next we update the list of conversations that the user has ongoing and finally we disable the send message button if there are no more conversations taking place.

    function recvMsg(sender, e) {
       var message = e.get_message();
       displayMsg(message);
       document.getElementById('msgLastRecv').innerText = 'Last message at: ' + _conv.get_history().get_lastReceived().toString();
    }

     

    In the receive message event handler, we get the message that was received (passed in as the event argument), display the message using the function we discussed above and also notify the user about this message in a zone we've defined in our html markup specifically for this purpose. We do this because we might receive a message from a conversation different to that that the user currently has displayed, so we need to inform them that a message from another conversation has been received.

    function sendMsg() {
       var txtMessage = document.getElementById('txtMessage');
       var messageText = txtMessage.value;
       var message = new Microsoft.Live.Messenger.TextMessage(messageText, null);
       if (_user) {
        _conv.sendMessage(message, null);
       }
       displayMsg(message);
       txtMessage.value = '';
       txtMessage.focus();
    }

     

    The sendMsg() function is activated by the send message button defined in our html markup. Here we get the text the user has entered into the message textbox in our main markup and create a new Message object from it. Next we call the sendMessage() method of the conversation object and pass in the new message object we've just created. Essentially this adds the message to the conversation history and your message gets passed through the cloud and will display in the contacts messenger.
    We then do some housekeeping by adding the new message to our conversation zone, blank off the message textbox where the user enters a message and make sure that that textbox has the focus.

    There you have it, a working Windows Live Messenger that you can insert into your own web page :-

    Working Messenger

    There are plenty of things you can add to this including adding the ability to add contacts and add nudges etc. In fact the Windows Live Messenger API has all the functions, event handlers etc. in it that you could create essentially an exact copy of the Windows Live Messenger client within your web page.

    Here is the completed code that we've discussed over the last two articles :-

    <%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>
     
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
     
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title>WLMessenger Site</title>
       <script src="http://settings.messenger.live.com/api/1.0/messenger.js" type="text/javascript" language="javascript"></script>
       <script type="text/javascript" language="javascript">
    function scriptMain() {
       var privUrl = 'http://[url]/Privacy.htm';
       var chanUrl = 'http://[url]/Channel.htm';
       _signin = new Microsoft.Live.Messenger.UI.SignInControl('signinframe', privUrl, chanUrl, 'en-US');
       _signin.add_authenticat