tags:

views:

454

answers:

1

I'm trying to programmatically set the constructor sting of a COM+ component from a C# application. I found the following sample code online, but it throws an exception:

        COMAdminCatalogCollection Components;
        COMAdminCatalogClass Catalog = new COMAdminCatalogClass();
        string strConstr;
        string ApplicationName = "ApplicationName"; // case sensitive
        string CompName = "MyComponent.ProgID";
        COMAdminCatalogCollectionClass Applications = (COMAdminCatalogCollectionClass)Catalog.GetCollection("Applications");
        Applications.Populate();
        // find the correct application
        foreach (COMAdminCatalogObjectClass AppObject in Applications)
        {
            if (AppObject.Name == ApplicationName)
            {
                // find matching component
                Components = (COMAdminCatalogCollectionClass)(Applications.GetCollection("Components", AppObject.Key));
                Components.Populate();
                foreach (COMAdminCatalogObjectClass CompObject in Components)
                {
                    if (CompObject.Name.ToString() == CompName)
                    {
                        CompObject.get_Value("ConstructorString").ToString();
                        CompObject.get_Value("ConstructionEnabled").ToString();
                    }
                }
            }
        }

When I run this code, I get the following exception on line 6:

Unable to cast COM object of type 'System.__ComObject' to class type 'COMAdmin.COMAdminCatalogCollectionClass'. COM components that enter the CLR and do not support IProvideClassInfo or that do not have any interop assembly registered will be wrapped in the __ComObject type. Instances of this type cannot be cast to any other class; however they can be cast to interfaces as long as the underlying COM component supports QueryInterface calls for the IID of the interface.

Any idea where I'm going wrong? Or is there an easier way to do this?

+2  A: 

I found a way to avoid the exception. Rather than doing this in C#, I can take advantage of VB.NET's optional weak typing to remove all of the casts and a couple of the variable declaration types. The resulting code looks like this:

    Dim Components As COMAdminCatalogCollection
    Dim Catalog As New COMAdminCatalogClass()
    Dim ApplicationName As String = "ApplicationName"
    Dim CompName As String = "MyComponent.ProgID"
    Dim Applications = Catalog.GetCollection("Applications")
    Applications.Populate()
    For Each AppObject In Applications

        If (AppObject.Name = ApplicationName) Then

            Components = (Applications.GetCollection("Components", AppObject.Key))
            Components.Populate()
            For Each CompObject In Components

                If (CompObject.Name.ToString() = CompName) Then
                    CompObject.Value("ConstructorString") = "Some new value"

                    Components.SaveChanges()
                End If

            Next
        End If
    Next

This is one situation in which VB and C# significantly differ, and knowing these things really helps you choose the right tool for the job.

Brian Sullivan