C++ DLL creation for C# project - No functions exported - c#

I am working on a project that requires some image processing. The front end of the program is C# (cause the guys thought it is a lot simpler to make the UI in it). However, as the image processing part needs a lot of CPU juice I am making this part in C++.
The idea is to link it to the C# project and just call a function from a DLL to make the image processing part and allow to the C# environment to process the data afterwards. Now the only problem is that it seems I am not able to make the DLL. Simply put the compiler refuses to put any function into the DLL that I compile.
Because the project requires some development time testing I have created two projects into a C++ solution. One is for the Dll and another console application. The console project holds all the files and I just include the corresponding header into my DLL project file. I thought the compiler should take out the functions that I marked as to be exported and make the DLL from them. Nevertheless this does not happens.
Here it is how I defined the function in the header:
extern "C" __declspec(dllexport) void _stdcall RobotData(BYTE* buf, int** pToNewBackgroundImage, int* pToBackgroundImage, bool InitFlag, ObjectInformation* robot1, ObjectInformation* robot2, ObjectInformation* robot3, ObjectInformation* robot4, ObjectInformation* puck);
extern "C" __declspec(dllexport) CvPoint _stdcall RefPointFinder(IplImage* imgInput, CvRect &imgROI,
CvScalar &refHSVColorLow, CvScalar &refHSVColorHi );
Followed by the implementation in the cpp file:
extern "C" __declspec(dllexport) CvPoint _stdcall RefPointFinder(IplImage* imgInput, CvRect &imgROI,&refHSVColorLow, CvScalar &refHSVColorHi ) { \\...
return cvPoint((int)( M10/M00) + imgROI.x, (int)( M01/M00 ) + imgROI.y) ;}
extern "C" __declspec(dllexport) void _stdcall RobotData(BYTE* buf, int** pToNewBackgroundImage, int* pToBackgroundImage, bool InitFlag, ObjectInformation* robot1, ObjectInformation* robot2, ObjectInformation* robot3, ObjectInformation* robot4, ObjectInformation* puck) { \\ ...};
And my main file for the DLL project looks like:
#ifdef _MANAGED
#pragma managed(push, off)
#endif
/// <summary> Include files. </summary>
#include "..\ImageProcessingDebug\ImageProcessingTest.h"
#include "..\ImageProcessingDebug\ImageProcessing.h"
BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
return TRUE;
}
#ifdef _MANAGED
#pragma managed(pop)
#endif
Needless to say it does not work. A quick look with DLL export viewer 1.36 reveals that no function is inside the library. I don't get it. What I am doing wrong ?
As side not I am using the C++ objects (and here it is the C++ DLL part) such as the vector. However, only for internal usage. These will not appear in the headers of either function as you can observe from the previous code snippets.
Any ideas? Thx,
Bernat

It seems you are confused about which files to include in your DLL project vs your console project. If it is true that "The console project holds all the files" then this is your problem.
Your DLL project needs to include the cpp file which has the __declspec(dllexport)s. As you describe it, you have included your RefPointFinder() & RobotData() functions in the console project. In other words your DLL has no functions in it whatsoever, regardless of whether anything is exported.
Just including the .h files in the DLL main file does nothing by itself. It doesn't include these functions in the DLL.

Related

The nightmare of importing C# DLL to MQL5

