我正在尝试以编程方式从C#应用程序设置COM +组件的构造函数sting。我在网上找到了以下示例代码,但它引发了异常:
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行得到以下异常:
无法将类型为“System .__ ComObject”的COM对象强制转换为类类型“COMAdmin.COMAdminCatalogCollectionClass”。进入CLR但不支持IProvideClassInfo或没有注册任何interop程序集的COM组件将包装在__ComObject类型中。此类型的实例不能转换为任何其他类;但是只要底层的COM组件支持对接口的IID的QueryInterface调用,它们就可以转换为接口。
知道我哪里出错了吗?或者有更简单的方法吗?
答案 0 :(得分:2)
我找到了避免异常的方法。我可以利用VB.NET的可选弱类型删除所有的转换和一些变量声明类型,而不是在C#中执行此操作。结果代码如下所示:
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#显着不同的一种情况,了解这些事情确实有助于您为工作选择合适的工具。
答案 1 :(得分:0)
我确信你已经顺利通过了这个,但我正在开发一个目前需要类似功能的项目,我能够提出一个使用.NET和PowerShell的解决方案。首先,我在C#中创建了一个自定义cmdlet,如下所示:
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>