none
.NET Runtime version 2.0.50727.5448 - Fatal Execution Engine Error (73FAF7FC) (80131506) RRS feed

  • Question

  • Getting the above error log when running QueryExpress to exercise a home-grown OLE DB Provider. Error occurs when running on Windows Server 2008 R2 SP1 x64. All my code is 32-bit, the same combo runs absolutely fine on Windows 7. Stack trace below:

    KernelBase.dll!_RaiseException@16()  + 0x58 bytes 
      mscorwks.dll!RaiseTheExceptionInternalOnly()  + 0x159 bytes 
      mscorwks.dll!UnwindAndContinueRethrowHelperAfterCatch()  + 0x53 bytes 
      mscorwks.dll!NativeDelayFixupStub()  + 0x22cf52 bytes 
      mscorwks.dll!_NativeDelayFixupAsmStub@0()  + 0x24 bytes 
      System.Data.ni.dll!718f2085()  
      System.Data.ni.dll!718ebf37()  
      System.Data.ni.dll!718eab44()  
      System.Windows.Forms.ni.dll!7236dc46()  
      [Frames below may be incorrect and/or missing, no symbols loaded for System.Windows.Forms.ni.dll] 
      System.Windows.Forms.ni.dll!7236deb8()  
      mscorwks.dll!_CallDescrWorker@20()  + 0x33 bytes 
      mscorwks.dll!_CallDescrWorkerWithHandler@24()  + 0x9f bytes 
      mscorwks.dll!MethodDesc::CallDescr()  + 0x15a bytes 
      mscorwks.dll!MethodDesc::CallTargetWorker()  + 0x1f bytes 
      mscorwks.dll!MethodDescCallSite::Call()  + 0x1a bytes 
      mscorwks.dll!ClassLoader::RunMain()  - 0x38dfd bytes 
      mscorwks.dll!Assembly::ExecuteMainMethod()  + 0xa4 bytes 
      mscorwks.dll!SystemDomain::ExecuteMainMethod()  + 0x3e3 bytes 
      mscorwks.dll!ExecuteEXE()  + 0x49 bytes 
      mscorwks.dll!__CorExeMain@0()  + 0x98 bytes 
      mscoree.dll!__CorExeMain@0()  + 0x32 bytes 
      mscoree.dll!_ShellShim__CorExeMain@0()  + 0x3a4e bytes 
      mscoree.dll!__CorExeMain_Exported@0()  + 0x8 bytes 
      kernel32.dll!7532339a()  
      ntdll.dll!775d9ef2()  
      ntdll.dll!775d9ec5()  

    So I'd very much appreciate some guidance on how to get over this problem.

    Thanks

    Tuesday, February 14, 2012 12:14 PM

