I'm force to expose some methods in a C# library so that they can be used from an external program written in C++ (VC++ 6.0). I thus created a mixed assembly which works quite ok so far but I have some troubles with a method that returns an array of .NET objects.
The .NET signature of the method is:
public Results[] Measure(String model, String identifier);
Where Results itself is:
public class Results
{
public String[] ElementType;
public bool[] HasError;
}
To provide entry point from C++, I started to write a C++/CLI wrapper method like this:
std::vector<ResultsWrapper> Measure(char* model, char* identifier)
{
// Call .NET code
String^ gcmodel = gcnew System::String(model);
String^ gcidentifier = gcnew System::String(identifier);
cli::array<Results^>^ gcres = myNetInstance->Measure(gcmodel, gcidentifier);
// Convert results to C++ vector
std::vector<ResultsWrapper> ret;
for (int ki = 0; ki < res->Length; ki++)
{
ResultsWrapper r = ResultsWrapper(res[ki]->...., );
ret.push_back(r);
}
return ret;
}
but I must admit I'm a bit lost, this is very long time I haven't wrote a single line of C++ and very long time I haven't deal with by hand memory management...
What is the best solution to create ResultsWrapper class so that there will be no much need to care for memory management from C++ side. Maybe something like the following ?
class ResultsWrapper
{
public:
ResultsWrapper(vector<std::String> elementType, vector<bool> hasError)
{
this.ElementType = elementType;
this.HasError = hasError;
}
public:
vector<std:String> ElementType;
vector<bool> HasError;
}
NB: I don't think team on VC++ 6.0 side are aware of boost library or share_ptr types (and I'm not very knowledgable about them either). All C++ code is very classic C++ code style, not even using stdlib.
I could not pass safely/easily STL types across dll boundaries so I get back to old char**, and manual allocation/deallocation and It Just Worked...
IJW for a while only ... then I tried to check for when throwing exception from .NET back to the calling C++ application and then patatra ... need conversion to native exceptions ... that again cannot safely cross dll boundaries ...
Mixed mode assemblies sounded appealing to go from .NET to native but was an IJS experience in my case... I give up and will go through COM instead.
In C++/CLI I started to write a wrapper method like this:
No, you did not
public Results[] Measure(String model, String identifier);
has no resemblance in
std::vector Measure(char* model, char* identifier)
None.
There is no marshalling required in a C++/CLI reference class. Use String^ as pointer to string (instead of char*) and use array<ResultsWrapper>^ as pointer to a managed array.
There is no need to use a wrapper at all. Declare a class as managed reference (ref class) and you can call it from the .NET side because it is a .NET class.
I have a solution with 3 projects. A C# WinForms project which depends on second project which is a C++ DLL. The C++ DLL depends on the third project which is a static library. The static library is C code with C++ classes. The DLL acts as an interop between the C code and C# code.
I need to set the variables used by the static library through C# structure.
I do not have experience in C++/CLI (I have started reading. Examples found on the web do not make sense to me as of now)
So far, I have created a structure in C#. I created a initialized unmanaged memory to hold this struct:
IntPtr ptData = Marshal.AllocHGlobal(Marshal.SizeOf(objMyClass.data));//data is the structure I am initializing in the constructor of MyClass
Marshal.StructureToPtr(objPythonInterop.data, ptData, false);
objCPPClass.UpdateData(ptData);//objCPPClass is object to class in DLL. libClass is the object of class in static library
This is my structure in C#:
[StructLayout(LayoutKind.Sequential)]
public struct Data
{
members here..
}
In the DLL, this is the UpdateData function:
Header:
void UpdateData(IntPtr ptrData);
Source:
void CPPClass::UpdateData(IntPtr ptrData)
{
m_lib->UpdateDataInLib(ptrData);// m_lib is object to class in static library
}
UpdateDataInLib is a function in the Class in Static library. How do I use the ptrData in this function and update the variables? I have a structure in the static library similar to the structure defined in my C# code. How do I cast the ptr to this structure and access the members?
I have a structure in my C++ static library which contains equivalent members of the structure in C#:
extern "C" __declspec(dllexport) typedef struct Data
{
members here..
}Data, *pData;
I need help.
There's a simpler approach. You don't need dynamic memory allocation if your DLL doesn't access the structure anymore after the call. Just put the structure on the stack (you still need fixed nevertheless):
var data = new objMyClass.data
{
field1 = value1, // etc
};
unsafe
{
fixed (objMyClass.data* ptr = &data)
{
objCPPClass.UpdateData(new IntPtr(ptr));
}
}
If the structure is long-lived then keep your code as-is but don't forget to free the allocated memory.
Then, on the C++ side, you could just cast:
void CPPClass::UpdateData(IntPtr ptrData)
{
m_lib->UpdateDataInLib(static_cast<pData>(ptrData.ToPointer()));
}
But as I don't know the signature of UpdateDataInLib I'm not sure about this approach.
Also, you can get rid of the IntPtr intermediate step, and just use a pointer.
Could somebody tell me what the difference between CLR and CLI is in it's basic functionallity but most important would be which one of them is better?
All I got so far is that using the ICLRRuntimeHost Interface does not allow me to return anything else than an int and the only allowed parameter is a LPCWSTR (see ExecuteInDefaultAppDomain)
At this point I am wondering if one could/would allocate memory e.g. for a struct in his C program, give a pointer as a LPCWSTR string to ExecuteInDefaultAppDomain and translates this pointer back into that struct on the other side to work on that struct. I don't get it how one can work with the limitation of this signator for each function: int fncname(string param);
I took a look at this tutorial but I don't get it how calling C++/CLI from a C program works and how I could return complex objects or anything more complex than an int.
And could somebody please show me HOW I can use CLI within C? I can't seem to find some lines of code that would show how that would work.
You can pass and return complex data in CLI. CLI is an intermediate layer. when you pass data from a managed code(.NET) to native code (c,c++) you need a intermediate layer which will take responsibility of managed to native object and vice verse conversation because managed objects are managed by Garbage collector and native objects are managed by programmer (need to delete when created).
In C++/CLI there are two type of class. 1) Manged class 2) Native class. A managed class is defined as :
public ref class ManagedClass
{
NativeObject* native;
ManagedObject^ mObject;
}
This can contain managed and native object. So in this class you create a managed/native class object which is replica of native/managed object (in terms of containing data and method). The basic data in any object is either another object or basic primitive data which can be easily converted. You have to take care of objects only.
Suppose you want to execute C++ method form .NET. Your c++ code has an object called NativeClass and your c++ method return this native object. You can't pass this object directly to .NET layer. So you will store that object instance in variable native of above class ManagedClass. Note that you can access native as well as managed object in CLI layer. Now you create a manged object class in CLI which will be exact replica of native class in term of containing data. Now you copy all date from Native object to managed object and assign that managed object instance to variable mObject. Now you can pass this variable mObject to .NET layer because this is Manged object.
Similar approach can be used when you pass Managed object to Native method.
You can go through this PDF to know more about C++/CLI.
http://asawicki.info/Download/Productions/Publications/CPP_CLI_tutorial.pdf
UPDATE:
I will recommend you to first go through the PDF. Below is a simple example how this conversion happens. NativeObject is C++ object (You can also have C struct instaed of Class) and ManagedObject is C# object and CLIInterface is used to provide interface.
public ref class CLIInterface
{
private:
NativeObject* native;
ManagedObject^ mObject;
public:
CLIInterface(NativeObject* nativeObj){
native = nativeObj;
mObject = gcnew ManagedObject(nativeObj);
}
string getNativeMessage();
int getNaiveID();
String^ getManagedMessage();
int getmanagedID();
}
Native class:(C++ Object or C struct and can be used in CLI)
public class NativeObject
{
private:
int id;
string msg;
public:
string getMessage(){return msg;}
int getID(){return id;}
}
Managed class: (C# object and you can use it in CLI)
public ref class ManagedObject
{
private:
NativeObject* native;
public:
ManagedObject(NativeObject* obj){
native = obj;
}
String^ getMessage(){
convertNativeToCLI(native->getMessage()); //you can use marshaling to implement convertNativeToCLI method.
}
int getID(){
return native->getID();
}
}
You can use Managed class object and CLIInterface from C# code and you can use Native Object in C++ code. I hope this will help. You can also go to Microsoft's C++/CLI documentation.
I am new to C# but have worked extensively with C++. I have a C++ function that needs to be called from C#. After reading some answers from SO and some googling, I conclude that I need to make a pure C interface to the function. I have done this, but am still confused about how to call it from C#.
The function in C++ looks like this:
int processImages(
std::string& inputFilePath, // An input file
const std::vector<std::string>& inputListOfDirs, // Input list of dirs
std::vector<InternalStruct>& vecInternalStruct, // Input/Output struct
std::vector<std::vector< int > >& OutputIntsForEachFile,
std::vector< std::vector<SmallStruct> >& vecVecSmallStruct, // Output
int verboseLevel
);
The same function, converted in C, looks like this:
int processImagesC(
char* p_inputFilePath, // An input file
char** p_inputListOfDirs, // Input list of dirs
size_t* p_numInputDirs, // Indicating number of elements
InternalStruct* p_vecInternalStruct, // Input/Output struct
size_t* p_numInternalStructs,
int** p_OutputIntsForEachFile, // a 2d array each row ending with -1
size_t* p_numOutputIntsForEachFile //one number indicating its number of rows
SmallStruct** p_vecVecSmallStruct, // Output
size_t* p_numInVecSmallStruct,
int verboseLevel
);
This is based on this advice.
Now I need to call this from C#, which is where the confusion is. I have tried my best to convert the structures.
The C# code looks like this:
[DllImport(
#"C:\path\to\cppdll.dll", CallingConvention=CallingConvention.Cdecl,
EntryPoint="processImagesC", SetLastError=true)]
[return: MarshalAs(UnmanagedType.I4)]
unsafe public static extern int processImagesC(
String inputFilePath,
String[] inputListOfDirs,
ref uint numInputListOfDirs,
// Should I use ref InternalStruct * vecInternalStruct?
ref InternalStruct[] vecInternalStruct,
ref uint numInternalStruct,
// Or ref int[] or ref int[][] or int[][]?
ref int[][] OutputIntsForEachFile,
ref uint numOutputIntsForEachFile,
// again, ref ..[], [][], or ref [][]?
ref SmallStruct[][] vecVecSmallStruct,
int verboseLevel
);
There are memory allocations for all the output variables (pointers) done within the C/C++ code. This likely means we need to declare the code as unsafe, correct?
How do we handle memory deallocation? Should I write another API (function) that does the deallocation of objects/arrays allocated by C/C++?
The C++ code needs to be standard compliant and platform independent, so I cannot insert any windows-specific things in it.
I hope someone could make sense of this and provide an answer or at least point me in the right direction.
Since there seems to be some interest in using It Just Works (IJW) with C++/CLI, I'll post some info about that, further google searches and research will need to be done to figure it all. C++/CLI can be enabled with a single compiler flag (/CLI, enabled through Property Page->General->Common Language Runtime Support). C++/cli is NOT c++, but rather just another managed language. C++/CLI classes can be compiled into dll's and called directly from other .NET projects (C#, VB.NET, ect). However, unlike the other .NET languages it can directly interact with C++ code.
This is an ok start to learning C++/CLI. The big thing to learn is the decorations that tell you the class is managed (.NET class) and not Vanila C++. The "ref" keyword decalres the definition as a .NET definition:
public ref class Foo{ public: void bar();};//Managed class, visible to C#
public ref struct Foo{};//Managed struct, visible to C#
All reference classes are referred to with Handles rather than pointers or references. A handle is denoted by the ^ operator. To make a new handle, you use gcnew, and to access functions/members of the handle, use the -> operator.
//in main
Foo^ a = gcnew Foo();
a->bar();
You often have to move structures common from C# to native types and back again. (such as managed Array^ or String^ to void* or std::string). This process is called Marshaling. This handy table is pretty useful for figuring that out.
A common task is to create a wrapper for a native class, done like this:
//Foo.h
#include <string>
namespace nativeFoo
{
class Foo
{
private:
std::string fooHeader;
public:
Foo() {fooHeader = "asdf";}
std::string Bar(std::string& b) {return fooHeader+b;}
};
}
//ManagedFoo.h
#include "foo.h"
namespace managedFoo
{
public ref class Foo
{
private:
nativeFoo::Foo* _ptr;
public:
Foo(){_ptr = new nativeFoo::Foo();}
~Foo(){!Foo();}
!Foo(){if (_ptr){delete ptr;ptr = NULL;}}
String^ bar(String^ b)
{
return marshal_as<String^>(_ptr->bar(marshal_as<std::string>(b)));
}
};
}
Warning: I am totally missing a bunch of #include and #using statements, this is just to give a general gist of how to use this.
Begin from this:
How to pass structure as pointer in C dll from C#
And something about marshalling in this:
Deep copying an array c# without serialization
Note that Marshal.Copy also overloads for arrays use. With marshalling you can get rid of ref excepting that you do want to. Just write C/C++ in their way.
And following is a little bit complicated:
Physical disk size not correct (IoCtlDiskGetDriveGeometry)
The 2 ways I've often seen this handled is to either have a 'FreeResource' style API, or specify in the function the size of output buffers.
Method 1
C++
void GetName(char ** _str)
{
if (!_str)
return; // error
*_str = new char[20];
strcpy(*str, "my name");
}
void FreeString(char * _str)
{
delete str;
}
Client (any language)
char * name;
GetName(&name);
...
FreeString(name);
Method 2
C++
void GetName(char * _str, size_t _len)
{
if (_len < 20)
return; // error
strcpy(str, "my name");
}
Client (any language)
char * name = new char[20];
GetName(name, 20);
...
If you are willing to use third party tool, there is a tool named C#/.NET PInvoke Interop SDK may be helpful to you. But you can do it yourself as well. For simple classes with a few methods, you can write your own code in managed C# code.
The basic idea of instantiating a C++ object from .NET world is to allocate exact size of the C++ object from .NET, then call the constructor which is exported from the C++ DLL to initialize the object, then you will be able to call any of the functions to access that C++ object, if any of the method involves other C++ classes, you will need to wrap them in a C# class as well, for methods with primitive types, you can simply P/Invoke them. If you have only a few methods to call, it would be simple, manual coding won't take long. When you are done with the C++ object, you call the destructor method of the C++ object, which is a export function as well. if it does not have one, then you just need to free your memory from .NET.
Here is an example.
public class SampleClass : IDisposable
{
[DllImport("YourDll.dll", EntryPoint="ConstructorOfYourClass", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.ThisCall)]
public extern static void SampleClassConstructor(IntPtr thisObject);
[DllImport("YourDll.dll", EntryPoint="DoSomething", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.ThisCall)]
public extern static void DoSomething(IntPtr thisObject);
[DllImport("YourDll.dll", EntryPoint="DoSomethingElse", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.ThisCall)]
public extern static void DoSomething(IntPtr thisObject, int x);
IntPtr ptr;
public SampleClass(int sizeOfYourCppClass)
{
this.ptr = Marshal.AllocHGlobal(sizeOfYourCppClass);
SampleClassConstructor(this.ptr);
}
public void DoSomething()
{
DoSomething(this.ptr);
}
public void DoSomethingElse(int x)
{
DoSomethingElse(this.ptr, x);
}
public void Dispose()
{
Marshal.FreeHGlobal(this.ptr);
}
}
For the detail, please see the below link,
C#/.NET PInvoke Interop SDK
The tool, xInterop NGen++ 2.0 has been released. Please check it out if you are interested in creating C# wrapper for native C++ DLL.
(I am the author of the SDK tool)
All the examples I can find using DLLImport to call C++ code from C# passes ints back and forth. I can get those examples working just fine. The method I need call takes two structs as its import parameters, and I'm not exactly clear how I can make this work.
Here's what I've got to work with:
I own the C++ code, so I can make any changes/additions to it that I need to.
A third party application is going to load my DLL on startup and expects the DLLExport to be defined a certain way, so i can't really change the method signature thats getting exported.
The C# app I'm building is going to be used as a wrapper so i can integrate this C++ piece into some of our other applications, which are all written in C#.
The C++ method signature I need to call looks like this
DllExport int Calculate (const MathInputStuctType *input,
MathOutputStructType *output, void **formulaStorage)
And MathInputStructType is defined as the following
typedef struct MathInputStuctTypeS {
int _setData;
double _data[(int) FieldSize];
int _setTdData;
} MathInputStuctType;
The MSDN topic Passing Structures has a good introduction to passing structures to unmanaged code. You'll also want to look at Marshaling Data with Platform Invoke, and Marshaling Arrays of Types.
From the declaration you posted, your C# code will look something like this:
[DllImport("mydll.dll")]
static extern int Calculate(ref MathInputStructType input,
ref MathOutputStructType output, ref IntPtr formulaStorage);
Depending on the structure of MathInputStructType and MathOutputStructType in C++, you are going to have to attribute those structure declarations as well so that they marshal correctly.
For the struct:
struct MathInputStuctType
{
int _setData;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = FieldSize)]
double[] _data;
int _setTdData;
}
You might want to look at this project on CodePlex, http://www.codeplex.com/clrinterop/Release/ProjectReleases.aspx?ReleaseId=14120. It should help you marshal the structures correctly.