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.

MindManager 7 ToDoList AddIn development Part 6: the Mysteries of COM interop

Sometimes there are inevitable mysteries uncovered when writing code.  Well, I’ve bumped into quite a rich source of mysteries in trying to use an aspect of the MindManager object model that thunks through a brittle COM interop module, known as CmjDocumentCollectionComObject.  Here’s just a couple of examples that have come up recently:

“unable to create document”

Here is the ‘offending’ code:

public static MMInterop.Document GetMap(string filename)
    MMInterop.Document toDoListMap;
    MMInterop.Documents maps;
    string toDoListMapFullPath = Connect.applicationObject.get_Path(MMInterop.MmDirectory.mmDirectoryMyMaps) + filename;
    maps = Connect.applicationObject.get_Documents(true);
    try // open a ToDoList map
        toDoListMap = maps.Open(toDoListMapFullPath, String.Empty, true); // here's where the COMException is raised

Here is the exception raised:

System.Runtime.InteropServices.COMException occurred
  Message=”Object ‘CmjDocumentCollectionComObject’ reports an error: ‘unable to create document'”
       at Mindjet.MindManager.Interop.DocumentsClass.Open(String pFileName, String pPassword, Boolean Visible)
       at ParanoidMike.MindManager.ToDoList.ToDoListMap.GetMap(String filename) in C:\personal\VS Projects\MM7TODOList\ToDoList.cs:line 187

And do you want to know what that exception really means?  “The specified file does not exist” would be my interpretation.  If I understand the MindManager function maps.Open() correctly, this is meant to open an existing document.  I’ve just asked it to open a non-existent document, so I’d expect “can’t find it”, but I’m puzzled by “unable to create document”.  It’s like whoever wrote the error strings for the CmjDocumentCollectionComObject is interpreting the name of the Win32 CreateFile() API literally.

I am attempting to use a Try…Catch approach to testing whether the requested file exists. If the file exists, then maps.Open() would succeed; if it didn’t exist, then I’d use the Catch block to instead create the named file.  I didn’t expect to have to catch a System.Runtime.InteropServices.COMException, nor in figuring out how to catch only the exception with a specific ErrorCode/HRESULT returned by the COM object.

But then again, “Nobody expects the Spanish Inquisition”

{“Retrieving the COM class factory for component with CLSID {5B9EA9CE-76A3-4878-9A6B-22D0A3042774} failed due to the following error: 80040154.”}

Here’s the code:

MMInterop.Document toDoListMap;
    toDoListMap = new MMInterop.Document();
catch (System.Runtime.InteropServices.COMException e)

Here’s the .NET exception that gets thrown:

{“Retrieving the COM class factory for component with CLSID {5B9EA9CE-76A3-4878-9A6B-22D0A3042774} failed due to the following error: 80040154.”}

And here’s the HRESULT that is being thrown by the COM object: -2147220992

In various posts, the common theme seems to be that the “component with the noted CLSID” needs to be re-registered.  Searching for this CLSID on my system (predictably) leads to Mindjet.MindManager.Interop, Version=7.0.323.0, Culture=neutral, PublicKeyToken=19247b5ea06b230f and Mindjet.MindManager.Interop, Version=7.1.388.0, Culture=neutral, PublicKeyToken=19247b5ea06b230f.  [However, there’s no ProgID registered for Mindjet.MindManager.Interop.  Is that bad — I know it’s not good for typical apps, but is a COM interop assembly a “typical” COM app?]

I remember reading somewhere that the MindManager 7 Primary Interop Assemblies were installed by default when installing MM7, so I thought perhaps and Add/Remove Programs “Repair” operation would suffice.

Unfortunately no — damned MindManager, I ran the full Repair, and it even reinstalled all the 41 default templates (so I know it did completely successfully), but my code is still throwing this same error.  So I went looking for the file path, which meant examining the Properties of the “MindManager” Reference, and it reports that this “ActiveX” file is stored here: C:\WINDOWS\assembly\GAC_MSIL\Mindjet.MindManager.Interop\7.1.388.0__19247b5ea06b230f\Mindjet.MindManager.Interop.dll.  Fire up a Command Prompt in that directory, run “REGSVR32.EXE Mindjet.MindManager.Interop.dll”, and I end up with this error:



Here’s a riddle: how does one initialize a variable that cannot be initialized?

When I try to create a new mindmap document using a .NET AddIn, I’m finding that the variable I declare to hold a reference to the new mindmap is not usable: (a) it won’t work until it’s initialized, but (b) when it’s initialized it throws the error documented here:

I’ve tried to dig up any hints that would help me figure out what to do to resolve this error, but so far nothing has worked (including trying to Register the Interop DLL, and Repairing the installation of MindManager).

There are plenty of people asking about this kind of issue — some related to straight COM objects, others talking about COM Interop assemblies:

(1) I tried loading up the Interop DLL in DEPENDS.EXE, but there appear to be no missing dependencies.
(2) I tried registering the assembly using REGASM.EXE, according to the article here:
using the following command:

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727>regasm C:\WINDOWS\assembly\GAC_MSIL\Mindjet.MindManager.Interop\7.1.388.0__19247b5ea06b230f\mindjet.mindmanager.interop.dll
Microsoft (R) .NET Framework Assembly Registration Utility 2.0.50727.1433
Copyright (C) Microsoft Corporation 1998-2004.  All rights reserved.

Types registered successfully


