Reputation: 533
thsi is my first time asking a question here, althought i use this site a lot!!
So after I've searched a while, i found this: http://tigerang.blogspot.pt/2008/09/reverse-pinvoke.html
I think that is almost what i want to do. I will now explain: (PLZ note i'm new to c++, c#, i come from java)I have a solution on visual studio with two projects, unmanaged c++ and a C# WPF app. The c++ only has one class, that does some processing using OpenCV. The WPF class connects to an image, retrieves some (x,y) points, and i have to pass them to c++. Afterwards I will call a C++ function from the WPF side, where i will get my results.
SO my question now is, I want to pass a List of Points (List), but i'm having trouble adapting the example I'm seeing to my situation and i found very litle documentation on this (or perhaps i'm too newbie and i don't know how to find/use it).
Sample code: C#
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct Ponto
{
public double x;
public double y;
}
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate List<Ponto> CallBackDelegate();
public class ManagedClass
{
private CallBackDelegate _delegate;
public List<Ponto> vectorp;
public ManagedClass()
{
_delegate = new CallBackDelegate(this.Foo);
}
public CallBackDelegate GetDelegate()
{
return _delegate;
}
public List<Ponto> Foo()
{
//do shit
Ponto p1 = new Ponto();
p1.x = 10;
p1.y = 2;
Ponto p2 = new Ponto();
p2.x = 5;
p2.y = 7;
Ponto p3 = new Ponto();
p3.x = 3;
p3.y = 8;
vectorp.Add(p1);
vectorp.Add(p2);
vectorp.Add(p3);
return vectorp;
}
}
SAmple Code C++;
#include <iostream>
#pragma once
#include <windows.h>
#include <list>
#define INTEROPBRIDGE_API __declspec(dllexport)
INTEROPBRIDGE_API void fnInteropBridge(list<Ponto> data) //IM GETTING ERRORS HERE
{
ManagedLib::ManagedClass^ c = gcnew ManagedLib::ManagedClass();
IntPtr p = Marshal::GetFunctionPointerForDelegate(c->GetDelegate());
NativeToManaged funcPointer = (NativeToManaged) p.ToPointer();
// invoke the delegate
funcPointer(data);
}
// data structure for the callback function
struct Ponto
{
double x;
double y;
};
// callback function prototype
typedef void (*NativeToManaged)(list<Ponto> data);
using namespace std;
void main()
{
cout << "Hello World!" << endl;
cout << "Welcome to C++ Programming" << endl;
}
Upvotes: 1
Views: 2240
Reputation: 6668
Your C++ code won't work because System.Collections.Generic.List is completely different from C++'s std::list.
If your C++ code is managed (as it currently is), you can just reference the C# classes directly. No need for function pointers.
But if you really want to consume C# code from unmanaged C++, the simplest way is through COM. The only thing you need to change about your C# code is to change ManagedClass.Foo to return an array instead of a List, because List is not visible to COM, plus add a couple of attributes to the types and add an interface for the class to implement:
[ComVisible(true)]
[Guid("2EF06BCB-A25B-41AD-B233-33A956DBEB69")]
public struct Ponto
{
public double x;
public double y;
public Ponto(double x, double y)
{
this.x = x;
this.y = y;
}
}
[ComVisible(true)]
[Guid("EB9258F5-DCFB-4F91-8342-5A05EB17557D")]
public interface IManagedClass
{
Ponto[] Foo();
}
[ComVisible(true)]
[Guid("11B23AD7-F79E-45D7-BC87-89F0DBC8B83F")]
[ClassInterface(ClassInterfaceType.None)]
public class ManagedClass : IManagedClass
{
private List<Ponto> points;
public ManagedClass()
{
points = new List<Ponto>();
points.Add(new Ponto(1.0, 1.0));
points.Add(new Ponto(2.0, 2.0));
points.Add(new Ponto(3.0, 3.0));
}
public Ponto[] Foo()
{
return points.ToArray();
}
}
Build the project, start the Visual Studio Command Prompt with administrator privileges, and use a command like this to export a type library for the assembly and register it:
regasm ManagedAssembly.dll /tlb:ManagedAssembly.tlb /codebase
And the C++ code would consume it like this:
#import "ManagedAssembly.tlb"
#include <iostream>
using namespace ManagedAssembly;
using namespace std;
int main()
{
::CoInitialize(NULL);
{
IManagedClassPtr pManagedClass(__uuidof(ManagedClass));
SAFEARRAY* psa = pManagedClass->Foo();
Ponto* pPoints = (Ponto*)psa->pvData;
for (int i = 0; i < 3; ++i)
cout << pPoints[i].x << " " << pPoints[i].y << endl;
}
::CoUninitialize();
}
Upvotes: 1