When I compile the application using "Any CPU" I am getting System.BadImageFormatException whenever I try to open a connection using Firebird embedded dll (don't ask me why I am still using this legacy DB. not my choice)
Then I thought it must be that the dll only supports 32bit mode. So I tried to compile using x86 and indeed it runs fine this time.
However when I compile using x64 the application still runs fine. This confuses me cause it clearly indicates the dll is able to load in 64bit mode.
I made couple more tests and here are the results:
Any CPU: 64 bit process. System.BadImageFormatException
x86: 32 bit process. Runs fine
x64: 64 bit process. Runs fine
Any CPU (prefer 32bit): 32 bit process. Runs fine
I thought the only magic Any CPU does is that it picks whether to launch the process in 32/64 bit mode during startup. If the application runs fine under strict 64 bit mode then I would expect Any CPU to run fine on the same 64bit machine.
I would prefer to use Any CPU (without prefer 32bit flag) still since it makes the distribution easier.
What could be causing the exception and is there a way to deal with it?
Edit:
So I tried to use reflection to get assembly info and this is the error message I got
Exception calling "GetAssemblyName" with "1" argument(s): "Could not
load file or assembly 'fbembed.dll' or one of its dependencies. The
module was expected to contain an assembly manifest." At line:1 char:1
+ [reflection.assemblyname]::GetAssemblyName("${pwd}\fbembed.dll") | fl
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : BadImageFormatException
After examining the dll's header it turns out that Nuget is the one performing the magic. If I set the target to x86/x64 nuget will include the according version of the dll during compile.
But if I target "Any CPU" nuget will pick the x86 version of the dll. Thus if I try to launch my application in 64 bit mode it will throw BIFE.
Related
I've managed to boil down my test to a simple command:
PS C:\Users\CpUser> [System.Reflection.Assembly]::LoadFrom("C:\Users\CpUser\.nuget\packages\njsonschema\10.4.0\lib\net45\NJsonSchema.dll")
MethodInvocationException: Exception calling "LoadFrom" with "1" argument(s): "Could not load file or assembly 'NJsonSchema, Version=10.4.0.0, Culture=neutral, PublicKeyToken=c2f9c3bdfae56102'."
I'm using 64-bit Powershell v7.1.3 on Windows 10. Ran as administrator. It's not able to load the DLL I gave it, which is very odd to me. It also does not give me any detail as to why it cannot load it. When I try a lower version of NJsonSchema.dll, it works, but it loads it from an unexpected location:
PS C:\Users\CpUser> [System.Reflection.Assembly]::LoadFrom("C:\Users\CpUser\.nuget\packages\njsonschema\9.10.52\lib\net45\NJsonSchema.dll")
GAC Version Location
--- ------- --------
False v4.0.30319 C:\Program Files\PowerShell\7\NJsonSchema.dll
It's loading it from C:\Program Files\Powershell\7 which seems wrong to me. I sent to the Properties -> Details of that DLL and it says it is version 10.2.2. What it seems like is happening here is:
Powershell takes the version of the assembly I provided in the LoadFrom() call
It searches C:\Program Files\PowerShell\7 for the same DLL with a version equal to or greater than the version obtained in the previous step
If not found, fail.
What I expect is for it to load the DLL using the absolute path I gave it.
As a workaround, I found another solution that does seem to work:
$AssemblyPath = "C:\Users\CpUser\.nuget\packages\njsonschema\10.4.0\lib\net45\NJsonSchema.dll"
$bytes = [System.IO.File]::ReadAllBytes($AssemblyPath)
[System.Reflection.Assembly]::Load($bytes)
I get a successful result when I run the above in a script:
PS C:\Users\CpUser> .\testLoadDll.ps1
GAC Version Location
--- ------- --------
False v4.0.30319
So I feel like this rules out any issues with the DLL itself. I'm completely lost here. Can someone explain the behavior I'm seeing and how to get the behavior I expect?
According to the documentation, for Assembly.LoadFrom Method
The LoadFrom method has the following disadvantages. Consider using
Load instead.
...
If an assembly is loaded with LoadFrom, and the probing path includes
an assembly with the same identity but a different location, an
InvalidCastException, MissingMethodException, or other unexpected
behavior can occur.
Update:
According to Resolving PowerShell module assembly dependency conflicts,
PowerShell and .NET
PowerShell runs on the .NET platform. NET is ultimately responsible
for resolving and loading assembly dependencies, so we must understand
how .NET operates here to understand dependency conflicts.
We must also confront the fact that different versions of PowerShell
run on different .NET implementations. In general, PowerShell 5.1 and
below run on .NET Framework, while PowerShell 6 and above run on .NET
Core. These two implementations of .NET load and handle assemblies
differently. This means that resolving dependency conflicts can vary
depending on the underlying .NET platform.
Therefore, ensure you are loading the DLL in the netstandard2.0 folder, if using Powershell version 6 and above.
Try the following:
Open PowerShell version 7.1.3:
In "Type here to search" box, enter pwsh
Right-click PowerShell 7 (x64)
Select Run as administrator
Get PowerShell version:
Get-Host | Select-Object Version
Get Loaded Assemblies:
[System.AppDomain]::CurrentDomain.GetAssemblies()
Load NJsonSchema.dll:
Note: Since we're using PowerShell 7.x.x, use the NJsonSchema.dll file in the netstandard2.0 folder.
$Assembly = [System.Reflection.Assembly]::Loadfile('C:\Users\CpUser\.nuget\packages\njsonschema\10.4.0\lib\netstandard2.0\NJsonSchema.dll')
Get Loaded Assemblies (again):
[System.AppDomain]::CurrentDomain.GetAssemblies()
Check the version of NJsonSchema.dll:
$Assembly.GetName()
Every time i try to compile i'm getting this error:
System.BadImageFormatException: 'An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)'
when i try to run session = PXCMSession.CreateInstance();
I'm running Windows 10 pro, 32 bit operating system.
Added reference to file:
c:\Program Files\Intel\RSSDK\bin\win32\libpxcclr.cs.dll
added to post build evenent:
if "$(Platform)" == "x86" ( copy /y "$(RSSDK_DIR)\bin\win32\libpxccpp2c.dll" "$(TargetDir)" ) else ( copy /y "$(RSSDK_DIR)\bin\x64\libpxccpp2c.dll" "$(TargetDir)" )
And in build tab changed platform target from Any CPU to X86
That exception is usually, in my experience, due to a x64/x86 conflict. Are you definitely referencing the x86 version of libpxcclr.cs.dll?
The fix is to go back to cmake and build with the x64 compilers on your system. If you don't see the prompt for the compiler version, delete the "build" directory and try cmake-gui again. All the C# examples work in x64 but don't in 32-bit.
I created a project and compiled it as Any CPU. on x64-Windows. As I have trouble to reference that assembly from my code I checked the runtime and the target-plattform:
As you can see the target plattform is x64 when running on an x64-OS (as mine). I checked DumpBin also:
PE signature found
File Type: EXECUTABLE IMAGE
FILE HEADER VALUES
14C machine (x86)
3 number of sections
57A49000 time date stamp Fri Aug 05 15:09:20 2016
0 file pointer to symbol table
0 number of symbols
E0 size of optional header
102 characteristics
Executable
32 bit word machine
However when I run CorFlags it´s giving me x64 as plattform for that assembly:
Version : v4.0.30319
CLR Header: 2.5
PE : PE32
CorFlags : 9
ILONLY : 1
32BIT : 0
Signed : 1
As far as I understand when I chose Any CPU as target platform the OS will chose how to execute the assembly. On an 64bit system it´ll run in 64bit, on 32bit-OS as 32bit respectivly.
So my question is: what version am I actually targetting? 32 or 64bit?
That's entirely normal. AnyCPU means that it can run on any cpu so the machine field in the header cannot be relevant. Having to pick something, it just picks x86. Keeps it compatible with ancient Windows versions like Win98 and Win2k.
The special heroics happen on a 64-bit operating system, the OS loader needs help to creating a 64-bit process from a 32-bit executable, that requires patching internal loader structures. The mscoree.dll "loader-shim" gets that job done as described in the linked post.
So you do not target any particular version. It truly is AnyCPU.
I've added a reference to the CUDAfy.NET library via NuGet.
<package id="CUDAfy.NET" version="1.12.4695.21111" targetFramework="net45" />
When I run my program, I hit a Win32Exception:
The system cannot find the file specified
This happens on the first actual line of the program:
CudafyModule km = CudafyTranslator.Cudafy();
There's no indication from the exception object as to what file they're attempting to load.
How can I get past this problem?
EDIT
I see the same exception when running the bundled examples from the Codeplex download in VS2010 using .NET 4.0.
The strack trace is:
at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)
at Cudafy.CudafyModule.Compile(eGPUCompiler mode, Boolean deleteGeneratedCode)
at Cudafy.Translator.CudafyTranslator.Cudafy(ePlatform platform, eArchitecture arch, Version cudaVersion, Boolean compile, Type[] types)
at Cudafy.Translator.CudafyTranslator.Cudafy(ePlatform platform, eArchitecture arch, Type[] types)
at Cudafy.Translator.CudafyTranslator.Cudafy()
Setting VS to break on thrown exceptions shows the ProcessStartInfo object at the top of the stack in the locals pane of the debugger.
The relevant properties are:
FileName = nvcc
Arguments = -m64 -arch=sm_12 "c:\<path>\CUDAFYSOURCETEMP.cu" -o "c:\<path>\CUDAFYSOURCETEMP.ptx" --ptx
Some information from this article explains that the CUDA Toolkit must be installed. Fair enough.
Ensure that the C++ compiler (cl.exe) is on the search path. This set-up of NVCC is actually the toughest stage of the whole process, so please persevere. Read any errors you get carefully - most likely they are related to not finding cl.exe or not having either 32-bit or 64-bit CUDA Toolkit.
That article discusses version 4 of the toolkit, but version 5 is available now and supported since CUDAfy v1.1.
Download from https://developer.nvidia.com/cuda-downloads
Note that the 64-bit version of the CUDA Toolkit 5.0 is a 942 MB download. If you install everything you'll need an additional 2815 MB. The toolkit alone requires 928 MB.
EDIT After installing the CUDA Toolkit 5.0, the program failed with a CudafyCompileException at the same source line:
Compilation error: nvcc : fatal error : Cannot find compiler 'cl.exe' in PATH
Searching my system drive:
C:\>dir /s cl.exe
This shows many different versions of the compiler/linker, both from VS 10.0 and 11.0. Apparently only cl.exe versions 9 and 10 are supported, so I opted for the VS10.0 amd64 version, I included the following in my PATH environment variable:
C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\amd64
Your path may be different, depending upon your CPU. I recommend running the search to see your options.
Note that you will have to restart VS after changing the PATH environment variable if you already have it open.
After taking these steps, my basic program ran successfully.
This may also happen if you had at some point installed CUDA Toolkit v7.5, but realized that the most recent version of CUDAfy supports CUDA 7.0.
On uninstalling CUDA 7.5 from the control panel, some files/folders may still remain. You should delete these manually. You may use CUDAfyViewer to see which version of CUDA Toolkit is being accessed.
app was complied on windows7, .net4.0
i put the dll: TECIT.TFORMer.dll in the app file
test-pc,i386:
server-pc,amd64:
on test-pc,i debug the app, and got the resut, log:
but on server-pc, throw exception, log:
why test-pc app :DllImport attempting to load: 'libTFORMer6.so'
but server-pc app never show the log?
thanks.
If your mono is 64 bit, you can not load a 32 bit library into it.
While the OS usually supports running 32 bit code, it applies to the whole process.
So you should either make a 64 bit library or run 32 bit mono.
Disclaimer: your question wasn't quite clear whether you are trying to use the same library on both systems.