From 7a4bbc6eab2062e1118b8b277abb3da96e1f42eb Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Thu, 1 Nov 2018 16:17:21 -0500 Subject: [PATCH] Pad the configuration struct to 250 bytes, so the SDK.DLL ABI doesn't change when fields are added. --- sdk/SMX.h | 8 +++++++- smx-config/SMX.cs | 13 +++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/sdk/SMX.h b/sdk/SMX.h index 43f52e0..41b1a7a 100644 --- a/sdk/SMX.h +++ b/sdk/SMX.h @@ -215,8 +215,14 @@ struct SMXConfig uint8_t panelThreshold5Low, panelThreshold5High; uint8_t panelThreshold6Low, panelThreshold6High; uint8_t panelThreshold8Low, panelThreshold8High; + + // Pad the struct to 250 bytes. This keeps this struct size from changing + // as we add fields, so the ABI doesn't change. Applications should leave + // any data in here unchanged when calling SMX_SetConfig. + uint8_t padding[166]; }; -static_assert(sizeof(SMXConfig) == 84, "Expected 84 bytes"); +static_assert(offsetof(SMXConfig, padding) == 84, "Expected 84 bytes"); // includes one padding byte +static_assert(sizeof(SMXConfig) == 250, "Expected 250 bytes"); // The values (except for Off) correspond with the protocol and must not be changed. enum SensorTestMode { diff --git a/smx-config/SMX.cs b/smx-config/SMX.cs index c501157..a6a70a7 100644 --- a/smx-config/SMX.cs +++ b/smx-config/SMX.cs @@ -60,6 +60,10 @@ namespace SMX public Byte panelThreshold6Low, panelThreshold6High; public Byte panelThreshold8Low, panelThreshold8High; + // Pad this struct to exactly 250 bytes. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 166)] + public Byte[] padding; + // enabledSensors is a mask of which panels are enabled. Return this as an array // for convenience. public bool[] GetEnabledPanels() @@ -291,6 +295,15 @@ namespace SMX { if(!DLLAvailable()) return; + // Sanity check SMXConfig, which should be 250 bytes. If this is incorrect, + // check the padding array. + { + SMXConfig config = new SMXConfig(); + int bytes = Marshal.SizeOf(config); + if(bytes != 250) + throw new Exception("SMXConfig is " + bytes + " bytes, but should be 250 bytes"); + } + // Make a wrapper to convert from the native enum to SMXUpdateCallbackReason. InternalUpdateCallback NewCallback = delegate(int PadNumber, int reason, IntPtr user) { SMXUpdateCallbackReason ReasonEnum = (SMXUpdateCallbackReason) Enum.ToObject(typeof(SMXUpdateCallbackReason), reason);