Calling C# Method from C++ via Delegates Results in Reversed Parameters - c#

I am trying to have a C++ function call a method on a form in C# in order to update the GUI. For some reason, the function call from C++ sends the parameters in reversed order.
So the UpdateDROCallback() function gets 3.0 for the first parameter, 2.0 for the second, and 1.0 for the last when it was called with function(1.0, 2.0, 3.0).
What am I missing here?
[C#]
public partial class Form1 : Form
{
delegate void DROUpdateDelegate(double x, double y, double z);
DROUpdateDelegate m_DROUpdateDelegate;
static DROUpdateDelegate s_DROUpdateDelegate;
public Form1()
{
InitializeComponent();
m_DROUpdateDelegate = new DROUpdateDelegate(UpdateDROCallback);
s_DROUpdateDelegate = new DROUpdateDelegate(UpdateDRO);
}
private void btnGo_Click(object sender, EventArgs e)
{
int address = m_DROUpdateDelegate.Method.MethodHandle.GetFunctionPointer().ToInt32();
TestDll.RegisterScaleUpdateCallback(address);
}
private static void UpdateDROCallback(double x, double y, double z)
{
s_DROUpdateDelegate(x, y, z);
}
private void UpdateDRO(double x, double y, double z)
{
BeginInvoke(
new Action(
() =>
{
lblDROX.Text = x.ToString("0.0000");
lblDROY.Text = y.ToString("0.0000");
lblDROZ.Text = z.ToString("0.0000");
}));
}
}
TestDll.cs:
public static class TestDll
{
(...)
[DllImport("test.dll", EntryPoint = "RegisterScaleUpdateCallback")]
public static extern void RegisterScaleUpdateCallback(int address);
(...)
}
[C++]
StrobeTest.h:
#pragma once
class StrobeTest
{
typedef void (__stdcall *DROUpdate)(double x, double y, double z);
private:
static DROUpdate s_CallbackFunction;
public:
StrobeTest(void);
~StrobeTest(void);
static void InitializeStrobe(void);
static void MoveXAtSpeed(double velocity);
static void CALLBACK RegisterScaleUpdateCallback(DROUpdate function);
};
StrobeTest.cpp
(...)
void StrobeTest::RegisterScaleUpdateCallback(DROUpdate function)
{
StrobeTest::s_CallbackFunction = function;
StrobeTest::s_CallbackFunction(1.0, 2.0, 3.0);
}
(...)

Show the code of TestDll, especially the declaration of TestDll.RegisterScaleUpdateCallback in it. There will be the cause. Make sure that the calling conventions match.

Related

Why is this nested struct creation slower than un-nested?

I've been benchmarking some C# struct creation, and I've been surprised to find that creation of a nested struct is significantly slower than the un-nested version. I would have expected the JITter to basically produce the same assembly for a flat and nested structure, but this appears to not be the case.
Does anyone have an explanation for why the struct construction in my test code below doesn't get optimized down to just writing the 3 doubles? It seems to (if I'm reading the assembly correctly) zero and create a temporary memory location before writing the values to the final location - presumably actually creating a temporary copy of the nested struct.
And in the follow-up, is there a way to avoid this extra work such that the nested struct has similar creation speed to the un-nested one?
public class StructBenchmarks
{
public struct Vector3_dp
{
public Vector3_dp(double x, double y, double z)
{
X = x;
Y = y;
Z = z;
}
public double X;
public double Y;
public double Z;
}
public readonly struct ContainsVector
{
public ContainsVector(double x, double y, double z)
{
m_vector = new Vector3_dp(x, y, z);
}
public ContainsVector(Vector3_dp input)
{
m_vector = input;
}
private readonly Vector3_dp m_vector;
}
private ContainsVector m_vector1;
private ContainsVector m_vector2;
private Vector3_dp m_vector3_dp1;
private Vector3_dp m_vector3_dp2;
// 0.2ns
public void Vector3_dp_Construction()
{
m_vector3_dp1 = new Vector3_dp(20, 30, 40);
}
// 3.8ns
public void Vector_Construction()
{
m_vector1 = new ContainsVector(20, 30, 40);
}
// 3.8ns
public void Vector_ConstructionFromVector3_dp()
{
m_vector1 = new ContainsVector(m_vector3_dp1);
}
// ~0ns
public void Vector3_dp_Copy()
{
m_vector3_dp1 = m_vector3_dp2;
}
// ~0ns
public void Vector_Copy()
{
m_vector1 = m_vector2;
}
}
And SharpLab link: https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA0AXEBDAzgWwB8BYAKAAJLyABAZhoCZyBlDKAVzAwCEYA7MAAt82KAGtcZKuQDeU6VTrlcbThnIA1GF2i0A+gBMADvIWzTZxfS06o+4wAoDEdsAA2McgjTlnrj+QAnj5+7p4AXgCUFpbmFLGWABrkALxeANwxCZQAmqlBmfHZ0gBa+eGFxeQAvmRZZkqhAYmVxY0uYeQ5rdnt/p4lPQq1pPU09LDYznxugcqqXOQAwhB8GNgAlny4NhjQY3JFCUora5vbu9BOHQHevjeewff95FFj0odV0vh6AG7aeyg+T4MAA7poAbpDEYHHcnlEhrERu8rMtVustjtIVAHJc7NDyFsjOwMNEjrFPl9KD9/rZ8kSSYjLMjyZYjFANr9sBhPJNprMIbZ7EZyDTsUzKCzYuzOdzPKcMRdsaK/tiAIwS8gyrk8tFnTF4lW0wEMQpjbVywWA4VG7HCjXmjk6zx4m1ioXQ011VmUAD0vvIAAYAHQMbZjJTUFBWqHGPSnFQcLgbVYOMkUlHU1Ue4xq4FgmP4xwMQM+Wil8goQORTVSyz+8i0YMADnDPvGNGjePjq0TahTfDTB0zttsebSIPBCvOWNsDhLZYrVZrYzrZgbTdbknbka72J72wWGAHADEoBB8K7oUP25Tsu7AePyJO9YrZ4CHA/Y0Y1Sv22uFF3QthR7IxAhvDN22+bNrWhJ8vyLIwvX/MYI3oKNC1A8D00sO8EgQ+CYOgZCkQsEYgA=

