Marshal.Sizeof() returning unexpected value - c#

I'm debugging code in C# written by a 3rd party. The project is an old C++ project that was rewritten in C# by a contractor, and I have no access to the contractor. I authored the original C++ version.
The issue is when the C# code gets the size of a structure that represents data received over a UDP connection.
The struct is defined as:
[StructLayout(LayoutKind.Sequential,Pack=1)]
internal class PROXY_HDR {
public ushort pad;
public ushort label;
public char flags;
public ushort length;
public char[] ip = new char[4];
public ushort port;
}
The size of this struct is retrieved as:
int size = Marshal.Sizeof(typeof(PROXY_HDR));
and the value returned is 17 instead of the expected 13. With a 4-byte difference, I suspect the ip member, but only because it's expressed differently than the other members (with 'new'), but I have no other basis to decide.
I don't typically use this type of marshaling in my C# code that parses received packets without a problem, so I don't know how to modify this struct definition to make it 'line up' with the original version size-wise.
I could replace the Marshal line with
int size = 13;
but that's cheating, right?
Can I modify this layout somehow to get the size to come out right?

Add this to the structure:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal class PROXY_HDR
{
public ushort pad;
public ushort label;
public byte flags;
public ushort length;
[MarshalAs(UnmanagedType.ByValArray,
SizeConst = 4, ArraySubType = UnmanagedType.U1)]
public byte[] ip;
public ushort port;
}
This will tell the compiler to treat it as a typical C-style array, not a pointer. This should be byte, as an IP address is an unsigned char array. char typically isn't used in these types of headers, it's usually byte (i.e: unsigned char)

Related

safe fixed size array in struct c#

I have a C struct in an embedded MCU with about 1000 elements, and it contains lots of fixed size arrays and other structs inside, Now I want to bring the data to PC Using C#
Here is a simple preview of my struct elements in C
struct _registers
{
char name[32];
float calibrate[4][16];
float DMTI;
float DMTII;
float DMTIII;
float DMTIE;
float DMTIIE;
....
};
Now I want to convert the Struct into C# using the GCHandle class,
something like this
//The C struct is in this byte array named buffer
byte[] buffer = new byte[4096];
GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
_registers stuff = (protection_registers)Marshal.PtrToStructure(handle.AddrOfPinnedObject(),typeof(_registers));
handle.Free();
the problem is that the Visual studio complains about the "Pointers and fixed size buffers may only be used in an unsafe context"
is there a way to use it normally without unsafe code? I have found Doing something like this
[StructLayout(LayoutKind.Explicit, Size = 56, Pack = 1)]
public struct NewStuff
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
[FieldOffset(0)]
public string name;
[MarshalAs(UnmanagedType.U4)]
[FieldOffset(32)]
public float calibrate[4][16];
}
but as the Code on the MCU is evolving in the coming years and we will add lots of functionality and parameter to the Struct, and since the struct has already 1000 elements, how we can do it better and more clever way? because keep tracking of all the offsets is very hard and error prone!
Try doing something like this instead (note: using class instead of struct which is more appropriate for C# - still marshals OK to a C++ struct):
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class NewStuff
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public StringBuilder name;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4*16)]
public float[,] calibrate;
[MarshalAs(UnmanagedType.R4)]
public float DMTI;
[MarshalAs(UnmanagedType.R4)]
public float DMTII;
// Etc
}
You won't be able to remove the SizeConst since the marshalling needs to know this.
Also, when you intialise the class, you will need to set the array fields to the appropriate sized buffers, and initialise the StringBuilder with the correct buffer size.
Doing it this way means you can avoid using fixed buffers (and hence, you avoid the unsafe code).

PInvoke - Attempted to read or write protected memory. This is often an indication that other memory is corrupt