Now I’m getting the same .NET exception, with a different HRESULT: -2147221164.  That HRESULT appears to be associated with needing to re-register Atl.dll, so I gave that a shot.  Unfortunately, it gave me the same error and the same HRESULT.  I also tried re-running the above REGASM.EXE command, with no change — still throwing the same exception.

Cheap Hack: avoid init issues with dummy calls

I’m almost embarrassed to even discuss how I’m getting around this intractable problem…but not embarrassed enough not to do it, so I might as well own up to it.  Who knows?  Maybe one of you will know what I’m overlooking.  Maybe I’ll find this article in six months’ time and remember why I put this hack in place.  Maybe this will just be my own personal legacy to the world. 🙂

Let’s recap: my design for this AddIn is to use a separate map to list copies of all Tasks found in the searched maps. If the named map already existed, just open it; if not, a new map should be created.  However, I kept getting blocked by not “initializing” the local variable to hold the new/opened Document handle before returning it to the calling function.  However, initializing the local variable with a “new MMInterop.Document()” call just caused other problems.

I was thinking that because Visual Studio was throwing the CS0165 error “Use of unassigned local variable ‘toDoListMap” on the final line of code “return toDoListMap”, and not on any of the preceding where the toDoListMap variable was being assigned, what Visual Studio might be reacting to is that toDoListMap wouldn’t have a non-null value on all code paths through the function.  I’d ignored this thought because (a) the code paths where it wouldn’t get a value were intentional, and (b) the documentation on CS0165 kept indicating that I needed to initialize the variable.

However, after exhausting all the “right way” options, I finally just dropped some initializations (assignments?) into the code paths where toDoListMap wasn’t previously being touched:

public static MMInterop.Document GetMap(string filename)
    MMInterop.Document toDoListMap;
    MMInterop.Documents maps;
    string toDoListMapFullPath = Connect.applicationObject.get_Path(MMInterop.MmDirectory.mmDirectoryMyMaps) + filename; // TODO: remove this hard-coded pathing to the ToDoList map
    maps = Connect.applicationObject.get_Documents(true); // assign/initialize the maps variable so the array can be searched by maps.Open().  "Connect" is the Class that implements a static variable "applicationObject" which is assigned to the "application" object that's captured during AddIn initialization.

    try // open the existing ToDoList map
        toDoListMap = maps.Open(toDoListMapFullPath, String.Empty, false);
    catch (System.Runtime.InteropServices.COMException e) // if a ToDoList map by that name does not exist, create one
        if (e.ErrorCode == -2147220992) // "Object 'CmjDocumentCollectionComObject' reports an error: 'unable to create document'"
            System.Windows.Forms.MessageBox.Show("Exception opening map: " + e.Message); // TODO: remove once initial debugging is complete
            string templateFullPath = Connect.applicationObject.get_Path(MMInterop.MmDirectory.mmDirectoryTemplates) + templateFileName; //construct reference to the template that's required when creating a new Document

            toDoListMap = maps.AddFromTemplate(templateFullPath, String.Empty, false);
        else // this is never intended to be run - it's just here to convince the compiler that the toDoListMap variable has been initialized on all code paths, as it otherwise throws an exception "Use of unassigned local variable 'toDoListMap'.
            System.Windows.Forms.MessageBox.Show("If you see this message, record the error and report it to the developer - this should never be seen: error code = " + e.ErrorCode.ToString());
            toDoListMap = new MMInterop.Document();
    catch (Exception e) // this is never intended to be run - it's just here to convince the compiler that the toDoListMap variable has been initialized on all code paths, as it otherwise throws an exception "Use of unassigned local variable 'toDoListMap'.
        System.Windows.Forms.MessageBox.Show("If you see this message, record the error and report it to the developer - this should never be seen: error code = " + e.ErrorCode.ToString());
        toDoListMap = new MMInterop.Document();

    return toDoListMap;

And now, miraculously this damned code compiles and runs correctly.  I really wish I had some better ideas than these “new” calls, ’cause I’ve got a feeling they’ll come back to bite me far down the line.  I’ve added some MessageBox “please let me know if you see this” dialogs, but that won’t really solve the problem — just make me look a little more like an amateur code-jockey.

[I’m still not sure why in this case, I was able to assign the toDoListMap variable without first initializing it — it’s not one of the simple datatypes, so I don’t think it’s being implicitly initialized by the compiler, and I thought I’d just re-learned that a complex Object always needs to be declared, initialized and then assigned.  Once again there’s something I don’t get about this, but I’ll leave that to dig up in the future, as yet another great surprise. :)]

MindManager 7 ToDoList AddIn development Part 5: minimizing Object overhead between classes

I’ve created quite a puzzle for myself.  In writing an AddIn that calls functions from custom Classes, I am forcing the AddIn to pass in all the data that would be needed in the custom code.  I’ve added a few helper functions to the ToDoListBuilder class including GetAllTasks(), IsTaskCompleted() and IsTopicATask().  These are easy because I’m passing simple variables into each function.

However, I haven’t yet wired up the primary function that will be called from the AddIn’s mmCommand_Click() event, and I haven’t decided what I need to pass down from the button_Click() to the cascade of encapsulated functions, nor how far down to pass any object like a baton.

It seems like it’d be correct to pass the MMInterop.Application object into the ToDoListBuilder code, but in passing the Application object to a GenerateToDoListItems() method, I’ll have to pass the Application object to at least one further layer of called functions such as GetAllToDoListMaps().  Or will I?

