How can I automatically crosspost/publish Google Reader "shares" to Google+, Facebook or Twitter?

Google Reader is such a great, simple way as a desktop user to keep up with dozens or hundreds of RSS feeds – but even moreso, to be able to selectively share and comment on the blog articles in those feeds with your friends and with various “external” social services (Facebook, Twitter, Delicious, Stumbleupon, and lots of even-more-ancient-sounding services).

What *isn’t* Google Reader great at?
  • sharing your favourite articles (with commentary) via a purely mobile experience
  • sharing those same faves with your burgeoning Google+ circles
Mobile: the Google Reader team have added a tiny number of widgets for sharing to the mobile web experience. Other third-party iPhone apps have done a better job of integrating to the foreign services’ APIs, but it’s not like they voraciously keep up or try to stay ahead of the next wave. [Reeder’s been good to me but hardly stellar – the FB integration works, but I guess I’d rather it just added this as a background operation for all sharing rather than me having to take the time and extra steps to bother sharing outside of the native Google Reader/Buzz feed.]
G+: And what the heck is with Google leaving no clues as to the status of Google Buzz, and whether/when they’ll move operations (like automatic posting of your Google Reader “sharing” activity to the Buzz feed) over to a native G+ implementation? After a year on Buzz, I accumulated no further “organic” growth of friends & followers than the folks that I originally scraped together on day one. I’m seeing a little better “natural uptick” of followers on G+, but still nothing like I see on Twitter – though to be fair, I think if I got new bot followers every time I posted to the Public feed on G+, I’d probably lose my mind.
So what’s up with Google Reader? Has it effectively been zombied, or starved of any reasonable squad of hungry developers and Product Owners? Or is this still a feature with a future? Hell, if I have to find yet *another* place to host my RSS feeds I’m probably gonna lose my mind. And that’s likely the reason why Google has starved the Reader team of any serious developer resources: there’s no competition left. Google is the last place to offer free, voluminous RSS scraping and it shows in their complacency. Up to the rest of us to kludge together some pretty Rube Goldbergian workflows to make it worth reading/sharing on Reader in the first place.
So what does *your* Goldberg machine look like?
So far, the furthest I’ve gotten is to ensure that Sharing & Notes are still working from the mobile Reader and the Reeder iPhone app. Nothing in the Reader “Send To” list even seems to hint at a G+ interaction – and I haven’t gotten creative enough yet to figure out how to make a ‘custom link’ post to one place, that will eventually (and richly – i.e. without cryptically condensing and stripping good content off the original shares) end up on FB, G+ & Twitter without me having to take a half-dozen manual steps at each post. Last I looked, Friendfeed does a cryptic job; does Seesmic have anything to offer here? Any new services from Silicon Valley that I should be looking into?

Review: 52: Vol. 4

52: Vol. 4
52: Vol. 4 by Geoff Johns
My rating: 4 of 5 stars

Summary: too bad about the never-say-die multiverse addiction at DC.

Dibny’s story? Awesome. Week 43 Day 1? Like a five-year-old wrote it.

Black Adam’s finale was not written by that five-year-old, and works much better.

And the build-up to the final climax? Cool. I felt like I participated in something actually pretty wondrous.

Too bad about bringing back the multiverse tho. Seems like DC is just addicted to its easy outs – the many, many variations on the same themes that make it so easy to explain away any discontinuities. Is DC just fundamentally lazy? Some describe it as "enabling creativity", but sometimes endless possibilities leave you without having to think hard, make choices or come up with elegant solutions.

DC is the brute force method of writing superhero stories. Just keep bashing on the same characters until one of the iterations finally comes out with something good.

I still liked the ending to 52, but it sure reminds me of how tiring these "restarts" get every time DC lets its writers paint them into a corner.

View all my reviews

How can I publish GoodReads reviews on Google+, Facebook or Twitter?

Hey all my geeky friends: I’m trying to figure out the most automated way (least number of extra steps) to enable all the reviews I write on GoodReads to show up on my Google+ and/or Facebook streams. I realize that with the amount of effort I’ve put into these reviews over the last year or two, I might as well be getting more value out of the postings than from the dozen or so ‘friends’ I’ve accumulated on GoodReads itself.

Has anyone come up with a good scheme for pulling or pushing GoodReads reviews to their social walls? I’m currently experimenting with ways to pull or push reviews using this blog as a staging ground – see if I can find a way to pull or push from Blogger to G+ or Facebook.


Right now, I do all my reviewing from the GoodReads iPhone app, and based on my previous experiments, it looks like all of the automation is still just “semi-automated”, and only really available from a desktop browser. That is, GoodReads will certainly cache the locations and credentials necessary to cross-post from GR to the ‘foreign’ services; however, it still requires me to (a) fire up my laptop, (b) browse to GR, (c) find the review I just published via GR on iPhone, (d) click the checkbox for the ‘foreign service’ to which I want to post, and (e) push the review to that service.

My ideal behaviour: I’d LOVE GoodReads if they could enable the following scenario:
  • I write a review on GoodReads via the iPhone app
  • I switch the “shelf” from “currently-reading” to “read”
  • GoodReads publishes the review automatically (with no further actions on my part) to all previously-configured social platforms: Blogger, Facebook, Twitter (and in the near future, Google+)
