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);
}
}
}
Related
I am creating a C++ library from a C library.
C library have functions that contain callback,and callback have also arg(number of arguments).
I want to expose callback class override functions to the user so that the user can access callback function data.
As shown in this example user use callback class
To simplify, I created the smallest version of my issue.
Here I am trying to use a standard C function with a callback and assign a pure virtual function as the callback.
/// library.h part of code //////
#include <iostream>
extern "C" {
#include<stdio.h>
}
extern "C" {
void qsort(void *base, size_t nmemb, size_t size, int (*)(const void *, const void *));
}
struct callback{
virtual int compare(const void *a, const void *b)=0;
};
struct myclass{
myclass()=default;
callback *callback_;
void mycallback(callback& cb){
callback_ = &cb;
}
void sortdata(int *array,int size){
qsort((void*)array,size,sizeof(int),callback::compare);
//qsort((void*)array,size,sizeof(int),&callback_->compare);
};
};
and
////Application.cpp part code ///////////////////
//#include "library.h"
class usercallback : public callback{
public:
//currenty only one callback but in my case many
virtual int compare(const void *a, const void *b) override{
std::cout<<__PRETTY_FUNCTION__<<std::endl;
return *((int*)a) < *((int*)b);
}
};
int main(){
int array[] = {1,2,4,5,7,8,93,2,4,6,7,89,43,2,4,5};
int size = sizeof(array)/sizeof(array[0]);
myclass myobj;
usercallback cb;
myobj.mycallback(cb);
myobj.sortdata(array,size);
}
this program gives error and i gauss because of C++ internally pass this object as arg.
error: invalid use of non-static member function ‘virtual int callback::compare(const void*, const void*)’
23 | qsort((void*)array,size,sizeof(int),callback::compare);
I have also read this article.but it not solve my problem.
i also know that it can be solved by using static, but i want to expose a class to the users, as in this example.
code building on Ubuntu.
The ideal solution is to not paint yourself in that corner in the first place. If you have any leeway at all towards addressing this differently from a design standpoint, that should be your goto.
That being said, if you are stuck, and HAVE to make that interoperability work, you'll have to marhsall the this available from a free-floating function, which means a global variable. A private static member variable is the best approach for this here, and ideally, it should be thread_local for safety.
For example:
// library.h
struct myclass{
myclass()=default;
void mycallback(callback& cb){
callback_ = &cb;
}
void sortdata(int *array,int size){
active_instance_ = this;
qsort((void*)array,size,sizeof(int),compare_entry);
active_instance_ = nullptr;
};
private:
callback *callback_;
static thread_local myclass* active_instance_;
static int compare_entry(const void *a, const void *b) {
assert(active_instance_);
active_instance_->callback_->compare(a, b);
}
};
// library.cpp
thread_local myclass* myclass::active_instance_ = nullptr;
Obviously, this is only fine for callbacks that only live until the stack unwinds. It is inappropriate for anything involving long-lived callbacks.
For those, hopefully, the API in question provides a void* user_data pointer in which you can store this. If so, then you would be able to do:
//assuming
void register_callback(void* user_data, void (*cb)(void*, int));
// library.h
struct myclass{
myclass()=default;
void mycallback(callback& cb){
callback_ = &cb;
register_callback(this, callback_entry);
}
private:
callback *callback_;
static int callback_entry(void* user_data, int p) {
auto self = reinterpret_cast<myclass*>(user_data);
self->callback_->some_method(p);
}
};
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:
I am trying to marshal a callback function in C++/CLI. The following example only prints an "H" so the marshaling of the wide chars to the managed string doesn't seem to work even though I have specified [MarshalAs(UnmanagedType::LPWStr)].
Also tried marshaling using BSTRs but got the same result.
typedef void(*PFN_PRINT)(const wchar_t*);
void PrintHej(PFN_PRINT pfnPrint)
{
pfnPrint(L"Hej");
}
ref class PrinterClass
{
public:
static void Printer(String^ str)
{
Console::WriteLine(str);
}
};
delegate void PrinterDelegate([MarshalAs(UnmanagedType::LPWStr)] String^);
int main(array<System::String ^> ^args)
{
PrinterDelegate^ pDelegate = gcnew PrinterDelegate(&PrinterClass::Printer);
GCHandle gch = GCHandle::Alloc(pDelegate);
IntPtr pFn = Marshal::GetFunctionPointerForDelegate(pDelegate);
PrintHej(static_cast<PFN_PRINT>(pFn.ToPointer()));
gch.Free();
return 0;
}
First post here and I've tried to look at previous similar posts but none of them seem to work or do quite what I want.
I have some C code, call it library.c. I've removed a lot of the code and simplified it.
// libary.c
// A callback function that takes an int
void (*library_cb)(int);
void init(void (*cb())) {
// some other code
library_cb = cb;
}
void sample() {
int data;
// execute a bunch of code and then call the callback function
(*library_cb)(data);
}
Now I have c++ code that defines the callback function that I want to pass to the code in library.c
// someclass.cpp
class SomeClass {
public:
SomeClass() {
};
~SomeClass() {
};
void callback(int data) {
// Do some stuff
}
};
And then in main.cpp I want to do something like
// main.cpp
extern "C" {
#include "library.h"
}
#include "someclass.h"
SomeClass some_class;
int main() {
init(&some_class.callback) // obviously doesn't work
while(true) {
sample(); // this would call callback in SomeClass
}
}
Now I know one solution is to define callback as
static void callback(int data)
But I was wondering if there are any other ways to do this. From what I read, std::function might help or std::mem_fn. But I can't seem to figure out how.
I haven't included the header files and I wrote this code as an example of my problem so there might be some syntax errors, but hopefully the question/goal is clear.
Edit:
I should have mentioned that I can edit the c library.
Reading the answers, it seems I can change the c library to also accept a void* pointer to the class object to get this to work. Could someone show me an example for this case please? I'm super new to interfacing c code with c++.
Passing a pointer to a C++ member function to a C API library
... is not possible.
From what I read, std::function might help or std::mem_fn
Neither of those can be called in C either, but keep reading 'till the end.
C only has regular non-member function pointers so those are the only function pointers that a C program can call. In C++, such pointer can point to either a free function or a static member function.
Within the C++ implementation of such static- or non-member function you can of course do anything within the power of C++ (although, letting an exception escape the function would be bad), so you can indeed call a non-static member function there.
But to call a non-static member function, there needs to be an instance. A static object is a trivial solution, but is not very flexible and only useful in a few situations.
Well designed callback API's in C let user of the API register a generic data pointer (i.e. void*) in addition to a function pointer, and that data pointer will be forwarded to the callback. This design allows the callbacks to be stateful - the state is stored in the pointed object. When using such C API, you can pass a pointer to an object whose member functions the callback can then call. Or, you could pass a data pointer to a std::function or some other stateful type erasing function wrapper, and use a generic free function that simply forwards the call to the wrapper.
Your C API is not very usable. Here's how I'd do it:
The callback must at least take a user-provided void* parameter that the library doesn't interpret in any way. Without this parameter, callbacks are useless. Yes, they really are useless and the users of your API users will hate you for that.
If you want the callback to be able to modify the value of its parameter, you can pass the address of the void* parameter. That is useful for e.g. allocation-on-registration and similar uses where the parameter changes during callback's execution. This makes the library completely decoupled from the use of the pointer: not only it doesn't interpret the pointer, but it doesn't keep its value constant.
The library API symbols are all prefixed to prevent collisions in the global namespace.
Typedefs are used as needed to ensure readable code. Typing out function pointer types is tedious at best.
The header is guarded against multiple-inclusion, i.e. it must be OK to include it multiple times in a translation unit, without any errors.
The header declares a C interface when compiled in a C++ translation unit, since, well: the interface is a C one. C++ mangles the symbol names and the header will declare binary-incompatible symbols.
The header declares the C interface noexcept in C++11. This presents optimization opportunities to the C++ users.
Consider the library registering more than one callback, as well as possibly invoking the callback on registration and deregistration: those make interoperation with other programming languages much easier.
library.h - usable from C and C++
#pragma once
#ifdef __cplusplus
extern "C" {
#pragma GCC diagnostic push
// clang erroneously issues a warning in spite of extern "C" linkage
#pragma GCC diagnostic ignored "-Wc++17-compat-mangling"
#endif
#ifndef LIBRARY_NOEXCEPT
#if __cplusplus >= 201103L
// c.f. https://stackoverflow.com/q/24362616/1329652
#define LIBRARY_NOEXCEPT noexcept
#else
#define LIBRARY_NOEXCEPT
#endif
#endif
enum library_register_enum { LIBRARY_REG_FAILURE = 0, LIBRARY_REG_SUCCESS = 1, LIBRARY_REG_DUPLICATE = -1 };
enum library_call_enum { LIBRARY_SAMPLE, LIBRARY_REGISTER, LIBRARY_DEREGISTER };
typedef enum library_register_enum library_register_result;
typedef enum library_call_enum library_call_type;
#if __cplusplus >= 201103L
void library_callback_dummy(library_call_type, int, void**) LIBRARY_NOEXCEPT;
using library_callback = decltype(&library_callback_dummy);
#else
typedef void (*library_callback)(library_call_type, int, void**);
#endif
void library_init(void) LIBRARY_NOEXCEPT;
library_register_result library_register_callback(library_callback cb, void *cb_param) LIBRARY_NOEXCEPT;
void library_deregister_callback(library_callback cb, void *cb_param) LIBRARY_NOEXCEPT;
void library_deregister_any_callback(library_callback cb) LIBRARY_NOEXCEPT;
void library_deregister_all_callbacks(void) LIBRARY_NOEXCEPT;
void library_deinit(void) LIBRARY_NOEXCEPT;
void library_sample(void) LIBRARY_NOEXCEPT;
#ifdef __cplusplus
#pragma GCC diagnostic pop
}
#endif
Below note that the private data and functions, i.e. those not part of the API, are declared so (static).
library.c - the implementation
#include "library.h"
#include <stdlib.h>
typedef struct callback_s {
struct callback_s *next;
library_callback function;
void *parameter;
} callback;
static callback *cb_head;
void library_init(void) { /* some other code */
}
void library_deinit(void) { library_deregister_all_callbacks(); }
library_register_result library_register_callback(library_callback cb, void *cb_param) {
callback *el = cb_head;
while (el) {
if (el->function == cb && el->parameter == cb_param) return LIBRARY_REG_DUPLICATE;
el = el->next;
}
el = malloc(sizeof(callback));
if (!el) return LIBRARY_REG_FAILURE;
el->next = cb_head;
el->function = cb;
el->parameter = cb_param;
cb_head = el;
cb(LIBRARY_REGISTER, 0, &el->parameter);
return LIBRARY_REG_SUCCESS;
}
static int match_callback(const callback *el, library_callback cb, void *cb_param) {
return el && el->function == cb && el->parameter == cb_param;
}
static int match_any_callback(const callback *el, library_callback cb, void *cb_param) {
return el && el->function == cb;
}
static int match_all_callbacks(const callback *el, library_callback cb, void *cb_param) {
return !!el;
}
typedef int (*matcher)(const callback *, library_callback, void *);
static void deregister_callback(matcher match, library_callback cb, void *cb_param) {
callback **p = &cb_head;
while (*p) {
callback *el = *p;
if (match(el, cb, cb_param)) {
*p = el->next;
el->function(LIBRARY_DEREGISTER, 0, &el->parameter);
free(el);
} else
p = &el->next;
}
}
void library_deregister_callback(library_callback cb, void *cb_param) {
deregister_callback(match_callback, cb, cb_param);
}
void library_deregister_any_callback(library_callback cb) {
deregister_callback(match_any_callback, cb, NULL);
}
void library_deregister_all_callbacks(void) {
deregister_callback(match_all_callbacks, NULL, NULL);
}
void library_sample(void) {
int data = 42;
// execute a bunch of code and then call the callback function
callback *el = cb_head;
while (el) {
el->function(LIBRARY_SAMPLE, data, &el->parameter);
el = el->next;
}
}
That way, the user registering the callback can pass arbitrary data to the callback. The library-using code would be implemented in C++ as follows:
// https://github.com/KubaO/stackoverflown/tree/master/questions/c-cpp-library-api-53643120
#include <iostream>
#include <memory>
#include <string>
#include "library.h"
struct Data {
std::string payload;
static int counter;
void print(int value) {
++counter;
std::cout << counter << ": " << value << ", " << payload << std::endl;
}
};
int Data::counter;
extern "C" void callback1(library_call_type type, int value, void **param) noexcept {
if (type == LIBRARY_SAMPLE) {
auto *data = static_cast<Data *>(*param);
data->print(value);
}
}
using DataPrintFn = std::function<void(int)>;
extern "C" void callback2(library_call_type type, int value, void **param) noexcept {
assert(param && *param);
auto *fun = static_cast<DataPrintFn *>(*param);
if (type == LIBRARY_SAMPLE)
(*fun)(value);
else if (type == LIBRARY_DEREGISTER) {
delete fun;
*param = nullptr;
}
}
void register_callback(Data *data) {
library_register_callback(&callback1, data);
}
template <typename F>
void register_callback(F &&fun) {
auto f = std::make_unique<DataPrintFn>(std::forward<F>(fun));
library_deregister_callback(callback2, f.get());
library_register_callback(callback2, f.release());
// the callback will retain the functor
}
int main() {
Data data;
data.payload = "payload";
library_init();
register_callback(&data);
register_callback([&](int value) noexcept { data.print(value); });
library_sample();
library_sample();
library_deinit(); // must happen before the 'data' is destructed
assert(data.counter == 4);
}
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.