Как освободить необработанный объект COM-сервера из Excel VBA - PullRequest
5 голосов
/ 07 сентября 2011

Как заставить Excel (2007) VBA выпускать ссылки на объект COM-сервера?

Я написал COM-сервер inprocess (DLL для одного экземпляра) в Visual Foxpro 9 SP2, который создается из кода Excel 2007 VBA на моей машине для разработки. В Excel, похоже, содержится ссылка на COM-объект / dll, хотя я установил его = Nothing. Это не позволяет мне пересобрать библиотеку DLL из-за сообщения «Доступ к файлу запрещен TestCOM.dll» до тех пор, пока я не выйду из Excel, что вызывает боль каждый раз, когда я хочу внести изменение и проверить его.

Я свел код к очень простой тестовой настройке: Проект VFP9 (TestCOM) имеет только один файл .prg со следующим содержимым

DEFINE CLASS TestClass As Session OLEPUBLIC

ENDDEFINE

Код VBA выглядит следующим образом:

Sub Test()

    Set objTest = CreateObject("TestCOM.TestClass")
    Set objTest = Nothing

End Sub

Я попытался удалить ссылку на библиотеку COM-сервера в проекте VBA, но это не имеет никакого значения. Я пытался с и без DIMing объектных переменных, и это не имеет значения. Я попытался создать новый проект VFP DLL, но проблема сохраняется.

Если я создаю приложение / dll VFP как INPROCESS / DLL и запускаю код VBA, я получаю эту проблему, но если я создаю его как OUTOFPROCESS / EXE и запускаю код VBA, я НЕ получаю эту проблему.

Я обнаружил очень похожую проблему в Очистка COM-объекта , за исключением того, что мой COM-сервер написан на Visual Foxpro 9 SP2, тогда как это относится к C #, а OP не объяснил подробно, как они решили проблему, так Я не знаю, как обойти это; если это вообще возможно.

Ответы [ 2 ]

6 голосов
/ 07 сентября 2011

Процедура, используемая для создания экземпляра вашего класса COM из кода в вашей DLL, заключается в том, что Excel вызывает уровень библиотеки COM, чтобы найти вашу реализацию, используя либо ProgID, либо ClassID.Если у вас есть сервер inproc, это означает, что он находит путь к вашей DLL и использует LoadLibrary для загрузки его в ваш клиентский процесс, а затем создает фабрику классов и вызывает методы в DLL.Таким образом, конечный результат заключается в том, что Excel вызывает LoadLibrary для вашей DLL, и это блокирует файл, пока Excel не вызовет FreeLibrary для дескриптора.

Используя COM-интерфейсы, вы не можете это контролировать.Вы вызываете CoCreateInstance () (или из VBA вы создаете объект с помощью New или CreateObject, который вызывает этот Win32 API внизу).Реализация этого обрабатывает LoadLibrary и все остальное, пока вы не получите указатель интерфейса для работы.Некоторые приложения будут периодически вызывать CoFreeUnusedLibraries (), чтобы попытаться освободить загруженные COM-библиотеки, которые в данный момент не используются.Реализация фабрики классов по умолчанию поддерживает счетчик созданных объектов, который можно использовать, чтобы определить, используется ли DLL или нет - но это не всегда надежно, так как разработчики COM-классов могут не подчиняться правилам.Выход из Excel, очевидно, снимает блокировку файла.

Когда вы создаете свой COM-класс как внепроцессный сервер - он живет в отдельном исполняемом файле или DLL, время жизни которых управляется по-другому.Excel больше не удерживает блокировку DLL, и освобождение экземпляра COM вполне может позволить процессу хостинга завершиться.

Вы можете преобразовать DLL для использования в качестве локального сервера (вне процесса), организовавустроить его на DllHost.Если вы используете утилиту OleView и нашли ваши классы ProgId, вы можете включить хостинг в суррогатном процессе (dllhost).Прошло много времени с тех пор, как я это сделал, но в Интернете должна быть информация об использовании суррогатного хостинга.Очевидно, что размещение COM-объекта вне процесса замедляет работу и создает потенциальную возможность для различных проблем с сортировкой.При условии, что вы сохраняете совместимые с oleautomation интерфейсы, все должно быть в порядке.

1 голос
/ 03 ноября 2017

Добавление более короткого ответа ....

Выпуск DLL является сложной задачей, и она знакома разработчикам незавершенных COM компонентов для использования в Excel.

Есть два условия, которые должны быть выполнены

1) Не используйте ранние ссылки на библиотеки (Tools-> Reference), вместо этого используйте позднюю привязку. Ссылка на инструменты раннего связывания будет содержать блокировку.

2) Звоните CoFreeUnusedLibraries, чтобы выгрузить COM серверы, у которых больше нет клиентов.

Из вашего примера кода вы уже связываетесь с опозданием, но, пожалуйста, проверьте ваши ссылки. В то время как пункт 2) упоминается в ответе payyhoyts код не указан.

Вот копия и вставляемая декларация

Private Declare Sub CoFreeUnusedLibraries Lib "ole32.dll" ()
...