Проблема загрузки C ++ DLL из тестовой среды Visual Studio - PullRequest
0 голосов
/ 04 апреля 2011

Итак, я пытался настроить тесты для своего решения, используя среду тестирования Visual Studio. Настройка выглядит следующим образом:

Third party native library --> Managed C++ wrapper DLL --> C# project being tested
                                        ^                        ^
Foundation C# Projects -----------------|------------------------|

Существует две теоретически взаимозаменяемые сторонние библиотеки с соответствующими обертками. Мне нужно иметь возможность поддерживать оба.

Итак, когда я запускаю свой тестовый проект, вот что происходит:

  1. Тестируемый проект успешно загружен
  2. Основные проекты C # загружаются успешно
  3. Оболочка C ++ A не загружается; если я использую обертку B, все в порядке.

Исключительная ситуация стека вызовов для оболочки A:

mscorlib.dll!System.Runtime.InteropServices.Marshal.ThrowExceptionForHR(int errorCode) + 0x23 bytes 
msvcm90d.dll!<CrtImplementationDetails>::DoCallBackInDefaultDomain(int* function = 0x1018E1D0, bool cookie = false) Line 451    C++
[Native to Managed Transition]  
[Managed to Native Transition]  
Wrapper.dll!<CrtImplementationDetails>::DefaultDomain::Initialize() Line 284    C++
Wrapper.dll!<CrtImplementationDetails>::LanguageSupport::InitializeDefaultAppDomain() Line 519  C++
Wrapper.dll!<CrtImplementationDetails>::LanguageSupport::_Initialize() Line 730 C++
Wrapper.dll!<CrtImplementationDetails>::LanguageSupport::Initialize() Line 876  C++
Wrapper.dll!?.cctor@@$$FYMXXZ() Line 922 + 0x9 bytes    C++
[Native to Managed Transition]  
[Managed to Native Transition]  
TestProject.dll!TestProject.TestProjectBase.TestProjectBase() Line 44 + 0x8 bytes   C#
[Native to Managed Transition]  
[Managed to Native Transition]  
TestProject.dll!TestProject.Test.Test() Line 17 + 0x8 bytes C#
[Native to Managed Transition]  
[Managed to Native Transition]  
Microsoft.VisualStudio.QualityTools.Tips.UnitTest.Adapter.dll!Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestExecuter.CreateTestClassInstance() + 0x174 bytes  

Я искал это в Интернете и обнаружил, что многие люди спрашивают об одном и том же стеке вызовов с очень небольшим количеством ответов.

Я посмотрел, что происходит с ProcMon. Я сравнил то, что происходит при загрузке оболочки A и оболочки B. Вещи выглядят более или менее одинаковыми, пока не завершится загрузка оболочки B. В этот же момент оболочка A необъяснимым образом начинает загружаться снова, на этот раз, пытаясь загрузить базовые библиотеки C #, которые уже были загружены тестовым проектом. Но он не находит эти DLL, потому что путь поиска DLL не содержит тестовую папку (он ищет библиотеки DLL в GAC и каталоге VSTestHost).

Еще одна вещь, которую я заметил, это то, что код C # не запускается в домене приложения по умолчанию. Итак, моя теория заключается в том, что происходит следующее:

  1. Wrapper A пытается загрузить домен приложения в песочнице.
  2. Что-то происходит, чтобы заставить систему думать, что Wrapper A не загрузился успешно
  3. Система пытается загрузить Wrapper A в домене приложения по умолчанию. В этом домене приложения библиотеки DLL C # не загружаются, поэтому он пытается и не может их загрузить.

Итак, что дает? Что может происходить на шаге 2? Каковы некоторые возможные причины, по которым оболочка B успешно загружается, а оболочка A - нет?

В случае, если вам интересно, чем отличаются оболочка A и оболочка B: их проекты имеют одинаковые параметры и поддерживают одинаковые интерфейсы; в противном случае они совершенно разные. Но я хотел бы знать, какие различия могут привести к этой ситуации.

Я должен добавить, что, если я добавлю DLL в GAC или скопирую их в каталог VSTestHost, оболочка A найдет DLL и успешно загрузится. Тем не менее, я все еще хотел бы понять, что происходит не так.

1 Ответ

0 голосов
/ 04 апреля 2011

Возможно, ваш Wrapper A создает собственный поток, который позже запускает управляемый код.Если это так, то попробуйте этот API :

msclr::call_in_appdomain(appDomainId, func, object);

. Это позволяет указать, в какой домен приложений должен запускаться поток func. В противном случае, когда собственный поток пытается запустить управляемый код, потоки используют то, что процесс считает доменом AppDomain по умолчанию, что объясняет точки # 1 и # 3 в вашем вопросе.Поэтому, если ваш код застрянет в неправильном домене приложения, он не найдет никаких зависимых библиотек DLL / сборок, поскольку текущий рабочий каталог, вероятно, будет отличаться от того, что вы хотите.

РЕДАКТИРОВАТЬ: Запустите ProcessMonitor и настройте фильтр для отслеживания Wrapper A и всех его зависимостей, это поможет убедиться, что все они загружаются при запуске тестового проекта.

...