Thursday, January 11, 2007

IDSObjectPicker - Why isn't there one for .NET?

About a year and a half ago, I was writing a piece of software that did a lot of things in Active Directory, with Group Policy Objects specifically, but that's not relevant here.  What is relevant is that I wanted to pop up a dialog to allow the user to select one or more user objects from active directory.  I had used the IDSObjectPicker interface before, however, all the other times I had used it were in unmanaged C++.  This was the first time I would attempt it in managed code.

For the uninitiated, IDSObjectPicker is a goddamn miserable interface.  If I met its author on the street, I would punch balls first and ask questions later.  It looks unassuming with only two exposed methods, but those methods belie a seething underbelly of complex nested structures and obscure enumerations.  You could write a whole page of code just filling out all the required bit masks, creating arrays of other structures to assign to the previous structures, etc.

I honestly thought, given my previous fantastic experiences with C# (especially with COM interop) that this was going to be easier than before.  I would reference the COM DLL in which the interface resided, and everything would be marshaled for me.

I was mistaken.

It turns out that this was my first time using COM interop with a COM interface that didn't stick to automation types (BSTR, VARIANT, etc.) for its parameters -- They would just get marshaled across the interop boundary as Objects.  I spend about two days writing tedious C# code to re-create enumerated types and manually marshal as much of the parameters and return values as I needed until I got to one particular structure that vexed me.  

DSOP_INIT_INFO.apwzAttributeNames

It's not even really a complicated structure.  MSDN describes it as a "Pointer to an array of null-terminated Unicode strings".  As simple as that sounds, I went as far as manually allocated the array's memory using the Marshal.Alloc* methods, and attempting to binary-copy the memory in an attempt to get it to take that value, but it just wouldn't.

Giving up when it comes to something I'm pretty sure is possible is not something I usually do, but I was ready to punch my monitor at this point (and it was the big, heavy, 19" CRT kind).  I eventually threw in the towel and wrote a wrapper COM object in unmanaged C++ for IDSObjectPicker which translated the input parameters from automation-types to pass in, and the return values back to automation-types to pass back.  That was the only way I managed to get the IDSObjectPicker working in .NET.

I recently stumbled upon this guy who had the exact same problem that I did, which is what prompted me to make this post.  We're not alone.

So WHY isn't there an equivalent, .NET-ified version of this godforsaken interface?

2 comments:

Sergio Rykov said...

I found your note by pure accident. I've spent 1 day to create working wrapper. It seemed that it would be easy. But when I've changed value



initInfo.apwzAttributeNames = 0



from zero ... Heh. We are not alone :(. :)

Paul Ward said...

Download the "Active Directory Common Dialogs" project at http://adui.codeplex.com/.

If you apply patch 7313 from eugicts, the library supports retrieving additional attributes.

Contributors