Как передать указатель интерфейса в поток?
-
21-08-2019 - |
Вопрос
Примечание:
- С использованием сырой Win32 CreateTheard() API
- Нет МФЦ
- Интерфейс — это просто указатель на виртуальную таблицу.
Вопрос:
- Как передать указатель интерфейса в поток?
Иллюстрация:
IS8Simulation *pis8 = NULL;
...
CoCreateInstance(
clsid,
NULL,
CLSCTX_LOCAL_SERVER,
__uuidof(IS8Simulation),
(void **) &pis8);
...
hThread = CreateThread(
NULL,
0,
SecondaryThread,
//interface pointer pis8
0,
&dwGenericThreadID);
...
DWORD WINAPI SecondaryThread(LPVOID iValue)
{
//using iValue accordingly
//E.g.: iValue->Open
С уважением
Решение
Как было указано ниже, прохождение COM
Указатель интерфейса между потоками небезопасен.
Предполагая, что вы знаете, что делаете:
hThread = CreateThread(
NULL,
0,
SecondaryThread,
(LPVOID) pis8
0,
&dwGenericThreadID);
DWORD WINAPI SecondaryThread(LPVOID iValue)
{
((IS8Simulation*) iValue)->Open();
}
Потокобезопасная версия:
void MainThread()
{
IStream* psis8;
HRESULT res = CoMarshalInterThreadInterfaceInStream (IID_IS8SIMULATION, pis8, &psis8);
if (FAILED(res))
return;
hThread = CreateThread(
NULL,
0,
SecondaryThread,
(LPVOID) psis8
0,
&dwGenericThreadID
);
}
DWORD WINAPI SecondaryThread(LPVOID iValue)
{
IS8Simulation* pis8;
HRESULT res = CoGetInterfaceAndReleaseStream((IStream*) iValue, IID_IS8SIMULATION, &pis8);
if (FAILED(res))
return (DWORD) res;
pis8->Open();
}
Другие советы
Если интерфейс в вашем вопросе является COM-интерфейсом, подхода, предложенного Quassnoi, может быть недостаточно.Вы должны обратить внимание на потоковую модель используемого COM-объекта.Если вторичный поток присоединится к отдельной COM-квартире, отличной от той, в которой был создан ваш COM-объект, и если этот объект не гибкий в квартире, вам нужно будет маршалировать этот указатель интерфейса, чтобы вторичный поток получил прокси, а не прямой указатель на объект.
COM-объект обычно становится гибким с помощью специальной реализации IMarshal.Самый простой подход — агрегировать Free Threaded Marshaler.
Несколько полезных ссылок...
- CoMarshalInterThreadInterfaceInStream
- ГлобальнаяИнтерфейстаблица (GIT)
- CoCreateFreeThreadedMarshaler
Обновлять:О свободном маршалере...
Из комментариев по этой теме становится ясно, что некоторые люди рекомендуют никогда не прикасаться к FTM.Хотя «Эффективный COM» — отличная книга, я думаю, что некоторые из ее рекомендаций открыты для интерпретации.В пункте 33 говорится: «Остерегайтесь FTM»;там не написано «Никогда не используйте FTM».Очень мудро рекомендуется соблюдать осторожность, особенно когда ваш гибкий к апартаментам объект содержит ссылки на другие объекты, потому что они могут не быть гибкими к апартаментам.Итак, на самом деле совет:При создании гибких объектов тщательно подумайте, используют ли они FTM для достижения своей гибкости.Если вы уверены, что можете построить гибкий объект, я не вижу причин, по которым вы бы не использовали FTM для достижения этой цели.
В основном вам нужно сделать следующее:
CoMashalInterThreadInterfaceInStream
==> вы получаете интерфейс IStream.- передать этот IStream в поток, например.как сказал Куасной.
- в SecondaryThread вызовите
CoGetInterfaceAndReleaseStream
получить интерфейс (или прокси к нему, если необходимо).
Не освобождайте интерфейс IStream, если создание потока не завершится неудачно, и не выходите из потока, пока вы не позвоните. CoGetInterfaceAndReleaseStream
.
Среда выполнения COM автоматически создаст для вас прокси.Прокси гарантирует, что, например.COM-компонент с квартирным потоком вызывается в потоке, который его создал.Однако для этого также необходимо, чтобы:
- Интерфейс — IDispatch, или для интерфейса зарегистрированы компоненты прокси/заглушки.
- поток, создавший компонент, имеет цикл обработки сообщений и обрабатывает сообщения