简体   繁体   中英

Iterate ActiveX collection object with late bind interop on C# (COMAdminCatalogCollection)

I need to iterate COM+/ActiveX collection objects using late bind interop in C#. At this very moment I need to iterate COMAdmin.COMAdminCatalogCollection , from GetCollection("Applications") method in COMAdmin.COMAdminCatalog . But as it is a POC to be used with others proprietary COM+/ActiveX objects I need to get this done with late bound. How I should box my object object to be iterable?

COMPlus.cs

public abstract class COMPlus
{
    public object COMObject { get; private set; }
    public System.Type COMObjectType { get; private set; }

    protected COMPlus(string progId)
    {
        this.COMObject = System.Activator.CreateInstance(System.Type.GetTypeFromProgID(progId));
        this.COMObjectType = this.COMObject.GetType();
    }

    protected COMPlus(object comObject, string progId)
    {
        this.COMObject = comObject;
        this.COMObjectType = System.Type.GetTypeFromProgID(progId);
    }
}

COMAdminCatalog.cs

public class COMAdminCatalog : COMPlus
{
    public COMAdminCatalog() : base("COMAdmin.COMAdminCatalog") { }
    public COMAdminCatalog(object comObject) : base(comObject, "COMAdmin.COMAdminCatalog") { }

    public void Connect(string serverAddress)
    {

    }

    public COMAdminCatalogCollection GetCollection(string collectionName)
    {
        return new COMAdminCatalogCollection(
            base.COMObjectType.InvokeMember("GetCollection",
                System.Reflection.BindingFlags.InvokeMethod,
                null,
                base.COMObject,
                new object[] { (object)collectionName }));
    }
}

COMAdminCatalogCollection.cs

public class COMAdminCatalogCollection : COMPlus
{
    public COMAdminCatalogCollection() : base("COMAdmin.COMAdminCatalog") { }
    public COMAdminCatalogCollection(object comObject) : base(comObject, "COMAdmin.COMAdminCatalog") { }

    public void Populate()
    {
        base.COMObjectType.InvokeMember("Populate",
            System.Reflection.BindingFlags.InvokeMethod,
            null,
            base.COMObject, null);
    }
}

Toolbox.cs

public static class Toolbox
{
    public static void CreateApp(string appName, string serverAddress = null)
    {
        COMAdminCatalog comAdminCatalog = new Interop.COMAdmin.COMAdminCatalog();
        COMAdminCatalogCollection comAdminCatalogCollection;

        if (!String.IsNullOrEmpty(serverAddress))
        {
            comAdminCatalog.Connect(serverAddress);
        }

        comAdminCatalogCollection = comAdminCatalog.GetCollection("Applications");

        comAdminCatalogCollection.Populate();

        // here the fun has to begin iterating the Applications collection to verify if there is already an application with the given name or not.
    }
}

EDIT

I need it compatible with .Net 2.0 (3.5 tops), so dynamic don't suits me.

You use the foreach keyword in C#, just like you normally would to iterate a collection. The DLR knows how to automagically map it to the ICatalogCollection::_NewEnum() method.

Let's first do the early-bound version since it is so very unlikely that you really want to do this late-bound. This server has been stable for a very long time and the .NET 4.0 Embed Interop Types feature avoid any dependency on an interop library. Use Project > Add Reference > Browse button > select c:\\windows\\system32\\com\\comadmin.dll. Sample code:

static void EarlyBound(string server) {
    var cat = new COMAdmin.COMAdminCatalog();
    cat.Connect(server);
    var coll = (COMAdmin.COMAdminCatalogCollection)cat.GetCollection("Applications");
    coll.Populate();
    foreach (COMAdmin.ICatalogObject app in coll) {
        Console.WriteLine(app.Name);
        var comps = coll.GetCollection("Components", app.Key);
        comps.Populate();
        foreach (COMAdmin.ICatalogObject comp in comps) {
            Console.WriteLine("  {0} - {1}", comp.Name, comp.Key);
        }
    }
}

The late-bound version isn't very different thanks to the dynamic keyword:

static void LateBound(string server) {
    var catt = Type.GetTypeFromProgID("COMAdmin.COMAdminCatalog");
    dynamic cat = Activator.CreateInstance(catt);
    cat.Connect(server);
    dynamic coll = cat.GetCollection("Applications");
    coll.Populate();
    foreach (dynamic app in coll) {
        Console.WriteLine(app.Name);
        dynamic comps = coll.GetCollection("Components", app.Key);
        comps.Populate();
        foreach (dynamic comp in comps) {
            Console.WriteLine("  {0} - {1}", comp.Name, comp.Key);
        }
    }
}