Attempt to call a function in C# from a C Dll

I coded a simple sum function using Rhapsody Developer in C and declared it as __declspec(dllexport) int Class_Sum_sum(Class_Sum* const me, int a, int b); in my C file. I am a total beginner in C# programming.
My C# program looks like this:
using System.Runtime.InteropServices;
namespace Test1_C_Sharp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
int x = Win32.Class_Sum_sum(5, 8);
textBox1.Text = x.ToString();
}
}
public class Win32
{
[DllImport("CalcSum.dll", CharSet = CharSet.Auto)]
public static extern int Class_Sum_sum(int a, int b);
}
}
When i execute this code, i get a Form with a textbox and "sum" button, as expected, when i press the "sum" button, an exception is thrown saying that
PInvokeStackImbalance was detected
which actually makes sense because i have three arguments in my C function (Class_sum *,int,int) and I do not know what exactly the first argument in my C# code should look like.
Does anyone know the right way to do this?
EDIT: I modelled my class "Class_sum" in IBM Rhapsody which translates to a struct in C. A snippet from my H file like this:
/*## class Class_Sum */
typedef struct Class_Sum Class_Sum;
struct Class_Sum {
RiCReactive ric_reactive;
int op1; /*## attribute op1 */
int op2; /*## attribute op2 */
int sum; /*## attribute sum */
/*#[ ignore */
int rootState_subState;
int rootState_active;
int MainState_subState;
/*#]*/
......
......
};
Rhapsody generates its own functions and structures like me for instance, which translates to this in an OOP Language.
you have to put the third parameter and because it is a pointer in C# you have to use the word ref
public static extern int Class_Sum_sum(ref Class_Sum parameterName,int a, int b)

CS5001 Program does not contain a static 'Main' method suitable for an entry point