Hy everyone i have a bit of a problem, I program mostly in python, and it's been a while actually since i coded in C# and i code in mql every now and again. My problem is i built a C# dll file that has a couple of simple functions:
[DllExport("debugger", CallingConvention = CallingConvention.StdCall)]
[return: MarshalAs(UnmanagedType.LPWStr)]
public static string debugger()
{
return "Send help!! SOS";
}
[DllExport("debugger2", CallingConvention = CallingConvention.StdCall)]
public static int debugger2()
{
return 12345;
}
This is my simple code from my C# file, it's all inside a public static class and the Solution platform is x64. Code compiles just fine and i find no issues. Now this is how my MetaEditor code looks:
#import "simpleFunctions.dll"
string debugger();
int debugger2();
#import
int OnInit()
{
//Print a statement just to show where code crashes
Print("We are definitly in it :D");
Print(debugger);
}
From what the Journal tells me everything runs just fine, the file is added from libraries and the print statement at the beginning of the OnInit function runs as well. The problem is come when calling the first debugger function from my dll file, just below my Print statement in the journal i get the following errors:
- Cannot find 'debugger', in 'simpleFunctions.dll'
- unresolved import function call
- OnInit critical error
- tester stopped because OnInit failed
I have searched all over the internet to my dissatisfaction of finding that no one really answers this question in a practical way. I suspect the error lies maybe in the C# side of things with regard to data type differences but i really don't know where to continue looking at this point. Any help would be greatly appreciated.
Well after searching probably every website for an answer relating to my question, switching back to python and trying a different way to connect to mql5 (using sockets), than finally trying C++ and spending the last two days learning that, I think I finally solved my problem. Only posting this to help anyone who might have a similar problem in the future. I figured that since MQL5 is more like C++ than C# the linking process would be a bit easier. The code it's self was not complex at all because I was just trying to get functions running in MQL5 from C++.
#include "pch.h"
#include "CPPMQLSQLConnector.h"
#define CPPMQLSQLCONNECTOR_API
#include <string>
std::string __stdcall myString(std::string Words)
{
static std::string myWords = "This is about to work I can feel it. ";
return myWords + Words;
}
int __stdcall myInt(int numbr)
{
static int myNumber = 1998;
numbr = 22;
return myNumber + numbr;
}
Note the __stdcall before method pointer, calling convention is required to let MQL5 know how to get the functions from the library.
In my C++ header file I let C++ know which functions I want to export using the '__declspec(dllexport)' and the '__declspec(dllimport)', my opinion on this issue is worth as much as you paid for it but my understanding is that the export keyword let's C++ know which functions I would like to export and the import keyword is used by MQL5 or which ever application, to know which functions to import. My header file
#pragma once
#include <string>
#ifndef MYDLL
#define MYDLL
#ifdef CPPMQLSQLCONNECTOR_API
extern "C" __declspec(dllexport) std::string __stdcall myString(std::string Words);
extern "C" __declspec(dllexport) int __stdcall myInt(int numbr);
#else
extern "C" __declspec(dllimport) std::string __stdcall myString(std::string Words);
extern "C" __declspec(dllimport) int __stdcall myInt(int numbr);
#endif
#endif
We use the extern "C" keyword to let the compiler know it should expect 'C' code.
Finally the MQL5 code, it's very simple. We just import the dll and and start using the functions for what ever purpose they were made
#import "CPPMQLSQLConnector.dll"
string myString(string s);
int myInt(int i);
#import
int OnInit()
{
string Word = "Momma I made it!!!!!!!!!!!!";
int numbr = 25;
Print("We definitely init ;D");
Print("La string: ", myString(Word));
Print("La integer: ", myInt(numbr));
return(INIT_SUCCEEDED);
}

Sharing function between c and c# [duplicate]

