I'm writing a program in .NET 3.5, that in some places has to go out and execute code from hardware APIs. This is all good, and working in 32-bit Windows 7, Windows XP, etc. The problem comes with Windows 7 64 bit.
I compile in 'Any CPU', and it does run in 64 bit on Windows 7 64 bit. So, to interface with this one piece of hardware, I had to write my own wrapper DLL, in unmanaged C++.
So, after I had it all working in 32 bit, I then flipped the switches to go to 64 bit, and therein lies the problem. The issue I'm having is pretty much the EXACT opposite of Stack Overflow question “An attempt was made to load a program with an incorrect format” even when the platforms are the same... In that question, he's trying to get his code to run in 32 bit (force it to) on Windows 7.
OK, now, I don't want to do that, since there IS a 64 bit API for this piece of hardware. So, I compiled my code in 64 bit, and then after a 开发者_如何学JAVAlot of trial and error, I got it LINK properly in 64 bit, and I have a PURE 64-bit native C++ DLL, and Depends.exe
confirms that. Now, Depends.exe
also displays the vendor's DLL file as pure 64 bit. Which is good, because the first time the code didn't work, I started the research with the manufacturer, and they have updated their code quite a bit with my help, or should I say with my ISSUES... :)
So, short story long, I've broken this down to as simple a setup as I can. My DLL file, the HW API.dll
, (which is also native C++), and a .NET application to call them, using the same P/Invoke syntax, and calls as the 64-bit version...
My calls, just for reference look like this:
[DllImport("xBiometrics.dll", ExactSpelling=true, SetLastError=true)]
[return: MarshalAs(UnmanagedType.I4)]
public static extern Int32 bioScanOpenDevice();
Now, when I attempt to call this code, from .NET, I get an exception error:
"System.BadImageFormatException:
An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)"
This leads me to belive that SOMEHOW, something 32 bit is interfeering... How could I possibly tell that? I mean, yes, I've already looked into the resource explorer, and made sure that the DLL files were getting loaded from the correct place, and again, they ARE compiled in 64 bit, and the .NET application is running in 64 bit, even though it's compiled for "Any CPU". I've verified all this...
Am I being totally stupid about something here? Did I miss the paragraph where it tells us that P/Invoke does not work on 64 bit or something? And if I did, why is it throwing a bad image format exception?
Is what I'm doing even possible or not? Can a 64 bit .NET application, load, and call a 64 bit native DLL file? And can THAT DLL file dynamically link to another native 64-bit DLL file? Would it make a difference if I used a managed 64-bit DLL file as the wedge DLL file? I'm only using a wedge DLL file because of some of the calls in the hardware vendor's DLL file. They pass void pointers to buffers, and such and it got to be too complicated to do in C# (having to have the "Allow Unsafe Code" checked, etc.) So, my wedge idea worked much better... I do all the heavy lifting in C++ and pass back more structured data to the C# code.
I know for a fact that I can call a 64-bit native DLL from a C# program that was compiled with "Any CPU" and is running under the 64-bit runtime.
I would suggest the following for debugging:
1) In your C# program, check the value of IntPtr.Size
when the program starts up. If it's not == 8, then you're not running in 64-bit.
2) Set the full path of the 64-bit DLL in your DllImport. That is:
[DllImport(@"c:\fullpath\xBiometrics.dll", ExactSpelling=true, SetLastError=true)]
If that works (which I suspect it will), then the problem is that there's a 32-bit copy of the DLL somewhere in your DLL search path. This has tripped me up more than once.
The most likely source of error is that you declared some parameter wrongly - e.g. an Int32 when you really wanted an IntPtr.
It's also possible that you failed compiling the 64bit version. For example, I know for a fact that VS bit me in the ass before changing some non-bit-related project settings when changing address size. I would go through all your unmanaged project settings and make sure that they are all identical between 32bit and 64bit.
Finally, try loading the unmanaged DLL from an unmanaged application. You want to know if the error is on the managed side or in the unmanaged code.
Another option you might think about is to write a out-of-process COM wrapper around your DLL functions.
Then COM marshaling will handle any 32 to 64 bit interface problems.
It is slower though.
I have encountered a similar problem before, and I resolved it by ensuring that my code worked with pointers defined as long - check that they are all 64-bit.
You may find that you are actually running the 32 bit framework for some reason. You can manage the DLL files being found by specifying alternate paths to find the correct DLL to load. See an answer to Stack Overflow question How to use the correct unmanaged DLL file according CPU architecure? (32 / 64 bits).
精彩评论