2017-01-03 47 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); 
} 

对于分区,它的设计,以显示与自己的应用程序集合中的每个用户。如果当前分区与用户关联,则分区不需要用代码写入。

相关问题