VB6 COM + DLL прежней версии, звонящий в собственный Win32 DLL — распараллеливающие проблемы с STA?

[button setFont:...] устарела.

Используйте вместо этого [button.titleLabel setFont:...], например:

[myButton.titleLabel setFont:[UIFont systemFontOfSize:10]];

7
задан Chris J 29 June 2009 в 10:04
поделиться

2 ответа

В многоканальном последовательном COM-сервере каждый экземпляр COM-класса гарантированно доступен для одного потока. Это означает, что экземпляр является потокобезопасным. Однако многие экземпляры могут быть созданы одновременно с использованием разных потоков. Что касается COM-сервера, ваша собственная DLL не должна делать ничего особенного. Подумайте только о kernel32.dll, который используется каждым исполняемым файлом - инициализирует ли он COM, когда используется COM-сервером?

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

1
ответ дан 7 December 2019 в 20:38
поделиться

Я подозреваю, что ваша проблема заключалась в том, что где-то глубоко внутри вызываемой DLL она выполнила исходящий вызов COM в другое подразделение (другой поток в том же процессе или объект в MTA или другой процесс полностью). COM разрешает потоку STA, ожидающему результата исходящего вызова, получить другой входящий вызов, обрабатывая его рекурсивно. Он предназначен только для текущих разговоров между одними и теми же объектами - то есть A вызывает B, B вызывает A обратно, A снова вызывает B - но может принимать вызовы от других объектов, если вы передали указатель интерфейса нескольким клиентам или клиенту поделился указателем интерфейса с другим клиентом. Как правило, передавать указатели на интерфейс однопоточного объекта нескольким клиентским потокам - плохая идея, поскольку им нужно будет только ждать друг друга.Создайте один рабочий объект для каждого потока.

COM не может приостанавливать и возобновлять выполнение по желанию в любом потоке - новый входящий вызов в потоке STA может поступить только через насос сообщений. Когда «заблокирован» в ожидании ответа, поток STA фактически перекачивает сообщения, проверяя с помощью фильтра сообщений (см. IMessageFilter), следует ли обрабатывать сообщение. Однако обработчики сообщений не должны делать новый исходящий вызов - если они это сделают, COM вернет ошибку RPC_E_CANTCALLOUT_INEXTERNALCALL («Недопустимо вызывать внутри фильтра сообщений.»)

Подобные проблемы могут возникнуть, если у вас есть насос сообщений ( GetMessage / DispatchMessage) в любом месте собственной библиотеки DLL. У меня были проблемы с DoEvents VB в интерфейсных процедурах.

CoInitializeEx должен вызываться только создателем потока, потому что только он знает, каким будет его поведение перекачки сообщений. Вероятно, что если вы попытаетесь вызвать его в DllMain, он просто потерпит неудачу, поскольку ваша собственная DLL вызывается в ответ на вызов COM, поэтому вызывающий должен в конечном итоге уже вызвать CoInitializeEx в потоке, чтобы сделать вызов. Выполнение этого в уведомлении DLL_THREAD_ATTACH для вновь созданных потоков может работать поверхностно, но может привести к сбою в работе программы, если COM блокируется, когда он должен перекачиваться, и наоборот.

0
ответ дан 7 December 2019 в 20:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: