I have a Delphi DLL that contains the following types:
type
TStepModeType = (smSingle, smMultiStep);
TParameter = record
Number: Integer;
end;
TStruct = record
ModType: PAnsiChar;
ModTypeRev: Integer;
ModTypeID: Integer;
RecipeName: PAnsiChar;
RecipeID: Double;
RootParamCount: Integer;
StepMode: TStepModeType;
ParamCount: Integer;
Parameters: array of TParameter;
end;
I need to call this DLL from C# passing a ref object corresponding to the Delphi types that the DLL will fill and return. I have defined structures in my C# code like this:
enum stepModeType
{
Single,
MultiStep
}
[StructLayout(LayoutKind.Sequential)]
struct parameter
{
public int Number;
}
[StructLayout(LayoutKind.Sequential)]
struct recipe
{
public string modType;
public int modTypeRev;
public int modTypeId;
public string recipeName;
public double recipeId;
public int rootParamCount;
public stepModeType stepMode;
public int paramCount;
public IntPtr parameters;
}
I was doing fine until I ran into the dynamic array (Parameters: array of TParameter) in the Delphi code. I understand that dynamic arrays are a Delphi only construct, so I chose to use an IntPtr in my C# code in the hopes of just getting a pointer to the array and pulling the contents. Unfortunately, I am rather new to this interop stuff and I am not sure how to deal with the IntPtr.
Let's say the Delphi DLL populates the dynamic array with 2 parameter items. Can someone possibly show me the C# code that would get those 2 parameter items out of the array once it gets passed back from the Delphi DLL to my C# calling application?
UPDATE: Well, as it happens the Delphi code I was given was a simplified version. One of our Delphi developers thought it would be easier to get started with the simplified version than the real version, which is substantially more complex containing dynamic arrays of dynamic arrays of dynamic arrays. Anyway, I am now completely over my head. I only know enough about Delphi to be dangerous. Below is the code for the real structures in the Delphi code. Any further guidance on how to deal with these structures from my C# calling application would be greatly appreciated. It may not even be possible with the nesting of dynamic arrays such that they are.
type
TStepModeType = (smSingle, smMultiStep);
TParamValue = record
strVal: String;
fVal: Double;
Changed: Boolean;
end;
TSteps = array of TParamValue;
TRule = record
Value: String;
TargetEnabled: Boolean;
end;
TParamInfo = record
Caption: String;
Units: String;
RuleCount: Integer;
Rules: array of TRule;
end;
TParameter = record
Info: TParamInfo;
Steps: TSteps;
end;
TStruct = record
ModType: PAnsiChar;
ModTypeRev: Integer;
ModTypeID: Integer;
RecipeName: PAnsiChar;
RecipeID: Double;
RootParamCount: Integer;
StepMode: TStepModeType;
ParamCount: Integer;
Parameters: array of TParameter;
end;
I am assuming trust that the DLL has a function that deallocates the recipe struct. That's something that you can't possibly hope to do from C#. More on this point later on.
A Delphi dynamic array is not a valid interop type. It really should only used internally to Delphi code compiled with a single version of the compiler. Exposing it publically is akin to exporting C++ classes from a DLL.
In an ideal world you would re-work the Delphi code so that it exported the array using a proper interop type. However, in this case it is actually relatively easy for you to do the marshalling without adjusting the Delphi code.
Delphi dynamic arrays were introduced way back in Delphi 4 and their implementation has remained unchanged since then. The array of T dynamic array variable is effectively a pointer to the first element. The elements are laid out sequentially in memory. The dynamic array variable also maintains (at negative offsets) a reference count and the size of the array. You can safely ignore these since you are neither modifying the dynamic array nor needing to ascertain its size.
Using IntPtr for the Parameters field is perfect. Because TParameter contains just a single 32 bit integer you can use Marshal.Copy to copy it straight to an int[] array.
So, when the Delphi DLL returns, you can do the final marshalling step using Marshal.Copy.
if (theRecipe.paramCount>0)
{
int[] parameters = new int[theRecipe.paramCount];
Marshal.Copy(theRecipe.parameters, parameters, 0, theRecipe.paramCount);
... do something with parameters
}
That deals with the dynamic array, but as it happens you have another problem with your code as it stands. You are declaring the two strings as string in the C# struct. This means that the marshaller will take responsibility for freeing the memory returned by the Delphi DLL in the two PAnsiChar fields. It will do so by calling CoTaskMemFree. I'm fairly sure that's not going to match the allocation of the PAnsiChar fields made in the Delphi code.
As stated above, I would expect that the contract for this interface is that you call a further DLL function to deallocate the heap memory referenced by the recipe struct. That is, the two strings, and the dynamic array.
To deal with this issue from C# you need to make sure that the marshaller does not attempt to deallocate the PAnsiChar fields. You can achieve that by declaring them as IntPtr in the C# struct. Then call Marshal.PtrToStringAnsi to convert to a C# string.
I've had to make a few assumptions about the contract between the Delphi code and the C# code in order to write the above. If any of my assumptions are incorrect please update the question and I'll try to make this answer match! I hope this helps.
Jargon confusion I suspect, my first thought was simply.
public parameter[] parameters;
Two options: Either you figure out exactly how dynamic arrays are stored and match that on the c# side or better still create a set of basic methods on the Delphi side that can be called from the c# side to manipulate the array and record, eg getItem and setItem etc. That's usually what is done when there are incompatible types across a language barrier. I would use the later approach because you don't know whether at some point in the future the memory structure of a dynamic array might change.
By the way, why have you defined TParameter as a record, you could have used TParameter = integer ?
I found this link which has something to say about the structure of Delphi dynamic arrays:
http://www.programmersheaven.com/mb/delphikylix/262971/262971/dynamic-array-memory-storage/
And this link has even more details. The structure is a bit more complicated than a simple array.
Dynamic Array Structure
Related
I'm learning C++ and it seems like it is impossible to have an array as a return type. Is this true?
int foo(){}
works fine but
int[] foo(){}
does not. What is the commonly accepted work around to this?
I'm currently working on a project that utilizes both C# and C++. I have a C# file that access some DLL code with:
[DllImport("Test.dll")]
public static extern byte[,] getBytes(
[In] string filePath,
[In] string dataGroup);
My header file has:
TEST_DLL BYTE[][] getBytes(std::string filePath, std::string dataGroup);
/* This throws an error since I can't use an array as a return type. */
and my implementation inside the .cpp file is:
TEST_DLL BYTE[][] getBytes(std::string filePath, std::string dataGroup)
{
printf("getBytes entered."
/* More code here...*/
}
/* This also throws an error due to the array use. */
Basically, I'm trying to return a 2D byte array from my DLL code without needing to convert anything on the C# side, i.e., all code execution related to getBytes should occur in the C++ code.
I have a working example of this that does not use an array but rather a void*, which from my understanding is a pointer to the array I'm returning. I then have a C# function that uses an IntPtr and Marshal.Copy to get the byte array. I'm trying to determine the overhead difference between the two methods. I would imagine that it would be much faster to return a 2D byte array directly from the C++ code instead of using the additional C# conversion code (the datasets I'm using are huge - some over 500GB so every little bit of optimization counts).
Basically, how can I retrieve a 2D byte array purely from my C++ code without having to convert it in C#?
You have two separate issues:
Returning an array from a C/C++ function (method)
Interoperating with C#.
There are a number of solutions to issue #1. Probably the best is to return a vector (if you want to copy the data out) or a reference to a vector (if you have a return value that will stay around "forever")) You could also pass in a reference to a vector as a parameter and populate the vector in your function.
Issue #2: A C# array is NOT a native data type in C++, so you will need special purpose code to "marshal" the data into the appropriate C# type. See this question for more details.
How can i use this dll function in c#? I tried the following but i get error.
"External component has thrown an exception."
First time i am doing this PInvoke stuff with C# and Delphi.
function HTTPGET(location:string):string; stdcall;
var
HTTP:TIdHttp;
begin
HTTP := TidHttp.Create(nil);
try
result := HTTP.Get(location);
finally
FreeAndNil(HTTP);
end;
end;
exports
HTTPGET;
begin
end.
namespace Test
{
class Program
{
[DllImport("project1.dll")]
public static extern string HTTPGET(string location);
static void Main(string[] args)
{
Console.WriteLine(HTTPGET("http://www.reuters.com/"));
}
}
}
You cannot call that function from C#. That's because you cannot use Delphi string for interop. You can use PAnsiChar for strings passed from managed to unmanaged, but in the other direction it's more complex. You'd need to allocate the memory at the caller, or use a shared heap. I prefer the latter approach which is easiest done with the COM BSTR. This is WideString in Delphi.
As has been discussed before, you cannot use WideString as a return value for interop, since Delphi uses a different ABI from MS tools for return values.
The Delphi code needs to look like this:
procedure HTTPGET(URL: PAnsiChar; out result: WideString); stdcall;
On the C# side you write it like this:
[DllImport("project1.dll")]
public static extern void HTTPGET(
string URL,
[MarshalAs(UnmanagedType.BStr)]
out string result
);
If you want Unicode for the URL then use PWideChar and CharSet.Unicode.
procedure HTTPGET(URL: PWideChar; out result: WideString); stdcall;
....
[DllImport("project1.dll", CharSet=CharSet.Unicode)]
public static extern void HTTPGET(
string URL,
[MarshalAs(UnmanagedType.BStr)]
out string result
);
Do not use string type: strings require memory management, and C# and Delphi modules obviously use different memory managers (leave alone that C# passes char* and Delphi expects String). Try changing location type to PChar in your DLL, and also change your result type so it's either PChar (the buffer should be allocated explicitly) or something else, but not string.
As i remember, you can't marshall delphi strings with C#... you have to use a workaround with PChar and manage the memory yourself, or use something like the workaround provided in the last answer here:
Using Delphi's stuct arrays and strings in C#
Try Unmanaged Exports for c# by Robert Giesecke
https://sites.google.com/site/robertgiesecke/Home/uploads/unmanagedexports
we are using encrypting engine from c# in Delphi App due compatibility with php and works well (so, the mentioned strings problem do not exists).
our earlier solution (worse) : register c# dll as com component and use it. with above solution output library have to be placed in exe directory and without registration works well :)
What is equivalent of the VARIANT datatype of C++ in C#?
I have code in C++ which uses the VARIANT datatype. How can I convert that code in C#?
Well, there are actually two variant's in C++: boost::variant and COM variant. The solution follows more or less the same idea, but the former is more complex. I expect you mean to use the latter.
Let me first start by telling that this is something you just shouldn't use if possible. That said, this is how you do it :-)
Variants and interop
Variants are sometimes used in interop of if you need the byte representation to be the same.
If you're dealing with interop, make sure to check out the VariantWrapper class on MSDN and make it work like that.
Variants and porting considerations
Variants are mostly used in APIs, and usually like this:
void Foo(SomeEnum operation, Variant data);
The reason it's done like this in C++ is because there is no base object class and you therefore need something like this. The easiest way to port this is to change the signature to:
void Foo(SomeEnum operation, object data);
However, if you're porting anyway, you also seriously want to consider these two, since they are resolved at compile-time and can save you the big 'switch' that usually follows in method Foo:
void SomeOperation(int data);
void SomeOperation(float data);
// etc
Variants and byte consistency
In rare cases you need to manipulate the bytes themselves.
Essentially the variant is just a big union of value types wrapped in a single value type (struct). In C++, you can allocate a value type on the heap because a struct is the same as a class (well sort-of). How the value type is being used is just a bit important but more on that later.
Union simply means you are going to overlap all the data in memory. Notice how I explicitly noted value type above; for variant's this is basically what it's all about. This also gives us a way to test it - namely by checking another value in the struct.
The way to do this in C# is to use the StructLayout attribute in a value type, which basically works as follows:
[StructLayout(LayoutKind.Explicit)]
public struct Variant
{
[FieldOffset(0)]
public int Integer;
[FieldOffset(0)]
public float Float;
[FieldOffset(0)]
public double Double;
[FieldOffset(0)]
public byte Byte;
// etc
}
// Check if it works - shouldn't print 0.
public class VariantTest
{
static void Main(string[] args)
{
Variant v = new Variant() { Integer = 2 };
Console.WriteLine("{0}", v.Float);
Console.ReadLine();
}
}
C++ variant's can also be stored on the heap as I noted earlier. If you do this, you probably still want the memory signature to be the same. The way to do this is to box the Variant struct we build earlier by simply casing it to object.
This is a tricky question.
From C# 4, you can use dynamic to indicate that the type is known at run-time.
By my personal understanding, however, c++ requires the type known at compile time. Thus you might consider to use object, but object in C# is an existent type.
For the concept of multi-type, single value (AKA polymorphism) of VARIANT, you would not need to find a corresponding type in C#, just define your classes and interfaces. You can always reference an object as its interface which the class implements.
If you are porting the code, and to figure out a syntax that you can simply use in LHS and for the considering of the type is known at compile time, then use var.
When .NET implements a COM interface, just use VARIANT* instead.
Then bypass marshalling on the .NET receiving side by using a IntPtr type to receive the pointer.
public class ComVariant
{
[StructLayout(LayoutKind.Sequential)]
public struct Variant
{
public ushort vt;
public ushort wReserved1;
public ushort wReserved2;
public ushort wReserved3;
public Int32 data01;
public Int32 data02;
}
private Variant _variant;
private IntPtr _variantPtr;
public ComVariant(int variantPtr) : this(new IntPtr(variantPtr))
{
}
public ComVariant(IntPtr variantPtr)
{
_variant = (Variant)Marshal.PtrToStructure(variantPtr, typeof(Variant));
_variantPtr = variantPtr;
}
public VarEnum Vt
{
get
{
return (VarEnum)_variant.vt;
}
set
{
_variant.vt = (ushort)value;
}
}
public object Object
{
get
{
return Marshal.GetObjectForNativeVariant(_variantPtr);
}
}
}
then if you are accessing a VT_UNKNOWN pointing to a COM interface object instance, just
var variant = new ComVariant(variantPtr);
var stream = variant.Object as IStream; // will not be null if type is correct
var obj = variant.Object as IObj; // in general...
will do the trick, but pay attention not to use a newly allocated VARIANT and giving its ownership to the .NET implementation without deallocating it somewhere...
For more complex code you might read this article which also talks about memory management.
Let's take a step back. Sooner or later, we want the actual data in the VARIANT. A VARIANT is just a holder for meaningful data. Suppose we converted the VARIANT to some sort of Object in C# that had the variant type and some raw buffer under the .NET hood (e.g. .NET strings can expose the raw buffer). At that point, the VARIANT type would need to be determined from the object and the raw data converted or cast to the data type specified by the variant, and then create a new Object e.g. string/int/etc. from the raw data.
So, rather than worry about passing the VARIANT to C#, look at the variant data type and convert it in C++ to the actual data type and pass that to C#.
For example, if the VARIANT type is VT_INT, then get the int from the variant and can use something like:
VARIANT var;
Int^ returnInt = gcnew Int(var.intVal);
returnInt can be returned as an Out parameter from a C++ function in a C++ dll that can be called from C#. The C++ dll needs to use /clr option.
Function would look like:-
void ThisFunctionReturnsAnInt(Runtime::InteropServices::OutAttribute Int^ % returnIntValue)
{
VARIANT var;
Int^ returnInt = gcnew Int(var.intVal);
}
Can use similar approach for other data types. It's only natural, a VARIANT of VT_INT is really just like an int, it's not as if there's some major conversion going on, you're just taking the actual value out of the VARIANT at the time when you're interested in it as you would if you were passing a straight integer value from C++ to C#. You would still need to do the gcnew anyway.
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.
So what I have is a C++ API contained within a *.dll and I want to use a C# application to call methods within the API.
So far I have created a C++ / CLR project that includes the native C++ API and managed to create a "bridge" class that looks a bit like the following:
// ManagedBridge.h
#include <CoreAPI.h>
using namespace __CORE_API;
namespace ManagedAPIWrapper
{
public ref class Bridge
{
public:
int bridge_test(void);
int bridge_test2(api_struct* temp);
}
}
.
// ManagedBridge.cpp
#include <ManagedBridge.h>
int Bridge::bridge_test(void)
{
return test();
}
int Bridge::bridge_test2(api_struct* temp)
{
return test2(temp);
}
I also have a C# application that has a reference to the C++/CLR "Bridge.dll" and then uses the methods contained within. I have a number of problems with this:
I can't figure out how to call bridge_test2 within the C# program, as it has no knowledge of what a api_struct actually is. I know that I need to marshal the object somewhere, but do I do it in the C# program or the C++/CLR bridge?
This seems like a very long-winded way of exposing all of the methods in the API, is there not an easier way that I'm missing out? (That doesn't use P/Invoke!)
EDIT: Ok, so I've got the basics working now thanks to responses below, however my struct (call it "api_struct2" for this example) has both a native enum and union in the C++ native code, like the following:
typedef struct
{
enum_type1 eEnumExample;
union
{
long lData;
int iData;
unsigned char ucArray[128];
char *cString;
void *pvoid;
} uData;
} api_struct2;
I think I have figured out how to get the enum working; I've re-declared it in managed code and am performing a "native_enum test = static_cast(eEnumExample)" to switch the managed version to native.
However the union has got me stumped, I'm not really sure how to attack it.. Ideas anyone?
Yes, you are passing an unmanaged structure by reference. That's a problem for a C# program, pointers are quite incompatible with garbage collection. Not counting the fact that it probably doesn't have the declaration for the structure either.
You can solve it by declaring a managed version of the structure:
public value struct managed_api_struct {
// Members...
};
Now you can declare the method as
int bridge_test2(managed_api_struct temp); // pass by value
or
int bridge_test2(managed_api_struct% temp); // pass by reference
Pick the latter if the structure has more than 4 fields (~16 bytes). The method needs to copy the structure members, one-by-one, into an unmanaged api_struct and call the unmanaged class method. This is unfortunately necessary because the memory layout of a managed structure is not predictable.
This is all pretty mechanical, you might get help from SWIG. Haven't used it myself, not sure if it is smart enough to deal with a passed structure.
A completely different approach is to make the wrapper class cleaner by giving it a constructor and/or properties that lets you build the content of an api_struct. Or you could declare a wrapper ref class for the structure, much like you would in managed code.
as it has no knowledge of what a api_struct actually is
You need to define a managed version in a .NET assembly, that uses attributes (like StructLayoutAttribute) to ensure it marshals correctly.
This seems like a very long-winded [...]
The other approach is to create a COM wrapper (e.g. using ATL) around your API. This might be more effort, but at least you avoid the double coding of struct and function definitions needed for P/Invoke.
Correction: You have created a C++/CLI project: so just add correct '#pragma' to tell the compiler this is .NET code, and then the output is an assembly the C# project can just reference.
Yuo are trying to do this way more complicated that it really is. What you want is two different structs. One managed and one unmanaged. You expose the managed version externally (to your C# app). It will be all ".Net-ish" with no concepts of unions or so.
In your bridge you receive the managed version of the struct, manually create the unmanaged struct and write code to move your data, field by field over to the unmanaged struct. Then call your unmanaged code and finally move the data back to the managed struct.
The beautiful thing about C++/CLI is that the managed code also can work with unmanaged code and data (and include the unmanaged .h files).