Direct memory access of C++ DLL in C# - 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.

Related

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.

C# P/Invoke: native output parameter value won't reach managed code

I'm marshalling a native C++ DLL to a C# DLL. I'm not very acknowledged in C/C++, but I've managed to make it work until I got stuck on this problem. Here's a very simplistic code example:
C++
PROASADLL __declspec(dllexport) void outTest(int* number){
int temp = *number + 10;
number = &temp; //*number = 12
}
C#
[DllImport("ProAsaNativeDll.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern void outTest(ref int number);
public static int OutTest()
{
int number = 2;
outTest(ref number);
return number; //number = 2
}
Please notice that I'm my real scenario, I'm trying to get this to work with a pointer to pointer to struct but I decided to leave it out as it is not a marshalling issue; not even this simple code will work. The C++ code works but I wouldn't rule out being dumb and having a problem there: like I said, I don't know much C/C++.
The number variable value in the C# wrapper method won't change. Please help.
I think you are getting a bad result because in your C++ code you are actually changing the parameter number by setting it to another pointer.
I believe that your change will only be visible in your function outTest's scope.
However, if you change the value where the pointer ... points... that's should be a different story. Pretty much like this:
*number = *number + 10;
EDIT: This bit is not tested. Oh... and also... I haven't written anything in C++ for ages. Might as well be totally wrong.

Passing safearray of unmanaged structs between managed and unmanaged code

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);

How to pass address of objects created in a C# List to C++ dll?

I have been looking all over google to find some answers to my questions but do not quite understand what I have found. I have some objects which are created and stored in C# List after using System.IO to read some text files. After that, I want to send references (using const pointers) to each of these objects to the internal classes in C++ dll so that it can use them for computation of some algorithms.
Here are some simple example (not actual code) of what I am doing:
The C# class:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class SimpleClass
{
[MarshalAs(UnmanagedType.LPStr)]
public string Name;
public float Length;
}
with corresponding C struct:
struct SimpleClass
{
const char* Name;
float Length;
};
stored in
List<SimpleClass> ItemList;
after parsing some text files.
Then calling the following dll function:
C#:
[DllImport("SimpleDLL")]
public static extern void AddSimpleReference(SimpleClass inSimple);
C:
void AddSimpleReference(const SimpleClass* inSimple)
{
g_Vector.push_back(inSimple); // g_Vector is a std::vector<const SimpleClass* > type
}
What I have tried is:
for(int i=0; i<ItemList.Count;++i)
{
SimpleClass theSimpleItem = ItemList[i];
AddSimpleReference(theSimpleItem);
}
Initially, I thought it would be easy to get a actual reference/address just by using the assignment operator since classes in C# are passed-by-reference but it turns out that the C++ class is always pushing the same address value (the address value of the temp reference) into the container instead of the actual address. How do I get the actual object addresses and send it to C++ DLL so that it can have read-only access to the C# objects?
UPDATE: Sorry to those who posted answers with unsafe codes. I forgot to mention that the C# code is actually used as a script in Unity game engine which does not allow the use of unsafe codes.
First you need to change your interop signature to take a pointer (and thus making it unsafe).
[DllImport("SimpleDLL")]
public unsafe static extern void AddSimpleReference(SimpleClass* inSimple);
Then, because the GC is free to move objects around in memory as it pleases, you will need to pin the object in memory for the entire time you will need its address on the unmanaged side. For that you need the fixed statement:
SimpleClass theSimpleItem = ItemList[i];
unsafe
{
fixed(SimpleClass* ptr = &theSimpleItem)
{
AddSimpleReference(ptr);
}
}
This would work if AddSimpleReference used the pointer and then discarded it. But you're storing the pointer in a std::vector for later. That won't work, because the pointer will probably become invalid due to the GC moving the original item somewhere else once execution leaves the fixed block.
To solve this, you need to pin the items until you are done with them. To do this you may need to resort to the GCHandle type.
// Change the interop signature, use IntPtr instead (no "unsafe" modifier)
[DllImport("SimpleDLL")]
public static extern void AddSimpleReference(IntPtr inSimple);
// ----
for(int i=0; i<ItemList.Count;++i)
{
SimpleClass theSimpleItem = ItemList[i];
// take a pinned handle before passing the item down.
GCHandle handle = GCHandle.Alloc(theSimpleItem, GCHandleType.Pinned);
AddSimpleReference(GCHandle.ToIntPtr(handle));
// probably a good idea save this handle somewhere for later release
}
// ----
// when you're done, don't forget to ensure the handle is freed
// probably in a Dispose method, or a finally block somewhere appropriate
GCHandle.Free(handle);
When doing something like this, keep in mind that pinning objects in memory for a long time is a bad idea, because it prevents the garbage collector from doing its job efficiently.
Even though I think this is not a good idea, have a look at unsafe code and memory pinning. Here is a good start on MSDN.
fixed and unsafe keywords are likely what you should be looking for.
You cannot. The C# GC will move objects for fun. Your addresses will go out of scope.

Writing C# GUI over a C++ dll or C++ exe

I have a C++ console Exe which does some progamming. Now i wanted to write a C# GUI which does some of the programming that the C++ exe does. I was thinking of few approaches,
Write the C# GUI with all programming in C++ done from scratch.(I do not want to do this for the amount of rework it entails)
Build a C++ dll which does the programming and have it imported in GUI app.(Now here i have a concern. How do i capture the output of the routines in c++ dll and display it in GUI? Should i return the output as string for every routine that the app calls.? Since i dont know managed c++ iam going to build an unmanaged C++ dll. )
Building a C++/CLI dll really isn't that hard. You basically use unmanaged C++ code except that you define a "public ref class" which hosts the functions you want the C# code to see.
What kind of data are you returning? Single numbers, matrices of numbers, complex objects?
UPDATE: Since it has been clarified that the "output" is iostreams, here is a project demonstrating redirection of cout to a .NET application calling the library. Redirecting clog or cerr would just require a handful of additional lines in DllMain patterned after the existing redirect.
The zip file includes VS2010 project files, but the source code should also work in 2005 or 2008.
The iostreams capture functionality is contained in the following code:
// compile this part without /clr
class capturebuf : public std::stringbuf
{
protected:
virtual int sync()
{
// ensure NUL termination
overflow(0);
// send to .NET trace listeners
loghelper(pbase());
// clear buffer
str(std::string());
return __super::sync();
}
};
BOOL WINAPI DllMain(_In_ HANDLE _HDllHandle, _In_ DWORD _Reason, _In_opt_ LPVOID _Reserved)
{
static std::streambuf* origbuf;
static capturebuf* altbuf;
switch (_Reason)
{
case DLL_PROCESS_ATTACH:
origbuf = std::cout.rdbuf();
std::cout.rdbuf(altbuf = new capturebuf());
break;
case DLL_PROCESS_DETACH:
std::cout.rdbuf(origbuf);
delete altbuf;
break;
}
return TRUE;
}
// compile this helper function with /clr
void loghelper(char* msg) { Trace::Write(gcnew System::String(msg)); }
So you just want to call c++ library from managed .net code?
Then you would need to either build a COM object or a p-invokable library in c++. Each approach has it's own pros and cons depending on your business need. You would have to marshall data in your consumer. There are tons and tons of material on both concepts.
Possibly relevant: Possible to call C++ code from C#?
You could just write a C# GUI wrapper (as you suggest in option 2) and spawn the C++ process; however, this will be a little slow (I don't know if that matters).
To run your C++ exe and capture the output you can use the ProcessRunner I put together. Here is the basic usage:
using CSharpTest.Net.Processes;
partial class Program
{
static int Main(string[] args)
{
ProcessRunner run = new ProcessRunner("svn.exe", "update");
run.OutputReceived += new ProcessOutputEventHandler(run_OutputReceived);
return run.Run();
}
static void run_OutputReceived(object sender, ProcessOutputEventArgs args)
{
Console.WriteLine("{0}: {1}", args.Error ? "Error" : "Output", args.Data);
}
}
See the first comment in this page to redirect stderr
Probably the best way to go here is use P/Invoke or Platform Invoke. Depending on the structure or your C++ dll interface you may want to wrap it in a pure C interface; it is easiest if your interface uses only blittable types. If you limit your dll interface to blittable types (Int32, Single, Boolean, Int32[], Single[], Double[] - the basics) you will not need to do any complex marshaling of data between the managed (C#) and unmanaged (C) memory spaces.
For example, in your c# code you define the available calls in your C/C++ dll using the DllImport attribute.
[DllImport, "ExactDllName.dll"]
static extern boolean OneOfMyCoolCRoutines([In] Double[] x, [In] Double[] y, [Out] Double result)
The little [In]'s and [Out]'s are not strictly required, but they can speed things along. Now having added your "ExactDllName.dll" as a reference to your C# project, you can call your C/C++ function from your C# code.
fixed(Double *x = &x[0], *y = &y[0] )
{
Boolean returnValue = OneOfMyCoolCRoutines(x, y, r);
}
Note that I'm essentially passing pointers back and fourth between my dll and C# code. That can cause memory bugs because the locations of those arrays may be changed by the CLR garbage collector, but the C/C++ dll will know nothing of it. So to guard against that, I've simply fixed those pointers in my C#, and now they won't move in memory while my dll is operating on those arrays. This is now unsafe code and I'll need to compile my C# code w/ that flag.
There are many fine details to language interop, but that should get you rolling. Sticking to a stateless C interface of blittable types is a great policy if possible. That will keep your language interop code the cleanest.
Good luck,
Paul

Categories