I am trying to use a C# DLL which has multiple references to .NET classes and C# Classes in Embarcadero C++ Builder.
Things like the Point class and String class as well as Delegates.
I am wondering if the >NET references or C# ones will mess me up somehow. I am just about to getting it hooked up, but I am wondering if some of the problems I am having could be caused by C++ not wanting to play nice.
I gave a similar answer to your problem in this question.
You basically want a C++/CLI interface to your C# code.
If you want to pass a C# delegate to C++ code, you can translate it using Marshal::GetFunctionPointerForDelegate() (MSDN). That gives you a IntPtr that you can call ToPointer() on to pass in as a function pointer.
You will need to use C++/CLI to use any .NET content in C++. You might also be able to set up your own AppDomain, but those are the only two choices, as C++ has no native ability to interact with .NET, at all.
Or you can use the mono CLR embedder
Managed code can invoke unmanaged code in two ways, [using P/Invoke or] using the low-level Mono embedding API.
This works a lot like the oldfashioned embedding of a Perl, Python or Ruby 'interpreter' (actually, virtual machines) in your C/C++ executable. I don't think there is actually such a thing as a Swig(++) wrapper generator for this (yet), but here is a snippet of what a call into CIL code looks like:
class MyClass {
static void Foo (int value) {
...
}
int Bar (string name) {
...
}
}
assuming you got the corresponding MonoMethod* in foo_method and bar_method and this_arg is a MonoObject* of type MyClass, you simply execute:
/* we execute methods that take one argument */
void *args [1];
int val = 10;
/* Note we put the address of the value type in the args array */
args [0] = &val;
/* execute Foo (10);
* it's a static method, so use NULL as the second argument.
*/
mono_runtime_invoke (foo_method, NULL, args, NULL);
/* a string is a reference, so we put it directly in the args array */
args [0] = mono_string_new (domain, "Hello");
/* execute my_class_instance.Bar ("Hello");
* See the Creating Objects section to learn how to get this_arg.
*/
MonoObject *result = mono_runtime_invoke (bar_method, this_arg, args, NULL);
/* we always get a MonoObject* from mono_runtime_invoke (), so to get
* the integer value we need to unbox (which returns a pointer to
* the value stored in the object) and dereference.
*/
int int_result = *(int*)mono_object_unbox (result);
For extra entertainment value: if you AOT-compile all of your CIL code, you'll be able to statically link your assembly into your native binary (effectively doing what Managed C++ (c++-cli) calls mixed mode assemblies). Look at
mono --aot=static myassembly.dll
and
mkbundle
Related
I have a custom struct defined in MIDL:
struct Foo
{
[string] char* Bar;
int Baz;
}
I'm trying to pass this from a C# application to a C++ application. The interface assembly was generated with tlbimp.exe.
I should mention that I have next to no knowledge of MIDL and COM interop, but we're stuck using this interop method for the time being, so there's no way around that for now.
I tried various ways of defining an array of such a type, none with success. Ideally I'd want to call it on the C# side just like this:
ComObject.SomeFunction(someArray);
However, I may not be able to do that without a size parameter, so this would also be fine:
ComObject.SomeFunction(someArray.Length, someArray);
I tried the following ways to define it, none of which were successful:
HRESULT SomeFunction(struct Foo array[]); // For some reason it interprets this as a
// ref parameter... I assume because it's
// equivalent to a pointer?
HRESULT SomeFunction(struct Foo** array); // Tried with a pointer as well,
// but I think the memory layout messes it up
HRESULT SomeFunction(int length, [size_is(length)] struct Foo array[]);
HRESULT SomeFunction(int length, [size_is(length)] struct Foo** array); // I don't know how
// to marshal that on
// the C# side
What's the right way to define this in the MIDL and to invoke it on the C# side? Ugly temporary solutions welcome, since this entire thing will be refactored anyway in two months, but we need this before then. For example, currently I'm considering passing in two arrays of simple types (char* and int) and then combine them into the appropriate structure on the C++ side.
I am passing a C# object (PSObject) to managed C++ in the following way. But it crashes in the commented statement. Am I missing something?
Am I passing PSObject correctly to managed C++?
or am I accessing it wrongly?
I am using clr:oldsyntax.
Actually C# will pass a PSObject to managed C++,
in managed C++ I want to examine the properties present in PSObject. (An object returned by running PowerShell commands)
In C#, using delegate concept I am calling managed C++ method to pass PSObject.
The delegate is declared as below:
delegate bool CFuncDelegate(PSObject Arg);
funcObj (a IntPtr) is a pointer to addData function in C++ (I didn't write that code here, since it is not relevant) and I am calling addData in csharp as:
CFuncDelegate func = (CFuncDelegate)Marshal.GetDelegateForFunctionPointer(funcObj, typeof(CFuncDelegate));
bool isCompleted = func(psoObject); //psoObject is a PSObject
and in managed C++,
static bool __clrcall addData(System::Management::Automation::PSObject* curPsObj)
{
log(Marshal::StringToHGlobalUni(curPsObj->AdaptedMemberSetName));
//prints psadapted
System::Object* value = curPsObj->Properties->get_Item("DisplayName");
//crashes
}
It would be better if someone just post two lines of code to pass object from C# and accessing it in managed C++. Thanks in advance.
I think it's really time that you abandoned oldsyntax and moved to C++/CLI. Anyway, even doing that is not going to solve your problem. You define a delegate like this:
delegate bool CFuncDelegate(PSObject Arg);
And then you assign a delegate variable like this:
CFuncDelegate func = (CFuncDelegate)Marshal.GetDelegateForFunctionPointer(
funcObj, typeof(CFuncDelegate));
The documentation for Marshal.GetDelegateForFunctionPointer says:
Converts an unmanaged function pointer to a delegate.
So, your code can only work if funcObj is an unmanaged function. And your addData method is certainly not that. You need to stop using GetDelegateForFunctionPointer here. It is simply not compatible with calling the managed function addData.
I've no idea where funcObj comes from. You said:
funcObj (a IntPtr) is a pointer to addData function in cpp (i didnt write that code here, since it is not relevant)
In fact it is not only relevant to the problem, it is the root cause of the problem. What I would expect to see here would be for you to add the C++ assembly to your C# project as a reference, at which point addData could be referenced directly.
Of course, none of this even mentions the fact that your calling conventions are mis-matched. The managed code uses clrcall and your unmanaged function pointer is taken to be stdcall.
Update
There's some more information in the comments. Pass addData as a delegate. You'll need to declare the delegate type in the C# code which I believe you reference from your C++ assembly.
I am developing a C# application. Since I have some algorithms for least-squares fit in C/C++ that would be too cumbersome too translate, I have made the C++ code into a dll and then created a wrapper in C#.
In the C# code, I have defined a struct that is passed to the unmanaged C++ code as a pointer. The struct contains the initial guesstimates for the fitting functions, and it is also used to return the results of the fit.
It appears to me that you must define the struct in both the managed and the unmanaged code. However, someone using my source code in in the future might decide to change the fields of the struct in the C# application, without understanding that they also have to change the struct in the native code. This will result in a run-time error at best (and produce erroneous results at worse), but there will be no error message telling the developer / end user what is wrong.
From my understanding, it impossible to create a test in the unmanaged C++ DLL that checks if the struct contains the correct fields, but is it posible to have the DLL returning a struct of the correct format to the C# wrapper?
Otherwise, what ways are there to reduce the risk that some careless programmer in the future causes run-time errors that are hard to detect?
Sample code:
//C++
struct InputOutputStruct {
double a,b,c;
}
extern "C" __declspec(dllexport) void DoSomethingToStruct(InputOutputStruct* s)
{
// ... algorithm
}
//C#
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
public struct InputOutputStruct {
public double a,b,c;
}
[DllImport("CpluplusDll.dll")]
public static unsafe extern bool DoSomethingToStruct(InputOutputStruct* s);
class CSharpWrapper {
static void Main(string[] args)
{
InputOutputStruct s = new InputOutputStruct();
unsafe {
InputOutpustruct* sPtr = &s;
DoSomethingToStruct(sPtr);
s = *sPtr;
}
}
}
It appears to me that you must define the struct in both the managed
and the unmanaged code.
Not true. This is what C++/CLI was invented for- facilitate much easier interoperation with C++ and .NET.
but is it posible to have the DLL returning a struct of the correct format to the C# wrapper?
I don't think so, because you always need to define the structs on the C# side.
Here are a solution which may work ( never tested ):
Give each struct which is shared a unique identifier on both sides ( GUID, Macros )
Create a reflection for C++ which contains informations about the the types which are used on C# and C++ side. This could be done by using macros.
Compare the C++ structs and the C# structs on startup by using the GUIDs, reflection and macros. You can also use sizeof to compare sizes first.
That could be a lot of work
When working on C++ side you still can make a lot of things wrong when you not know about the macros
So I have this C .dll source code which I want to use in my C# application. Instead of doing bunch of DllImports I've decided to write a wrapper for it in C++/CLI.
My C function takes a pointer to a struct with 4 callback functions in it:
typedef struct
{
PFN_IN readFp;
PFN_OUT writeFp;
}OPEN_ARGS;
C++/CLI shares the same .h file, therefore uses the same typedef.
C# code has it's own definition of this structure and delegates for CBs, because I can't attach .h to C# project.
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate Int32 PFN_OUT(IntPtr arg, IntPtr pSrc, Int32 len);
[StructLayout(LayoutKind.Sequential)]
public struct OPEN_ARGS
{
public PFN_IN readFp;
public PFN_OUT writeFp;
};
So, when I add my C++/CLI dll explicitly to C# project references, the compliler wouldn't accept calls to C++/CLI functions saying
"Error 2 Argument 2: cannot convert from 'WrapperTest.Program.OPEN_ARGS' to 'SAR_OPEN_ARGS'"
But if I include the C++/CLI dll implicitly like that
[DllImport("Wrapper.dll", CharSet = CharSet.Auto, EntryPoint = "?CLIOpen##YAHHUOPEN_ARGS###Z")]
public static extern int CLIOpen(int a, OPEN_ARGS args);
It will work just fine.
So is there a way to tell C# compiler to ignore this type cast error, or may be other way to wrap C code functions?
EDIT: cleaned up variable names for better readabiltiy
What if you did this another way. Since you have a C++/CLI DLL handling interop duties between the C DLL and the C# assembly, you could expose an equivalent API, only using more .NET-like concepts.
For example, instead of exposing the struct with function pointers, you could expose a class that has three events. The C# assembly would add handlers for those events. Inside the C++ DLL, it would use the function pointers that the C DLL expects, but their implementation would fire the .NET events that the C# assembly is handling.
This would provide a much better experience using the DLL on the C# side, and likely get rid of the interop compiler errors that you're encountering.
Please consider using SWIG to generate the wrapper code for all your pinvoke.
http://www.swig.org/Doc1.3/CSharp.html
So for managed C++, you can use the #pragma managed/unmanaged compiler directives instead of pInvoke, which it looks like you are using. Then you can compile managed and native code together into the same assembly, even the same CPP file.
Then you could do something like:
#pragma managed
// include your native headers here
#include "foo.h" // whatever you call it.
#using <System.dll> // what ever else you need here...
// Have to wrap a function in a class, since .NET doesn't allow free standing functions.
public ref class foo
{
public static int sarCLIOpen(int a, SARWrapperTest::Program::SAR_OPEN_ARGS args)
{
// do something to convert your managed args to native args.
::SAR_OPEN_ARGS native_args = ...
// then call your native function
return sarCLIOpen(a, native_args );
}
};
I have some legacy code I want to port to C#. I cannot modify the C++ code, I just have to make do with what I'm given.
So, the situation. I'm using SwIG, and I came across this function:
void MarshalMe(int iNum, FooClass** ioFooClassArray);
If I ran SWIG over this, it wouldn't know what to do with the array, so it will create a SWIGTYPE_p_pFooClass. Fair enough!
C# code for this would look like
void MarshalMe(int iNum, SWIGTYPE_p_p_FooClass ioFooClassArray); // Not ideal!
There are some techniques for marshalling this kind of code correctly, so I tried a few of them:
%typemap(ctype) FooClass** "FooClass**"
%typemap(cstype) FooClass** "FooClass[]"
%typemap(imtype, inattributes="[In, Out, MarshalAs(UnmanagedType.LPArray)]") FooClass** "FooClass[]"
%typemap(csin) FooClass** "$csinput"
%typemap(in) FooClass** "$1 = $input;"
%typemap(freearg) FooClass** ""
%typemap(argout) FooClass** ""
This effectively creates a nicer signature:
void MarshalMe(int iNum, FooClass[] ioFooClassArray); // Looks good! Would it work?
However, when I try to run it, I get the following error:
{"Exception of type 'System.ExecutionEngineException' was thrown."}
Any ideas about the actual typemap?
The exception tells you that the function has corrupted the garbage collected heap. It writing past the end of the array. If it is actually a FooClass[], big question, then you'll have to create the array first:
FooClass[] array = new FooClass[666];
MarshalMe(42, array);
Which assumes that the function will fill the array with FooClass objects. The size of the array really matters here, you'll have to have some kind of idea how many elements you'll get back. That can only work reliable if "iNum" is an argument that says how long the array is. Pass array.Length.
It could also mean that the function will create the array itself and return a pointer to it. You're really screwed if that's the case, you cannot release the memory for the array.
[Swig] Java: Another way to pass pointer-to-pointer
I had a similar problem with a C-function (API) which returned a pointer-to-pointer as an input argument. I was trying to call the C-function from JAVA and I had no way modify the API.
The API.h header file contained:
extern int ReadMessage(HEADER **hdr);
The original C-call looked like:
HEADER *hdr;
int status;
status = ReadMessage(&hdr);
The function of the API was to store data at the memory location specified by the pointer-to-pointer.
I tried to use SWIG to create the appropriate interface file. SWIG.i created the file SWIGTYPE_p_p_header.java from API.h. The problem is the SWIGTYPE_p_p_header constructor initialized swigCPtr to 0.
The JAVA call looked like:
SWIGTYPE_p_p_header hdr = new SWIGTYPE_p_p_header();
status = SWIG.ReadMessage(hdr);
But when I called the API from JAVA the ptr was always 0.
I finally gave up passing the pointer-to-pointer as an input argument. Instead I defined another C-function in SWIG.i to return the pointer-to-pointer in a return value. I thought it was a Kludge ... but it worked!
You may want to try this:
SWIG.i looks like:
// return pointer-to-pointer
%inline %{
HEADER *ReadMessageHelper() {
HEADER *hdr;
int returnValue;
returnValue = ReadMessage(&hdr);
if (returnValue!= 1) hdr = NULL;
return hdr;
}%}
The inline function above could leak memory as Java won't take ownership of the memory created by ReadMessageHelper, since the HEADER instance iscreated on the heap.
The fix for the memory leak is to define ReadMessageHelper as a newobject in order for Java to take control of the memory.
%newobject ReadMessageHelper();
JAVA call now would look like:
HEADER hdr;
hdr = SWIG.ReadMessageHelper();
If you are lucky, as I was, you may have another API available to release the message buffer. In which case, you wouldn’t have to do step 4.
William Fulton, the SWIG guru, had this to say about the approach above:
“I wouldn't see the helper function as a kludge, more the simplest solution to a tricky problem. Consider what the equivalent pure 100% Java code would be for ReadMessage(). I don't think there is an equivalent as Java classes are passed by reference and there is no such thing as a reference to a reference, or pointer to a pointer in Java. In the C function you have, a HEADER instances is created by ReadMessage and passed back to the caller. I don't see how one can do the equivalent in Java without providing some wrapper class around HEADER and passing the wrapper to the ReadMessage function. At the end of the day, ReadMessage returns a newly created HEADER and the Java way of returning newly created objects is to return it in the return value, not via a parameter.”
Using SWIG typemap to pass pointer-to-pointer:
Here is another approach using typemaps. It is targetting Perl, not Java, but the concepts are the same. And I finally managed to get it working using typemaps and no helper functions:
For this function:
typedef void * MyType;
int getblock( int a, int b, MyType *block );
I have 2 typemaps:
%typemap(perl5, in, numinputs=0) void ** data( void * scrap )
{
$1 = &scrap;
}
%typemap(perl5, argout) void ** data
{
SV* tempsv = sv_newmortal();
if ( argvi >= items ) EXTEND(sp,1);
SWIG_MakePtr( tempsv, (void *)*$1, $descriptor(void *), 0);
$result = tempsv;
argvi++;
}
And the function is defined as:
int getblock( int a, int b, void ** data );
In my swig .i file. Now, this passes back an opaque pointer in the argout typemap, becaust that's what useful for this particular situation, however, you could replace the SWIG_MakePtr line with stuff to actually do stuff with the data in the pointer if you wanted to. Also, when I want to pass the pointer into a function, I have a typemap that looks like this:
%typemap(perl5, in) void * data
{
if ( !(SvROK($input)) croak( "Not a reference...\n" );
if ( SWIG_ConvertPtr($input, (void **) &$1, $1_descriptor, 0 ) == -1 )
croak( "Couldn't convert $1 to $1_descriptor\n");
}
And the function is defined as:
int useblock( void * data );
In my swig .i file.
Obviously, this is all perl, but should map pretty directly to Java as far as the typemap architecture goes. Hope it helps...
I managed to solve this using Swig Managed Arrays and Pinning documentation.
Given a function in C++
void myArrayCopy(int *sourceArray, int *targetArray, int nitems);
Declare the method as unsafe in C#
%csmethodmodifiers myArrayCopy "public unsafe";
Add the appropriate typemaps
%include "arrays_csharp.i"
%apply int FIXED[] {int *sourceArray}
%apply int FIXED[] {int *targetArray}
As a result, we get the following method in the module class:
public unsafe static void myArrayCopy(int[] sourceArray, int[] targetArray, int nitems)
{
fixed ( int *swig_ptrTo_sourceArray = sourceArray )
{
fixed ( int *swig_ptrTo_targetArray = targetArray )
{
examplePINVOKE.myArrayCopy((IntPtr)swig_ptrTo_sourceArray,
(IntPtr)swig_ptrTo_targetArray,
nitems);
}
}
}
In practice this might differ a little with FooClass** but Swig does support direct pointer to pointer marshalling, which also avoids a copy as well so can be considered better performance