Calling Unmanaged C++ from C# - c#

I'm running VS2012 on Win7 with .NET 4.0.
I've tried the following:
Create C++ DLL project
Checked\Unchecked the export symbols box
I've made sure my platform targets are the same. In my case, win32
I've added the necessary extern "C" and __declspec(dllexport) where needed.
I've successfully compiled my DLL and have tried to reference it in a C# project.
Unfortunately, I get an error telling my it can't be added and that I need to make sure it's a valid assembly or COM object.
I've given up trying to get my code to export, so I'd be happy with just the example "42" getting through!
I've tried looking at it with dumpbin and it is correctly exporting symbols:
1 0 00011023 ??0CEvolutionSimulator##QAE#XZ
2 1 00011127 ??4CEvolutionSimulator##QAEAAV0#ABV0##Z
3 2 00011005 ?GetNumber#CEvolutionSimulator##QAEHXZ
4 3 0001104B ?fnEvolutionSimulator##YAHXZ
5 4 00017128 ?nEvolutionSimulator##3HA
My brain is fresh out of ideas. Can someone please enlighten me? I seem to get this error no matter what I try.

You need to pinvoke the functions residing in your C++ DLL (exported using extern "C") from your .NET code using the DllImportAttribute. You can't reference your C++ DLL like a .NET assembly, and you can't use classes from the DLL, only DllImported C-like functions.
Example from msdn:
using System;
using System.Runtime.InteropServices;
class Example
{
// Use DllImport to import the Win32 MessageBox function.
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
public static extern int MessageBox(IntPtr hWnd, String text, String caption, uint type);
static void Main()
{
// Call the MessageBox function using platform invoke.
MessageBox(new IntPtr(0), "Hello World!", "Hello Dialog", 0);
}
}

Related

DllImport for Dotnet core returning DLLNotFoundException for present DLL

Over the past few days I have been trying to interface with a C library (built for an ARM platform) on linux, in dotnet core. All I am trying to do is call a simple function which (essentially) returns a string.
However, I have no experience of using DLLImport or interop on the whole in C# and I am struggling.
The C code looks like (with substitute names as I am using a work platform):
int version(int argc, char *argv[])
{
return READ_DATA(0,
version, //callbackfunction
"version: 0x%04x\n"); //formatting string
}
public class Board
{
private Interop_Commands _commands = new Interop_Commands();
public string GetVersion()
{
return _commands.GetVersion();
}
}
internal class Interop_Commands
{
public const string LIBRARYPATH = "libname";
[DllImport(LIBRARYPATH,CharSet=CharSet.Unicode, CallingConvention =CallingConvention.Cdecl)]
public static extern int version(int argc, StringBuilder argv);
public string GetVersion()
{
var sb = new StringBuilder();
Console.WriteLine($"Calling {nameof(version)}");
version(0, sb);
Console.WriteLine($"Called {nameof(version)}, got: {sb.ToString()}");
return sb.ToString();
}
}
with the calling class (main for this very simple proof of concept/trial code):
static void Main(string[] args)
{
Console.WriteLine("Getting Version from board..");
var board = new Board();
Console.WriteLine(board.GetVersion());
Console.WriteLine("done");
Console.ReadLine();
}
The folder structure is (simplified):
folder
|--> Dll/runtime
|--> libname (note no .so here, just libname)
Any help would be appreciated, I am finding examples of C imports/usages limited, and also finding examples limited for how to use custom libraries in dotnet core.
EDIT 1:
Following help from #Sohaib Jundi, I have added the extern so the signature is now: (it wouldnt compile with extern "C")
extern int version(int argc, char *argv[])
I am unsure what to try next.
but dotnet core wont publish with x86 and target runtime set to linux-arm, just throws an unknown exception, with the log file not being very helpful..
If i use the compiled library with the previous code (AnyCPU + linux-arm), then the DllNotFoundException is still thrown
* EDIT 2: *
As it turns out, the original no extension file i was using appears to be an executable referencing a static library (which ends up compiled into the executable). rebuilding I have managed to get the static library separate, but still get the same DllNotFoundException. Does anyone know what the search procedure is for the DllImport on dotnet core?
The interop/import code now looks like:
[DllImport("libname",
CallingConvention =CallingConvention.Cdecl,
EntryPoint= "version")]
public static extern int version(ref uint val);
where the static lib code looks like:
extern int version(uint32_t *);
After some playing around, I managed to get an example to work.
Follow these steps:
1. export your function from the dll, i.e: add extern "C" __declspec(dllexport) to the function signature
2. Make sure that both the dll and your dotnet core application have the same architecture. don't keep the dotnet core as "Any CPU", force it to the same architecture as the dll. (project properties -> build -> platform target = x86 or x64)
I have found the solution.. the library was being compiled as a .la (statically linked library) rather than a .so (shared object) library. The DllImport doesnt work with statically linked libraries so.. a recompilation of the library into a shared object library has meant it will now find the dll (I also exported LD_LIBRARY_PATH as pwd to make sure it was in the search path..).
Once this was in, the rest of the code fell into place. The matching dll import declaration for the version above was correct (from *EDIT 2 *) - using ref uint. So now I have to extend the methods supported in my interop class to fully support the library.
Thanks for your help #Sohaib Jundi

