• Wiz/dumb

    Moving your apps to Office 2010

    • 0 Comments

    The Office team put out some Channel9 videos and some tools to help you get your add-ins and applications onto the Office 2010 platform.

    http://channel9.msdn.com/learn/courses/Office2010/AppCompatUnit/

  • Wiz/dumb

    Rude Operator

    • 0 Comments

    If you are automating Outlook in a standalone application or other app outside of Outlook and have trouble on some machines with your CreateObject call succeeding when Outlook is not already running, this article may be for you.

    Have you ever called someone only to be put on hold as soon as they answer? Do you hang up immediately, or do you hold on for a few minutes to see if they pick up? If you’ve ever ordered a pizza where I order mine, I know you’ve experienced this. Well, it turns out, Outlook [or any Office application for that matter] acts just like this rude operator. When you try to automate Outlook, the Outlook.exe process has to be running in order to serve your requests. Outlook is what’s called a COM server. So your call to CreateObject (or "new”) makes a call into the COM subsystem which does the work of spinning up an instance of Outlook for you to work from using the –Embedding switch which tells Outlook not to display any UI by default. Part of Outlook’s start up logic involves loading all the COM add-ins and calling into the OnConnect and OnStartupComplete events. This is where things could go badly for you.

    If your user is an comaddinophile they may have some add-ins installed that take a looooooong time to load. They may be calling into a database or a webservice or just have really poor code that takes a long time to execute. Outlook does all this work on its main thread – they aren’t spun off to a background thread – so all the time it takes for these add-ins to load and run is time the COM subsystem is spending growing very impatient. It can, after a while, just time out or it could succeed the initial load, but if Outlook is busy handling other requests your call to get the Application dispatch object could be actively refused because Outlook is blocking. In these cases, you could end up with a RPC_E_SERVERCALL_RETRYLATER error bubbling up in your .net automation code. The error you get will be something like “Call was rejected by callee.”

    Oftentimes, you can follow up your failed CreateObject call with a second one and it succeeds because at this time Outlook.exe is running and may be unblocked and ready to service your request. However, it may just block again. In these cases, you will need to implement an IMessageFilter to be able to tell the COM subsystem that you’re ok waiting and to keep retrying your call until it succeeds or you get a different error.

    The best sample I found for this was describing implementing this to solve this same problem when doing Visual Studio automation, but the same logic applies. Andrew Whitechapel wrote a sample also. In his case he was describing a similar problem when you try to make object model calls on a background thread from an add-in. Here’s a VB.NET sample I wrote.

    Public Class MessageFilter
        Implements IOleMessageFilter

        Public Shared Sub Register()
            Dim newFilter As IOleMessageFilter = New MessageFilter()
            Dim oldFilter As IOleMessageFilter = Nothing
            CoRegisterMessageFilter(newFilter, oldFilter)
        End Sub

        Public Shared Sub Revoke()
            Dim oldFilter As IOleMessageFilter = Nothing
            CoRegisterMessageFilter(Nothing, oldFilter)
        End Sub
        Public Function HandleInComingCall(ByVal dwCallType As Integer, ByVal hTaskCaller As System.IntPtr, ByVal dwTickCount As Integer, ByVal lpInterfaceInfo As System.IntPtr) As Integer Implements IOleMessageFilter.HandleInComingCall
            Return 0
        End Function

        Public Function MessagePending(ByVal hTaskCallee As System.IntPtr, ByVal dwTickCount As Integer, ByVal dwPendingType As Integer) As Integer Implements IOleMessageFilter.MessagePending
            Return 2
        End Function

        Public Function RetryRejectedCall(ByVal hTaskCallee As System.IntPtr, ByVal dwTickCount As Integer, ByVal dwRejectType As Integer) As Integer Implements IOleMessageFilter.RetryRejectedCall
            If (dwRejectType = 2) Then
                Return 99
            Else
                Return -1
            End If
        End Function


        <DllImport("Ole32.dll")>
        Private Shared Function CoRegisterMessageFilter(ByVal newFilter As IOleMessageFilter, ByRef oldFilter As IOleMessageFilter) As Integer
        End Function

    End Class



    <ComImport(), Guid("00000016-0000-0000-C000-000000000046"),
        InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)>
    Public Interface IOleMessageFilter
        <PreserveSig()>
        Function HandleInComingCall(
                                   ByVal dwCallType As Integer,
                                   ByVal hTaskCaller As IntPtr,
                                   ByVal dwTickCount As Integer,
                                   ByVal lpInterfaceInfo As IntPtr) As Integer

        <PreserveSig()>
        Function RetryRejectedCall(
                 ByVal hTaskCallee As IntPtr,
                ByVal dwTickCount As Integer,
                ByVal dwRejectType As Integer) As Integer

        <PreserveSig()>
        Function MessagePending(
                ByVal hTaskCallee As IntPtr,
                ByVal dwTickCount As Integer,
                ByVal dwPendingType As Integer) As Integer


    End Interface

    To use it, just drop that in your code and then wrap your automation code like this:

    Private Sub Automate()

        MessageFilter.Register()

        Try

            Dim myOutApp As Outlook.Application = New Outlook.Application()
            Dim myOutNS As Outlook.NameSpace = myOutApp.Session
            Dim myOutlookFolder As Outlook.MAPIFolder

            myOutlookFolder = myOutNS.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox)

            MessageBox.Show(String.Format("{0} unread items in Inbox.", myOutlookFolder.UnReadItemCount))

            System.Runtime.InteropServices.Marshal.ReleaseComObject(myOutlookFolder)
            System.Runtime.InteropServices.Marshal.ReleaseComObject(myOutNS)
            System.Runtime.InteropServices.Marshal.ReleaseComObject(myOutApp)


        Catch ex As Exception

            'Handle Exception

        Finally

            MessageFilter.Revoke()

        End Try
    End Sub

    The important part to notice is the calls to MessageFilter.Register and MessageFilter.Revoke.

  • Wiz/dumb

    Introducing The Outlook Social Connector Provider Proxy Library

    • 0 Comments

    You may have heard of OfficeTalk. You may have heard of the Outlook Social Connector. As it turns out, my team is responsible for supporting developers building Outlook Social Connector (OSC) providers for their social networks. As a means of learning about how the technology works in preparing myself and my team for supporting this new technology, I decided to take on the challenge of building an OSC provider for OfficeTalk. It turned out pretty well and I learned a lot about the OSC and what sort of things our customers will be experiencing as they build their own connectors. That’s not really the point of this post though. In building OfficeTalkOSC I decided that it would be a great thing to have a library which sort of served as a buffer between the providers and the OSC itself and wrapped a lot of the logic that is confusing and problematic to implement. So I came up with the OSC Provider Proxy Library. The library should allow .NET developers to focus on the implementation of their business logic instead of the complexities of building an OSC provider from scratch.

    This library is implemented in .NET Framework v4.0 (RTM’d today). It boils the 4 interfaces the OSC requires down to just one. It abstracts the work of maintaining the XML schema rules and provides a nice object model around activities and templates.

    I would strongly suggest reading the documentation on building an OSC provider from here first. This will provide a very strong foundation for what it takes to build an OSC provider and will make the OSCProvider library much more intuitive.

    Once you’ve read that documentation and you’re ready to begin, you can download the library and documentation from here: http://code.msdn.microsoft.com/oscprovider

    Please also provide feedback using the Issue Tracker (for bugs and feature requests) and the Discussions tab for general praise and adoration.

    This isn’t like an officially supported binary or anything like that (though you are welcome to use it) so their may be breaking changes between releases, but I’ll try to keep them to a minimum and document when those types of changes occur….I said “try”. :)

  • Wiz/dumb

    How To Programmatically Access Exchange 2010 Archive Mailboxes

    • 5 Comments

    Archive mailboxes are a new concept in Exchange 2010 that solve some of the problems inherent in PST archives – the primary of which being that there’s no way to access your PST files from a different machine. Archive mailboxes solve this by providing you a second mailbox you can use to archive mail from your primary mailbox in a location that is accessible via OWA and from other computers.

    In a future release, there should be functionality to access these archive mailboxes with web services, but as of the time of this writing, there’s no way to access the archive mailboxes with EWS.

    You can, however access these new mailboxes with MAPI. You simply pass the legacy DN of the mailbox into IExchangeManageStore::CreateStoreEntryId to create an ENTRYID you can use in your call to OpenMsgStore. The LegacyDN you need can be retrieved from a call to the new SOAP AutoDiscover service. Simply call GetUserSettings and include the AlternateMailboxes setting in your RequestedSettings value. If you get a result in this property, and it looks just like your UserDN but with an added /guid=<some guid> at the end, then that’s your archive mailbox.

  • Wiz/dumb

    That’s My Name, Don’t Wear It Out

    • 0 Comments
    Part 1

    It used to be in earlier versions of Exchange, you were able to change the names of the “special” folders, like Inbox, Calendar, Tasks, etc. This is because MAPI keeps track of the Entry ID for these special folders in properties stored on the root folder. As long as the folder never got deleted, the Entry ID for that folder would work, and if it ever did, we simply updated the Entry ID we had stored.

    It was always risky to do that though, because if you were using a path or URL that was defined by the display name of the folder, you could break yourself. So we locked down certain APIs, such as OOM (http://support.microsoft.com/kb/831363) to not allow you to update the display name on some special folders. EWS and OWA had the same limitation in Exchange 2007 (and continue to in Exchange 2010). As you are probably aware, EWS and OWA use an internal API dubbed “XSO” for communicating with the information store. What’s new in Exchange 2010 is that we moved MAPI to the middle tier, into a process we call RPC Client Access. So now, Outlook, CDO 1.21, and all other MAPI applications talk to the CAS server instead of talking to the mailbox role directly.All the MAPI logic gets funneled through XSO as it goes to the store. Because we’re going through XSO now, we are subject to the same constraints that EWS and OWA endure. This means that MAPI can now no longer update the PidTagDisplayName property on special folder types.

    For a list of folder types that cannot be renamed, run this PowerShell command in EMS: [System.Enum]::GetNames([Microsoft.Exchange.Data.Storage.DefaultFolderType])

    This is obviously just an enumeration that includes members such as “None”, so use your common sense to decipher this list, but you should get the idea of which folders these enumeration values are referring to.

    We saw this new truth surface recently with a customer who was attempting a CopyTo operation on a message store object in MAPI. As MAPI went through each folder attempting to SetProps on the destination, the call failed with MAPI_E_CORRUPT_DATA which bubbled up to the caller. Digging in, we saw that the problem was in setting the PidTagDisplayName on the Common Views folder. We were able to verify that in Exchange 2007, EWS is unable to change the DisplayName on the special folders but MAPI is able to, however in Exchange 2010, this same operation doesn’t work from MAPI.

    So if your MAPI application is doing any copy operations or calling SetProps on a folder object, you may want to exclude PidTagDisplayName property on these special folders.

    Part B

    This also serves as a good recommendation in general for testing your MAPI applications against Exchange 2010. If something gives you an error that didn’t used to on previous versions (especially Exchange 2007) then chances are, the problem is related to RPC Client Access (RCA) and MAPI going through XSO. To see if your problem is related to MAPI or is in XSO, try doing the same operation (or as close as you can) in EWS. You can use EWSEditor to run through your repro. If you get a similar error, it’s most likely the case that what you are seeing is a result of MAPI going through the XSO layer. If EWS and/or OWA don’t have the same problem as your application does, your problem becomes a little more interesting.

Page 2 of 14 (70 items) 12345»