Latest Tweet:
  • Loading...

One of the demos I gave during my Visual Studio 2008 presentation at MSDN Live this Monday was on Visual Studio Tools for Office and how to build an Outlook 2007 Add In. VSTO is now as integrated part of Visual Studio 2008 and not a separate product anymore. Previous versions of VSTO have been a bit limited, but the latest version lets you extend Outlook, Word, Excel, PowerPoint, Visio, InfoPath and Project using managed code. This opens up to some really nice integration scenarios where you can integrate line-of-business applications directly into Office.

In my demo I integrate Virtual Earth maps into the contact form in Outlook 2007. When you open up a contact you get a new button to view a map showing the contacts location on the map. The way I integrate Virtual Earth is by using the Windows Forms Web Browser control. The cool thing about the Web Browser control is that it's really easy to invoke JavaScript functions on the page being displayed directly from C#.  The JavaScript code to find a location on the map and display a pushpin is based on the Virtual Earth Interactive SDK samples.

To create a new Outlook 2007 Add-in start by going File - New Project, and select Visual C# - Office - 2007 - Outlook Add-in. This will create a new Outlook Add-in project. The project template will create a simple ThisAddIn.cs file that contains methods for Add-in startup and exit. For now just ignore this file. The next thing you need to do is add a forms region to your project. Right click the project and select Add - New Item. This will bring up the dialog box with all available items. Select the Outlook Form Region item to design a new form. Adding this item will launch a short "Outlook Form Region" wizard. You get options to design a new form, or import an existing design from an .ofs file. Select new form region. The next question is what type of form region you want to create. You can choose separate, adjoining, replacement and replace-all. Choosing separate will add a new button to the toolbar, which will open your form region as a separate page when you click the button. Select this option. Next step is to give your form a name, before the final step is to select which type of message class you want to display the form region on. You can select multiple options (like mail, RSS, task). For this form we'll simply select contact. This will make the add-in available only on the contact form inside Outlook.

newofficeproject  

newoutlookform

After completing the wizard you get a design surface that should look familiar to any Windows Forms developer. It's the good old Windows User Control designer where you can drag and drop any Windows Forms control onto the surface. Start by adding a web browser control and dock it to the parent. Set the ScrollBarsEnabled property to false. Add an event handler for the DocumentCompleted event. This event is executed when the browser is done loading the web page. Set the URL property of the web browser control to http://jonas.follesoe.no/content/binary/virtualearth.htm, or your own version of the Virtual Earth HTML file. The content of the file is straight forward, and can be viewed below. For security reasons IE (the Web Borwser Control is a simple wrapper around IE) displays a warning when ever a local HTML file is loaded. Even if you accept blocked content I can't get the map to display correctly. That's why I have the map HTML file up on a web server (and not as a local file on disk). The HTML and JavaScript looks like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
    <title>Virtual Earth</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <style type="text/css">
        body        
        {
            margin: 0px;
            padding: 0px;
        }
    </style>
    <script src="http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=5" type="text/javascript"></script>
    <script type="text/javascript">      
        var map = null;  
        var pinid = 0; 
        var title = "";
        var description = "";               
        
        function GetMap()      
        {         
           map = new VEMap('myMap');
           map.SetDashboardSize(VEDashboardSize.Small);
           map.LoadMap();      
        }      
                 
        function FindLocation(location, contactName, contactDescription)
        {
           try
           {
               title = contactName;
               description = contactDescription;
               
               if(map == null)
                   GetMap();
              
               map.Find(null, location, null, null, 1, 1, true, true, true, true, LocationFound);
           }
           catch(e)
           {
               alert(e.message);
           }
        }   
        
        function LocationFound(a, b, placeArray, d, e)
        {
           var shape = new VEShape(VEShapeType.Pushpin, placeArray[0].LatLong);          
           shape.SetTitle(title);
           shape.SetDescription(description);
           
           pinid++;          
           map.AddShape(shape);          
        }
    </script>

</head>
<body>
    <div id='myMap' style="position: relative; width: 100%; height: 100%;"></div>
</body>
</html>