Answers

  • Hmm.. That is strange. Beyond my knowledge I think, there could be some settings in Visual Studio which did the trick (I cannot create a sample app since I don't have a 64 bit machine at this moment). I did some online search. Couldn't find much info, but this one caught my attention. Read the very last post in that thread.  You might find that helpful.


    Please mark this post as answer if it solved your problem. Happy Programming!

    • Marked as answer by SimonScott Monday, February 20, 2012 9:01 AM
    Thursday, February 16, 2012 9:13 AM
  • Ok. I think I now understand what was happening. So in case anybody's interested...

    The version of QueryExpress as downloaded from the website has a CLR header of 2.0 (according to corflags). That appears to imply that the process will always run 32-bit on a 64-bit machine regardless of the /32bit+ setting.

    When I rebuilt QE from source, the CLR header came out at 2.5. And indeed the process does run either 64- or 32-bit depending on how I set the 32BIT flag using corflags.

    So I can now believe that running the original version of QE loaded my 32-bit OLE DB provider and subsequently hit the exception described above. FWIW, I have converted my OLE DB provider DataSource object from Apartment- to Both-threaded and now everything works fine using the original QE. For the QE that I have built from source, I still need to build it for 32-bit to have everything work.

    So I'm halfway there - I've converted my OLE DB provider from Apartment- to Both-threaded. Now all I need is a 64-bit version of it, which is a much bigger undertaking.

    Thanks Adavesh for your clues that led me along this trail.

    • Marked as answer by SimonScott Monday, February 20, 2012 11:50 AM
    Monday, February 20, 2012 11:50 AM

All replies

  • You said, error occurs when running on Windows Server 2008 R2 SP1 x64. So, I doubt that you have built your code in 'Any CPU' mode. Due to this, the application will run in 64 bit mode but the 32 bit code will fail. So, if you have built the project in 'Any CPU' mode, then build it in 'x86' mode instead.

    Please mark this post as answer if it solved your problem. Happy Programming!

    Wednesday, February 15, 2012 5:02 AM
  • Hi thanks for the response.

    I have marked the QueryExpress executable using corflags /32bit+ - and indeed this exception goes away! Thanks! But I'm not quite sure what I should do with my product.

    My part of this software is an OLE DB Provider written in unmanaged C++ and compiled 32-bit. QueryExpress is to me a third-party application that I have no control over. So the question is, how should I adapt my OLE DB Provider so that this exception isn't provoked in a general .Net consumer?  Shouldn't something in .Net be detecting the incompatibility and informing the user that to use a 32-bit OLE DB Provider they need their .Net consumer to run as 32-bit?  How is it that a 64-bit .Net application is able to load a 32-bit DLL?

    Wednesday, February 15, 2012 11:00 AM
  • How is it that a 64-bit .Net application is able to load a 32-bit DLL?

    What happens if your application is built in AnyCPU mode (/32bit) then it will run in 64 bit mode in 64 bit machines and runs in 32 bit mode in 32 bit machines which is well and good. Suppose you have a DLL built specifically in x86 mode (/32bit+). Now since your exe is 'Any CPU' mode and runs in 64 bit mode in 64 bit machines. But, when the exe tries to load the 32bit DLL, it will with BadImageFormat Exception (something like you got). This is because, when a 64 bit application is started, CLR creates a 64 bit process. But, you can't run a 32 bit DLL code in 64 bit process.

    To overcome this problem, you have to build you main application in x86 mode (/32bit+) explicitly. Then, when you run the application. This is will start a WoW64 process (32 bit). Which means, your applicaiton will run in 32 bit mode only. Now, if your application tries to load the 32 bit DLL, it is loaded happily because the process is already running in 32 bit mode.

    So the question is, how should I adapt my OLE DB Provider so that this exception isn't provoked in a general .Net consumer? 

    So, you have a main application which you don't have control over. And you have 2 versions of DLL - one x86 and another x64. Since, you don't have control over the main application to start it in a specific cpu mode, you can pick appropriate DLL as - First find the CPU mode against which the main app is built. You can use CorFlags or some other utility for this. If the app is built in x86 mode then load 32 bit DLL. If the app is built in 64 bit mode, load x64 bit DLL. Otherwise, if the app is built in 'Any CPU' mode then you need to get the CPU architecture (may be using Environment.Is64BitMachine) and depending on it, you can load appropriate DLL.


    Please mark this post as answer if it solved your problem. Happy Programming!

    Wednesday, February 15, 2012 11:31 AM
  • Again thanks for the response and I think I'm almost there. I need to emphasize that the OLE DB Provider is unmanaged code - so I don't think it makes sense to talk about building with /32bit+. Rather, it's a complete recompile and having two DLLs, a 32 and 64 bit version.

    So the actual loading of the OLE DB Provider DLL is done by .Net OleDB classes. And I guess what I'm interested in is how those classes, when running as 64-bit, managed to load and call a 32-bit provider DLL. Even if I were to build a 64-bit provider DLL, how can I be sure that .Net would load the 64-bit version? It seems quite happy to load the 32-bit version and crash later....

    Wednesday, February 15, 2012 12:38 PM
  • Ok. I understand what are you asking. Oledb provider is a part of System.Data.dll which recides in GAC. Now, let me tell you something intersting. An assembly is commonly identified by name, version and culture. But GAC identifies an assembly by name, version, culture and CPU Architecture. Also, when installing .NET framework, 2 copies of System.Data are installed. One copy to folder where compilers are present which is C:\Windows\Microsoft.NET\Framework\<version>. Other one is installed to C:\Windows\Microsoft.NET\assembly folder. If you open C:\Windows\Microsoft.NET\assembly folder, you can see System.Data.dll in GAC_32 folder in 32 bit machines and in 64 bit machines you can find this DLL in both GAC_32 and GAC_64 folders. In GAC_32 folder, 32 bit version of System.Data is present and in GAC_64 folder 64 bit version of dll is present. 

    When you are building your project, you add reference to System.Data is added from C:\Windows\Microsoft.NET\Framework\<version>. But, when you are running your application, correct verison of System.Data is loaded. I mean, if the app is running in 32 bit mode, System.Data is loaded from GAC_32 folder. On the other hand, if the app is running in 64 bit mode, System.Data is loaded from GAC_64 folder.

    I hope you are getting what I explain. So, having said all this, CLR is smart enough to load correct DLL from GAC depending upon which mode your application is running. So, You don't have to worry about shipping correct version of FCL assembly. CLR will take care of it.

    I hope this helps you.


    Please mark this post as answer if it solved your problem. Happy Programming!

    Wednesday, February 15, 2012 4:49 PM
  • Thank you very much this is great info!

    So the one thing I don't quite understand, given the design you describe, is how, in the 64-bit world, the GAC_64 version of System.Data was able to load my 32-bit unmanaged COM object OLE DB provider? Is there something missing from my COM registration that would stop that?

    Wednesday, February 15, 2012 5:19 PM
  • The exception may be due to some other 32 bit DLL.

    If you think not, my attention turns to whatever you said before - "My part of this software is an OLE DB Provider written in unmanaged C++ and compiled 32-bit". What I didn't get here is have you written this OLEDB provider yourself in unmanaged code?

    If yes, then make two versions of the dll (x86 and x64) and let the dlls be installed in the GAC so that CLR can pick appropriate DLL. Or if you have only 32 bit dll, then there is no way but to run the QueryExpress executable in 32 bit mode always. So, anyways you have set /32bit+ flag. You can ship the same execuatble for installation :)


    Please mark this post as answer if it solved your problem. Happy Programming!

    Wednesday, February 15, 2012 5:32 PM
  • Yes absolutely I am the author of the OLE DB Provider, and I accept that to be as fully interoperable as possible I may need to provide a 64-bit version (not trivial unfortunately).

    So thank you very much. The only nagging question that I still have is that I saw my 32-bit DLL hit breakpoints when I was running the "anycpu" version of QueryExpress. Everything that I have read and you have said suggests that that should not be the case - i.e. that a 64-bit CLR process should not load a 32-bit DLL. I'm just wondering if there is some extra magic in System.Data and/or the OleDbConnection class that tries to support 32-bit OLE DB providers in a 64-bit CLR?

    Thursday, February 16, 2012 8:42 AM
  • Hmm.. That is strange. Beyond my knowledge I think, there could be some settings in Visual Studio which did the trick (I cannot create a sample app since I don't have a 64 bit machine at this moment). I did some online search. Couldn't find much info, but this one caught my attention. Read the very last post in that thread.  You might find that helpful.


    Please mark this post as answer if it solved your problem. Happy Programming!

    • Marked as answer by SimonScott Monday, February 20, 2012 9:01 AM
    Thursday, February 16, 2012 9:13 AM
  • Thanks for your help. I will test again to verify my finding and maybe post again under a more specific title.
    Monday, February 20, 2012 9:02 AM
  • Ok. I think I now understand what was happening. So in case anybody's interested...

    The version of QueryExpress as downloaded from the website has a CLR header of 2.0 (according to corflags). That appears to imply that the process will always run 32-bit on a 64-bit machine regardless of the /32bit+ setting.

    When I rebuilt QE from source, the CLR header came out at 2.5. And indeed the process does run either 64- or 32-bit depending on how I set the 32BIT flag using corflags.

    So I can now believe that running the original version of QE loaded my 32-bit OLE DB provider and subsequently hit the exception described above. FWIW, I have converted my OLE DB provider DataSource object from Apartment- to Both-threaded and now everything works fine using the original QE. For the QE that I have built from source, I still need to build it for 32-bit to have everything work.

    So I'm halfway there - I've converted my OLE DB provider from Apartment- to Both-threaded. Now all I need is a 64-bit version of it, which is a much bigger undertaking.

    Thanks Adavesh for your clues that led me along this trail.

    • Marked as answer by SimonScott Monday, February 20, 2012 11:50 AM
    Monday, February 20, 2012 11:50 AM