How do I use a DLL function in C# without adding the DLL as reference?

I'm trying to use functions from a DLL that can't be added as Reference through Visual Studio (a message saying "reference cannot be added" appears). However, I've gotten instructions from the creator of the DLL and they suggested I use them like this in VB.Net:
Private Declare Function Prn_Init Lib "VAx_VPOS396_APPAPI.dll" () As Integer
That works, but now I want to write a program in C#. How do I "translate" that declaration to C#?
Additional: In C++ the declaration comes in a *.h file with these lines:
#ifndef _VPOS396DLL_API_H
#define _VPOS396DLL_API_H
VPOS396_DLL_API int Prn_Init(void);
You should create the method(s) you want to use in C#, make them extern and add a [DllImport] attribute. For example:
[DllImport("kernel32.dll")]
static extern bool Beep(uint dwFreq, uint dwDuration);
See https://msdn.microsoft.com/en-us/library/aa984739%28v=vs.71%29.aspx
[System.Runtime.InteropServices.DllImport("VAx_VPOS396_APPAPI.dll")]
public static extern unsafe Int32 Prn_Init(void);
("unsafe" is optional)

Call native method from dll

I am trying to use MimeTex.dll in Mixed Mode of C++/CLI project. I include the dll by:
#pragma comment(lib,"MimeTex.dll")
and I tried to call this method:
CreateGifFromEq("expression","path");
but the compiler inform that it doesn't know CreateGifFromEq() method.
I didn't find resources in the web in how to use MimeTex.dll in C++. I just find how to use it with C# in this link by Pinvok like:
[System.Security.SuppressUnmanagedCodeSecurity()]
internal class NativeMethods
{
private NativeMethods()
{ //all methods in this class would be static
}
[System.Runtime.InteropServices.DllImport("MimeTex.dll")]
internal static extern int CreateGifFromEq(string expr, string fileName);
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
internal extern static IntPtr GetModuleHandle(string lpModuleName);
[System.Runtime.InteropServices.DllImport("kernel32.dll")]
[return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
internal extern static bool FreeLibrary(IntPtr hLibModule);
}
and then call it like:
NativeMethods.CreateGifFromEq(equation, tempGifFilePath);
How I can call it without Pinvok in mixed mode of C++/CLI?
Surely you meant to write:
#pragma comment(lib,"MimeTex.lib")
In other words, you pass the .lib file to the linker rather than the .dll. When you compiled the DLL, a .lib file will have been generated.
But that's not your immediate problem. The compiler has no declaration for CreateGifFromEq. That's because you have not included the library's header file in your C++ code. Doing that should resolve the issue.
If all you need is that one function then it should be trivial to declare it in your C++ code.
__declspec(dllimport) extern int CreateGifFromEq(char *expr, char *fileName);
You probably will need to wrap that in an extern "C" block too.
Actually, having looked at the library, the header file that is supplied with the source does not declare that function, even though it's present in the library.
In C++/CLI you can use P/Invoke as in C#.
If you don't want to use P/Invoke, the other way is to load the DLL with LoadLibrary and get pointers to the functions with GetProcAddress.
Here's the equivalent of the C# code in C++/CLI:
using namespace System;
using namespace System::Runtime::InteropServices;
private ref class NativeMethods abstract sealed
{
internal:
[DllImport("MimeTex.dll")]
static int CreateGifFromEq(String^ expr, String^ fileName);
[DllImport("kernel32.dll")]
static IntPtr GetModuleHandle(String^ lpModuleName);
[DllImport("kernel32.dll")]
[returnvalue: MarshalAs(UnmanagedType::Bool)]
static bool FreeLibrary(IntPtr hLibModule);
};
As you can see it's almost identical to the C# code except for some minor syntax changes.
Here's how you would use LoadLibrary and GetProcAddress (which has the advantage of not requiring marshaling, which is unnecessary in C++ anyway):
HMODULE hModule = LoadLibrary(L"MimeTex.dll");
int (*fpCreateGifFromEq)(WCHAR*, WCHAR*) = GetProcAddress(hModule, "CreateGifFromEq");
(*fpCreateGifFromEq)(L"expression", L"filename");
You don't need to do that for GetModuleHandle and FreeLibrary, because they're from kernel32.dll so you can just include Windows.h and call them normally.
There's a cleaner way of doing things:
Create a C++/CLI project. It will be your interface between C# and C++ (this is what C++/CLI is aimed at).
Make your C# project have a reference to this new assembly.
Inside your new C++/CLI project, configure project options so as you point to the directory with mimetex .h files for the compiler to compile your project, and the directory with .lib/.dll for the linker.
Inside your C++/CLI part, you just write C++ inside the functions. They are exposed to your C# assembly, but in the inside it's just calls to C++ functions as usual.
(You should check a C++CLI tutorial to know what to do with strings to convert them to native char or std::string. I remember I had to look at that.)*
In your C# part, you just call the C++CLI project assembly exposed functions like normal C# functions, without noticing it's native code called behind.

How to properly create an entry point on an external .dll resource written in C++ consumed in C#

Long time reader, first time poster. One day I hope to be answering questions on here...
So it's kind of similar to: "Unable to find an entry point named [function] in dll" (c++ to c# type conversion)
But I can't seem to apply the same solution...
Basically, I wrote a new Method:
Defined in the header file of the C++ project as :
extern "C" {
__declspec(dllexport) bool IsDataValid();
}
Defined in the source file of the C++ project as: (signiature only)
extern bool __cdecl IsDataValid() {
//function stuf......... returns a bool
}
Imported into a forms C# application within the C# Project as:
[DllImport("CarChipSDK_C_Sharp.dll", EntryPoint = "IsDataValid")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsDataValid();
It is called from the same place within C# forms .cs file as:
bool isDataValid = IsDataValid();
It is returning an exception with the message:
"Unable to find an entry point
'IsDataValid()' named in DLL
'CarChipSDK_C_Sharp.dll'.
I have used dumpbin.exe and dependency walker on the .dll generated from the c++ code and it shows that it has the IsDataValid() entry point.
All help is much appreciated...
Problem Solved! Stupid me, this was the code from a previous co-op at my current company, turns out he was reading the .dll from the bin/release folder where as I was building to the bin/debug folder. Should have known. My sincere apologies.
You are encountering C++ name mangling. Declare the C++ functions as extern "C". So, in your C++ module...
extern "C" __declspec(dllexport) bool IsDataValid();
You really don't need the entry point specification attribute either. Your C# declaration will be:
[DllImport("CarChipSDK_C_Sharp.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsDataValid();
For future reference, dumpbin.exe is a very useful program for analyzing problems like this. If you run it on your DLL you will see what those functions are actually named by the time they are compiled.

"Unable to find an entry point named [function] in dll" (c++ to c# type conversion)

I have a dll which comes from a third party, which was written in C++.
Here is some information that comes from the dll documentation:
//start documentation
RECO_DATA{
wchar_t Surname[200];
wchar_t Firstname[200];
}
Description:
Data structure for receiving the function result. All function result will be
stored as Unicode (UTF-8).
Method:
bool recoCHN_P_Name(char *imgPath,RECO_DATA *o_data);
Input:
char * imgPath
the full path of the image location for this
function to recognize
RECO_DATA * o_data
data object for receiving the function
result.
Function return:
True if Success, otherwise false will return.
//end documentation
I am trying to call the recoCHN_P_Name from my C# application. To this end, I came up with this code:
The code to import the dll:
public class cnOCRsdk
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct RECO_DATA{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=200)]
public string FirstName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 200)]
public string Surname;
}
[DllImport(#"cnOCRsdk.dll", EntryPoint="recoCHN_P_Name")]
public static extern bool recoCHN_P_Name(byte[] imgPath, RECO_DATA o_data);
}
The code to call the function:
cnOCRsdk.RECO_DATA recoData = new cnOCRsdk.RECO_DATA();
string path = #"C:\WINDOWS\twain_32\twainrgb.bmp";
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
byte[] bytes = encoding.GetBytes(path);
bool res = cnOCRsdk.recoCHN_P_Name(bytes, recoData);
And the error I'm getting is
""Unable to find an entry point named 'recoCHN_P_Name' in DLL 'cnOCRsdk.dll'."
I'm suspecting that I'm having an error in converting a type from C++ to C#. But where exactly ... ?
First make sure the function is actually exported:
In the Visual Studio Command Prompt, use dumpbin /exports whatever.dll
C# doesn't support C++ name mangling and you either need to declare the C++ functions with
extern "C" {...}
(may not an option if they're from a third party), or call the mangled name directly if you can get it to work. It may be easier to get the third party to provide a non-mangled interface to the functionality.
Solved - at least to the point where the program does not break and actually returns me a bool value.
The key, I guess, was to specify the entry point as the 'mangled' name
[DllImport(#"cnOCRsdk.dll", EntryPoint="?recoCHN_P_Name#CcnOCRsdk##QAE_NPADPAURECO_DATA###Z")]
public static extern bool recoCHN_P_Name(ref string imgPath, ref RECO_DATA o_data);
After that I got some other errors but the 'unable to find entry point' went away.
I solved the same problem in these steps:
step 1) If you program your custom DLL in C++ using Visual studio,then at the property page of your project set the Common Language Runtime Support (/clr)parameter to Common Language Runtime Support (/clr).
step 2) To function deceleration in .h file use __declspec(dllexport) keyword like below:
__declspec(dllexport) double Sum(int a,int b);
step 3) Build and export DLL file, then use the Dependency Walker software to get your function EntryPoint.
step4) Import DLL file In the C# project and set EntryPoint and CallingConvention variable like below:
[DllImport("custom.dll", EntryPoint = "?Sum##YAXHHHHHHNNN#Z", CallingConvention = CallingConvention.Cdecl)]
public static extern double Sum(int a,int b);
I'd write a wrapper using C++/CLI. This wrapper will be able to include the .h files and link to the .lib files you got from the third party vendor. Then it is both easy and safe to write a managed interface for your C# program.
Correct EntryPoint string could be found in ".lib" file that comes along with main unmanaged dll.
We had this problem when we want to access to DB and solved it by changing EF core to EF 6.4.4
It may be you have a problem like this and need to change or downgrade your version of EF (If you used EF)
We had this problem .we change EntityFramework.core to EntityFrameWork 6.4.4 and after that the program worked fine. you most change you're Framework Version.
you may get this error due to string marshalling mismatch between DLL and your application . for example, one is using ANSI and the other is unicode.
you can try something like this:
[DllImport("yourDLL.dll", CharSet = CharSet.Unicode )]
public static extern String YourFunction(String name);
checkout HERE for a list of other possible reasons.
You could try using the unmangled name while specifying a CallingConvention in the DllImport

Categories

Resources