In the DocumentCompleted event you need to execute the FindLocation JavaScript function on the loaded HTML page. You do this by calling the webBrowser.Document.InvokeScript method. As parameters to the FindLocation function you need to pass in the contacts name, address and description (used by the pushpin). The code to execute the script and access the currently selected contact is displayed below:

        private void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            Outlook.ContactItem currentContact = (Outlook.ContactItem)this.OutlookItem;
            string address = currentContact.BusinessAddress.Replace("\r\n", ",");
            ExecuteScript("FindLocation", address, currentContact.FullName, currentContact.BusinessAddress);
        }

        private void ExecuteScript(string scriptName, params object[] parameters)
        {
           webBrowser.Document.InvokeScript(scriptName, parameters);
        }

The FindLocation function will use VirtualEarth to look up the address, move the map and add a pushpin with the name and address of the contact. Screenshot below:

contactscreenshot

This example is just a quick demo of what some of the new features in Visual Studio Tools For Office 3.0 shipping as part of Visual Studio 2008 has to offer. For another interesting demo check out the TechEd US key note available over at Virtual TechEd. The Office/Outlook demo starts about 58:30 into the video.

For more information about Office Development check out the Visual Studio Tools for Office Developer Portal.

One of the cool, but perhaps overlooked features, of Outlook 2007 is the integration of mobile messaging. Today many mobile providers offers some kind of plug-in to Outlook enabling their customers to send SMS messages from Outlook. The implementation and user experience differs for each mobile provider. In Outlook 2007 there is a standard way to supports incoming and outgoing SMS and MMS messages directly from Outlook. You simply implement an XML Web Service consisting of three simple methods. There really isn't too much information available on Outlook Mobile Services in the blog sphere, so hopefully this post and webcast will be a welcome addition. In this post you'll learn how to create a Outlook 2007 Mobile Service. I've also created a screen cast that walks you through the development and deployment process.

This post is the third in a series covering free SMS messages using the Ung1881 service. The first post covered how to wrap the service into a .NET library, while the second covered how to use the .NET library from a Vista Sidebar Gadget. In this post I'm going to discuss how to implement an Outlook 2007 Mobile Service that use the same library to send free SMS messages from Outlook 2007!

Using the Ung1881 Free SMS library and Outlook 2007 Mobile Services you can send free SMS messages directly from Outlook 2007

Your Web Service only need to implement three methods, GetServiceInfo, GetUserInfo and SendXms. I've included a simple class diagram showing the methods you need to implement.

The strings passed back and fourth between server and client contains XML data. The XML structure, and Outlook 2007 Mobile Services in general, is well documented in a comprehensive developer guide up on MSDN. Last week I did some e-mailing with the team behind Outlook 2007 Mobile Services, because I couldn't get it to work by following the code samples up on MSDN. I turned out the samples where written for 1.1, and that the SOAP encoder works a little bit different in .NET 2.0. The problem was that Outlook called the service, but the parameters where always null. In the samples they use SoapRpcMethodAttribute on all methods, instead of traditional SOAP message style. But you can just overlook all the attributes and just use the WebMethod attribute as usual. The entire code of the service is fairly short (less than 200 lines) and is included below.

#region Licence agreement
// Copyright (c) 2007, Jonas Follesø
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the Jonas Follesø nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY Jonas Follesø "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL Jonas Follesø BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#endregion

using System;
using System.IO;
using System.Web;
using System.Xml;
using System.Data;
using System.Text;
using System.Collections;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Security.Authentication;
using System.Collections.Generic;
using System.Web.Services.Description;
using System.ComponentModel;

using Ung1881;

namespace Ung1881OMS
{
    /// <summary>
    /// A WebService implementing the Outlook 2007 Mobile Service interface.
    /// Allows you to send SMS messages from Outlook 2007!
    /// </summary>
    [WebService(Namespace = "http://schemas.microsoft.com/office/Outlook/2006/OMS")]
    [WebServiceBinding(ConformsTo=WsiProfiles.BasicProfile1_1)]
    public class OMSService : System.Web.Services.WebService, IOutlookMobileService
    {
        /// <summary>
        /// Returns information about the service. The returned XML contains
        /// information about the service, if it supports SMS, MMS or both etc.
        /// See the ServiceInfo.xml for more information about the XML format.
        /// </summary>
        /// <returns></returns>
        [WebMethodAttribute()]
        public string GetServiceInfo()
        {
            return ReadXml("ServiceInfo.xml");
        }

