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?
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.
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));
}
}
}
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:
My program running in the debugger was then able to get the running instance of Outlook successfully.
User contributions licensed under CC BY-SA 3.0