Now that I’m looking around, the Connect class has a private applicationObject variable.  While it seems unlikely I’d be able to make reference to that Class’ private variable from a called Class, there should be no reason why I couldn’t create another private variable in the ToDoListBuilder class as soon as the GenerateToDoListItems() method is called, and then call on that Class-wide variable from then on.

Reducing Memory Footprint of Application Object(s) without Passing References Everywhere

Here’s how the code around the Application object comes out from the Visual Studio AddIn Template wizard by default:

    public class Connect : Object, Extensibility.IDTExtensibility2
private Mindjet.MindManager.Interop.Application applicationObject; private Mindjet.MindManager.Interop.Command mmCommand;
... }

Changing the first declaration to public from private makes that applicationObject object available outside of the assembly as well as within it, so that pointers (references) to the object don’t have to be explicitly passed around the code.

Assuming that nothing can affect the state of the applicationObject, there should be no reason not to declare it as “public”.  I’m not entirely naive though — I assume there’s reasons why you’d want to do one and not the other, but I have to believe that any code running in the MindManager application should necessarily want/try to use a single application object anyway.

Solution: Static/Shared modifier

After bashing my skull into the wall of my ineptitude for a few days, I finally dislodged a bone fragment of useful info: the “static” modifier.  Somehow this does what I had expected the “public” keyword to accomplish — makes it possible to access the variable from outside the class, without having to instantiate another copy of the object.

Open Questions

Now I’m left wondering two things:

  1. What’s the lowest level of accessibility that the object needs?  Does it still need to be public, or would protected or less be acceptable?
  2. Under what circumstances would it be inadvisable to use the static modifier?  I can imagine that in theory, anything that is supposed to represent multiple objects should not be marked “static”, but that still leaves a ton of room for interpretation (and for subtle mistakes in code that will bite me only later).

Aside: Registry entries in Setup project Aren’t Automatically Installed

Idiot assumption of the day: just because I entered the correct Registry settings in the Setup project, doesn’t mean that when I Debug the Solution those settings will be automatically added to the computer’s Registry.  (Sigh, sometimes I surprise myself with how dense I can be.)

So which “hack” would be better — should I hand-enter the Registry settings I need (which seems pretty lame) or should I build the Setup project and actually install this AddIn (which might end up leaving behind stuff that I’ll need to rip out later after I’ve rev’d the AddIn a few times)?

I guess I’m going down the path of hand-entering the Registry settings.  I don’t like doing this, and I really wish debugging MindManager AddIns didn’t require this lame step, but it looks like I’ve got no better option.

NullReferenceException: When will I ever learn?

I can’t believe the number of times I get caught by this seemingly predictable error:

        private System.Collections.ArrayList toDoListItems; // building list of all Tasks to be emitted as the items for the ToDoList
        private Mindjet.MindManager.Interop.Application applicationObject; // local instance of the Application object

        public System.Collections.ArrayList GenerateToDoListItems(MMInterop.Application application)
            System.Collections.ArrayList toDoListMaps; // collection of all maps to be searched for Task topics
            applicationObject = application; // sets the local variable equal to the value of the passed-in parameter
            toDoListMaps = GetAllToDoListMaps(); // generate the collection of maps to be enumerated and searched
            toDoListItems = new System.Collections.ArrayList(); // declare this to avoid a NullReferenceException when it's assigned below
            foreach (MMInterop.Document map in toDoListMaps)
            return toDoListItems;

I really don’t get why I don’t have to declare the “new toDoListMaps” object, but I have to declare the “new toDoListItems”.  Is there something about creating the object inside the method that implicitly initializes it, but this implicit initialization doesn’t occur for objects that are created outside of the method?

And why does creating an int object not require initialization, but creating an ArrayList object does?  This might make sense to veteran coders, but my god it’s confusing for those of us just trying to get their first few apps out the door…

MindManager 7 "ToDo List" Add-in development Part 2: Adventures in Add-in Installation

MindManager 7 provides the ability (through the MindManager options menu) to inspect and enable/disable already-installed add-ins.  However, it’s not clear from the UI nor Help file how to install an add-in for MindManager.  The DevZone article indicates that once I’ve built the assembly it should be installed in MM7 automatically, but I’ve built it many times and it definitely doesn’t show up in the listed add-ins in MindManager:

If the code compiled successfully, your add-in DLL was created and registered with MindManager. At this point, you are ready to test your new add-in.

I’d posted a couple of requests to the MM7 developer user forum and that’ll probably give me some clues, but in the meantime I happened to find this blog article (Creating a MindManager 7 Add-in Sample) from last summer, and spotted this gem:

“Probably the most useful thing the wizard does is create a Setup project that carries the Windows Registry settings needed to let the MindManager application locate the Add-in component at load-time.  These settings are used by MindManager to discover and load selected Add-in components.  If they are wrong, your Add-in never makes  it onto the available Add-ins list.”

[That sharp sound you heard was my hand hitting my forehead]  Duh, indeed.

Registry Settings Are the “Key”

It appears that the critical piece of info I hadn’t found in the documentation (MM7 Help file, DevZone walkthrough) was the existence of the Registry Key HKLM\Software\Mindjet\MindManager\7\Addins\.  The add-in downloadable from the “Sample” blog article creates the following in that Addins key:

  • Key = MmxSample.Connect [i.e. the ProgID for the add-in]
    • Value: FriendlyName (REG_SZ) = Pandimonium[sic] Productions Mmx Sample Add-in
    • Value: LoadBehavior (REG_DWORD) = 2
    • Value: Description (REG_SZ) = A sample MindManager Add-In to dump map contents

