How do I set the constructor string of a COM+ component from .NET?
Asked Answered
N

2

0

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?

Noh answered 19/11, 2008 at 16:16 Comment(2)
What exactly are you trying to achieve here?Onaonager
I want to set the constructor string for a COM+ component. I realize that this code won't actually set it, but I wanted to try to display the string first, and I can't even do that yet.Noh
N
3

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.

Noh answered 19/11, 2008 at 18:11 Comment(0)
C
2

I'm sure you have moved well passed this but I am working on a project currently that needs a similar functionality and I was able to come up with a solution using .NET and PowerShell to do so. First I created a custom cmdlet in C# as follows:

using COMAdmin;
using System;
using System.Runtime.InteropServices;
using System.Management.Automation;

namespace COMAdminModule
{
    // Name the cmdlet
    [Cmdlet("Set", "COMConstructorString")]
    public class SetCOMConstructorSting : PSCmdlet
    {

        // App name Parameter
        private string comAppName;

        [Parameter(
            Mandatory = true,
            ValueFromPipelineByPropertyName = true,
            ValueFromPipeline = true,
            Position = 0,
            HelpMessage = "Name of COM+ Application"
            )]

        [Alias("App Name")]


        public string COMApp
        {
            get { return comAppName; }
            set { comAppName = value; }
        }


        // App Component name
        private string componentName;

        [Parameter(
            Mandatory = true,
            ValueFromPipelineByPropertyName = true,
            ValueFromPipeline = true,
            Position = 1,
            HelpMessage = "The name of the Component that will receive a new Constructor string"
            )]

        [Alias("Component Name")]


        public string ComponentName
        {
            get { return componentName; }
            set { componentName = value; }
        }


        // Constructor String
        private string constructorString;

        [Parameter(
            Mandatory = true,
            ValueFromPipelineByPropertyName = true,
            ValueFromPipeline = true,
            Position = 2,
            HelpMessage = "The new Constructor string"
            )]

        [Alias("Constructor String")]


        public string ConstructorString
        {
            get { return constructorString; }
            set { constructorString = value; }
        }


        // Provides a one-time, preprocessing functionality for the cmdlet
        protected override void BeginProcessing()
        {
            base.BeginProcessing();
        }

        // Provides a record-by-record processing functionality for the cmdlet
        protected override void ProcessRecord()
        {
            string working = "Setting the constructor string " + constructorString;
            working = " to the Component " + componentName;
            working += " for the COM App " + comAppName;

            WriteObject(working);

            setConstructorString(comAppName, componentName, constructorString);
        }

        // Provides a one-time, post-processing functionality for the cmdlet
        protected override void EndProcessing()
        {
            base.EndProcessing();
        }




        //Add component method
        private void setConstructorString(string comAppName, string componentName, string constructorString)
        {
            ICOMAdminCatalog2 oCatalog = null;

            try
            {

                //Create the comAdmin object
                oCatalog = (ICOMAdminCatalog2)Activator.CreateInstance(Type.GetTypeFromProgID("ComAdmin.COMAdminCatalog"));

                //Get the comApps
                ICatalogCollection comApps = (ICatalogCollection)oCatalog.GetCollection("Applications");
                comApps.Populate();


                foreach (ICatalogObject app in comApps)
                {

                    //Find the comApp
                    if (app.Name.ToString().Equals(comAppName))
                    {
                        //Get the Components
                        ICatalogCollection components = (ICatalogCollection)comApps.GetCollection("Components", app.Key);
                        components.Populate();


                        foreach (ICatalogObject component in components) 
                        {
                            //Find the component
                            if (component.Name.ToString().Equals(componentName))
                            {
                                // Set the constructor string
                                component.set_Value("ConstructorString", constructorString);

                                components.SaveChanges();

                                break;
                            }

                        }

                        break; 
                    }

                }

            }
            catch (Exception e)
            {
                WriteObject(e.Source);
                throw;
            }
        }
    }
}

And then Import that Module into a PowerShell Script and run it as follows:

PS C:\Windows\system32> Import-Module "<dll path>"

PS C:\Windows\system32> Set-COMConstructorString <Application Name> <Component Name> <Constructor String>
Chavis answered 17/6, 2014 at 16:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.