I have to use a dll written in C in a C# VS project.
I have some difficulties to translate and use the structures declared in C.
structure of the trend list :
===============================
C structure
-------------
typedef struct
{
WV_PARAMETER_ID WvParameterID [WV_MAX_TREND_PARAMETERS]; ;
TCHAR Label [WV_MAX_TREND_PARAMETERS] [WV_LABEL_SIZE] ;
int NumberOfTrends;
} WV_TREND_LIST ;
WV_MAX_TREND_PARAMETERS = 60
WV_LABEL_SIZE = 20
The problem I have is that there is only one returned value for the "NumberOfTrends" but 60 for the others. Then I found that I need to create the structures as follow.
This is working.
C# Structure
-------------
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct WV_TREND_LIST
{
public WV_TREND_LIST_Items WV_TrendItem;
public int NumberOfTrends;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct WV_TREND_LIST_Items
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 60, ArraySubType = System.Runtime.InteropServices.UnmanagedType.I4)]
public int[] WV_Trend_ParameterID;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 60, ArraySubType = System.Runtime.InteropServices.UnmanagedType.ByValTStr)]
public WV_ParameterLabel[] labelparameter;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct WV_ParameterLabel
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public string ParamLabel;
}
I have a to declare another set of structures that are about the same. The difference is that there is a lot of more data to be returned - too much I think. I got the following error when I call the procedure.
{"Cannot marshal 'parameter #2': Internal limitation: structure is too complex or too large."}
Structure for the trend values
===============================
C structure
-------------
typedef struct
{
WV_PARAMETER_ID WvParameterID ; // parameter id
TCHAR Label [WV_LABEL_SIZE] ; // label in english
WV_NET_UNITS_OF_MEASURE Units ;
TCHAR Values [WV_MAX_TREND_SAMPLES][WV_VALUE_SIZE];
} WV_TREND_PARAMETER_DATA;
WV_MAX_TREND_SAMPLES = 1501
WV_LABEL_SIZE = 20
WV_VALUE_SIZE = 20
C# Structure
-------------
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct WV_TREND_DATA
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 60, ArraySubType = System.Runtime.InteropServices.UnmanagedType.Struct)]
public WV_TREND_PARAMETER_DATA[] WV_TrendDataItem;
//public Tren_DATA_Item_Class[] WV_TrendDataItem;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct WV_TREND_PARAMETER_DATA
{
[MarshalAs(UnmanagedType.I4)]
public int Trend_Parameter_ID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public string Trend_Label;
[MarshalAs(UnmanagedType.I4)]
public int Trend_Units;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1501, ArraySubType = System.Runtime.InteropServices.UnmanagedType.ByValTStr)]
public WV_TrendValue[] Trend_Values;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct WV_TrendValue
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public string TrendValue;
}
DLL Declarations
[DllImport("WVAPI.dll", EntryPoint = "WvGetTrendData", SetLastError = true,
CharSet = CharSet.Ansi, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
[DllImport("WVAPI.dll", EntryPoint = "WvGetTrendData", SetLastError = true,
CharSet = CharSet.Ansi, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int WvGetTrendData(int connectionID, ref structures.WV_TREND_DATA pTrendDatas, int numHours, structures.WV_TREND_LIST pTrends);
[DllImport("WVAPI.dll", EntryPoint = "WVGetAvailableTrends", SetLastError = true,
CharSet = CharSet.Ansi, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int WVGetAvailableTrends(int pConnectID, ref structures.WV_TREND_LIST ptrendlist);
Variables declarations
structures.WV_TREND_LIST TrendList = new structures.WV_TREND_LIST();
structures.WV_TREND_DATA DataOfTheTrends = new structures.WV_TREND_DATA();
procedures
int returnTrendList = NATIVE_WV.WVGetAvailableTrends(connectionID, ref TrendList);
int returnTrendData = NATIVE_WV.WvGetTrendData(connectionID, ref DataOfTheTrends, totalhours, TrendList);
I have found on the internet that the solution of the error can be to use class instead of structures.
I must say that I have some difficulties to figure out how to fill a class with dynamic arrays. I can understand the mechanism with the structures : read sequentially the memory marshalling the values etc ... but for the class ?
Is there somebody that can help ?
best regards
I have some difficulties to translate and use the structures declared in C.
structure of the trend list :
===============================
C structure
-------------
typedef struct
{
WV_PARAMETER_ID WvParameterID [WV_MAX_TREND_PARAMETERS]; ;
TCHAR Label [WV_MAX_TREND_PARAMETERS] [WV_LABEL_SIZE] ;
int NumberOfTrends;
} WV_TREND_LIST ;
WV_MAX_TREND_PARAMETERS = 60
WV_LABEL_SIZE = 20
The problem I have is that there is only one returned value for the "NumberOfTrends" but 60 for the others. Then I found that I need to create the structures as follow.
This is working.
C# Structure
-------------
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct WV_TREND_LIST
{
public WV_TREND_LIST_Items WV_TrendItem;
public int NumberOfTrends;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct WV_TREND_LIST_Items
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 60, ArraySubType = System.Runtime.InteropServices.UnmanagedType.I4)]
public int[] WV_Trend_ParameterID;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 60, ArraySubType = System.Runtime.InteropServices.UnmanagedType.ByValTStr)]
public WV_ParameterLabel[] labelparameter;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct WV_ParameterLabel
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public string ParamLabel;
}
I have a to declare another set of structures that are about the same. The difference is that there is a lot of more data to be returned - too much I think. I got the following error when I call the procedure.
{"Cannot marshal 'parameter #2': Internal limitation: structure is too complex or too large."}
Structure for the trend values
===============================
C structure
-------------
typedef struct
{
WV_PARAMETER_ID WvParameterID ; // parameter id
TCHAR Label [WV_LABEL_SIZE] ; // label in english
WV_NET_UNITS_OF_MEASURE Units ;
TCHAR Values [WV_MAX_TREND_SAMPLES][WV_VALUE_SIZE];
} WV_TREND_PARAMETER_DATA;
WV_MAX_TREND_SAMPLES = 1501
WV_LABEL_SIZE = 20
WV_VALUE_SIZE = 20
C# Structure
-------------
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct WV_TREND_DATA
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 60, ArraySubType = System.Runtime.InteropServices.UnmanagedType.Struct)]
public WV_TREND_PARAMETER_DATA[] WV_TrendDataItem;
//public Tren_DATA_Item_Class[] WV_TrendDataItem;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct WV_TREND_PARAMETER_DATA
{
[MarshalAs(UnmanagedType.I4)]
public int Trend_Parameter_ID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public string Trend_Label;
[MarshalAs(UnmanagedType.I4)]
public int Trend_Units;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 1501, ArraySubType = System.Runtime.InteropServices.UnmanagedType.ByValTStr)]
public WV_TrendValue[] Trend_Values;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct WV_TrendValue
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public string TrendValue;
}
DLL Declarations
[DllImport("WVAPI.dll", EntryPoint = "WvGetTrendData", SetLastError = true,
CharSet = CharSet.Ansi, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
[DllImport("WVAPI.dll", EntryPoint = "WvGetTrendData", SetLastError = true,
CharSet = CharSet.Ansi, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int WvGetTrendData(int connectionID, ref structures.WV_TREND_DATA pTrendDatas, int numHours, structures.WV_TREND_LIST pTrends);
[DllImport("WVAPI.dll", EntryPoint = "WVGetAvailableTrends", SetLastError = true,
CharSet = CharSet.Ansi, ExactSpelling = true,
CallingConvention = CallingConvention.StdCall)]
public static extern int WVGetAvailableTrends(int pConnectID, ref structures.WV_TREND_LIST ptrendlist);
Variables declarations
structures.WV_TREND_LIST TrendList = new structures.WV_TREND_LIST();
structures.WV_TREND_DATA DataOfTheTrends = new structures.WV_TREND_DATA();
procedures
int returnTrendList = NATIVE_WV.WVGetAvailableTrends(connectionID, ref TrendList);
int returnTrendData = NATIVE_WV.WvGetTrendData(connectionID, ref DataOfTheTrends, totalhours, TrendList);
I have found on the internet that the solution of the error can be to use class instead of structures.
I must say that I have some difficulties to figure out how to fill a class with dynamic arrays. I can understand the mechanism with the structures : read sequentially the memory marshalling the values etc ... but for the class ?
Is there somebody that can help ?
best regards