在 C# 上使用后期绑定互操作迭代 ActiveX 集合对象 (COMAdminCatalogCollection)
Iterate ActiveX collection object with late bind interop on C# (COMAdminCatalogCollection)
我需要在 C# 中使用后期绑定互操作来迭代 COM+/ActiveX 集合对象。此时此刻,我需要从 COMAdmin.COMAdminCatalog
中的 GetCollection("Applications")
方法迭代 COMAdmin.COMAdminCatalogCollection
。但由于它是一个与其他专有 COM+/ActiveX 对象一起使用的 POC,我需要通过后期绑定来完成这项工作。我应该如何将我的 object
对象装箱成可迭代的?
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.
}
}
编辑
我需要兼容.Net 2.0 (3.5 tops),所以dynamic不适合我。
您在 C# 中使用 foreach
关键字,就像您通常迭代集合一样。 DLR 知道如何自动将其映射到 ICatalogCollection::_NewEnum()
方法。
让我们先做早期绑定版本,因为你不太可能真的想做这个后期绑定。该服务器已经稳定了很长时间,.NET 4.0 嵌入互操作类型功能避免了对互操作库的任何依赖。使用项目 > 添加引用 > 浏览按钮 > select c:\windows\system32\com\comadmin.dll。示例代码:
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);
}
}
}
由于 dynamic
关键字,后期绑定版本并没有太大的不同:
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);
}
}
}
根据要求,此代码的后期绑定版本适用于 .NET 2.0,《日内瓦程序员权利公约》禁止的残酷和不寻常的惩罚。您从 _NewEnum() COM 方法获得迭代器,您可以将其转换为 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);
}
}
}
所有三个片段在我的 COM+ 无阻碍机器上的输出:
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}
我需要在 C# 中使用后期绑定互操作来迭代 COM+/ActiveX 集合对象。此时此刻,我需要从 COMAdmin.COMAdminCatalog
中的 GetCollection("Applications")
方法迭代 COMAdmin.COMAdminCatalogCollection
。但由于它是一个与其他专有 COM+/ActiveX 对象一起使用的 POC,我需要通过后期绑定来完成这项工作。我应该如何将我的 object
对象装箱成可迭代的?
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.
}
}
编辑
我需要兼容.Net 2.0 (3.5 tops),所以dynamic不适合我。
您在 C# 中使用 foreach
关键字,就像您通常迭代集合一样。 DLR 知道如何自动将其映射到 ICatalogCollection::_NewEnum()
方法。
让我们先做早期绑定版本,因为你不太可能真的想做这个后期绑定。该服务器已经稳定了很长时间,.NET 4.0 嵌入互操作类型功能避免了对互操作库的任何依赖。使用项目 > 添加引用 > 浏览按钮 > select c:\windows\system32\com\comadmin.dll。示例代码:
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);
}
}
}
由于 dynamic
关键字,后期绑定版本并没有太大的不同:
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);
}
}
}
根据要求,此代码的后期绑定版本适用于 .NET 2.0,《日内瓦程序员权利公约》禁止的残酷和不寻常的惩罚。您从 _NewEnum() COM 方法获得迭代器,您可以将其转换为 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);
}
}
}
所有三个片段在我的 COM+ 无阻碍机器上的输出:
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}