I suppose I have to create a managed C++ code to wrap the native C++. But I have the problem while trying to wrap an array used in function parameter whose type is defined in native C++. The native C++ code is as follows:
//unmanageCPP.h
class __declspec(dllexport) unmanageMoney
{
public:
unmanageMoney(int a, int b) { rmb = a; dollar = b; }
unmanageMoney() { rmb = 0; dollar = 0; }
int rmb;
int dollar;
};
class __declspec(dllexport) unmanageSum
{
public:
//how to wrap this funciton?
int addDollar(unmanageMoney a[], unmanageMoney b[]);
};
//unmanageCPP.cpp
#include "unmanaged.h"
int unmanageSum::adddollar(unmanageMoney a[], unmanageMoney b[])
{
return a[0].dollar + b[0].dollar;
}
Could anyone tell me how to write the manageCPP.h? Thanks very much!
Update
I compose the manageCPP.h as follows, but I don't know how to write addDollar()
//first, I wrap the class unmanageMoney for use in manageSum::addDollar()
public ref class manageMoney
{
private:
unmanageMoney* mMoney;
public:
unmanageMoney getMoney()
{
return *mMoney;
}
manageMoney(int a, int b) { mMoney = new unmanageMoney(a, b); }
~manageMoney() { delete mMoney; }
};
public ref class manageSum
{
// TODO: Add your methods for this class here.
private:
unmanageSum *mSum;
public:
manageSum()
{
mSum = new unmanageSum();
}
~manageSum()
{
delete mSum;
}
//it must be wrong if I code like this, for unmanageSun::adddollar() only
// receives unmanageMoney as arguments. So what should I do?
int adddollar(manageMoney a[], manageMoney b[])
{
return mSum->adddollar(a, b);
}
};
You create a C++/CLI source file with
public ref class SomethingOrOther
{
//...
};
and set the compile options to use the /clr option.
Beyond that, it's almost the same as writing native C++. You'll #include the header file for the class you want to reuse, create instances and call their member functions, just the same as normal C++. But anything inside that ref class will be visible to C#.
And you do NOT put __declspec(dllexport) on the class. Not ever. It's useful for functions, but creates misery when used with classes.
Related
I'm currently working on a .NET Framework 4.7.2 application using a business logic library written in unmanaged C++. I need to use unmanaged C++.
I need to use the logic from the C++ project, unfortunately I cannot correctly convert the input or output parameters of my program.
When I input 42, and simply want to return that value, I get 17582022 as a result. Which should actually be 42.
My C++ code looks like that:
MYCore header file:
#ifdef MYCORE_EXPORTS
#define MYCORE_API __declspec(dllexport)
#endif
#pragma once
#include <string>
using namespace std;
extern "C"
{
class MYCORE_API TestClass
{
private:
string name;
public:
TestClass(char*);
long Iterate(long &n);
};
MYCORE_API TestClass* TestClass_Create(char* name);
}
MYCore source file:
#include "stdafx.h"
#include "MYCore.h"
TestClass::TestClass(char* n)
{
name = n;
}
long TestClass::Iterate(long &n)
{
return n;
}
extern "C"
{
MYCORE_API TestClass * TestClass_Create(char* name)
{
return new TestClass(name);
}
}
I'm using a .NET 4.7.2 Framework Interface project to export the C++ library functionality:
namespace MYCore.Interface
{
public static class MYProxy
{
private const string coreDLL = "my.core.dll";
[DllImport(coreDLL, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr TestClass_Create(string name);
[DllImport(coreDLL, EntryPoint = "?Iterate#TestClass##XXXXX#X", CallingConvention = CallingConvention.ThisCall)]
public static extern int Iterate(int n);
}
}
In my actual application I further import the dll and use the logic like that:
public static void Initialize()
{
var test = MYProxy.WrapperIterator_Create("test");
var result = MYProxy.Iterate(42); // as a result I'm getting sth. like 17582022 instead of 42
}
Do you know how to correctly convert an int input from C# to C++ and vice versa?
Thank you!
What you're doing in C# does not work in C++ either:
auto result = Iterate(42l);
results in the compiler error
Cannot convert argument 1 from 'long' to 'long &'
I see two solutions:
a) Change the C++ code
long TestClass::Iterate(long n)
(without the reference)
b) Change the C# code
static extern int Iterate(ref int n);
(pass a reference) and call it like
int n = 42;
Console.WriteLine(Iterate(ref n));
The problem is actually called "Marshal an unmanaged C++ Class to C#".
In my Proxy class I created a method to call an actual instance method:
[DllImport(coreDLL, EntryPoint = "?Iterate#TestClass##XXX#X", CallingConvention = CallingConvention.ThisCall)]
public static extern int CallIterate(IntPtr instance, int n);
and the method in my C++ looks like that:
MYCORE_API int CallIterate(TestClass * instance, int n)
{
if (instance!= NULL)
{
return instance->Iterate(n);
}
}
For further reading on how to marshal unmanaged C++ classes, I can suggest the following article:
https://www.codeproject.com/Articles/18032/How-to-Marshal-a-C-Class
My solution works fine now. Thanks for all the good input!
I have an unmanaged DLL that exports only a C style factory method that returns a new instance of a class (simplified here to look simple).
hello.h
#if defined(HWLIBRARY_EXPORT) // inside DLL
# define HWAPI __declspec(dllexport)
#else // outside DLL
# define HWAPI __declspec(dllimport)
#endif
struct HelloWorld{
public:
virtual void sayHello() = 0;
virtual void release() = 0;
};
extern "C" HWAPI HelloWorld* GetHW();
hello.cpp
#include "hello.h"
struct HelloWorldImpl : HelloWorld
{
void sayHello(){
int triv;
std::cout<<"Hello World!";
std::cin>>triv;
};
void release(){
this->HelloWorldImpl::~HelloWorldImpl();
};
HelloWorld* GetHW(){
HelloWorld* ptr = new HelloWorldImpl();
return ptr;
};
Now, I can use dllimport to access GetHW() but is there a way to access the member functions of the returned 'struct'... ie, sayHello and release?
I was also stuck with the same problem. This question was asked a while before. I commented to it for any better solution but didn't get any reply yet. So, reposting it.
When i googled, able to find out two solutions.
Solution1: Expose all the member functions in the C-style for the existing dll. Which i cant do, as it is a 3rd party dll.
Solution2: Write a managed C++ dll exposing the functionality of native C++ dll, which later can be used in your C# dll. Here many classes/functions are present. So, creating would take most of the time.
i got the above solutions from the link below.
How To Marshall
Please let me know if there is any better solution other than the above two solutions?
i have the source code for C++ solution. But what i though was not to touch C++ dll. If there is any possibility to do it in C#, it would be great.
If there is no alternative, i need to follow any one of the specified two solutions.
The C++ code is using the way abstract classes are implemented by the Visual C++ compiler. http://blogs.msdn.com/b/oldnewthing/archive/2004/02/05/68017.aspx. This memory layout is "fixed" because it is used for implementing COM interfaces. The first member of the struct in memory will be a pointer to a vtable containing the function pointers of your methods. So for a
struct HelloWorldImpl : public HelloWorld
{
public:
int value1;
int value2;
}
the "real" layout in memory would be:
struct HelloWorldImpl
{
HelloWorldVtbl *vtbl;
int value1;
int value2;
}
where vtbl would be:
struct HelloWorldVtbl
{
void *sayHello;
void *release;
}
Just for the sake of doing a complete response, I'm writing the example for this signatures:
struct HelloWorld {
public:
virtual int sayHello(int v1, int v2, int v3) = 0;
virtual void release() = 0;
};
C# code:
[DllImport("NativeLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr GetHW();
[StructLayout(LayoutKind.Sequential)]
struct HelloWorldVtbl
{
public IntPtr sayHello;
public IntPtr release;
}
Your functions are void Func(void) or int Func(int, int, int), but in truth they have a hidden parameter, this, so you can write them as:
int sayHello(HelloWorld*, int, int, int);
void release(HelloWorld*);
so in C# the delegate is
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
public delegate int Int32MethodInt32Int32Int32(IntPtr ptr, int v1, int v2, int v3);
[UnmanagedFunctionPointer(CallingConvention.ThisCall)]
public delegate void VoidMethodVoid(IntPtr ptr);
Then you can use
IntPtr ptr = GetHW();
IntPtr vtbl = Marshal.ReadIntPtr(ptr, 0);
HelloWorldVtblhw = (HelloWorldVtbl)Marshal.PtrToStructure(vtbl, typeof(HelloWorldVtbl));
Int32MethodInt32Int32Int32 sayHello = (Int32MethodInt32Int32Int32)Marshal.GetDelegateForFunctionPointer(hw.sayHello, typeof(Int32MethodInt32Int32Int32));
int res = sayHello(ptr, 1, 2, 3);
Console.WriteLine(res);
VoidMethodVoid release = (VoidMethodVoid)Marshal.GetDelegateForFunctionPointer(hw.release, typeof(VoidMethodVoid));
release(ptr);
I went through the tutorial of C# COM INterop. Performed the demo example given in the link successfully runs! Understood every statement present there, their meaning.
And came across the equivalent data types for c# objects.
I Couldn't find any good books (with examples on C# COM interop and calling COM components from native C++) apart from Adam Nathan's .NET and COM interoperability and Nishant Shivakumar's CCLI in Action. I have no problems in registering assembly and other stuff but facing problems in COM syntax.
Before explaining my code, I wanted to understand what VARIANT is. Why is it there?
This is my situation, I have a C# class as below:
using System.Text;
using System.Runtime.InteropServices;
using System.Drawing;
namespace ManagedDLL
{
// Interface declaration.
[ComVisible(true), Guid("3265C537-E149-4559-B4E1-DBE334927DFA"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ICalculator
{
int Add(int Number1, int Number2);
int Subtract(Subtraction sb);
};
// Interface implementation.
[ComVisible(true), Guid("0F50D3BE-CEEA-4C57-9882-4A609C7BB36C")]
public class ManagedClass : ICalculator
{
private int a, b;
public int Add(int Number1, int Number2)
{
return Number1 + Number2;
}
public int Subtract(Subtraction sub)
{
int a = 10, b = 3;
return sub.SubtractTwoNumbers(a, b);
}
}
[ComVisible(true)]
[Guid("C718EDDE-541C-4D15-B7EA-0533AB11A839")]
[ClassInterface(ClassInterfaceType.None)]
public class Subtraction
{
public int SubtractTwoNumbers(int a, int b)
{
return a - b;
}
}
}
Got the .tlh file after importing tlb file as below:
#pragma once
#pragma pack(push, 8)
#include <comdef.h>
namespace ManagedDLL {
//
// Forward references and typedefs
//
struct __declspec(uuid("4e5098b7-4e51-45e5-a705-a7e3c51e2a80"))
/* LIBID */ __ManagedDLL;
struct __declspec(uuid("3265c537-e149-4559-b4e1-dbe334927dfa"))
/* interface */ ICalculator;
struct /* coclass */ ManagedClass;
struct /* coclass */ Subtraction;
struct __declspec(uuid("c8e9181c-f064-3ec1-869e-042c6fdd3e46"))
/* dual interface */ _ManagedClass;
//
// Smart pointer typedef declarations
//
_COM_SMARTPTR_TYPEDEF(ICalculator, __uuidof(ICalculator));
_COM_SMARTPTR_TYPEDEF(_ManagedClass, __uuidof(_ManagedClass));
//
// Type library items
//
struct __declspec(uuid("3265c537-e149-4559-b4e1-dbe334927dfa"))
ICalculator : IUnknown
{
//
// Raw methods provided by interface
//
virtual HRESULT __stdcall Add (
/*[in]*/ long Number1,
/*[in]*/ long Number2,
/*[out,retval]*/ long * pRetVal ) = 0;
virtual HRESULT __stdcall Subtract (
/*[in]*/ struct _Object * sb,
/*[out,retval]*/ long * pRetVal ) = 0;
};
struct __declspec(uuid("0f50d3be-ceea-4c57-9882-4a609c7bb36c"))
ManagedClass;
// [ default ] interface _ManagedClass
// interface _Object
// interface ICalculator
struct __declspec(uuid("c718edde-541c-4d15-b7ea-0533ab11a839"))
Subtraction;
// [ default ] interface _Object
struct __declspec(uuid("c8e9181c-f064-3ec1-869e-042c6fdd3e46"))
_ManagedClass : IDispatch
{};
//
// Named GUID constants initializations
//
extern "C" const GUID __declspec(selectany) LIBID_ManagedDLL =
{0x4e5098b7,0x4e51,0x45e5,{0xa7,0x05,0xa7,0xe3,0xc5,0x1e,0x2a,0x80}};
extern "C" const GUID __declspec(selectany) IID_ICalculator =
{0x3265c537,0xe149,0x4559,{0xb4,0xe1,0xdb,0xe3,0x34,0x92,0x7d,0xfa}};
extern "C" const GUID __declspec(selectany) CLSID_ManagedClass =
{0x0f50d3be,0xceea,0x4c57,{0x98,0x82,0x4a,0x60,0x9c,0x7b,0xb3,0x6c}};
extern "C" const GUID __declspec(selectany) CLSID_Subtraction =
{0xc718edde,0x541c,0x4d15,{0xb7,0xea,0x05,0x33,0xab,0x11,0xa8,0x39}};
extern "C" const GUID __declspec(selectany) IID__ManagedClass =
{0xc8e9181c,0xf064,0x3ec1,{0x86,0x9e,0x04,0x2c,0x6f,0xdd,0x3e,0x46}};
} // namespace ManagedDLL
#pragma pack(pop)
and finally this is my native C++ application:
HRESULT hr = CoInitialize(NULL);
ManagedDLL::ICalculatorPtr ptrInterface(__uuidof(ManagedDLL::ManagedClass));
IUnknown* pUnk=NULL;
hr=CoCreateInstance(__uuidof(ManagedDLL::Subtraction), NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)pUnk);
long lResult;
ptrInterface->Subtract(pUnk, &lResult); //what should be written instead of pUnk, because it expects a _Object* as evident in the tlh file
return lResult;
Questions galore:
How to access the Subtract method in the interface? How should we instantiate Subtraction class whose object should be passed as parameter in this Subtract method?
How to collect value of a function returning a COM class as return type?
What are IUnknown and IDispatch?
And most importantly, why the _Object* was created as an argument in the COM .tlh file instead of Subtraction* as argument?
The questions you are asking are classical, fundamental questions about COM that could take a small book to answer. I would suggest you get a tutorial or a book on COM that will bring you up to speed. You won't understand the interop until you understand COM basics. Start there, then work through the harder stuff.
It takes some serious time to get up to speed on all the issues involved, so don't get in a hurry!
Here's a place to start:
http://msdn.microsoft.com/en-us/library/727z646z(v=vs.80).aspx
I am using a c# wrapper, in the c++ library, the called function returns a pointer to the class object.
In the c# wrapper, if I call that method it returns an interface variable.
That interface variable is null, so I am unable gets the values.
How should I handle that interface variable in order to get values.
Anyone please help me.
In the below code we have ROOTNET.Interface.NTH1F it is an interface, where ROOTNET.NTH1F is a class
using ROOTNET.Utility;
using ROOTNET.Interface;
NTH1F g = new ROOTNET.NTH1F("g", "background removal", doubleArrayX.Length - 1,
doubleArrayX);
g.SetContent(doubleArrayY);
g.GetXaxis().SetRange(xmin, xmax);
ROOTNET.NTH1F bkg = new ROOTNET.NTH1F(g);
bkg.Reset();
bkg.Add(g.ShowBackground(80, ""));
In the above Im expecting the backgroung removed values to be saved in bkg but bkg contains all zeros, can you please help me in getting background removed values of g into bkg.
Where as the code of ShowBackground(int niter, string option) method is
public unsafe virtual NTH1 ShowBackground (int niter, string option)
{
NetStringToConstCPP netStringToConstCPP = null;
NetStringToConstCPP netStringToConstCPP2 = new NetStringToConstCPP (option);
NTH1 bestObject;
try
{
netStringToConstCPP = netStringToConstCPP2;
int num = *(int*)this._instance + 912;
bestObject = ROOTObjectServices.GetBestObject<NTH1> (calli ((), this._instance, niter, netStringToConstCPP.op_Implicit (), *num));
}
catch
{
((IDisposable)netStringToConstCPP).Dispose ();
throw;
}
((IDisposable)netStringToConstCPP).Dispose ();
return bestObject;
}
You cannot treat a pointer value returned from C++ as an interface (unless it's a COM interface, I guess). C++ and C# classes and interfaces may (and mostly probably do) have different low-level structures, so you cannot simply cast one onto another.
The only way is to write another wrapper around C++ class returned by your library. It should look more less like that:
C++/DLL:
__declspec(dllexport) void * ReturnInstance()
{
return new MyClass();
}
__declspec(dllexport) void MyClass_CallMethod(MyClass * instance)
{
instance->Method();
}
C#:
[DllImport("MyDll.dll")]
private static extern IntPtr ReturnInstance();
class MyClassWrapper
{
private IntPtr instance;
[DllImport("MyDll.dll")]
private static extern void MyClass_CallMethod(IntPtr instance);
public MyClassWrapper(IntPtr newInstance)
{
instance = newInstance;
}
public void Method()
{
MyClass_CallMethod(instance);
}
}
// (...)
IntPtr myClassInstance = ReturnInstance();
MyClassWrapper wrapper = new MyClassWrapper(myClassInstance);
wrapper.Method();
Hope this helps.
I want to use PInvoke to bring to managed side something this:
(C code)
typedef struct{
//some fields...
} A;
type struct{
A* a;
} B;
int getB(B* destination){ //destionation will be an output parameter to C#
//puts an B in 'destination'
return 0;
}
Now, I need a way to tell managed side how to marshalling B from C to C# structure or class. I've tryed many things such as IntPtr fields, MarchalAs atributes, but with no success. I will not expose here the code that I've tryed to keep the question simple. However i could do it as long answers arrive.
If it were me, I would just use unsafe code and use pointers on the C# side:
public unsafe class UnmanagedStuff {
public struct A {
// some fields
}
public struct B {
public A* a;
}
// Add appropriate PInvoke attribute here
public static extern int getB(B* destination);
public static void UseBForSomething() {
B b;
getB(&b);
// Do something with b
}
}
You can do that using the Marshal class.
// Define a C# struct to match the unmanaged one
struct B
{
IntPtr a;
}
[DllImport("dllName")]
extern int getB(IntPtr destination);
B GetB()
{
IntPtr ptrToB = IntPtr.Zero;
getB(ptrToB);
return (B)Marshal.PtrToStructure(ptrToB, typeof(B));
}