Friday, March 11, 2005

COM Types in interop projects

The Tridion Object Model (TOM) is still in good old (VB6) COM.
When creating eventsystems, or other solutions on top of the TOM in .Net, it can get hard to know what you are dealing with.

Typically (in C#) you would use something like:

TDS.TDSE tdse = new TDS.TDSEClass();

object o = tdse.GetObject(myUri,TDSDefines.EnumOpenMode.OpenModeView,

                            null, TDSDefines.XMLReadFilter.XMLReadAll);


Now, what Tridion Type is object o???

First guess: use o.GetType!
Sure (says the CLR), its a __ComObject (duh).
Well, that didn't help us any thing.

Second Try.
What does Bill tell us to to?
Lets create a function like this:

public string TridionType (object o)

{

    if (o is TDS.Publication)

    {

        return "Publication";

    }

    else if (o is TDS.Folder)

    {

        return "Folder";

    }

    // and so on, and on, and on... and maintenance hell and so on

}


Since we do almost all of our .Net development in C#, the easiest solution was a bit hard to swallow:

Add a reference to the "Microsoft Visual Basic .NET Runtime" assembly.
The above mentioned function is then simply reduced to:

public string TridionType (object o)

{

    return Microsoft.VisualBasic.Information.TypeName(o);

}   




Damn... I just found an advantage of VB.Net

5 comments:

Anonymous said...

Frank,

Interesting subject. I've also been experimenting a lot with C# and the TOM, as are some colleagues of mine at this very moment.

Please also see this blog entry of mine, which also has a link to our forum where a discussion about this very subject is taking place.

René

Anonymous said...

I'm still puzzling how to get this right.
Using
TDS.TDSE tdsTdse = new TDS.TDSEClass();

and
object obj = tdsTdse.GetObject("tcm:0-2-1", TDSDefines.EnumOpenMode.OpenModeView, null, TDSDefines.XMLReadFilter.XMLReadAll);

results in
Unable to get TOM object for URI: tcm:0-2-1.
Unable to Initialize TDSE object.
Access is denied for the user NT AUTHORITY\NETWORK SERVICE.

Seems that either my security is too tight or I need to do an Impersonate().

Buck said...

It is indeed all about whos running the show.
From the username shown, I would say you're trying to do some stuff from an IIS6. IIS6 will run its processes (w3wp) under the NETWORK SERVICES user, no matter what the security level on the website.

As such, it differs from IIS5 where the calling user would be used on OS level.

For Tridion usage this means indeed that you'll need to call the Impersonate function like:

tdse.Impersonate(System.Web.HttpContext.Current.User.Identity.Name);

Anonymous said...

Just for completeness, here's another approach.
I've avoided using it in practice myself, as I suspect that the "maintenance hell" version performs better (especially as you can put the most likely to succeed cast at the top)


Anyway - let's say that you want to call GetXml from an organizational item, and you know that the signature of GetXml is the same for a folder and a structure group. You can avoid casting altogether, and just invoke the method by reflection.

(This snippet is a little out of context, so you have to imagine the rest.)

object[] args = new object[1];
args[0] = filter;
orgItemDoc.LoadXml((string)orgItem.GetType().InvokeMember("GetXML",
System.Reflection.BindingFlags.Public
| System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.InvokeMethod
, null, orgItem, args));
return orgItemDoc;

Like I said, in practice I'm just working with the casts, but somebody somewhere might have a use case where this is the only way.

Anonymous said...

thanks for this kindly tips 147896325