I have a C lib and want to call function in this library from C# application. I tried creating a C++/CLI wrapper on the C lib by adding the C lib file as linker input and adding the source files as additional dependencies.
Is there any better way to achieve this as am not sure how to add C output to c# application.
My C Code -
__declspec(dllexport) unsigned long ConnectSession(unsigned long handle,
unsigned char * publicKey,
unsigned char publicKeyLen);
My CPP Wrapper -
long MyClass::ConnectSessionWrapper(unsigned long handle,
unsigned char * publicKey,
unsigned char publicKeyLen)
{
return ConnectSession(handle, publicKey, publicKeyLen);
}
The example will be, for Linux:
1) Create a C file, libtest.c with this content:
#include <stdio.h>
void print(const char *message)
{
printf("%s\\n", message);
}
That’s a simple pseudo-wrapper for printf. But represents any C function in the library you want to call. If you have a C++ function don’t forget to put extern C to avoid mangling the name.
2) create the C# file
using System;
using System.Runtime.InteropServices;
public class Tester
{
[DllImport("libtest.so", EntryPoint="print")]
static extern void print(string message);
public static void Main(string[] args)
{
print("Hello World C# => C++");
}
}
3) Unless you have the library libtest.so in a standard library path like “/usr/lib”, you are likely to see a System.DllNotFoundException, to fix this you can move your libtest.so to /usr/lib, or better yet, just add your CWD to the library path: export LD_LIBRARY_PATH=pwd
credits from here
EDIT
For Windows, it's not much different.
Taking an example from here, you only have yo enclose in your *.cpp file your method with extern "C"
Something like
extern "C"
{
//Note: must use __declspec(dllexport) to make (export) methods as 'public'
__declspec(dllexport) void DoSomethingInC(unsigned short int ExampleParam, unsigned char AnotherExampleParam)
{
printf("You called method DoSomethingInC(), You passed in %d and %c\n\r", ExampleParam, AnotherExampleParam);
}
}//End 'extern "C"' to prevent name mangling
then, compile, and in your C# file do
[DllImport("C_DLL_with_Csharp.dll", EntryPoint="DoSomethingInC")]
public static extern void DoSomethingInC(ushort ExampleParam, char AnotherExampleParam);
and then just use it:
using System;
using System.Runtime.InteropServices;
public class Tester
{
[DllImport("C_DLL_with_Csharp.dll", EntryPoint="DoSomethingInC")]
public static extern void DoSomethingInC(ushort ExampleParam, char AnotherExampleParam);
public static void Main(string[] args)
{
ushort var1 = 2;
char var2 = '';
DoSomethingInC(var1, var2);
}
}
UPDATE - Feb 22 2019: Since this answer has been getting quite a few upvotes, I decided to update it with a better way of calling the C method. Previously I had suggested using unsafe code, but the safe and correct way is to use MarshalAs attribute for converting a .NET string to a char*. Also, in VS2017 there is no Win32 project anymore, you'll probably have to create a Visual C++ dll or empty project and modify that. Thank you!
You can directly call C functions from C# by using P/Invoke.
Here's a short how-to on creating a C# lbrary that wraps around a C dll.
Create a new C# Library project (I'll call it "Wrapper")
Add a Win32 project to the solution, set application type to: DLL (I'll call it "CLibrary")
You can remove all the other cpp/h files since we won't need them
Rename the CLibrary.cpp file to CLibrary.c
Add a CLibrary.h header file
Now we need to configure the CLibrary project, right-click it and go to properties, and select Configuration: "All Configurations"
In Configuration Properties > C/C++ > Precompiled headers, set Precompiled Headers to: "Not using Precompiled Headers"
In the same C/C++ branch, go to Advanced, change Compile As to: "Compile as C code (/TC)"
Now in the Linker branch, go to General, and change Output File to: "$(SolutionDir)Wrapper\$(ProjectName).dll", this will copy the built C DLL to the C# project root.
CLibrary.h
__declspec(dllexport) unsigned long ConnectSession(unsigned long handle,
unsigned char * publicKey,
unsigned char publicKeyLen);
CLibrary.c
#include "CLibrary.h"
unsigned long ConnectSession(unsigned long handle,
unsigned char * publicKey,
unsigned char publicKeyLen)
{
return 42;
}
Right-click CLibrary project, build it, so we get the DLL in the C# project directory
Right-click C# Wrapper project, add existing item, add CLibrary.dll
Click on CLibrary.dll, go to the properties pane, set "Copy to output Directory" to "Copy Always"
It's a good idea to make the Wrapper project dependent on CLibrary so CLibrary gets built first, you can do that by right-clicking the Wrapper project, going to "Project Dependencies" and checking "CLibrary".
Now for the actual wrapper code:
ConnectSessionWrapper.cs
using System.Runtime.InteropServices;
namespace Wrapper
{
public class ConnectSessionWrapper
{
[DllImport("CLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
static extern uint ConnectSession(uint handle,
[MarshalAs(UnmanagedType.LPStr)] string publicKey,
char publicKeyLen);
public uint GetConnectSession(uint handle,
string publicKey,
char publicKeyLen)
{
return ConnectSession(handle, publicKey, publicKeyLen);
}
}
}
Now just call GetConnectSession, and it should return 42.
Result:
Okay well, Open VS 2010, Goto File -> New -> Project -> Visual C++ -> Win32 -> Win32 Project and give it a name (HelloWorldDll in my case), Then in the window that follows under Application Type choose 'DLL' and under Additonal Options choose 'Empty Project'.
Now goto your Solution Explorer tab usually right hand side of VS window, right click Source Files -> Add Item -> C++ file (.cpp) and give it a name (HelloWorld in my case)
Then in the new class paste this code:
#include <stdio.h>
extern "C"
{
__declspec(dllexport) void DisplayHelloFromDLL()
{
printf ("Hello from DLL !\n");
}
}
Now Build the project, after navigate to your projects DEBUG folder and there you should find: HelloWorldDll.dll.
Now, lets create our C# app which will access the dll, Goto File -> New -> Project -> Visual C# -> Console Application and give it a name (CallDllCSharp), now copy and paste this code to your main:
using System;
using System.Runtime.InteropServices;
...
static void Main(string[] args)
{
Console.WriteLine("This is C# program");
DisplayHelloFromDLL();
Console.ReadKey();
}
and build the program, now that we have both our apps built lets use them, get your *.dll and your .exe (bin/debug/.exe) in the same directory, and execute the application output should be
This is C# program
Hello from DLL !
Hope that clears some of your issues up.
References:
How to create a DLL library in C and then use it with C#
NOTE : BELOW CODE IS FOR MULTIPLE METHODS FROM DLL.
[DllImport("MyLibc.so")] public static extern bool MyLib_GetName();
[DllImport("MyLibc.so")] public static extern bool MyLib_SetName(string name);
[DllImport("MyLibc.so")] public static extern bool MyLib_DisplayName(string name);
public static void Main(string[] args)
{
string name = MyLib_GetName();
MyLib_SetName(name);
MyLib_DisplayName(name);
}
The P/Invoke method has been described extensively and repeatedly, ok so far.
What I'm missing here is, that the C++/CLI method has a big advantage: Calling safety.
In contrast to P/Invoke, where the call of the C funtion is like shooting blind into the sky (if this comparison is allowed), nobody will check the function arguments when calling the C function.
Using C++/CLI in this case means normally, you include a headerfile with the functions prototypes you want to use. If you are calling the C function with wrong/to much /to few arguments, the compiler will tell you.
I don't think you can say in general which is the better method, honestly I don't like either of them.

Porting DLL import from c# to c++

This is how I use/import the DLL using c#. How do I do it on c++ project?
[DllImport(#".\x64\something.dll", EntryPoint = "somthng", CharSet = CharSet.Unicode)]
static extern int somthng(string input);
Provided that you do not have the development header and lib files available for the DLL and you need to dynamically load the DLL into your C++ project, then you can do the following.
Define a function pointer (equivalent to your extern declaration):
typedef int FnSomeFunction(const char* input);
Load the library (I'm using LoadLibraryA here to load an ansi-named DLL, this depends on your C++ project). The DLL must be in the search path, i.e. in the same path as the executable):
HMODULE hModule = LoadLibraryA("something.dll");
Check that the module is successfully loaded:
if (hModule == nullptr)
throw std::runtime_error("Lib not loaded");
Get the function entry point from the library:
FnSomething* fnSomething = (FnSomeFunction*)GetProcAddress(hModule, "somthng");
Call the function:
(*fnSomething)("some text");
Free the library when no longer needed:
FreeLibrary(hModule);

Dll become unable to load when calling function from another dll

Now I have a Unity (C#) project, which calls my C++ project from a dll. They both worked fine, so as calling C++ functions from Unity.
However, when I try add one line to call a function another library (NLOpt library, from another dll) in the C++ project, the generated dll becomes unable to be loaded in the Unity project.
Plugin.h
extern "C" __declspec(dllexport) bool __stdcall LoadData(int agent_num, int frame_num, float* data);
Plugin.cpp
#include "Plugin.h"
#include <nlopt.h>
__declspec(dllexport) bool __stdcall LoadData(int agent_num, int frame_num, float* d)
{
...
nlopt_opt opt = nlopt_create(NLOPT_LN_COBYLA, 3); //this line
}
As I add the line above, Unity will the following error:
Plugins: Failed to load 'Assets/Plugins/BirdOpti/BirdOpti.dll'
and
DllNotFoundException: Opti
I have tried couple of times so I am sure the problem is the line.
Did I do anything wrong?
Adding also the used dll file to the plugin directory solves the problem.

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.

Categories

Resources