COM + активация на удаленном сервере с разделами в С#

Я хочу получить доступ к секционированным приложениям 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);
            }

        }

Итак, когда мы локальны на (удаленной) машине, разделы работают с именем и маршалом .BindToMoniker. Но когда я пытаюсь сделать то же самое дистанционно с моей машины, я получаю сообщение об ошибке Marshal.BindToMoniker, что Partitons не включен. Потому что на моих машинных разделах не включен.

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

Как я могу использовать Marshal.BindToMoniker для запуска на удаленном сервере. Это что-то, что я могу добавить в строку прозвища i.e.

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

Мои вопросы очень симпатичны: COM + активация объекта в другом разделе

Ответ 1

ТЛ, д-р
Согласно документации MS, есть способ сделать это, установив pServerInfo в структуру BIND_OPTS2 для привязки прозвища. К сожалению, это не работает для прозвища класса COM.

см: https://msdn.microsoft.com/en-us/library/windows/desktop/ms694513(v=vs.85).aspx где он говорит для * pServerInfo:

COM new class moniker в настоящее время не соблюдает флаг pServerInfo.

Но, возможно, просто попробуйте свой сценарий, и в какой-то момент времени он может быть поддержан (или уже есть, и документация неверна).

также см. http://thrysoee.dk/InsideCOM+/ch11c.htm
где также говорится в сноске, что это не работает для прозвища класса: http://thrysoee.dk/InsideCOM+/footnotes.htm#CH1104

Теория и предлагаемое решение, если она была поддержана в С#
Отказ от ответственности: я не мог проверить код, так как у меня нет тестовой настройки. Это от головы. Немного псевдокода.

Для этого вам придется вводить код 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; 
    } 

CreateBindCtx, MkParseDisplayName и BindMoniker являются функциями 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; 
    } 

Как уже говорилось, к сожалению, этот код нельзя писать в С# из коробки. Даже объявления метода 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 должен получить доступ к очереди или DCOM. При доступе к DCOM вам необходимо экспортировать прокси-сервер приложения. И установите прокси-сервер на клиентском ПК.

Тип активации COM должен быть настроен как "Серверное приложение" для экспорта прокси-сервера приложения.

После установки прокси-приложения клиент может напрямую вызвать

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

Для раздела он предназначен для отображения каждого пользователя с собственным набором приложений. Если текущий раздел связан с пользователем, раздел не должен записываться в коды.