Passing safearray of unmanaged structs between managed and unmanaged code - c#

I have defined a struct MyStructure at IDL of unmanaged library SomeLibrary. I need to call managed code (C#) MyManagedLibPtr->RetrieveStuff from unmanaged library (C++) to fill and retrieve an array of these structs back for caller. The problem is that I haven't been able to figure out the signature of RetrieveStuff at managed side. I guess some custom marshalling is required? Here's what I have:
IDL of "SomeLibrary":
[
uuid(xxxxx-xxxx-xxxx-xxxx-xxxxx)
]
struct MyStructure
{
[helpstring("Some string values")] SAFEARRAY(BSTR) moValues;
[helpstring("Some other value")] BSTR moValue;
};
Unmanaged code (caller):
SAFEARRAY* saArray = NULL;
MyManagedLibPtr->RetrieveStuff(&saArray); // <--This is the key part
// The rest is just parsing the results.
// Using SafeArray -wrapper class that handles access/unaccess/etc..
SafeArray<SomeLibrary::MyStructure, VT_RECORD> oResults(saArray);
for (int i =0; i < oResults.GetSize(0); i++)
{
SomeLibrary::MyStructure oStruct = oResults[i];
// Etc......
}
At C# side, I've tried a few different solutions but none of them have been correct. This one would have been the sweetest, but obviously the mashalling automation wasn't sweet enough:
// Interface
[DispId(123)]
void RetrieveStuff(ref SomeLibrary.MyStructure[] roResultArray);
The error I get is some HRESULT -code. Haven't checked which one in particular, but obviously it's caused by incorrect signature or marshalling. Any help?

So, I found an answer that's ALMOST as requested. For whatever reason I couldn't get it working with ref parameter but I was able to do the marshalling with out. So this isn't 100% answer for the problem but damn close to it and will probably help others as well.
The correct interface declaration at managed side:
// Interface
[DispId(123)]
void RetrieveStuff([Out, MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_RECORD)] out SomeLibrary.MyStructure[] roResultArray);

Related

Marshal out parameter that is a reference type

I'm trying to get a C# class (not struct!) from a C++ function back (using out parameter). This is the C# side:
[StructLayout(LayoutKind.Sequential)]
public class OutClass
{
public int X;
}
// This interface function will be mapped to the C++ function
void MarshalOutClass(out OutClass outClass);
The C++ part looks like this
struct OutClass
{
int x = 0;
};
extern "C" MARSHAL_TESTS_API void MarshalOutClass(OutClass** out);
The function mapping works via a custom mechanism and is not part of this question. All marshaling attributes are treated normally.
In C#, we usually declare out arguments inline, like:
MarshalOutClass(out var outClass);
DoSomething(outClass);
Since C# reference types are marshaled by pointer, I figured I would have to add another pointer for ref or out parameters. So I use OutClass** on the C++ side.
I assume that C# translates the
MarshalOutClass(out var outClass);
part to roughly
OutClass outClass = default(OutClass);
MarshalOutClass(ref outClass);
which is a reference to null, or on C++ side: a pointer to a nullptr. This wouldn't be a problem for C# value types (aka struct) because their default is a default constructed instance.
This means, I'd have to manually create an instance of my object on the C++ side and marshal it back to C#.
void MarshalOutClass(OutClass** out)
{
auto ptr = static_cast<OutClass*>(CoTaskMemAlloc(sizeof(OutClass)));
*ptr = OutClass{};
*out = ptr;
}
The code seems to work, but I'm not sure if I'm leaking memory with this or if the marshaler is going to to take care of it properly. I don't do any cleanup on the C# side.
This brings me to the following questions:
is my assumption on how ref and out are translated to C++ correct?
is CoTaskMemAlloc the correct function here?
do I have to perform any additional memory management related tasks (on either side)?
is the overall approach correct here? What should I do differently?
I know that static_cast<OutClass*>(CoTaskMemAlloc(sizeof(OutClass))) is a bit sketchy here but lets assume OutClass is always a trivial type.

