Check if COM+ application is already running?
Asked Answered
G

2

7

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.

Goodness answered 16/9, 2010 at 12:26 Comment(0)
T
7

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;
}
Towner answered 16/9, 2010 at 19:26 Comment(0)
S
1

Have you checked the COM+ administration components? I'd bet that you can find this information using these interfaces.

Best

Selia answered 16/9, 2010 at 14:20 Comment(2)
I've had a look and although I can get the list of Applications, and ShutDown or Start my application, I can't find any way to tell if it was actually running in the first place!Goodness
Actually you can query for the ApplicationInstances (msdn.microsoft.com/en-us/library/ms679173(v=VS.85).aspx) collection which will provide you the information you want with no need to use third part code.Selia

© 2022 - 2024 — McMap. All rights reserved.