        /// <summary>
        /// Method authenticating a user and geting user information.
        /// Returns an XML string with some basic user information (phone number and e-mail).
        /// </summary>
        /// <param name="xmsUser">An XML string containing the user credentials.</param>
        /// <returns>An XML string with user information.</returns>
        [WebMethodAttribute()]
        public string GetUserInfo(string xmsUser)
        {
            try
            {
                XmlDocument xml = new XmlDocument();
                xml.LoadXml(xmsUser);

                XmlNamespaceManager nmManager = new XmlNamespaceManager(xml.NameTable);
                nmManager.AddNamespace("o", "http://schemas.microsoft.com/office/Outlook/2006/OMS");                
                
                string username = xml.SelectSingleNode("/o:xmsUser/o:userId", nmManager).InnerText;
                string password = xml.SelectSingleNode("/o:xmsUser/o:password", nmManager).InnerText;

                Ung1881Proxy proxy = new Ung1881Proxy();
                proxy.Login(username, password);
                
                return ReadXml("UserInfo.xml");
            }
            catch (Exception)
            {
                StringWriter stringWriter = new StringWriter();
                XmlTextWriter xmlWriter = new XmlTextWriter(stringWriter);

                xmlWriter.WriteStartElement("userInfo", "http://schemas.microsoft.com/office/Outlook/2006/OMS");                
                
                xmlWriter.WriteStartElement("error");
                xmlWriter.WriteAttributeString("code", "invalidUser");
                xmlWriter.WriteAttributeString("severity", "failure");
                xmlWriter.WriteEndElement(); 
               
                xmlWriter.WriteEndElement();

                string error = stringWriter.GetStringBuilder().ToString();

                xmlWriter.Close();
                stringWriter.Dispose();

                return error;
            }
        }

        /// <summary>
        /// Method sending an SMS/MMS message to one or more recepients.
        /// </summary>
        /// <param name="xmsData">An XML string with the list of recepients and the content of the message.</param>
        /// <returns>An XML string with a status message.</returns>
        [WebMethodAttribute()]
        public string SendXms(string xmsData)
        {            
            XmlDocument xml = new XmlDocument();
            xml.LoadXml(xmsData);

            XmlNamespaceManager nmManager = new XmlNamespaceManager(xml.NameTable);
            nmManager.AddNamespace("o", "http://schemas.microsoft.com/office/Outlook/2006/OMS");

            string username = xml.SelectSingleNode("/o:xmsData/o:user/o:userId", nmManager).InnerText;
            string password = xml.SelectSingleNode("/o:xmsData/o:user/o:password", nmManager).InnerText;

            try
            {
                List<string> recipients = new List<string>();
                List<string> messages = new List<string>();

                foreach (XmlNode node in xml.SelectNodes("//o:recipient", nmManager))
                {
                    recipients.Add(node.InnerText);
                }

                foreach (XmlNode node in xml.SelectNodes("//o:content[@contentType='text/plain']", nmManager))
                {
                    messages.Add(node.InnerText);
                }

                Ung1881Client client = new Ung1881Client(username, password);

                foreach (string number in recipients)
                {
                    foreach (string message in messages)
                    {
                        client.SendMessage(number, message);
                    }
                }

                return BuildError("ok", false);;
            }
            catch (AuthenticationException)
            {
                return BuildError("invalidUser", true);
            }
            catch (Exception)
            {
                return BuildError("others", true);
            }
        }

        /// <summary>
        /// Simple helper method reading an file from disk and
        /// returning the content as a string.
        /// </summary>
        /// <param name="fileName">The relative path to the file you want to read.</param>
        /// <returns>The file content.</returns>
        private string ReadXml(string fileName)
        {
            StreamReader sr = new StreamReader(Server.MapPath(fileName), Encoding.Unicode);
            string xml = sr.ReadToEnd();
            sr.Dispose();
            return xml;
        }

        /// <summary>
        /// Simple helper method building the return XML for the SendXms method.
        /// </summary>
        /// <param name="errorCode">The error code.</param>
        /// <param name="failed">If this was a failure or not.</param>
        /// <returns>The XML fragment to return to the client.</returns>
        private string BuildError(string errorCode, bool failed)
        {
            StringWriter stringWriter = new StringWriter();
            XmlTextWriter wr = new XmlTextWriter(stringWriter);

            wr.WriteStartDocument();
            wr.WriteStartElement("xmsResponse", "http://schemas.microsoft.com/office/Outlook/2006/OMS");
            wr.WriteStartElement("error");
            wr.WriteAttributeString("code", errorCode);
            wr.WriteAttributeString("severity", failed ? "failure" : "neutral");
            wr.WriteEndElement();
            wr.WriteEndElement();
            wr.WriteEndDocument();

            wr.Close();
            string returnValue = stringWriter.GetStringBuilder().ToString();
            stringWriter.Dispose();
            return returnValue;
        }
    }
}

