17

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?

TomCaps
  • 2,497
  • 3
  • 22
  • 25

3 Answers3

32

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.

F Snyman
  • 499
  • 1
  • 5
  • 6
  • 2
    Silly me, I did not see your comment. So I kept trying and trying, until it dawned upon me to try running my program from a restricted command prompt. And it worked. And then I came here to add my newly found knowledge, and I saw your comment. Oh well. Cheers! – Mike Nakis Oct 27 '13 at 23:48
13

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));
        }
    }
}  
MishaU
  • 708
  • 6
  • 14
  • 1
    thanks! I used your code to list objects in ROT,finding there is no any QuickTest related object in the list. But weirdly enough,the vbscript code still works! Is the vbscript's GetObject() function doesn't look up the ROT as it's C# counterpart does? – TomCaps Oct 13 '11 at 02:10
  • 1
    http://msdn.microsoft.com/en-us/library/kdccchxa%28v=vs.85%29.aspx MSDN GetObject 1st remark: “If pathname is a zero-length string (""), GetObject returns a new object instance of the specified type.”, so your VBScript create new instance of QuickTest.Application, and your code in C# have to be like var qtApp = new QuickTest.Application(); ... – MishaU Oct 13 '11 at 07:29
  • I changed C# code into var qtApp = new QuickTest.Application(); and it works! thank you very much! – TomCaps Oct 14 '11 at 03:48
  • What does one do in the case where there is no ProgID? – Fowl Oct 21 '12 at 23:34
3

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.

Reg Edit
  • 6,719
  • 1
  • 35
  • 46