Unified Communications @ PDC09

I love the PDC.  Before I joined Microsoft in 2000, I went to every PDC so I could evaluate the future of the Microsoft platform and integrate it into my development and architecture.

Since I joined the company, I’ve attended every PDC to share what we’re doing at Microsoft with regards to the future of the platform to start the conversation with other developers around feedback and early adoption.

From either side of the conversation, it’s always been worth getting out of the office.

Here are the 3 sessions we’ll have on the UC platform at PDC09:

Microsoft Unified Communications: Developer Platform Futures

Chris Mayo

Learn how Microsoft Communications Server and Microsoft Exchange provide a comprehensive and flexible communications platform for developers. Get a first look at the next generation of this platform through a series of demos and code examples. See how to embed Communicator features in your application using new Microsoft Silverlight and Windows Presentation Foundation (WPF) controls, and learn about the new API to develop full custom clients for Communications Server. Also see how the UC Managed API 3.0 provides access to the new Voice-over-IP features of Communication Server.

Integrating and Extending the Microsoft Office Communicator Experience with Windows Presentation Foundation and Microsoft Silverlight

David Ollason

Come take an in-depth look at how to integrate and extend the Office Communicator experience into your Windows Presentation Foundation (WPF) and Silverlight applications. See how to provide the same integration experience as Office and Outlook including contact search, contact lists, presence, contact details and more. Learn how to pass contextual data from your application using the new contextual conversation API.

 

The Exchange 2010 Developer Story: Building Rich Exchange-enabled Applications for the Enterprise and the Cloud

Jason Henderson

Learn how to make your application calendar or contact aware with the Exchange Web Services Managed API and Exchange Online. Get a first look at our new Exchange Web Services and Exchange Online developer story. See how developers can leverage the power of Azure and Exchange Web Services to create rich Software + Services solutions on Windows Presentation Foundation (WPF) or Microsoft Silverlight. Come learn how quick and easy it is to develop an Exchange Web Services application that can be deployed to millions of seats both on-premises and in the cloud.

When I’m not speaking or attending the other UC platform sessions, I’ll be in the Expo or at the evening events. 

I hope to see you there.

Thanks,

Chris

My Schedule at TechEd Europe 2009

I’ll be at TechEd Europe this year speaking on the future of the UC platform (OCS, OC, Exchange and Outlook) and meeting up with my European friends and colleagues.

I’m speaking at the following session:

UNC304 The State of the Art in Microsoft's Unified Communications Developer Platform (*PDC at TechEd)

Presenter: Chris Mayo

Tue 11/10 | 17:00-18:15 | Paris 1 - Hall 7-1c

Programmable Communications have become a reality over the last two years. Developers can now easily embed email, chat, and voice/video deeply into their software leveraging their .NET skills. This session gives an overview of the capabilities of the Microsoft Unified Communications platform and shows an in-depth code walk-through of key scenarios any developer can use in their software.

When I’m not in that session, I’ll be at the Expo in the UC booth and hanging out at the various evening events.

We’ve got over 60 sessions in the UC track this year for both developers and IT professionals (and those of us that do both).  You can get details on the track here:

http://www.msteched.com/europe/public/sessionlist.aspx

I hope to see you there.

Thanks,

Chris

Exchange 2010 and Exchange Web Services - What’s New Webcasts

Exchange Web Services gives you programmatic access to the information and business logic in Exchange 2010.  If you think about all the stuff you do in Outlook 2007 to manage your daily life (mail to communicate with friends and coworkers, calendar items to manage your day and tasks to track the things that you need to get done), all that information and business logic (think free/busy when scheduling a meeting) is provided by Exchange and accessible via the Exchange Web Services Managed API.

This is a quick video with Jason Henderson and David Claux of the EWS team to show what you can do with the new EWS Managed API and what’s new in Exchange 2010 for developers.

Get Microsoft Silverlight

Check out the following web casts to learn more. 

10/13/2009 - Exchange Server 2010 Development (Part 1 of 6): Migrating Applications to Exchange Web Services

10/14/2009 - Exchange Server 2010 Development (Part 2 of 6): A Deep Dive into Using Autodiscover Service in Exchange Web Services

10/15/2009 - Exchange Server 2010 Development (Part 3 of 6): A Deep Dive into Impersonation and Delegation in Exchange Web Services

10/20/2009 - Exchange Server 2010 Development (Part 4 of 6): A Deep Dive into Exchange Web Services Notifications (Push/Pull)

10/21/2009 - Exchange Server 2010 Development (Part 5 of 6): A Deep Dive into the Exchange Web Services Managed API

10/22/2009 - Exchange Server 2010 Development (Part 6 of 6): Best Practices for Building Scalable Exchange Server Applications

 

Thanks,

Chris

How to get presence using Office Communicator SDK