Once you have your service up and running you can add a new account in Outlook 2007. In the add account wizard, select "other" and "Outlook Mobile Service" as the account type. This will bring up the "Outlook Mobile Service Account" dialog. Here you enter the URL to the service and your user credentials.

 

Once you've created an Outlook Mobile Service account you get a new item in the "New" menu called "New Text Message". This brings up the new message dialog. When you send your message, Outlook will call your service and the SendXms method.

The installation process isn't as easy as I wish it was, since this is a server application you need to configure IIS. Outlook will only connect to HTTPS sites, so you need to create your own certificate as well. The screen cast walks you through this process. Scott Guthrie has a nice post on IIS7 and self signed certificates over at his blog

The next post in this Free SMS series will be an .NET 3.0 application for Windows XP users who don't have the Vista Sidebar available. Stay tuned! Please drop me a comment if you downloaded and installed the service and found it useful, or have any questions regarding Outlook 2007 Mobile Services.
 

TodoWhat a week! Both Office 2007 RTM and Windows Vista RTM is now available on MSDN. I downloaded and installed Office 2007 Monday. The download was only 450MB or something like that, so it actually took longer time to install it than to download it. The upgrade from Office 2003 was painless, all my settings, files and content was unchanged, as expected.

Fellow RD Scott Hanselman made a post about one of his new favorite features: The new insert menu in Outlook messages, and in particular the insert calendar function. Check out his post if you're curious what it's all about.

I figured I had to write a quick post my self about my favorite features after a week of Office 2007 usage:

1. The Outlook To-Do Bar: How did we get stuff done with out this guy? This seams to be "everyone's" favorite. Basically you get a bar on the right side of Outlook displaying the three next upcoming appointments, all tasks and all items that you want to follow up on.

2. RSS in Outlook: I know there are third party solutions out there for 2003, but it's something different when it comes "out of the box", tightly integrated with the platform. If I subscribe to a feed in IE, it automatically shows up in Outlook. When I hit "send and receive" the feeds get updated.

And guess what: You can tag and add follow up flags to any item in Outlook, including RSS items. So, for instance if there is a cool blog post I want to comment on I tag it as "interesting post, need comment", and mark it for follow up this week. This will off course make the RSS item show up in the To-Do bar as an item. If I double click the item in the To-Do bar I get directly to the post.

3. Smart art: Remember how "cool" WordArt was back in 1997? Well, 10 years have passed and we have a new kid on the block: Smart art. This thing is basically about adding graphical "stuff" to your document/presentation/mail. The "stuff" can be a simple chart, a cool looking table, a "flow chart" thingy etc.

The cool thing about Smart art is the ability to add "styles" on top of Smart art making it look ultra sweet. I don't think you can make Smart art look  bad even if you try. Well, perhaps you could, but you get my point.

4. The overall user experience: Office 2007 just looks amazing. Period. To many changes to mention them all

5. OneNote 2007 with Smartphone integration: OneNote 2007 have several new features. One of the cooler is the new OneNote Mobile version. You hade some Smartphone/Pocket PC integration in 2003, but it was limited to synchronizing audio recordings into OneNote. In 2007 you have a separate mobile client which allows you to take notes, capture pictures and add voice recordings to a new OneNote note. When you connect your mobile phone all the notes, including pictures and voice, get's imported into a notebook in OneNote.

For instance, if you take a photo of a poster or business card, the text becomes searchable trough text recognition. If you use your phone to record memos the audio becomes searchable trough voice recognition.

One of the main things I use the camera on my Qtek 8310 for is taking photos of posters to concerts/events I want to remember. When I walk the hallways at the university I come across interestin stuff daily that I take a snapshot off. The problem is remembering to get these pictures onto my computer before they become outdated. Using OneNote I get all my poster pictures directly on my computer.

You can off course synchronize from your computer to your cell phone. So for instance if you're going on a holiday you could include a map as an image file, the address to the hotel, your flight reservation number etc. in a single OneNote note, and have it synchronized to your mobile phone.

Read more on what you can do with OneNote Mobile at Chris Pratley’s blog.

<September 2010>
SunMonTueWedThuFriSat
2930311234
567891011
12131415161718
19202122232425
262728293012
3456789