Who do I have to get drunk to make this happen?

Review: Final Crisis

Final Crisis
Final Crisis by Grant Morrison
My rating: 2 of 5 stars

Found the first few pages waaaaay too abstract to bother reading the rest. However it keeps coming back at me, and after realizing it was the linchpin between Batman RIP and Batman Reborn, I finally gave in.

This book feels like it’s all over the place – intentionally. That’s good for the DC geeks who know every minor character or sub-plot that gets a cameo here, but holy hell is it uninteresting to a DC amateur like me.

And frankly the hardest part of reading this book was trying to find and follow the narrative. I mean, there’s good mind-bending storytelling that Morrison is famous for, and then there’s just putting the plot points, characters and dialogue in a blender and simply churning until it’s an unrecognizable mass.

I’m sure if I read it again I’d get much more out of it, and maybe I will someday after I’ve spent a couple of years catching up on the DC universe (after five years I’ve focused so much on Marvel).

Until then I’m going to lament Morrison’s dubious decision to narrate most dialogue in that most insipid and stilted style that was popular back when comic books were still printed using droplet ink.

I totally felt duped into reading this when I saw how little airtime Batman and his “death” actually got. I didn’t know anything more about the continuity jump between Batman RIP and Batman Reborn than before I’d read this unholy mess.

View all my reviews

Building an Outlook add-in: troubleshooting an add-in that won’t start

I made some changes to my code a couple of weeks ago and didn’t document them for myself, nor did I try to debug the code for a week or so.  So by the time I did try it out, I didn’t remember what I’ve done, and of course there’s some reason the add-in isn’t loading anymore.  It’s still listed among the 14 add-ins listed as “Loading Add-ins” as Outlook starts up, but the context menu isn’t available where it should be anymore.

Digging deep into Outlook 2010 to see what goes on with the add-in (Outlook File menu > Options > Add-Ins > COM Add-ins Go… button > click on the add-in in the list), the Load Behavior text says the following:

Not loaded. A runtime error occurred during the loading of the COM Add-in.

Google that error message, a few articles come back, and I bookmarked a couple to check on later.  I’ve reviewed them and tried the following:

http://blogs.msdn.com/b/vsod/archive/2008/04/22/troubleshooting-com-add-in-load-failures.aspx

  • Examined Registry entry (HKCU\…\Outlook\Addins\) to confirm two things:
    • LoadBehaviour setting is still = 3 (it is)
    • file path listed in Manifest value is still valid (it is)
  • Ensured add-in isn’t on the Disabled list (it isn’t)
  • Ran Dbgview.exe while loading Outlook to see if there are any obvious errors being thrown that aren’t otherwise being noticed (there aren’t any entries remotely related to my add-in)

http://social.msdn.microsoft.com/forums/en-US/vsto/thread/f2f2a8f6-3ed5-4c1f-ab6b-17120e64f13d/

  • Set the VSTO_SUPPRESSDISPLAYALERTS=0
  • Observed the following error:
    • Microsoft Office Application Add-In
      An add-in could not be found or could not be loaded.
    • Details button:

      Exception from HRESULT: 0x8004063E

    • ************** Exception Text **************
      System.Runtime.InteropServices.COMException (0x8004063E): Exception from HRESULT: 0x8004063E
         at System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32 errorCode, IntPtr errorInfo)
         at System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(Int32 errorCode, IntPtr errorInfo)
         at Microsoft.VisualStudio.Tools.Office.Runtime.DomainCreator.CreateCustomizationDomainInternal(String solutionLocation, String manifestName, String documentName, Boolean showUIDuringDeployment, IntPtr hostServiceProvider, IntPtr& executor)
         at Microsoft.VisualStudio.Tools.Office.Runtime.DomainCreator.Microsoft.VisualStudio.Tools.Office.Runtime.Interop.IDomainCreator.CreateCustomizationDomain(String solutionLocation, String manifestName, String documentName, Boolean showUIDuringDeployment, IntPtr hostServiceProvider, IntPtr& executor)

  • Found a bunch of discussions referencing this error, and started with the first result: http://social.msdn.microsoft.com/Forums/en-US/vsto/thread/d0ffb791-43bb-41f3-a2ca-c22bd959f4c3
  • Per instructions, I shut down Outlook, started VS2010, chose “Clean [project]” from the Build menu – this seems to have removed the HKCU registry entry for the add-in

Worked like a charm – next time I debugged the add-in, it came up exactly as I expected it to.

Additional Reference

Debugging in Application-Level Projects http://msdn.microsoft.com/en-us/library/ms269003.aspx

Building an Outlook add-in: binding data to XAML (questions)

ToDo’s (from last post)

Need to figure out how to bind the NameValueCollection to the XAML for my WPF-based add-in.  Then I need to find my a** with two hands and a map.  And after that, perhaps I’ll look into the complexity of referral chasing to get the non-GC-replicated user attributes.

Bind AD Data to XAML

