使用C#中的分区在远程服务器上进行COM +激活

Ham*_*rin 11 c# activation com+ moniker remote-server

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

        }
Run Code Online (Sandbox Code Playgroud)

因此,当我们在(远程)机器上本地时,分区正在使用名字对象和Marshal.BindToMoniker.但是,当我尝试从我的机​​器远程执行相同的操作时,我从Marshal.BindToMoniker收到错误,即未启用Partitons.因为我的机器分区未启用.

Message = "COM+ partitions are currently disabled. (Exception from HRESULT: 0x80110824)"
Run Code Online (Sandbox Code Playgroud)

如何使用Marshal.BindToMoniker在远程服务器上运行.这是我可以添加到名字字符串的东西,即

moniker = $"server:_server/partition:{partitionId}/new:{new Guid(MsgInClassId)}"
Run Code Online (Sandbox Code Playgroud)

我的问题非常类似于: 在另一个分区中激活COM +对象

Uwe*_*ner 3

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 调用的代码。为此,您可以查看微软实施的来源作为起点。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; 
    } 
Run Code Online (Sandbox Code Playgroud)

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; 
    } 
Run Code Online (Sandbox Code Playgroud)

如前所述,不幸的是,该代码无法直接用 C# 编写。甚至 OLE32.dll 方法声明 CreateBindCtx、MkParseDisplayName 和 BindMoniker 也在 Marshal.cs 中私有声明,因此您必须在项目中再次声明它们。

但幸运的是,我们IBindCtx使用了 a 声明BIND_OPTS2和 BIND_OPTS2 结构定义本身。它们是在Microsoft.VisualStudio.OLE.Interop(无论如何在这个命名空间中有趣的声明)中声明的。因此您可以尝试使用它们,因为在 Marshal 对象和 marshal.cs 中仅使用了 BIND_OPTS 结构。我不知道这是否是框架的一部分并且可重新分发(我对此表示怀疑),但对于测试来说这应该足够好了。如果有效,可以在您自己的解决方案中再次声明这些内容。

有关所用函数的一些信息:
BindMoniker
CreateBindCtx
MkParseDisplayName
BIND_OPTS2