I've seen the attempted to read or write protected memory error before.
Typically the error shows up when I don't set up the c# struct correctly. I do have other calls working properly but this one is not co-operating.
I'm almost certain that it could be both my function call and the struct that is causing the problem.
C Syntax
int CardTransaction(pTRequest req, char *ProductCodes)
Request structure (I condensed it b/c there were repetitive data types)
typedef struct _cardRequest
{
unsigned short RedemptionNum
long TotalAmount;
unsigned char filler1[257];
char CardNumber[80];
unsigned char cardType;
} TRequest, *pTRequest;
C# function call
[DllImport("card.dll"), CallingConvention.Cdecl, CharSet = CharSet.Auto)]
public static extern int CardTransaction(ref CardRequest cardRequest, [MarshalAs(UnManagedType.LPStr)] StringBuilder productCodes);
ProductCodes is null so I just instantiated a stringbuilder object with nothing in it and passed it through. This is one place I'm thinking could be a problem.
C# structure
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct CardRequest
{
public uint16 RedemptionNum
public int TotalAmount;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 257)]
public string filler1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 80)]
public string CardNumber;
public byte cardType;
}
The obvious problem is that the C code uses an aligned struct, but for some reason you have elected to pack the C# struct. Remove the Pack = 1 from the C# code to make the two structures match.
Beyond that the filler array looks more like a byte array than a string. I'd declare it like this:
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 257)]
public byte[] filler1;
If you want to pass null to the productCodes parameter, then I expect you can do just that. I cannot recall every doing that myself, but generally when you pass null to a p/invoke, then the marshaller will pass NULL to the native code.

Converting Delphi code for unmanaged dll to C#

