Function with multiple return parameter - c#

I am new to C#. For a motor driver that we use, I want to see its current and there is a BOOL function in motor driver's guide. But I have no idea how I can use it.
VCS_GetCurrentIsAveraged(KeyHandle,NodeId, short* pCurrentIsAveraged,
pErrorCode)
for this function KeyHandle and NodeId are parameters and pCurrentIsAveraged and pErrorCode are return parameters.
I have all parameters already in my code except pCurrentIsAveraged, which is what I want to see. So how can I get this value as a return.
//Initialize
short* pCurrentIsAveraged;
double current;
current=VCS_GetCurrentIsAveraged(KeyHandle,NodeId,pCurrentIsAveraged,
pErrorCode)
Would this work, I want to get current but what should I enter for pCurrentIsAveraged value as return parameter?
Thanks.

Using the function signature VCS_GetCurrentIsAveraged(KeyHandle,NodeId, short* pCurrentIsAveraged, pErrorCode) requires you to use unsafe code, which, if you are new to C#, you should avoid. That looks like a p/invoke wrapper around a C-style API.
As it stands, you would need to call it like this (from an unsafe block) (fixing may not be needed if currentIsAveraged happens to be allocated on the stack):
short currentIsAveraged = 0;
double current;
fixed (short* pCurrentIsAveraged = &currentIsAveraged) {
current = VCS_GetCurrentIsAveraged(KeyHandle,NodeId,pCurrentIsAveraged, pErrorCode);
}
bool isCurrentAveraged = (currentIsAveraged != 0);
If you have control of the p/invoke definition of VCS_GetCurrentIsAveraged, you could change that signature to use an ref short pCurrentIsAveraged rather than short* pCurrentIsAveraged. This would let you use that method like this (without the need for unsafe code):
short currentIsAveraged = 0;
double current;
current = VCS_GetCurrentIsAveraged(KeyHandle,NodeId,ref currentIsAveraged, pErrorCode);
bool isCurrentAveraged = (currentIsAveraged != 0);
You can optimize the p/invoke signature further by using [Out] attribute on that value to tell the marshaller to skip a probably unneeded copy, and you could also convice the compiler to treat it as a bool directly rather than going back and forth with a short, but that's all advanced stuff. Check out the System.Runtime.InteropServices namespace if you are interested in that.

Related

How do I call a C++ function that sets the values of an int array from C#?

I have the following function in C++ inside a .dll:
extern "C"
{
__declspec(dllexport) void ColorRamps_getColorRampTable(int n, int *table);
}
It takes in an array with n elements and sets the array values.
How do I call this from C#?
I understand that I must first DllImport the function (?):
[DllImport("ColorRamps.dll")]
static extern void ColorRamps_getColorRampTable(int n, int[] table);
public static void getColorRampTable(int[] table)
{
int n = table.Length;
ColorRamps_getColorRampTable(n, table);
}
Is this correct?
When I call getColorRampTable(int[] table) must I pin the array?
How do I do this?
I tried:
int[] table = new int[164];
GCHandle handle = GCHandle.Alloc(table, GCHandleType.Pinned);
getColorRampTable(table);
handle.Free();
You have two options. One is to rely on the .NET marshaller, another is to use unsafe code.
Both are actually quite simple for your case. The marshaller one:
[DllImport("ColorRamps.dll")]
static extern void ColorRamps_getColorRampTable(int n, [In, Out] int[] table);
public static void getColorRampTable(int[] table)
{
int n = table.Length;
ColorRamps_getColorRampTable(n, table);
}
This has a slight overhead in that the marshaller copies the array to unmanaged memory first, and then copies it back into your array again. EDIT: As Xanatos correctly noted, since int[] is a blittable type, the marshaller actually cheats and passes a pointer to your actual array. Or at least that's the documented behaviour.
If this is a performance problem for you (and it's a real, measured problem - don't do this otherwise), you can pass a pointer to the .NET array directly using unsafe code:
[DllImport("ColorRamps.dll")]
static extern void ColorRamps_getColorRampTable(int n, int* table);
public unsafe static void getColorRampTable(int[] table)
{
int n = table.Length;
fixed (int* pTable = &table)
{
ColorRamps_getColorRampTable(n, pTable);
}
}
The class has to be marked with the unsafe keyword, and you have to enable unsafe code in the project settings.
EDIT:
As above, this doesn't actually apply for the int[] case. I'm going to leave it in here because it's true for non-blittable types, but int[] is blittable, and the marshaller should just pass the pointer directly, while handling the pinning for you. You should still use the [In, Out] attribute, though - even though it will usually behave as In/Out by default, the contract should be clearly specified.
The main difference is that in the first case, the C(++) code never has access to any of the managed memory of yours - it always works on copies of the data. By adding the [In, Out] attributes, you're telling the marshaller to not only copy the data in, but also to copy it out after the call is done - otherwise your table array would never change.
On the other hand, the second variant passes a pointer to the actual array you're using on the C# side - this may or may not be faster, depending on way too many things, and it's generally slightly more unsafe (be very careful about specifying the correct length of the array, for example).
Another EDIT:
There's also an option to use IntPtr table in the P/Invoke method declaration, which allows you additional flexibility. The easiest example would be just pinning the array, which is equivalent to the fixed case:
var hTable = GCHandle.Alloc(table, GCHandleType.Pinned);
try
{
ColorRamps_getColorRampTable(n, hTable.AddrOfPinnedObject());
}
finally
{
hTable.Free();
}
And even allowing you to explicitly manage the copying quite easily:
var pTable = Marshal.AllocHGlobal(sizeof(int) * table.Length);
try
{
Marshal.Copy(table, 0, pTable, table.Length);
ColorRamps_getColorRampTable(n, pTable);
Marshal.Copy(pTable, table, 0, table.Length);
}
finally
{
Marshal.FreeHGlobal(pTable);
}
This is a decent workaround if you can't use unsafe code for some reason, but do remember that it's just as "unsafe" as unsafe code in most scenarios. The truth is, since you're interacting with native code, you're always (somewhat) unsafe - a bug in the native code can easily corrupt your whole application.