As well (though I wonder if this is optional — at least while developing the add-in), the Setup project creates the following entries under HKCR (HKEY_Classes_Root):

  • Key = MmxSample.Connect
    • Key = CLSID
      • Value: (Default) (REG_SZ) = {925b5786-bf6f-4ac5-9df1-61ee50a815ca}
    • Value: (Default) (REG_SZ) = MmxSample.Connect

Since these Registry values are static, it appears that MindManager enumerates the keys under \Addins at each startup.  Therefore, I believe that just building the add-in assembly does not magically make MindManager aware of the add-in you’re developing.

So perhaps I can just populate my Registry settings by hand?  The AddInSetupen.vdproj file for my add-in’s setup project intends to set these values:

  • [\Addins] Key = ParanoidMike.ToDoList.AddIn.1
    • Value: FriendlyName (REG_SZ) = MM7TODOList
    • Value: LoadBehavior (REG_DWORD) = 2
    • Value: Description (REG_SZ) = MM7TODOList|Built by ParanoidMike|Version 1.0.0


Oh hell.  I just went back to the DevZone walkthrough article, and the next thing (just beyond the point at which I abandoned the walkthrough) is this page that documents exactly the Registry settings I just unearthed.  Man, this is truly time to let it go for the evening…

One Open Question

My project’s Setup does not currently populate any HKCR settings!  Is this the cause of the “unrecoverable error” when building the Setup project?

MindManager developer resources

These are the various sources of information I’ve stumbled across so far that are useful for me (a budding MindManager add-in developer):

Resources related to Custom Properties

I anticipate leveraging custom Properties in my add-in, so I’ll want to dig into these articles when I get to that point:

Developing a MindManager Add-in for Staying On Top of my ToDo Lists

I’ve made a few attempts at staying “on top of” my workload using tools like the Getting Things Done add-in for Outlook, MindManager, and even tried the ResultsManager add-in for MindManager. Each of them help, but somehow they all seemed a bit too “high maintenance” for my needs — they required a great deal of management of metadata about each project and task, and yet I always found it hard to get a simple “to do list” summary of stuff I need to do.

It wasn’t that I couldn’t get some subset list or grouping of my tasks. I just couldn’t quite make it work for me in a way that made it easy to see what I really needed to work on.

My Woes with the Commercial Alternatives

With the GTD tool, I could see my tasks grouped by Project or by “context” (a GTD-ism for “if I’m near a phone, I should knock off all my calls; if I’m by my computer, I should knock off a bunch of computer-needing tasks all at once”). However, while I was really good about collecting all my tasks, I wasn’t so good about understanding which of them was most urgent — it all just became one big pile and I could never get a “meta-view”. I also could never get the hang of using the Prioritization field that should’ve allowed me to order & re-order all the tasks without regard for their project/context grouping.

Ages ago I’d even tried Taskline, which adds even more metadata to the Tasks in Outlook, but even with the combination of Taskline and GTD, I wasn’t able to make any more sense out of the 200+ tasks that I’d be able to collect, each time I gave these things a try.

With MindManager, I’m able to pull together a random set of ideas, tasks, steps, requirements and issues, and re-group them in ways that make sense once I’ve got them all in the same “place”. However, while it has some integration with Outlook, and I should be able to sync Tasks bidirectionally, I can’t say I’ve ever committed to the notion of marrying the incredible number of Tasks I’ve already got in Outlook to the scattered (and possibly overlapping or conflicting) musings I’ve got in MindManager.

When I added ResultsManager to MindManager, I was blown away by the UI, the great number of useful metadata I could assign to my “project planning” items (though such efforts on my part are a great insult to those skilled/sick individuals who actually know how to manage projects), and the really well-thought-out introduction process they used to familiarize customers and get them up and running quickly. However, I found that once I got all my projects, deliverables and tasks into the environment, I was still struggling to (a) find a ResultsManager template that would give me that “holy crap” daily/weekly view of my critical tasks, and (b) prioritize all my tasks relative to each other when they’re gathered together in one mind map. I’ve even tried discussing this with some of their technical evangelist types, but for all the work they did in trying to explain how to customize the ResultsManager environment, something about it didn’t click for me.

I really like the concepts behind ResultsManager — tagging items that are in multiple maps and gathering them into one “meta-map”, organizing projects into sub-deliverables and tasks, using icons and other visual elements to help annotate the information. I liked the flexibility in the design, and the implicit promise that it’ll help you see the patterns and overall workflow.

However, it doesn’t quite live up to that — at least not for me, with only a moderate amount of time invested in the training they provide for newbies (and poking around their forums and discussions). And frankly, I didn’t like what I saw when I looked under the hood — it’s all written in VBA, and becomes a real hog at any sort of scale. They’re interested in developing in .NET (or VSTA?), but between that and the effort to simplify the usability, I can’t imagine it would be really ready in time to keep me from getting fired. (I’m kidding, mostly.)

Build My Own MindManager add-in

So I’ve decided to explore the effort it would take to do something similar, but aimed at one single goal: produce a ToDo List from the task items scattered throughout my MindManager maps, and be able to prioritize (i.e. re-order) them in a persistent manner.