I am new to C#. I'd be thankful if any body can show me why the following error is shown for code.
"CS5001 Program does not contain a static 'Main' method suitable for an entry point"
using System;
class test
{
void Foo(int x) { Console.WriteLine(x); }
void Foo(double x) { Console.WriteLine(x); }
void Foo(int x, float y) { Console.WriteLine(x); Console.WriteLine(y);}
void Foo(float x, int y) { Console.WriteLine(x); Console.WriteLine(y); }
void Main()
{
Foo(123); // int
Foo(123.0); // double
Foo(123, 123F); // int, float
Foo(123F, 123); // float, int
}
}
This error occurs when Main method is defined with incorrect signature. This error also occurs if Main, is defined with the wrong case, such as lower-case main.
Main must be declared as static and it must return void or int, and it
must have either no parameters or else one parameter of type string[]
Define your main method like this -
static void Main()
OR like this -
static void Main(string[] args)
Have a look at this link for more information
Your fixed code should look like this:
using System;
class test
{
static void Foo(int x) { Console.WriteLine(x); }
static void Foo(double x) { Console.WriteLine(x); }
static void Foo(int x, float y) { Console.WriteLine(x); Console.WriteLine(y); }
static void Foo(float x, int y) { Console.WriteLine(x); Console.WriteLine(y); }
static void Main()
{
Foo(123); // int
Foo(123.0); // double
Foo(123, 123F); // int, float
Foo(123F, 123); // float, int
}
}
Remove <OutputType>Exe</OutputType> in project file (.csproj)

Passing Method Call with arguments already specified

I would like to call a methodA with parameters already specified from another method.
So I want to pass the method call and arguments as a parameter to MethodB and once it's done some processing, call the MethodA with arguments specified.
I know i can pass the call as a methodB as a delegate parameter and then also pass the parameters like so :
static void Main( string[] args )
{
MethodB(1, 2, Add);
Console.ReadLine();
}
public static void Add(int i, int j)
{
Console.WriteLine(i+j);
}
static public class DelegateWithDelegateParameter
{
public static void MethodB(int param1, int param2, Action<int, int> dAction)
{
dAction(param1, param2);
}
}
Wondering, if it's possible to do this with the parameters already specified rather than having to pass parameters ParamA,ParamB to MethodB from Main already specified. Was just wondering. Hope this make sense, please let me know if you want more detail.
If I'm following what you are asking, to get what you want you need to wrap your call to Add in a delegate that holds it's parameters. This is easy to do using lamda syntax:
static void Main( string[] args )
{
MethodB(() => Add(1, 2));
Console.ReadLine();
}
public static void Add(int i, int j)
{
Console.WriteLine(i+j);
}
static public class DelegateWithDelegateParameter
{
public static void MethodB(Action dAction)
{
dAction();
}
}
The statement () => Add(1,2) creates a new Action delegate that is defined to call Add() with the parametes 1,2.
I think what you want is:
static object InvokeMethod(Delegate method, params object[] args){
return method.DynamicInvoke(args);
}
static int Add(int a, int b){
return a + b;
}
static void Test(){
Console.WriteLine(InvokeMethod(new Func<int, int, int>(Add), 5, 4));
}
You can do it through Delegate. declare a delegate first and hook your method to it like
public delegate void adddelegate(int a, int b);
class Program
{
static void Main(string[] args)
{
adddelegate adddel = new adddelegate(Add);
DelegateWithDelegateParameter.MethodB(1, 2, adddel);
Console.ReadLine();
}
public static void Add(int i, int j)
{
Console.WriteLine(i + j);
}
}
static public class DelegateWithDelegateParameter
{
public static void MethodB(int param1, int param2, adddelegate dAction)
{
dAction(param1, param2);
}
}

How to marshal an array of structure In C#?

