How to marshal C++/CLI array of struct to unmanaged C++ - c++

I'm searching for the correct syntax to pass a struct array to an unmanaged C++ dll.
my dll imports are called like this
#define _DllImport [DllImport("Controller.dll", CallingConvention = CallingConvention::Cdecl)] static
_DllImport bool _Validation(/* array of struct somehow */);
In my client code I have
List<MyStruct^> list;
MyObject::_Validation(/* list*/);
I know System::Runtime::InteropServices::Marshal has a lot of useful methods for doing stuff like this but I'm not sure about which to use.

Create a managed version of the unmanaged struct using StructLayout.Sequential (make sure to put things in the same order). You should then be able to pass it like you'd pass it to any managed function (e.g., Validation(MyStruct[] pStructs).
For example, let's say our native function has this prototype:
extern "C" {
STRUCTINTEROPTEST_API int fnStructInteropTest(MYSTRUCT *pStructs, int nItems);
}
and the native MYSTRUCT is defined as follows:
struct MYSTRUCT
{
int a;
int b;
char c;
};
Then in C#, you define a managed version of the struct as follows:
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
public struct MYSTRUCT
{
public int a;
public int b;
public byte c;
}
And the managed prototype as follows:
[System.Runtime.InteropServices.DllImportAttribute("StructInteropTest.dll", EntryPoint = "fnStructInteropTest")]
public static extern int fnStructInteropTest(MYSTRUCT[] pStructs, int nItems);
You can then call the function passing it an array of MYSTRUCT structs as follows:
static void Main(string[] args)
{
MYSTRUCT[] structs = new MYSTRUCT[5];
for (int i = 0; i < structs.Length; i++)
{
structs[i].a = i;
structs[i].b = i + structs.Length;
structs[i].c = (byte)(60 + i);
}
NativeMethods.fnStructInteropTest(structs, structs.Length);
Console.ReadLine();
}

You can use Marshall.StructureToPtr to get an IntPtr which could be passed into a native MyStruct* array.
However, I'm not sure how to do this from a List directly. I believe you need to convert this to an array and use a pin_ptr (to prevent the GC from moving your memory) prior to passing it to the native code.

Related

Getting Read/Write access error when trying to use method from external library

