I'm calling functions from C++ that returns a pointer to an array of struct and I'm having problems since I'm new to this operation/implementation.
My C++ codes:
// My C++ Structs
typedef struct _MainData {
double dCount;
DataS1 *DS1;
int iCount1;
DataS2 *DS2;
int iCount2;
}MainData;
typedef struct _DataS1 {
unsigned int uiCount1;
unsigned int uiCount2;
int iCount;
void *pA;
void *pB;
} DataS1;
typedef struct _DataS2 {
unsigned int uiCount1;
unsigned int uiCount2;
unsigned int uiCount3;
unsigned int uiCount4;
double dCount;
int iCount1;
char strLbl[64];
} DataS2;
// My C++ Function
MainData* GetData(const int ID)
{
MainData* mData;
int iLength = Get_Count();
mData = new MainData[iLength];
for(int x = 0;x < VarCounter; x++)
{
// Codes here assign data to mData[x]
}
return mData;
}
Question:
How can I call the C++ function GetData to C#?
My current codes in C# are:
[DllImport(".\\sdata.dll")]
[return: MarshalAs(UnmanagedType.LPArray)]
private static unsafe extern MainData[] GetData(int ID);
// The struct MainData in my C# side is already "Marshalled"...
//My function call is here:
MainData[] SmpMapData = GetData(ID);
When I compiled it, there's an exception:
"Cannot marshal 'return value': Invalid managed/unmanaged type combination."
Sorry for the poor coding... Please help...
First, you need to remember that MarshalAs (explicit or implicit) for the return value essentially means "copy native structures content into managed structures".
Second, since the CLR marshaler only copies the data, if you do not free the memory you're allocated in the C++ function, you've got a memory leak to manage.
Third, this error is mainly due to the fact that the CLR marshaler has no way of knowing the length of the array returned by the native code, since you're basically returning a memory pointer and no length.
If you want to keep these memory structures as-is, I strongly suggest you to look into C++/CLI. You'll be able to wrap those complex types into mixed native/managed classes that will avoid you to copy the data around. This will help you keep the data marshaling to the bare minimum between native and managed code.
If you still want to use C# and no C++/CLI, you'll have to write a somehow smarter piece of code to unmarshal the data returned by the native code into managed data. You can look into Custom Marshaling for that.
I don't see how the .NET runtime could possibly know how many MainData are allocated in GetData(...).
Refactor your C++ code to consume an array to populate or return single MainDatas.
Related
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'm trying to create a C# interface which receives a callback from an external C DLL.
The callback's parameters contain pointers to C structs, which themselves have a pointer to a different struct.
The callback signature:
typedef application_event_result (*application_event_ptr)(abuffertype* read_buffer, abuffertype* write_buffer);
The buffer struct definitions in C:
typedef struct {
uint16 size;
uint8* data;
} anotherbuffertype;
typedef struct {
anotherbuffertype *buffer;
uint16 position;
} abuffertype;
I know that the C# signature of the callback should use "ref" for the pointer type of the parameter. But how can the pointer inside the "abuffertype" struct be defined in C#?
So far I have this definition of the two structs in C#:
[StructLayout(LayoutKind.Sequential)]
public struct anotherbuffer
{
UInt16 size;
IntPtr data;
}
[StructLayout(LayoutKind.Sequential)]
public struct abuffer
{
anotherbuffer buffer;
UInt16 position;
}
But that doesn't work. The contents of "abuffer" in C# is not what was there before the callback in the C code.
Do I need to unmarshal the internal struct pointer manually, and if so, how?
You will not get help from the marshaller, this normally causes a major memory management problem. But can work in the specific case of a callback since it is the calling C program that manages the data.
You have to convert the data yourself. Declare the pointers as IntPtr and use Marshal.PtrToStructure() to retrieve the data.
The anotherbuffertype.data member looks like an array, use Marshal.Copy() to copy its content into your own byte[] array. If you don't mind the unsafe keyword then you can keep it declared as byte* and access the elements with data[index], avoids the cost of the copy. It is not very unsafe, pretty easy to keep index constrained to [0..size).
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 need your help.
I am trying to import a C Dll into a C# project. While doing that, I need pass a struct between the Dll and C# project in both directions.
Here is C definition:
struct mwBITMAP
{
int bmWidth;
int bmHeight;
BYTE* bmData;
};
Here is C# definition:
[StructLayout(LayoutKind.Sequential)]
public struct MwRemoteBmp
{
public int Width;
public int Height;
public byte[] Data;
}
I tried to pass the a struct (the Data is well initialized) from C# to a dll's test function by reference. The width and height are both right. But the Data is all wrong.
Where did I make mistakes?
Yes, the array gets marshaled as a SAFEARRAY. Not crashing the pinvoke marshaller is pretty unusual. Declare the Data member as IntPtr, then use Marshal.Copy() to copy the data.
Beware that this would be hard to use in C as well. There's a memory management problem, it isn't clear who owns the array. Most typically, the C function would use malloc() to allocate the array. That's a big problem, you cannot release that array in C#, no way to call free(). You'll have an unpluggable memory leak. If you can't rewrite the C code then you'll need to write a wrapper in the C++/CLI language so that you can call free(). Even that is tricky if the C dll doesn't use the same CRT as the C++/CLI code. You have to compile the C code with the /MD option.
Use the IntPtr type instead of byte[] type.
In your example:
[StructLayout(LayoutKind.Sequential)]
public struct MwRemoteBmp
{
public int Width;
public int Height;
public IntPtr Data;
}
I have an unmanaged C++ dll that exports the following methods:
ERASURE_API void encode(unsigned char ** inp, unsigned char ** outp,
unsigned int *block_nums, size_t num_block_nums, size_t sz);
ERASURE_API void decode(unsigned char ** inp, unsigned char ** outp,
unsigned int * index, size_t sz);
Size of inp and outp can be as large as 10KB, What would be the best performance way to call these methods from C# managed code?
EDIT: I did the following implementation, and It works, but is it the most efficient way to do this.
C++ :
ERASURE_API void encode_w(unsigned char * inpbuf,int k, unsigned char * outpbuf,
int nfecs, unsigned int * block_nums, size_t num_block_nums, size_t sz)
{
unsigned char ** inp= new unsigned char*[k];
for(i=0;i<k;i++){
inp[i] = inpbuf+i*sz;
}
unsigned char ** outp= new unsigned char *[nfecs];
for(i=0;i<nfecs;i++){
outp[i] =outpbuf+i*sz;
}
encode(inp,outp,block_nums,num_block_nums,sz);
delete [] inp;
delete [] outp;
}
C#:
[DllImport("erasure.dll")]
public static extern void encode_w([In] byte[] inpbuf,int k,[Out] byte[] outpbuf,
int nfecs, uint[] block_nums, int num_block_nums, int sz);
Is C++/CLI an option? IMO, it's these sorts of complex interop/custom marshaling scenarios for which it was designed.
Errg that's some awesome Marshalling to be done there.
I've only ever come across one good article that deals with this sort of thing:
Marshalling a Variable-Length Array From Unmanaged Code In C#
Do you have to marshal data between managed and native heap? If you move all operation on the buffer to your native DLL you can avoid the cost of data copy between heaps.
That means you need to allocate the data on the native heap, return it in a ref IntPtr parameter, then hold the buffer's address in IntPtr (.Net equivalent of void*) and pass it around. After you are done with the buffer you can call another function in your native dll to delete the buffer. Use System.Runtime.InteropServices.Marshal.Copy when you have to copy the data to the managed heap (that's what the CLR marshaller called for marshalling built-in types).
Creating COM wrappers of the buffer-operating functions would be a little slower but makes the code more readable. However, allocating on the COM heap could be a little slower because managed code can also locking the COM heap.
I would recommend creating COM wrapper for these functions.