Marshal.GetActiveObject() throws MK_E_UNAVAILABLE exception in C#

15

The following vbscript code works prefectly fine:

Dim App 
Set App = GetObject("","QuickTest.Application")
App.Quit

But when I translate it into C# code as below:

class Program
{
    [STAThread]
    static void Main(string[] args)
    {
        object qtApp = Marshal.GetActiveObject("QuickTest.Application");
        (qtApp as QuickTest.Application).Quit();
    }
}

I get the exception:

An unhandled exception of type 'System.Runtime.InteropServices.COMException' occurred in mscorlib.dll

Additional information: (Exception from HRESULT: 0x800401E3 (MK_E_UNAVAILABLE))

I don't think the problem is related to ROT, because the vbscript code works. So what is wrong with the C# code?

c#
com-interop
asked on Stack Overflow Oct 12, 2011 by TomCaps

3 Answers

30

I found that running the debugger/IDE with elevated privileges (i.e. Admin mode) can cause this problem when the process you are trying to detect is running without elevated privileges.

answered on Stack Overflow Sep 5, 2013 by F Snyman • edited Sep 5, 2013 by F Snyman
11

Marshal.GetActiveObject use progID , check your progID, e.g. you could use this code for display objects in ROT

using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
using Microsoft.Win32;
...
class Program
{
    private const int S_OK = 0x00000000;

    [DllImport("ole32.dll")]
    private static extern int GetRunningObjectTable(uint reserved, out IRunningObjectTable pprot);

    [DllImport("ole32.dll")]
    private static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc);      

    private static void OleCheck(string message, int result)
    {
        if (result != S_OK)
            throw new COMException(message, result);
    }

    private static System.Collections.Generic.IEnumerable<IMoniker> EnumRunningObjects()
    {           
        IRunningObjectTable objTbl;
        OleCheck("GetRunningObjectTable failed", GetRunningObjectTable(0, out objTbl));
        IEnumMoniker enumMoniker;
        IMoniker[] monikers = new IMoniker[1];
        objTbl.EnumRunning(out enumMoniker);
        enumMoniker.Reset();
        while (enumMoniker.Next(1, monikers, IntPtr.Zero) == S_OK)
        {
            yield return monikers[0];
        }
    }

    private static bool TryGetCLSIDFromDisplayName(string displayName, out string clsid)
    {
        var bBracket = displayName.IndexOf("{");
        var eBracket = displayName.IndexOf("}");
        if ((bBracket > 0) && (eBracket > 0) && (eBracket > bBracket))
        {
            clsid = displayName.Substring(bBracket, eBracket - bBracket + 1);
            return true;
        }
        else 
        {
            clsid = string.Empty;
            return false;
        }   
    }

    private static string ReadSubKeyValue(string keyName, RegistryKey key)
    {
        var subKey = key.OpenSubKey(keyName);
        if (subKey != null)
        {
            using(subKey)
            {
                var value = subKey.GetValue("");
                return value == null ? string.Empty : value.ToString();
            }
        }
        return string.Empty;
    }

    private static string GetMonikerString(IMoniker moniker)
    {
        IBindCtx ctx;
        OleCheck("CreateBindCtx failed", CreateBindCtx(0, out ctx));
        var sb = new StringBuilder();
        string displayName;
        moniker.GetDisplayName(ctx, null, out displayName);
        sb.Append(displayName);
        sb.Append('\t');
        string clsid; 
        if (TryGetCLSIDFromDisplayName(displayName, out clsid))
        {
            var regClass = Registry.ClassesRoot.OpenSubKey("\\CLSID\\" + clsid);
            if (regClass != null)
            {
                using(regClass)
                {
                    sb.Append(regClass.GetValue(""));
                    sb.Append('\t');
                    sb.Append(ReadSubKeyValue("ProgID", regClass));
                    sb.Append('\t');
                    sb.Append(ReadSubKeyValue("LocalServer32", regClass));
                }
            }
        }
        return sb.ToString();
    }

    [STAThread]
    public static void Main(string[] args)
    {
        Console.WriteLine("DisplayName\tRegId\tProgId\tServer");
        foreach(var moniker in EnumRunningObjects())
        {
            Console.WriteLine(GetMonikerString(moniker));
        }
    }
}  
answered on Stack Overflow Oct 12, 2011 by MishaU
2

The issue can also be triggered by not running with elevated privileges. This seems to have changed over the years, so try all permutations of running either the IDE or the target program with or without elevated privileges.

As of August 2017, to get the running instance of Outlook 365 under the Visual Studio 2015 debugger, I had to do the following to avoid the MK_E_UNAVAILABLE error:

  • Start Outlook as Administrator
  • Start Visual Studio as Administrator

My program running in the debugger was then able to get the running instance of Outlook successfully.

answered on Stack Overflow Aug 27, 2017 by Reg Edit

User contributions licensed under CC BY-SA 3.0