How do I pass arrays of struct from .NET to Delphi using unmanaged export (Robert Giesecke)?

I have just asked and obtained an answer to my question that was : "can't return custom type instance with unmanaged export (Robert Giesecke)" -> can't return custom type instance with unmanaged export (Robert Giesecke)
I wonder if (and how) it is possible to pass arrays of struct from .NET to Delphi using unmanaged export (Robert Giesecke):
Returning arrays directly like
[DllExport] public static void CreateSampleInstance(out Sample[] sample)
using array member in a returned struct
[DllExport] public static void CreateSampleInstance(out Sample sample)
and
`public struct Sample
{
Other[] Others;
}`
My question here is how to write the Delphi side and what attribute to set in the .NET one.
Thanks a lot.
Arrays are more tricky because you need to take more care over where the array is allocated and destroyed. The cleanest approach is always to allocate at the caller, pass the array to the callee to let it fill out the array. That approach would look like this in your context:
public struct Sample
{
[MarshalAs(UnmanagedType.BStr)]
public string Name;
}
[DllExport]
public static int func(
[Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)]
Sample[] samples,
ref int len
)
{
// len holds the length of the array on input
// len is assigned the number of items that have been assigned values
// use the return value to indicate success or failure
for (int i = 0; i < len; i++)
samples[i].Name = "foo: " + i.ToString();
return 0;
}
You need to specify that the array needs to be marshalled in the out direction. If you wanted values marshalled both ways then you would use In, Out instead of Out. You also need to use MarshalAs with UnmanagedType.LPArray to indicate how to marshal the array. And you do need to specify the size param so that the marshaller knows how many items to marshal back to the unmanaged code.
And then on the Delphi side you declare the function like this:
type
TSample = record
Name: WideString;
end;
PSample = ^TSample;
function func(samples: PSample; var len: Integer): Integer; stdcall;
external dllname;
Call it like this:
var
samples: array of TSample;
i, len: Integer;
....
len := 10;
SetLength(samples, len);
if func(PSample(samples), len)=0 then
for i := 0 to len-1 do
Writeln(samples[i].Name);
Update
As AlexS discovered (see comments below), passing the size param index by reference is only supported on .net 4. On earlier versions you need to pass the size param index by value.
The reason I chose to pass it by reference here is to allow for the following protocol:
The caller passes in a value indicating how large the array is.
The callee passes out a value indicating how many elements have been populated.
This works well on .net 4, but on earlier versions you would need to use an extra parameter for step 2.

SafeArrayTypeMismatchException while trying to use unmanaged C++ DLL