I hope someone can assist me with the problem I'm currently experiencing. We have a lot of Delphi legacy code, and need to convert some of our Delphi applications to C#.
The legacy code I'm currently struggling with is that of calling a function from a 3rd party application's non-COM DLL.
Here is the C-style header and struct used for the specific function:
/*** C Function AwdApiLookup ***/
extern BOOL APIENTRY AwdApiLookup( HWND hwndNotify, ULONG ulMsg,
BOOL fContainer, CHAR cObjectType,
SEARCH_CRITERIA* searchCriteria,
USHORT usCount, USHORT usSearchType,
VOID pReserved );
/*** C Struct SEARCH_CRITERIA ***/
typedef struct _search_criteria
{
UCHAR dataname[4];
UCHAR wildcard;
UCHAR comparator[2];
UCHAR datavalue[75];
} SEARCH_CRITERIA;
In our Delphi code, we have converted the above function and structure as:
(*** Delphi implementation of C Function AwdApiLookup ***)
function AwdApiLookup(hwndNotify: HWND; ulMsg: ULONG; fContainer: Boolean;
cObjectType: Char; pSearchCriteria: Pointer; usCount: USHORT;
usSearchType: USHORT; pReserved: Pointer): Boolean; stdcall;
external 'AWDAPI.dll';
(*** Delphi implementation of C Struct SEARCH_CRITERIA ***)
TSearch_Criteria = record
dataname: array [0..3] of char;
wildcard: char;
comparator: array [0..1] of char;
datavalue: array [0..74] of char;
end;
PSearch_Criteria = ^TSearch_Criteria;
and the way we call the above mentioned code in Delphi is:
AwdApiLookup(0, 0, true, searchType, #criteriaList_[0],
criteriaCount, AWD_USE_SQL, nil);
where criteriaList is defined as
criteriaList_: array of TSearch_Criteria;
After all that is said and done we can now look at the C# code, which I cannot get to work. I'm sure I'm doing something wrong here, or my C header is not translated correctly. My project does compile correctly, but when the function is called, I get a "FALSE" value back, which indicates that the function did not execute correctly in the DLL.
My C# code thus far:
/*** C# implementation of C Function AwdApiLookup ***/
DllImport("awdapi.dll", CharSet = CharSet.Auto)]
public static extern bool AwdApiLookup(IntPtr handle, ulong ulMsg,
bool fContainer, char cObjectType,
ref SearchCriteria pSearchCriteria,
ushort usCount, ushort usSearchType,
Pointer pReserverd);
/*** C# implementation of C Struct SEARCH_CRITERIA ***/
[StructLayout(LayoutKind.Sequential)]
public struct SearchCriteria
{
private readonly byte[] m_DataName;
private readonly byte[] m_Wildcard;
private readonly byte[] m_Comparator;
private readonly byte[] m_DataValue;
public SearchCriteria(string dataName, string comparator, string dataValue)
{
m_DataName = Encoding.Unicode.GetBytes(
dataName.PadRight(4, ' ').Substring(0, 4));
m_Wildcard = Encoding.Unicode.GetBytes("0");
m_Comparator = Encoding.Unicode.GetBytes(
comparator.PadRight(2, ' ').Substring(0, 2));
m_DataValue = Encoding.Unicode.GetBytes(
dataValue.PadRight(75, ' ').Substring(0, 75));
}
public byte[] dataname { get { return m_DataName; } }
public byte[] wildcard { get { return m_Wildcard; } }
public byte[] comparator { get { return m_Comparator; } }
public byte[] datavalue { get { return m_DataValue; } }
}
My C# call to the C# function looks like this
var callResult = UnsafeAwdApi.CallAwdApiLookup(IntPtr.Zero, 0, true, 'W',
ref searchCriteria[0], criteriaCount,
66, null);
where searchCriteria and criteriaCount is defined as
List<SearchCriteria> criteriaList = new List<SearchCriteria>();
var searchCriteria = criteriaList.ToArray();
var criteriaCount = (ushort)searchCriteria.Length;
and adding data to searchCriteria:
public void AddSearchCriteria(string dataName, string comparator, string dataValue)
{
var criteria = new SearchCriteria();
criteria.DataName = dataName;
criteria.Wildcard = "0";
criteria.Comparator = comparator;
criteria.DataValue = dataValue;
criteriaList.Add(criteria);
}
Like I said, my code compiles correctly, but when the function executes, it returns "FALSE", which should not be the case as the Delphi function does return data with the exact same input.
I know I'm definitely doing something wrong here, and I've tried a couple of things, but nothing seems to be working.
Any assistance or nudge in the right direction would be greatly appreciated.
Thanks, Riaan
Several things here.
First of all C++ ULONG is a 32-bit integer, and becomes uint in C# - ulong is 64-bit.
For the struct, you don't need to mess with byte arrays. Use strings, and ByValTStr. Also, it's not really worth bothering with readonly and properties for interop structs. Yes, mutable value types are generally bad in a pure .NET API, but in this case it's the existing API, there's no point in masking it. So:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public struct SearchCriteria
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4]
public string m_DataName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1]
public string m_Wildcard;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2]
public string m_Comparator;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 75]
public string m_DataValue;
}
If you really want to do all the string conversions yourself, it may be easier to just use unsafe and fixed-size arrays:
public unsafe struct SearchCriteria
{
public fixed byte m_DataName[4];
public byte m_Wildcard;
public fixed byte m_Comparator[2];
public fixed byte m_DataValue[75];
}
[EDIT] Two more things.
CHAR cObjectType should become byte cObjectType, and not char cObjectType that you currently use.
Also, yes, there is a problem with array marshaling in your example. Since your P/Invoke declaration is ref SearchCriteria pSearchCriteria - i.e. a single value passed by reference - that's precisely what P/Invoke mashaler will do. Keep in mind that, unless your struct only has fields of unmanaged types in it (the one with fixed arrays above is that, the one with string is not), the marshaler will have to copy the structs. It won't just pass address to the first element of the array directly. And in this case, since you didn't tell it it's an array there, it will only copy the single element you reference.
So, if you use the version of the struct with string, fields, you need to change the P/Invoke declaration. If you only need to pass SEARCH_CRITERIA objects into the function, but won't need to read data from them after it returns, just use an array:
public static extern bool AwdApiLookup(IntPtr handle, uint ulMsg,
bool fContainer, byte cObjectType,
SearchCriteria[] pSearchCriteria,
ushort usCount, ushort usSearchType,
Pointer pReserverd);
And call it like this:
var callResult = UnsafeAwdApi.CallAwdApiLookup(
IntPtr.Zero, 0, true, (byte)'W',
searchCriteria, criteriaCount,
66, null);
If function writes data into that array, and you need to read it, use [In, Out]:
[In, Out] SearchCriteria[] pSearchCriteria,
If you use the version with fixed byte[] arrays, you can also change the P/Invoke declaration to read SearchCriteria* pSearchCriteria, and then use:
fixed (SearchCriteria* p = &searchCriteria[0])
{
AwdApiLookup(..., p, ...);
}
This will require unsafe as well, though.

