tags:

views:

1623

answers:

7

Ok, I've figured out what caused the problem but I still don't know why - it happened when I started using fmod, and it must have something to do with how the linker decides to bring in and execute static libraries and dll's. My code under test is a static lib; it refers to fmodex_vc, another static lib, which at some point (though I know not when) decides to load in its fmodex.dll. (Which is in the same directory as everything else, so I don't know why it wouldn't find it.) As far as I know, the code under test absolutely does not call the fmod initialization functions, but maybe fmod has some static global initializers that initialize themselves and load in the dll? And that code only gets pulled in if code in a module that uses it gets...used?

I'm testing unmanaged C++ code using the Visual Studio test framework and when I started using fmod it stopped working: Every test, even "test" tests that do nothing, would report (wrapped for readability):

Unable to get type SlidersTest.UnitTest1, SlidersTest.
    Error: System.IO.FileNotFoundException: 
    The specified module could not be found.
    (Exception from HRESULT: 0x8007007E)

After a lot of trial and error, excluding .cpp files and re-adding them, I discovered that only one of the test files elicits the problem; and it only does if this line is called:

EntityMgr::Init();

Interestingly, all the tests start failing with that message if that line is in the code. EntityMgr::Init() is a function that does very little:

EntityMgr* EntityMgr::instG = null;

and

void EntityMgr::Init()
{
   instG = new EntityMgr;
}

and

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, is a pretty vanilla class with no pointers, just various floats for its fields.

  • No matter how I run the tests (from test view, run selected, run all, run from the command line, from the test menu) I get the error.
  • Attempting to step into the test with the debugger fails - the test fails before the debugger gets to step in. Setting the debugger to break on System exceptions did nothing as well.
  • The code under test is a static .lib. CLR support is /clr.
  • Oh, and this just in: if I call a static Entity member function, same deal. If I move said static function outside of the class, same deal. But, if I move that function to another module, it's fine.

If I set the debugger to break on any exception, I do get something interesting:

First-chance exception at 0x7c812aeb in vstesthost.exe: Microsoft C++ exception: HRException at memory location 0x05129890..

There's no source code at that location, of course. Here's the call stack:

     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()

And here's the stack trace that mstest reports - I don't get anything useful out of it.

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().

Why is fmod doing this?

A: 

Maybe some property was modified for that file? Probably already looked at this, but make sure that all the settings are from "Inherit from parent" in Visual Studio.

Jay

The two files, the one where the function works and the one where it doesn't, seem to have the same properties: I double checked by opening the properties in two instances of VS.
Jamie Fristrom
A: 

My best guess, from what you've posted so-far is that the exception is being thrown somewhere inside the CLR type loader — it looks like an assembly that you're indirectly dependent on either isn't in the GAC, or isn't being copied to the test directory.

Is there an actual stack trace in the test results? That might help narrow down what type(s) its trying to load.

Alex Lyman
Added - any help?
Jamie Fristrom
A: 

Since you say that this started happening all of a sudden, I assume that tests with this line of code were working just fine previously. This may be a radical choice, but in the absence of another solution, perhaps you would consider reinstalling visual studio (a long procedure to be sure)

Joel Martinez
Or go back in source control. Sadly we were having issues with our host and I have about a week's worth of changes in one check-in, so I don't know the exact change that broke it.
Jamie Fristrom
A: 

Can you set Visual Studio to break on all exceptions, regardless of where they come from during debugging?

It sounds as if cosmic rays or a faulty hard drive have caused a test .dll to become corrupt, or the dll you're building is corrupt (consistently). Before re-installing all of Visual Studio, you may want to ask it to do a repair, which should check for inconsistencies between your current install and what's on your installation medium.

Jeff
A: 

How is the FMod .dll getting into your test directory? Do you have it set up to copy it to wherever mstest wants the test to occur? Note that "Copy to Output Directory" doesn't actually accomplish this. There's some other method, though I can't remember quite what it is.

Jeff
+1  A: 

I suggest running your application under Dependency Walker's Profile mode (http://www.dependencywalker.com/). It can record all attempts to load DLLs and EXEs, along with the resulting error codes - it sounds likely that the File not Found error is coming from an indirect dependency - perhaps being pulled in from linking FMod.

If this is the case, profiling your application with Dependency Walker will show one or more failed attempts to load a library. One of them will be the one responsible for the error.

Kevin Gadd
A: 

I'd run it in a debugger and check the run output - in particular the "loading path\fmodex.dll" line to see if it's loading the right dll.

I've seen similar errors when mixing dlls from different configurations.