As demanded, the late-bound version of this code for .NET 2.0, cruel and unusual punishment that's outlawed by the Geneva Convention on Programmer's Rights. You obtain the iterator from the _NewEnum() COM method, you can cast it to IEnumerator:

static void LateBound20(string server) {
    Type catt = Type.GetTypeFromProgID("COMAdmin.COMAdminCatalog");
    object cat = Activator.CreateInstance(catt);
    cat.GetType().InvokeMember("Connect", BindingFlags.InvokeMethod, null,
        cat, new object[] { server });
    object coll = cat.GetType().InvokeMember("GetCollection", BindingFlags.InvokeMethod, null,
        cat, new object[] { "Applications" });
    coll.GetType().InvokeMember("Populate", BindingFlags.InvokeMethod, null,
        coll, new object[] { });
    object iter = coll.GetType().InvokeMember("_NewEnum", BindingFlags.InvokeMethod, null,
        coll, new object[] { });
    System.Collections.IEnumerator iter1 = (System.Collections.IEnumerator)iter;
    while (iter1.MoveNext()) {
        object app = iter1.Current;
        object name = app.GetType().InvokeMember("Name", BindingFlags.GetProperty, null,
            app, new object[] { });
        object key = app.GetType().InvokeMember("Key", BindingFlags.GetProperty, null,
            app, new object[] { });
        Console.WriteLine(name.ToString());
        object comps = coll.GetType().InvokeMember("GetCollection", BindingFlags.InvokeMethod, null,
            coll, new object[] { "Components", key });
        comps.GetType().InvokeMember("Populate", BindingFlags.InvokeMethod, null,
            comps, new object[] { });
        object iter2 = comps.GetType().InvokeMember("_NewEnum", BindingFlags.InvokeMethod, null,
            comps, new object[] { });
        System.Collections.IEnumerator iter3 = (System.Collections.IEnumerator)iter2;
        while (iter3.MoveNext()) {
            object comp = iter3.Current;
            object cname = comp.GetType().InvokeMember("Name", BindingFlags.GetProperty, null,
                comp, new object[] { });
            object ckey = comp.GetType().InvokeMember("Key", BindingFlags.GetProperty, null,
                comp, new object[] { });
            Console.WriteLine("  {0} - {1}", cname, ckey);
        }
    }
}

Output on my COM+ unencumbered machine for all three snippets:

COM+ Utilities
  RemoteHelper.RemoteHelper - {E423AF7C-FC2D-11D2-B126-00805FC73204}
  TxCTx.TransactionContext - {7999FC25-D3C6-11CF-ACAB-00A024A55AEF}
  TxCTx.TransactionContextEx - {5CB66670-D3D4-11CF-ACAB-00A024A55AEF}
  QC.Recorder - {ECABAFC2-7F19-11D2-978E-0000F8757E2A}
  QC.ListenerHelper - {ECABAFC4-7F19-11D2-978E-0000F8757E2A}
COM+ QC Dead Letter Queue Listener
  QC.DLQListener - {ECABAFCA-7F19-11D2-978E-0000F8757E2A}
COM+ Explorer
  COMEXPS.CTrkEvntListener - {2C3E140B-7A0D-42D1-B2AA-D343500A90CF}
COM+ Utilities (32 bit)
  RemoteHelper.RemoteHelper - {E423AF7C-FC2D-11D2-B126-00805FC73204}
  TxCTx.TransactionContext - {7999FC25-D3C6-11CF-ACAB-00A024A55AEF}
  TxCTx.TransactionContextEx - {5CB66670-D3D4-11CF-ACAB-00A024A55AEF}
  QC.Recorder - {ECABAFC2-7F19-11D2-978E-0000F8757E2A}
  QC.ListenerHelper - {ECABAFC4-7F19-11D2-978E-0000F8757E2A}
System Application
  Catsrv.CatalogServer - {182C40F0-32E4-11D0-818B-00A0C9231C29}
  EventPublisher.EventPublisher - {ECABAFBC-7F19-11D2-978E-0000F8757E2A}
  COMSVCS.TrackerServer - {ECABAFB9-7F19-11D2-978E-0000F8757E2A}
  Mts.MtsGrp - {4B2E958D-0393-11D1-B1AB-00AA00BA3258}
  Pdump.ProcessDump - {ECABB0C4-7F19-11D2-978E-0000F8757E2A}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM