Совместное использование COM-объектов внутри процесса в другом процессе

Прежде чем я задам этот вопрос, я хотел бы прояснить, что я знаю, что существуют библиотеки и методы для взаимодействия между процессами. Тем не менее, это учебный вопрос о COM. Я также знаю о внепроцессных серверах, но это не то, что я ищу.

Вопрос:

Что я хочу знать, поскольку я этого не знаю, возможно ли, и если да, то как, совместно использовать внутрипроцессный COM-объект (объект, определенный в DLL), живущий в одном процессе (был создан экземпляр в процессе) через другой процесс? То есть, как мне получить указатель на внутрипроцессный объект из процесса A в процессе B?

Заранее спасибо.


person ActiveX    schedule 24.03.2011    source источник
comment
Не могли бы вы описать, какую реальную проблему вы пытаетесь решить, пожалуйста?   -  person sharptooth    schedule 25.03.2011


Ответы (3)


Да, это возможно. Базовый принцип один и тот же независимо от того, используете ли вы один экземпляр объекта совместно между подразделениями в одном процессе или между отдельными процессами.

Здесь есть два подхода: возможно, самый простой — использовать Таблица рабочих объектов: это, по сути, таблица именованных COM-объектов для всей рабочей станции. У вас есть один процесс, добавляющий в таблицу объект с хорошо известным именем, а другой процесс ищет этот объект.

Другой подход заключается в использовании маршалинга. Маршалинг — это процесс использования COM API для получения последовательности байтов, описывающих расположение объекта. Затем вы можете скопировать эту серию байтов в другой процесс, используя любые средства, которые вы хотите (общая память, файл, канал и т. д.), а затем использовать другой COM API в принимающем процессе для демаршалирования объекта; Затем COM создает в этом процессе подходящий удаленный прокси-сервер, который обменивается данными с исходным. Ознакомьтесь с API CoMarshalInterface и CoUnmarshalInterface для получения дополнительных сведений.

Обратите внимание, что оба они требуют, чтобы у вас была подходящая поддержка удаленного взаимодействия для объекта; интерфейсы, которые вы используете, должны быть описаны в IDL, скомпилированы и зарегистрированы соответствующим образом.

--

К сожалению, у меня нет кода для любого из этих случаев.

Для подхода CoMarshalInterface процесс выглядит примерно так:

  • Use CreateStreamOnHGlobal (with NULL hglobal) to create an IStream that's backed by a HGLOBAL that COM allocates as needed
  • Use CoMarshalInterface to marshal the interface pointer to the stream (which in turn writes it to the memory backed by the HGLOBAL)
  • Use GetHGlobalFromStream to get the HGLOBAL from the stream
  • Use GlobalLock/GlobalSize to lock the HGLOBAL and access the marhaled data (GlobalUnlock when done)
  • Use whatever means you want to to copy the bytes to the target process.

На дальней стороне используйте:

  • GlobalAlloc/GlobalLock/GlobalUnlock to create a new HGLOBAL and populate it with the marshaled data
  • CreateStreamOnHGlobal with your new HGLOBAL
  • Pass this stream to CoUnmarshalInterface

Ко всему этому применяются обычные правила подсчета ссылок/ресурсов COM и Windows; AddRef/Release по мере необходимости; используйте GlobalFree, чтобы освободить любые HGLOBAL, которые вы выделяете, и т. д.

person BrendanMcK    schedule 25.03.2011
comment
Ответ, который я искал. У вас есть полный пример кода GetRunningObjectTable? или CoMarshallInterface? - person ActiveX; 28.03.2011
comment
На самом деле, скажем, если я маршалирую указатель интерфейса с помощью CoMarshallInterface в поток... что тогда? Как передать поток другому процессу? Через метод межпроцессного взаимодействия, такой как именованный канал/сокет/файл с отображением памяти? Если это так, то маршалинг действительно не спасает меня от работы. - person ActiveX; 28.03.2011
comment
У меня нет подходящего кода для этих сценариев; Я использовал вариант подхода CoMarshal в проекте несколько лет назад; обновили ответ выше с более подробной информацией о необходимых шагах. - person BrendanMcK; 28.03.2011
comment
@ActiveX: это экономит вам много работы, потому что вам нужно сделать это только один раз в одном направлении, чтобы передать объект другому процессу. Затем DCOM выполняет всю работу по передаче параметров туда и обратно для каждого вызова метода и доступа к свойствам. - person Ben Voigt; 28.03.2011
comment
Да вы правы. Это экономит мне немного работы. Я ожидал, что COM будет иметь более нативную поддержку, чем метод COM Services CoCreateSharedInstance(), который делает всю работу за меня :) В любом случае, спасибо за ответы, очень полезно. Я также нашел жемчужину в Интернете (msdn.microsoft.com/en-us/magazine /cc302324.aspx) Я рассмотрю альтернативы. Фабрика потребительского класса в сочетании с вашими идеями выглядит очень многообещающе - person ActiveX; 28.03.2011
comment
Полный пример подхода CoMarshalInterface на C# приведен в исходном коде .NET: SerializeToBlob() показывает, как использовать CoMarshalInterface, и DeserializeFromBlob() показывает, как использовать CoUnmarshalInterface - person transistor1; 22.01.2015

Существует также другое возможное решение с использованием оконного сообщения WM_GETOBJECT:

В приложении, в котором есть объект, вы просто создаете окно со своим классом. В обработчике вам нужно обработать сообщение окна следующим образом (в качестве примера интерфейса я использую IDispatch):

LRESULT WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
    case WM_GETOBJECT:
        {
            if(lParam == OBJID_NATIVEOM)
            {
                return LresultFromObject(IID_IDispatch, wParam, g_MyGlobalIDispatchPointer);
            }
            else
            {
                // Not handled
                break;
            }
        }
        return 0;
    }

    // Default
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

Другое приложение должно найти это конкретное окно и получить объект через AccessibleObjectFromWindow

В примере:

HWND hWndCommunicator = FindWindow(_T("MyWindowClassOfTheOtherApplication"), _T("MyWindowTitleOfTheOtherApplication"));
if(hWndCommunicator)
{
    IDispatch* poObject = nullptr;
    HRESULT hr = AccessibleObjectFromWindow(hWndCommunicator, static_cast<DWORD>(OBJID_NATIVEOM), IID_IDispatch, &poWindow);
    if(SUCCEEDED(hr))
    {
        // Do something with the object of the other process
        // i. e. poObject->Invoke
    }
}

Маршаллинг выполняется автоматически с помощью этого решения.

person David Gausmann    schedule 11.11.2016

Вот для чего нужны CoRegisterClassObject и CoGetClassObject.

person Sheng Jiang 蒋晟    schedule 24.03.2011
comment
Разве CoRegisterClassObject не предназначен только для серверов exe (вне процесса)? У меня внутрипроцессный сервер. - person ActiveX; 25.03.2011
comment
Я думаю, он говорит о совместном использовании определенного экземпляра объекта, а не двух отдельных экземпляров одного и того же класса, по одному экземпляру на процесс. - person BrendanMcK; 25.03.2011
comment
@ActiveX вы можете сделать внепроцессную оболочку для внутрипроцессного сервера - person Sheng Jiang 蒋晟; 25.03.2011
comment
Это звучит так, как будто хак не похож на COM. Я ищу опубликованное решение. У вас есть пример этого? - person ActiveX; 28.03.2011