I am writing C# code that call a C library and something it is not quite clear in my mind.
The C function has this signature:
double* DoSomeStuff(double* input,int numberOfElements);
I have mapped the function as:
[System.Runtime.InteropServices.DllImportAttribute("myDll.dll", EntryPoint="DoSomeStuff")]
public static extern System.IntPtr DoSomeStuff(ref double input, int numberOfElements) ;
The input value is an array, so the C function will expect a contiguous memory layout. I am more familiar with C++ than C#. In C++ I'd used a std::vector to store the data and then I would use the data() method to get the pointer and exchange the information with C code. std::vector guarantees a contiguous layout memory.
Which data structure can I used in C#? Is there anything like std::vector in C#?
I have faced before the same problem for a string (In C++ std::string is just a std::vector with some make up). And I have solve the problem using:
System.IntPtr stringExample = Marshal.StringToHGlobalAnsi("StringExample");
The static function does the job for me. There is anything like this function for other types?
I have asked already too many questions, I think the most important one is: what is the best practise to solve this kind of problem?
Thanks
1)
Define the input as IntPtr:
[System.Runtime.InteropServices.DllImportAttribute("myDll.dll", EntryPoint="DoSomeStuff")]
public static extern System.IntPtr DoSomeStuff(IntPtr input, int numberOfElements) ;
2)
Create an array in a fixed block, then create an IntPtr from the Pointer and then pass it to DoSomeStuff.
double[] input = new double[20];
IntPtr result = IntPtr.Zero;
fixed(double* d = &input[0])
{
result = DoSomeStuff(new InptPtr(d), 20);
}
...
Reason for the fixed block is so that GC does not move the array while unmanaged code is populating it.
To make your example work you should define the siganture of the extern function as follows:
[System.Runtime.InteropServices.DllImportAttribute("myDll.dll", EntryPoint="DoSomeStuff")]
public static extern System.IntPtr DoSomeStuff([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)], int numberOfElements);
The second (named) parameter of MarshalAs attaribute tells to the marshaller where the size of the array stored.
Regarding the second question, C# has List<Type> class that behaves similary to std:vector<Type>. However, I don't think you can directly provide it to the marshaller. What you can do is to use ToArray() methor of the List class, to get an array.
Related
I am trying to call a function that converts sql queries between dialects. I am using an open-source project's DLL to use the functions for conversion in a C# university project. The problem i am facing is that i am getting a access violation reading location.
I've read some posts here on stack overflow which suggest that there might be a bad pointer somewhere, but i cannot find where. My pointers are not corrupt
The function for the conversion is this :
int ConvertSql(void *parser, const char *input, int64_t size, const char
**output, int64_t *out_size, int64_t *lines)
{
if(parser == NULL)
return -1;
SqlParser *sql_parser = (SqlParser*)parser;
// Run conversion
sql_parser->Convert(input, size, output, out_size, lines);
return 0;
}
I am calling the function in C#
char *parentInput;
fixed(char *input = &inputStr.ToCharArray()[0])
{
parentInput = input;
}
char** output = null;
Int64 out_size = 0;
Int64 lines = 0;
Int64 size = inputStr.Length;
Console.WriteLine(new IntPtr(&out_size)+" "+ new IntPtr(&lines)+" "+new IntPtr(&parserObj)+" "+new IntPtr(output));
int result = ConvertSql(&parserObj, intputStr, size, output, &out_size, &lines);
i get my parser object from this code which works without errors:
IntPtr parserObj = CreateParserObject();
the dllimport for the funtions are using this code:
[DllImport(dllName: "PATHTODLLFOLDER\\sqlparser.dll", EntryPoint = "CreateParserObject", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr CreateParserObject();
[DllImport(dllName: "PATHTODLLFOLDER\\sqlparser.dll", EntryPoint = "ConvertSql", CallingConvention = CallingConvention.Cdecl)]
public unsafe static extern int ConvertSql(void *parser, String input, Int64 size, char **output, Int64 *out_size, Int64 *lines);
In .NET, calling an unmanaged method through P/invoke (which is what happens when you call an extern method) involves various type conversions on the parameters, which is known as "marshalling" and is done automatically by a part of the runtime known as the "marshaller".
In general, it's a terrible idea to marshal pointers. Instead, use the CLR marshaller's ability to convert certain types to pointers for you by changing the signature of your P/invoked method:
// split on multiple lines for readability
[DllImport("PATHTODLLFOLDER\\sqlparser.dll", EntryPoint = "ConvertSql", CallingConvention = CallingConvention.Cdecl)]
public static extern int ConvertSql(
IntPtr parser,
[MarshalAs(UnmanagedType.LPStr)] string input,
long size,
out IntPtr output, // see explanation below
out long out_size,
out long lines);
A few things about the above. First, I took the liberty of using the C# type aliases (string, long), because that's more idiomatic C#, but it doesn't change the behavior. Also, since there are no pointers anymore, no need for unsafe.
First, I declared parser as an IntPtr because those get converted to void* automatically if needed and that's what's already returned by CreateParserObject() anyway.
Second, out parameters can be converted to pointers to uninitialized objects, so by marking both out_size and lines as out, you fix that other problem.
The input is a string, which has a specific format in .NET. Since your function takes a const char*, you need to tell the marshaller how to convert the characters. That's where the MarshalAs attribute comes in: it's when the default conversion doesn't work for you. UnmanagedType.LPStr means char* in this case, so the string gets converted. The runtime will manage the memory for you.
But here we hit a big snag in the road: the output. When marshalling things, there's always questions about lifetime, or, specifically: who releases the memory? The fact that output is a char** implies that the parser allocates a block of memory and then returns it through that, which means the caller has to release it. From the get go, that reeks of bad C++ design because the caller doesn't know how the memory was allocated. Was it with malloc? new[]? Platform specific APIs like LocalAlloc? Is it a pointer to a block of static memory? Usually these APIs come with documentation telling precisely what to do with the pointer once you're done with it. Good C++ APIs return smart pointers, or ask that the caller pass a block of previously allocated memory that they can then play with.
But, this is the thing you're playing with, so here's how to make it work. First, you'd think that you could declare output as [MarshalAs(UnmanagedType.LPStr)] out string: the marshaller will copy the characters into a managed string and return it... but then the native string's (on the C++ side) memory will leak because the runtime doesn't know how the string was allocated, so it prefers to not do anything about it. Also, this assumes the string is null-terminated, which might not always be the case.
So, another option would be to instead declare output as out IntPtr. Then you can use Marshal.PtrToStringAnsi to convert your pointer into a string, and then release it... but you'll need to know how it was allocated first.
Putting it all together:
var parserObj = CreateParserObject();
var output = IntPtr.Zero;
try
{
long lines;
long out_size;
int result = ConvertSql(parserObj, inputStr, inputStr.Length, out output, out out_size, out lines);
var outputStr = Marshal.PtrToStringAnsi(output, (int)out_size);
// do what you want with outputStr here
}
finally
{
if (output != IntPtr.Zero)
{
// release output here
}
}
Oh, also, one final thought: whatever is returned by CreateParserObject() will probably have to be freed at one point. You're probably going to need another function for it, probably like:
[DllImport(/* ... */)]
public static extern void DestroyParserObject(IntPtr parserObject);
It might even already exist in your DLL.
Good luck!
I have a function in C++, _GetFileList, that I am trying to get to return a list/array of strings to C# code. I am not married to wstring * or any other type, this is just how the example I had found did it, but I am trying to get it to return a list/array and not just a single string. How can I marshal this to have multiple strings on the C# side?
C++ code:
extern "C" __declspec(dllexport) wstring * __cdecl _GetFileList(int &size){
std::list<wstring> myList;
//Code that populates the list correctly
size = myList.size();
wstring * arr = new wstring[size];
for( int i=0;i<size;i++){
arr[i] = myList.front();
myList.pop_front();
}
return arr;
}
I call that from C# like this:
[DllImport(#"LinuxDirectory.Interface.dll")]
private static extern IntPtr _GetFileList(ref int size);
public bool GetFileList() {
int size = 0;
IntPtr ptr = _GetFileList( ref size );
//WHAT DO I DO HERE TO GET THE LIST OF STRINGS INTO SOMETHING I CAN READ?
}
I've tried to use Marshal.PtrToStringUni, Marshal.PtrToStringAnsi, and the structure one as well but couldn't seem to get the syntax correct.
You don't. P/Invoke can only deal with function signatures that are C-compatible, meaning pointers have to be to plain-old-data, not full C++ classes.
If you can rewrite the C++ code, change it to call SysAllocString and return a BSTR, which the OS-provided string type intended for data exchange between components written in different languages. P/invoke already has all the right magic for receiving a BSTR, just use the C# string type in the p/invoke declaration.
If you can't change the C++ signature, you'll have to wrap it. Either use C++/CLI, which can deal with C++ classes as well as .NET, or use standard C++ and create and return a BSTR, copying data from the std::wstring.
For multiple strings, you can use the OS-provided type for array (SAFEARRAY) which is able to carry BSTR inside and again is language independent. Or it may be easier to just join and split using an appropriate (not appearing naturally in the data) separator character.
There's some really great information here: https://msdn.microsoft.com/en-us/magazine/mt795188.aspx
Running .NET Framework (the Microsoft implementation, on Windows), you can use the helper classes:
#include <windows.h>
#include <atlbase.h>
#include <atlsafe.h>
#include <string>
extern "C" __declspec(dllexport) LPSAFEARRAY GetFileList()
{
std::vector<std::wstring> myList;
//Code that populates the list correctly
size = myList.size();
CComSafeArray<BSTR> sa(size);
int i=0;
for( auto& item : myList ) {
CComBSTR bstr(item.size(), &item[0]);
sa.SetAt(i++, bstr.Detach()); // transfer ownership to array
}
return sa.Detach(); // transfer ownership to caller
}
On the C# side, p/invoke handles it all:
[DllImport("NativeDll.dll"),
return:MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)]
public static extern string[] GetFileList();
Your question suggests you might be on Linux. Unfortunately, the documentation I found seems to say that Mono's p/invoke doesn't know what to do with variable-sized arrays at all. So you're stuck doing everything by hand, including deallocation (the code in your question leaks new wstring[size] -- C# has absolutely no clue how to call a C++ delete[] operator). Have a look at Mono.Unix.UnixMarshal.PtrToStringArray.
I would like to call a function in a c dll, from my c# application, which takes a fixed array of structs as a function argument, and modifies the data.
[DllImport("my_c_program.dll", CallingConvention=CallingConvention.Cdecl)]
public static extern int GetData([MarshalAs(UnmanagedType.LPArray,
ArraySubType = UnmanagedType.Struct,
SizeConst=4)]
MyDataStruct[] myData);
I make a call to the function
MyDataStruct [] myDataArrayOfStructs = new MyDataStruct[4];
GetRangingMeasurementData(myDataArrayOfStructs);
And can confirm that the function receives the array and modifies the data, however, following completion of the function, the returned array is unchanged.
Can someone please advise what I am doing wrong.
Thanks.
I have a dll that I cannot import in my vs2012 c# project. I have used dllImport before but I have never had to use Marshal or pointers before. Lucky me I guess.
This is the code that I currently have.
The function being called is fnLDA_GetDevInfo(DEVID *ActiveDevices)
DEVID is a normal unsigned integer (#define DEVID unsigned integer)
//Allocate an array big enough to hold the device ids for the number of devices present.
//Call fnLDA_GetDevInfo(DEVID *ActiveDevices), which will fill in the array with the device ids for each connected attenuator
//The function returns an integer, which is the number of devices present on the machine.
[DllImport(DLLLOCATION,CallingConvention = CallingConvention.Cdecl)]
private static extern int fnLDA_GetDevInfo([MarshalAs(UnmanagedType.LPArray)] ref uint[] ActiveDevices);
I call the function in my code this way
uint[] MyDevices;
fnLDA_GetDevInfo(ref MyDevices);
At this point I get an error:
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Now I'm pretty sure the error occurs because I don't call the pointer right or something.
Any help would be appreciated.
You have an extra level of indirection. An array is marshalled as a pointer to the array. When you declare the parameter as ref, again a pointer is passed. Thus your C# code matches uint**. Even so, you cannot use ref with an array type because you cannot expect the unmanaged code to produce a managed array.
Your p/invoke should be:
[DllImport(DLLLOCATION,CallingConvention = CallingConvention.Cdecl)]
private static extern int fnLDA_GetDevInfo([Out] uint[] ActiveDevices);
Note that this function is pretty hard to call. Since the function is not passed the length of the array, it is impossible for the function to avoid running off the end of the array if the array is not long enough. I really hope that you have some way to work out how large the array needs to be ahead of calling this function.
So perhaps you are expected to call it like this:
uint[] MyDevices = new uint[SomeLargeNumberThatYouPresumablyCanProvide];
int len = fnLDA_GetDevInfo(MyDevices);
Or perhaps like this:
int len = fnLDA_GetDevInfo(null);
uint[] MyDevices = new uint[len];
fnLDA_GetDevInfo(MyDevices);
I trust that you'll be able to work the rest out from the documentation for the DLL and/or the example C++ programs that call the DLL.
I will be laconic.
I have a library written in C++ using the openCV lib.
One of my functions is:
EXTERN_HEADER HWND createHandle(FListener fl);
where FListener is a callback function pointer defined as:
typedef void (__stdcall *FListener)
(int fSN, int fC, byte* fSData, IplImage **fS);
IplImage is an openCV struct.
I am trying to use this library and these functions in C# so i am DllImport-ing as such:
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
delegate void FListener(int fSN, int fC, ref byte fSData, ref IntPtr fS);
[DllImport("FLib.dll", CharSet = CharSet.Auto,
CallingConvention = CallingConvention.Cdecl)]
static extern int createHandle(FListener fl);
and finally i declare the method that will be called back to my c# program as:
private void test(int fSN, int fC, ref byte fSD, ref IntPtr fS)
{
//how -for the love of God- do I access that openCV double pointer struct
//inside "fS"?
}
Naturally fS is a pointer to an array of pointers pointing to IplImages.
Do I have to declare the IplImage struct again inside my C# code?
I dont want to use any C# wrapper for openCV. I want to keep things "clean" and "simple"
but i am totally stuck with the marshalling part... Any help would be appreciated.
UPDATE: If i pass the fS array as an IntPtr* it works like a charm. The elements are retrieved as fS[0], fS[1] etc. If I pass it as a "ref IntPtr" then the first element can be retrieved as fS but where can i find the second one e.t.c.? I tried fS + Marshal.SizeOf(typeof(IplImage)) with no luck... any ideas?
No ideas at all?
It's been a while since I've done Platform Invoke, but I think your callback will have to be unsafe, e.g.,
unsafe delegate void FListener(int fSN, int fC, ref byte fSData, IplImage **fS);
This may not be the exact syntax, but it should get you going in the right direction.
As for your second question, you can access the other elements using the IntPtr.ToPointer() method in unsafe code, so that you will have a pointer to the base of the structure/array of pointers or whatever, and then you can simply use the indexer the access them, for example:
int* p = (int*)fS.ToPointer();
p[3] = ...;
if it's a pointer to array of IntPtrs do the same, ToPointer once again.