C++ dll on C# OpenCV - c#

I am creating a dll using C++ with OpenCV. This dll is going to be used on C#.
My c++ (dll) code has three functions:
extern "C"
{
bool x(Mat image, Mat gray, Point center)
{...}
}
extern "C"
{
bool y(Mat image. Mat gray, Point center)
{...}
}
extern "C"
{
__declspec(dllexport)
int main (const char *cam1 ,int blur)
{...}
}
main function receives a string and an int from the C# code.
In C# I have:
[DllImport("mydll.dll")]
public static extern int main(string path, int blur);
How should I declare the other functions on C# knowing they have arguments with types like Mat and Point?

I did as Owuor suggested and it works.
My C++ bool functions are now
extern "C"
{
bool x(Mat *image, Mat *gray, Point *center)
{...}
}
extern "C"
{
bool y(Mat *image, Mat *gray, Point *center)
{...}
}
on C# I have
[DllImport("mydll.dll")]
public static extern int main(string path, int blur);
[DllImport("mydll.dll")]
public static extern bool (IntPtr ptr1, IntPtr ptr1, IntPtr ptr1);

Related

unity3d EntryPointNotFoundException yet entryPoint exists

I have a C/C++ unmanaged DLL that is working with the exception of a single method which causes an EntryPointNotFoundException
i'm setting up the DLL in c#
private const string dllname = "mydllname";
[DllImport(dllname)]
private static extern IntPtr CreateBridge();
[DllImport(dllname)]
private static extern void DestroyBridge(IntPtr context);
[DllImport(dllname)]
private static extern int getChannels(IntPtr context);
[DllImport(dllname)]
private static extern void setUpdate(IntPtr context, IntPtr values);
and then calling the method
IntPtr updatePtr = Marshal.AllocHGlobal(Marshal.SizeOf(update));
Marshal.StructureToPtr(update, updatePtr, true);
setUpdate(context, updatePtr);
Before I'm calling setUpdate(context, updatePtr) I'm sucessfully calling CreateBridge() and getChannels(IntPtr context) so we know the DLL is present, that it is loaded and that other entryPoints can be called
But setUpdate(context, updatePtr) causes the exception EntryPointNotFoundException
the C definition is as follows
#define DLL_EXPORT __declspec(dllexport)
...
extern "C" {
DLL_EXPORT UnityBridge* CreateBridge();
DLL_EXPORT void DestroyBridge(const UnityBridge* _unitybridge);
DLL_EXPORT int getChannels(UnityBridge* _unitybridge);
DLL_EXPORT void setUpdate(UnityBridge* _unitybridge, Update* update);
}
What else can cause this exception?
EDIT #1
I checked with Dependency it is not being exported... this makes the question different, but any clues?

Calling C++ DLL from C++ and C#

