I am attempting to write a C# class (2010) that allows the usage of functions contained in a legacy C++ dll. The functions are exported using __stdcall, and have varying sets of parameters. I have no issue dealing with strings and other primatives, and am able to invoke these functions without issue.
The problem is that a few of the functions contain a CArray & reference as a parameter. I cannot figure out how to marshal this datatype, or if it's even possible.
I can't change the legacy DLL code, unfortunately.
To deal with this correctly, you can make a wrapper DLL (using the same MFC/C++ runtime version as what you want to call into, and make sure accepts the same array in the form of, say, a traditional pointer to a native C++ array.
This wrapper DLL can be called into from C#.
You could try with a more recent MFC version (and use C++/CLI for the marshalling), but then the new CArray could be binary incompatible with what to legacy library expects.
Related
When calling a method on a C++ object from .NET using the .calli IL-instruction, how do you resolve the pointer to the actual method you want to call? I realize that this is going to be platform dependant.
I know the excellent SharpDX library uses the .calli instruction extensively, and I have peeked at the code it generates, and the method pointer gets pulled out like this:
((void**)(*(void**)_nativePointer))[69]
where _nativePointer is a pointer to the object instance. It's then cast to a void** which is de-references, and then cast again to a void** which indexes into slot 69. I just can't figure out what exactly is going on here.
Calli opcode will only work with objects having a vtable but cannot be used with standard C++ methods (non virtuals). It also requires that objects follow the same ABI, thus this is working well with COM as it defines a standard ABI to access C++ objects. But this will not work with, for example, C++ multiple inheritance.
In order to access plain C++ method on an object, you need to have a generated C wrapper that provides a plain C function for each C++ method where the first parameter is usually the instance of the C++ object and the following parameters are the parameters from the C++ method (Some wrapper, like CXXI, are sometimes able to link directly to C++ objects by following compilers ABI). So in order to make this bridge you can:
Develop your own C wrapper (A dynamic library DLL/so that is providing these functions translating calls to C++ object)
SWIG is typically used to automate this kind of C++/C# bridge.
There was also an attempt from some Mono folks to provide a C++ bridging called CXXI, but doesn't seem to be developed.
I've been working recently in COM interop thing.Read some Good books about it C++/CLI in Action By Nishant Shivakumar. I also went through this link by Srinivas wherein he has explained beautifully how to Consume C# libraryin native C++ using C++/CLI.I downloaded the code present at the bottom of the page..Read it..And loved it.My application is loosely based on it. I have a question though in that example(which you can download it there).
In C# Library "Worker.cs",If I have a method in the Worker class with a signature like this::
public void GetStudent(ManagedStudent student,int ){....}
FYI:: I need the object parameter because I would be accessing a method from that class in the Worker Class.
In C++/CLI wrapper project, NativeInterface.h, I wanted to export a method which gets this managed object as a parameter unlike the example.
__declspec dllexport void GetStudent(ManagedStudent^ obj)
What is the equivalent of an object in C++/CLI?
And later I want to access this method by importing this method by passing an object in my native Win32 Application/DLL.
I am including the "NativeInterface.h" file in my native dll/App . But an error comes while building the dll/App..managed targeted code requires \clr option.
FYI::
1. My WIN32 dll/app is being compiled with no \clr support and my wrapper with \clr support
2. I believe the error comes because of the handle used as a parameter? I want to access UnmanagedStudent(Object obj) in native app/dll;
Is that possible
It's possible, but you can't pass a .NET object to a native DLL, which is a native C++ code...
The equivalent of an .NET object in native C++ is C++ object... but this is like asking a C# to understand Native or PHP, or....
So, there are several approaches.
Don't use C++ managed wrapper. Instead using Marsahling and C# interoperability directly call into native C++, in 1 of 2 ways:
Pass the object fields as a long list of parameters to the C++ and re-construct the object inside native C++. A bit "not nice" approach but very efficient and easy to debug.
You can also pass the object as a class pointer to the C++ native directly, you need first to create the right marshaling in C#. See here:
http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal(v=vs.110).aspx
Use C++ Interop (which you are doing...). You need to compile with Mixed mode! See this nice example:
http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/f2de75c5-50a6-41ac-9ddf-694a8c0ce75b/
BUT... you need to understand the basics and know how to compile it:
http://msdn.microsoft.com/en-us/library/x0w2664k.aspx
Interoperability is a complex issue... and I try to write a short answer, please revert to me for further clarifications....
I wrote my program in C++ and exported it as a DLL. I have a C# WPF GUI and I want to import the DLL to do the processing.
I am very new to C#. How can I use the C++ class in C#? I know I can't just use the .h file.
Because I used pointers in C++, in C# I couldn't use pointers. That's why I got confused. Like in C++ i used char* instead of string, and I need to return double* for a big collection of double data, and things like that.
There are a number of ways:
Export the DLL functions and use DllImportAttribute to P/Invoke into the DLL.
If it is a COM DLL, then you can generate a Runtime Callable Wrapper via TLBIMP.exe
You can use C++/CLI to build create a .Net assembly which loads and calls methods on the DLL natively.
To address your additional concerns, yes, you can use pointers in C#. If you have a function which has a double* parameter, you can declare that in C# like this:
[DllImport("Your.DLL")]
private static extern unsafe void DoProcessing(double* data, int dataSize);
You need to make sure you check the "Allow Unsafe Code" checkbox on the build tab of the C# project, and after that, you can use pointers to your heart's content.
However, note that while I'm providing the pointer signature here, since you are obviously comfortable with pointers, there are other signatures which could be more safe for you to use, and would not require you to compile C# with unsafe code. The standard marshaller in the CLR will take care of the conversion from a pointer to a C# array, provided you give it a bit of a hint if the length is required:
[DllImport("Your.DLL")]
private static extern void DoProcessing(
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)] double[] data,
int dataSize);
This instructs the marshaller to use the parameter at index 1 (the 2nd parameter) as the size of the array of doubles pointed at by the 1st parameter. This allows you to avoid pointers in C#, and use safe CLI types. However, if you like pointers, my advice is to just use them - the C# will be easier for you than having to figure out how to write the method signature without them.
For more details on P/Invoke, refer to this documentation: http://msdn.microsoft.com/en-us/library/aa288468(VS.71).aspx
A lot depends on the structure of your C++ dll. If you have just a handful of functions, and they are not member functions of a class, then you can make them "extern C" functions and use the P/Invoke capability in .NET (sometimes called DllImport because of the attribute you use) to access the functions from C#.
I have a Delphi DLL with a function defined as:
function SubmitJobStringList(joblist: tStringList; var jobno: Integer): Integer;
I am calling this from C#. How do I declare the first parameter as a tStringList does not exist in C#. I currently have the declaration as:
[DllImport("opt7bja.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
public static extern int SubmitJobStringList(string[] tStringList, ref int jobno);
But when I call it I get a memory access violation exception.
Anyone know how to pass to a tStringList correctly from C#?
You'll most likely not have any luck with this. The TStringList is more than just an array, it's a full-blown class, and the exact implementation details may differ from what is possible with .NET. Take a look at the Delphi VCL source code (that is, if you have it) and try to find out if you can rebuild the class in C#, and pass it with the help of your best friend, the Interop Marshaller. Note that even the Delphi string type is different from the .NET string type, and passing it without telling the marshaller what he should do, he will pass it as a char-array, most likely.
Other than that, I would suggest changing the Delphi DLL. It's never a good thing to expose anything Delphi-specific in a DLL that is to be used by non-Delphi clients. Make the parameter an array of PChar and you should be fine.
If this is your DLL, I'd rewrite the function to accept an array of strings instead. Avoid passing classes as DLL parameters.
Or, if you really want to use a TStringList for some reason, Delphi's VCL.Net can be used from any .Net language.
An old example using TIniFile: http://cc.codegear.com/Item/22691
The example uses .Net 1.1 in Delphi 2005. Delphi 2006 and 2007 support .Net 2.0.
If you don't control the DLL and they can't or won't change it, you could always write your own Delphi wrapper in a separate DLL with parameters that are more cross-language friendly.
Having a class as a parameter of a DLL function really is bad form.
I am not exactly clear your way of using delphi and C#. It seems you have created a Win32 DLL which you want to call from C#. Offcourse you must be using PInvoke for this.
I would suggest that you create a .NET DLL using your source code since complete porting of VCL is available. I can further elaborate if you wish....
In theory, you could do something like this by using pointers (casting them as the C# IntPtr type) instead of strongly typed object references (or perhaps wrapping them in some other type to avoid having to declare unsafe blocks), but the essential catch is this: The Delphi runtime must be the mechanism for allocating and deallocating memory for the objects. To that end, you must declare functions in your Delphi-compiled DLL which invoke the constructors and destructors for the TStringList class, you must make sure that your Delphi DLL uses the ShareMem unit, and you must take responsibility for incrementing and decrementing the reference count for your Delphi AnsiStrings before they leave the DLL and after they enter it, preferably also as functions exported from your Delphi DLL.
In short, it's a lot of work since you must juggle two memory managers in the same process (the .NET CLR and Delphi's allocators) and you must both manage the memory manually and "fool" the Delphi memory manager and runtime. Is there a particular reason you are bound to this setup? Could you describe the problem you are trying to solve at a higher level?
As Hemant Jangid said, you should easily be able to do this by compiling your code as a .NET dll and then referring to that assembly in your c# project.
Of course, you'll only be able to do this if the version of Delphi you have has Delphi.NET.
I don't know a lot about c#, but a technique that I use for transporting stringlists across contexts is using the .text property to get a string representing the list, then assigning that property on "the other side".
It's usually easier to get a string over the wall that it is a full blown object.
I have an interface that I have defined in C++ which now needs to be implemented in C#. What is the best way to go about this? I don't want to use COM at all in my interface definition. The way I have solved this right now is to to have two interface definitions, one in C++ and one in C#. I then expose the C# interfaces as a COM server. This was my application which is written in C++ can call into C#. Is there anyway I can avoid having to define my implementation in C++ as well as C#?
If you are willing to use C++/CLI for your managed code instead of C#, then you can just consume the native C++ interface definition directly via the header file. How easy this will be will depend on exactly what is in your interface - simplest case is something that you could use from C.
Take a look at Marcus Heege's Expert C++/CLI: .NET for Visual C++ Programmers, for a lot of helpful information on mixing native and managed C++ in .NET.
Swig is a great tool for wrapping C++ classes in other languages like C#.
Why don't you want to use COM?
This would have been my suggestion. COM interop has worked really well for me, and I've used COM objects and interfaces in C# (simply reference the COM object and the runtime callable wrapper gets created automatically). Similarly marking a C# class as "Register for COM interop" has worked the other way around.
Write the interface in C++ and use macros to make it look like a standard cpp header file on UNIX and like an IDL file on windows (If this does not work out, you can always write a python/ruby script to generate the IDL from the C++ header file).
Compile the IDL to generate a typelib. Use TypeLib Importer to generate the interface definitions for C# and implement the interfaces there.
The other approach is to use a 'flat', C-style API. You might as well use extern "C" to prevent accidental overloading. Use a DEF file to explicitly name the exported functions, so they're definitely not decorated in any way (C++ functions are 'decorated' with an encoding of the parameter types in the export table).
On x86, beware of calling conventions. It's probably to explicitly declare the use of __stdcall or __cdecl. Because P/Invoke is primarily used to invoke Windows APIs, it defaults to StdCall, but C and C++ default to cdecl, because that supports varargs.
I recently wrapped the COM interface IRapiStream in a flat C interface as .NET seemed to be trying to convert the IStream into a storage, which failed with the error STG_E_UNIMPLEMENTEDFUNCTION.
You don't mention which version of .NET you're using, but something that's worked for me in using Visual Studio .NET 2003 is to provide a thin C# wrapper around the pimpled implementation of the real C++ class:
public __gc class MyClass_Net {
public:
MyClass_Net()
:native_ptr_(new MyClass())
{
}
~MyClass_Net()
{
delete native_ptr_;
}
private:
MyClass __nogc *native_ptr_;
};
Obviously, one would prefer to use a Boost shared_ptr there, but I could never get them to play nicely with V.NET 2003...
Methods simply forward to the underlying C++ methods through the pointer. Method arguments may have to be converted. For example, to call a C++ method which takes a string, the C# method should probably take a System.String (System::String in Managed C++). You'd have to use System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi() to do that.
One nice thing about this approach is because Managed C++ is a .NET language, you get to expose accessors as properties (__property). You can even expose attributes, very much like in C#.