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++.
Related
I'm trying to return a struct from a C++ callback from C# and I get the error as described in the title.
I appreciate there is a lot of information, but I wanted to include too much rather than not enough.
I've tried returning the function as a structure, but then read it may be easier to return the function as an IntPtr and use Marshal.PtrtoStructure.
The function that I want to call is from a .dll that comes from a different source and the input is:
C++:
rVDACQ_Connect(int, tVDACQ_CallBackProc, void*, short*, int)
the function in the sample (C++) code returns a struct (rACQ_CallBackRec) which is as follows:
rACQ_CallBackRec = theApp.m_Intf.rVDACQ_Connect(cVDACQ_FBright, CALLBACK_Acquisition, this, m_FrmBuffer, 0);
//rACQ_CallBackRec is the struct type tVDACQ_CallBackRec (as described below)
With CALLBACK_Aquisition being:
extern "C" {
__declspec(dllexport) void _stdcall CALLBACK_Acquisition(tVDACQ_CallBackRec* AR)
{
tVDACQ_CallBackProc test;
((CPreviewDlg*)AR->rUserParam)->My_ACQ_CallBack(AR, test);
}
}
The layout of the struct is as follows:
typedef struct {
int rFlags, // combination of cVDACQ_Fxxxx
rType, // cVDACQ_ETxxx
rEvent, // cVDACQ_Exxx
rSocket; // 0:no relation to a 'socket'; otherwise socket's ID>0 (event's source ID)
TCHAR rMsg[256]; // message (trace, wrn, err)
int rFrameWidth, // full frame width
rFrameHeight; // full frame height
short* rFrameBuffer; // user supplied frame buffer "AFrameBuffer"
union {
int rCaptureRows; // # of received rows (for single frame acquisition)
int rCaptureFrames; // # of received full frames (for framegrabber)
};
int rCapturePercent; // received data in percents
void* rUserCallBackProc, // user supplied "ACallBackProc"
* rUserParam; // user supplied "AUserParam"
int rAborted; // 1: VDACQ_Abort -1:internally
void* rPacketData; // pointer to received packet; usually it is nil
int rFGControl; // frame-grabber's control flags
} tVDACQ_CallBackRec;
typedef void(_stdcall* tVDACQ_CallBackProc)(tVDACQ_CallBackRec*); //The Callback
C#
I've created the callback procedure in C#, as well as the struct and PInvoke:
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
public delegate void tVDACQ_CallBackProc(tVDACQ_CallBackRec AR);
[DllImport("C:\\Users\\jch\\source\\repos\\FlatPanelSensor\\x64\\Debug\\VADAV_AcqS.dll", EntryPoint = "CALLBACK_Acquisition", CallingConvention = CallingConvention.Cdecl)]
public unsafe static extern void CALLBACK_Acquisition(tVDACQ_CallBackRec AR);
[DllImport("C:\\Users\\jch\\source\\repos\\FlatPanelSensor\\FlatPanelSensor\\bin\\Debug\\VADAV_FGM_64.dll", EntryPoint = "VDACQ_Connect", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I4)]
public unsafe static extern IntPtr VDACQ_Connect(int i, [MarshalAs(UnmanagedType.FunctionPtr)] tVDACQ_CallBackProc proc, dynamic n, IntPtr[] buffer, int j);
Struct:
[StructLayout(LayoutKind.Sequential)]
public struct tVDACQ_CallBackRec
{
public int rFlags;
public int rType;
public int rEvent;
public int rSocket;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string rMsg;
public int rFrameWidth;
public int rFrameHeight;
public IntPtr rFrameBuffer;
public int rCaptureRows;
public int rCaptureFrames;
public int rCapturePercent;
public IntPtr rUserCallBackProc;
public IntPtr rUserParam;
public int rAborted;
public IntPtr rPacketData;
public int rFGControl;
}
CallBack:
tVDACQ_CallBackProc callBack =
(AR) =>
{
CALLBACK_Acquisition(AR); //Don't know how necessary this
is
};
Function call:
IntPtr work = VDACQ_Connect(0, callBack, this, m_FrmBuffer, 0);
//I know 'this' isn't defined as a void* in my DLLImport,
//but making it an IntPtr didn't work either so
//the only type I could think of was dynamic.
If I could return this as a IntPtr or, even better, the struct I defined in my C# code that would be great.
If you need anymore information then please let me know, as I think I included everything.
The Sctruct
I am not much of a C# or C programmer and have not found much guidance on specifying pointers and structs within a struct. I am attempting to import the following from a C dll into a C# program:
#define MAXFILENAME 259
struct IDentry {
char* IDname;
int length;
};
typedef struct IDentry idEntry;
struct SMOutputAPI {
char name[MAXFILENAME + 1];
FILE* file;
struct IDentry *elementNames;
long Nperiods;
int FlowUnits;
int Nsubcatch;
int Nnodes;
int Nlinks;
int Npolluts;
int SubcatchVars;
int NodeVars;
int LinkVars;
int SysVars;
double StartDate;
int ReportStep;
__int64 IDPos;
__int64 ObjPropPos;
__int64 ResultsPos;
__int64 BytesPerPeriod;
};
I am not sure how to handle the *elementsNames, file or name properties. What I have so far in C# is:
int MAXFILENAME = 259
[StructLayout(LayoutKind.Sequential)]
public struct SMOutputAPI
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAXFILENAME+1)]
public string name;
IntPtr file;
IntPtr elementNames;
public long Nperiods;
public int FlowUnits;
public int Nsubcatch;
public int Nnodes;
public int Nlinks;
public int Npolluts;
public int SubcatchVars;
public int NodeVars;
public int LinkVars;
public int SysVars;
public double StartDate;
public int ReportStep;
public int IDPos;
public int ObjPropPos;
public int ResultsPos;
public int BytesPerPeriod;
};
The C# application builds fine, but when I call the C initialization function that should return a new SMOutputAPI struct I get an error:
System.Runtime.InteropServices.MarshalDirectiveException
Method's type signature is not PInvoke compatible.
Any thoughts on how to properly specify this struct in C# would be much appreciated. Thanks!
Initializing the Struct
The struct is initialized in the c-code with:
SMOutputAPI* DLLEXPORT SMO_init(void)
//
// Purpose: Returns an initialized pointer for the opaque SMOutputAPI
// structure.
//
{
SMOutputAPI *smoapi = malloc(sizeof(struct SMOutputAPI));
smoapi->elementNames = NULL;
return smoapi;
}
The corresponding c# code is:
[DllImport("swmm-output.dll")]
static extern SMOutputAPI SMO_init();
static void Main(string[] args)
{
Console.Write("Hello World!");
SMOutputAPI SMO = SMO_init();
}
I have a DLL developed in C++ that performs some computations. I am trying to link this DLL into my C# application.
I have a struct within a struct which contains a char array (C string). I have a pointer to the object created by the C++ DLL within my C# application.
namespace Test
[StructLayout(LayoutKind.Sequential)]
public unsafe struct Child
{
public float number1;
public float number2;
[MarshalAs(UnmanagedType.LPArray)]
public char[] name;
}
[StructLayout(LayoutKind.Sequential)]
public unsafe struct DataStructure
{
public Child child;
...
}
.
.
.
public unsafe partial class Form1:Form {
[DllImport("Calculation.dll", CallingConvention = CallingConvention.Cdecl)]
unsafe public static extern IntPtr createInstance();
[DllImport("Calculation.dll", CallingConvention = CallingConvention.Cdecl)]
unsafe public static extern DataStructure* processData(IntPtr source); // Setup of data
[DllImport("Calculation.dll", CallingConvention = CallingConvention.Cdecl)]
unsafe public static extern int calculate(IntPtr calc); // Perform calculation
.
.
public Form2()
{
private void button1_Click_1(object sender, EventArgs e)
{
// test functions
unsafe
{
IntPtr ptr1 = createInstance(); // Returns pointer to the instance
DataStructure* data = processData(ptr1); // Returns pointer to DataStructure object created through DllImport
data->child.number1 = 1.234F; // Works
data->child.number1 = 9.876F; // Works
data->child.name = "......" // This doesn't work!!
int result = calculate(ptr1); // Returns value when name commented
}
}
}
}
If I don't comment name, I get the Error - Cannot take the address of managed object.
If I comment name, I am able to run the calculation without issue.
I wish to update the value of the char array name but can't seem to figure out the solution. Below is my usual C solution. Thanks!
#include "DataStructure.h"
#define DLLNAME "Calculation.dll"
int main(int argc, char** argv) {
HINSTANCE dllHandle = LoadLibraryA(fileNameDll);
const void* ptr1 = 0;
int result = 0;
DataStructure *data;
ptr1 = createInstance();
data = processData(ptr1);
data->child.number1 = 1.234;
data->child.number2 = 9.876;
sprintf(data->child.name, "3104-03");
result = calculate(ptr1);
}
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)
I am attempting to invoke an unmanaged DLL and use what it returns for authentication. Could someone help me correct my code to return the correct authentication strings?
I am confused about the struct's, any assistance would be appreciated.
this is my C# code invoking the library
class Wrapper
{
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 1)]
public struct ARSSOUserCredentialsStruct
{
/// int
public int m_nARTCPNum;
public int m_nARRPCNum;
/// string*
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)]
public static string m_szARUserName;
public string m_szARPassword;
public string m_szARAuthenticationstring;
public int m_nARNumberOfServers;
//bool
public bool m_bARUsingPreferenceServer;
}
public struct ARSSOServerInformation
{
/// int
public int m_nARTCPNum;
public int m_nARRPCNum;
/// string*
[System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.LPStr)]
public string m_szARServerName;
}
[System.Runtime.InteropServices.DllImportAttribute("ARSSOInfo.dll", EntryPoint = "ARGetSSOLoginCrendentials")]
public static extern System.IntPtr ARGetSSOLoginCrendentials(string m_szARUserName);
public static IntPtr getInfo(string m_szARUserName)
{
IntPtr ptr = ARGetSSOLoginCrendentials(m_szARUserName); // should this be IntPtr?
//return (ARSSOUserCredentialsStruct)(Marshal.PtrToStructure(ptr, typeof(ARSSOUserCredentialsStruct))); // what should type >
// var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(m_szARUserName));
if(ptr != null)
{
Marshal.StructureToPtr(m_szARUserName, ptr, false);
Console.WriteLine("Not null");
Console.WriteLine();
}
else
{
Console.WriteLine("null");
Console.ReadLine();
}
return ptr;
}
class Program
{
static void Main(string[] args)
{
getInfo("jp");
}
}
}
unmanaged dll code which is being called by C# app:
#include <string.h>
#include <stdafx.h>
struct ARSSOServerInformation
{
char * m_szARServerName;
int m_nARTCPNum;
int m_nARRPCNum;
};
struct ARSSOUserCredentialsStruct
{
char* m_szARUserName;
char* m_szARPassword;
char* m_szARAuthenticationString;
bool m_bARUsingPreferenceServer;
int m_nARNumberOfServers;
};
extern "C"
{
__declspec(dllexport) void
ARGetSSOLoginCrendentials(ARSSOUserCredentialsStruct
*pUserCredentialStruct)
{
// The required memory for struct ARSSOUserCredentialsStruct is allocated by user tool,
// This dll just needs to assign values.
// eg:
strcpy(pUserCredentialStruct->m_szARUserName, "Demo");
pUserCredentialStruct->m_nARNumberOfServers = 2;
}
}//End 'extern "C"
extern "C"
{
__declspec(dllexport) void
ARGetSSOServerInformation(ARSSOServerInformation *pServerInfo)
{
// The required memory for struct ARSSOServerInformation is allocated by user tool,
// This dll just needs to assign values.
// eg:
strcpy(pServerInfo[0].m_szARServerName, "ServerName1");
pServerInfo->m_nARTCPNum = 3040; pServerInfo->m_nARRPCNum
= 390622;
strcpy(pServerInfo[1].m_szARServerName, "ServerName2");
}
}//End 'extern "C"