2017-01-03 113 views
11

我想訪問遠程服務器上的分區COM +應用程序。 我已經試過這樣:在C#中使用分區的遠程服務器上的COM +激活#

using COMAdmin 
using System.Runtime.InteropServices; 

_serverName = myRemoteServer; 
_partionName = myPartionName; 
_message = myMessage; 
ICOMAdminCatalog2 catalog = new COMAdminCatalog(); 
     catalog.Connect(_serverName); 
     string moniker = string.Empty; 
     string MsgInClassId = "E3BD1489-30DD-4380-856A-12B959502BFD"; 

     //we are using partitions 
     if (!string.IsNullOrEmpty(_partitionName)) 
     { 
      COMAdminCatalogCollection partitions = catalog.GetCollection("Partitions"); 
      partitions.Populate(); 
      string partitionId = string.Empty; 


      foreach (ICatalogObject item in partitions) 
      { 
       if (item.Name == _partitionName) 
       { 
        partitionId = item.Key; 
        break; 
       } 
      } 
      if (!string.IsNullOrEmpty(partitionId)) 
      { 
       moniker = $"partition:{partitionId}/new:{new Guid(MsgInClassId)}"; 
       try 
       { 
        var M = (IMsgInManager)Marshal.BindToMoniker(moniker); 
        M.AddMsg(_message); 
       } 
       catch (Exception ex) 
       { 

        throw new Exception($"We can not use: {_partitionName} with Id {partitionId}. {ex.ToString()}"); 
       }     
      } 
      else 
      { 
       throw; 
      } 
     } 
     else 
//we don't have partitions and this will work 
      { 
       Type T = Type.GetTypeFromCLSID(new Guid(MsgInClassId), _serverName, true); 
       var M = (IMsgInManager)Activator.CreateInstance(T); 
       M.AddMsg(_message); 
      } 

     } 

所以,當我們的(遠程)機器上的本地,分區與綽號和Marshal.BindToMoniker工作。 但是,當我嘗試從我的機​​器遠程執行相同的操作時,我從 Marshal.BindToMoniker中得到一個錯誤,表示Partitons未啓用。因爲在我的機器上分區沒有啓用。

Message = "COM+ partitions are currently disabled. (Exception from HRESULT: 0x80110824)" 

如何使用Marshal.BindToMoniker在遠程服務器上運行。 有什麼事情我可以添加到別名字符串即

moniker = $"server:_server/partition:{partitionId}/new:{new Guid(MsgInClassId)}" 

我的問題是非常simular這樣: COM+ object activation in a different partition

+0

您確定這不是由設計?該錯誤消息似乎與您的設置一致。我應該聯繫微軟。還請檢查:https://social.technet.microsoft.com/Forums/windows/en-US/a601d45a-10c0-4da9-a424-d35afef22161/how-to-enable-windows-7-windows-8-com-分區功能 –

+0

我想你不知何故必須將服務器名稱合併到名稱中。現在您只能使用服務器名稱連接到服務器上的目錄。您不使用它來創建對象,就像在不使用分區的情況下一樣。所以你實際上試圖在你沒有啓用分區的本地機器上創建對象。該解決方案可能不會像@SimonMourier所提供的鏈接所建議的那樣在本地啓用分區,因爲這隻允許您在本地創建對象,而這可能不是您想要的。 –

+1

@MikaelEriksson理論上也許是可能的。實際上看起來像現在可能不被支持。 BindToMoniker通過調用CreateBindCtx(獲取IBindCtx),MkParseDisplayName以及最後一個BindMoniker來實現。您可以自己實現序列,而不是使用默認的BindCtx(具有BIND_OPTS結構),您可以使用BIND_OPTS2結構自己創建一個序列。它有一個帶有服務器信息的pServerInfo。現在這是好的一部分。來自文檔的不好的部分:類名字對象目前沒有兌現pServerInfo標誌。所以這聽起來像現在不能工作。 – Uwe

回答

3

TL;博士
根據MS文檔有辦法做到這通過在BIND_OPTS2結構中設置pServerInfo來綁定名字對象。不幸的是,這是而不是工作COM類名字對象。

