Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Marshal.GetActiveObject() throws MK_E_UNAVAILABLE exception in C#

Tags:

c#

com-interop

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?

like image 338
TomCaps Avatar asked Oct 12 '11 06:10

TomCaps


3 Answers

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.

like image 139
F Snyman Avatar answered Nov 10 '22 06:11

F Snyman


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));
        }
    }
}  
like image 20
MishaU Avatar answered Nov 10 '22 05:11

MishaU


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.

like image 3
Reg Edit Avatar answered Nov 10 '22 05:11

Reg Edit