Unmanaged Exports not showing up in DLL - c#

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/

Related

Using UnmanagedExports Package [DllExport] to call C# DLL in VBA Triggers "Can't Find DLL Entry Point" Error

I'm using Robert Giesecke's Unmanaged Exports package to access c# dll in Excel VBA. I've followed several examples and continue to get the run-time error 453: "can't find entry point MyDLLFunction in myDllName.dll"
I'm on a 64bit machine using 64bit Excel and am packaging the dll for x64.
I'm working in Visual Studio 2022 and have tried preparing the dll in both .NET 6.0 and .Net Framework 4.7.2.
Here's my exported class:
namespace MyNamespace
{
public static class UnmanagedExports
{
//entry point for dll
static UnmanagedExports()
{
//nothing
}
[DllExport("HelloWorld", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)]
public static string HelloWorld()
{
return "Hello World";
}
[DllExport("MyDLLFunction", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.IDispatch)]
static object MyDLLFunction()
{
return new InnerNamespace.MyCsharpClass();
}
}
}
Then here is my other C#:
namespace MyNamespace.InnerNamespace
{
[ComVisible(true), ClassInterface(ClassInterfaceType.AutoDual)]
public class MyCsharpClass
{
[return: MarshalAs(UnmanagedType.BStr)]
public async Task<string> InnerFunction(string LookupType, string LookupNumber)
{
object Response = await GetResponseAsync(LookupType, LookupNumber);
string ResultAsString = Response.ToString();
return ResultAsString;
}
}
In Excel VBA:
Private Declare PtrSafe Function AddDllDirectory Lib "kernel32" (ByVal lpLibFileName As String) As Integer
Public Declare PtrSafe Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As LongPtr
Public Declare PtrSafe Function MyDLLFunction Lib "C:\my\long\path\to\my\project\bin\x64\Debug\net472\myDllName.dll" () As Object
Sub Test()
Dim mObj As Object
Set mscObj = MyDLLFunction() //run time error here <- can't find entry point
End Sub
I followed this example but it's not working.
I've googled and tested out various configurations and have been unable to get past the error 'can't find entry point'.
I believe it's fixed. I'm finally able to see exported functions in the dumpbin /exports output. There were several things that I believe needed to be done to correct the problem. Hope this helps someone in the future.
Packaged is Not Updated - Try Older Version of VS
Based on the age of the package I suspected it wasn't cooperating in VS2022 so, I:
Created the project in Visual Studio 2015 (vs VS2022 which I was using)
Rebuilt project from scratch and added references to new project rather than trying to open old project in VS2015
DllExportAppDomainIsolatedTask Error
Then, the project wouldn't build, it kept throwing the error:
The "DllExportAppDomainIsolatedTask" task failed unexpectedly.
Based on this answer I:
Installed Microsoft Build Tools for VS2015
Installed .NET 3.5 and manually added Microsoft.Build.Tasks.v3.5 as a reference to my project by browsing to its location after the .NET3.5 install
But I kept receiving the same error. I then increased the debug output by changing the setting: Project>Properties>Build>Errors and Warnings>Warning Level to 4.
Digging through the debug log I found several lines from the UnmanagedExports package which referenced the project platform, framework path, library tools path, tools dll path, etc. In that section I found:
System.ArgumentException: Requested value 'Version47' was not found.
I was targeting .NET Framework 4.7.2 so I downgraded the project to target .NET Framework 4.5, deleted the bin/obj folder contents and rebuilt the project. Then, running dumpbin /exports showed my HelloWorld function!
It doesn't appear the package is compatible with .NET Framework 4.7.2.

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.

SQLite sqlite3_column_origin_name function

I've downloaded the file sqlite.dll precompiled for 64-bit Windows (.NET Framework 4.0) for my app written in C#.
(I follow this thread: SQLite3.dll for Windows 7 64 bit)
With my old 32-bit dll the function sqlite3_column_origin_name works correctly, but with latest version for 64-bit, this function give me an error:
[DllImport("sqlite3.dll", EntryPoint = "sqlite3_column_origin_name")]
static extern string sqlite3_column_origin_name(IntPtr stmHandle, int iCol);
I use DLL Export Viewer to read exported functions into this dll and this function happears.
Can anyone help me?
EDIT: Screenshot of "error" attached
Finally, I've found solution.
I've downloaded package from sqlite.org and I've used unmanaged code in combo with precompiled binaries.

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.

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