DLL Import Failure

Started by
31 comments, last by myvraccount 9 years, 8 months ago

Well here's a summary of what I've tried and what it's doing now:

To review, I have a third party DLL compiled to machine language (DLL A), and I used that inside a C++ project to make my own DLL which builds onto it (DLL B), and compiled it and put it into a C# project. I import it using the interop service and my syntax is good and everything compiles correctly, but when I try to call a function in it, I was getting a DllNotFoundException.

That's where I was at my previous post. Since then:

- I've put DLL B into each of the possible folders where it could be accessed (the solution, project, debug and release folders) to make sure it's finding it.

- I also recompiled DLL B in release mode instead of debug, and re-copied it into those folders.

- I also included DLL A into those folders and imported it into the project.

At least one of those things must have partially fixed it, because I no longer get a DllNotFoundException when I call the function; instead I get BadImageFormatException, and it says "An attempt was made to load a program with an incorrect format." and it says "HRESULT: 0x8007000B".

As an alternative, I also tried to just include DLL A instead of DLL B, with the intention of recreating DLL B within C# by using DLL A directly. I include and reference DLL A and its functions the same way I was doing with DLL B, but I just get a DllNotFoundException.

I don't really care which way works, because DLL B is simple and I can recreate it (it might even be cleaner that way) but whatever way works is fine with me.

Does anyone know what I'm doing wrong?

Advertisement
How are you compiling you C# code? The most likely problem I can think of is your C# code is compiled with "Any CPU" (the default in Visual Studio) which can mean that you're running 64-bit C# code on a 64-bit OS, but your C++ DLLs are 32-bit. So the OS goes looking for a 64-bit DLL and can't find one, so it errors.

When you interop between .NET and native code, you need to make sure that you're using the same bitness, so try forcing your build platform for C# to x86 (32-bit) or x64 (64-bit) depending on how you compiled your C++ DLL.

I second what SmkViper said, this sounds like you're trying to use a 32bit dll from a 64bit program or vice versa.

It seems to be corroborated by this StackOverflow post:

http://stackoverflow.com/questions/2023766/an-attempt-was-made-to-load-a-program-with-an-incorrect-format-even-when-the-p

 

That's a great idea; I'll try it!

But there would still be a few problems:

A) That wouldn't explain why when I import DLL A (explained above) directly instead of DLL B, I'm getting a DllNotFoundException even though I'm now doing it the same way as when I import DLL B. Ultimately if it works the other way this is a moot point, but I'm still curious about it anyway, and some day I may need to do this.

B) From what SmkViper says, it sounds like I can't make a 64 bit program recognize a 32 bit DLL. That can't be right though, because what if I need a program to be 64 bit, but use a 32 bit DLL? Or what if I need a program to use 2 different DLLs and one is 64 bit and the other is 32 bit and I can't recompile them because I don't have the source? There would have to be a way to do this.

B) From what SmkViper says, it sounds like I can't make a 64 bit program recognize a 32 bit DLL. That can't be right though, because what if I need a program to be 64 bit, but use a 32 bit DLL? Or what if I need a program to use 2 different DLLs and one is 64 bit and the other is 32 bit and I can't recompile them because I don't have the source? There would have to be a way to do this.


64-bit processes can't load 32-bit DLLs, and vice versa. All EXEs/DLLs loaded into the process must match.

The exception is that .Net's "Any CPU" DLLs can be loaded into 64-bit or 32-bit processes because the JIT can generate the appropriate code either way.

.Net's "Any CPU" EXEs, on the other hand, will start a 64-bit process if your OS is 64-bit, or a 32-bit process if the OS is 32-bit, but any DLLs loaded thereafter have to match the bit size the EXE picked.


If you don't have proper versions of all DLLs and don't have the source code, you have to go with the bitness that you have available (32-bit, in most cases). When making a .Net EXE which loads 32-bit DLLs, you have to make sure to change the .Net projects to target x86 instead of "Any CPU".

Right, but what if I wanted to use 2 DLLs in the same project, and one is 32 bit and the other is 64 bit, is it impossible to make any program that will use both DLLs? That seems absurd.

Right, but what if I wanted to use 2 DLLs in the same project, and one is 32 bit and the other is 64 bit, is it impossible to make any program that will use both DLLs? That seems absurd.


64-bit processes can't load 32-bit DLLs, and vice versa.

Right, but what if I wanted to use 2 DLLs in the same project, and one is 32 bit and the other is 64 bit, is it impossible to make any program that will use both DLLs? That seems absurd.


That's correct. You cannot mix 32-bit and 64-bit DLLs in the same program. You can, however, make two programs. The 32-bit program that uses 32-bit DLLs, and a 64-bit program that uses 64-bit DLLs.

I suppose if you're really persistent you could have your X-bit program load X-bit DLLs, and then use inter-process communication to load and talk to a separate Y-bit process that loads Y-bit DLLs. But you're going to basically be throwing performance out the window at that point.

Right, but what if I wanted to use 2 DLLs in the same project, and one is 32 bit and the other is 64 bit, is it impossible to make any program that will use both DLLs? That seems absurd.

If you need to mix 32bit + 64bit DLL's, then the only option you have is to use an IPC approach (pipes, named pipes, network socket), and use that to connect two applications together. It's neither nice, nor fun. Ditch the 32bit DLL and move on.... :)

Alright, I'm SO CLOSE, but I still have a bit of a problem.

So I tried the 32/64 bit thing. I tried changing it in the Build->Configuration Manager menu, both the Platform and the Active solution platform. It's odd, because in both cases, the only option initially was Any CPU, but I clicked New and there were options for Win32 and 64 bit, but no way to customize their options (other than copying settings from an existing one, which I also tried). Why aren't there any options to set, anyway? Is it sufficient to just pick which one you want and leave it at that? And if so, why do I have to choose them from "New"; shouldn't they just already be on the list?

Anyway, the third party DLL I'm using (DLL A) is apparently available in 32 or 64 bit, so I tried both. I tried them directly in the project, setting the platform settings to match, and I alternatively tried putting DLL A into a C++ project to make my DLL (DLL B), and then import that one. In that case, I had to make everything 32 bit, because it seemed like my C++ project was stuck that way, but I was able to compile and import that into my other project.

In all cases, when I called the functions, I got DllNotFoundException or BadImageFormatException, and usually I could manipulate the first one into the second one by changing some settings (it seems to me that the second exception is not as bad, and closer to the goal). But no matter what I did, I couldn't get rid of the exceptions completely so I could actually run the functions.

Also, when I "import" DLLs into my project, what I've been doing is placing the DLL, LIB, PDB and another file (I don't remember the extension off hand) into every folder within my project JUST IN CASE it's looking for it somewhere I wouldn't expect, then inside the project I "Add existing item" and pull them all in that way.

I thought that would be sufficient, but then I noticed that there is an "Add reference" on the menu, which then allows me to choose DLLs from a list of ones that are apparently already associated with the project in some way or another (like mine because I included it in the project). On this list, I checked the box to import it and clicked OK, but I got an error. Unfortunately I don't have the text with me, because I wrote down so many notes about errors I accidentally brought the wrong one, but I think it essentially said that it couldn't import it for some reason or wasn't compatible or something. Sorry if that's vague. I'll try to be more specific tomorrow when I bring the note.

So if anyone happens to know what I'm doing wrong, I would appreciate if you tell me please! Thank you.

This topic is closed to new replies.

Advertisement