First of all I'll say that I've searched high and low for the answer to this and when I have found something it's all gibberish to me, not being a C++ programmer. Programming is just a hobby for me.
I am using Visual Studio 2010 Ultimate, in a C# winforms project, in case that helps!
The problem is that I am trying to use a function from an unmanaged DLL (Bo Haglund's Double Dummy Solver). His readme is less than helpful and there are surprisingly few (ie, no) articles on how to use his DLL.
I have the prototype for the function in the DLL that I wish to use.
extern "C" __declspec(dllimport) int __stdcall CalcDDtablePBN(struct ddTableDealPBN tableDealPBN, struct ddTableResults * tablep);
I don't really know much about pointers, but I guessed that I would use "ref" in C#.
Here is his readme on the function:
CalcDDtable
CalcDDtable calculates the double dummy values of the initial 52 cards for all the 20 trump suit/declarer hand combinations.
Before CalcDDtable can be called, a structure of type " ddTableResults" must be declared.
CalcDDtable returns a status integer, "no fault" means the DLL supplies the double dummy scores in the "ddTableResults" type structure.
Status codes:
1=No fault,
Other status codes are errors, with codes equal to SolveBoard status codes.
Structure ”ddTableDeal” defines the dealt cards to be analyzed.
struct ddTableDeal {
unsigned int cards[4][4]; /* 1st index is hand, 2nd index is suit, same coding as for deal.remainCards for SolveBoard. */
};
struct ddTableResults { /* For each combination trump suit / declarer hand, the DLL provides the double dummy score. */
int resTable[5][4]; /* 1st index is trump (0=Spades, 1=Hearts, 2=Diamonds, 3=Clubs, 4=No Trump 2nd index is declarer hand, 0=North, 1=East, 2=South, 3=West */
};
CalcDDtablePBN
In CalcDDtablePBN the remaining cards in the deal information are given in PBN text format, see the description above for SolveBoardPBN. Otherwise, CalcDDtablePBN is identical to CalcDDtable.
struct ddTableDealPBN {
char cards[80];
};
I imported the function as follows:
[DllImport("dds.dll")]
public static extern int CalcDDtablePBN(DDTableDealPBNStruct tableDealPBN, ref DDTableResultsStruct tablep);
Here are my structs:
public struct DDTableDealPBNStruct
{
public char[] cards;
public DDTableDealPBNStruct(char[] pbnCards)
{
cards = pbnCards;
}
}
public struct DDTableResultsStruct
{
public short[,] resTable; /* 1st index is trump (0=Spades, 1=Hearts, 2=Diamonds, 3=Clubs, 4=No Trump 2nd index is declarer hand, 0=North, 1=East, 2=South, 3=West */
}
And this is how I call the function:
const string _dealPBN = "N:QJT..AJ76.AKJ765 AK64.AKJ7654..98 32.T932.KQ32.T43 9875.Q8.T9854.Q2";
DDTableDealPBNStruct tdPBN = new DDTableDealPBNStruct(_dealPBN.ToCharArray());
DDTableResultsStruct results = new DDTableResultsStruct();
results.resTable = new short[5, 4];
CalcDDtablePBN(tdPBN, ref results);
When I run the program, this is the error message I get:
SafeArrayTypeMismatchException was unhandled.
Specified array was not of the expected type.
It does not mention which array was bad, but I would be guessing that it is the short[5,4] array. I tried different [MarshalAs(UnmanagedType.blah)] options to no avail. Can anyone tell me what I'm doing wrong? I am honestly stumped.
I have also tried a few different array types, int, uint, short, Int16, etc, again to no avail. Unless I'm wrong and it's the char[] array that it is complaining about?
Thank you in advance.
You need to describe the layout of the struct.
[StructLayout(LayoutKind.Sequential)]
public struct DDTableResultsStruct
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
public int[] resTable;
}
There doesn't seem to be a way to say the array is 2-dimensional, so I've just given the full size of the array as if it was 1-dimensional. (In C a multdimensional array is laid out contiguously in memory.) Note that the element type is int, not short -- it's 32 bit. You should do the same for the other struct as well.
(Untested code.)

Improper marshaling: C# array to a C++ unmanaged array

