http://blog.robinzhong.com/index.php/archives/2006/09/28/124.html
在M$平台上面开发软件,很有可能要和COM+组件交互.或者写一个COM+组件,或者调用这样的一个组件.
但是M$只提供了MMC来管理COM+组件,没有提供的命令行的版本来增加/删除/修改COM+组件 ( 这是M$的一个习惯.不知道 PowerShell 出来后会不会好一点^-^).这对于全自动化的要求来说,是一个不小的问题.
不过,幸好M$不是白痴(这个,显然啦),M$系统管理的部分都是以COM组件提供出来的,所以我们可以直接调用 COMAdmin 这样一个组件来管理我们的COM+组件 :)
下面是我前一段时间写的一个简单的COMAdmin的C# Wrapper类.关于COMAdmin的具体使用,请 google 吧...
提前说一下: 这个只是满足我自己的需要写的,肯定是不完善的.比如不支持一个dll多个COMComponent...
这个是COMApplication类:
using System; using System.Collections.Generic; using System.Text; using COMAdmin; namespace COMAdmin.NET { public class ComApplication : IDisposable { #region Const Variations. private const string C_APPLICATIONS = "Applications"; const string c_DESCRIPTION = "Description"; const string c_CHANGEABLE = "Changeable"; const string c_DELETABLE = "Deleteable"; const string c_ACTIVATION = "Activation"; const string c_NAME = "Name"; #endregion #region COMAdmin related objects private COMAdminCatalog _com; private COMAdminCatalogCollection _apps; private COMAdminCatalogObject _app; #endregion #region Properties private string _appName; private int _index; public string Key { get { return (string) this._app.Key; } } public string AppName { get { return _appName; } set { _appName = value;this._app.set_Value( c_NAME,value); } } public string Desc { get { return this._app.get_Value(c_DESCRIPTION) as string; } set { this._app.set_Value( c_DESCRIPTION, value ); } } public bool Changeable { get { return (bool)this._app.get_Value(c_CHANGEABLE); } set { this._app.set_Value(c_CHANGEABLE,value); } } public bool Deletable { get { return (bool)this._app.get_Value(c_DELETABLE); } set { this._app.set_Value(c_DELETABLE,value); } } public COMActivationOptions AcOption { get { return (COMActivationOptions)Enum.Parse(typeof(COMActivationOptions),this._app.get_Value(c_ACTIVATION).ToString()); } set { this._app.set_Value(c_ACTIVATION,Enum.Parse(typeof(COMAdminActivationOptions),value.ToString())); } } internal COMAdminCatalogObject Application { get { return _app; } } internal COMAdminCatalogCollection Applications { get { return _apps; } } internal COMAdminCatalog COMAdminObj { get { return _com; } } #endregion #region Private Methods. private void InitialCOM ( ) { if (COMAdminObj == null || _apps == null) { _com = new COMAdminCatalogClass(); _apps = COMAdminObj.GetCollection( C_APPLICATIONS ) as COMAdminCatalogCollection; this._apps.Populate(); } } private void RetrieveAppObj() { _index = 0; foreach (COMAdminCatalogObject item in this._apps) { if (item.Name.ToString() == AppName) { _app = item; break; } _index++; } } private void InitialAppInfo() { RetrieveAppObj(); if (_app == null) { throw new NonExistComApplicationException( AppName ); } } private void InnerCreate() { InitialCOM(); _app = _apps.Add() as COMAdminCatalogObject; } protected virtual void Dispose(bool disposing) { if( disposing) { // free managed resource. } if( _app != null) { _app = null; } if( _apps != null) { _apps = null; } if( _com != null) { _com = null; } } #endregion #region Public Methods public static ComApplication Create () { ComApplication newapp = new ComApplication(); newapp.InnerCreate(); return newapp; } public static void Delete(string appName) { new ComApplication( appName ).Delete(); } public static bool IsExistApplication(string appName) { ComApplication temp = new ComApplication(); temp._appName = appName; temp.InitialCOM(); temp.RetrieveAppObj(); if( temp._app == null) { return false; } else { return true; } } public void Delete() { if (_app == null) { throw new NonExistComApplicationException(_appName); } _app = null; _apps.Remove(_index); _apps.SaveChanges(); Dispose(); } public void Save() { _apps.SaveChanges(); } public static IList<ComApplication> QueryApplications() { List<ComApplication> result = new List<ComApplication>( ); COMAdminCatalog _catalog = new COMAdminCatalog( ); COMAdminCatalogCollection _collections = _catalog.GetCollection( C_APPLICATIONS ) as COMAdminCatalogCollection; _collections.Populate( ); int curIndex = 0; foreach(COMAdminCatalogObject obj in _collections) { ComApplication comapp = new ComApplication( ); comapp._app = obj; comapp._appName = obj.Name as string; comapp._apps = _collections; comapp._com = _catalog; comapp._index = curIndex; curIndex++; result.Add( comapp ); } return result; } #region IDisposable Members public void Dispose ( ) { Dispose( true ); GC.SuppressFinalize( this ); } #endregion #endregion #region Constructor public ComApplication(string appName) : this() { _appName = appName; InitialCOM(); InitialAppInfo(); } internal ComApplication ( ) {} #endregion } }
接下来是 COMComponent 类:
using System; using System.Collections.Generic; using System.Text; using COMAdmin; using Microsoft.Win32; namespace COMAdmin.NET { public class ComComponent:IDisposable { #region Fields and Properties #region Const Variation const string c_COMPONENTS = "Components"; const string c_DESCRIPTION = "Description"; const string c_ConstructionEnabled = "ConstructionEnabled"; const string c_ConstructorString = "ConstructorString"; const string c_JustInTimeActivation = "JustInTimeActivation"; const string c_COMTIIntrinsics = "COMTIIntrinsics"; const string c_Synchronization = "Synchronization"; const string c_Transaction = "Transaction"; const string c_Name = "Name"; #endregion #region COMAdmin Related Objects private ComApplication _capp; private string _compName; private COMAdminCatalogCollection _comps; private COMAdminCatalogObject _comp; private int _index; #endregion #region Public Properties public string Name { get { return this._comp.Name as string; } } public string CompName { get { return _compName; } } public string Key { get { return (string)this._comp.Key; } } public string Description { get { return (string)this._comp.get_Value(c_DESCRIPTION); } set { this._comp.set_Value(c_DESCRIPTION,value); } } public bool ConstructionEnabled { get { return (bool)this._comp.get_Value(c_ConstructionEnabled); } set { this._comp.set_Value(c_ConstructionEnabled,value); } } public string ConstructorString { get { return (string) this._comp.get_Value( c_ConstructorString ); } set { this._comp.set_Value( c_ConstructorString, value ); } } public bool JustInTimeActivation { get { return (bool) this._comp.get_Value( c_JustInTimeActivation ); } set { this._comp.set_Value( c_JustInTimeActivation, value ); } } public bool COMTIIntrinsics { get { return (bool) this._comp.get_Value( c_COMTIIntrinsics ); } set { this._comp.set_Value( c_COMTIIntrinsics, value ); } } public COMSynchronizationOptions Synchronization { get { return (COMSynchronizationOptions) Enum.Parse( typeof (COMSynchronizationOptions), this._comp.get_Value( c_Synchronization ).ToString() ); } set { this._comp.set_Value( c_Synchronization, Enum.Parse( typeof (COMAdminSynchronizationOptions), value.ToString() ) ); } } public COMTransactionOptions Transaction { get{ return (COMTransactionOptions) Enum.Parse(typeof(COMTransactionOptions), this._comp.get_Value(c_Transaction).ToString());} set{ this._comp.set_Value(c_Transaction, Enum.Parse(typeof(COMAdminTransactionOptions), value.ToString()));} } #endregion #endregion #region Constructors public ComComponent(string appName,string compName):this(new ComApplication(appName),compName) {} public ComComponent(ComApplication capp,string compName) { _capp = capp; _compName = compName; InitialComponents(); } internal ComComponent(ComApplication capp) { _capp = capp; InitialCOM(); } #endregion #region Private Methods. private void InitialComponents() { if (_comps == null || _comp == null) { InitialCOM(); bool found = RetrieveComponent(); if (!found) { throw new NonExistComComponentException(_capp.AppName, _compName); } } } private void InitialCOM() { _comps = _capp.Applications.GetCollection(c_COMPONENTS, _capp.Application.Key) as COMAdminCatalogCollection; _comps.Populate(); } private bool RetrieveComponent() { bool found = false; _index = 0; foreach (COMAdminCatalogObject item in _comps) { if ((GetFilePath(item.Key as string) == _compName) || (item.Name as string == _compName)) { found = true; _comp = item; break; } _index++; } return found; } private static string GetFilePath(string clsid) { RegistryKey rk = Registry.ClassesRoot; string path = String.Format("CLSID\\{0}\\InprocServer32", clsid); rk = rk.OpenSubKey(path); if (rk != null) { return rk.GetValue("") as string; } return string.Empty; } private void InnerCreate() { _capp.COMAdminObj.InstallComponent(_capp.Key, _compName, "", ""); InitialComponents(); } protected virtual void Dispose(bool disposing) { if( disposing) { // free managed resource; } if( _capp != null) { _capp = null; } if( _comp != null) { _comp = null; } if( _comps != null) { _comps = null; } } #endregion #region Public Methods. Such as Create, Delete, Save... public static ComComponent Create(ComApplication capp, string compName) { ComComponent comp = new ComComponent(capp); comp._compName = compName; comp.InnerCreate(); return comp; } public void Save() { _comps.SaveChanges(); } public void Delete() { _comps.Remove(_index); _comps.SaveChanges(); Dispose(); } public static void Delete(ComApplication capp,string compName) { if (capp == null) throw new ArgumentNullException("capp", "ComApplication capp is null."); if (String.IsNullOrEmpty(compName)) throw new ArgumentException( "compName is null or empty.","compName"); if(! IsExistComponent(capp,compName)) { throw new NonExistComComponentException( capp.AppName, compName ); } ComComponent comp = new ComComponent( capp, compName ); comp.Delete(); } public static bool IsExistComponent( ComApplication capp,string compName) { ComComponent comp = new ComComponent(capp); comp._compName = compName; return comp.RetrieveComponent(); } public static IList<ComComponent> QueryComponents(ComApplication capp) { if (capp == null) throw new ArgumentNullException("capp","capp is null."); List<ComComponent> result = new List<ComComponent>(); COMAdminCatalogCollection allcomps = capp.Applications.GetCollection( c_COMPONENTS, capp.Application.Key ) as COMAdminCatalogCollection; allcomps.Populate( ); foreach( COMAdminCatalogObject obj in allcomps) { ComComponent curcomp = new ComComponent( capp ); curcomp._comps = allcomps; curcomp._comp = obj; curcomp._compName = GetFilePath( obj.Key as string ); result.Add( curcomp ); } return result; } #region IDisposable Members public void Dispose() { this.Dispose( true ); GC.SuppressFinalize(this); } #endregion #endregion } }
最后呢,就是UT啦 :)
TestCOMApp:
using System; using System.Collections.Generic; using System.Text; using NUnit.Framework; using COMAdmin.NET; using COMAdmin; namespace COMAdmin.NET.NTest { [TestFixture] public class TestComApp { const string c_myestapp = "mytestapp123"; const string c_mytestapp_new = "mytestapp new"; const string c_mytestapp_old_desc = "this is old description."; const string c_mytestapp_new_desc = "this is new description."; const COMActivationOptions c_acoption = COMActivationOptions.COMAdminActivationInproc; #region SetUp and TearDown [SetUp] public void SetUp() { TearDown(); COMAdminCatalog catalog = new COMAdminCatalogClass(); COMAdminCatalogCollection collection = catalog.GetCollection("Applications") as COMAdminCatalogCollection; collection.Populate(); COMAdminCatalogObject obj = collection.Add() as COMAdminCatalogObject; obj.set_Value("Name", c_myestapp); obj.set_Value("Description", c_mytestapp_old_desc); obj.set_Value("Activation", COMAdminActivationOptions.COMAdminActivationInproc); obj.set_Value("Changeable",true); obj.set_Value( "Deleteable", true ); collection.SaveChanges(); } [TearDown] public void TearDown() { string[] allapps = new string[] {c_myestapp, c_mytestapp_new}; foreach (string item in allapps) { COMAdminCatalog catalog = new COMAdminCatalogClass(); COMAdminCatalogCollection collection = catalog.GetCollection("Applications") as COMAdminCatalogCollection; collection.Populate(); int index = 0; bool found = false; foreach (COMAdminCatalogObject obj in collection) { if (obj.Name.ToString() == item) { found = true; break; } index++; } if (found) { Console.WriteLine("Found.\r\n Name is " + item + "\r\nIndex is " + index); catalog.ShutdownApplication(item); collection.Remove(index); collection.SaveChanges(); } } } #endregion [Test] public void TestSave() { ComApplication app = new ComApplication( c_myestapp ); Assert.AreEqual( c_mytestapp_old_desc, app.Desc ); app.Desc = c_mytestapp_new_desc; app.Save() ; Assert.AreEqual( c_mytestapp_new_desc, app.Desc ); ComApplication newapp = new ComApplication( c_myestapp ); Assert.AreEqual( c_mytestapp_new_desc, newapp.Desc ); } [Test] public void TestDelete() { Assert.IsTrue(ComApplication.IsExistApplication(c_myestapp)); ComApplication.Delete(c_myestapp); Assert.IsFalse(ComApplication.IsExistApplication(c_myestapp)); } [Test] public void TestDeleteObj() { Assert.IsTrue(ComApplication.IsExistApplication(c_myestapp)); ComApplication app = new ComApplication(c_myestapp); app.Delete(); Assert.IsFalse(ComApplication.IsExistApplication(c_myestapp)); } [Test] [ExpectedException(typeof(NonExistComApplicationException))] public void TestDeleteNonExistApp() { ComApplication.Delete("nonexisted com plus applications"); } [Test] public void TestCreate() { Assert.IsFalse(ComApplication.IsExistApplication(c_mytestapp_new)); ComApplication app = ComApplication.Create(); Assert.IsNotNull(app); app.AppName = c_mytestapp_new; app.Changeable = true; app.Deletable = true; app.Desc = c_mytestapp_new_desc; app.AcOption = COMActivationOptions.COMAdminActivationInproc; app.Save(); Assert.IsNotNull(app.Key); ComApplication newapp = new ComApplication(c_mytestapp_new); Assert.AreEqual(c_mytestapp_new_desc, newapp.Desc); Assert.AreEqual(COMActivationOptions.COMAdminActivationInproc, newapp.AcOption); Assert.IsTrue(newapp.Changeable); Assert.IsTrue(newapp.Deletable); Assert.AreEqual(app.Key, newapp.Key); } [Test] [ExpectedException(typeof(NonExistComApplicationException))] public void TestNonExistApplication() { new ComApplication("this is no an exist application."); } [Test] public void TestAppInfo() { ComApplication app = new ComApplication( c_myestapp ); Assert.AreEqual(c_myestapp, app.AppName); Assert.AreEqual(c_mytestapp_old_desc, app.Desc); Assert.IsTrue(app.Changeable); Assert.IsTrue(app.Deletable); Assert.AreEqual(c_acoption, app.AcOption); } [Test] public void TestQueryApplication() { IList<ComApplication> comapps = ComApplication.QueryApplications( ); Assert.Greater( comapps.Count,1 ); } } }
TestCOMComponent:
using System; using System.Collections.Generic; using System.Text; using COMAdmin; using COMAdmin.NET; using NUnit.Framework; using System.IO; namespace COMAdmin.NET.NTest { [TestFixture] public class TestComComp { const string c_myestapp = "ohismylife"; const string c_mytestapp_new = "mytestapp new"; const string c_mytestapp_old_desc = "this is old description."; const string c_mytestapp_new_desc = "this is new description."; const COMActivationOptions c_acoption = COMActivationOptions.COMAdminActivationInproc; const string c_NewCompName = "Project1.Class1"; string c_compname = new FileInfo(@"TestCOM.dll").FullName; #region SetUp and TearDown [SetUp] public void SetUp() { TearDown(); COMAdminCatalog catalog = new COMAdminCatalogClass(); COMAdminCatalogCollection collection = catalog.GetCollection("Applications") as COMAdminCatalogCollection; collection.Populate(); COMAdminCatalogObject obj = collection.Add() as COMAdminCatalogObject; obj.set_Value("Name", c_myestapp); obj.set_Value("Description", c_mytestapp_old_desc); obj.set_Value("Activation", COMAdminActivationOptions.COMAdminActivationInproc); obj.set_Value("Changeable", true); obj.set_Value("Deleteable", true); collection.SaveChanges(); Console.WriteLine( "The created APPID is " + obj.Key.ToString() ); Console.WriteLine( c_compname ); catalog.InstallComponent( obj.Key.ToString(), c_compname,"","" ); } [TearDown] public void TearDown() { string[] allapps = new string[] { c_myestapp, c_mytestapp_new }; foreach (string item in allapps) { COMAdminCatalog catalog = new COMAdminCatalogClass(); COMAdminCatalogCollection collection = catalog.GetCollection("Applications") as COMAdminCatalogCollection; collection.Populate(); int index = 0; bool found = false; foreach (COMAdminCatalogObject obj in collection) { if (obj.Name.ToString() == item) { found = true; break; } index++; } if (found) { Console.WriteLine("Found.\r\n Name is " + item + "\r\nIndex is " + index); catalog.ShutdownApplication(item); collection.Remove(index); collection.SaveChanges(); } } } #endregion [Test] [ExpectedException(typeof(NonExistComComponentException))] public void TestNonExistCom() { new ComComponent( new ComApplication( c_myestapp ), "non exist comp name" ); } [Test] public void TestCOMInfo() { ComComponent[] comps = new ComComponent[2]; comps[0] = new ComComponent(new ComApplication(c_myestapp), c_compname); comps[1] = new ComComponent( c_myestapp, c_NewCompName ); foreach (ComComponent comp in comps) { Assert.AreEqual("Project1.Class1", comp.Name); Assert.AreEqual(COMTransactionOptions.COMAdminTransactionNone, comp.Transaction); Assert.AreEqual(COMSynchronizationOptions.COMAdminSynchronizationRequired, comp.Synchronization); Assert.IsFalse(comp.ConstructionEnabled); Assert.IsTrue(comp.JustInTimeActivation); } } [Test] public void TestSave() { ComComponent comp = new ComComponent(c_myestapp, c_compname); comp.Transaction = COMTransactionOptions.COMAdminTransactionRequired; comp.JustInTimeActivation = true; comp.ConstructionEnabled = true; comp.Save(); Assert.AreEqual(c_NewCompName, comp.Name); Assert.AreEqual(COMTransactionOptions.COMAdminTransactionRequired, comp.Transaction); Assert.IsTrue(comp.JustInTimeActivation); Assert.IsTrue(comp.ConstructionEnabled); ComComponent newcomp = new ComComponent(c_myestapp, c_compname); Assert.AreEqual( c_NewCompName, newcomp.Name ); Assert.AreEqual( COMTransactionOptions.COMAdminTransactionRequired, newcomp.Transaction ); Assert.IsTrue( newcomp.JustInTimeActivation ); Assert.IsTrue( newcomp.ConstructionEnabled ); } [Test] public void TestIsExistComp() { ComApplication comApp = new ComApplication(c_myestapp); Assert.IsTrue(ComComponent.IsExistComponent(comApp, c_NewCompName)); Assert.IsFalse(ComComponent.IsExistComponent( comApp , "non existed components")); } [Test] public void TestDeleteObj() { ComApplication comApp = new ComApplication( c_myestapp ); ComComponent comp = new ComComponent( comApp, c_NewCompName ); comp.Delete( ); Assert.IsFalse( ComComponent.IsExistComponent( comApp, c_NewCompName ) ); } [Test] public void TestDelete() { ComApplication comApp = new ComApplication(c_myestapp); ComComponent.Delete(comApp,c_NewCompName); Assert.IsFalse(ComComponent.IsExistComponent(comApp, c_NewCompName)); } [Test] public void TestCreate() { string compName = new FileInfo( @"TestCOM2.dll" ).FullName; ComApplication comApp = new ComApplication( c_myestapp ); Assert.IsFalse( ComComponent.IsExistComponent( comApp, compName ) ); ComComponent comp = ComComponent.Create( comApp, compName ); Assert.IsTrue( ComComponent.IsExistComponent( comApp, compName ) ); Assert.AreEqual("TestProject.CTest", comp.Name); Assert.AreEqual(COMTransactionOptions.COMAdminTransactionNone, comp.Transaction); Assert.AreEqual(COMSynchronizationOptions.COMAdminSynchronizationRequired, comp.Synchronization); Assert.IsFalse(comp.ConstructionEnabled); Assert.IsTrue(comp.JustInTimeActivation); } [Test] [ExpectedException(typeof(NonExistComComponentException))] public void TestDeleteNonExistComp() { ComComponent.Delete( new ComApplication( c_myestapp ), "non existed comp" ); } [Test] public void TestGetComponents() { ComApplication capp = new ComApplication( c_myestapp ); Assert.IsTrue( ComComponent.IsExistComponent( capp, c_NewCompName ) ); IList<ComComponent> comps = ComComponent.QueryComponents( capp ); Assert.AreEqual( 1, comps.Count ); ComComponent comp = comps[0]; Assert.AreEqual( c_NewCompName, comp.Name ); Assert.AreEqual("Project1.Class1", comp.Name); Assert.AreEqual(COMTransactionOptions.COMAdminTransactionNone, comp.Transaction); Assert.AreEqual(COMSynchronizationOptions.COMAdminSynchronizationRequired, comp.Synchronization); Assert.IsFalse(comp.ConstructionEnabled); Assert.IsTrue(comp.JustInTimeActivation); } } }