From 78a694c5d3830ca36f1b284a6aa519c00a9ca00b Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Tue, 9 Dec 2014 10:46:34 +0100 Subject: [PATCH] - C#/.NET API: fixed problem with boolean marshalling together with VC++ compiled DLL --- dotnet/IEC61850forCSharp/Control.cs | 14 +-- dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs | 35 ++++++-- .../IEC61850forCSharp.csproj | 90 +++++++++---------- dotnet/IEC61850forCSharp/MmsValue.cs | 9 +- .../IEC61850forCSharp/ReportControlBlock.cs | 17 ++-- dotnet/IEC61850forCSharp/Reporting.cs | 21 +++-- src/iec61850/client/ied_connection.c | 51 ++++++++--- 7 files changed, 152 insertions(+), 85 deletions(-) diff --git a/dotnet/IEC61850forCSharp/Control.cs b/dotnet/IEC61850forCSharp/Control.cs index d064334b..bb4f876c 100644 --- a/dotnet/IEC61850forCSharp/Control.cs +++ b/dotnet/IEC61850forCSharp/Control.cs @@ -100,8 +100,6 @@ namespace IEC61850 /// public class ControlObject { - - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] private static extern LastApplErrorInternal ControlObjectClient_getLastApplError(IntPtr self); @@ -114,16 +112,20 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] private static extern int ControlObjectClient_getControlModel(IntPtr self); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] private static extern bool ControlObjectClient_operate(IntPtr self, IntPtr ctlVal, UInt64 operTime); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] private static extern bool ControlObjectClient_select(IntPtr self); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] private static extern bool ControlObjectClient_selectWithValue(IntPtr self, IntPtr ctlVal); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] private static extern bool ControlObjectClient_cancel(IntPtr self); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] diff --git a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs index 6056fcaa..992623da 100644 --- a/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs +++ b/dotnet/IEC61850forCSharp/IEC61850ClientAPI.cs @@ -54,7 +54,8 @@ namespace IEC61850 [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] static extern float MmsValue_toFloat (IntPtr self); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] static extern bool MmsValue_getBoolean (IntPtr self); [DllImport ("iec61850", CallingConvention=CallingConvention.Cdecl)] @@ -135,8 +136,8 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void IedConnection_deleteDataSet (IntPtr self, out int error, string dataSetReference); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern IntPtr IedConnection_getDataSetDirectory (IntPtr self, out int error, string dataSetReference, out bool isDeletable); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern IntPtr IedConnection_getDataSetDirectory(IntPtr self, out int error, string dataSetReference, [MarshalAs(UnmanagedType.I1)] out bool isDeletable); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern IntPtr IedConnection_getMmsConnection (IntPtr self); @@ -892,13 +893,33 @@ namespace IEC61850 if (error != 0) throw new IedConnectionException ("Failed to delete data set", error); - } - + } + + /// + /// Get the directory of the data set. + /// + /// This function returns a list of object references with appended functional constraints (FC) of the data set elemenents. + /// The object reference of the data set + /// the list of object references + /// This exception is thrown if there is a connection or service error + public List GetDataSetDirectory(string dataSetReference) + { + bool isDeletable; + + return GetDataSetDirectory(dataSetReference, out isDeletable); + } + + /// + /// Get the directory of the data set. + /// + /// This function returns a list of object references with appended functional constraints (FC) of the data set elemenents. + /// The object reference of the data set + /// Indication if this data set is permanent or deletable. + /// the list of object references /// This exception is thrown if there is a connection or service error - public List GetDataSetDirectory (string dataSetReference) + public List GetDataSetDirectory (string dataSetReference, out bool isDeletable) { int error; - bool isDeletable; IntPtr linkedList = IedConnection_getDataSetDirectory (connection, out error, dataSetReference, out isDeletable); diff --git a/dotnet/IEC61850forCSharp/IEC61850forCSharp.csproj b/dotnet/IEC61850forCSharp/IEC61850forCSharp.csproj index 535e22ab..be311af9 100644 --- a/dotnet/IEC61850forCSharp/IEC61850forCSharp.csproj +++ b/dotnet/IEC61850forCSharp/IEC61850forCSharp.csproj @@ -1,46 +1,46 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {C35D624E-5506-4560-8074-1728F1FA1A4D} - Library - iec61850dotnet - iec61850dotnet - - - true - full - false - bin\Debug - DEBUG; - prompt - 4 - false - - - none - true - bin\Release - prompt - 4 - false - - - - - - - - - - - - - - - - + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {C35D624E-5506-4560-8074-1728F1FA1A4D} + Library + iec61850dotnet + iec61850dotnet + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + + + none + true + bin\Release + prompt + 4 + false + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/dotnet/IEC61850forCSharp/MmsValue.cs b/dotnet/IEC61850forCSharp/MmsValue.cs index 0ab8c06b..cb85814e 100644 --- a/dotnet/IEC61850forCSharp/MmsValue.cs +++ b/dotnet/IEC61850forCSharp/MmsValue.cs @@ -46,7 +46,8 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern double MmsValue_toDouble (IntPtr self); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] static extern bool MmsValue_getBoolean (IntPtr self); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] @@ -61,7 +62,8 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void MmsValue_setBitStringBit(IntPtr self, int bitPos, bool value); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] static extern bool MmsValue_getBitStringBit(IntPtr self, int bitPos); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] @@ -130,7 +132,8 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern IntPtr MmsValue_getOctetStringBuffer(IntPtr self); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] static extern bool MmsValue_equals(IntPtr self, IntPtr otherValue); diff --git a/dotnet/IEC61850forCSharp/ReportControlBlock.cs b/dotnet/IEC61850forCSharp/ReportControlBlock.cs index 60f7a5fc..c1ddedb8 100644 --- a/dotnet/IEC61850forCSharp/ReportControlBlock.cs +++ b/dotnet/IEC61850forCSharp/ReportControlBlock.cs @@ -55,7 +55,8 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void IedConnection_setRCBValues (IntPtr connection, out int error, IntPtr rcb, UInt32 parametersMask, bool singleRequest); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] static extern bool ClientReportControlBlock_isBuffered (IntPtr self); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] @@ -65,12 +66,14 @@ namespace IEC61850 static extern void ClientReportControlBlock_setRptId (IntPtr self, string rptId); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] static extern bool ClientReportControlBlock_getRptEna (IntPtr self); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] - static extern void ClientReportControlBlock_setRptEna (IntPtr self, bool rptEna); + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + static extern void ClientReportControlBlock_setRptEna(IntPtr self, bool rptEna); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] static extern bool ClientReportControlBlock_getResv (IntPtr self); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] @@ -112,13 +115,15 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void ClientReportControlBlock_setIntgPd (IntPtr self, UInt32 intgPd); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] static extern bool ClientReportControlBlock_getGI (IntPtr self); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern void ClientReportControlBlock_setGI (IntPtr self, bool gi); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] static extern bool ClientReportControlBlock_getPurgeBuf (IntPtr self); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] diff --git a/dotnet/IEC61850forCSharp/Reporting.cs b/dotnet/IEC61850forCSharp/Reporting.cs index 4bade8e5..68e7e7aa 100644 --- a/dotnet/IEC61850forCSharp/Reporting.cs +++ b/dotnet/IEC61850forCSharp/Reporting.cs @@ -67,7 +67,8 @@ namespace IEC61850 public class Report { - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] static extern bool ClientReport_hasTimestamp (IntPtr self); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] @@ -79,28 +80,34 @@ namespace IEC61850 [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern int ClientReport_getReasonForInclusion(IntPtr self, int elementIndex); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] static extern bool ClientReport_hasSeqNum(IntPtr self); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern UInt16 ClientReport_getSeqNum(IntPtr self); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] static extern bool ClientReport_hasDataSetName(IntPtr self); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] static extern bool ClientReport_hasReasonForInclusion(IntPtr self); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] static extern bool ClientReport_hasConfRev(IntPtr self); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] static extern UInt32 ClientReport_getConfRev(IntPtr self); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] static extern bool ClientReport_hasBufOvfl(IntPtr self); - [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] + [return: MarshalAs(UnmanagedType.I1)] static extern bool ClientReport_hasDataReference(IntPtr self); [DllImport("iec61850", CallingConvention = CallingConvention.Cdecl)] diff --git a/src/iec61850/client/ied_connection.c b/src/iec61850/client/ied_connection.c index 490f3cf9..846d8071 100644 --- a/src/iec61850/client/ied_connection.c +++ b/src/iec61850/client/ied_connection.c @@ -34,6 +34,7 @@ #include "mms_value_internal.h" #define DEFAULT_CONNECTION_TIMEOUT 10000 +#define DATA_SET_MAX_NAME_LENGTH 64 /* is 32 according to standard! */ typedef struct sICLogicalDevice { @@ -1827,7 +1828,7 @@ IedConnection_createDataSet(IedConnection self, IedClientError* error, const cha { char domainIdBuffer[65]; - char itemIdBuffer[33]; /* maximum data set name = 32 chars */ + char itemIdBuffer[DATA_SET_MAX_NAME_LENGTH + 1]; const char* domainId; const char* itemId; @@ -1899,7 +1900,7 @@ void IedConnection_deleteDataSet(IedConnection self, IedClientError* error, const char* dataSetReference) { char domainId[65]; - char itemId[33]; + char itemId[DATA_SET_MAX_NAME_LENGTH + 1]; bool isAssociationSpecific = false; int dataSetReferenceLength = strlen(dataSetReference); @@ -1912,7 +1913,7 @@ IedConnection_deleteDataSet(IedConnection self, IedClientError* error, const cha const char* itemIdString = dataSetReference + strlen(domainId) + 1; - if (strlen(itemIdString) > 32) { + if (strlen(itemIdString) > DATA_SET_MAX_NAME_LENGTH) { *error = IED_ERROR_OBJECT_REFERENCE_INVALID; goto exit_function; } @@ -1953,7 +1954,7 @@ IedConnection_getDataSetDirectory(IedConnection self, IedClientError* error, con LinkedList dataSetMembers = NULL; char domainIdBuffer[65]; - char itemIdBuffer[129]; + char itemIdBuffer[DATA_SET_MAX_NAME_LENGTH + 1]; const char* domainId = NULL; const char* itemId = NULL; @@ -1962,9 +1963,22 @@ IedConnection_getDataSetDirectory(IedConnection self, IedClientError* error, con if (dataSetReference[0] != '@') { domainId = MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainIdBuffer); - char* itemIdRef = copyStringToBuffer(dataSetReference + strlen(domainId) + 1, itemIdBuffer); - StringUtils_replace(itemIdRef, '.', '$'); - itemId = itemIdRef; + + if (domainId == NULL) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + goto exit_function; + } + + const char* itemIdRef = dataSetReference + strlen(domainId) + 1; + + if (strlen(itemIdRef) > DATA_SET_MAX_NAME_LENGTH) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + goto exit_function; + } + + char* itemIdRefInBuffer = copyStringToBuffer(itemIdRef, itemIdBuffer); + StringUtils_replace(itemIdRefInBuffer, '.', '$'); + itemId = itemIdRefInBuffer; } else { itemId = dataSetReference + 1; @@ -2006,6 +2020,7 @@ IedConnection_getDataSetDirectory(IedConnection self, IedClientError* error, con *error = iedConnection_mapMmsErrorToIedError(mmsError); +exit_function: return dataSetMembers; } @@ -2014,7 +2029,7 @@ IedConnection_readDataSetValues(IedConnection self, IedClientError* error, const ClientDataSet dataSet) { char domainIdBuffer[65]; - char itemIdBuffer[129]; + char itemIdBuffer[DATA_SET_MAX_NAME_LENGTH + 1]; const char* domainId = NULL; const char* itemId = NULL; @@ -2023,7 +2038,21 @@ IedConnection_readDataSetValues(IedConnection self, IedClientError* error, const if (dataSetReference[0] != '@') { domainId = MmsMapping_getMmsDomainFromObjectReference(dataSetReference, domainIdBuffer); - char* itemIdRef = copyStringToBuffer(dataSetReference + strlen(domainId) + 1, itemIdBuffer); + + if (domainId == NULL) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + goto exit_function; + } + + const char* itemIdRefOrig = dataSetReference + strlen(domainId) + 1; + + if (strlen(itemIdRefOrig) > DATA_SET_MAX_NAME_LENGTH) { + *error = IED_ERROR_OBJECT_REFERENCE_INVALID; + goto exit_function; + } + + char* itemIdRef = copyStringToBuffer(itemIdRefOrig, itemIdBuffer); + StringUtils_replace(itemIdRef, '.', '$'); itemId = itemIdRef; } @@ -2045,7 +2074,7 @@ IedConnection_readDataSetValues(IedConnection self, IedClientError* error, const if (dataSetVal == NULL) { *error = iedConnection_mapMmsErrorToIedError(mmsError); - goto cleanup_and_exit; + goto exit_function; } else *error = IED_ERROR_OK; @@ -2059,7 +2088,7 @@ IedConnection_readDataSetValues(IedConnection self, IedClientError* error, const MmsValue_update(dataSetValues, dataSetVal); } -cleanup_and_exit: +exit_function: return dataSet; }