Как установить строку конструктора компонента COM+ из .NET?

Я пытаюсь программно установить конструктор компонента COM+ из приложения C#. Я нашел в Интернете следующий пример кода, но он выдает исключение:

        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();
                    }
                }
            }
        }

Когда я запускаю этот код, я получаю следующее исключение в строке 6:

Не удалось преобразовать COM-объект типа «System.__ComObject» в класс типа «COMAdmin.COMAdminCatalogCollectionClass». Компоненты COM, которые входят в среду CLR и не поддерживают IProvideClassInfo или не имеют зарегистрированных сборок взаимодействия, будут заключены в тип __ComObject. Экземпляры этого типа нельзя привести ни к какому другому классу; однако их можно приводить к интерфейсам, если базовый компонент COM поддерживает вызовы QueryInterface для IID интерфейса.

Есть идеи, где я ошибаюсь? Или есть более простой способ сделать это?


person Brian Sullivan    schedule 19.11.2008    source источник
comment
Чего именно вы пытаетесь достичь здесь?   -  person Grzenio    schedule 19.11.2008
comment
Я хочу установить строку конструктора для компонента COM+. Я понимаю, что этот код на самом деле не установит его, но я хотел сначала попытаться отобразить строку, но пока не могу даже этого сделать.   -  person Brian Sullivan    schedule 19.11.2008


Ответы (2)


Я нашел способ избежать исключения. Вместо того, чтобы делать это на C#, я могу воспользоваться опциональной слабой типизацией VB.NET, чтобы удалить все приведения типов и несколько типов объявлений переменных. Результирующий код выглядит следующим образом:

    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

Это одна из ситуаций, в которой VB и C# существенно различаются, и знание этих вещей действительно поможет вам выбрать правильный инструмент для работы.

person Brian Sullivan    schedule 19.11.2008

Я уверен, что вы хорошо продвинулись, но в настоящее время я работаю над проектом, которому нужна аналогичная функциональность, и я смог найти решение, используя для этого .NET и PowerShell. Сначала я создал собственный командлет на C# следующим образом:

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;
            }
        }
    }
}

Затем импортируйте этот модуль в сценарий PowerShell и запустите его следующим образом:

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

PS C:\Windows\system32> Set-COMConstructorString <Application Name> <Component Name> <Constructor String>
person William Delong    schedule 17.06.2014