I have to call a C++ dll in C#. And the header of the dll is as following(simplified):
//Header of C++
struct vector
{
float x;
float y;
vector()
{}
vector(float x0, float y0)
{
x = x0;
y = y0;
}
};
struct unmanaged_struct
{
int int_var;
float float_var;
char* chars_var;
vector vector_var;
unmanaged_struct(int i, float f, char* ch, float vec_x, float vec_y)
{
int_var = i;
float_var = f;
chars_var = ch;
vector_var = vector(vec_x, vec_y);
}
};
// this function is used to output all the variable values of the struct instance
extern "C" __declspec( dllexport ) void unmanagedstruct_summary(unmanaged_struct* us_list, int length);
And I defined following class in C#
//CSharp
[StructLayout(LayoutKind.Sequential)]
public class Vector
{
public float x;
public float y;
public Vector(float f1, float f2)
{
x = f1;
y = f2;
}
}
[StructLayout(LayoutKind.Sequential)]
public class UnmanagedStruct
{
public int int_var;
public float float_var;
public string char_var;
public Vector vector_var;
public UnmanagedStruct(int i, float f, string s, Vector vec)
{
this.int_var = i;
this.float_var = f;
this.char_var = s;
this.vector_var = vec;
}
}
class UnmanagedDllCallTest
{
[DllImport("unmanageddll.dll", EntryPoint = "unmanagedstruct_summary")]
public static extern void unmanagedstruct_summary([Out]UnmanagedStruct[] usList, int length);
static void Main(string[] args)
{
UnmanagedStruct[] usList = new UnmanagedStruct[1];
usList[0] = new UnmanagedStruct(1, 1.0f, "aa", new Vector(10, 1));
usList[1] = new UnmanagedStruct(2, 2.0f, "ba", new Vector(20, 2));
UnmanagedDllCallTest.unmanagedstruct_summary(usList, 2);
}
And the output is as following:
unmanaged_struct summary:
0
1.12104e-044
Unhandled Exception:
System.AccessViolationException:
Attempted to read or write protected
memory. This is often an indication
that other memory is corrupt. at
callunmanageddll.UnmanagedDllCallTest.unmanagedstruct_summary(UnmanagedStr
uct[] usList, Int32 length) at
callunmanageddll.Program.Main(String[]
args) in c:\users\dynaturtle\docume
nts\visual studio
2010\Projects\callunmanageddll\callunmanageddll\Program.cs:lin
e 68
The C++ dll is OK as I have written test in C++ and the function works well. I have read this thread but it seems the solution didn't work in my case. Any suggestions? Thanks in advance!
Use Marshal.PtrToStructure. There is a sample here.
So you would have to change the signature of the method from out structure array to out IntPtr. However, you need to know the size of the buffer being passed out.
public struct Vector
{
public float x;
public float y;
}
public struct UnmanagedStruct
{
public int int_var;
public float float_var;
public string char_var;
public Vector vector_var;
}
class UnmanagedDllCallTest
{
[DllImport("unmanageddll.dll", EntryPoint = "unmanagedstruct_summary")]
public static extern void unmanagedstruct_summary([Out] IntPtr ptr, int length);
static void Main(string[] args)
{
for(int i=0; i<length; i++)
{
UnmanagedStruc st;
Marshal.PtrToStructure(ptr, st);
// increment ptr and move forward
}
}
First: Vector and UnmanagedStruct should be structs, not classes.
JIC I'd share my approach. Perhaps this is not an expected answer by at one time I spend a time to resolve my issue.
I have the following structure to expose some data from DLL.
//C++ code
struct State
{
const wchar_t * name;
unsigned int state;
};
APIENTRY bool get_states(H_PRCSR, MacroState *, const int sz); //pay attention, function accepts already allocated array and size for it
To accept this data From C++ I can do this way
std::vector<State> states(desired_size);
get_states(hparser, &states[0], states.size());
To do the same on C# I used the following way
//C#
[StructLayout(LayoutKind.Sequential)]
public struct Status
{
public IntPtr name;
public uint state;
public string getName()
{
if (name == IntPtr.Zero) return "<no-value>";
return Marshal.PtrToStringUni(name);
}
}
//And import function...
[DllImport(dll, CallingConvention = CallingConvention.Winapi)]
private static extern bool get_states(IntPtr p, [Out]MacroFlag[] flags, int flags_size);
//And simple decoder
public static Status[] getAll(IntPtr p, int size)
{
var results = new Status[size];
get_states(p, results, size);
return results;
}
As, I saw the are different approaches to do this. This is one of them. And it works for me. Perhaps, this post will not resolve the issue but will be a good point to start

Categories

Resources