BadImageFormatException: PInvoke ImportDll with hdf5dll.dll - c#

Ok, I have the HDF5 library downloaded from the official site, and I have a few DLLs, including hdf5dll.dll, and hdf5_hldll.dll.
I have what I think to be some wrappers around the native calls, in my classes H5, H5LT, H5F, and H5T. Example from H5.cs:
namespace HDF5
{
using hid_t = System.Int32;
using herr_t = System.Int32;
using hsize_t = System.UInt64;
using size_t = System.UInt32;
// hbool_t is 0:false, +:true
using hbool_t = System.UInt32;
// htri_t is 0:false, +:true, -:failure
using htri_t = System.Int32;
public class H5
{
const CharSet StringMarshallingType = CharSet.Ansi;
const string DLLNAME = "hdf5dll.dll";
///* Functions in H5.c */
//H5_DLL herr_t H5open(void);
[DllImport(DLLNAME,
CharSet = StringMarshallingType)]
public static extern herr_t H5open();
And in Program.cs, I use H5.H5open();, but I get a BadImageFormatException. Do I need a different DLL? Does the method signature look wrong?
I'd like to, as the next step, get this in C#: http://www.hdfgroup.org/HDF5/Tutor/h5lite.html .
OS: Windows 7 64 bit
Environment: Visual Studio 2008 Professional
Update: I don't know if this will be related, and I don't remember if my environment is VS2008 SP1, but this question may hold a key to solving the mystery. I am as of now trying to repeat the scenario on 32 bit VS 2010 at home.

That happens when you're trying to run P/Invoke operations on a dll meant for x86 architecture from within an x64 process or vice versa. I'd check all of that and if they're out of sync, consider targeting the processor that HDF5 targets with your application, or checking if a processor-specific version is available.

Looking at the documentation from here, the function prototype is:
herr_t H5open(void);
And also the DLLNAME is disallowed, you must explicitly specify the dll name - no questions asked.
The proper signature is:
[DllImport("hdf5dll.dll")]public static extern herr_t H5open();
Make sure you have the type herr_t defined...
Let the runtime take care of the marshalling for you....
Also make sure, the DLL is present in the same path as where the compiled .EXE (your code) is generated.
Edit: Thanks to the OP for pointing out my blooper....

On x64 operatingsystems .net programs usually run in x64 mode.
Just set your target processor architecture to x86 and try again.
Just in Visual studio open your "Solution Configuration"-Manager and add a new target Platform.

Related

Unmanaged Exports not showing up in DLL

I have a new project and a test class, method below:
[ComVisible(true)]
[DllExport("Heartbeat2", CallingConvention = CallingConvention.StdCall)]
public static void Heartbeat2(){
//Do stuff here
}
Im using Unmanaged Exports (RGiesecke.DllExport) latest in DotNet 4.6...when running Nirsofts viewer, I do not see my method in the dll http://www.nirsoft.net/utils/dll_export_viewer.html)
I have the platform target to x86 also...what am I doing wrong? I plan on using this in a ruby 1.8.1 program using Win32API
Giesecke's Unmanaged Exports works fine using VS2015, but not in VS2017 or VS2019.
Try downloading VS2015 Community and try your example there.
Be sure you are building for X64 or X86, not Any CPU.
The Unmanaged Exports should generate a DLL, plus a LIB and RES file.
You can check whether the DLL was modified by checking it with one of several fine .Net decompilers, my current favourite is https://www.jetbrains.com/decompiler/

Debugging a failure to access libleveldb with C# on OSX

A C# project I'm interested in uses leveldb via a PInvoke 'wrapper' that works fine on both Windows and Linux but throws the following error on OSX.
src/tcmalloc.cc:331] Attempt to free invalid pointer 0x7f83cb954a00
A minimal example to reproduce the error with is
using System;
using System.Runtime.InteropServices;
namespace leveldb_test2
{
internal static class Native {
[DllImport("libleveldb", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr leveldb_options_create();
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("before");
IntPtr handle = Native.leveldb_options_create();
Console.WriteLine("after");
}
}
}
What I've tried
Manually building leveldb
Leveldb was initially installed via homebrew. Not knowing if they do anything magical, I also did a manual build which gave me the same error.
Verifying the method signature
The method signature used with DllImport seems ok, as it's identical to what's used in a wrapper project I found: leveldb-sharp (fwiw; I tried using that project, same error)
Note that original export from leveldb is
extern leveldb_options_t* leveldb_options_create();
I also created my own dll with the same signature and that worked fine. This also confirmed for me that I can correctly enforce which exact library file is being loaded to avoid it using some broken version somewhere else on my system.
Verifying library exports
I dumped the exports using nm to make sure no name mangling is going on, seems fine.
I can also access the library successfully with ctypes in Python.
Try older versions of leveldb
I tried all older versions up to 1.15 from September 2014. All give the same error.
What's next
Ideally, I'd like to be able to debug the native side. However, unlike with Visual Studio on Windows, the OSX Visual Studio Community Edition doesn't have the "Enable native code debugging" option described here. So my question is
How would I go about debugging the native side while initiated from C#?
I believe the latter part of this question is important, because as said before it works fine when initiated from Python. Any tips/hints/help are much appreciated!
PS: a bonus would be the solution to getting the wrapper to work.

Using 64-Bit SPSS Libraries in C#

I'm trying to create an .sav file programmatically without having to use SPSS automation (the SPSS.BackendAPI library) in order to free up more SPSS licenses. I found this library at CodePlex that uses the 32-bit I/O module without requiring a license, which is good.
The problem is that I need to build the application as x64 in order to gain access to the extra addressable memory in my own application. Thus, I need to use the 64-bit libraries as well. Has anyone had luck using the 64-bit libraries in managed code?
You can use that library from CodePlex, but you'll have to modify it a bit to work with the spssio64.dll that's included with the I/O Module. In the SpssThinWrapper.cs file, you'll need to change the DLL that's being imported. You'll also have to change some of the entry points. To get the names of the entry points in the 64-bit DLL, you'll want to run dumpbin /exports spssio64.dll. If you do this you'll see that the the 64-bit and 32-bit entry points are basically the same, except that some of the 32-bit ones have an # sign and a number after them, whereas none of the 64-bit entry points do. Do change all of those along with the DLL in the DllImport attribute. For example:
[DllImport("spssio32.dll", EntryPoint="spssCloseAppend#4", CharSet=CharSet.Ansi, SetLastError=true, ExactSpelling=true)]
public static extern ReturnCode spssCloseAppend(int handle);
becomes
[DllImport("spssio64.dll", EntryPoint = "spssCloseAppend", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
public static extern ReturnCode spssCloseAppend(int handle);
and so on.
After doing this you'll want to make sure you're using the correct DLLs. Copy the spssio64.dll, icudt32.dll, icuin32.dll, and icuuc32.dll from the win64 folder of the I/O Module into the Resources folder from the SPSS .NET library from CodePlex. This will overwrite the existing 32-bit dlls, so if you need both 32-bit and 64-bit you'll have to do something different, but it sounds like you just need 64-bit, so this should work.
As an example of how easy it is to create an .sav with this library:
using (SpssDataDocument spssDoc = SpssDataDocument.Create("test.sav")) {
SpssVariable v = new SpssNumericVariable();
v.Name = "gender";
v.Label = "What is your gender?";
v.ValueLabels.Add(1, "Male");
v.ValueLabels.Add(2, "Female");
doc.Variables.Add(v);
doc.CommitDictionary();
SpssCase c = doc.Cases.New();
c["gender"] = 1;
c.Commit();
}
The library handles all of the spss* calls for you, and makes sure they're in the right order and everything.
Why don't you just use the SPSS Statistics i/o dll available via the SPSS Community site (www.ibm.com/developerworks/spssdevcentral)? It is free and comes in 32 and 64 bit versions for all the supported SPSS platforms. It does not require an SPSS license.

c# dllimport of MsiGetShortcutTarget(msi.dll) failed with error 1603 under Windows 7

I want to resolve an advertised MSI shortcut in c# as described here:
How to parse "special" .lnk files, aka. MSI shortcuts aka. Windows Installer advertised shortcuts using C#
[DllImport("msi.dll", CharSet = CharSet.Auto)]
private static extern UInt32 MsiGetShortcutTarget(
string szShortcutTarget,
[Out] StringBuilder szProductCode,
[Out] StringBuilder szFeatureId,
[Out] StringBuilder szComponentCode);
public static string ParseShortcut(string file)
{
StringBuilder product = new StringBuilder(MaxGuidLength + 1);
StringBuilder feature = new StringBuilder(MaxFeatureLength + 1);
StringBuilder component = new StringBuilder(MaxGuidLength + 1);
UInt32 res = MsiGetShortcutTarget(file, product, feature, component);
...
}
I use VS 2010 and tried with different settings for "Platform target" and/or "Target framework". MsiGetShortcutTarget always returns 1603 (A fatal error occurred during installation) under Windows 7.
I tried to do the same with c++ and I can resolve the Shortcut and everything is fine. I also tested with a msi.dll, that I copied from a Windows XP and this dll can resolve the Shortcut with the C# code. I have no idea why the c# code won't work with the msi.dll under Windows 7.
I testet MsiGetComponentPath with a known product GUID and component GUID to resolve the target path in c# with the dll, that returns 1603 for MsiGetShortcutTarget and it works perfectly. So only MsiGetComponentPath fails under Windows 7 and I don't know why it went wrong.
This seems related to the way COM is initialized.
If I add [STAThread] to my Main method, it works fine (well, if you actually use StringBuilder instead of char[] for your arguments :-), but I get a return value of 1603 when using MTA.
I highly suggest taking a look at WiX's Deployment Tools Foundation. It has a really nice interop library developed by a MSFT employee that makes calling MSI easy.
For example, the Microsoft.Deployment.WindowsInstaller namespace has an Installer class that exposes a static method ShortcutTarget GetShortcutTarget( string shortcut ). The ShortcutTarget class then has get accessors for ComponentCode, Feature and ProductCode.
Additionalyl this is an open source project so if you really, really want to know how the P/Invoke stuff works you can look at the code.

AnyCPU/x86/x64 for C# application and it's C++/CLI dependency

I'm Windows developer, I'm using Microsoft visual studio 2008 SP1. My developer machine is 64 bit.
The software I'm currently working on is managed .exe written in C#. Unfortunately, I was unable to solve the whole problem solely in C#. That's why I also developed a small managed DLL in C++/CLI. Both projects are in the same solution.
My C# .exe build target is "Any CPU". When my C++ DLL build target is "x86", the DLL is not loaded.
As far as I understood when I googled, the reason is C++/CLI language, unlike other .NET languages, compiles to the native code, not managed code.
I switched the C++ DLL build target to x64, and everything works now. However, AFAIK everything will stop working as soon as my client will install my product on a 32-bit OS. I have to support Windows Vista and 7, both 32 and 64 bit versions of each of them.
I don't want to fall back to 32 bits. That 250 lines of C++ code in my DLL is only 2% of my codebase. And that DLL is only used in several places, so in the typical usage scenario it's not even loaded.
My DLL implements two COM objects with ATL, so I can't use "/clr:safe" project setting.
Is there way to configure the solution and the projects so that C# project builds "Any CPU" version, the C++ project builds both 32 bit and 64 bit versions, then in the runtime when the managed .EXE is starting up, it uses either 32-bit DLL or 64-bit DLL depending on the OS?
Or maybe there's some better solution I'm not aware of?
Thanks in advance!
There is a way: to have an "AnyCPU" C# wrapper and a C++ project per architecture, and let the C# wrapper load the right C++ project at run time.
For the C++ project, create one version per different architecture (x86, x64), and build them all. Then in the wrapper do:
public class CppWrapper
{
// C++ calls that will be dynamically loaded from proper architecture:
public static readonly Func<long> MyCplusplusMethodUsableFromCsharpSpace;
// Initialization:
static CppWrapper()
{
if(Environment.Is64BitProcess)
{
MyCplusplusMethodUsableFromCsharpSpace = CppReferences64.MyCplusplusClass.Method;
// Add your 64-bits entry points here...
}
else
{
MyCplusplusMethodUsableFromCsharpSpace = CppReferences32.MyCplusplusClass.Method;
/* Initialize new 32-bits references here... */
}
}
// Following classes trigger dynamic loading of the referenced C++ code
private static class CppReferences64
{
public static readonly Func<long> MyCplusplusMethod = Cpp64.MyCplusplusMethod;
/* Add any64-bits references here... */
}
private static class CppReferences32
{
public static readonly Func<long> MyCplusplusMethod = Cpp32.MyCplusplusMethod;
/* Add any 32-bits references here... */
}
}
And in the C++ code, I use the same sources as I said, but will compile to different namespace depending on the build architecture:
#ifdef _M_X64
namespace Cpp64 {
#else
namespace Cpp32 {
#endif
public ref class MyCPlusPlusClass
{
public: static __int64 Method(void) { return 123; }
};
}
There is no easy way around it. If you have native code (i.e. your C++) and you need to support x86, then you have to compile x86 (unless you want to work in WOW world...ie. running 32 bit code in both 32 and 64 bit envrionments). You can have both an x86 and x64 distributions, but if you're supporting both 32 and 64 bit, and you have native code or COM introp' then you have to have both 32 and 64 bit binaries. "Any CPU" only really is useful when there is no native code or interop, then you get that benifit.

Categories