I have a large library written in C that I would like to use as a DLL in a C# program. Most of the C code will be used by the libraries own functions, but I do need one function to be able to be called from the C# project.
So there's an example C function below
__declspec(dllexport) char* test(char* a){
char* b = "World";
char* result = malloc(strlen(a) + strlen(b) + 1);
strcpy(result, a);
strcpy(result, b);
return result;
}
Now in the C# code I have got using System.Running.InteropServices;
and also [DllImport("mydll.dll")] but I'm not sure how to declared the function.
public static extern char* test(char* a); obviously doesn't work because C# doesn't support pointers like C does.
So how should I pass a string to this C function and have it return a string as well?
You're looking for a MarshalAs attribute:
[DllImport("mydll.dll")]
static public int test([MarshalAs(UnmanagedType.LPStr)]String a);
As for returning a dynamically allocated C string, bad idea. How will you reliably de-allocate the string? It's a recipe for a memory leak. Allocate a byte array in C#, pin it and pass it to the C code along with its size so the C code can copy the result into it. Then convert to a string using System.Text.Encoding.ASCII.GetString().
Related
I am wrapping a C++ object and it has certain methods that return by value, and I would like the C# wrapper method to return a native type without having to allocate and de-allocate memory in C++-land. In this situation I think copying data into the return type is appropriate but I can't figure out how to do it in a nice way.
As a simple working example the following C++ code is a file parser. I only list the the std::pair<int,int> version() method but you can imagine other that return a small constant std::array, list, etc.
#include <utility>
#include <tuple>
class MyFile {
public:
std::pair<int,int> version() const noexcept {
return {version_major_, version_minor_};
}
private:
int version_major_;
int version_minor_;
};
Using Out Arguments
I like this one the best, but I can't for the life of me figure out how to remove the out arguments for just the C# wrapper! C# is responsible for the memory and just passes it to C++ to fill in. This requires some C++ wrappers using %extend but that is ok.
I really want a final C# method with signature of public Tuple<int, int> version()
SWIG code
%module parser
%include "typemaps.i"
%rename("$ignore", fullname=1) MyFile::version() const noexcept;
%extend MyFile {
void version(int* major_out, int* minor_out) {
std::tie(*major_out, *minor_out) = self->version();
}
}
%typemap(ctype, out="void *") int* major_out, int* minor_out "int *"
%typemap(imtype, out="void") int* major_out, int* minor_out "out int"
%typemap(cstype) int* major_out, int* minor_out "out int"
%typemap(cstype) void MyFile::version "Tuple<int, int>"
%typemap(csin, pre=" int tmp_$csinput = 0;") int* major_out, int* minor_out "out tmp_$csinput"
// implment the C# function that returns the type specified above
%typemap(csout, noblock=1, excode=SWIGEXCODE) void MyFile::version
{
$imcall;$excode
major_out = tmp_major_out;
minor_out = tmp_minor_out;
return new Tuple<int, int>(tmp_major_out, tmp_minor_out);
}
Generated C++ wrapper
SWIGEXPORT void SWIGSTDCALL CSharp_parser_MyFile_version(void * jarg1, int * jarg2, int * jarg3) {
MyFile *arg1 = (MyFile *) 0 ;
int *arg2 = (int *) 0 ;
int *arg3 = (int *) 0 ;
arg1 = (MyFile *)jarg1;
arg2 = (int *)jarg2;
arg3 = (int *)jarg3;
MyFile_version(arg1,arg2,arg3);
}
Generated PInvoke Code
[global::System.Runtime.InteropServices.DllImport("parser", EntryPoint="CSharp_parser_MyFile_version")]
public static extern void MyFile_version(global::System.Runtime.InteropServices.HandleRef jarg1, out int jarg2, out int jarg3);
Generated C# Bindings
public Tuple<int, int> version(out int major_out, out int minor_out) {
int tmp_major_out = 0;
int tmp_minor_out = 0;
parserPINVOKE.MyFile_version(swigCPtr, out tmp_major_out, out tmp_minor_out);
major_out = tmp_major_out;
minor_out = tmp_minor_out;
return new Tuple<int, int>(tmp_major_out, tmp_minor_out);
}
Other methods
I have tried other methods but to keep the question short I won't post all the generated code here.
Returning pointer to a static array
this works, but requires static data for every method that I want to work this way. This doesn't scale. I could easily run into lifetime issues if I try to do this with member data that I assume will live long enough for C# to copy.
wrap the default generated code in a csout typemap
This also works but allocated and de-allocates a lot for a function just returning two ints! you end up with a C# wrapper something like:
public Tuple<int, int> version() {
System.IntPtr cPtr = parserPINVOKE.MyFile_version(swigCPtr);
pair_of_int tmp = new pair_of_int(cPtr, false);
Tuple<int, int> ret = new Tuple<int, int>(tmp.first, tmp.second);
tmp.Dispose();
return ret;
}
Other SO Questions
a similar question is this one, but that deals with java. Java has JNI and Pyhton has a C interface that lets you create memory/object in the C code and return it... I don't see a way to do that in .NET withou C++/CLI (which SWIG isn't using).
I am working on C#.Net application which uses C-based library. As it needs C# Wrapper I am implementing code to marshal functions from C-based library to be accessible in C# and map data type correctly.
I have a function in library which Takes A char array by reference, The function contains logic to update array with values in it. So, At function call we can pass null array and access result value after its been called.
Objective: to pass null char array and return value by reference
The C-dll function:
int function_call(char ** var);
The C function call code:
char *name = NULL;
int val = function_Call(&name);
The C# wrapper code:
[DllImport("mylibrary.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int function_call([In] string[] val);
The C# function call code:
string[] name = null;
int ret = function_call(name);
I came across similar queries :
How to get char** using C#? [duplicate]
How do I marshal a pointer to an array of pointers to structures?
marshaling char**
C# equivalent to C const char**
Tried all of them but did not work. returns null value.
Is there a simple working way to marshal Char ** ?
You can simply marshal it as IntPtr :
[DllImport("mylibrary.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int function_call(IntPtr val);
Just that on function call side, allocate mem to pointer and to access the data held by pointer : Marshal data from an unmanaged block of memory to the type specified by a generic type parameter.
I am having C++ code like this just to try out to get the string to C# application from c++ dll.
int GetValue(void *pBuffer)
{
int x = 0;
String^ temp;
temp = "TestStringtest1test2";
memcpy(pBuffer, &temp,sizeof(temp));
Console::WriteLine(temp);
return x;
}
on c# side all I am doing is
[DllImport("Cplusplusapp.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public static extern int GetValue(StringBuilder pBuffer);
StringBuilder Buffer = new StringBuilder(100);
int x = GetValue(Buffer);
Console.WriteLine(Buffer);
I have tried marshalling and various other suggestions but I am not able to understand why I am getting garbage values.Its fairly simple but what is that I am missing.
Address of temp IS NOT string itself then memcpy won't work as expected. Moreover sizeof(String) will return size of System.String object (4 bytes on 32 bit machine), not string length.
If you need to copy a value from a managed string to an unmanaged pointer you have to follow next steps.
First of all System.String is always UNICODE then you won't have char* but wchar_t* (but you can convert it to what you need with usual helper macros). To convert a string from System.String to wchar_t* call Marshal::StringToBSTR():
String^ temp = L"My string";
BSTR bstr = Marhshal::StringToBSTR(temp);
memcpy(pBuffer, bstr, SysStringLength(bstr));
Marshal::FreeBSTR(bstr);
Of course if you do not need to use a System.String you can skip all of these simply not assigning your string to System.String. Change it to wchar_t* or char* according to how you'll import that function (CharSet.Ansi or not), take a look to other Marshal::StringToXYZ functions, I would create e temporary string from System::String and then I would strcpy to destination buffer (check functions with Ansi suffix for char* versions). See this post here on SO for an example of that.
I have a DLL file that is written in C. I am try to use C DLL in my c# code. C program method return int** . int** in c and int[][] in c# is same?
I am getting an error while returning a value from c program.
c method
__declspec(dllexport) int someMethod
(
size_t *foo,
int **bar
)
{
*foo = 10;
**bar = 10;
}
My c# code
[DllImport(#"my.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true, BestFitMapping = true, EntryPoint = "someMethod")]
public unsafe static extern int someMethod
(
out Int16 foo,
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(JaggedArrayMarshaler))]
out int[][] bar
);
C's int** and C#'s int[][] are similar in concept, but different at the binary level:
int** is a pointer to pointer, into the raw data in unmanaged heap memory.
int[][] is a managed reference to a managed array of managed references to managed arrays; each points to the array's header (which contains its length) instead of its raw data.
I don't know what would be easiest to marshal for C#. Can SAFEARRAY be nested? If so, it would probably easily map to C# arrays.
The solution that's sure to work is to use a C++/CLI DLL as glue between the two codes, to convert the int** into a cli::array<cli::array<int>^>^ (which involves copying the pointed data) before returning to C#.
Assuming the C function prototype is correct, I think you should declare it thusly on the C# side:
public unsafe static extern int someMethod
(
out Int16 foo,
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0, ArraySubType=UnmanagedType.I2)]
out int[] bar
);
However, I fear a memory leak. I'm not sure how the unmanaged array can be deallocated.
I have a C++ dll that has a function that returns a c string and I have a C# program that calls this function and returns the data to a C# string. Here's what I mean
__declspec(dllexport) const char* function (const char* str) {
std::string stdString( str );
std::cout << stdString.c_str() << std::endl; // this prints fine, no data loss
return stdString.c_str();
}
And here's the C# code
[DllImport("MyDLL.dll")]
public static extern string function(string data);
string blah = function("blah");
Console.WriteLine(blah); // doesn't print anything...
When I look into the locals it says variable 'blah' is equal to "".
What happened to the data?
Your C++ code is broken. You are returning a pointer to a local variable. It no longer exists after the function returns. This tends to work by accident in a C++ program but is strong Undefined Behavior. It cannot possibly work in an interop scenario, the pinvoke marshaler's use of the stack will overwrite the string.
A declaration that could work:
void function (const char* str, char* output, size_t outputLength)
Use a StringBuilder in the [DllImport] declaration for the output argument and pass an initialized one with sufficient Capacity.