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

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)

Related

Calling C++ struct parameter from C#

Below is the header documentation to call the DLL:
#define CM24_NUMTYPENOTE 24
typedef struct SNOTETYPE
{
char Notetype[6];
int NumNote;
} SNOTE;
typedef struct SDEP
{
int InNumber;
int TotalDepBnk;
int Refused;
int Unrecognized;
SNOTE Types[CM24_NUMTYPENOTE*4];
} SDEPOSIT;
typedef SDEPOSIT *PADEPOSITCASS;
int APIENTRY InterDoCheck (int , PADEPOSITCASS);
And here is my code in C# which is calling the C++ DLL
public struct SNOTE
{
public String notetype;
public int numNote;
}
public struct SDEPOSIT
{
public int InNumber;
public int TotalDepBnk;
public int Refused;
public int Unrecognized;
public SNOTE[] Types;
}
[DllImport("myDLL.dll")]
public static extern int InterDoCheck(int mode, ref SDEPOSIT PADEPOSITCASS);
private void button3_Click(object sender, EventArgs e)
{
SDEPOSIT sdeposit = new SDEPOSIT();
deposit.Types = new SNOTE[96];
int r = InterDoCheck(0, ref sdeposit);
}
So, here when I click the button it will call the DLL and getting an error below:
An unhandled exception of type 'System.ArgumentException' occurred in
WindowsFormsApp2.exe The parameter is incorrect. (Exception from
HRESULT: 0x80070057 (E_INVALIDARG))
I tried to commented out the line SDEPOSIT sdeposit = new SDEPOSIT(); It was calling successfully but it's getting hang when receiving the result from DLL.
I'm not sure if I'm I calling it correctly, or is my struct in C# is correct or not.
Basically I want to know how to pass values to this type of struct in C++.

C DLL with C# exception error (Access Violation)

I have a C DLL that I am call from C#
C Code
// The real DLL entry point
__declspec(dllexport) int Do_7plus(char *cmd_line)
char *p1, *p2;
char **argv;
int argc = 0;
int i, l;
int ret;
/*
* Count the args.
*/
l = strlen(cmd_line);
C# Code
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices; // DLL support
namespace Packet
{
public partial class _7PlusFrm : Form
{
[DllImport("7plus.dll")]
public static extern void Do_7plus(string args);
public _7PlusFrm()
{
InitializeComponent();
}
private void button_ok_Click(object sender, EventArgs e)
{
Do_7plus("c:\\temp\\7plus.zip -SAVE \"c:\\temp\\\" -SB 5000");
}
}
}
I get an exception error (Access Violation)
How do I fix it?
Is the problem the pointer in C and string in C#?
You need to marshal the string to the c-string type.
Something like this should do the trick:
[DllImport("7plus.dll", Charset = Charset.Ansi)]
public static extern void Do_7plus([MarshalAs(UnmanagedType.LCPStr)]string args);
b.t.w. you can solve this problem without PInvoke and without the massive security vulnerability of that shell injection you are doing.

Calling Fortran DLL from C#