I know that Mindjet has produced some resources for developers who wish to add functionality to MindManager:

  • a Visual Studio template for C#/VB development
  • a Primary Interop Assembly (PIA) that installs by default with MindManager Pro 7
  • a free community portal where documentation and resources are available for registered developers

Once I downloaded the VS template, installed it, and created a new project from it, I was surprised at how many different files were generated by the wizard: there’s AssemblyInfo.cs, Connect.cs and Utility.cs in the Addin project, then a Common project and an AddinSetup_en project. This made me think there’s probably a tour of the different components in the MindManager add-in project somewhere on the Mindjet developer site, and that I’d probably earn a few shortcuts in my development time if I read up on this first.

Browse over to the Mindjet Devzone. That’s where folks like me (as well as professional development organizations) can get at the really cool developer resources. Once you’re registered, you’ll be able to access resources aimed at MindManager version 6 or version 7 such as “How to Create a MindManager 7 Add-in Using C#” and the “MindManager 7 Object Model Reference“. They even provide a downloadable archive of all their online documentation if you’d rather just dig through the info without having to login each time.

Now, it’s not well-documented where a guy like me should start, but it’s a pretty good guess that “How to Create a MM7 Add-in using C#” is a likely walkthrough for newbie developers. And as it turns out, this is definitely targeted at a C# developer who’s just starting into MindManager development.