I have the following C# code with a structure definition (CInput), obj definition and init, and a call to a C++ (native) DLL function (that has also been written by me).
//C# code
public struct CInput
{
[MarshalAsAttribute(UnmanagedType.R8)]
public double Time;
[MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_R8)]
public double[] Database;
/* other similar fields*/
}
CInput Inputs = new CInput();
/* init of Inputs fields*/
int bfr = Example(ref Inputs); //'Example' being the C++ DLL call
Messagebox.Show(bfr.ToString());
There is an error in the marshaling of the second parameter, I don't know where. Then:
//C++ code
struct CInput {
double Time;
double Database[3650];
/*etc*/
}
int Example(CInput& ObjIn) {
return ObjIn.Database[0]; // just an example
}
If I'm not careful and specify only "SafeArray" in the Database marshaling I get a 'error in reading/writing memory, probably corrupt' etc.
if "Database" was marshaled as ByValArray everything is fine, the values show up correctly. Unfortunately I get an internal size exception because I have many arrays of that size, therefore I have to go for pointers - but anything with "SizeArray" will bring the following results (with the code just posted):
(from C++):
Database[0] = **0**
Database[1..etc] = values of the next parameters in the struct marshaled with ByValArray.
I think I should mention that I need the same identical structure from C# to C++, I'm not looking for anything fancy. So Array in a Struct >>> Array in a Struct.
ANY insight in reference to this would be of great value. I have been looking for hours and I don't have yet a solution.
Many thanks in advance.
As I understand your question, you can't use ByValArray with SizeConst because your real struct has a large number of such arrays which results in the stack overflowing.
You opine that maybe you need to use pointers in your structs and I agree with you. Here is how to do it.
On the C++ side you should declare each array as a pointer to the element type:
struct CInput {
double *array;
}
You may also wish to include the length of the arrays in the struct to avoid excessive amounts of hard-coded constants.
All the hard work happens on the C# side.
public struct CInput
{
public IntPtr array;
}
...
double[] theArray = new double[3650];
CInput input = new CInput();
input.array = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(double))*theArray.Length);
try
{
Marshal.Copy(theArray, 0, input.array, theArray.Length);
//call your C++ function here
}
finally
{
Marshal.FreeHGlobal(input.array);
}
public struct CInput
{
public double Time;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3650)]
public double[] Database;
}
CInput Inputs = new CInput();
int bfr = Example(ref Inputs);
Edit. If you need to have dynamically allocated Database array, both C++ and C# code should be changed. In C++ Database should be defined as double*, and you need to add array length somewhere. In C# Database should be declared as IntPtr, and allocated using Marshal.AllocHGlobal method. Please correct C++ structure according to your requirements, and then C# code can be fixed according to this.

Complicated (?) pinvoke situation - avoid function overloading

Summary:
I have a bunch of C functions I have to call from C#. My current working solution is based on function overloading and I'm wondering if there is a more elegant solution.
The C stuff:
somewhere in a header file
typedef struct _unknown_stuff * handle; // a opaque pointer
an example of the function
func( uint num_entries,
handle * objects,
uint * n)
{ ... }
in C the function should be used similar to this:
// warning: i bet that the syntax is not correct but you should get the idea...
uint n;
func(0, null, &n);
handle * objects = malloc(n * sizeof(handle));
func(n, objects, null);
The C# stuff:
right now I'm doing the following in C#:
public struct handle
{
public IntPtr Pointer;
}
// version to get number of objects
[DllImport(dll, ...]
private static extern void
func( uint must_be_zero,
object must_be_null,
out uint n);
// version to get the actual data
[DllImport(dll, ...]
private static extern void
func( uint num_entries,
[Out] handle[] objects,
int must_be_zero);
and then:
handle[] objects;
uint n = 42;
func(0, null, out n);
objects = new handle[n];
func(n, objects, 0);
The Question
Since I'm a C# noob, I was wondering if this is the best way to do this. Especially I would like to know if there is a way around overloading the function.
First of all, your code as is is wrong, because in the second C# signature your third argument is int, while the corresponding C argument is still int*. It will work when targetting 32-bit Windows, because sizeof(int)==sizeof(int*) there - so when you pass a 0 int you end up passing a null pointer - but it is not 64-bit safe. If you still want to do it that way, you need to use IntPtr there.
Aside from that, you could try:
[DllImport(dll, ...]
private static extern void func(
uint num_entries,
[Out] handle[] objects,
[Out] int[] num_devices);
making the third argument an array so that you could pass null there.
Or just use pointers. There's nothing bad about it, and don't be afraid of unsafe keyword - any kind of P/Invoke is inherently unsafe anyway, so you might as well be explicit about it.
Wouldn't the C dll look at 0, and process that as null?
It only has one function, correct? That is, the C function is defined once, and not separately for a null case, and would have an if( objects == NULL ) check somewhere in there. On most systems (check the stdio.h of the target system) this is 0.
So calling from pinvoke with a 0 value in this place should do what you wanted overloading to do.

Categories

Resources