【问题标题】:COM+ activation on a remote server with partitions in C#在具有 C# 分区的远程服务器上激活 COM+
【发布时间】:2017-05-17 10:37:05
【问题描述】:

我想访问远程服务器上的分区 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)}"

我的问题与此非常相似: COM+ object activation in a different partition

【问题讨论】:

  • 你确定这不是设计的吗?错误消息似乎与您的设置一致。我猜你应该联系微软。还要检查这个:social.technet.microsoft.com/Forums/windows/en-US/…
  • 我猜你必须以某种方式将服务器名称合并到名字对象中。现在您只使用服务器名称连接到服务器上的目录。您不会像在不使用分区的情况下那样使用它来创建对象。因此,您实际上是在尝试在未启用分区的本地计算机上创建对象。解决方案可能不是按照@SimonMourier 提供的链接所建议的那样在本地启用分区,因为这只会允许您在本地创建对象,而这可能不是您想要的。
  • @MikaelEriksson 理论上是可能的。实际上看起来目前可能不支持。 BindToMoniker 是通过调用 CreateBindCtx(获取 IBindCtx)、MkParseDisplayName 和最后一个 BindMoniker 来实现的。您可以自己实现序列,而不是使用默认的 BindCtx(具有 BIND_OPTS 结构),您可以使用 BIND_OPTS2 结构自己创建一个。那有一个带有服务器信息的 pServerInfo。现在这是好的部分。文档中的坏处:类名字对象当前不支持 pServerInfo 标志。所以听起来它现在不起作用。
  • 在排队的组件中有一个“ComputerName=cc/new:”。您可以尝试“ComputerName:”只是为了它。但这更像是抓住稻草;-)。
  • @MikaelEriksson 是的,这就是我的意思。然后我会写一些详细信息和链接以获得答案。

标签: c# remote-server com+ activation moniker


【解决方案1】:

tl;dr
根据 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
它还在脚注中说它不适用于类绰号:http://thrysoee.dk/InsideCOM+/footnotes.htm#CH1104

理论和建议的解决方案(如果 c# 支持)
免责声明:我无法测试代码,因为我没有测试设置。这不是我的想法。有点伪代码。

为此,您必须自己编写 COM/Moniker 调用的代码。为此,您可以将 microsoft 实施的来源作为起点。 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

【讨论】:

    【解决方案2】:

    远程 COM 需要通过 Queue 或 DCOM 访问。通过 DCOM 访问时,需要在服务器上导出应用程序代理。并在客户端 PC 上安装代理。

    COM 激活类型必须配置为“服务器应用”才能导出应用代理。

    安装应用代理后,客户端可以直接调用

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

    对于分区,它旨在向每个用户展示自己的应用程序集。如果当前分区与用户相关联,则该分区不需要写代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-21
      • 2012-02-13
      • 2019-07-26
      • 2016-02-28
      • 2020-10-28
      • 1970-01-01
      • 2023-03-08
      • 2023-03-26
      相关资源
      最近更新 更多