I am trying to use the following implementation from a library
C++
int CALLBACK xCallback(long xmitlen, int buflen, char *buf, long flen)
{
return 0;
}
extern "C" __declspec(dllexport) int __stdcall TXFIlestransfer(int port, string fileName);
__declspec(dllexport) int __stdcall TXFIlestransfer(int port, string fileName)
{
int ret;
char *test = &fileName[0];
ret = sio_FtKermitTx(port, test, xCallback, 27);
return ret;
}
I am importing this to use with C# and am getting System.AccessViolationException: 'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.'
Any help with resolving this error would be greatly appreciated.
I tested your program by simulating the sio_FtKermitTx function in my C++ dll (Mydll.dll):
int sio_FtKermitTx (int port, char *fname, int (CALLBACK *func) (long xmitlen, int buflen, char *buf, long flen), int key)
{
return 5;
}
And even with an empty body, I have the same problem as you.
After several investigations, I noticed that the problem came from the fact that we are using a string object between C# and C++ code which for one reason or another (unicode / multibyte configuration for example, or simply because sharing complex objects is difficult to implement) causes problem.
Solution:
By replacing the string object with a primitive char type, everything works correctly:
C# Code:
using System.Runtime.InteropServices;
namespace MyProgramme
{
class Test
{
// Import C++ DLL
[DllImport("Mydll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int TXFIlestransfer(int i, char[] filename);
//public static extern int TXFIlestransfer(int i, string filename); // this crash
static void RunTest(/*LoadFilterEVENTMessage msg*/)
{
string c = "ABC";
char[] char_arr = c.ToCharArray();
int i = TXFIlestransfer(3, char_arr);
// int i = TXFIlestransfer(3, c); string version crash
string s = i.ToString();
MessageBox.Show(s);
}
/* Methods in DLL being used below */
public static void Main()
{
RunTest();
}
};
}
C++ DLL code (Mydll.dll) :
extern "C" __declspec(dllexport) int TXFIlestransfer(int port, char fileName[])
{
int ret;
char *test = &fileName[0];
ret = sio_FtKermitTx(port, test, xCallback, 27);
return ret;
}
anyway, your sio_FtKermitTx function accepts a char* in parameter, so changing your TXFIlestransfer parameters from string to char[] is not problematic.
Result:
After running C# program you will get this:

How to create wrapper for using C++ code in C?

I'm trying to do a C wrapper for a C++ third-party library because I need to use it in my C project.
I've seen examples of a C++ class wrapper but I don't undertood the process and I can't wrapper a C++ struct.
struct I want to wrapper:
struct confGlobal{
long int device;
string name;
int number;
string uid;
string message;
bool mode;
confiGlobal():device{LONG_MAX}, number{INT_MAX}{}
};
struct product{
string id;
string name;
};
struct category{
unsigned char id;
string name;
string description;
category():id{UCHAR_MAX}{}
};
struct subCategory{
unsigned char id;
string name;
string description;
unsigned char idRoot;
subCategory():id{UCHAR_MAX}, idRoot{UCHAR_MAX}{}
};
struct confPartner{
vector<struct product> tableProduct;
vector<struct category> tableCategory;
vector<struct subCategory> tableSubCategory;
};
For call to this method:
class my_API {
public:
static my_API* Instance(struct confGlobal cGlobal,
struct confPartner cPartner);
... another methods ...
private:
virtual ~my_API();
struct confGlobal cGlobal;
struct confPertner cPartner;
};
I need to fill this structs and call my_API::Instance() from C but my attempts have been unsuccessful.
wrapper.h
#ifdef __cplusplus
extern "C" {
#endif
struct confGlobal_wpr; // An opaque type that we'll use as a handle
typedef struct confGlobal_wpr confGlobal_wpr;
confGlobal_wpr *confGlobal_create(unsigned int device,
char *name,
int number,
char *uid,
char *message,
unsigned char mode);
struct product_wpr{
char id[4];
char name[30];
};
typedef struct product_wpr product_wpr;
struct category_wpr{
unsigned char id;
char name[3];
char description[30];
};
typedef struct category_wpr category_wpr;
struct subcategory_wpr{
unsigned char id;
char name[3];
char description[30];
unsigned char idRoot;
};
typedef struct subCategory_wpr subCategory_wpr;
struct confPartner_wpr; // An opaque type that we'll use as a handle
typedef struct confPartner_wpr confPartner_wpr;
confPartner_wpr *confPartner_create(Product_wpr tableProducts[],
unsigned char numProducts,
Category_wpr tableCategories[],
unsigned char numCategories,
SubCategory_wpr tableSubCategories[],
unsigned char numSubCategories);
struct my_api_wpr;
typedef struct my_api_wpr my_api_wpr;
my_api_wpr *my_api_create(struct confGlobal_wpr cGlobal,
struct confPartner_wpr cPartner);
#ifdef __cplusplus
}
#endif
wrapper.cpp
confGlobal_wpr *confGlobal_create(unsigned int device,
char *name,
int number,
char *uid,
char *message,
unsigned char mode)
{
confGlobal_wpr *cg;
struct confGlobal confiGlobal;
confiGlobal.name = name;
confiGlobal.device = device;
confiGlobal.number = number;
confiGlobal.uid = uid;
confiGlobal.message = message;
if (mode == 0)
confiGlobal.mode = false;
else
confiGlobal.mode = true;
return cg;
}
void confGlobal_destroy(confGlobal_wpr *cg)
{
if (cg == NULL)
return;
delete static_cast<confGlobal_wpr *>(cg->instance); // ERROR: invalid static_cast from type ‘confGlobal’ to type ‘confGlobal_wpr*’
free(cg);
}
confPartner_wpr *confPartner_create(product_wpr tableProducts_wpr[],
unsigned char numProducts,
category_wpr tableCategories_wpr[],
unsigned char numCategories,
subCategory_wpr tableSubCategories_wpr[],
unsigned char numSubCategories)
{
unsigned char i=0;
confPartner_wpr *cc;
struct confPartner cPartner;
vector< struct product> tableProduct;
vector< struct category> tableCategory;
vector< struct subCategory> tableSubCategory;
for (i=0; i<numProducts; i++)
{
struct product p;
p.id = tableProducts_wpr[i].id;
p.name = tableProducts_wpr[i].name;
tableProduct.push_back(p);
}
cPartner.tableProduct = tableProducts;
for (i=0; i<numCategories; i++)
{
struct category c;
c.id = tableCategories_wpr[i].id;
c.nombre = tableCategories_wpr[i].name;
c.descripcion = tableCategories_wpr[i].description;
tableCategory.push_back(c);
}
cPartner.tableCategory = tableCategory;
for (i=0; i<numSubCategories; i++)
{
struct subZona sc;
sc.id = tableSubCategories_wpr[i].id;
sc.name = tableSubCategories_wpr[i].name;
sc.description = tableSubCategories_wpr[i].description;
sc.idRoot = tableSubCategories_wpr[i].idRoot;
tableSubCategory.push_back(sc);
}
cPartner.tableSubCategory = tableSubCategory;
return cc;
}
my_api_wpr *my_api_create(struct confGlobal_wpr confiGlobal_wpr,
struct confPartner_wpr confiPartner_wpr)
{
my_api_wpr *my_api;
my_API *obj;
my_api = (typeof(my_api))malloc(sizeof(*my_api));
obj = my_API::Instance(confiGlobal_wpr, confiConsorcio_wpr);
/* With this compile and linked OK
confGlobal cg;
confPartner cc;
obj = my_API::Instance(cg, cc);
*/
my_api->obj = obj;
return my_api;
}
void my_api_destroy(ct_api_wpr *my_api)
{
if (my_api == NULL)
return;
delete static_cast<my_API *>(my_api->ptr_api); // ERROR: ‘virtual my_API::~my_API()’ is private within this context
free(my_api);
}
The output error when compile and linked with:
g++ -shared -o libwrapper.so *.cpp wrapper.h -l:libthird-party.a -L. -ldl -lrt -Wl,-rpath /usr/local/lib -lc
In function ‘my_api_wpr* my_api_create(confGlobal_wpr, confPartner_wpr)’:
error: no matching function for call to ‘my_API::Instance(confGlobal_wpr&, confPartner_wpr&)’
obj = my_API::Instance(confiGlobal_wpr, confiConsorcio_wpr);
^
my_API.h:30:20: note: candidate: static my_API* my_API::Instance(confGlobal, confPartner)
static my_API* Instance(struct confGlobal cGlobal, struct confiPartner cPartner);
^~~~~~~~
my_API.h:30:20: note: no known conversion for argument 1 from ‘confGlobal_wpr’ to ‘confGlobal’
You're forgetting that CT_API::Instance doesn't understand the "handle" types that you have created in C to wrap the C++ structures. This is precisely what the error message is telling you, if you read it. You must translate those back to the appropriate C++ types.
Firstly, since you are using "create"-style routines to build the structures and return them as a pointer, you should consider making your my_api_create function accept pointers instead. Particularly because the resulting handle types are forward-declared structs with no definition visible in C and it will not be possible for your C client to dereference them.
That highlights another issue. You are also not using these handles correctly from C++.
So, one thing at a time...
Your creation routine in C should be declared as:
my_api_wpr *my_api_create(struct confGlobal_wpr* cGlobal, struct confPartner_wpr* cPartner);
On the C++ side, you need to actually define your handle types. Something like:
extern "C" struct confGlobal_wpr {
struct confGlobal instance;
};
extern "C" struct confPartner_wpr {
struct confPartner instance;
};
extern "C" struct my_api_wpr {
my_API *ptr;
};
Now, your creation:
confGlobal_wpr *confGlobal_create(unsigned int device,
char *name,
int number,
char *uid,
char *message,
unsigned char mode)
{
confGlobal_wpr *cg = new confGlobal_wpr;
struct confGlobal& cGlobal = cg->instance; //<-- note the reference
// TODO: populate cGlobal as usual
return cg;
}
confPartner_wpr *confPartner_create(product_wpr tableProducts_wpr[],
unsigned char numProducts,
category_wpr tableCategories_wpr[],
unsigned char numCategories,
subCategory_wpr tableSubCategories_wpr[],
unsigned char numSubCategories)
{
confPartner_wpr *cc = new confPartner_wpr;
struct confPartner& cPartner = cc->instance; //<-- note the reference
// TODO: populate cPartner as usual
return cc;
}
my_api_wpr *my_api_create(struct confGlobal_wpr* cGlobal, struct confPartner_wpr* cPartner)
{
my_api_wpr *my_api = new my_api_wpr;
my_api->ptr = CT_API::Instance(cGlobal->instance, cPartner->instance);
return my_api;
}
You should also add corresponding _destroy methods for all the above.
To use C++ code in C project you need define wrapper functions with C calling convention - extern "C"(turning off C++ name mangling/decoration) , and call them and only them in your C project. Inside those C functions you can use C++ code. Pass to C wrapper functions only types that C understands. You can create intermediate structures for passing data to C wrapper functions. Then you need copy data to types that C++ class expects. In you particular case you incorrectly pass confGlobal_wpr wrapper struct but C++ method requires confGlobal, and compiler complains on this directly.
Below is observable snippet how to use C++ code from C code:
Foo.h
#include <string>
class Bar
{
public:
Bar(std::string s) : s_(s)
{
}
std::string s_;
};
class Foo
{
public:
Foo(Bar) {}
};
CWrappers.h // include this header to C project
struct BarWrapper
{
char data[100] = "";
};
#ifdef __cplusplus
extern "C" {
#endif
BarWrapper createFoo(char *c);
#ifdef __cplusplus
}
#endif
Wrapper.cpp
#include <algorithm>
#include "Foo.h"
#include "CWrappers.h"
// input and output to this C function should be understandable for C
BarWrapper createFoo(char *c)
{
// inside you can use C++
std::string data(c);
Bar bar(data);
Foo * foo = new Foo(bar);
BarWrapper barWrapper;
std::copy(data.begin(), data.end(), barWrapper.data);
return barWrapper; // pack data to C struct wrapper (that has no C++ specific)
}
C Project
#include "CWrappers.h"
int main()
{
BarWrapper barWrapper = createFoo((char *)"test");
}
Structs that contain anything other than primitive data types common to C and C++ largely can't be wrapped in the way you want. In this particular case, you have ::std::strings in your struct. And they definitely can't be accessed reasonably from C at all.
Additionally, the structs contain bool and I don't know if newer versions of the C standard have bool or define it in such a way that it will result in layout compatible structs with C++ implementations on the same platform.
There are solutions to this problem. But they involve using opaque pointers to the struct in C, and always calling functions to access its methods. I will try to whip up an example of how this might work for a really simple struct.
Looking more carefully at your code, it looks like you need a sort of thunk layer that takes the C struct and (in C++) hand-converts it to the C++ struct and returns a pointer to a dynamically allocated C++ struct that you can then pass to other C++ functions that have been exposed to C.

Initialize static variables declared in header

I'm changing the class implementation of a large class for a company project that has several static variables declared as private members of the class. There are many arrays and structs declared in the class header that utilize these static variables. I now need to assign the static data members values from my main function somehow. I tried assigning the static variables through the constructor but the header is declared prior to the constructor call so that wasn't possible.
For example, if I have
class Data
{
private:
static unsigned int numReadings = 10;
static unsigned int numMeters = 4;
unsigned int array[numMeters];
}
I would want to change it such that I could set numReadings and numMeters from my main function somehow, so it will allow all of my arrays and structs that utilize numMeters and numReadings to be initialized properly.
Is there a way to do this in C++? Of course I could always change my class design and set these in the constructor somehow but I'd like to avoid that if I can as it will take quite a long time.
You cannot do it in the main function, but you can do it in the main.cpp file:
// Main.cpp
#include <iostream>
#include "T.h"
using namespace std;
int T::a = 0xff;
int main()
{
T t; // Prints 255
return 0;
}
// T.h
#pragma once
#include <iostream>
using namespace std;
class T {
public:
T() { cout << a << endl; }
private:
static int a;
};
Have you tried making them public and accessing them with Data::numReadings = 10?
UPDATE:
#include <cstdlib>
using namespace std;
/* * */
class Asdf
{
public:
static int a;
};
int Asdf::a = 0;
int main(int argc, char** argv) {
Asdf::a = 2;
return 0;
}
Regardless of the accessibility of these variables, you need to define and initialize the static members outside the class definition:
// header
class Data
{
private:
static unsigned int numReadings;
static unsigned int numMeters;
unsigned int array[numMeters]; //<=see edit
};
// class implementation file
unsigned int Data::numReadings = 10;
unsigned int Data::numMeters = 4;
This is part of the implementation of the class and shouldn't be in the header (ODR rule).
Of course, if you want to access these variables (which are shared among all instances of the class) from outside, you need to make them public, or better, foresee and accessor.
Edit:
As the question is formulated around the static issue, I didn't notice the variable length array : this is not standard c++, although some compilers might accept it as a non-standard extension.
To do this properly, you should define a vector and initialize it at construction:
class Data
{
public:
Data ();
private:
static unsigned int numReadings;
static unsigned int numMeters;
vector<unsigned int> mycontainer; //<=for dynamic size
};
Data::Data() : mycontainer(numMeters) { } // initialize object with right size

C++ class member function callback

I have the following problem. I have a function from an external library (which cannot be modified) like this:
void externalFunction(int n, void udf(double*) );
I would like to pass as the udf function above a function member of an existing class. Please look at the following code:
// External function (tipically from an external library)
void externalFunction(int n, void udf(double*) )
{
// do something
}
// User Defined Function (UDF)
void myUDF(double* a)
{
// do something
}
// Class containing the User Defined Function (UDF)
class myClass
{
public:
void classUDF(double* a)
{
// do something...
};
};
int main()
{
int n=1;
// The UDF to be supplied is myUDF
externalFunction(n, myUDF);
// The UDF is the classUDF member function of a myClass object
myClass myClassObj;
externalFunction(n, myClassObj.classUDF); // ERROR!!
}
I cannot declare the classUDF member function as a static function, so the last line of the code above results in a compilation error!
This is impossible to do - in c++, you must use either a free function, or a static member function, or (in c++11) a lambda without capture to get a function pointer.
GCC allows you to create nested function which could do what you want, but only in C. It uses so-called trampolines to do that (basically small pieces of dynamically generated code). It would be possible to use this feature, but only if you split some of the code calling externalFunction to a separate C module.
Another possibility would be generating code at runtime eg. using libjit.
So if you're fine with non-reenrant function, create a global/static variable which will point to this and use it in your static function.
class myClass
{
public:
static myClass* callback_this;
static void classUDF(double* a)
{
callback_this.realUDF(a);
};
};
Its really horrible code, but I'm afraid you're out of luck with such a bad design as your externalFunction.
You can use Boost bind or TR1 bind (on recent compilers);;
externalFunction(n, boost::bind(&myClass::classUDF, boost::ref(myClassObj)));
Unfortunately, I lived in a pipe dream for the last 10 minutes. The only way forward is to call the target using some kind of a static wrapper function. The other answers have various neat (compiler-specific) tidbits on that, but here's the main trick:
void externalFunction(int n, void (*udf)(double*) )
{ double x; udf(&x); }
myClass myClassObj;
void wrapper(double* d) { myClassObj.classUDF(d); }
int main()
{
externalFunction(1, &wrapper);
}
std::function<>
Store a bound function in a variable like this:
std::function<void(double*)> stored = std::bind(&myClass::classUDF, boost::ref(myClassObj))
(assuming C++0x support in compiler now. I'm sure Boost has a boost::function<> somewhere)
Vanilla C++ pointers-to-member-function
Without magic like that, you'd need pointer-to-memberfunction syntax:
See also live on http://ideone.com/Ld7It
Edit to clarify to the commenters, obviously this only works iff you have control over the definition of externalFunction. This is in direct response to the /broken/ snippet int the OP.
struct myClass
{
void classUDF(double* a) { };
};
void externalFunction(int n, void (myClass::*udf)(double*) )
{
myClass myClassObj;
double x;
(myClassObj.*udf)(&x);
}
int main()
{
externalFunction(1, &myClass::classUDF);
}
C++98 idiomatic solution
// mem_fun_ref example
#include <iostream>
#include <functional>
#include <vector>
#include <algorithm>
#include <string>
int main ()
{
std::vector<std::string> numbers;
// populate vector:
numbers.push_back("one");
numbers.push_back("two");
numbers.push_back("three");
numbers.push_back("four");
numbers.push_back("five");
std::vector <int> lengths (numbers.size());
std::transform (numbers.begin(), numbers.end(), lengths.begin(),
std::mem_fun_ref(&std::string::length));
for (int i=0; i<5; i++) {
std::cout << numbers[i] << " has " << lengths[i] << " letters.\n";
}
return 0;
}
Here is how I do this, when MyClass is a singleton:
void externalFunction(int n, void udf(double) );
class MyClass
{
public:
static MyClass* m_this;
MyClass(){ m_this = this; }
static void mycallback(double* x){ m_this->myrealcallback(x); }
void myrealcallback(double* x);
}
int main()
{
MyClass myClass;
externalFunction(0, MyClass::mycallback);
}

Calling C++ function from C#

I have a the following C++ function
void FillAndReturnString(char ** someString)
{
char sourceString[] = "test";
*someString = new char[5];
memcpy(*someString, sourceString, 5);
}
It is declared as
extern "C"
{
__declspec(dllexport) void __cdecl FillAndReturnString(char ** someString);
}
How do I call this function from C#?
Thanks
With P/Invoke.
You need to know that you're allocating unmanaged memory block in your c++ function, so it will not be possible to pass a managed String or Array object from C# code to 'hold' the char array.
One approach is to define 'Delete' function in your native dll and call it to deallocate the memory. On the managed side, you can use IntPtr structure to temporarily hold a pointer to c++ char array.
// c++ function (modified)
void __cdecl FillAndReturnString(char ** someString)
{
*someString = new char[5];
strcpy_s(*someString, "test", 5); // use safe strcpy
}
void __cdecl DeleteString(char* someString)
{
delete[] someString
}
// c# class
using System;
using System.Runtime.InteropServices;
namespace Example
{
public static class PInvoke
{
[DllImport("YourDllName.dll")]
static extern public void FillAndReturnString(ref IntPtr ptr);
[DllImport("YourDllName.dll")]
static extern public void DeleteString(IntPtr ptr);
}
class Program
{
static void Main(string[] args)
{
IntPtr ptr = IntPtr.Zero;
PInvoke.FillAndReturnString(ref ptr);
String s = Marshal.PtrToStringAnsi(ptr);
Console.WriteLine(s);
PInvoke.Delete(ptr);
}
}
}