Совместное использование COM-объектов In-Proc в другом процессе - PullRequest
6 голосов
/ 25 марта 2011

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

Вопрос:

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

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

Ответы [ 3 ]

8 голосов
/ 25 марта 2011

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

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

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

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

-

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

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

  • Используйте CreateStreamOnHGlobal (с NULL hglobal) для создания IStream, поддерживаемого HGLOBAL, который COM выделяет при необходимости
  • Используйте CoMarshalInterface для маршалингауказатель интерфейса на поток (который, в свою очередь, записывает его в память, поддерживаемую HGLOBAL)
  • Используйте GetHGlobalFromStream, чтобы получить HGLOBAL из потока
  • Используйте GlobalLock / GlobalSize, чтобы заблокировать HGLOBAL и получить доступ к размеченным данным (GlobalUnlock, когдаготово)
  • Используйте все средства, которые хотите, чтобы скопировать байты в целевой процесс.

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

  • GlobalAlloc / GlobalLock / GlobalUnlock, чтобы создать новый HGLOBAL и заполнить его маршалированными данными
  • CreateStreamOnHGlobal с вашим новым HGLOBAL
  • Передайте этот поток CoUnmarshalInterface

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

1 голос
/ 11 ноября 2016

Существует также другое возможное решение, использующее сообщение окна 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
    }
}

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

0 голосов
/ 25 марта 2011

Для этого предназначены CoRegisterClassObject и CoGetClassObject.

...