Я понял, что вызвало проблему, но я до сих пор не знаю почему - это произошло, когда я начал использовать fmod
, и это должно быть как-то связано с тем, как компоновщик решает ввести и выполнить статические библиотеки и .dll
. Мой тестируемый код является статической библиотекой; это относится к fmodex_vc
, еще одной статической библиотеке, которая в какой-то момент (хотя я не знаю, когда) решает загрузить свою fmodex.dll
. (Который находится в той же директории, что и все остальное, поэтому я не знаю, почему он его не найдет.) Насколько я знаю, тестируемый код абсолютно не вызывает функции инициализации fmod, но, возможно, fmod имеет некоторые статические глобальные инициализаторы, которые инициализируют себя и загружают в dll? И этот код извлекается только в том случае, если код в модуле, который его использует, используется?
Я тестирую неуправляемый код C++ с помощью тестовой среды Visual Studio, и когда я начал использовать fmod, он перестал работать: каждый тест, даже «тестовые» тесты, которые ничего не делают, будет сообщать (обернутый для удобства чтения):
Unable to get type SlidersTest.UnitTest1, SlidersTest.
Error: System.IO.FileNotFoundException:
The specified module could not be found.
(Exception from HRESULT: 0x8007007E)
После множества проб и ошибок, исключая файлы .cpp
и добавляя их повторно, я обнаружил, что только один из тестовых файлов вызывает проблему; и это происходит только в том случае, если эта строка вызывается:
EntityMgr::Init();
Интересно, что все тесты начинают давать сбой с этим сообщением, если эта строка есть в коде. EntityMgr::Init()
— это функция, которая делает очень мало:
EntityMgr* EntityMgr::instG = null;
а также
void EntityMgr::Init()
{
instG = new EntityMgr;
}
а также
class EntityMgr
{
private:
static EntityMgr* instG;
public:
EntityMgr() // does nothing beyond the default
{
}
static void Init();
static EntityMgr* Inst() { return instG; }
...
vector<Entity> entitiesG;
};
Entity
, FWIW, — довольно ванильный класс без указателей, просто различные float
для его полей.
- Независимо от того, как я запускаю тесты (из режима тестирования, запускаю выбранные, запускаю все, запускаю из командной строки, из меню тестирования), я получаю сообщение об ошибке.
- Попытка войти в тест с помощью отладчика не удалась — тест завершился неудачно до того, как отладчик вмешается. Настройка отладчика на прерывание системных исключений также ничего не дала.
- Тестируемый код представляет собой статический .lib. Поддержка CLR —
/clr
. - О, и это только в: если я вызываю статическую функцию-член Entity, то же самое. Если я перенесу указанную статическую функцию за пределы класса, то же самое. Но если я перенесу эту функцию в другой модуль, все в порядке.
Если я настрою отладчик на прерывание любого исключения, я получу кое-что интересное:
First-chance exception at 0x7c812aeb in vstesthost.exe: Microsoft C++ exception: HRException at memory location 0x05129890..
Там, конечно, нет исходного кода. Вот стек вызовов:
kernel32.dll!7c812aeb()
[Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll]
kernel32.dll!7c812aeb()
[External Code]
msvcr80.dll!78158ed7()
msvcr80.dll!78158e34()
msvcr80.dll!78158047()
msvcr80.dll!7815850e()
msvcr80.dll!78158872()
msvcr80.dll!78158a57()
msvcr80.dll!78158b11()
ntdll.dll!7c9032a8()
ntdll.dll!7c90327a()
ntdll.dll!7c92a9ef()
ntdll.dll!7c90e46a()
kernel32.dll!7c812aeb()
kernel32.dll!7c812aeb()
kernel32.dll!7c812aeb()
msvcr80.dll!78139c4d()
msvcr80.dll!781323ff()
msctf.dll!74755764()
msctf.dll!74721557()
ws2_32.dll!71ab12bb()
ntdll.dll!7c90118a()
ntdll.dll!7c91b084()
ntdll.dll!7c90de7c()
ntdll.dll!7c90d04c()
ntdll.dll!7c90e43f()
kernel32.dll!7c80b713()
А вот трассировка стека, которую сообщает mstest — я не получаю из нее ничего полезного.
Unable to get type SlidersTest.game_EntityMgr_test, SlidersTest. Error: System.IO.FileNotFoundException: The specified module could not be found. (Exception from HRESULT: 0x8007007E)
at System.Reflection.Assembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
at System.Reflection.Assembly.InternalLoadFrom(String assemblyFile, Evidence securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm, Boolean forIntrospection, StackCrawlMark& stackMark)
at System.Reflection.Assembly.LoadFrom(String assemblyFile)
at Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestExecuter.GetType(UnitTestElement unitTest, String type)
at Microsoft.VisualStudio.TestTools.TestTypes.Unit.UnitTestExecuter.ResolveMethods().
Почему fmod делает это?