I have a question about calling a fortran DLL from C# (using VS 2010).
I cannot get this program to run. When stepping into the Fortran code from C#, at the line where z is calculated (sum of x and y), a message box pops up:
An unhandled exception of type 'System.AccessViolationException' occurred in WinApp_FortranDLLStruct2.exe
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt"
How do I fix this?
The Fortran DLL is called "TestDLL.DLL"
Fortran code:
MODULE TESTING
TYPE Point
REAL*8 :: x(10)
REAL*8 :: y(10)
REAL*8 :: z(10)
ENDTYPE Point
end module
!DEC$ ATTRIBUTES DLLEXPORT::CalcPoint
!DEC$ ATTRIBUTES ALIAS : "CalcPoint" :: CalcPoint
SUBROUTINE CalcPoint(myPts)
use TESTING
IMPLICIT NONE
INTEGER*4 I,J,NPTS
REAL*8 Sum_Out
TYPE(Point) :: myPts
do i = 1,10
myPts.z(i) = myPts.x(i) + myPts.y(i)
enddo
END SUBROUTINE CalcPoint
C# code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WinApp_FortranDLLStruct2 {
public partial class Form1 : Form {
[StructLayout(LayoutKind.Sequential)]
public unsafe struct myPoint {
public fixed double x[10];
public fixed double y[10];
public fixed double z[10];
}
public class FortranCall {
[DllImport("TestDLL.dll")]
public unsafe static extern void CalcPoint([Out] myPoint t);
}
public Form1()
{
InitializeComponent();
}
private unsafe void button1_Click(object sender, EventArgs e) {
int i;
double d1 = 1.0;
myPoint T = new myPoint();
for (i = 0; i < 10; i++) {
T.x[i] = (i+1)*d1;
T.y[i] = (i+2)*d1;
}
FortranCall.CalcPoint(T);
}
}
}
Adding C calling conventions solved my stack imbalance problems. Also change the [Out] to ref in order to point at the same memory and not copy values around. Here is my code
FORTRAN
MODULE TESTING
INTEGER, PARAMETER :: SIZE = 10
TYPE Point
SEQUENCE
REAL*8 :: x(SIZE), y(SIZE) , z(SIZE)
ENDTYPE Point
end module
SUBROUTINE CalcPoint(myPts)
!DEC$ ATTRIBUTES DLLEXPORT::CalcPoint
!DEC$ ATTRIBUTES ALIAS : 'CalcPoint' :: CalcPoint
use TESTING
IMPLICIT NONE
! Arguments
TYPE(Point), INTENT(INOUT) :: myPts
! Local variables
INTEGER*4 I
do i = 1,SIZE
myPts%z(i) = myPts%x(i) + myPts%y(i)
enddo
END SUBROUTINE CalcPoint
C#
[StructLayout(LayoutKind.Sequential)]
public unsafe struct myPoint
{
public const int size = 10;
public fixed double x[size];
public fixed double y[size];
public fixed double z[size];
public void Initialize(double d1)
{
fixed (double* x_ptr=x, y_ptr=y, z_ptr=z)
{
for (int i=0; i<size; i++)
{
x_ptr[i]=(i+1)*d1;
y_ptr[i]=(i+1)*d1;
z_ptr[i]=0.0;
}
}
}
}
class Program
{
[DllImport(#"FortranDll1.dll", CallingConvention=CallingConvention.Cdecl)]
public unsafe static extern void CalcPoint(ref myPoint t);
unsafe Program()
{
double d1=1.0;
var T=new myPoint();
T.Initialize(d1);
Program.CalcPoint(ref T);
// T.z = {2,4,6,...}
}
static void Main(string[] args)
{
new Program();
}
}
Appendix
To convert a fixed array to managed array and vise versa use the following code
public unsafe struct myPoint
{
public const int size=10;
public fixed double x[size];
...
public double[] X
{
get
{
double[] res=new double[size];
fixed (double* ptr=x)
{
for (int i=0; i<size; i++)
{
res[i]=ptr[i];
}
}
return res;
}
set
{
if (value.Length>size) throw new IndexOutOfRangeException();
fixed (double* ptr=x)
{
for (int i=0; i<value.Length; i++)
{
ptr[i]=value[i];
}
}
}
}
}
Try:
[DllImport("TestDLL.dll")]
public unsafe static extern void CalcPoint(ref myPoint t);
If that doesn't work, try creating a really simple FORTRAN method that takes X/Y values and adds them together and returns the sum. This will allow you to diagnose that the overall process is working correctly. Work up from there, adding more complexity in until it breaks. That will tell you if something else is wrong.

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

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.

Modifying value of structure passed to DLL from C#

I am trying to do 2 things: get a return value from a C dll function, and have that same function modify 1 of the members of a structure that is passed to it. After much experimentation I was able to get the function to return a value, but I am still unable to get it to return a modified value to the C# code; the value remains (unmodified) as 0.
I've tried lots of variations (ref, [In,Out], etc) to no avail
using System;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
namespace Vexing.Problem{
public class myIdx : VexingObject {
public myIdx(object _ctx) : base(_ctx) { }
private IPlotObject plot1;
[StructLayout(LayoutKind.Sequential)]
public class PLEX { public int yowser; }
[DllImport("my.dll", CharSet = CharSet.Unicode)]
public static extern int cFunction(
[MarshalAs(UnmanagedType.LPStruct)] PLEX mPlex);
PLEX a;
protected override void Create() { a = new PLEX(); }
protected override void CalcBar() {
int mf = cFunction(a);
plot1.Set(a.yowser); }
}}
// pertinent c dll code
typedef struct s_plex { int yowser;} cplex;
extern "C" __declspec( dllexport )
int cFunction(cplex *Cplex){ Cplex->yowser = 44; return 1;}
Your import declaration is wrong.
Setting the CharSet in your case doesn't make any sense (there are no string parameters in the native function declaration).
If you want to pass class instance, ref/out also must be thrown away (classes being passed by reference).
And the main point: extern "C" __declspec( dllexport ) means CallingConvention.Cdecl.
UPDATE. Here's complete working code sample:
C++ (header):
struct CStruct
{
int myField;
};
extern "C" __declspec( dllexport ) int MyFunction(CStruct *pStruct);
C++ (code):
int MyFunction(CStruct *pStruct)
{
pStruct->myField = 100;
return 1;
}
C#:
[StructLayout(LayoutKind.Sequential)]
class MyStruct
{
public int myField;
};
class Program
{
MyStruct myStruct = new MyStruct();
[DllImport("MyLib.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int MyFunction(MyStruct pStruct);
static void Main(string[] args)
{
var p = new Program();
var result = MyFunction(p.myStruct);
Console.WriteLine("Result: {0}, MyStruct.myField = {1}", result, p.myStruct.myField);
}
}
Prints:
Result: 1, MyStruct.myField = 100

Categories

Resources