Displaying the presence information for the local user or their contacts is a common scenario when adding Unified Communications features to your client applications.   For example, after Office Communicator is installed, Outlook 2007 displays the presence of contacts on the To: and the From: line so the user can make intelligent communication decisions (“should I reply in email or are there enough people online that a concall would be better?”) directly in Outlook 2007.

Luckily, it’s easy to integrate presence information into your client applications.  This video shows a great example:

Let’s break down the code in the above video.  When displaying presence information, you need to get the initial value to display and then update your client UI when changes to presence elements occur.  In the code below, Messenger.GetContact() is used to get an instance of IMessengerContactAdvanced for displaying the initial presence information and the Messenger.OnMyStatusChange and Messenger.OnContactStatusChange events are used to get updated presence information:

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:   
   6:  using CommunicatorAPI;
   7:  using System.Runtime.InteropServices;
   8:   
   9:  namespace ContactPresence
  10:  {
  11:      class Program
  12:      {
  13:          private static Messenger _messenger;
  14:   
  15:          static void Main(string[] args)
  16:          {
  17:              _messenger = new Messenger();
  18:   
  19:              _messenger.OnContactStatusChange += 
  20:                  new DMessengerEvents_OnContactStatusChangeEventHandler(
  21:                      _messenger_OnContactStatusChange);
  22:              _messenger.OnMyStatusChange += 
  23:                  new DMessengerEvents_OnMyStatusChangeEventHandler(
  24:                      _messenger_OnMyStatusChange);
  25:   
  26:              IMessengerContactAdvanced localUser = 
  27:                  (IMessengerContactAdvanced)_messenger.GetContact(
  28:                  _messenger.MySigninName, _messenger.MyServiceId);
  29:   
  30:              if (localUser != null)
  31:              {
  32:                  DisplayContactPresence(localUser);
  33:              }   
  34:   
  35:              Console.WriteLine("\nPress Enter key to exit the application.\n");
  36:              Console.ReadLine();
  37:   
  38:              _messenger.OnContactStatusChange -= 
  39:                  new DMessengerEvents_OnContactStatusChangeEventHandler(
  40:                      _messenger_OnContactStatusChange);
  41:              _messenger.OnMyStatusChange -= 
  42:                  new DMessengerEvents_OnMyStatusChangeEventHandler(
  43:                      _messenger_OnMyStatusChange);
  44:   
  45:              System.Runtime.InteropServices.Marshal.ReleaseComObject(_messenger);
  46:              _messenger = null;
  47:              System.Runtime.InteropServices.Marshal.ReleaseComObject(localUser);
  48:              localUser = null;
  49:          }

In order to display presence information, I’ve created a function called DisplayContactPresence.  This function uses IMessengerContactAdvanced.PresenceProperties to access the presence for a contact (their status, availability, presence note, etc.).  For example, the following code writes all the presence information for a contact out to the console:

   1:          static void DisplayContactPresence(IMessengerContactAdvanced contact)
   2:          {
   3:              object[] presenceProps = (object[])contact.PresenceProperties;
   4:   
   5:              if (contact.IsSelf)
   6:              {
   7:                  Console.WriteLine("Local User Presence Info for {0}:", 
   8:                      contact.FriendlyName);
   9:              }
  10:              else
  11:              {
  12:                  Console.WriteLine("Contact Presence Info for {0}:", 
  13:                      contact.FriendlyName);
  14:              }
  15:   
  16:              // Status or Machine State.
  17:              Console.WriteLine("\tStatus: {0}", 
  18:                  (MISTATUS)presenceProps[(int)PRESENCE_PROPERTY.PRESENCE_PROP_MSTATE]);
  19:              Console.WriteLine("\tStatus String: {0}", 
  20:                  GetStatusString((MISTATUS) presenceProps[(int)PRESENCE_PROPERTY.PRESENCE_PROP_MSTATE]));
  21:              // Status string if status is set to custom.
  22:              Console.WriteLine("\tCustom Status String: {0}", 
  23:                  presenceProps[(int)PRESENCE_PROPERTY.PRESENCE_PROP_CUSTOM_STATUS_STRING]);
  24:   
  25:              // Presence or User state.
  26:              Console.WriteLine("\tAvailability: {0}", 
  27:                  presenceProps[(int)PRESENCE_PROPERTY.PRESENCE_PROP_AVAILABILITY]);
  28:              Console.WriteLine("\tAvailability String: {0}", 
  29:                  GetAvailabilityString((int) presenceProps[(int)PRESENCE_PROPERTY.PRESENCE_PROP_AVAILABILITY]));
  30:   
  31:              // Presence note.
  32:              Console.WriteLine("\tPresence Note: \n'{0}'", 
  33:                  presenceProps[(int)PRESENCE_PROPERTY.PRESENCE_PROP_PRESENCE_NOTE]);
  34:              // Blocked status.  
  35:              Console.WriteLine("\tIs Blocked: {0}", 
  36:                  presenceProps[(int)PRESENCE_PROPERTY.PRESENCE_PROP_IS_BLOCKED]);
  37:              // OOF message for contact, if specified.
  38:              Console.WriteLine("\tIs OOF: {0}", 
  39:                  presenceProps[(int)PRESENCE_PROPERTY.PRESENCE_PROP_IS_OOF]);
  40:              // Tooltip.
  41:              Console.WriteLine("\tTool Tip: \n'{0}'\n", 
  42:                  presenceProps[(int)PRESENCE_PROPERTY.PRESENCE_PROP_TOOL_TIP]);
  43:          }
  44:   
  45:          static string GetAvailabilityString(int availability)
  46:          {
  47:              switch (availability)
  48:              {
  49:                  case 3000:
  50:                      return "Available";
  51:                  case 4500:
  52:                      return "Inactive";
  53:                  case 6000:
  54:                      return "Busy";
  55:                  case 7500:
  56:                      return "Busy-Idle";
  57:                  case 9000:
  58:                      return "Do not disturb";
  59:                  case 12000:
  60:                      return "Be right back";
  61:                  case 15000:
  62:                      return "Away";
  63:                  case 18000:
  64:                      return "Offline";
  65:                  default:
  66:                      return "";
  67:              }
  68:          }
  69:   
  70:          static string GetStatusString(MISTATUS mStatus)
  71:          {
  72:              switch (mStatus)
  73:              {
  74:                  case MISTATUS.MISTATUS_ALLOW_URGENT_INTERRUPTIONS:
  75:                      return "Urgent interuptions only";
  76:                  case MISTATUS.MISTATUS_AWAY:
  77:                      return "Away";
  78:                  case MISTATUS.MISTATUS_BE_RIGHT_BACK:
  79:                      return "Be right back";
  80:                  case MISTATUS.MISTATUS_BUSY:
  81:                      return "Busy";
  82:                  case MISTATUS.MISTATUS_DO_NOT_DISTURB:
  83:                      return "Do no disturb";
  84:                  case MISTATUS.MISTATUS_IDLE:
  85:                      return "Idle";
  86:                  case MISTATUS.MISTATUS_INVISIBLE:
  87:                      return "Invisible";
  88:                  case MISTATUS.MISTATUS_IN_A_CONFERENCE:
  89:                      return "In a conference";
  90:                  case MISTATUS.MISTATUS_IN_A_MEETING:
  91:                      return "In a meeting";
  92:                  case MISTATUS.MISTATUS_LOCAL_CONNECTING_TO_SERVER:
  93:                      return "Connecting to server";
  94:                  case MISTATUS.MISTATUS_LOCAL_DISCONNECTING_FROM_SERVER:
  95:                      return "Disconnecting from server";
  96:                  case MISTATUS.MISTATUS_LOCAL_FINDING_SERVER:
  97:                      return "Finding server";
  98:                  case MISTATUS.MISTATUS_LOCAL_SYNCHRONIZING_WITH_SERVER:
  99:                      return "Synchronizing with server";
 100:                  case MISTATUS.MISTATUS_MAY_BE_AVAILABLE:
 101:                      return "Inactive";
 102:                  case MISTATUS.MISTATUS_OFFLINE:
 103:                      return "Offline";
 104:                  case MISTATUS.MISTATUS_ONLINE:
 105:                      return "Online";
 106:                  case MISTATUS.MISTATUS_ON_THE_PHONE:
 107:                      return "In a call";
 108:                  case MISTATUS.MISTATUS_OUT_OF_OFFICE:
 109:                      return "Out of office";
 110:                  case MISTATUS.MISTATUS_OUT_TO_LUNCH:
 111:                      return "Out to lunch";
 112:                  case MISTATUS.MISTATUS_UNKNOWN:
 113:                      return "Unknown";
 114:                  default:
 115:                      return string.Empty;
 116:              }
 117:          }

When the presence of the local user or any of their contacts changes, the Messenger.OnMyStatusChange and Messenger.OnContactStatusChange events fire, respectively:

   1:          static void _messenger_OnMyStatusChange(int hr, MISTATUS mMyStatus)
   2:          {
   3:              // Your code to work with presence goes here...
   4:              Console.WriteLine("\n***OnMyStatusChange***");
   5:   
   6:              DisplayContactPresence((IMessengerContactAdvanced) 
   7:                  _messenger.GetContact(_messenger.MySigninName, _messenger.MyServiceId));
   8:          }
   9:   
  10:          static void _messenger_OnContactStatusChange(object pMContact, MISTATUS mStatus)
  11:          {
  12:              // Your code to work with presence goes here...
  13:              Console.WriteLine("\n***OnContactStatusChange***");
  14:   
  15:              DisplayContactPresence((IMessengerContactAdvanced) pMContact);
  16:          }

One thing to note, both events have a MISTATUS value passed to provide the current status of the contact.  Using IMessengerContactAdvanced.PresenceProperties is preferred to using this value since it provides access to all the presence information for a contact, not just status.

If you’d like to try this code out for yourself, you’ll need to download the Office Communicator 2007 SDK and setup a UC development environment.

You can download the WPF Presence Controls for Office Communicator 2007 example used in the first demo to see how this code is used in a solution.

More details, tips and tricks on UC development can be found in the Programming for Unified Communications book.

Thanks,

Chris

How to save IM conversations using Office Communicator SDK

Archiving the contents of an IM conversation using the Office Communicator SDK is something that I get asked about pretty routinely.  For example, let’s say that you want to launch an IM call from your application using the OC SDK and archive that conversation to be retrieved later (displaying all the application specific conversations in your application or on a SharePoint site, etc.).

The OC SDK provides the IMessengerConversationWndAdvanced.History property to access the body of an IM conversation.  For example, the following console application launches an IM call and then writes out the IM history to the console:

   1:  namespace History
   2:  {
   3:      class Program
   4:      {
   5:          private static Messenger _messenger;
   6:          private static IMessengerAdvanced _messengerAdv;
   7:   
   8:          private static long _myConvHWND = 0;
   9:          private static IMessengerConversationWndAdvanced _myConv;
  10:   
  11:          static void Main(string[] args)
  12:          {
  13:              _messenger = new Messenger();
  14:              _messengerAdv = (IMessengerAdvanced)_messenger;
  15:   
  16:              _messenger.OnIMWindowCreated +=
  17:                  new DMessengerEvents_OnIMWindowCreatedEventHandler(
  18:                  _messenger_OnIMWindowCreated);
  19:              _messenger.OnIMWindowDestroyed += 
  20:                  new DMessengerEvents_OnIMWindowDestroyedEventHandler(
  21:                  _messenger_OnIMWindowDestroyed);
  22:   
  23:              object[] sipUris = new object[] { "kf@fabrikam.com", "cb@fabrikam.com"  };
  24:   
  25:              object obj = _messengerAdv.StartConversation(
  26:                  // The call media.            
  27:                  CONVERSATION_TYPE.CONVERSATION_TYPE_IM,
  28:                  // The participants.
  29:                  sipUris,
  30:                  // Not supported.
  31:                  null,
  32:                  // The conversation window title as as string.
  33:                  "Account: Johnson (ID:12345)",
  34:                  // Not supported.  Pass "1".
  35:                  "1",
  36:                  // Not supported.
  37:                  null);
  38:   
  39:              _myConvHWND = long.Parse(obj.ToString());
  40:   
  41:              Console.WriteLine(
  42:                  "Press the Enter key to see IM conversation History.");
  43:              Console.ReadLine();
  44:   
  45:              if (_myConv != null)
  46:              {
  47:                  try
  48:                  {
  49:                      Console.WriteLine(_myConv.History);
  50:                  }
  51:                  catch (COMException ce)
  52:                  {
  53:                      Console.WriteLine(
  54:                          "COM Exception " + ce.ErrorCode.ToString());
  55:                  }
  56:              }
  57:   
  58:              Console.WriteLine("Press the Enter key to exit the application.");
  59:              Console.ReadLine();
  60:   
  61:              _messenger.OnIMWindowCreated -=
  62:                  new DMessengerEvents_OnIMWindowCreatedEventHandler(
  63:                  _messenger_OnIMWindowCreated);
  64:              _messenger.OnIMWindowDestroyed -=
  65:                  new DMessengerEvents_OnIMWindowDestroyedEventHandler(
  66:                  _messenger_OnIMWindowDestroyed);
  67:   
  68:              Marshal.ReleaseComObject(_messenger);
  69:              _messenger = null;
  70:              Marshal.ReleaseComObject(_messengerAdv);
  71:              _messengerAdv = null;
  72:   
  73:              if (_myConv != null)
  74:              {
  75:                  Marshal.ReleaseComObject(_myConv);
  76:                  _myConv = null;
  77:              }
  78:          }

In the code above, I’m registering for the OnIMWindowCreated and OnIMWindowDestroyed events to get and release my reference to the conversation window (_myConv) so I can access the History property.  The code below shows how I manage the _myConv reference:

   1:          static void _messenger_OnIMWindowCreated(object pIMWindow)
   2:          {
   3:              IMessengerConversationWndAdvanced newConv =
   4:                  (IMessengerConversationWndAdvanced)pIMWindow;
   5:   
   6:              if (newConv.HWND == _myConvHWND)
   7:              {
   8:                  newConv.SendText("This is a ongoing conversation " +
   9:                      "about the Account: Johnson (ID:12345) " +
  10:                      "and will be saved on the account site.");
  11:                  
  12:                  _myConv = newConv;
  13:              }
  14:          }
  15:   
  16:          static void _messenger_OnIMWindowDestroyed(object pIMWindow)
  17:          {   
  18:              if (object.ReferenceEquals((object)_myConv, pIMWindow))
  19:              {
  20:                  Marshal.ReleaseComObject(_myConv);
  21:                  _myConv = null;
  22:              }
  23:          }

In OnIMWindowCreated, I set _myConv using the pIMWindow object passed as an event argument after confirming it’s the conversation I started in code (by comparing the HWNDs).  When OnIMWindowDestroyed fires, I check to make sure the window being destroyed is mine by using object.ReferenceEquals and release the reference.  Note that I can’t use the HWND property in OnIMWindowDestroyed since conversation window no longer exists and _myConv is no longer a valid reference.

While this code works, it’s not an ideal solution.  I can’t rely on the user to do something (click a button, etc.) in my app before the conversation is closed.  I’d rather just write the IM conversation history out when the conversation is completed.  This leads a lot of developers to try the following:

   1:          static void _messenger_OnIMWindowDestroyed(object pIMWindow)
   2:          {   
   3:              if (object.ReferenceEquals((object)_myConv, pIMWindow))
   4:              {
   5:                  Console.WriteLine(_myConv.History);
   6:   
   7:                  Marshal.ReleaseComObject(_myConv);
   8:                  _myConv = null;
   9:              }
  10:          }

But, the call to IMessengerConversationWndAdvanced.History throws an exception since _myConv is no longer a valid reference when OnIMWindowDestroyed fires.

Another solution I’ve seen is polling History on another thread through the life of the conversation and writing out the last value when the conversation window is destroyed.  While this works, it’s less than ideal due to the resource you consume.

So what does provide a good working scenario?  Creating a UCMA 2.0 IM robot that archives conversations and inviting that bot to all the conversations you want archived is a great solution (and a great future blog post).

Details on how to start conversations using the Office Communicator SDK can be found in the How to make calls via Office Communicator SDK and How to send IM text using Office Communicator SDK posts on this blog.

If you’d like to try this code out for yourself, you’ll need to download the Office Communicator 2007 SDK and setup a UC development environment.

More details, tips and tricks on UC development can be found in the Programming for Unified Communications book.

Thanks,

Chris

How to send IM text using Office Communicator SDK

When starting call from your application using the Office Communicator Automation API, it’s often helpful to send some IM text to provide some context for the call (often using data from your application).  For example, Outlook 2007 does this when you start a conversation using the IM and Call features from an email.

SendText_01 

When the call is placed, Outlook 2007 uses the OC API to set the conversation window title and to provide details on the subject of the call (the email) via IM.

SendText_03 

Here is a quick video that shows how to send IM text using the Office Communicator Automation API: 

Let’s break down some of the details from the video.  First, the IMessengerAdvanced.StartConversation() method is used to start the call.  Once the call is accepted by the callee, a conversation window is created that I can use to send IM as part of the call. Due to the asynchronous nature of the OC API, this conversation window doesn’t get created right away.  Luckily, the StartConversation() method returns the HWND of the conversation window so I can identify it in code when it is created.  Registering for the OnIMWindowCreated event will give me access the conversation window when that happens.  For example, the following code registers for the OnIMWindowCreated event, starts a new audio call and stores the HWND of conversation window to be created in a local variable _myConvHWND:

   1:  namespace StartConversation
   2:  {
   3:      class Program
   4:      {
   5:          private static Messenger _messenger;
   6:          private static IMessengerAdvanced _messengerAdv;
   7:   
   8:          private static long _myConvHWND = 0;
   9:   
  10:          static void Main(string[] args)
  11:          {            
  12:              _messenger = new Messenger();
  13:              _messengerAdv = (IMessengerAdvanced)_messenger;
  14:   
  15:              _messenger.OnIMWindowCreated += new DMessengerEvents_OnIMWindowCreatedEventHandler(_messenger_OnIMWindowCreated);
  16:   
  17:              object[] sipUris = new object[] { "kf@fabrikam.com" };
  18:   
  19:              object obj = _messengerAdv.StartConversation(
  20:                  // The call media.            
  21:                  CONVERSATION_TYPE.CONVERSATION_TYPE_AUDIO,
  22:                  // The participants.
  23:                  sipUris,
  24:                  // Not supported.
  25:                  null,
  26:                  // The conversation window title as as string.
  27:                  "My Audio Call with IM as Context",
  28:                  // Not supported.  Pass "1".
  29:                  "1",
  30:                  // Not supported.
  31:                  null);
  32:   
  33:              _myConvHWND = long.Parse(obj.ToString());
  34:   
  35:              Console.WriteLine("Press the Enter key to exit the application.");
  36:              Console.ReadLine();
  37:   
  38:              _messenger.OnIMWindowCreated -= new DMessengerEvents_OnIMWindowCreatedEventHandler(_messenger_OnIMWindowCreated);
  39:   
  40:              Marshal.ReleaseComObject(_messenger);
  41:              _messenger = null;
  42:              Marshal.ReleaseComObject(_messengerAdv);
  43:              _messengerAdv = null;
  44:          }

When OnIMWindowCreated fires, it passes a reference to the conversation window via the IMessengerConversationWindowAdvanced interface.  I can use the HWND property on this interface to see if the conversation is the one I created with StartConversation() and send some IM using the SendText() method.  I need to check the HWND since OnIMWindowCreated will fire for every new conversation windows created by OC 2007 R2 (incoming or outgoing).  For example:

   1:          static void _messenger_OnIMWindowCreated(object pIMWindow)
   2:          {
   3:              IMessengerConversationWndAdvanced newConv = (IMessengerConversationWndAdvanced)pIMWindow;
   4:   
   5:              if (newConv.HWND == _myConvHWND)
   6:              {
   7:                  newConv.SendText("This IM was sent via SendText()...");
   8:              }
   9:          }

Using the SendText() method to provide some application data in the IM channel is a great way to add value to the calls you launch from your application.  Using the Outlook 2007/Office Communicator 2007 R2 integration as an example, you can start to think of ways that you can provide context to the calls your application launches using data from your application.

If you’d like to try this code out for yourself, you’ll need to download the Office Communicator 2007 SDK and setup a UC development environment.

More details, tips and tricks on UC development can be found in the Programming for Unified Communications book.

Thanks,

Chris

Posted 29 August 09 11:32 by cmayo | 0 Comments   
Filed under ,
How to make calls via Office Communicator SDK

Starting Office Communicator calls from your code is one of the simplest and most powerful features you can add to your application using the Office Communicator Automation API. 

This video shows some examples of the types of calls you can start in your code:

Let’s dive into the code.  When making calls via the Office Communicator Automation API you call the IMessengerAdvanced.StartConversation() method and specify the participants, the media type (IM, audio, video) and any call specific information (such as the conversation window title).  You get a reference to the IMessengerAdvanced interface by casting an instance of Messenger class.

For example, the following console application code starts an IM call with a single contact (kf@fabrikam.com) and sets the title of the conversation window to “My IM Call”:

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:   
   6:  using CommunicatorAPI;
   7:  using System.Runtime.InteropServices;
   8:   
   9:  namespace StartConversation
  10:  {
  11:      class Program
  12:      {
  13:          private static Messenger _messenger;
  14:          private static IMessengerAdvanced _messengerAdv;
  15:   
  16:          static void Main(string[] args)
  17:          {
  18:              _messenger = new Messenger();
  19:              _messengerAdv = (IMessengerAdvanced)_messenger;
  20:   
  21:              object[] sipUris = new object[] { "kf@fabrikam.com" };
  22:   
  23:              _messengerAdv.StartConversation(
  24:                  // The call media.            
  25:                  CONVERSATION_TYPE.CONVERSATION_TYPE_IM,
  26:                  // The participants.
  27:                  sipUris,
  28:                  // Not supported.
  29:                  null,
  30:                  // The conversation window title as as string.
  31:                  "My IM Call",
  32:                  // Not supported.  Pass "1".
  33:                  "1",
  34:                  // Not supported.
  35:                  null);
  36:   
  37:              Console.WriteLine("Press the Enter key to exit the application.");
  38:              Console.ReadLine();
  39:   
  40:              Marshal.ReleaseComObject(_messenger);
  41:              _messenger = null;
  42:              Marshal.ReleaseComObject(_messengerAdv);
  43:              _messengerAdv = null;
  44:          }
  45:      }
  46:  }

Changing the call media is just a matter of passing a different value from the CONVERSATION_TYPE enum.  For example, the follow code starts an audio call:

   1:              _messengerAdv.StartConversation(
   2:                  // The call media.            
   3:                  CONVERSATION_TYPE.CONVERSATION_TYPE_AUDIO,
   4:                  // The participants.
   5:                  sipUris,
   6:                  // Not supported.
   7:                  null,
   8:                  // The conversation window title as as string.
   9:                  "My Audio Call",
  10:                  // Not supported.  Pass "1".
  11:                  "1",
  12:                  // Not supported.
  13:                  null);

Starting a conference is just a matter of starting a call with multiple participants.  For example, the following code starts a video conference:

   1:              object[] sipUris = new object[] { "kf@fabrikam.com", "cb@fabrikam.com" };
   2:   
   3:              _messengerAdv.StartConversation(
   4:                  // The call media.            
   5:                  CONVERSATION_TYPE.CONVERSATION_TYPE_VIDEO,
   6:                  // The participants.
   7:                  sipUris,
   8:                  // Not supported.
   9:                  null,
  10:                  // The conversation window title as as string.
  11:                  "My Video Conference",
  12:                  // Not supported.  Pass "1".
  13:                  "1",
  14:                  // Not supported.
  15:                  null);

If you’d like to try this code out for yourself, you’ll need to download the Office Communicator 2007 SDK and setup a UC development environment.

More details, tips and tricks on UC development can be found in the Programming for Unified Communications book.

Thanks,

Chris

Posted 20 August 09 07:53 by cmayo | 0 Comments   
Exchange 2010 RC available now

Details can be found at the Exchange Team Blog.

Thanks,

Chris

Posted 19 August 09 03:03 by cmayo | 0 Comments   
Microsoft LifeCam Cinema 720p HD webcam

HD support is coming to webcams.  Understandably, I spend a lot of time in virtual meetings in front of a webcam and lately I’ve been looking for something that would, well, improve my image (no pun intended).

News of the new LifeCam Cinema with HD support hit the gadget sites today.  Honestly, I plan on getting one of these as soon as they come out (if I can’t score one earlier, that is).  Now I just need to do something about the light in my office, which tends to make me look a bit ‘undead’.

You can find details on the LifeCam Cinema in this post.

Posted 19 August 09 02:26 by cmayo | 0 Comments   
PDC09 registration open, Unified Communications Futures session posted

Before I joined Microsoft back in 2000, if I could only attend one conference a year it would be the PDC.  The opportunity to get a firsthand look at the future of the Microsoft platform and provide feedback directly to the product teams just couldn’t be passed up.  Other conferences do a great job showing how to get things done today, the PDC is all about how to get things done in the future. 

Now that I’m with Microsoft and in a role where I focus on the future of the Unified Communications Platform, I feel the same way.  I wouldn’t miss PDC09 for anything.  At the PDC last year, we shared details on the platform we released along with Office Communications Server 2007 R2 and Exchange 2010 and provided details on v.Next.

At PDC09, we’ll share specific details v.Next, including the UC product futures (including Office Communications Server, Office Communicator and Exchange) and platform futures (both client and server side) as well as sharing details on early adopter programs.

Details on registering for PDC09 and the Microsoft Unified Communications: Developer Platform Futures can be found on the PDC09 site.  You can watch the UC futures session at PDC08 to get a hint of what is coming.

Let’s get together while we’re there.

 

Thanks,

Chris.

What’s new in Office Communicator Mobile 2007 R2?

A nice write up of the new OC Mobile 2007 R2 features, including:

  • Joining OCS hosted conferences with one click.
  • Making outbound calls via your work number.
  • Windows Mobile 6.5 support.

Check out the Office Communicator Just Got Better post on the Communicator Team Blog.

Posted 14 August 09 07:18 by cmayo | 0 Comments   
Filed under
Getting sign in/sign out status via Office Communicator 2007 SDK

When using the Office Communicator 2007 SDK, you need to make sure that OC is running and signed in before you use classes from the SDK.  I often get email from developers new to the OC SDK who are getting errors when they try to debug their first applications.  For example, if OC 2007 R2 is not running on the client machine, you’ll get the following COMException when you try to create a instance of the Messenger class:

“Creating an instance of the COM component with CLSID {8885370D-B33E-44B7-875D-28E403CF9270} from the IClassFactory failed due to the following error: 80040111.”

Or, if Office Communicator is running but the user has not signed in, you’ll get the following error trying to access your instance of the Messenger class:

“Exception from HRESULT: 0x8100031E” (an error code that translates to not logged on if you refer to the OC SDK documentation).

So, how do you make sure OC 2007 R2 is running and signed in before you enable your OC SDK features (and disable them when that status changes)? 

This video shows as example of this in a simple console application:

Chris – Added video.

To see if Office Communicator is running, read the HKEY_CURRENT_USER\Software\IM Providers\Communicator\UpAndRunning value via code:

   1:          static bool IsCommunicatorRunning()
   2:          {
   3:              return Convert.ToInt32(Microsoft.Win32.Registry.CurrentUser
   4:                              .OpenSubKey("Software").OpenSubKey("IM Providers")
   5:                              .OpenSubKey("Communicator").GetValue("UpAndRunning", 1)) == 2;
   6:          }

If this registry value is 2, OC is up and running and you’re able to create instances of Messenger class.  Messenger class can be used to wire up events to track changes to Office Communicator or the sign in status of the local user and query the initial sign in status of the local user.  For example, the following code does just that:

   1:          private static Messenger _messenger;
   2:          private static bool _signedIn = false;
   3:   
   4:          static void Main(string[] args)
   5:          {
   6:              if (IsCommunicatorRunning())
   7:              {
   8:                  _messenger = new Messenger();
   9:   
  10:                  _messenger.OnAppShutdown += new DMessengerEvents_OnAppShutdownEventHandler(_messenger_OnAppShutdown);
  11:                  _messenger.OnSignin += new DMessengerEvents_OnSigninEventHandler(_messenger_OnSignin);
  12:                  _messenger.OnSignout += new DMessengerEvents_OnSignoutEventHandler(_messenger_OnSignout);
  13:   
  14:                  if ((_messenger.MyStatus & MISTATUS.MISTATUS_ONLINE) == MISTATUS.MISTATUS_ONLINE)
  15:                  {
  16:                      _signedIn = true;
  17:                  }
  18:                  else
  19:                  {
  20:                      _signedIn = false;
  21:                  }
  22:   
  23:                  Console.WriteLine("\nPress Enter key to exit the application.\n");
  24:                  Console.ReadLine();
  25:   
  26:                  _messenger.OnAppShutdown -= new DMessengerEvents_OnAppShutdownEventHandler(_messenger_OnAppShutdown);
  27:                  _messenger.OnSignin -= new DMessengerEvents_OnSigninEventHandler(_messenger_OnSignin);
  28:                  _messenger.OnSignout -= new DMessengerEvents_OnSignoutEventHandler(_messenger_OnSignout);
  29:   
  30:                  Marshal.ReleaseComObject(_messenger);
  31:                  _messenger = null;
  32:              }
  33:          }

The following line sets the initial value of the _signedIn by using Messenger.MyStatus and the & operator, evaluating to true if the local user is in any of the online states (any value other than Offline or Unknown including Online, In a Call, etc.):

   1:                  if ((_messenger.MyStatus & MISTATUS.MISTATUS_ONLINE) == MISTATUS.MISTATUS_ONLINE)

The _signedIn value is kept up to date via the Messenger class events for signed in status:

   1:          static void _messenger_OnSignout()
   2:          {
   3:              _signedIn = false;
   4:          }
   5:   
   6:          static void _messenger_OnSignin(int hr)
   7:          {
   8:              if (hr == 0)
   9:              {
  10:                  _signedIn = true;
  11:              }
  12:          }
  13:   
  14:          static void _messenger_OnAppShutdown()
  15:          {
  16:          }

Note: OnSignOut will always fire before OnAppShutdown, so setting _signedIn to false during OnSignOut is enough to keep your application up to date.

If you’d like to try this code out for yourself, you’ll need to download the Office Communicator 2007 SDK and setup a UC development environment.

More details, tips and tricks on UC development can be found in the Programming for Unified Communications book. 

 

Thanks,

Chris

Posted 13 August 09 06:44 by cmayo | 0 Comments   
Programming for Unified Communications with Microsoft® Office Communications Server 2007 R2 is Available Now!

The book is now available.  When writing this book, we wanted to create a single reference for getting started with UC development quickly as well as providing the insight, guidance and tips and tricks necessary to help your projects succeed.  I’m really happy with the result.

 

I was amazed how much I learned across the different APIs while searching for the pivotal nuggets of information to include in the book.  I hope you enjoy reading it as much as I enjoyed writing it!

 

Thanks,

Chris

Posted 05 June 09 01:09 by cmayo | 0 Comments   
Programming for Unified Communications Excerpts now on MS Press Blog

If you’d like a taste of the book, check out some excerpts here.

The book has not been released yet, but it available for preorder just about everywhere geeky/techy books are sold, like here.

 

Thanks,

Chris

Posted 01 June 09 12:30 by cmayo | 3 Comments   
We’d like your feedback…

If you attended my session on the Office Communicator Automation API, I’m going to be posting the community project for this API on CodePlex soon.  The rest of the community project team and I are reviewing/discussing some last minute details…

 

In the mean time, we’d like to get your feedback on what it’s like to be a developer using the Unified Communication platform SDKs.  We’ve put together a short survey with Frost and Sullivan to make it as easy as possible for you to give us feedback. 

 

For example, what UC applications have you developed?  What communication features or scenarios are most important to you? What other communications tools besides Microsoft’s Unified Communications products (like Office Communications Server, Office Communicator and Exchange) are you using?  What could we do could do to better help the UC developer community?

 

If you are a developer of Unified Communications applications such as OCS and Communicator, we’d appreciate you taking 10 minutes and to fill out this survey:

http://www.globaltestmarket.com/survey/s.phtml?sn=134581&lang=E&secid=9f8cbb

When you click the link you will be directed to a secured site hosted by Frost and Sullivan to fill out the survey.  The site requires cookies to be enabled.  Your individual responses will be kept confidential and anonymous.

 

We’ll use the results of this survey to shape our plans around developing resources to help you build enterprise software using the Microsoft Unified Communications platform.

 

Thanks,

Chris

Posted 27 May 09 06:42 by cmayo | 1 Comments   
More Posts Next page »

Search

This Blog

Syndication

Page view tracker