Search code examples
c#com+

Check if COM+ application is already running?


Is it possible in C# (4.0) to get the list of installed Com+ applications on the same box and then retrieve the status (Running/Shut down) of each of them?

I can find methods to start/stop, but not retrieve status.


Solution

  • I think the COM+ Administrative components only lets you query the "static" configuration properties (e.g. Identity, IsEnabled) and doesn't let you query the dynamic properties of COM+ (e.g. PID).

    The only way I found to do what you want is using the COMSVCSLib (COM+ Services Type Library).

    UPDATE: Based on @Vagaus's comment, we can use either COM+ Administrative components or COM+ Services Type Library!

    With quite a bit of help from the article Comonitor - A COM+ Monitor. I've cobbled together some code that uses COM+ Services Type Library:

    public static bool IsComPlusApplicationRunning(string appName)
    {
        int appDataSize = Marshal.SizeOf(typeof(COMSVCSLib.appData));
        Type appDataType = typeof(COMSVCSLib.appData);
    
        uint appCount;
        IntPtr appDataPtr = IntPtr.Zero;    
    
        GCHandle gh = GCHandle.Alloc(appDataPtr, GCHandleType.Pinned);
        IntPtr addressOfAppDataPtr = gh.AddrOfPinnedObject();
    
        COMSVCSLib.IGetAppData getAppData = null;
        COMSVCSLib.TrackerServer tracker = null;
    
        try
        {
            tracker = new COMSVCSLib.TrackerServerClass();
            getAppData = (COMSVCSLib.IGetAppData)tracker;
    
            getAppData.GetApps(out appCount, addressOfAppDataPtr);
            appDataPtr = new IntPtr(Marshal.ReadInt32(addressOfAppDataPtr));
    
            for (int appIndex = 0; appIndex < appCount; appIndex++)
            {
                COMSVCSLib.appData appData = (COMSVCSLib.appData)Marshal.PtrToStructure(
                    new IntPtr(appDataPtr.ToInt32() + (appIndex * appDataSize)),
                    appDataType);
    
                string currentAppName = GetPackageNameByPID(appData.m_dwAppProcessId);
    
                if (string.Compare(currentAppName, appName, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    Console.WriteLine("Application " + appName + " is running with PID " + appData.m_dwAppProcessId);
                    return true;
                }            
            }
        }
        finally
        {
            Marshal.FreeCoTaskMem(appDataPtr);
    
            if (tracker != null)
            {
                Marshal.ReleaseComObject(tracker);
            }
    
            gh.Free();
        }
    
        return false;
    }
    
    private static string GetPackageNameByPID(uint PID)
    {
        COMSVCSLib.MtsGrp grpObj = new COMSVCSLib.MtsGrpClass();
    
        try
        {
            object obj = null;
            COMSVCSLib.COMEvents eventObj = null;
    
            for (int i = 0; i < grpObj.Count; i++)
            {
                try
                {
                    grpObj.Item(i, out obj);
    
                    eventObj = (COMSVCSLib.COMEvents)obj;
    
                    if (eventObj.GetProcessID() == PID)
                    {
                        return eventObj.PackageName;
                    }
                }
                finally
                {
                    if (obj != null)
                    {
                        Marshal.ReleaseComObject(obj);
                    }
                }
            }
        }
        finally
        {
            if (grpObj != null)
            {
                Marshal.ReleaseComObject(grpObj);
            }
        }
    
        return null;
    }
    


    But we can also use the COM+ Administrative components (which seems simpler) to do the same thing:

    public static bool IsComPlusApplicationRunning(string appName)
    {
        COMAdmin.COMAdminCatalog catalog = new COMAdmin.COMAdminCatalogClass();
    
        COMAdmin.ICatalogCollection appCollection = (COMAdmin.ICatalogCollection)catalog.GetCollection("Applications");
        appCollection.Populate();
    
        Dictionary<string, string> apps = new Dictionary<string, string>();
        COMAdmin.ICatalogObject catalogObject = null;
    
        // Get the names of the applications with their ID and store for later
        for (int i = 0; i < appCollection.Count; i++)
        {
            catalogObject = (COMAdmin.ICatalogObject)appCollection.get_Item(i);
            apps.Add(catalogObject.get_Value("ID").ToString(), catalogObject.Name.ToString());
        }
    
        appCollection = (COMAdmin.ICatalogCollection)catalog.GetCollection("ApplicationInstances");
        appCollection.Populate();
    
        for (int i = 0; i < appCollection.Count; i++)
        {
            catalogObject = (COMAdmin.ICatalogObject)appCollection.get_Item(i);
    
            if (string.Compare(appName, apps[catalogObject.get_Value("Application").ToString()], StringComparison.OrdinalIgnoreCase) == 0)
            {
                Console.WriteLine(appName + " is running with PID: " + catalogObject.get_Value("ProcessID").ToString());
                return true;
            }
        }
    
        return false;
    }