Pass C# array of object to C++/CLI

I'm force to expose some methods in a C# library so that they can be used from an external program written in C++ (VC++ 6.0). I thus created a mixed assembly which works quite ok so far but I have some troubles with a method that returns an array of .NET objects.
The .NET signature of the method is:
public Results[] Measure(String model, String identifier);
Where Results itself is:
public class Results
{
public String[] ElementType;
public bool[] HasError;
}
To provide entry point from C++, I started to write a C++/CLI wrapper method like this:
std::vector<ResultsWrapper> Measure(char* model, char* identifier)
{
// Call .NET code
String^ gcmodel = gcnew System::String(model);
String^ gcidentifier = gcnew System::String(identifier);
cli::array<Results^>^ gcres = myNetInstance->Measure(gcmodel, gcidentifier);
// Convert results to C++ vector
std::vector<ResultsWrapper> ret;
for (int ki = 0; ki < res->Length; ki++)
{
ResultsWrapper r = ResultsWrapper(res[ki]->...., );
ret.push_back(r);
}
return ret;
}
but I must admit I'm a bit lost, this is very long time I haven't wrote a single line of C++ and very long time I haven't deal with by hand memory management...
What is the best solution to create ResultsWrapper class so that there will be no much need to care for memory management from C++ side. Maybe something like the following ?
class ResultsWrapper
{
public:
ResultsWrapper(vector<std::String> elementType, vector<bool> hasError)
{
this.ElementType = elementType;
this.HasError = hasError;
}
public:
vector<std:String> ElementType;
vector<bool> HasError;
}
NB: I don't think team on VC++ 6.0 side are aware of boost library or share_ptr types (and I'm not very knowledgable about them either). All C++ code is very classic C++ code style, not even using stdlib.
I could not pass safely/easily STL types across dll boundaries so I get back to old char**, and manual allocation/deallocation and It Just Worked...
IJW for a while only ... then I tried to check for when throwing exception from .NET back to the calling C++ application and then patatra ... need conversion to native exceptions ... that again cannot safely cross dll boundaries ...
Mixed mode assemblies sounded appealing to go from .NET to native but was an IJS experience in my case... I give up and will go through COM instead.
In C++/CLI I started to write a wrapper method like this:
No, you did not
public Results[] Measure(String model, String identifier);
has no resemblance in
std::vector Measure(char* model, char* identifier)
None.
There is no marshalling required in a C++/CLI reference class. Use String^ as pointer to string (instead of char*) and use array<ResultsWrapper>^ as pointer to a managed array.
There is no need to use a wrapper at all. Declare a class as managed reference (ref class) and you can call it from the .NET side because it is a .NET class.

Direct memory access of C++ DLL in C#

