Call into 64bit Dephi DLL from C# on 64bit Machine - c#

I my c# app I am trying to call into a Delphi DLL build as 64bit. I keep getting an error stating "An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B". I am running on a Windows 7 64 bit machine and have my C# project set to Any CPU.
API call
[DllImport("Cipher.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.ThisCall)]
public static extern void Encrypt(StringBuilder szPlainText, StringBuilder zCipherText);
Encrypt(plainString, encText);
If the Delphi DLL was build as 32bit this call works fine. Any ideas?

For some reason your app is not run as a 64-bit but rather a 32-bit process. If you need to do things like this, it's better to specify "x64" instead of "AnyCPU".

Related

DLLImport is showing my current directory in another user machine

I am new to PInvoke, I wanted to update my system volume using C#, I got one C++ dll and I have to just Import that DLL and use the methods to update the volume.
In C# I have written :
public const String DllName = "ChangeVolumeWindows.dll";
[DllImport(DllName, CharSet = CharSet.Auto)]
public static extern void SetSystemVolume(double newVolume, VolumeUnit vUnit);
I have put my dll into the exe path.
It is working fine for my pc , but when I package the app and send it to another machine I getting error " DLL not found "
I have observed that DLLImport is looking for path of my pc, which is not correct
For example:
I have put my dll in C:/User/ABC/Source/App/bin/debug/ChangeVolumeWindows.dll
in some another machine also it is looking for the same path instead of taking dll from C:/User/AnotherMachineUser/Source/App/bin/debug/ChangeVolumeWindows.dll
Can some one suggest where my code is going wrong.
I have tried to put my dll inside the project and the rebuild. Still I am facing the same issue.
Try this:
My.Application.Info.DirectoryPath("\folders\ChangeVolumeWindows.dll")

How to import function from c++ dll

Here is c++ dll code:
#include<stdlib.h>
#include "pch.h"
extern "C" _declspec(dllexport) int Add(int a, int b)
{
return a + b;
}
C# code, that i run in Visual Studio:
[DllImport(#"C:\Dll1.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern int Add(int port, int speed);
public static void Main()
{
int res = Add(8, 11);
Console.WriteLine(res);
}
No problems, output: 19
PowerShell code:
Add-Type -Name MyFunctions -Namespace Cpp #'
[DllImport(#"C:\Dll1.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
public static extern int Add(int port, int speed);
'#
[Cpp.MyFunctions]::Add(8, 11)
Output:
An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)
But functions from user32.dll/kernel32.dll imports without any problems.
How to fix it?
Make sure that you are using 32 bit dll for 32 bit powershell process and 64 bit dll for 64 bit powershell process.
The error looks like as if you trying to load 32 bit dll into 64 bit process. Please note that .net applications compiled as "Any CPU" will run in 32 bit mode by default even on 64-bit operating system.
Update
If you have a sources for your dll, then you should recompile it for 64 bit environment and then import this 64-bit build.
If you need to execute PS script in a both 32- and 64-bit powerShell environments, then you should deploy two versions of dll and select the right one in runtime. I do not know how this can be done for PS, but for C# solution you can use #ifdef-based solution as described here: Using a 32bit or 64bit dll in C# DllImport
If you do not have sources for your dll, then all become complicated and I do not know any direct solution here. You can try to wrap your DLL in the 32-bit in-process (or even out-of-process) COM server (with help of C# or C++) and then use this server with New-Object. As I know, the Windows have special shims which allow to utilize 32-bit COM objects from 64-bit process and vice versa, but I am unsure if this will work for PS or not.
For build-in DLLs Windows has automatic file paths redirection from System32 to SysWOW64. So, when you requesting user32 import, you will get different user32 libraries depending on your process bitness. You can read more about this here: 64bit PowerShell calls the 32bit DLL

DllNotFoundException with HRESULT 0x8007007E when loading 64-bit dll

I downloaded zlib and compiled the library as both Windows 32-bit and Windows 64-bit dll. I now have zlibwapi.dll and zlibwapi64.dll.
The dlls are copied into my application folder and are referenced as follows:
[DllImport(#"zlibwapi.dll", EntryPoint = "uncompress", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = false)]
private static extern int uncompress32(
IntPtr dest,
ref uint destLen,
[In(), MarshalAs(UnmanagedType.LPArray)] byte[] source,
uint sourceLen
);
[DllImport(#"zlibwapi64.dll", EntryPoint = "uncompress", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, ExactSpelling = true, SetLastError = false)]
private static extern int uncompress64(
IntPtr dest,
ref uint destLen,
[In(), MarshalAs(UnmanagedType.LPArray)] byte[] source,
uint sourceLen
);
At runtime I check whether I'm 32-bit or 64-bit, and call appropriate version.
This works fine if I'm 32-bit, but the 64-bit version gives
Cannot load DLL "zlibwapi64.dll": Module not found. (HRESULT exception: 0x8007007E)
I've found many similar questions on the Internet, and the suggested reason was that the library depends on some other libraries, and it is those libraries that may not be found.
This does not seem to the case:
zlibwapi64.dll only depends on Kernel32.dll and MSVCR90.dll. I do have VS2008 C++ runtimes installed, both 32 and 64 bit.
When I try to load zlibwapi64.dll from a non-managed C++ application, it loads no problem. It is C# that fails to load it.
I have tried setting absolute path to the 64-bit dll, it does not help.
How do I make it work?
It is a fairly basic "file not found" kind of error, unfortunately it doesn't tell you explicitly what DLL it couldn't find. You already know about the issue with dependent DLLs. Note that you can avoid the irksome dependency on msvcr90.dll by compiling the code with /MT
You'll need to debug the problem and that requires getting insight in where it is looking for DLLs. One good tool is SysInternals' ProcMon utility, it shows you exactly where your program is looking for files. You should see it probing for the DLL, searching through the directories of the PATH and failing to find the file.
Unfortunately ProcMon is a bit chatty and has a habit of drowning you in the data. A more dedicated tool is GFlags.exe, a tool available from the Debugging Tools for Windows package. These days included with the Windows SDK. Stored in c:\program files (x86)\debugging tools for windows\gflags.exe after you installed it. You can turn on the "Show loader snaps" option. On later Windows versions, that tells the Windows loader to generate debugging messages when it is searching for DLLs. They'll appear in the Output window when you enable unmanaged debugging.
Try ProcMon first, much easier to get going.
And of course consider pure managed solutions so you are not fighting these kind of install problems. Good ones are DotNetZip and SharpZipLib, take their first google hit.
Another good tool for examining Dll dependencies is Dependency walker (depends). It looks at the file in a static way so a little easier than using process monitor.
http://www.dependencywalker.com/

32 bit dllimport generating incorrect format error (0x8007000b) on win7 x64 platform

I'm trying to install and run a 32 bit application on a Win7 x64 machine. The application is built as a Win32 app. It runs fine on 32 bit platforms. On the x64 machine it installs correctly in the Programs(x86) directory and runs fine until I make a call into a 32 bit dll. At that time I get the incorrect format error (0x8007000b) indicating it is trying to load the dll of the wrong bitness. Indeed it is trying to load the 64 bit dll from the System32 directory rather than the 32 bit version in the SystemWOW64 directory.
Another 32 bit application provided by the dll vendor runs correctly and it does load the 32 bit dll from the SystemWOW64 directory. I do not have source to their application to see how they are accessing the DLL.
I'm using the DllImport function as shown below to access the dll. Is there a way to decorate the DllImport calls to force it to load the 32 bit version?
Any thoughts appreciated.
Thanks, DP
public static class Micronas
{
[DllImport(#"UAC2.DLL")]
public static extern short UacBuildDeviceList(uint uFlags);
[DllImport(#"UAC2.DLL")]
public static extern short UacGetNumberOfDevices();
[DllImport(#"UAC2.DLL")]
public static extern uint UacGetFirstDevice();
[DllImport(#"UAC2.DLL")]
public static extern uint UacGetNextDevice(uint handle);
[DllImport(#"UAC2.DLL")]
public static extern uint UacSetXDFP(uint handle, short adr, uint data);
[DllImport(#"UAC2.DLL")]
public unsafe static extern uint UacGetXDFP(uint handle, short adr, IntPtr data);
}
Force your .exe to run in 32-bit mode. Project + Properties, Build tab, Platform Target = x86.
Avoid getting confused by the project's Platform setting, it doesn't actually have to match the real setting. Which is Project + Properties, Build tab, Platform Target. Bit of a mess there.
Since your post is tagged with C#, I'm assuming this is a .NET app. It's probably not being set 32-bit only. You can verify by running corflags.exe on it, and setting the 32-bit only flag on it with corflags /32bit+ myapp.exe. If that fixes it, you need to fix your solution/project to build as x86 instead of Any CPU.
In order to force the application to run in 32-bit mode on 64-bit platform you can set it in IIS application pool: in advanced settings set "Enable 32-bits applications" to TRUE.

BadImageFormatException: PInvoke ImportDll with hdf5dll.dll

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.

Categories