I have a C++ application that I have to convert to a DLL. I have all the source.
my function is
extern "C"
__declspec(dllexport) int mymain(int i, std::wstring myArgs)
I need to be able to pass in the arguments from a c++ or c# wrapper. I am able to call this from a c++ console application without error. I am now trying to call it from C#.
This is my c# code:
public static class DllHelper
{
[DllImport("rep.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int mymain(int iArgs, string aArgs);
}
class Program
{
static void Main(string[] args)
{
string s = "my string data";
DllHelper.mymain(0, s);
}
}
}
When I run it I get
System.Runtime.InteropServices.SEHException: 'External component has thrown an exception.'
I am out of ideas.
TIA
Specify Unicode but also, in your C or C++ function, use printf with "%S" (upper-case 'S' means wide-character string).. OR std::wcout.
Without that, it might print weird or terminate at the first null char it finds. Also, you might want to actually pass the length of the string, but that's entirely up to you.
Note the signature of the C++ function uses LPCWSTR (const wchar_t*) for the myArgs parameter..
public static class DllHelper
{
[DllImport("rep.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
public static extern int mymain(int iArgs, string aArgs);
}
class Program
{
static void Main(string[] args)
{
string s = "my string data";
DllHelper.mymain(0, s);
}
}
#ifdef __cplusplus
extern "C" {
#endif
int __declspec(dllexport) mymain(int i, const wchar_t* myArgs)
{
#ifdef __cplusplus
std::wcout<<std::wstring(myArgs)<<L"\n";
#else
printf(L"%S\n", myArgs);
#endif
}
#ifdef __cplusplus
}
#endif
Based on yr last comment u might need to:
[DllImport("rep.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
anyway since I dont have rep.dll it's hard to guess
The naming used in your code:
mymain(int iArgs, string aArgs);
makes me think that what you are trying to do is probably passing an array of strings (similar to wmain(int argc, wchar_t** argv)).
If this is what you want, then on the native DLL side your function prototype would look like this:
extern "C" int __declspec(dllexport) mymain(int iArgs, wchar_t** aArgs)
And on the C# side, you would write a PInvoke declaration like this:
[DllImport("rep.dll",
CallingConvention=CallingConvention.Cdecl,
CharSet=CharSet.Unicode)]
public static extern int mymain(int iArgs, [In] string[] aArgs);
that you can invoke in C# like this:
string[] test = { "C64", "Bravo", "Charlie" };
int returnCode = mymain(test.Length, test);

c#, passing any array to C++ dll with a single function

For now I'm using below definition in the C# side
[DllImport("CL", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr bufferWrite(IntPtr handle,float[] obj);
to send a float array to C space in a c++ dll as in below definition
__declspec(dllexport)
void bufferWrite(OpenClBuffer * handle, void * ptr)
{
...
}
and it works(or seems like working). Now I need to support double, long and byte arrays too. Also I dont want to rewrite additional functions in c++ dll because it is already using a void pointer and size of buffer is handled by some other parameters inside.
Is it legal to use "ref object obj" instead of "float[] obj" or "long [] obj" in the C# space for all platforms(32 bit, 64 bit, xp,7,8.1,10) as in below
[DllImport("CL", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr bufferWrite(IntPtr handle,ref object obj);
or do I need to add extra functions to c++ such as
[DllImport("CL", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr bufferWriteFloat(...);
[DllImport("CL", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr bufferWriteInt(...);
[DllImport("CL", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr bufferWriteLong(...);
and make them call same old function with a casting to (void *)? Maybe just overloading the function in C# is enough and workds 100% of time?
[DllImport("CL", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr bufferWrit(..., float[] obj);
[DllImport("CL", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr bufferWrite(..., long[] obj);
[DllImport("CL", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr bufferWrite(..., double[] obj);
I'm assuming a void pointer is always same size as an array pointer when C#-C++ interop is used.

PInvoke with a void * versus a struct with an IntPtr

Imagine I have a function called
Myfunction(const void * x);
My C# declaration could be
MyFunction(IntPtr x);
Is this functionally and technically equivalent to
struct MyStruct { IntPtr P; }
MyFunction(MyStruct x);
Or will there be a difference in how they are marshalled.
I'm asking this because the library I'm calling is all void *, typedef'd to other names, and in C# I'd like to get type safety, for what it's worth.
If your StructLayout is Sequential, then it is indeed identical.
Easiest way to verify this for yourself is to try it out, of course:
Make a C++ Win32 DLL project:
extern "C"
{
__declspec(dllexport) void MyFunction(const void* ptr)
{
// put a breakpoint and inspect
}
}
Make a C# project:
public struct Foo
{
public IntPtr x;
}
[DllImport(#"Win32Project1.dll", EntryPoint = "MyFunction", CallingConvention = CallingConvention.Cdecl)]
public static extern void MyFunctionWithIntPtr(IntPtr x);
[DllImport(#"Win32Project1.dll", EntryPoint = "MyFunction", CallingConvention = CallingConvention.Cdecl)]
public static extern void MyFunctionWithStruct(Foo x);
static void Main(string[] args)
{
IntPtr j = new IntPtr(10);
var s = new Foo();
s.x = new IntPtr(10);
MyFunctionWithIntPtr(j);
MyFunctionWithStruct(s);
}
In your debug settings, make sure you select Native debugging is enabled.
You'll see both values to be 0xA.
Note, however, if you use out/ref parameters for your IntPtr vs Struct, they will be different values.

C# Error Finding Method in DLLImport

I have a C++ assembly that I am importing using DLLImport.
I am attempting to call its method:
namespace Testing
{
class Test{
int Run(char* filePath, bool bEntry, double duration){//code}
};
}
by
[DllImport(dllName, CharSet = CharSet.Auto)]
public static extern int Run(string filePath, bool bEntry, double duration)
);
When I call its method, I get the error message:
Unable to find an entry point named Run in dll
The "Run" looks to be a non-static class method. Although, it's possible to call such methods from C# this is not the primary use-case. It would be way easier to consume it from .NET if you expose it via COM, or at-least as a plain C interface:
extern "C" __declspec(dllexport) void* Testing_Test_Create();
extern "C" __declspec(dllexport) void Testing_Test_Destroy(void* self);
extern "C" __declspec(dllexport) int Testing_Test_Run(void* self, char* filePath, bool bEntry, double duration);
And here is a sample how to call C++ class methods from C#:
// Test.cpp in NativeLib.dll
namespace Testing
{
class __declspec(dllexport) Test
{
public:
explicit Test(int data)
: data(data)
{
}
int Run(char const * path)
{
return this->data + strlen(path);
}
private:
int data;
};
}
// Program.cs in CSharpClient.exe
class Program
{
[DllImport(
"NativeLib.dll",
EntryPoint = "??0Test#Testing##QAE#H#Z",
CallingConvention = CallingConvention.ThisCall,
CharSet = CharSet.Ansi)]
public static extern void TestingTestCtor(IntPtr self, int data);
[DllImport(
"NativeLib.dll",
EntryPoint = "?Run#Test#Testing##QAEHPBD#Z",
CallingConvention = CallingConvention.ThisCall,
CharSet = CharSet.Ansi)]
public static extern int TestingTestRun(IntPtr self, string path);
static void Main(string[] args)
{
var test = Marshal.AllocCoTaskMem(4);
TestingTestCtor(test, 10);
var result = TestingTestRun(test, "path");
Console.WriteLine(result);
Marshal.FreeCoTaskMem(test);
}
}
Entry point names might be different for your build configuration/compiler, so use dumpbin utility to obtain them. Again, this is just a proof of concept, in real code it would be better to use COM.
See here: http://dotnetperls.com/dllimport
I'm not sure this will help if the function is a member of a class, but to locate the entry point by name, not ordinal, you'll need a .def file in your dll..
LIBRARY mylib
Run #1

Categories