I have searched stackoverflow for this problem but didn't find this exact one. In particular, I've found a ton of questions regarding retrieving C++ string references (char**) when the C# side is managing the memory but not the other way around.
The situation is as follows. I have a DLL (written on VC++ 2012) which I wrote myself. It loads and parses data from files and then lets anyone using the DLL access this data (by actual direct memory access for performance reasons) in several ways. Any program in C++ using this DLL has obviously no problems doing that. C# as it seems does...
A bit of context:
The DLL provides exported functions accepting char** (arrays of char*) parameters whose elements are being set to memory locations in the DLL and then further processed by the DLL's user after the call.
An example might look like this (examplatory implementation):
int myFunction(char* dataArray[], int row)
{
for (int i= 0; i < _something; ++i)
{
dataArray[i] = _some_char_ptr
}
}
And this is what the callee's implementation might look like in C++:
char** data = new char*[__num_fields];
myFunction(data, __some_row);
for (int i= 0; i < __something; ++i)
{
cout << data[i] << endl;
}
Special - thus different from all questions I found - about this is that the callee allocates a list of char* which after the call point to memory locations allocated by the DLL itself.
Now, I must say, I'm only using C# because you can get quite simple GUIs in notime. The C# GUI tool I'm working on is for integrity testing data the DLL loads. I'm not profound of C# at all. What I've tried so far wasn't successful at all and I'm aware there might be no solution for this problem due to C# not having any sort of pointer concepts. Similar problems I found in Java while using JNA to load DLLs there which led to me not using Java for such testing purposes anymore.
Now a bit of C# stuff I've tried, incl. context:
public static class DLLTest
{
// delegate object for the function:
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate int MyFunction_Type(out string[] dataArray, int row);
public static MyFunction_Type MyFunction { get; private set; }
public static void Load()
{
IntPtr dllAddress = DllUtilities.LoadLibrary(#"__dll_path");
IntPtr procAddress = DllUtilities.GetProcAddress(dllAddress, "myFunction");
MyFunction = (MyFunction_Type)Marshal.GetDelegateForFunctionPointer(procAddress, typeof(MyFunction_Type));
}
}
I'm then calling the function like this:
string[] data = new string[__num_fields];
DLLTest.MyFunction(out data, __row)
Code similar to this using things like normal strings, integers, booleans whatsoever work like a charm. Just these string arrays keep bugging me :-)
Note: I can't change the way the DLL works because I wrote this for my boss and he's using it fine in both C++ and Delphi programs. It performs well and we're not about to change anything on the DLL itself as it really is fine the way it is.
Any help or clarification is highly appreciated, thanks a lot, Greetings
out string[] dataArray
is the wrong translation for the char** parameter. It should be:
IntPtr[] dataArray
The calling C# code then allocates the array before calling the function. Just as the C++ code does.
IntPtr[] data = new IntPtr[__num_fields];
int retval = DLLTest.MyFunction(data, __row);
You can then access the memory to your hearts content using the Marshal class to read the unmanaged memory behind the IntPtr pointers.
The calling convention looks a bit odd. As written, the C++ function is cdecl. As Hans says, there must also be some mechanism for the DLL to know how long the passed in array is.

Accessing native objects via C++/CLI from C#!

