2011-10-12 11 views
13

Poniższy kod VBScript działa perfekcyjnie dobrze:Marshal.GetActiveObject() wyrzuca MK_E_UNAVAILABLE wyjątek w C#

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

Ale kiedy przełożyć je na kod C# jak poniżej:

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

otrzymuję wyjątek :

Nieobsługiwany wyjątek typu "System.Runtime.InteropServices.COMException" wystąpił w pliku mscorlib.dll

Dodatkowe informacje: (Wyjątek od HRESULT: 0x800401E3 (MK_E_UNAVAILABLE))

Nie sądzę, że problem jest związany z ROT, ponieważ działa kod vbscript. Więc co jest nie tak z kodem C#?

Odpowiedz

10

Marshal.GetActiveObject użyj progID, sprawdź swój progID, np. można użyć tego kodu dla obiektów wyświetlanych w 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)); 
     } 
    } 
} 
+1

dzięki! Użyłem twojego kodu do listy obiektów w ROT, stwierdzając, że nie ma żadnego powiązanego obiektu QuickTest na liście. Ale, co dziwne, kod vbscript nadal działa! Czy funkcja GetObject (vbscript) nie wyszukuje ROTa, tak jak to robi odpowiednik C#? – TomCaps

+1

http://msdn.microsoft.com/en-us/library/kdccchxa%28v=vs.85%29.aspx MSDN GetObject Pierwsza uwaga: "Jeśli pathname jest łańcuchem o długości zero (" "), GetObject zwraca nowa instancja obiektu określonego typu. ", więc twój VBScript tworzy nową instancję QuickTest.Application, a twój kod w C# musi być podobny do var qtApp = new QuickTest.Application(); ... – MishaU

+0

Zmieniłem kod C# na var qtApp = new QuickTest.Application(); i to działa! Dziękuję Ci bardzo! – TomCaps

29

Okazało się, że działa debugger/IDE z podwyższonymi uprawnieniami (czyli w trybie administratora) może powodować ten problem, gdy proces staramy się wykryć to działa bez podwyższonymi uprawnieniami .

+2

Silly me, nie widziałem twojego komentarza. Próbowałem więc i próbowałem, dopóki nie przyszło mi do głowy, że spróbuję uruchomić mój program z ograniczonego wiersza poleceń. I zadziałało. A potem przyszedłem tutaj, aby dodać moją nowo odkrytą wiedzę i zobaczyłem twój komentarz. No cóż. Twoje zdrowie! –

0

Problem może być również wyzwalany przez , a nie z podwyższonymi uprawnieniami. Wydaje się, że zmieniło się to z biegiem lat, więc wypróbuj wszystkie permutacje uruchamiania IDE lub programu docelowego z podniesionymi uprawnieniami lub bez nich.

W sierpniu 2017 roku, aby uzyskać działające wystąpienie programu Outlook 365 pod Visual Studio 2015 debugger, musiałem wykonać następujące czynności w celu uniknięcia MK_E_UNAVAILABLE błąd:

  • Uruchom program Outlook jako Administrator
  • start Visual Studio jako Administrator

Mój program uruchomiony w debugerze był wtedy w stanie pomyślnie uruchomić działającą instancję programu Outlook.

Powiązane problemy