C#: marshalling a struct that contains arrays

I am doing some C# interop work. I have the following struct:
#pragma pack(push,1)
typedef struct
{
unsigned __int64 Handle;
LinkType_t Type;
LinkState_t State;
unsigned __int64 Settings;
signed __int8 Name[MAX_LINK_NAME];
unsigned __int8 DeviceInfo[MAX_LINK_DEVINFO];
unsigned __int8 Reserved[40];
} LinkInfo_t;
This is my attempt to convert it into a C# struct:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct LinkInfo_t
{
[MarshalAs(UnmanagedType.U8)]
public UInt64 Handle;
[MarshalAs(UnmanagedType.I4)]
public LinkType_t Type;
[MarshalAs(UnmanagedType.I4)]
public LinkState_t State;
[MarshalAs(UnmanagedType.U8)]
public UInt64 Settings;
[MarshalAs(UnmanagedType.LPStr, SizeConst = MAX_LINK_NAME)]
public string Name;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_LINK_DEVINFO, ArraySubType = UnmanagedType.U1)]
public byte[] DeviceInfo;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 40, ArraySubType = UnmanagedType.U1)]
public byte[] Reserved;
}
However, whenever I initialize the struct the Name, DeviceInfo, and Reserved fields are all set to null. How do I fix this?
For the arrays, try to use the fixed keyword:
public fixed byte DeviceInfo[MAX_LINK_DEVINFO];
public fixed byte Reserved[40];
whenever I initialize the struct the
Name, DeviceInfo, and Reserved fields
are all set to null
This is correct, and your definition looks OK to me (BTW, you don't need [MarshalAs] on the primitive fields, the default behaviour is to do what you specified there). Because your array fields are null, the marshaler won't do anything about them when marshaling your struct to unmanaged memory, but it's going to create the strings and arrays when unmarshaling.
What Anton Tykhyy says is correct. I just want to clarify with some examples. Using 'fixed' works, but that forces you to use 'unsafe' as well. I like to avoid using unsafe wherever possible. Using Marshal is a way to get around that.
First, let's say that I have a library that was created in C with the following definitions.
typedef struct {
int messageType;
BYTE payload[60];
} my_message;
/**
* \param[out] msg Where the message will be written to
*/
void receiveMessage(my_message *msg);
/*
* \param[in] msg The message that will be sent
*/
void sendMessage(my_message *msg);
In C#, the following structure would be equivalent to the one in C.
[StructLayout(LayoutKind.Sequential, Size = 64), Serializable]
struct my_message
{
int messageType;
[MarshalAs(UnmanagedType.ByValArray,SizeConst = 60)]
byte[] payload;
public initializeArray()
{
//explicitly initialize the array
payload = new byte[60];
}
}
Since the msg in receiveMessage() is documented as [out], you don't need to do anything special to the array in the structure before passing it to the function. i.e.:
my_message msg = new my_message();
receiveMessage(ref msg);
byte payload10 = msg.payload[10];
Since the msg in sendMessage() is documented as [in], you will need to fill the array before calling the function. Before filling the array, the array needs to be explicitly instantiated before using it. i.e.:
my_message msg = new my_message();
msg.initializeArray();
msg.payload[10] = 255;
sendMessage(ref msg);
Calling initializeArray() should instantiate the array in the previously allocated space created within the struct for this array.

How can C++/CLI make this situation easier?

I have a little piece of a library that I would like to write a .NET wrapper for. At the moment, I'm using P/Invoke, but since I don't have the library's source code or a whole lot of C knowledge, I'm having a difficult time with marshaling. It works so far (sort of), but it feels like a hack.
C Signatures
typedef struct
{
unsigned short sAddress[MAX_ADDRESS_CHAR_LENGTH + 1];
unsigned short sCallback[MAX_CALLBACK_CHAR_LENGTH + 1];
unsigned short sMessage[(MAX_MESSAGE_CHAR_LENGTH + 1) ];
unsigned short sSmscAddress[MAX_ADDRESS_CHAR_LENGTH+1];
unsigned short sSubject[MAX_SUBJECT_CHAR_LENGTH + 1];
unsigned char msgLength;
unsigned char pduType;
unsigned short msgRef;
unsigned char msgSequence;
unsigned char msgTotal;
EMsgPriority nPriority;
struct tm tTime;
EncodingType encoding;
unsigned char bReceipt;
unsigned long dwDataMask;
struct tm tValidity;
unsigned char nValidityType;
unsigned char bRelativeValidityFlag;
unsigned char isDeliveryAck;
} SMS_MSG_DATA;
unsigned short SmsEncodeMessage( SMS_MSG_DATA* sms_msg, unsigned char* msg_buf,
unsigned short* msg_buf_len );
C# P/Invoke
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct SMS_MSG_DATA {
[MarshalAs(UnmanagedType.ByValTStr,
SizeConst=SmsEncoding.MAX_ADDRESS_CHAR_LENGTH+1)]
public string sAddress;
[MarshalAs(UnmanagedType.ByValTStr,
SizeConst=SmsEncoding.MAX_CALLBACK_CHAR_LENGTH+1)]
public string sCallback;
[MarshalAs(UnmanagedType.ByValTStr,
SizeConst=SmsEncoding.MAX_MESSAGE_CHAR_LENGTH+1)]
public string sMessage;
[MarshalAs(UnmanagedType.ByValTStr,
SizeConst=SmsEncoding.MAX_ADDRESS_CHAR_LENGTH+1)]
public string sSmscAddress;
[MarshalAs(UnmanagedType.ByValTStr,
SizeConst=SmsEncoding.MAX_SUBJECT_CHAR_LENGTH+1)]
public string sSubject;
public byte msgLength;
public byte pduType;
public ushort msgRef;
public byte msgSequence;
public byte msgTotal;
public EMsgPriority nPriority;
public tm tTime;
public EncodingType encoding;
public byte bReceipt;
public long dwDataMask;
public tm tValidity;
public byte nValidityType;
public byte bRelativeValidityFlag;
public byte isDeliveryAck;
}
[DllImport(Constants.LIB_SMSENCODE)]
public static extern ErrorCode SmsEncodeMessage(ref SMS_MSG_DATA sms_msg,
byte[] msg_buf, ref short msg_buf_len);
Essentially, what this does is takes the SMS_MSG_DATA struct and outputs it to a binary format in the msg_buf byte array. The initial value of msg_buf_len is the size of the byte array, but when the encoding completes, it is set to the number of bytes actually filled.
How can a C++/CLI wrapper make this process any easier and cleaner?
This is perfectly reasonable P/Invoke code, though you should make sure that you are not passing Unicode around (check your struct defn.), because all your native declarations seem to take ANSI strings.
C++/CLI doesn't really help you too much here - the place where it makes your life easier is when you want to write some blocks of native code, and make the interface to the C# part simpler. The only thing you could do here, is if on the C# side you really only cared about 1-2 params, you could have the C++/CLI DLL fill out the rest for you and not worry about as much ugly code on the C# side
C++/CLI can make this easier because you don't have to write a PInvoke definition. Instead you can just use the original native SMS_MSG_DATA structure directly. You are free to write a better looking wrapper structure which is internally converted to SMS_MSG_DATA. This wrapper structure need not have any ugly PInvoke declaration and can be much more in lines with managed guidelines.

Categories

Resources