I have written a C# application that injects a DLL into a third-party executable (which happens to have been built using the Qt framework). This DLL uses EasyHook to intercept calls to a number of specific functions. When my injected code is called, I then try to inspect some of the objects that are parameters to these functions.
For example, I have intercepted a call made to parse some XML:
virtual bool __thiscall QXmlSimpleReader::parse(class QXmlInputSource const &)
In my C# code, I have a PInvoke signature to match this:
static extern bool XmlParse(IntPtr Reader, IntPtr Source)
I would like to call the "data()" function which is a member of the "Source" class. That is, the QXmlSimpleReader parses the raw XML from the QXmlInputSource, but before it does so, I am trying to inspect the raw XML via this "data()" function.
On the advice of one of the experts here, I have tried to use C++/CLI to access the object natively (see Calling methods in third-party DLLs ). I have constructed a wrapper object in C++ that accepts the IntPtr from the C# code:
Header:
public ref class QXmlInputSource
{
public:
// Constructor must be called with C# IntPtr
QXmlInputSource(IntPtr Ptr);
bool LoadQt(void);
bool UnloadQt(void);
String^ Data();
private:
// Pointer to the native Qt object
void * Native;
HINSTANCE DllHandle;
// SIGNATURE: virtual QString QXmlInputSource::data() const
typedef void * (__thiscall *QXmlInputSource_Data)(void *);
QXmlInputSource_Data fpData;
};
CPP file:
QXmlInputSource::QXmlInputSource(IntPtr Ptr)
{
LoadQt();
Native = Ptr.ToPointer();
}
bool QXmlInputSource::LoadQt(void)
{
FARPROC Addr;
/* get handle to dll */
std::wstring LibName = QtPath + QtXml;
DllHandle = LoadLibrary(LibName.c_str());
/* get pointer to the function in the dll*/
Addr = GetProcAddress(HMODULE (DllHandle), "?data#QXmlInputSource##UBE?AVQString##XZ");
fpData = QXmlInputSource_Data(Addr);
return true;
}
bool QXmlInputSource::UnloadQt()
{
/* Release the Dll */
FreeLibrary(DllHandle);
return true;
}
String^ QXmlInputSource::Data()
{
void* Ptr = fpData(Native);
return "EPIC FAIL";
}
The Qt-based application crashes when I try to call the fpData() function pointer. Help :P
Some additional information which may or may not help:
I have successfully called functions on "simpler" objects, such as QString.count() and QString.data() using the same methodology. (QString seems to be just a lightweight wrapper for a standard unicode string).
In the QtXml4.dll file that contains the XML functions I am interested in, there are actually TWO parse() methods; one where the Source is a const &, and in the other, Source is a const *. I have no idea if I should be using one or the other. I don't think my signatures will change in any event.
While I was trying to play around, I tried dereferencing the IntPtr in the C# code and passing it to C++:
IntPtr DerefSrc = (IntPtr)Marshal.PtrToStructure(Source, typeof(IntPtr));
If I print out the values of these two IntPtrs, Source has a value of around 3.5Mb, while the DerefSrc has a value of 1.6Gb - which roughly matches the address of the QtXml4.dll in memory. My guess is that the 3.5Mb is a relative offset, while the DerefSrc is clearly an absolute reference. Is it worth a shot converting the DerefSrc to a relative address and passing that to C++ instead ... ?
I see several problems:
1.: You don't check the return value of LoadLibrary and GetProcAddress. Is QXmlInputSource::data even a DLL-exported method? If not then GetProcAddress will obviously fail.
2.: How do you instantiate the QXmlInputSource class? I ask because it seems you are trying to do it in the C# code, which is hard to do right (you need to know the size required for the class, allocate a properly aligned chunk of memory of that size, and call the constructor on it).
3.: The way you're invoking the function pointer is wrong. You need to declare a method pointer of the appropriate type:
FARPROC fp = ::GetProcAddress(...);
typedef QString (QXmlInputSource::*DataMethod)();
DataMethod mpData = reinterpret_cast<DataMethod>(fp);
QXmlInputSource source;
QString data = (source.*mpData)();
4.: Looking at the documentation for QXmlInputSource::data, I see that it returns a QString, which is woefully different from a pointer (as you're currently treating it). To convert it to a System.String, you need code like this:
QString s1 = (QChar*)L"example string";
String^ s2 = gcnew String((wchar_t*)s1.data()); // calls the String::String(wchar_t*) constructor overload

Conversion of unmanaged type structure pointer into managed type structure pointer

Consider the following stucture in c++, I need to wrap this using CLI to make it usable for C#
typedef struct A
{
int b[5];
A* next;
};
How can I do so? Please help.
non-op edit:
What I've tried is the following:
public ref struct ANET
{
array<int>^ b;
ANET^ next;
ANET()
{ b = gcnew array<int>(5) }
};
now let's say we have an pointer of object of A is a, pointer of object ofANET is aNET
nSize = sizeof(a->b)/sizeof(a->b[0]);
Marshal::Copy( IntPtr( ( void * ) a->b ), aNET->b, 0, nSize);
so far I am able get the values of a->b in aNET->b but I am stuck with marshaling the pointer of a->next to aNET->next.
Thanks
That's a linked list. So one option is to write C++/CLI code to adapt the native linked list to a .net LinkedList<T>. Going down this route will mean that you need to make copies of the list whenever it is modified in the native code and needs to be returned to the managed code. And vice versa.
If making copies is not an option then you should wrap the native linked list in a managed class. So you don't try to convert the struct definition at all. Instead you write a C++/CLI managed class that encapsulates the functionality that you need to expose. I can't say much more than that because you haven't given any information on the operations that you need to perform on this list. Now have you explained what the data flow is.

Categories