2011-10-12 49 views
13

Mã VBScript sau hoạt động prefectly tốt:Marshal.GetActiveObject() ném ngoại lệ MK_E_UNAVAILABLE trong C#

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

Nhưng khi tôi dịch nó thành mã C# như sau:

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

tôi nhận được ngoại lệ :

Ngoại lệ không được loại trừ của loại 'System.Runtime.InteropServices.COMException' xảy ra trong mscorlib.dll

Thông tin bổ sung: (Ngoại lệ từ HRESULT: 0x800401E3 (MK_E_UNAVAILABLE))

Tôi không nghĩ rằng vấn đề có liên quan đến ROT, bởi vì mã vbscript hoạt động. Vì vậy, những gì là sai với mã C#?

Trả lời

10

Marshal.GetActiveObject progID sử dụng, kiểm tra progID của bạn, ví dụ: bạn có thể sử dụng mã này cho các đối tượng được trưng bày tại 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

cảm ơn! Tôi đã sử dụng mã của bạn để liệt kê các đối tượng trong ROT, việc tìm kiếm không có bất kỳ đối tượng liên quan đến QuickTest nào trong danh sách. Nhưng đủ kỳ lạ, mã vbscript vẫn hoạt động! Hàm GetObject() của vbscript có tìm kiếm ROT vì nó là đối tác C# không? – TomCaps

+1

http://msdn.microsoft.com/en-us/library/kdccchxa%28v=vs.85%29.aspx MSDN GetObject Nhận xét thứ nhất: “Nếu tên đường dẫn là chuỗi có độ dài bằng không (" "), thì trả về GetObject một thể hiện đối tượng mới của kiểu được chỉ định. ”, vì vậy VBScript của bạn tạo ra thể hiện mới của QuickTest.Application và mã của bạn trong C# phải giống như var qtApp = new QuickTest.Application(); ... – MishaU

+0

Tôi đã thay đổi mã C# thành var qtApp = new QuickTest.Application(); Và nó hoạt động! Cảm ơn nhiều! – TomCaps

29

tôi thấy rằng chạy debugger/IDE với quyền cao (tức là chế độ quản lý) có thể gây ra vấn đề này khi quá trình bạn đang cố gắng để phát hiện là chạy mà không có đặc quyền nâng cao .

+2

Ngớ ngẩn tôi, tôi không thấy bình luận của bạn. Vì vậy, tôi tiếp tục cố gắng và cố gắng, cho đến khi nó phát hiện ra tôi để thử chạy chương trình của tôi từ một dấu nhắc lệnh bị hạn chế. Va no đa hoạt động. Và sau đó tôi đến đây để thêm kiến ​​thức mới được tìm thấy của tôi, và tôi thấy bình luận của bạn. Oh well. Chúc mừng! –

0

Sự cố cũng có thể được kích hoạt bởi không phải đang chạy với các đặc quyền nâng cao. Điều này dường như đã thay đổi qua nhiều năm, vì vậy hãy thử tất cả các hoán vị chạy IDE hoặc chương trình đích có hoặc không có đặc quyền nâng cao.

Tính đến tháng 8 năm 2017, để có được những ví dụ chạy của Outlook 365 dưới Visual Studio 2015 debugger, tôi phải làm như sau để tránh những lỗi MK_E_UNAVAILABLE:

  • Bắt đầu Outlook as Administrator
  • Bắt đầu Visual Studio làm Quản trị viên

Chương trình của tôi đang chạy trong trình gỡ rối sau đó có thể lấy phiên bản Outlook đang chạy thành công.