The more I look at this snarl of code I’ve pieced together from different samples, the more worried I get that I’ve created an intractable problem.  I have three major classes developed so far (plus the XAML):

  1. ContextMenuItem.cs – inherits Office.IRibbonExtensibility, and implements the IRibbon extensibility member and the Ribbon callbacks (i.e. the context menu click handler).  The click handler instantiates the Pop-Up window, converts the Outlook contact to an email address and runs the AD query.
  2. UserDetailsPopup.cs – implements the ElementHost WinForms object that wraps the WPF control.
  3. ActiveDirectoryUser.cs – implements the query against the Global Catalog, and returns a collection of requested data.
  4. UserDetailsLayout.xaml – implements the XAML UI in which we’d like to drop the requested data.

How should I store the data, and how can I get the XAML to consume it (and ensure it gets displayed in the UI)?

Where to Store the Data?

Let’s assume for the moment that the ContextMenuItem class gets instantiated when the user right-clicks on a contact, and doesn’t die until the context menu and/or the pop-up window it generates are all dead.  That means any Property of the ContextMenuItem will exist during that timeframe, and can be read by other members of the add-in.

So exposing the data the add-in needs as a read-only Property of the ContextMenuItem class seems the only smart way to go here.

How to “Push” Data to UI?

Next, we need some way to cause something in the pop-up window (the XAML, the C# code-behind for the XAML, and/or the WinForms ElementHost that contains the WPF control) to consume the Property’s data, and then refresh the UI of the pop-up window if necessary.

I’m used to the fairly simple .NET app development model, where the first class instantiated is the UI, and it “pulls” in all code calls until the UI receives a callback (user click or some other event) that performs an atomic function.  The best approach I can think of at the moment (given the classes I’ve constructed) is to create some function in either the UserDetailsPopup or the UserDetailsLayout (whichever’s code can cause the intended effect) that reads the ContextMenuItem’s property and then… what, “paints” the data into the XAML labels?  Writes it to a class-local collection to which the XAML is already bound at design time?  Or is there some other elegant feature of VSTO, WPF or .NET 4 that I am totally missing?

Here’s where my inexperience with (1) sophisticated design patterns or (2) WPF is coming to bite me on the butt.  However, it occurs to me that the fundamental problem isn’t WPF but rather a VSTO-and-Outlook-centric design pattern that ferries remote data to local content-driven UI.  Getting the data to the WinForms equivalent in this model must be the majority of the problem; pushing the data the last mile through the WinForms-to-WPF wrapper can’t be all that hard, can it?

Next Steps

So I guess my next quest is to find an Outlook VSTO code sample that creates a new WinForms object in response to user input (rather than all the examples that just graft VSTO code into an existing Outlook “Form” such as an email window, Appointment item and the like).

The final quest in making a functional object is to re-examine the WPF-in-ElementHost examples for Outlook VSTO add-ins, to see how external data gets bound or otherwise propagated into the XAML.

Found: Minimum permissions to edit Site Columns in SharePoint 2010

Our organization has a requirement to delegate the maintenance of a number of Site Columns (re-used throughout our business application) to colleagues who do not have Site-wide responsibilities or authority.  We didn’t want to simply grant one of the all-powerful permissions/groups (such as Site Collection Administrators, Site Collection Owner, [Site] Owners, or just granting Full Control) as that would leave them open to accusatory questions every time the site or application started behaving badly.  We’d like them to be able to act fairly autonomously, without having to worry that they could cause unintentional damage to the site or application due to excessive permissions.

Knowing that most every Microsoft product has a rich, granular set of DACLs applied at every object level, and having exercised some of the rich permissions available in SharePoint 2010, I was pretty sure there should be a way to combine some permissions together to enable Site Column edits, without giving away the farm.  However I was unable to find any documentation or research that definitively asserted they knew what those permissions were.

Finally I asked my colleague Dale Cox to pair up with me and, together with four hours and an experimental sub-site, we were able to work out a tight sub-set of permissions that (a) definitely allow Site Columns edits to propagate to inheriting Lists and (b) were ratcheted down stepwise until we were comfortable there was no place lower to go.

Permissions: Summary

There are two sets of permissions we tested for: site-level permissions needed to edit an existing Site Column (that is being used as a column in one or more Lists in the SharePoint site), and List-level permissions needed to propagate Site Column changes down to inheriting columns in a List.

The former permissions *only* exist at the site level (even though some permissions in the permissions set are labelled “site permissions” and others “list permissions”) – we’ve found there are *no* permissions that can be managed directly related to Site Columns, but only indirectly via the site-level permissions.

That we also require the latter permissions was surprising at first (once we configured the inheritance, why should we need ongoing permissions on every inheriting List?), but that’s just a design decision that Microsoft’s SharePoint team made.  It means we have to manually *track* all the Lists that inherit changes from Site Columns, and make sure our site column maintenance people have enough permissions to the Lists.

Site-level Permissions

  • Manage Lists (labelled “List Permissions”)
  • View Items (labelled “List Permissions”)
  • Add and Customize Pages (labelled “Site Permissions”)
  • Browse Directories (labelled “Site Permissions”)
  • View Pages (labelled “Site Permissions”)
  • Open (labelled “Site Permissions”)

List-level Permissions

  • Manage Lists (individual permission – which includes View Items, View Pages and Open)
  • Contribute (permission set)

There is one case we did *not* explicitly test for, but found was part of the resultant permissions we arrived at: creating a new Site Column.  While we believe this probably requires only a subset of the site-level (site and/or List) permissions, we didn’t spend the extra cycles to isolate the minimum permissions needed there.  Perhaps it’s implied in the results, and if we need to know we’ll pursue it, but it’s not something we needed to know right now.

Steps We Followed To Distill These Permissions

We had to work as a team to test each permissions combination, as I’d found early on that as soon as I removed myself from the all-powerful groups, I was unable to restore myself or change permissions later on.  I manipulated the permissions, and Dale ran the test cases.  I pre-created the following groups in our experimental site and assigned them specific site-level permissions, to make it easy to switch from one permission set to another:

Group name

Permission Levels assigned to group (custom permissions included)

Approve Approve
Design Design
Manage lists Manage Lists (Manage Lists, View Items, View Pages, Open, Manage Personal Views)
Manage web site Manage Web Site (View Items, Manage Web Site, Add and Customize Pages, Browse Directories, View Pages, Enumerate Permissions, Browse User Information, Open)
Site viewers Contribute, Read, View Only
Edit Site Columns (Add and Customize Pages, Browse Directories, View Pages, Open)

 

  1. Dale’s starting position:
    • Permissions: member of Site Viewers group
    • Result: can view site Libraries and Lists but cannot even load the Site Columns page (/_layouts/mngfield.aspx)
  2. Added Dale to “Manage Lists” group
    • Result: can load Site Settings page but still cannot access Site Columns page
  3. Removed Dale from “Manage Lists” group, added to “Manage web site” group
    • Result: Can load Site Columns page but cannot edit site columns
  4. Granted Dale the Contribute permission on one of the Lists that inherits a Column definition from the Site Column being tested.
    • Result: can still load Site Columns page but still cannot edit the site column being tested
    • Dale even tried just updating the site column definition without propagating the change to the inheriting Lists, but that still didn’t work
    • NOTE: from here onwards we started making a point of trying to separate out the ability to edit the site column definition from the ability for that site column definition to propagate to inheriting lists
  5. Removed Dale from “Manage web site” group, added to “Approve” group
    • Result: Dale cannot load Site Columns page
  6. Added “Manage Web Site” permission to a new permission group called “Approve + MWS”
    • That is, copied the “Approve” permission group, then checked the “Manage Web Site” permission (and left the dependent permissions that came with it)
    • Result: Dale can load the Site Columns page, but cannot commit changes to any Site Columns
  7. Removed Dale from “Approve + MWS”, added Dale to “Manage Hierarchy” group
    • Note: while the difference in included permissions between “Manage Web Site” and “Manage Hierarchy” is large, still the “Manage Hierarchy” permission set is a superset of “Manage Web Site”
    • Result: Dale can access the Site Columns page, but cannot commit changes to Site Columns
    • However, we noticed that Dale can create a new Site Column, and can edit that new Site Column
    • Dale attempted just a non-propagating edit with one of the existing Site Columns, and was successful.
    • Theory: current permissions on the Lists that inherit from the existing Site Columns are what’s blocking the previous Site Column edits
  8. Granted to Dale “Contribute” permission on all of the three Lists which inherit from the existing Site Columns
    • Result: Dale cannot commit a propagating edit on an existing, inherited Site Column
    • Theory: the individual permission “Manage Lists” is what’s needed on each inheriting List for the Site Column propagation to succeed
  9. Granted to Dale “Design” permission (which includes the individual “Manage Lists” permission) to one of the three inheriting Lists
    • Result: Dale could not commit a propagating edit on an existing, inherited Site Column.  Further, the change did not even inherit to the inheriting List (where the permissions needed for propagation could have allowed the change).
    • Theory: propagating edits to a Site Column are a transactional request – if the request doesn’t succeed on every inheriting List, then the edit “transaction” is rolled back, rather than partially succeeding.
  10. Changed the following permissions to all three inheriting Lists: changed from “Design” + “Contribute” to “Manage Lists” + “Contribute”
    • Result: Dale’s propagating edit finally succeeded!
  11. Decided to go back over the site-level permissions to determine whether there was an unknown interaction between the site-level and list-level permissions that we didn’t account for.
  12. Kept the List-level permissions as-is, but changed Dale’s site-level permissions – removed him from “Manage Hierarchy” and added him to “Approve + MWS” group.
    • Result: propagating edit failed, and non-propagating edit failed.
  13. Removed Dale from “Approve + MWS” group, added Dale to Design group (which has Design permissions set).
    • Result: propagating edit succeeded.
  14. Compared the permissions between the “Design” and the “Manage Hierarchy” permissions groups, and found the following eight permissions in common:
    • Add and Customize Pages
    • Browse Directories
    • View Pages
    • Browse User Information
    • Use Remote Interfaces
    • Use Client Integration Features
    • Open
    • Edit Personal User Information
  15. Analysis of these permissions, looking for the “secret sauce” that they share:
    • The “Manage Web Site” site-level individual permission isn’t the one that Dale needs (as it isn’t part of the Design permission set, and yet Dale was still able to propagate the edit when he had the Design permission)
    • Based on the descriptions of each individual permission listed above, the most likely candidate is “Add and Customize Pages”
  16. Created a new Group called “Edit Site Columns”.  Created a new permissions set called “Edit Site Columns”.  To that permissions set, we added only “Add and Customize Pages”.  Removed Dale from Design group, added him to Edit Site Columns group.
    • Note: when “Add and Customize Pages” is checked, the following permissions were automatically checked: “Browse Directories”, “View Pages”, “Open”, “View Items”.
    • Result: propagating and non-propagating edits failed.  Adding a new Site Column also failed.  Dale could access the Site Columns page.
  17. Added back all eight site-level permissions that were in common between the Design and Manage Hierarchy permissions sets.
    • Note: the “Edit Site Columns” permission set at this point doesn’t include any of the List-level permissions that I’ve so far ignored.  Continued failure means that to edit Site Columns, a user needs some of these “list permissions” assigned at the site level.  [Confused yet?]
    • Result: propagating and non-propagating edits failed.  Dale is still able to access the Site Columns page.
  18. Re-examined the “list permissions” that were included in both of the site-level permissions sets (Design and Manage Hierarchy) that were successful for Dale:
    • Manage Lists  –  Create and delete lists, add or remove columns in a list, and add or remove public views of a list. 
    • Override Check Out  –  Discard or check in a document which is checked out to another user. 
    • Add Items  –  Add items to lists and add documents to document libraries. 
    • Edit Items  –  Edit items in lists, edit documents in document libraries, and customize Web Part Pages in document libraries. 
    • Delete Items  –  Delete items from a list and documents from a document library. 
    • View Items  –  View items in lists and documents in document libraries. 
    • Open Items  –  View the source of documents with server-side file handlers. 
    • View Versions  –  View past versions of a list item or document. 
    • Delete Versions  –  Delete past versions of a list item or document. 
    • Create Alerts  –  Create alerts. 
    • View Application Pages  –  View forms, views, and application pages. Enumerate lists. 
  19. Added all of the above permissions to the “Edit Site Columns” permission set except View Items.
    • Result: propagating edits were successful.
  20. Stripped down the site permissions from the “Edit Site Columns” permission set to leave only the following: ACP, Browse Directories, View Pages, Open.
    • Result: propagating edits were successful.
  21. Stripped out a number of List-level permissions from the “Edit Site Columns” permission set to leave only the following: ML, VI.  Left the site permissions as in the last step.
    • Result: propagating edits were successful.
  22. Wanted to ensure this result is reproducible, so we created a new permissions set “Edit Site Columns – Confirmation”, added the same permissions to this new set (i.e. ML, VI, ACP, BD, VP, Open),  created new group “Edit Site Columns – Confirmation”, granted the new permission set to the new group, added Dale to the new group and removed him from the older “Edit Site Columns” group.
    • Result: all operations were successful – view Site Columns page, commit propagating and non-propagating edit of inherited Site Columns, add new Site Column.

Building an Outlook Add-in: completing work on the Active Directory query

ToDo’s (from last post):

  • Implement the GC (domain-less) query, rather than orient to the current implicit binding to the user’s current domain
    • Big question to answer: are all the fields of interest being replicated in the AD GC?
  • Implement a reasonable collection that will be useful to the calling code, and return the user info in the return value
    • After 15 minutes in MSDN Library and some wide-swath google searches, it sounds like the NameValueCollection class is fairly suitable: hashtable-based, strings-only, and allows multiple values for a single key (which may come in handy later for multi-value directory data, of which AD allows a few)
  • Start testing this beast against the company AD

Y’see, this is one of the problems with doing code development in your spare time – I’m facing a major uphill climb, trying to remember (1) where I was going next, (2) where the next layer of function calls was supposed to get plugged into, and (3) which article I was reading that headed me down this design path.  Arrgh.

So I’m starting over with the first “article” (actually MSDN video demo) that caught my fancy, and downloaded the sample code.  I have an idea of (1) – to plug the utility class that scrapes AD for user data into the code that calls the Winforms-wrapping-WPF control, and display the user data in that blank context menu window I’ve already sketched out.  By wandering around the sample code, I’m hoping to figure out (2) without having to review every line of code and compare to my own design “pattern”.  Presumably by retracing the steps outlined in my blogs, I’ll be able to quickly stumble across (3) – again, without having to review every word I’ve written.

God I hope this works.

Acquiring the user’s Email Address

Fortunately, by looking in the sample code’s ThisAddIn.vb class, I’ve already discovered a helpful Function that I knew I needed somewhere.  A quick trip to a VB-to-C# converter and I’ll drop this into my own ThisAddIn.cs class.

However, there’s no direct property of an IMsoContactCard object that corresponds to the contact’s email address – for that I had to find this sample code that does a conversion.

D’oh! Nope, even that just ends up returning the X.500 version of the Exchange mail address.  Instead, I ended up back at this article that I’d read before, which provides a great GetSmtpAddress() function in VB.  Oh, *right* – which I’d already implemented in my project’s code a few weeks ago.  See what I mean about this “once a week coding” nonsense?

Here’s my completed OnClick() method for the Contact context menu item, that calls into my ActiveDirectoryUser class:

public void onGetUserDetailsClick(Office.IRibbonControl control)
{
    try
    {
        Office.IMsoContactCard card = control.Context as Office.IMsoContactCard;

        if (card != null)
        {
            // Here's where we need to instantiate the UserDetailsPopup() object
            UserDetailsPopup UserDetailsInfoForm = new UserDetailsPopup();
            UserDetailsInfoForm.Show();

            string emailAddress = GetSmtpAddress(card);
            ActiveDirectoryUser user = new ActiveDirectoryUser();
            
            NameValueCollection coll = user.getGcUserData(emailAddress);
        }
        else
        {
            // Here's where we handle this edge case
        }
    }
    catch (Exception ex)
    {
        // Handle the exceptions
        Console.WriteLine("Error spat out" + ex.Message);
    }
}

Much later, after a couple of hours of debugging this slapped-together code, I’ve finally arrived at a method that’s finally deriving the output of live queries against AD.  And I have an answer to the big question: no, not all of the really useful attributes are being replicated to the GC.  The most obvious one that’s missing would be the job description-oriented attribute.  Of all the User object custom attributes *not* to replicate, why did they pick on this one?  Is it really so hard to believe that someone would want to query this value in a global directory?  Looks like I’m going to have to implement some referral chasing and see if that doesn’t tank the performance of the add-in.

Completed GC-querying Method

Here’s my GC-querying method call to derive the GC-replicated attributes (using “department” as substitute for the the custom attributes internal to the organization that I’m going after):

public NameValueCollection getGcUserData(string emailAddress)
{
    NameValueCollection returnValue = new NameValueCollection();
    
    DirectoryEntry gc = new DirectoryEntry("GC: ");
    DirectoryEntry _root = null;
    using (gc)
    {
        //there is only 1 child under "GC: "
        foreach (DirectoryEntry root in gc.Children)
        {
            _root = root;
            break;
        }
    }

    //Note: the filter must be searching for a GC replicated attribute!
    string filter = String.Format(
        "(mail={0}) ",
        emailAddress
        );

    DirectorySearcher ds = new DirectorySearcher(
        _root,
        filter,
        null,
        SearchScope.Subtree
        );

    using (SearchResultCollection src = ds.FindAll())
    {
        foreach (SearchResult sr in src)
        {
            returnValue.Add("department", sr.Properties["department"].ToString());
        }
    }
    return returnValue;
}

Next Steps

Need to figure out how to bind the NameValueCollection to the XAML for my WPF-based add-in.  Then I need to find my ass with two hands and a map.  And after that, perhaps I’ll look into the complexity of referral chasing to get the non-GC-replicated user attributes.

Acknowledged: the two simple articles that saved my ass twice now

Extending the User Interface in Outlook 2010

Customizing the Context Menu of a Contact Card in Outlook 2010

Building an Outlook add-in: Context Menu of Contact Card in Outlook 2010

Before going *any* further with VSTO code, I am taking some very good advice I gave myself a couple of years ago and installing some of the VSTO Power Tools (just the VSTO_PT.exe package) – specifically to obtain the VSTO Developer Cleaner and the VSTO Troubleshooter.  I recall both of these being very helpful, the last time I went down this path.

Note also: I am *not* going to pursue the Office Interop API Extensions.  I am aware they’re targeted specifically at easing C# development of VSTO apps in Word, Excel and Outlook.  However, after reading PhillipHoff’s blog that “documented” them, the near-total lack of a deployment story is enough to encourage me to tough it out without ‘em:

“You are correct in that the User Guide does not explicitly state that you cannot use VSTO_PTExtLibs.exe to redistribute the extension assemblies, but as you found, the installer has a dependency check which prevents it from being used for that purpose.

“You have two basic options for distributing the extension assembly: either a custom installer that places it in the GAC or another common location, or side-by-side the referencing assembly.”

Heh, yeah right.  A year or two ago I feel down the rabbit hole of developing a custom setup package for a Word VSTO app add-in.  That sucked me dry for months, and I never got any satisfaction out of it (tho it’ll probably save me a couple of months this time around).  *Voluntarily* adding to my pain by trying to install a helper assembly of dubious provenance and poor support?  Not bloody likely my friends.

 

Creating a WPF Control for use within Outlook 2010

Diving back into this video tutorial.  Already stuck on one of the first steps – adding the WPF “User Control” to the ElementHost winforms container.  Even though I’m able to successfully build the project, there’s no WPF user control to add to the ElementHost (at least that’s what the ElementHost “Select Hosted Content” taskpane is indicating.  Google it is… searching on elementhost “select hosted content” none:

…actually, I just remembered how many articles I’ve been skimming are focused so strongly on .NET Framework 4, so first I decided to re-target the VSTO project to .NET 4.  For some reason that seems to have wiped out the piece of code that contained the ElementHost-including form, so perhaps that’ll clear up the problem I’ve been having.

I ended up Building the project and failing, needing to add a Reference to System.Xaml (from the .NET 4 namepsace) to one of the .CS files.  Once I did that, magically I was able to add either of the XAML user controls I’d tried to create as children of the ElementHost object.  Amazing.

I’m re-trying this approach with an Office Ribbon (XML) item as is outlined in Customizing the Context Menu of a Contact Card in Outlook 2010.  I change the button element’s id, label, and onAction XML parameters, then run this article’s VB-only code through a VB-to-C# converter to import into my code.  Each time I have to fill in a few blanks along the way – figuring out which method to add to my code, to which CS library, and matching some undeclared variable names and using statements up with orphaned code in the sample.  What moron would expect a “Visual How To” from Microsoft to ever run without a ton of band-aid work to actually fill in boring-but-essential components?

Once I figured out how this sample code would instantiate the Ribbon (XML) item, I only have two more tasks before I start binding the XAML to its data source:

  1. instantiating the XAML-encapsulated-in-WinForms control, and
  2. creating the Callback Methods that are hinted at (but not spelled out) in the Ribbon (XML) //TODO section (automatically generated by Visual Studio when I created the Ribbon (XML) object.

Yeah, that should be easy.  Callbacks – is that like in the theatre?  Hell, for all *I* know, (2) is where I *implement* (1).

Aha!  Apparently I’m not far off from the truth – the Walkthrough: Creating a Custom Tab by Using Ribbon XML says:

You must add onAction callback methods for the Insert Text and Insert Table buttons to perform actions when the user clicks them.

Right right right – so the meaning of “callbacks” is coming slowly back to me – at least in the context of button pushing. 🙂

 

Problem: UserControl doesn’t Show()

I spent some time looking for a suitable approach to rendering the WPF Element Host-ing user control, and tried a couple of approaches, but none work so far.  The approach I’ve landed on instantiates a new instance of the Class that hosts the ElementHost (here called “DataDetails”), then calls the .Show() method for the object instance, like so:

DataDetails dataDisplay = new DataDetails();
dataDisplay.Show();

However nothing appears visible when I click the new context menu item in Outlook 2010.  Here’s what I’ve tried, none of which tells me why this won’t display:

  • follow the .Show() call with calling the BringToFront() method, in case somehow the user control was being hidden behind Outlook
  • added a straight System.Windows.Forms class to the project (called it my Debug window), then instantiate it as for the DataDetails class instance and call the ShowDialog() or Show() method [which works]
  • did a line-by-line debug of this area of my code [which proves that every line of code is being called – nothing skipped – but the ElementHost is still not showing up]

Re-examining the Debug vs. DataDetails objects, I’m pretty convinced that using the Form class is easy, but there’s some step I’m still missing when using the UserControl class.  This is borne out when I merely substitute “Form” in place of the original “UserControl” for the partial inheritance, like so:

public partial class DataDetails : Form

{

    public DataDetails() {  InitializeComponent(); }

}

Further Research References

Aside: the specific Context Menu I’m manipulating here is sometimes called the Persona Context Menu (at least by the article Extending the User Interface in Outlook 2010).  I have a feeling that will be a very useful phrases in my current research.

Other articles I’ll probably need to almost immediately:

Here are some other articles I expect I’ll need in the future:

Finally, here are some possible sources of working code that I’ve found in my travels:

Building an Outlook Add-in: customizing the Contact Card, other options?

[I’m working on an app for work – enable me to pull job title, team name, etc. from a proprietary internal database, since our Exchange Address Book doesn’t contain that info.  Just to set the context for what the h*** I’m up to.]

Did a broad search for “Outlook 2010 VSTO” to find some beginners’ guide to writing something that will run in Outlook 2010.  Lots of possible stuff to read, but this 20-minute video seemed like my best bet:

How Do I: Create a WPF Control for Use Within Outlook 2010

Yes the question should be asked: are you better off writing an Outlook 2010 add-in using WPF or a Windows Forms?  I haven’t yet found a definitive answer, and they may both be supported to some degree, but the majority of articles I stumbled across were using WPF not Windows Forms.  That *may* just be a tyrannical bias coming from Microsoft, where XAML is all the rage and you’re ‘not allowed’ to talk about legacy development there anymore.  Regardless, if I see WPF and Outlook 2010 mentioned more than a half-dozen times, that *has* to be supported pretty well, so I’ll go with that for now.

Contact Card

Next I need to know what kind of Outlook “object” I’m trying to attach to.  I am aiming for that new intermediate Contact panel that shows up when you double-click the email address of an email in your Inbox (this example borrowed from Microsoft Support):

Contact Card example

  1. It already has a tabbed interface, so adding another tab makes intuitive sense as a user.
  2. It’s the first interface you get to detailed info on a user, so it’s the fewest clicks to get to an extended UI I could add.
  3. It’s new in Outlook 2010, which (I hope) means that the Outlook Interop object model has implemented first-class .NET support for interacting with that object.  [As opposed to some of the legacy objects in Outlook for which there is pretty crappy support in the .NET Interop model.]

Searches for “Outlook 2010 new features” take me to pages like this, which refer to this new interface as “a new easy-to-access contact card”.  Digging into the official Outlook blog there’s a detailed article “Using the contact card to learn who someone is”, so I’m definitely on the right track.  Now if only this was the same nomenclature used in the Outlook object model (developer side of the world) – it’s rare that the underlying code and the marketing names ever get aligned, so I’m not surprised much anymore if I don’t get that fantasy fulfilled.  [Heh, and just to show how easy it could’ve been, I realize now that the Contact Card is available as a context menu item when you right-click the email address.]

So my next search – Outlook 2010 “contact card” “object model” – turned up an article called “Customizing the Context Menu of a Contact Card in Outlook 2010”.  Among other things, this article states that “The IMsoContactCard object is defined in the primary interop assembly, Office.dll, of the Microsoft Office object library, not in Outlook 2010.”  So this is apparently an Office-wide object, available to other Office apps – not just Outlook (though it’s entirely possible Outlook is the only app that bothered).

Which also happens to lead to a Code Gallery sample called “Outlook 2010: Visual How Tos: Code Samples” that includes the sample code.  Unfortuately the sample is adding a new entry to the context menu, not to the Contact Card itself (which is a mite confusing, as the object model doesn’t make a really clear distinction between the two).  HOwever, this gives me a great lead on what area of the object model to focus my attention on.  And worse come to worst, I can always start with a really crude hack of adding a context menu selection that just pulls up the internal directory data for the selected user (or as I’m seeing from the code sample, the “Recipient” – gotta get your nomenclature aligned when you dive into an Office object model exploration).

Next let’s see if anyone out there has been monkeying with this object or this part of the object model – searches on Stack Overflow turn up nothing, but MSDN Social Forums hits some info on:

And a search of MSDN Library for IMsoContactCard led to one non-reference article: Extending the User Interface in Outlook 2010.  According to this article, adding a new item to the context menu when you right-click an email sender or recipient is done using the ContextMenuContactCardRecipient context menu.

Given that these articles all seem to say that it’s impossible to extend the contact card itself, I find myself with two alternatives:

  1. Add a right-click menu option that pulls the internal directory info for the selected recipient.
  2. Add another tab to the ‘legacy’ Outlook Properties window (which was the default in Outlook 2007 & 2003 when you double-click on a user).

Context Menu vs. Properties window

Comparing Option (1) and (2), I come to these benefits & drawbacks:

  1. The programming for the Contact Card context menu was just added in 2010, which probably makes it behave more consistently and robustly than the COM-based crap that comes with legacy Outlook features.
  2. Adding a tab to the Properties window (form) would assist me more easily if I wanted to “crawl up the address book” (i.e. look for the same information on the managers of the recipient I’m exploring).  I find I *can* get to a context menu for the recipient’s manager, but it’s hellishly buried and I’d probably be one of three people who’d find it (or who’d bother taking this path).
  3. From my recollection, Office (and Outlook in particular) can be really picky about exactly how and when to dispose of objects – generally resulting (from <100% perfect code) in deadlocks, memory leaks or difficulties in shutting down the hosting app.  I would imagine the Interop Assemblies have a harder time communicating reliably with the legacy COM object model (e.g. Properties window) than with objects only recently introduced (e.g. Fluent UI).
  4. While the Office Interop Assemblies have been incredibly forgiving about providing backwards-compatibility to all the COM objects that have been accumulated over the decades, I have to believe that Fluent UI customizations have a better future in coming versions of Office than COM-based customizations.  This should be especially true of Outlook, since that team took a “wait and see” approach to the Fluent UI in the Outlook 2007 generation.  If they’re still on board, they’ve benefited from the delay *and* it is likely they’re more committed than if they’d gotten burned by jumping in early.
  5. If I’m reading this right, Office Communicator (probably 2007 R2 and later) implements support for the IMsoContactCard – so a Fluent UI approach might actually give us coverage in Outlook *and* Communicator.  I don’t know how useful that really would be, but it *sounds* cool.

Thinking as an end user, I’d find another tab on the Outlook Properties window more intuitive, but I’d also be extremely unforgiving if my Outlook user experience slowed down or destabilized.  I don’t like the Context Menu approach that I seem to be left with in customizing the Fluent UI, but I can be optimistic that a more integrated approach will become apparent as my research continues – and in the meantime I’ll have a Fluent UI-compatible set of code to build on.

Details: Fluent UI

All these articles I’m finding talk about these Contact Card customizations in terms of customizing the “Fluent UI”.  I’m not sure, but I had believed that this Fluent UI was primarily introduced as a wrapping layer of menu/ribbon ‘cleanup’ of the Office UI that was long overdue by Office 2007.  These references make it sound as if the Fluent UI is where all new UI improvements are “homed” in Outlook 2010.

As I dig a little further, there are some pretty clear indications this is true:

Customize the Office UI

In Office 2010, the Office Fluent UI is fully customizable. This includes the ribbon, the Quick Access Toolbar, and the built-in context menus. By using the flexible XML-based markup and callbacks, you can create context menus by updating Open XML Format files or by using add-ins that are created in Microsoft Visual Studio.

Customizing Context Menus in Office 2010

In Office 2010, you can customize built-in context menus just as you can the other components of the Ribbon UI. This XML-based context menu extensibility model is based on the familiar Ribbon extensibility model. This means that you can use the same XML markup and callbacks that you currently use to customize the Ribbon UI.

Encouraging, but not specifically helpful other than a lot of hand-waving and empty promises.  Having clear documentation on what the object model does is the critical piece, and all I’ve got here so far is a Context menu (which is hardly an intuitive UI approach).  However, if that’s what I’ve got then it’ll have to do.  Off to implement code based on Customizing the Context Menu of a Contact Card in Outlook 2010 and see how well that treats me.