見: https://msdn.microsoft.com/en-us/library/windows/desktop/ms694513(v=vs.85).aspx 在那裏說了* pServerInfo:

COM的新一類的綽號目前不兌現pServerInfo標誌。

但也許只是嘗試你的方案,並在未來的某個時間可能會支持(或已經是和文檔是錯誤的)。

還看到: http://thrysoee.dk/InsideCOM+/ch11c.htm
它也說,在腳註它並不適用於類的綽號工作:如果它是在C#
免責聲明支持http://thrysoee.dk/InsideCOM+/footnotes.htm#CH1104

理論和建議的解決方案:我由於我沒有測試設置,因此無法測試代碼。這是我的頭頂。有點僞代碼。

要做到這一點,你必須自己編寫COM/Moniker調用。爲此,您可以將microsofts實現的來源作爲起點。 有BindToMoniker將實現這樣的:

public static Object BindToMoniker(String monikerName) 
    { 
     Object obj = null; 
     IBindCtx bindctx = null; 
     CreateBindCtx(0, out bindctx); 

     UInt32 cbEaten; 
     IMoniker pmoniker = null; 
     MkParseDisplayName(bindctx, monikerName, out cbEaten, out pmoniker); 

     BindMoniker(pmoniker, 0, ref IID_IUnknown, out obj); 
     return obj; 
    } 

CreateBindCtxMkParseDisplayNameBindMoniker是OLE32.DLL功能。

IBindCtx有更改綁定上下文的方法。爲此,請致電IBindCtx.GetBindContext(out BIND_OPTS2)並將設置更改爲您所需的設置。然後用IBindCtx.SetBindContext(BIND_OPTS2)設置新的綁定上下文。所以基本上你自己的代碼看起來會像這樣(僞代碼):

public static Object BindToMoniker(String monikerName) 
    { 
     Object obj = null; 
     IBindCtx bindctx = null; 
     CreateBindCtx(0, out bindctx); 

     BIND_OPTS2 bindOpts; 
     bindOpts.cbStruct = Marshal.SizeOf(BIND_OPTS2); 
     bindctx.GetBindOptions(ref bindOpts); 
     // Make your settings that you need. For example: 
     bindOpts.dwClassContext = CLSCTX_REMOTE_SERVER; 
     // Anything else ? 
     bindOpts.pServerInfo = new COSERVERINFO{pwszName = "serverName"}; 
     bindctx.SetBindOptions(ref bindOpts); 

     UInt32 cbEaten; 
     IMoniker pmoniker = null; 
     MkParseDisplayName(bindctx, monikerName, out cbEaten, out pmoniker); 

     BindMoniker(pmoniker, 0, ref IID_IUnknown, out obj); 
     return obj; 
    } 

至於說,不幸的是這代碼是不可能在C#寫開箱。即使OLE32.dll方法聲明CreateBindCtx,MkParseDisplayName和BindMoniker也是在Marshal.cs中私下聲明的,所以你必須再次在你的項目中聲明它們。

但我們很幸運IBindCtx聲明使用BIND_OPTS2和BIND_OPTS2結構定義本身。它們在Microsoft.VisualStudio.OLE.Interop中聲明(無論如何,這個命名空間中有趣的聲明)。所以你可以嘗試使用它們,因爲在Marshal對象和marshal.cs中只使用了BIND_OPTS結構。我不知道這是否是框架和可再發行組件的一部分(我懷疑它),但是爲了測試這應該足夠好。如果它有效,這些事情可以在你自己的解決方案中再次聲明。

一些信息所使用的功能:
BindMoniker
CreateBindCtx
MkParseDisplayName
BIND_OPTS2

0

遠程COM需要由隊列或DCOM訪問。您需要在通過DCOM訪問時導出服務器上的應用程序代理。並在客戶端PC中安裝代理。

必須將COM激活類型配置爲「服務器應用程序」才能導出應用程序代理。

安裝應用程序代理後,客戶端可以直接調用

moniker = $"new:{new Guid(MsgInClassId)}"; 
try 
{ 
    var M = Marshal.BindToMoniker(moniker); 
} 

對於分區,它的設計,以顯示與自己的應用程序集合中的每個用戶。如果當前分區與用戶關聯,則分區不需要用代碼寫入。

相關問題