You will need to read the guidance with a grain of salt, however; there’s a lot of steps specified in the first few sections that don’t apply if you’re using Visual Studio 2005 + the MM7 addin template (i.e. MM7AddInTemplateSetup2005.msi found in

[Also note: if you’ve got the same setup that I happen to have — which is to say, Visual Studio 2005 and Visual Studio 2008 installed side-by-side — then you’ll probably have to create your MM7 add-in project in VS2005 and then open it in VS2008. I couldn’t find a way to install the MM7 add-in template so that it showed up in the VS2008 “New Project” selection, but that’s probably because I haven’t uninstalled VS2005 yet.]

Brewing Problem

I don’t know why, but I decided to try building the Solution before I spent too much time writing code. It turns out that there are three errors with this Solution, and I don’t think the minor changes I’ve made could possibly have caused all this damage:

General failure building custom actions C:\personal\VS Projects\MM7TODOList\MM7TODOList\Common\Common.vdproj (Project=)Common

Unrecoverable build error C:\personal\VS Projects\MM7TODOList\MM7TODOList\Common\Common.vdproj (Project=)Common

Unable to import merge module ‘C:\personal\VS Projects\MM7TODOList\MM7TODOList\Common\Debug\Common.msm’ C:\personal\VS Projects\MM7TODOList\MM7TODOList\AddInSetUp\AddInSetupen.vdproj (Project=)AddInSetup_en

I figure I better get these problems resolved before too long, or else I won’t be able to debug this project and even bigger issues will go unnoticed. I’ve posted this issue to the MindManager developer forum, and I hope it gets answered soon. 🙂

Update: For the benefit of everyone who’s waited with baited breath…

Well, even if you just want to know how to deal with this, here’s what Mindjet Developer Support told me:

“The solution on the DevZone is based of VS 2005 that’s why (I am assuming) that you could not get it to compile on VS2008. I have modified your project a little bit (removed custom actions) and it is working fine.”

Couple of Open Questions

  1. What’s the difference between adding a Reference in the References section of the Solution Explorer, and adding the “using CLASSNAME” statement in each source file?
  2. If I wanted to rename a namespace after I created the project, can I just right-click on the name of the namespace (e.g. MM7TODOList) and choose Rename? Or do I need to find other dependent code fragments that don’t get updated automatically?

Certificate enrollment in .NET managed code: a primer on gathering the right tools

[y’know, I always thought that was pronounced “pr(eye)mer”, not “pr(imm)er”…]

So here I am with Visual Studio 2008 and .NET Framework 3.5, and I can’t for the life of me find a managed class that would submit an enrollment request to a Windows Certificate Server.  I know that the System.Security namespace has had a bunch of classes available (e.g. .Cryptography.Pkcs, .Cryptography.X509Certificates) that assist in the digital certificates arena.  However, there’s nothing in the framework (at least through v3.5) that appears to map in any way to the functionality in XENROLL (the Win32 container for certificate enrollment, which included COM interfaces) or CERTENROLL (the same control renamed in Windows Vista).

The only way I knew so far to take advantage of Win32 functionality in .NET was to use p/invoke to map/marshal the unmanaged call with a .NET “wrapper”.  However, when I went looking on for anything mentioning XENROLL or CERTENROLL, I came up snake eyes.

The clue that finally broke the mystery wide open for me was this article (“XENROLLLib reference for C# and VB.NET”), that seemed to indicate there was some way of getting a set of classes that exposed the XENROLL functionality.  I tried pasting some of the example code into a new Visual Studio project but that didn’t work, and when I searched the Object Browser for any default classes that contained XENROLL, XENROLLLib, CENROLL or other terms that looked like they would be base classes, I still didn’t succeed.

I don’t recall how anymore, but somewhere I connected a few dots between that article and “adding a reference” to the COM object, and then it clicked!  Damn, it seems so obvious once you know what you were supposed to do.  All I had to do was look in the Solution Explorer view, right-click on References, choose “Add Reference…”, choose the COM tab, and select the Component name “xenroll 1.0 Type Library”.

Oh, that’s right, now I remember: there was some discussion about XENROLL being a COM object, and other discussions that helped me piece together various ways to “wrap” a COM object for use by managed code.

Your best bet would be to find the Primary Interop Assembly (PIA) — i.e. the “official” RCW for the COM object in which you’re interested.  [Unfortunately, the developers of XENROLL have so far refused to acknowledge any need for a PIA for XENROLL.]

Another option would be to build an interop assembly to wrap the COM object, which requires some degree of hand-coding, but not as bad as writing the p/invoke signatures around each and every function exposed by that COM object.

However, the easiest of the “do-it-yourself” options is by adding a Reference to the COM object, and letting Visual Studio “magically”, automatically create the interop assembly (aka/or RCW) that’s needed to access the functions.

It turns out that the XENROLLLib article I’d found was really just documenting what was exposed automatically by Visual Studio when you add the Reference to “xenroll 1.0 Type Library”, but that wasn’t obvious to me (and may not be obvious to most folks who happened to stumble on the article).

Tip: the IC* interfaces are COM (scripting) oriented, and the I* interfaces are C++ oriented.  Thus, any manual work to “wrap” the native cert enrollment code in .NET interop assemblies should probably focus on IEnroll4 (which inherits from IEnroll2 and IEnroll), rather than ICEnroll4 and its predecessors.

So if I’m going to add COM references in my code to create a Cert enrollment assembly, do I just need to reference XENROLLib?  Apparently not — this discussion indicates that I’ll also need a reference “CERTCLIENTLib” to kick off the actual submission of the Certificate enrollment request to the Windows CA’s web interface.

And which COM reference will this require then?  A quick Google search on CERTCLIENTLib.CCertRequest should give me a lead pretty quick.  And bingo!  The second link is to this article, which mentions “…code below that uses the CertCli library get the certificate from the CA”, and this corresponds in Visual Studio’s “Add Reference” COM tab to “CertCli 1.0 Type Library”.  Now I’m getting the hang of this!

One open question: how do I go about actually using the Interfaces vs. the Class implementations such as CEnroll or CEnrollClass?

Summary of Findings

So there we go: to write a certificate enrollment client in C# requires a whole lot of COM interop, using COM References to “xenroll 1.0 Type Library” and “CertCli 1.0 Type Library”.  That, plus leaning heavily on samples from others who’ve gone down this path before (like here and here), should enable a pretty reusable .NET certificate enrollment library.  [Now if only Microsoft’s CERTENROLL team would add “releasing a CERTENROLL PIA” to their development schedule.]

Additional References

These will be useful at least for myself, even if they’re not useful to anyone else.

MSDN: Mapping XENROLL functions to CERTENROLL

MSDN: implementation of initializing a certificate request using a cert template (including C# code in Community section)

some native code & discussion of using IEnroll “class” (though I don’t know if the concept is known as a “class” in Win32)

An MSDN newsgroup article on requesting a certificate in managed code

MyPicasaPictures Part 5: Hacking the XP development environment for Vista Media Center applications

So I’m going through the Windows Media Center Application Step by Step guide (which incidentally, is in the XPS format — Microsoft’s pretender to the PDF throne, and a risky choice for any application to choose ahead of the widespread adoption of the underlying platform).  I’ve gotten as far as to add the References to the MediaCenter assemblies, when I realize (for the first time) that developing a Media Center application might very well mean that I have to have the development environment installed on a Media Center PC.

This seems like an odd dependency to have, considering all the other types of development projects that don’t necessarily require you to run your IDE on the target platform.  So I’m wondering if there’s a way to either (a) just drop the assembly files (i.e. the DLLs) into the expected directory and just reference them & go, or (b) I’ll have to figure out how to register those assemblies on my non-Media Center system.

On pages 5 and 6 of the Step by Step guide the instructions indicate to add references to the Microsoft.MediaCenter.dll and Microsoft.MediaCenter.UI.dll assemblies.  While it assumes you’re working from a Vista Premium/Ultimate machine and have those assemblies in the %SYSTEMROOT%\ehome folder, I found that copying those files from the VMC box and browsing to their copied location on my Windows XP SP2 system seemed to resolve the references just fine.  [I’m not convinced there won’t be other issues later on, but it’s at least worth a try.]

What’s The Sample Code Doing?

The code going into Application.cs looks interesting, but without any Comments to help us understand the purpose of each line, it’s not very instructive.  For me, this is all I’m able to infer:

  • we’re creating an Application class (though I don’t know what VMC developers would think of as an “application” — an add-in?  a piece of UI?  an assembly?  the whole Media Center process and children?)
  • we’re creating three Properties, both a private instance and its public instance (though I don’t really have any specific idea what these properties are meant to do)
  • the Application “object” is overloaded, but I’m not even sure if it’s a Property or something else
  • there are references to this, but I don’t really know what the “this” is referencing — is it the Application class, or is it something else?  [It doesn’t help that I’m not an expert at coding, so I don’t intuitively recognize what each of these things are, but it sure would help to reinforce my tentative steps into this if I had Comments that told me what I was looking at.]

I’m also puzzled by why this code doesn’t follow the Design Guidelines for Managed Class Developers, when nearly all managed code published by Microsoft adheres to these standards.  For example,

public void DialogTest(string strClickedText)

does not need “str” to prefix the ClickedText variable (aka Hungarian notation) — Visual Studio will always indicate the datatype with tooltips.

As another example, the private member variables

            int timeout = 5;
            bool modal = true;
            string caption = Resources.DialogCaption;

are all named using Camel case but without any prefix (such as a leading “_” character).  I understand that the Design Guidelines don’t specifically call out prefixing rules for member (? or private ?) variables, but apparently the guidelines do recommend the use of “this.” to prefix instance variables (which is awful confusing, as you can see above).  Personally I’d prefer to see “_” or “m_” prefixes on private member variables, but I’d at least like to see *some* consistency in the use (or non-use) of prefixes on variables.

While prefixing is a religious fight, the use of Hungarian is not — it’s clearly not recommended.

Compile Errors

I followed the Step by Step through to Build the Solution, at which point I got back one error in the compiler, at Line 55 of my code:

‘MyProject.Resources’ does not contain a definition for ‘DialogCaption’

If I followed the code adequately, the Step by Step has a bug (or at least an ambiguity) in the step Add Resources.resx/Add Strings.  Whereas the Step by Step guide actually wanted me to create one String called “DialogCaption” in the Resources file, I understood it to instruct me to create two Strings — one called “Name” and the other called “Value”:

It seems pretty obvious now, but at the time my interpretation seemed intuitive.


After resolving that more trivial issue, the next Build confronted me with this error:

The command “%windir%\eHome\McmlVerifier.exe -verbose -assemblyredirect:”C:\VS2005 Projects\MyProject\MyProject\bin\Debug” -directory:”C:\VS2005 Projects\MyProject\MyProject\Markup”” exited with code 9009.

This turned out to be harder (and dumber) to diagnose.  There were no specific errors related to McmlVerifier and 9009, and the first real lead from Google referred to path quoting issues.  I finally realized that the McmlVerifier.exe file didn’t even exist on my XP (development) system.  Strangely though, it didn’t exist on the VMC system either – is this one of the SDK tools?  Yes.  However, for some reason the SDK didn’t install it into the %windir%\ehome directory.

Once I copied McmlVerifier.exe to the ehome directory, the Build completed successfully.

Strangely, most of the steps under Enable UI Testing and MCML Verification (steps 7-17) were redundant – they were already completed on my behalf.


When I tried Debugging the solution, I got yet another error:

System.DllNotFoundException was unhandled

Unable to load DLL “EhUI.dll”: The specified module could not be found.
(Exception from HRESULT: 0x8007007E)

However, this time when I merely copied EhUI.dll to the %windir%\ehome directory, the Debugger threw another exception, slightly more impenetrable:

System.DllNotFoundException was unhandled

Unable to load DLL “EhUI.dll”: The specified procedure could not be found.
(Exception from HRESULT: 0x8007007F)

The stack trace for this was:

at Microsoft.MediaCenter.Interop.RenderApi.SpWrapBufferProc(ProcessBufferProc pfnProcessBufferProc, IntPtr* ppNativeProc)\r\n
at Microsoft.MediaCenter.Interop.RenderApi.InitArgs..ctor(MessageCookieLayout layout, ContextID idContextNew, ProcessBufferProc pfnProcessBufferProc)\r\n
at Microsoft.MediaCenter.UI.MessagingSession..ctor(UiSession parentSession, ContextID idLocalContext, TimeoutHandler handlerTimeout, UInt32 nTimeoutSec)\r\n
at Microsoft.MediaCenter.UI.UiSession..ctor(ContextID idLocalContext, IServiceProvider parentProvider, RenderingInfo renderingInfo, EventHandler rendererConnectedCallback, TimeoutHandler handlerTimeout, UInt32 nTimeoutSec)\r\n
at Microsoft.MediaCenter.UI.UiSession..ctor(RenderingInfo renderingInfo)\r\n
at Microsoft.MediaCenter.Tools.StandAlone.Startup(String[] args)\r\n
at Microsoft.MediaCenter.Tools.StandAlone.Startup()\r\n
at Microsoft.MediaCenter.Tools.McmlPad.Main(String[] args)

Given that I’ve got the Vista version of EHUI.DLL in the right place, I assumed I’d have to “register” it (I forget the equivalent in the .NET Framework world) so that its procedures could be “found”.  However, before going down a “.NET theory” path I decided to google the error message.  The first five or so forum posts that came back pointed finally clued me in that in fact this may represent a second-order dependency in another missing DLL.  With that, I decided to just copy in the entire contents of my VMC’s %WINDIR%\eHome directory and retry debugging.

Debugging exponentially: Process Monitor, Dependency Walker

That wasn’t any more successful, so next I fired up Process Monitor and watched for any “NOT FOUND” errors that followed the EHUI.DLL load event (hoping that this was merely a case of a missing filesystem reference, and not something more sinister).  That helped me discover the following errors (presumably, as is often the case in these situations, mostly a list of false negatives):

  • McmlPad.exe called RegCreateKey() for HKLM\Software\Microsoft\Fusion\GACChangeNotification\Default
  • McmlPad.exe failed to find OLE32.DLL under C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727, and oddly didn’t try searching the environment’s PATH locations
  • devenv.exe searched multiple times for C:\temp\symbols.flat.txt and McmlPad.pdb (symbols) under C:\temp\symbols\McmlPad.pdb\6B1042D64F29479FA1C07939AE072D941\, C:\Windows\symbols\exe, C:\Windows\exe, C:\Windows
  • McmlPad.exe failed to find C:\WINDOWS\assembly\GAC\PublisherPolicy.tme (and didn’t look anywhere else)
  • McmlPad.exe tried looking for a couple of files in the GAC search paths before it went looking directly for the file in C:\Windows\ehome:
    • Microsoft.MediaCenter\6.0.6000.0__31bf3856ad364e35
    • Microsoft.MediaCenter.UI\6.0.6000.0__31bf3856ad364e35
  • Once McmlPad.exe successfully loaded EHUI.DLL from C:\Windows\ehome, it (successfully) opened these files:
    • C:\WINDOWS\assembly\GAC_32\mscorlib\\sorttbls.nlp
    • C:\WINDOWS\assembly\GAC_32\mscorlib\\sortkey.nlp
  • Then devenv.exe successfully loaded C:\Program Files\Microsoft Visual Studio 8\Common7\Packages\Debugger\cscompee.dll
  • Then McmlPad.exe loaded C:\WINDOWS\assembly\NativeImages_v2.0.50727_32\System.Configuration\eee9b48577689e92db5a7b5c5de98d9b\

Hmmm, I’m not sure I learned much from that.  It looks like the application being debugged (McmlPad.exe) was looking for some GAC registration info and a few obscure files.  However, it’s likely that this is expected behaviour even on a working system.

So I went back to my google search results which convinced me to try DEPENDS.EXE to see what it would say.  I expected nothing, frankly, but that gave me two new leads I wouldn’t have otherwise found: it indicates that EHUI.DLL is looking for DWMAPI.DLL and DXGI.DLL, neither of which were present anywhere on my system.

Fascinating – one of the first Forum posts I found referencing DWMAPI.DLL indicates this file may not be needed when “linked” by a multi-OS-targeting application.  However, I suspect that for VMC libraries like EHUI.DLL, these two missing DLLs are not “load on demand” libraries – they’re just libraries that don’t appear on non-Vista platforms.

Once I grabbed copies of these two files from my Vista machine and dropped them into the %windir%\ehome folder, DEPENDS.EXE warned me that D3D10.DLL and NUCLEUS.DLL were required for DXGI.DLL, and that EHTRACE.DLL (a demand-load library) was missing.  Okey-dokey… and then I’m “warned” that even with all these files in place…:

Error: At least one module has an unresolved import due to a missing export function in an implicitly dependent module.
Warning: At least one module has an unresolved import due to a missing export function in a delay-load dependent module.

Feeling lucky despite all evidence to the contrary, I re-ran MyProject from Visual Studio, but no love was had – still and all, “the specified procedure could not be found”.  OK, let’s continue…

The unresolved imports were flagged in the following libraries on my XP development PC:


Unresolved Import(s)

MSVCRT.DLL _except_handler4_common
D3D9.DLL Direct3DCreate9Ex
USER32.DLL IsThreadDesktopComposited
MPR.DLL WNetRestoreConnectionA

So, the obvious question is: if I copy *these* libraries from my VMC computer to C:\windows\ehome on my development XP computer, will that suffice to allow McmlPad.exe + Visual Studio 2005 to successfully debug my VMC app?

And the answer is: not quite yet.  Unfortunately, when loading EHUI.DLL, Windows will still end up loading the standard libraries (such as MSVCRT.DLL) from the PATH (i.e. %windir%\system32).  I realize that Windows is just trying to behave nicely, not being “tricked” into loading rogue versions of already-installed libraries, so I am not too upset by this.  However, this has turned into a much more difficult problem than I first anticipated.

Files copied to my development system so far:

  • %windir%\ehome\Microsoft.MediaCenter.dll (from VMC system)
  • %windir%\ehome\Microsoft.MediaCenter.UI.dll (from VMC system)
  • %windir%\ehome\ehui.dll (from VMC system)
  • %programfiles%\Microsoft SDKs\Windows Media Center\v5.0\Tools\McmlVerifier.exe (to %windir%\ehome)
  • %programfiles%\Microsoft SDKs\Windows Media Center\v5.0\Tools\McmlPad.exe (to %windir%\ehome)
  • %windir%\system32\dwmapi.dll (from VMC system)
  • %windir%\system32\dxgi.dll (from VMC system)
  • %windir%\system32\d3d10.dll (from VMC system)
  • nucleus.dll (from I don’t remember where)
  • %windir%\system32\msvcrt.dll (from VMC system)
  • %windir%\system32\d3d9.dll (from VMC system)
  • %windir%\system32\user32.dll (from VMC system)
  • %windir%\system32\advapi32.dll (from VMC system)
  • %windir%\system32\mpr.dll (from VMC system)


  • 😦 “I will say that if you are a hobbyist then MCML is not likely to be very friendly to you.”
  • 😦 “It took me a long while to create a gallery that displays a list of images from an ArrayListDataSet.”
  • 🙂 “I have persevered in the days since my last post and have managed to get a repeater/scroller working to emulate the behaviour of the ‘my music’ section of media center.”
  • 🙂 has a good tutorial on making the sliding menu at the top of the screen.”
  • 😦 “Following the rumour about Microsoft encouraging their internal teams to deprecate the use of an underscore prefix for private fields, I have decided to do the same.”  [I just got my head wrapped around the use of underscores for private fields, and now I need to unlearn that behaviour just as quickly.  At least I haven’t done too much damage with it.]
  • 🙂 “If you can’t easily work out where the variable is defined (local scope, local parameter, member variable) then your code is too complex and needs refactoring.  It’s that simple.”  [I can handle that idea, yeah.]